summaryrefslogtreecommitdiff
path: root/resources/jquery
diff options
context:
space:
mode:
Diffstat (limited to 'resources/jquery')
-rw-r--r--resources/jquery/images/jquery.arrowSteps.divider-ltr.pngbin0 -> 307 bytes
-rw-r--r--resources/jquery/images/jquery.arrowSteps.divider-rtl.pngbin0 -> 310 bytes
-rw-r--r--resources/jquery/images/jquery.arrowSteps.head-ltr.pngbin0 -> 939 bytes
-rw-r--r--resources/jquery/images/jquery.arrowSteps.head-rtl.pngbin0 -> 1006 bytes
-rw-r--r--resources/jquery/images/jquery.arrowSteps.tail-ltr.pngbin0 -> 338 bytes
-rw-r--r--resources/jquery/images/jquery.arrowSteps.tail-rtl.pngbin0 -> 485 bytes
-rw-r--r--resources/jquery/images/marker.pngbin0 -> 652 bytes
-rw-r--r--resources/jquery/images/mask.pngbin0 -> 2020 bytes
-rw-r--r--resources/jquery/images/spinner.gifbin0 -> 4648 bytes
-rw-r--r--resources/jquery/images/wheel.pngbin0 -> 11733 bytes
-rw-r--r--resources/jquery/jquery.arrowSteps.css45
-rw-r--r--resources/jquery/jquery.arrowSteps.js81
-rw-r--r--resources/jquery/jquery.autoEllipsis.js8
-rw-r--r--resources/jquery/jquery.byteLimit.js61
-rw-r--r--resources/jquery/jquery.checkboxShiftClick.js6
-rw-r--r--resources/jquery/jquery.client.js34
-rw-r--r--resources/jquery/jquery.collapsibleTabs.js10
-rw-r--r--resources/jquery/jquery.color.js8
-rw-r--r--resources/jquery/jquery.cycle.all.js1529
-rw-r--r--resources/jquery/jquery.expandableField.js2
-rw-r--r--resources/jquery/jquery.farbtastic.css54
-rw-r--r--resources/jquery/jquery.farbtastic.js286
-rw-r--r--resources/jquery/jquery.footHovzer.css6
-rw-r--r--resources/jquery/jquery.footHovzer.js45
-rw-r--r--resources/jquery/jquery.form.js310
-rw-r--r--resources/jquery/jquery.js3166
-rw-r--r--resources/jquery/jquery.makeCollapsible.js52
-rw-r--r--resources/jquery/jquery.messageBox.js20
-rw-r--r--resources/jquery/jquery.mockjax.js382
-rw-r--r--resources/jquery/jquery.mw-jump.js15
-rw-r--r--resources/jquery/jquery.mwExtension.js121
-rw-r--r--resources/jquery/jquery.mwPrototypes.js120
-rw-r--r--resources/jquery/jquery.placeholder.js4
-rw-r--r--resources/jquery/jquery.qunit.completenessTest.js36
-rw-r--r--resources/jquery/jquery.qunit.css21
-rw-r--r--resources/jquery/jquery.qunit.js783
-rw-r--r--resources/jquery/jquery.spinner.css12
-rw-r--r--resources/jquery/jquery.spinner.js44
-rw-r--r--resources/jquery/jquery.suggestions.css13
-rw-r--r--resources/jquery/jquery.suggestions.js150
-rw-r--r--resources/jquery/jquery.tabIndex.js8
-rw-r--r--resources/jquery/jquery.tablesorter.css12
-rw-r--r--resources/jquery/jquery.tablesorter.js15
-rw-r--r--resources/jquery/jquery.textSelection.js116
-rw-r--r--resources/jquery/jquery.validate.js1166
-rw-r--r--resources/jquery/jquery.xmldom.js46
46 files changed, 6511 insertions, 2276 deletions
diff --git a/resources/jquery/images/jquery.arrowSteps.divider-ltr.png b/resources/jquery/images/jquery.arrowSteps.divider-ltr.png
new file mode 100644
index 00000000..0de1ae9c
--- /dev/null
+++ b/resources/jquery/images/jquery.arrowSteps.divider-ltr.png
Binary files differ
diff --git a/resources/jquery/images/jquery.arrowSteps.divider-rtl.png b/resources/jquery/images/jquery.arrowSteps.divider-rtl.png
new file mode 100644
index 00000000..f3f06519
--- /dev/null
+++ b/resources/jquery/images/jquery.arrowSteps.divider-rtl.png
Binary files differ
diff --git a/resources/jquery/images/jquery.arrowSteps.head-ltr.png b/resources/jquery/images/jquery.arrowSteps.head-ltr.png
new file mode 100644
index 00000000..dbcc71b9
--- /dev/null
+++ b/resources/jquery/images/jquery.arrowSteps.head-ltr.png
Binary files differ
diff --git a/resources/jquery/images/jquery.arrowSteps.head-rtl.png b/resources/jquery/images/jquery.arrowSteps.head-rtl.png
new file mode 100644
index 00000000..760798bf
--- /dev/null
+++ b/resources/jquery/images/jquery.arrowSteps.head-rtl.png
Binary files differ
diff --git a/resources/jquery/images/jquery.arrowSteps.tail-ltr.png b/resources/jquery/images/jquery.arrowSteps.tail-ltr.png
new file mode 100644
index 00000000..61340fa8
--- /dev/null
+++ b/resources/jquery/images/jquery.arrowSteps.tail-ltr.png
Binary files differ
diff --git a/resources/jquery/images/jquery.arrowSteps.tail-rtl.png b/resources/jquery/images/jquery.arrowSteps.tail-rtl.png
new file mode 100644
index 00000000..dd2d8e8a
--- /dev/null
+++ b/resources/jquery/images/jquery.arrowSteps.tail-rtl.png
Binary files differ
diff --git a/resources/jquery/images/marker.png b/resources/jquery/images/marker.png
new file mode 100644
index 00000000..3929bbb5
--- /dev/null
+++ b/resources/jquery/images/marker.png
Binary files differ
diff --git a/resources/jquery/images/mask.png b/resources/jquery/images/mask.png
new file mode 100644
index 00000000..b0a4d406
--- /dev/null
+++ b/resources/jquery/images/mask.png
Binary files differ
diff --git a/resources/jquery/images/spinner.gif b/resources/jquery/images/spinner.gif
new file mode 100644
index 00000000..37d3a43d
--- /dev/null
+++ b/resources/jquery/images/spinner.gif
Binary files differ
diff --git a/resources/jquery/images/wheel.png b/resources/jquery/images/wheel.png
new file mode 100644
index 00000000..97b343d9
--- /dev/null
+++ b/resources/jquery/images/wheel.png
Binary files differ
diff --git a/resources/jquery/jquery.arrowSteps.css b/resources/jquery/jquery.arrowSteps.css
new file mode 100644
index 00000000..60461032
--- /dev/null
+++ b/resources/jquery/jquery.arrowSteps.css
@@ -0,0 +1,45 @@
+.arrowSteps {
+ list-style-type: none;
+ list-style-image: none;
+ border: 1px solid #666666;
+ position: relative;
+}
+
+.arrowSteps li {
+ float: left;
+ padding: 0px;
+ margin: 0px;
+ border: 0 none;
+}
+
+.arrowSteps li div {
+ padding: 0.5em;
+ text-align: center;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.arrowSteps li.arrow div {
+ /* @embed */
+ background: url(images/jquery.arrowSteps.divider-ltr.png) no-repeat right center;
+}
+
+/* applied to the element preceding the highlighted step */
+.arrowSteps li.arrow.tail div {
+ /* @embed */
+ background: url(images/jquery.arrowSteps.tail-ltr.png) no-repeat right center;
+}
+
+/* this applies to all highlighted, including the last */
+.arrowSteps li.head div {
+ /* @embed */
+ background: url(images/jquery.arrowSteps.head-ltr.png) no-repeat left center;
+ font-weight: bold;
+}
+
+/* this applies to all highlighted arrows except the last */
+.arrowSteps li.arrow.head div {
+ /* TODO: eliminate duplication of jquery.arrowSteps.head.png embedding */
+ /* @embed */
+ background: url(images/jquery.arrowSteps.head-ltr.png) no-repeat right center;
+} \ No newline at end of file
diff --git a/resources/jquery/jquery.arrowSteps.js b/resources/jquery/jquery.arrowSteps.js
new file mode 100644
index 00000000..f9637545
--- /dev/null
+++ b/resources/jquery/jquery.arrowSteps.js
@@ -0,0 +1,81 @@
+/**
+ * jQuery arrowSteps plugin
+ * Copyright Neil Kandalgaonkar, 2010
+ *
+ * This work is licensed under the terms of the GNU General Public License,
+ * version 2 or later.
+ * (see http://www.fsf.org/licensing/licenses/gpl.html).
+ * Derivative works and later versions of the code must be free software
+ * licensed under the same or a compatible license.
+ *
+ *
+ * DESCRIPTION
+ *
+ * Show users their progress through a series of steps, via a row of items that fit
+ * together like arrows. One item can be highlighted at a time.
+ *
+ *
+ * SYNOPSIS
+ *
+ * <ul id="robin-hood-daffy">
+ * <li id="guard"><div>Guard!</div></li>
+ * <li id="turn"><div>Turn!</div></li>
+ * <li id="parry"><div>Parry!</div></li>
+ * <li id="dodge"><div>Dodge!</div></li>
+ * <li id="spin"><div>Spin!</div></li>
+ * <li id="ha"><div>Ha!</div></li>
+ * <li id="thrust"><div>Thrust!</div></li>
+ * </ul>
+ *
+ * <script language="javascript"><!--
+ * $( '#robin-hood-daffy' ).arrowSteps();
+ *
+ * $( '#robin-hood-daffy' ).arrowStepsHighlight( '#guard' );
+ * // 'Guard!' is highlighted.
+ *
+ * // ... user completes the 'guard' step ...
+ *
+ * $( '#robin-hood-daffy' ).arrowStepsHighlight( '#turn' );
+ * // 'Turn!' is highlighted.
+ *
+ * //-->
+ * </script>
+ *
+ */
+
+( function( $j ) {
+ $j.fn.arrowSteps = function() {
+ this.addClass( 'arrowSteps' );
+ var $steps = this.find( 'li' );
+
+ var width = parseInt( 100 / $steps.length, 10 );
+ $steps.css( 'width', width + '%' );
+
+ // every step except the last one has an arrow at the right hand side. Also add in the padding
+ // for the calculated arrow width.
+ var arrowWidth = parseInt( this.outerHeight(), 10 );
+ $steps.filter( ':not(:last-child)' ).addClass( 'arrow' )
+ .find( 'div' ).css( 'padding-right', arrowWidth.toString() + 'px' );
+
+ this.data( 'arrowSteps', $steps );
+ return this;
+ };
+
+ $j.fn.arrowStepsHighlight = function( selector ) {
+ var $steps = this.data( 'arrowSteps' );
+ var $previous;
+ $j.each( $steps, function( i, step ) {
+ var $step = $j( step );
+ if ( $step.is( selector ) ) {
+ if ($previous) {
+ $previous.addClass( 'tail' );
+ }
+ $step.addClass( 'head' );
+ } else {
+ $step.removeClass( 'head tail lasthead' );
+ }
+ $previous = $step;
+ } );
+ };
+
+} )( jQuery );
diff --git a/resources/jquery/jquery.autoEllipsis.js b/resources/jquery/jquery.autoEllipsis.js
index 7d726894..9a5fcc9c 100644
--- a/resources/jquery/jquery.autoEllipsis.js
+++ b/resources/jquery/jquery.autoEllipsis.js
@@ -25,7 +25,7 @@ $.fn.autoEllipsis = function( options ) {
$el.text( $el.data( 'autoEllipsis.originalText' ) );
}
}
-
+
// container element - used for measuring against
var $container = $el;
// trimmable text element - only the text within this element will be trimmed
@@ -43,7 +43,7 @@ $.fn.autoEllipsis = function( options ) {
.empty()
.append( $trimmableText );
}
-
+
var text = $container.text();
var trimmableText = $trimmableText.text();
var w = $container.width();
@@ -81,7 +81,7 @@ $.fn.autoEllipsis = function( options ) {
return;
}
}
-
+
if ( $trimmableText.width() + pw > w ) {
switch ( options.position ) {
case 'right':
@@ -136,7 +136,7 @@ $.fn.autoEllipsis = function( options ) {
} else {
cache[text][w][options.position] = $container.html();
}
-
+
} );
};
diff --git a/resources/jquery/jquery.byteLimit.js b/resources/jquery/jquery.byteLimit.js
index c1d26fc4..10411924 100644
--- a/resources/jquery/jquery.byteLimit.js
+++ b/resources/jquery/jquery.byteLimit.js
@@ -6,24 +6,54 @@
( function( $ ) {
/**
- * Enforces a byte limit to a textbox, so that UTF-8 entries are not arbitrarily truncated.
+ * Enforces a byte limit to a textbox, so that UTF-8 entries are counted as well, when, for example,
+ * a databae field has a byte limit rather than a character limit.
+ * Plugin rationale: Browser has native maxlength for number of characters, this plugin exists to
+ * limit number of bytes instead.
+ *
+ * Can be called with a custom limit (to use that limit instead of the maxlength attribute value),
+ * a filter function (in case the limit should apply to something other than the exact input value),
+ * or both. Order of arguments is important!
+ *
+ * @context {jQuery} Instance of jQuery for one or more input elements
+ * @param limit {Number} (optional) Limit to enforce, fallsback to maxLength-attribute,
+ * called with fetched value as argument.
+ * @param fn {Function} (optional) Function to call on the input string before assessing the length
+ * @return {jQuery} The context
*/
- $.fn.byteLimit = function( limit ) {
+ $.fn.byteLimit = function( limit, fn ) {
+ // If the first argument is the function,
+ // set fn to the first argument's value and ignore the second argument.
+ if ( $.isFunction( limit ) ) {
+ fn = limit;
+ limit = undefined;
+ }
- // Default to current attribute value
- if ( limit == null ) {
- limit = this.attr( 'maxLength' );
+ // Default limit to current attribute value
+ if ( limit === undefined ) {
+ limit = this.prop( 'maxLength' );
+ }
- // If passed, update/set attribute value instead
+ // Update/set attribute value, but only if there is no callback set.
+ // If there's a callback set, it's possible that the limit being enforced
+ // is too low (ie. if the callback would return "Foo" for "User:Foo").
+ // Usually this isn't a problem since browsers ignore maxLength when setting
+ // the value property through JavaScript, but Safari 4 violates that rule, so
+ // we have to remove or not set the property if we have a callback.
+ if ( fn == undefined ) {
+ this.prop( 'maxLength', limit );
} else {
- this.attr( 'maxLength', limit );
+ this.removeProp( 'maxLength' );
}
// Nothing passed and/or empty attribute, return without binding an event.
- if ( limit == null ) {
+ if ( limit === undefined ) {
return this;
}
+ // Save function for reference
+ this.data( 'byteLimit-callback', fn );
+
// We've got something, go for it:
return this.keypress( function( e ) {
// First check to see if this is actually a character key
@@ -31,21 +61,22 @@
// Based on key-event info from http://unixpapa.com/js/key.html
// jQuery should also normalize e.which to be consistent cross-browser,
// however the same check is still needed regardless of jQuery.
-
+
// Note: At the moment, for some older opera versions (~< 10.5)
// some special keys won't be recognized (aka left arrow key).
// Backspace will be, so not big issue.
-
+
if ( e.which === 0 || e.charCode === 0 || e.which === 8 ||
e.ctrlKey || e.altKey || e.metaKey )
{
return true; //a special key (backspace, etc) so don't interfere.
}
-
- var len = $.byteLength( this.value );
- // Note that keypress returns a character code point, not a keycode.
- // However, this may not be super reliable depending on how keys come in...
- var charLen = $.byteLength( String.fromCharCode( e.which ) );
+
+ var val = fn !== undefined ? fn( $( this ).val() ): $( this ).val(),
+ len = $.byteLength( val ),
+ // Note that keypress returns a character code point, not a keycode.
+ // However, this may not be super reliable depending on how keys come in...
+ charLen = $.byteLength( String.fromCharCode( e.which ) );
if ( ( len + charLen ) > limit ) {
e.preventDefault();
diff --git a/resources/jquery/jquery.checkboxShiftClick.js b/resources/jquery/jquery.checkboxShiftClick.js
index cfa696d4..0a1d7d7d 100644
--- a/resources/jquery/jquery.checkboxShiftClick.js
+++ b/resources/jquery/jquery.checkboxShiftClick.js
@@ -16,9 +16,9 @@ $.fn.checkboxShiftClick = function( text ) {
if ( prevCheckbox !== null && e.shiftKey ) {
// Check or uncheck this one and all in-between checkboxes
$box.slice(
- Math.min( $box.index( prevCheckbox ), $box.index( e.target ) ),
- Math.max( $box.index( prevCheckbox ), $box.index( e.target ) ) + 1
- ).attr( {checked: e.target.checked ? 'checked' : ''} );
+ Math.min( $box.index( prevCheckbox ), $box.index( e.target ) ),
+ Math.max( $box.index( prevCheckbox ), $box.index( e.target ) ) + 1
+ ).prop( 'checked', e.target.checked ? true : false );
}
// Either way, update the prevCheckbox variable to the one clicked now
prevCheckbox = e.target;
diff --git a/resources/jquery/jquery.client.js b/resources/jquery/jquery.client.js
index 8082fa7d..ae74a324 100644
--- a/resources/jquery/jquery.client.js
+++ b/resources/jquery/jquery.client.js
@@ -14,7 +14,7 @@
/* Public Methods */
$.client = {
-
+
/**
* Get an object containing information about the client.
*
@@ -37,18 +37,18 @@
}
// Use the cached version if possible
if ( profileCache[nav.userAgent] === undefined ) {
-
+
/* Configuration */
-
+
// Name of browsers or layout engines we don't recognize
var uk = 'unknown';
// Generic version digit
var x = 'x';
// Strings found in user agent strings that need to be conformed
- var wildUserAgents = [ 'Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3'];
+ var wildUserAgents = ['Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3'];
// Translations for conforming user agent strings
var userAgentTranslations = [
- // Tons of browsers lie about being something they are not
+ // Tons of browsers lie about being something they are not
[/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
// Chrome lives in the shadow of Safari still
['Chrome Safari', 'Chrome'],
@@ -86,9 +86,9 @@
var platforms = ['win', 'mac', 'linux', 'sunos', 'solaris', 'iphone'];
// Translations for conforming operating system names
var platformTranslations = [['sunos', 'solaris']];
-
+
/* Methods */
-
+
// Performs multiple replacements on a string
var translate = function( source, translations ) {
for ( var i = 0; i < translations.length; i++ ) {
@@ -96,9 +96,9 @@
}
return source;
};
-
- /* Pre-processing */
-
+
+ /* Pre-processing */
+
var ua = nav.userAgent,
match,
name = uk,
@@ -113,9 +113,9 @@
}
// Everything will be in lowercase from now on
ua = ua.toLowerCase();
-
+
/* Extraction */
-
+
if ( match = new RegExp( '(' + names.join( '|' ) + ')' ).exec( ua ) ) {
name = translate( match[1], nameTranslations );
}
@@ -131,9 +131,9 @@
if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( ua ) ) {
version = match[3];
}
-
+
/* Edge Cases -- did I mention about how user agent string lie? */
-
+
// Decode Safari's crazy 400+ version numbers
if ( name.match( /safari/ ) && version > 400 ) {
version = '2.0';
@@ -143,9 +143,9 @@
version = ua.match( /version\/([0-9\.]*)/i )[1] || 10;
}
var versionNumber = parseFloat( version, 10 ) || 0.0;
-
+
/* Caching */
-
+
profileCache[nav.userAgent] = {
'name': name,
'layout': layout,
@@ -158,7 +158,7 @@
}
return profileCache[nav.userAgent];
},
-
+
/**
* Checks the current browser against a support map object to determine if the browser has been black-listed or
* not. If the browser was not configured specifically it is assumed to work. It is assumed that the body
diff --git a/resources/jquery/jquery.collapsibleTabs.js b/resources/jquery/jquery.collapsibleTabs.js
index b2399727..1784f86a 100644
--- a/resources/jquery/jquery.collapsibleTabs.js
+++ b/resources/jquery/jquery.collapsibleTabs.js
@@ -7,7 +7,7 @@
if( !this.length ) return this;
//merge options into the defaults
var $settings = $.extend( {}, $.collapsibleTabs.defaults, options );
-
+
this.each( function() {
var $this = $( this );
// add the element to our array of collapsible managers
@@ -20,7 +20,7 @@
$.collapsibleTabs.addData( $( this ) );
} );
} );
-
+
// if we haven't already bound our resize hanlder, bind it now
if( !$.collapsibleTabs.boundEvent ) {
$( window )
@@ -70,15 +70,15 @@
$.collapsibleTabs.instances.each( function() {
var $this = $( this ), data = $.collapsibleTabs.getSettings( $this );
if( data.shifting ) return;
-
+
// if the two navigations are colliding
if( $this.children( data.collapsible ).length > 0 && data.collapseCondition() ) {
-
+
$this.trigger( "beforeTabCollapse" );
// move the element to the dropdown menu
$.collapsibleTabs.moveToCollapsed( $this.children( data.collapsible + ':last' ) );
}
-
+
// if there are still moveable items in the dropdown menu,
// and there is sufficient space to place them in the tab container
if( $( data.collapsedContainer + ' ' + data.collapsible ).length > 0
diff --git a/resources/jquery/jquery.color.js b/resources/jquery/jquery.color.js
index b0419428..8a619b5c 100644
--- a/resources/jquery/jquery.color.js
+++ b/resources/jquery/jquery.color.js
@@ -15,7 +15,7 @@
fx.start = getColor( fx.elem, attr );
fx.end = $.colorUtil.getRGB( fx.end );
}
-
+
fx.elem.style[attr] = 'rgb(' + [
Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
@@ -24,7 +24,7 @@
}
}
);
-
+
function getColor(elem, attr) {
var color;
@@ -33,12 +33,12 @@
// Keep going until we find an element that has color, or we hit the body
if ( color != '' && color != 'transparent' || $.nodeName(elem, 'body') )
- break;
+ break;
attr = 'backgroundColor';
} while ( elem = elem.parentNode );
return $.colorUtil.getRGB(color);
};
-
+
} )( jQuery );
diff --git a/resources/jquery/jquery.cycle.all.js b/resources/jquery/jquery.cycle.all.js
new file mode 100644
index 00000000..d57fb720
--- /dev/null
+++ b/resources/jquery/jquery.cycle.all.js
@@ -0,0 +1,1529 @@
+/*!
+ * jQuery Cycle Plugin (with Transition Definitions)
+ * Examples and documentation at: http://jquery.malsup.com/cycle/
+ * Copyright (c) 2007-2010 M. Alsup
+ * Version: 2.9999 (13-NOV-2011)
+ * Dual licensed under the MIT and GPL licenses.
+ * http://jquery.malsup.com/license.html
+ * Requires: jQuery v1.3.2 or later
+ */
+;(function($, undefined) {
+
+var ver = '2.9999';
+
+// if $.support is not defined (pre jQuery 1.3) add what I need
+if ($.support == undefined) {
+ $.support = {
+ opacity: !($.browser.msie)
+ };
+}
+
+function debug(s) {
+ $.fn.cycle.debug && log(s);
+}
+function log() {
+ window.console && console.log && console.log('[cycle] ' + Array.prototype.join.call(arguments,' '));
+}
+$.expr[':'].paused = function(el) {
+ return el.cyclePause;
+}
+
+
+// the options arg can be...
+// a number - indicates an immediate transition should occur to the given slide index
+// a string - 'pause', 'resume', 'toggle', 'next', 'prev', 'stop', 'destroy' or the name of a transition effect (ie, 'fade', 'zoom', etc)
+// an object - properties to control the slideshow
+//
+// the arg2 arg can be...
+// the name of an fx (only used in conjunction with a numeric value for 'options')
+// the value true (only used in first arg == 'resume') and indicates
+// that the resume should occur immediately (not wait for next timeout)
+
+$.fn.cycle = function(options, arg2) {
+ var o = { s: this.selector, c: this.context };
+
+ // in 1.3+ we can fix mistakes with the ready state
+ if (this.length === 0 && options != 'stop') {
+ if (!$.isReady && o.s) {
+ log('DOM not ready, queuing slideshow');
+ $(function() {
+ $(o.s,o.c).cycle(options,arg2);
+ });
+ return this;
+ }
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+ return this;
+ }
+
+ // iterate the matched nodeset
+ return this.each(function() {
+ var opts = handleArguments(this, options, arg2);
+ if (opts === false)
+ return;
+
+ opts.updateActivePagerLink = opts.updateActivePagerLink || $.fn.cycle.updateActivePagerLink;
+
+ // stop existing slideshow for this container (if there is one)
+ if (this.cycleTimeout)
+ clearTimeout(this.cycleTimeout);
+ this.cycleTimeout = this.cyclePause = 0;
+
+ var $cont = $(this);
+ var $slides = opts.slideExpr ? $(opts.slideExpr, this) : $cont.children();
+ var els = $slides.get();
+
+ var opts2 = buildOptions($cont, $slides, els, opts, o);
+ if (opts2 === false)
+ return;
+
+ if (els.length < 2) {
+ log('terminating; too few slides: ' + els.length);
+ return;
+ }
+
+ var startTime = opts2.continuous ? 10 : getTimeout(els[opts2.currSlide], els[opts2.nextSlide], opts2, !opts2.backwards);
+
+ // if it's an auto slideshow, kick it off
+ if (startTime) {
+ startTime += (opts2.delay || 0);
+ if (startTime < 10)
+ startTime = 10;
+ debug('first timeout: ' + startTime);
+ this.cycleTimeout = setTimeout(function(){go(els,opts2,0,!opts.backwards)}, startTime);
+ }
+ });
+};
+
+function triggerPause(cont, byHover, onPager) {
+ var opts = $(cont).data('cycle.opts');
+ var paused = !!cont.cyclePause;
+ if (paused && opts.paused)
+ opts.paused(cont, opts, byHover, onPager);
+ else if (!paused && opts.resumed)
+ opts.resumed(cont, opts, byHover, onPager);
+}
+
+// process the args that were passed to the plugin fn
+function handleArguments(cont, options, arg2) {
+ if (cont.cycleStop == undefined)
+ cont.cycleStop = 0;
+ if (options === undefined || options === null)
+ options = {};
+ if (options.constructor == String) {
+ switch(options) {
+ case 'destroy':
+ case 'stop':
+ var opts = $(cont).data('cycle.opts');
+ if (!opts)
+ return false;
+ cont.cycleStop++; // callbacks look for change
+ if (cont.cycleTimeout)
+ clearTimeout(cont.cycleTimeout);
+ cont.cycleTimeout = 0;
+ opts.elements && $(opts.elements).stop();
+ $(cont).removeData('cycle.opts');
+ if (options == 'destroy')
+ destroy(opts);
+ return false;
+ case 'toggle':
+ cont.cyclePause = (cont.cyclePause === 1) ? 0 : 1;
+ checkInstantResume(cont.cyclePause, arg2, cont);
+ triggerPause(cont);
+ return false;
+ case 'pause':
+ cont.cyclePause = 1;
+ triggerPause(cont);
+ return false;
+ case 'resume':
+ cont.cyclePause = 0;
+ checkInstantResume(false, arg2, cont);
+ triggerPause(cont);
+ return false;
+ case 'prev':
+ case 'next':
+ var opts = $(cont).data('cycle.opts');
+ if (!opts) {
+ log('options not found, "prev/next" ignored');
+ return false;
+ }
+ $.fn.cycle[options](opts);
+ return false;
+ default:
+ options = { fx: options };
+ };
+ return options;
+ }
+ else if (options.constructor == Number) {
+ // go to the requested slide
+ var num = options;
+ options = $(cont).data('cycle.opts');
+ if (!options) {
+ log('options not found, can not advance slide');
+ return false;
+ }
+ if (num < 0 || num >= options.elements.length) {
+ log('invalid slide index: ' + num);
+ return false;
+ }
+ options.nextSlide = num;
+ if (cont.cycleTimeout) {
+ clearTimeout(cont.cycleTimeout);
+ cont.cycleTimeout = 0;
+ }
+ if (typeof arg2 == 'string')
+ options.oneTimeFx = arg2;
+ go(options.elements, options, 1, num >= options.currSlide);
+ return false;
+ }
+ return options;
+
+ function checkInstantResume(isPaused, arg2, cont) {
+ if (!isPaused && arg2 === true) { // resume now!
+ var options = $(cont).data('cycle.opts');
+ if (!options) {
+ log('options not found, can not resume');
+ return false;
+ }
+ if (cont.cycleTimeout) {
+ clearTimeout(cont.cycleTimeout);
+ cont.cycleTimeout = 0;
+ }
+ go(options.elements, options, 1, !options.backwards);
+ }
+ }
+};
+
+function removeFilter(el, opts) {
+ if (!$.support.opacity && opts.cleartype && el.style.filter) {
+ try { el.style.removeAttribute('filter'); }
+ catch(smother) {} // handle old opera versions
+ }
+};
+
+// unbind event handlers
+function destroy(opts) {
+ if (opts.next)
+ $(opts.next).unbind(opts.prevNextEvent);
+ if (opts.prev)
+ $(opts.prev).unbind(opts.prevNextEvent);
+
+ if (opts.pager || opts.pagerAnchorBuilder)
+ $.each(opts.pagerAnchors || [], function() {
+ this.unbind().remove();
+ });
+ opts.pagerAnchors = null;
+ if (opts.destroy) // callback
+ opts.destroy(opts);
+};
+
+// one-time initialization
+function buildOptions($cont, $slides, els, options, o) {
+ var startingSlideSpecified;
+ // support metadata plugin (v1.0 and v2.0)
+ var opts = $.extend({}, $.fn.cycle.defaults, options || {}, $.metadata ? $cont.metadata() : $.meta ? $cont.data() : {});
+ var meta = $.isFunction($cont.data) ? $cont.data(opts.metaAttr) : null;
+ if (meta)
+ opts = $.extend(opts, meta);
+ if (opts.autostop)
+ opts.countdown = opts.autostopCount || els.length;
+
+ var cont = $cont[0];
+ $cont.data('cycle.opts', opts);
+ opts.$cont = $cont;
+ opts.stopCount = cont.cycleStop;
+ opts.elements = els;
+ opts.before = opts.before ? [opts.before] : [];
+ opts.after = opts.after ? [opts.after] : [];
+
+ // push some after callbacks
+ if (!$.support.opacity && opts.cleartype)
+ opts.after.push(function() { removeFilter(this, opts); });
+ if (opts.continuous)
+ opts.after.push(function() { go(els,opts,0,!opts.backwards); });
+
+ saveOriginalOpts(opts);
+
+ // clearType corrections
+ if (!$.support.opacity && opts.cleartype && !opts.cleartypeNoBg)
+ clearTypeFix($slides);
+
+ // container requires non-static position so that slides can be position within
+ if ($cont.css('position') == 'static')
+ $cont.css('position', 'relative');
+ if (opts.width)
+ $cont.width(opts.width);
+ if (opts.height && opts.height != 'auto')
+ $cont.height(opts.height);
+
+ if (opts.startingSlide != undefined) {
+ opts.startingSlide = parseInt(opts.startingSlide,10);
+ if (opts.startingSlide >= els.length || opts.startSlide < 0)
+ opts.startingSlide = 0; // catch bogus input
+ else
+ startingSlideSpecified = true;
+ }
+ else if (opts.backwards)
+ opts.startingSlide = els.length - 1;
+ else
+ opts.startingSlide = 0;
+
+ // if random, mix up the slide array
+ if (opts.random) {
+ opts.randomMap = [];
+ for (var i = 0; i < els.length; i++)
+ opts.randomMap.push(i);
+ opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;});
+ if (startingSlideSpecified) {
+ // try to find the specified starting slide and if found set start slide index in the map accordingly
+ for ( var cnt = 0; cnt < els.length; cnt++ ) {
+ if ( opts.startingSlide == opts.randomMap[cnt] ) {
+ opts.randomIndex = cnt;
+ }
+ }
+ }
+ else {
+ opts.randomIndex = 1;
+ opts.startingSlide = opts.randomMap[1];
+ }
+ }
+ else if (opts.startingSlide >= els.length)
+ opts.startingSlide = 0; // catch bogus input
+ opts.currSlide = opts.startingSlide || 0;
+ var first = opts.startingSlide;
+
+ // set position and zIndex on all the slides
+ $slides.css({position: 'absolute', top:0, left:0}).hide().each(function(i) {
+ var z;
+ if (opts.backwards)
+ z = first ? i <= first ? els.length + (i-first) : first-i : els.length-i;
+ else
+ z = first ? i >= first ? els.length - (i-first) : first-i : els.length-i;
+ $(this).css('z-index', z)
+ });
+
+ // make sure first slide is visible
+ $(els[first]).css('opacity',1).show(); // opacity bit needed to handle restart use case
+ removeFilter(els[first], opts);
+
+ // stretch slides
+ if (opts.fit) {
+ if (!opts.aspect) {
+ if (opts.width)
+ $slides.width(opts.width);
+ if (opts.height && opts.height != 'auto')
+ $slides.height(opts.height);
+ } else {
+ $slides.each(function(){
+ var $slide = $(this);
+ var ratio = (opts.aspect === true) ? $slide.width()/$slide.height() : opts.aspect;
+ if( opts.width && $slide.width() != opts.width ) {
+ $slide.width( opts.width );
+ $slide.height( opts.width / ratio );
+ }
+
+ if( opts.height && $slide.height() < opts.height ) {
+ $slide.height( opts.height );
+ $slide.width( opts.height * ratio );
+ }
+ });
+ }
+ }
+
+ if (opts.center && ((!opts.fit) || opts.aspect)) {
+ $slides.each(function(){
+ var $slide = $(this);
+ $slide.css({
+ "margin-left": opts.width ?
+ ((opts.width - $slide.width()) / 2) + "px" :
+ 0,
+ "margin-top": opts.height ?
+ ((opts.height - $slide.height()) / 2) + "px" :
+ 0
+ });
+ });
+ }
+
+ if (opts.center && !opts.fit && !opts.slideResize) {
+ $slides.each(function(){
+ var $slide = $(this);
+ $slide.css({
+ "margin-left": opts.width ? ((opts.width - $slide.width()) / 2) + "px" : 0,
+ "margin-top": opts.height ? ((opts.height - $slide.height()) / 2) + "px" : 0
+ });
+ });
+ }
+
+ // stretch container
+ var reshape = opts.containerResize && !$cont.innerHeight();
+ if (reshape) { // do this only if container has no size http://tinyurl.com/da2oa9
+ var maxw = 0, maxh = 0;
+ for(var j=0; j < els.length; j++) {
+ var $e = $(els[j]), e = $e[0], w = $e.outerWidth(), h = $e.outerHeight();
+ if (!w) w = e.offsetWidth || e.width || $e.attr('width');
+ if (!h) h = e.offsetHeight || e.height || $e.attr('height');
+ maxw = w > maxw ? w : maxw;
+ maxh = h > maxh ? h : maxh;
+ }
+ if (maxw > 0 && maxh > 0)
+ $cont.css({width:maxw+'px',height:maxh+'px'});
+ }
+
+ var pauseFlag = false; // https://github.com/malsup/cycle/issues/44
+ if (opts.pause)
+ $cont.hover(
+ function(){
+ pauseFlag = true;
+ this.cyclePause++;
+ triggerPause(cont, true);
+ },
+ function(){
+ pauseFlag && this.cyclePause--;
+ triggerPause(cont, true);
+ }
+ );
+
+ if (supportMultiTransitions(opts) === false)
+ return false;
+
+ // apparently a lot of people use image slideshows without height/width attributes on the images.
+ // Cycle 2.50+ requires the sizing info for every slide; this block tries to deal with that.
+ var requeue = false;
+ options.requeueAttempts = options.requeueAttempts || 0;
+ $slides.each(function() {
+ // try to get height/width of each slide
+ var $el = $(this);
+ this.cycleH = (opts.fit && opts.height) ? opts.height : ($el.height() || this.offsetHeight || this.height || $el.attr('height') || 0);
+ this.cycleW = (opts.fit && opts.width) ? opts.width : ($el.width() || this.offsetWidth || this.width || $el.attr('width') || 0);
+
+ if ( $el.is('img') ) {
+ // sigh.. sniffing, hacking, shrugging... this crappy hack tries to account for what browsers do when
+ // an image is being downloaded and the markup did not include sizing info (height/width attributes);
+ // there seems to be some "default" sizes used in this situation
+ var loadingIE = ($.browser.msie && this.cycleW == 28 && this.cycleH == 30 && !this.complete);
+ var loadingFF = ($.browser.mozilla && this.cycleW == 34 && this.cycleH == 19 && !this.complete);
+ var loadingOp = ($.browser.opera && ((this.cycleW == 42 && this.cycleH == 19) || (this.cycleW == 37 && this.cycleH == 17)) && !this.complete);
+ var loadingOther = (this.cycleH == 0 && this.cycleW == 0 && !this.complete);
+ // don't requeue for images that are still loading but have a valid size
+ if (loadingIE || loadingFF || loadingOp || loadingOther) {
+ if (o.s && opts.requeueOnImageNotLoaded && ++options.requeueAttempts < 100) { // track retry count so we don't loop forever
+ log(options.requeueAttempts,' - img slide not loaded, requeuing slideshow: ', this.src, this.cycleW, this.cycleH);
+ setTimeout(function() {$(o.s,o.c).cycle(options)}, opts.requeueTimeout);
+ requeue = true;
+ return false; // break each loop
+ }
+ else {
+ log('could not determine size of image: '+this.src, this.cycleW, this.cycleH);
+ }
+ }
+ }
+ return true;
+ });
+
+ if (requeue)
+ return false;
+
+ opts.cssBefore = opts.cssBefore || {};
+ opts.cssAfter = opts.cssAfter || {};
+ opts.cssFirst = opts.cssFirst || {};
+ opts.animIn = opts.animIn || {};
+ opts.animOut = opts.animOut || {};
+
+ $slides.not(':eq('+first+')').css(opts.cssBefore);
+ $($slides[first]).css(opts.cssFirst);
+
+ if (opts.timeout) {
+ opts.timeout = parseInt(opts.timeout,10);
+ // ensure that timeout and speed settings are sane
+ if (opts.speed.constructor == String)
+ opts.speed = $.fx.speeds[opts.speed] || parseInt(opts.speed,10);
+ if (!opts.sync)
+ opts.speed = opts.speed / 2;
+
+ var buffer = opts.fx == 'none' ? 0 : opts.fx == 'shuffle' ? 500 : 250;
+ while((opts.timeout - opts.speed) < buffer) // sanitize timeout
+ opts.timeout += opts.speed;
+ }
+ if (opts.easing)
+ opts.easeIn = opts.easeOut = opts.easing;
+ if (!opts.speedIn)
+ opts.speedIn = opts.speed;
+ if (!opts.speedOut)
+ opts.speedOut = opts.speed;
+
+ opts.slideCount = els.length;
+ opts.currSlide = opts.lastSlide = first;
+ if (opts.random) {
+ if (++opts.randomIndex == els.length)
+ opts.randomIndex = 0;
+ opts.nextSlide = opts.randomMap[opts.randomIndex];
+ }
+ else if (opts.backwards)
+ opts.nextSlide = opts.startingSlide == 0 ? (els.length-1) : opts.startingSlide-1;
+ else
+ opts.nextSlide = opts.startingSlide >= (els.length-1) ? 0 : opts.startingSlide+1;
+
+ // run transition init fn
+ if (!opts.multiFx) {
+ var init = $.fn.cycle.transitions[opts.fx];
+ if ($.isFunction(init))
+ init($cont, $slides, opts);
+ else if (opts.fx != 'custom' && !opts.multiFx) {
+ log('unknown transition: ' + opts.fx,'; slideshow terminating');
+ return false;
+ }
+ }
+
+ // fire artificial events
+ var e0 = $slides[first];
+ if (!opts.skipInitializationCallbacks) {
+ if (opts.before.length)
+ opts.before[0].apply(e0, [e0, e0, opts, true]);
+ if (opts.after.length)
+ opts.after[0].apply(e0, [e0, e0, opts, true]);
+ }
+ if (opts.next)
+ $(opts.next).bind(opts.prevNextEvent,function(){return advance(opts,1)});
+ if (opts.prev)
+ $(opts.prev).bind(opts.prevNextEvent,function(){return advance(opts,0)});
+ if (opts.pager || opts.pagerAnchorBuilder)
+ buildPager(els,opts);
+
+ exposeAddSlide(opts, els);
+
+ return opts;
+};
+
+// save off original opts so we can restore after clearing state
+function saveOriginalOpts(opts) {
+ opts.original = { before: [], after: [] };
+ opts.original.cssBefore = $.extend({}, opts.cssBefore);
+ opts.original.cssAfter = $.extend({}, opts.cssAfter);
+ opts.original.animIn = $.extend({}, opts.animIn);
+ opts.original.animOut = $.extend({}, opts.animOut);
+ $.each(opts.before, function() { opts.original.before.push(this); });
+ $.each(opts.after, function() { opts.original.after.push(this); });
+};
+
+function supportMultiTransitions(opts) {
+ var i, tx, txs = $.fn.cycle.transitions;
+ // look for multiple effects
+ if (opts.fx.indexOf(',') > 0) {
+ opts.multiFx = true;
+ opts.fxs = opts.fx.replace(/\s*/g,'').split(',');
+ // discard any bogus effect names
+ for (i=0; i < opts.fxs.length; i++) {
+ var fx = opts.fxs[i];
+ tx = txs[fx];
+ if (!tx || !txs.hasOwnProperty(fx) || !$.isFunction(tx)) {
+ log('discarding unknown transition: ',fx);
+ opts.fxs.splice(i,1);
+ i--;
+ }
+ }
+ // if we have an empty list then we threw everything away!
+ if (!opts.fxs.length) {
+ log('No valid transitions named; slideshow terminating.');
+ return false;
+ }
+ }
+ else if (opts.fx == 'all') { // auto-gen the list of transitions
+ opts.multiFx = true;
+ opts.fxs = [];
+ for (p in txs) {
+ tx = txs[p];
+ if (txs.hasOwnProperty(p) && $.isFunction(tx))
+ opts.fxs.push(p);
+ }
+ }
+ if (opts.multiFx && opts.randomizeEffects) {
+ // munge the fxs array to make effect selection random
+ var r1 = Math.floor(Math.random() * 20) + 30;
+ for (i = 0; i < r1; i++) {
+ var r2 = Math.floor(Math.random() * opts.fxs.length);
+ opts.fxs.push(opts.fxs.splice(r2,1)[0]);
+ }
+ debug('randomized fx sequence: ',opts.fxs);
+ }
+ return true;
+};
+
+// provide a mechanism for adding slides after the slideshow has started
+function exposeAddSlide(opts, els) {
+ opts.addSlide = function(newSlide, prepend) {
+ var $s = $(newSlide), s = $s[0];
+ if (!opts.autostopCount)
+ opts.countdown++;
+ els[prepend?'unshift':'push'](s);
+ if (opts.els)
+ opts.els[prepend?'unshift':'push'](s); // shuffle needs this
+ opts.slideCount = els.length;
+
+ // add the slide to the random map and resort
+ if (opts.random) {
+ opts.randomMap.push(opts.slideCount-1);
+ opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;});
+ }
+
+ $s.css('position','absolute');
+ $s[prepend?'prependTo':'appendTo'](opts.$cont);
+
+ if (prepend) {
+ opts.currSlide++;
+ opts.nextSlide++;
+ }
+
+ if (!$.support.opacity && opts.cleartype && !opts.cleartypeNoBg)
+ clearTypeFix($s);
+
+ if (opts.fit && opts.width)
+ $s.width(opts.width);
+ if (opts.fit && opts.height && opts.height != 'auto')
+ $s.height(opts.height);
+ s.cycleH = (opts.fit && opts.height) ? opts.height : $s.height();
+ s.cycleW = (opts.fit && opts.width) ? opts.width : $s.width();
+
+ $s.css(opts.cssBefore);
+
+ if (opts.pager || opts.pagerAnchorBuilder)
+ $.fn.cycle.createPagerAnchor(els.length-1, s, $(opts.pager), els, opts);
+
+ if ($.isFunction(opts.onAddSlide))
+ opts.onAddSlide($s);
+ else
+ $s.hide(); // default behavior
+ };
+}
+
+// reset internal state; we do this on every pass in order to support multiple effects
+$.fn.cycle.resetState = function(opts, fx) {
+ fx = fx || opts.fx;
+ opts.before = []; opts.after = [];
+ opts.cssBefore = $.extend({}, opts.original.cssBefore);
+ opts.cssAfter = $.extend({}, opts.original.cssAfter);
+ opts.animIn = $.extend({}, opts.original.animIn);
+ opts.animOut = $.extend({}, opts.original.animOut);
+ opts.fxFn = null;
+ $.each(opts.original.before, function() { opts.before.push(this); });
+ $.each(opts.original.after, function() { opts.after.push(this); });
+
+ // re-init
+ var init = $.fn.cycle.transitions[fx];
+ if ($.isFunction(init))
+ init(opts.$cont, $(opts.elements), opts);
+};
+
+// this is the main engine fn, it handles the timeouts, callbacks and slide index mgmt
+function go(els, opts, manual, fwd) {
+ // opts.busy is true if we're in the middle of an animation
+ if (manual && opts.busy && opts.manualTrump) {
+ // let manual transitions requests trump active ones
+ debug('manualTrump in go(), stopping active transition');
+ $(els).stop(true,true);
+ opts.busy = 0;
+ }
+ // don't begin another timeout-based transition if there is one active
+ if (opts.busy) {
+ debug('transition active, ignoring new tx request');
+ return;
+ }
+
+ var p = opts.$cont[0], curr = els[opts.currSlide], next = els[opts.nextSlide];
+
+ // stop cycling if we have an outstanding stop request
+ if (p.cycleStop != opts.stopCount || p.cycleTimeout === 0 && !manual)
+ return;
+
+ // check to see if we should stop cycling based on autostop options
+ if (!manual && !p.cyclePause && !opts.bounce &&
+ ((opts.autostop && (--opts.countdown <= 0)) ||
+ (opts.nowrap && !opts.random && opts.nextSlide < opts.currSlide))) {
+ if (opts.end)
+ opts.end(opts);
+ return;
+ }
+
+ // if slideshow is paused, only transition on a manual trigger
+ var changed = false;
+ if ((manual || !p.cyclePause) && (opts.nextSlide != opts.currSlide)) {
+ changed = true;
+ var fx = opts.fx;
+ // keep trying to get the slide size if we don't have it yet
+ curr.cycleH = curr.cycleH || $(curr).height();
+ curr.cycleW = curr.cycleW || $(curr).width();
+ next.cycleH = next.cycleH || $(next).height();
+ next.cycleW = next.cycleW || $(next).width();
+
+ // support multiple transition types
+ if (opts.multiFx) {
+ if (fwd && (opts.lastFx == undefined || ++opts.lastFx >= opts.fxs.length))
+ opts.lastFx = 0;
+ else if (!fwd && (opts.lastFx == undefined || --opts.lastFx < 0))
+ opts.lastFx = opts.fxs.length - 1;
+ fx = opts.fxs[opts.lastFx];
+ }
+
+ // one-time fx overrides apply to: $('div').cycle(3,'zoom');
+ if (opts.oneTimeFx) {
+ fx = opts.oneTimeFx;
+ opts.oneTimeFx = null;
+ }
+
+ $.fn.cycle.resetState(opts, fx);
+
+ // run the before callbacks
+ if (opts.before.length)
+ $.each(opts.before, function(i,o) {
+ if (p.cycleStop != opts.stopCount) return;
+ o.apply(next, [curr, next, opts, fwd]);
+ });
+
+ // stage the after callacks
+ var after = function() {
+ opts.busy = 0;
+ $.each(opts.after, function(i,o) {
+ if (p.cycleStop != opts.stopCount) return;
+ o.apply(next, [curr, next, opts, fwd]);
+ });
+ if (!p.cycleStop) {
+ // queue next transition
+ queueNext();
+ }
+ };
+
+ debug('tx firing('+fx+'); currSlide: ' + opts.currSlide + '; nextSlide: ' + opts.nextSlide);
+
+ // get ready to perform the transition
+ opts.busy = 1;
+ if (opts.fxFn) // fx function provided?
+ opts.fxFn(curr, next, opts, after, fwd, manual && opts.fastOnEvent);
+ else if ($.isFunction($.fn.cycle[opts.fx])) // fx plugin ?
+ $.fn.cycle[opts.fx](curr, next, opts, after, fwd, manual && opts.fastOnEvent);
+ else
+ $.fn.cycle.custom(curr, next, opts, after, fwd, manual && opts.fastOnEvent);
+ }
+ else {
+ queueNext();
+ }
+
+ if (changed || opts.nextSlide == opts.currSlide) {
+ // calculate the next slide
+ opts.lastSlide = opts.currSlide;
+ if (opts.random) {
+ opts.currSlide = opts.nextSlide;
+ if (++opts.randomIndex == els.length) {
+ opts.randomIndex = 0;
+ opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;});
+ }
+ opts.nextSlide = opts.randomMap[opts.randomIndex];
+ if (opts.nextSlide == opts.currSlide)
+ opts.nextSlide = (opts.currSlide == opts.slideCount - 1) ? 0 : opts.currSlide + 1;
+ }
+ else if (opts.backwards) {
+ var roll = (opts.nextSlide - 1) < 0;
+ if (roll && opts.bounce) {
+ opts.backwards = !opts.backwards;
+ opts.nextSlide = 1;
+ opts.currSlide = 0;
+ }
+ else {
+ opts.nextSlide = roll ? (els.length-1) : opts.nextSlide-1;
+ opts.currSlide = roll ? 0 : opts.nextSlide+1;
+ }
+ }
+ else { // sequence
+ var roll = (opts.nextSlide + 1) == els.length;
+ if (roll && opts.bounce) {
+ opts.backwards = !opts.backwards;
+ opts.nextSlide = els.length-2;
+ opts.currSlide = els.length-1;
+ }
+ else {
+ opts.nextSlide = roll ? 0 : opts.nextSlide+1;
+ opts.currSlide = roll ? els.length-1 : opts.nextSlide-1;
+ }
+ }
+ }
+ if (changed && opts.pager)
+ opts.updateActivePagerLink(opts.pager, opts.currSlide, opts.activePagerClass);
+
+ function queueNext() {
+ // stage the next transition
+ var ms = 0, timeout = opts.timeout;
+ if (opts.timeout && !opts.continuous) {
+ ms = getTimeout(els[opts.currSlide], els[opts.nextSlide], opts, fwd);
+ if (opts.fx == 'shuffle')
+ ms -= opts.speedOut;
+ }
+ else if (opts.continuous && p.cyclePause) // continuous shows work off an after callback, not this timer logic
+ ms = 10;
+ if (ms > 0)
+ p.cycleTimeout = setTimeout(function(){ go(els, opts, 0, !opts.backwards) }, ms);
+ }
+};
+
+// invoked after transition
+$.fn.cycle.updateActivePagerLink = function(pager, currSlide, clsName) {
+ $(pager).each(function() {
+ $(this).children().removeClass(clsName).eq(currSlide).addClass(clsName);
+ });
+};
+
+// calculate timeout value for current transition
+function getTimeout(curr, next, opts, fwd) {
+ if (opts.timeoutFn) {
+ // call user provided calc fn
+ var t = opts.timeoutFn.call(curr,curr,next,opts,fwd);
+ while (opts.fx != 'none' && (t - opts.speed) < 250) // sanitize timeout
+ t += opts.speed;
+ debug('calculated timeout: ' + t + '; speed: ' + opts.speed);
+ if (t !== false)
+ return t;
+ }
+ return opts.timeout;
+};
+
+// expose next/prev function, caller must pass in state
+$.fn.cycle.next = function(opts) { advance(opts,1); };
+$.fn.cycle.prev = function(opts) { advance(opts,0);};
+
+// advance slide forward or back
+function advance(opts, moveForward) {
+ var val = moveForward ? 1 : -1;
+ var els = opts.elements;
+ var p = opts.$cont[0], timeout = p.cycleTimeout;
+ if (timeout) {
+ clearTimeout(timeout);
+ p.cycleTimeout = 0;
+ }
+ if (opts.random && val < 0) {
+ // move back to the previously display slide
+ opts.randomIndex--;
+ if (--opts.randomIndex == -2)
+ opts.randomIndex = els.length-2;
+ else if (opts.randomIndex == -1)
+ opts.randomIndex = els.length-1;
+ opts.nextSlide = opts.randomMap[opts.randomIndex];
+ }
+ else if (opts.random) {
+ opts.nextSlide = opts.randomMap[opts.randomIndex];
+ }
+ else {
+ opts.nextSlide = opts.currSlide + val;
+ if (opts.nextSlide < 0) {
+ if (opts.nowrap) return false;
+ opts.nextSlide = els.length - 1;
+ }
+ else if (opts.nextSlide >= els.length) {
+ if (opts.nowrap) return false;
+ opts.nextSlide = 0;
+ }
+ }
+
+ var cb = opts.onPrevNextEvent || opts.prevNextClick; // prevNextClick is deprecated
+ if ($.isFunction(cb))
+ cb(val > 0, opts.nextSlide, els[opts.nextSlide]);
+ go(els, opts, 1, moveForward);
+ return false;
+};
+
+function buildPager(els, opts) {
+ var $p = $(opts.pager);
+ $.each(els, function(i,o) {
+ $.fn.cycle.createPagerAnchor(i,o,$p,els,opts);
+ });
+ opts.updateActivePagerLink(opts.pager, opts.startingSlide, opts.activePagerClass);
+};
+
+$.fn.cycle.createPagerAnchor = function(i, el, $p, els, opts) {
+ var a;
+ if ($.isFunction(opts.pagerAnchorBuilder)) {
+ a = opts.pagerAnchorBuilder(i,el);
+ debug('pagerAnchorBuilder('+i+', el) returned: ' + a);
+ }
+ else
+ a = '<a href="#">'+(i+1)+'</a>';
+
+ if (!a)
+ return;
+ var $a = $(a);
+ // don't reparent if anchor is in the dom
+ if ($a.parents('body').length === 0) {
+ var arr = [];
+ if ($p.length > 1) {
+ $p.each(function() {
+ var $clone = $a.clone(true);
+ $(this).append($clone);
+ arr.push($clone[0]);
+ });
+ $a = $(arr);
+ }
+ else {
+ $a.appendTo($p);
+ }
+ }
+
+ opts.pagerAnchors = opts.pagerAnchors || [];
+ opts.pagerAnchors.push($a);
+
+ var pagerFn = function(e) {
+ e.preventDefault();
+ opts.nextSlide = i;
+ var p = opts.$cont[0], timeout = p.cycleTimeout;
+ if (timeout) {
+ clearTimeout(timeout);
+ p.cycleTimeout = 0;
+ }
+ var cb = opts.onPagerEvent || opts.pagerClick; // pagerClick is deprecated
+ if ($.isFunction(cb))
+ cb(opts.nextSlide, els[opts.nextSlide]);
+ go(els,opts,1,opts.currSlide < i); // trigger the trans
+// return false; // <== allow bubble
+ }
+
+ if ( /mouseenter|mouseover/i.test(opts.pagerEvent) ) {
+ $a.hover(pagerFn, function(){/* no-op */} );
+ }
+ else {
+ $a.bind(opts.pagerEvent, pagerFn);
+ }
+
+ if ( ! /^click/.test(opts.pagerEvent) && !opts.allowPagerClickBubble)
+ $a.bind('click.cycle', function(){return false;}); // suppress click
+
+ var cont = opts.$cont[0];
+ var pauseFlag = false; // https://github.com/malsup/cycle/issues/44
+ if (opts.pauseOnPagerHover) {
+ $a.hover(
+ function() {
+ pauseFlag = true;
+ cont.cyclePause++;
+ triggerPause(cont,true,true);
+ }, function() {
+ pauseFlag && cont.cyclePause--;
+ triggerPause(cont,true,true);
+ }
+ );
+ }
+};
+
+// helper fn to calculate the number of slides between the current and the next
+$.fn.cycle.hopsFromLast = function(opts, fwd) {
+ var hops, l = opts.lastSlide, c = opts.currSlide;
+ if (fwd)
+ hops = c > l ? c - l : opts.slideCount - l;
+ else
+ hops = c < l ? l - c : l + opts.slideCount - c;
+ return hops;
+};
+
+// fix clearType problems in ie6 by setting an explicit bg color
+// (otherwise text slides look horrible during a fade transition)
+function clearTypeFix($slides) {
+ debug('applying clearType background-color hack');
+ function hex(s) {
+ s = parseInt(s,10).toString(16);
+ return s.length < 2 ? '0'+s : s;
+ };
+ function getBg(e) {
+ for ( ; e && e.nodeName.toLowerCase() != 'html'; e = e.parentNode) {
+ var v = $.css(e,'background-color');
+ if (v && v.indexOf('rgb') >= 0 ) {
+ var rgb = v.match(/\d+/g);
+ return '#'+ hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);
+ }
+ if (v && v != 'transparent')
+ return v;
+ }
+ return '#ffffff';
+ };
+ $slides.each(function() { $(this).css('background-color', getBg(this)); });
+};
+
+// reset common props before the next transition
+$.fn.cycle.commonReset = function(curr,next,opts,w,h,rev) {
+ $(opts.elements).not(curr).hide();
+ if (typeof opts.cssBefore.opacity == 'undefined')
+ opts.cssBefore.opacity = 1;
+ opts.cssBefore.display = 'block';
+ if (opts.slideResize && w !== false && next.cycleW > 0)
+ opts.cssBefore.width = next.cycleW;
+ if (opts.slideResize && h !== false && next.cycleH > 0)
+ opts.cssBefore.height = next.cycleH;
+ opts.cssAfter = opts.cssAfter || {};
+ opts.cssAfter.display = 'none';
+ $(curr).css('zIndex',opts.slideCount + (rev === true ? 1 : 0));
+ $(next).css('zIndex',opts.slideCount + (rev === true ? 0 : 1));
+};
+
+// the actual fn for effecting a transition
+$.fn.cycle.custom = function(curr, next, opts, cb, fwd, speedOverride) {
+ var $l = $(curr), $n = $(next);
+ var speedIn = opts.speedIn, speedOut = opts.speedOut, easeIn = opts.easeIn, easeOut = opts.easeOut;
+ $n.css(opts.cssBefore);
+ if (speedOverride) {
+ if (typeof speedOverride == 'number')
+ speedIn = speedOut = speedOverride;
+ else
+ speedIn = speedOut = 1;
+ easeIn = easeOut = null;
+ }
+ var fn = function() {
+ $n.animate(opts.animIn, speedIn, easeIn, function() {
+ cb();
+ });
+ };
+ $l.animate(opts.animOut, speedOut, easeOut, function() {
+ $l.css(opts.cssAfter);
+ if (!opts.sync)
+ fn();
+ });
+ if (opts.sync) fn();
+};
+
+// transition definitions - only fade is defined here, transition pack defines the rest
+$.fn.cycle.transitions = {
+ fade: function($cont, $slides, opts) {
+ $slides.not(':eq('+opts.currSlide+')').css('opacity',0);
+ opts.before.push(function(curr,next,opts) {
+ $.fn.cycle.commonReset(curr,next,opts);
+ opts.cssBefore.opacity = 0;
+ });
+ opts.animIn = { opacity: 1 };
+ opts.animOut = { opacity: 0 };
+ opts.cssBefore = { top: 0, left: 0 };
+ }
+};
+
+$.fn.cycle.ver = function() { return ver; };
+
+// override these globally if you like (they are all optional)
+$.fn.cycle.defaults = {
+ activePagerClass: 'activeSlide', // class name used for the active pager link
+ after: null, // transition callback (scope set to element that was shown): function(currSlideElement, nextSlideElement, options, forwardFlag)
+ allowPagerClickBubble: false, // allows or prevents click event on pager anchors from bubbling
+ animIn: null, // properties that define how the slide animates in
+ animOut: null, // properties that define how the slide animates out
+ aspect: false, // preserve aspect ratio during fit resizing, cropping if necessary (must be used with fit option)
+ autostop: 0, // true to end slideshow after X transitions (where X == slide count)
+ autostopCount: 0, // number of transitions (optionally used with autostop to define X)
+ backwards: false, // true to start slideshow at last slide and move backwards through the stack
+ before: null, // transition callback (scope set to element to be shown): function(currSlideElement, nextSlideElement, options, forwardFlag)
+ center: null, // set to true to have cycle add top/left margin to each slide (use with width and height options)
+ cleartype: !$.support.opacity, // true if clearType corrections should be applied (for IE)
+ cleartypeNoBg: false, // set to true to disable extra cleartype fixing (leave false to force background color setting on slides)
+ containerResize: 1, // resize container to fit largest slide
+ continuous: 0, // true to start next transition immediately after current one completes
+ cssAfter: null, // properties that defined the state of the slide after transitioning out
+ cssBefore: null, // properties that define the initial state of the slide before transitioning in
+ delay: 0, // additional delay (in ms) for first transition (hint: can be negative)
+ easeIn: null, // easing for "in" transition
+ easeOut: null, // easing for "out" transition
+ easing: null, // easing method for both in and out transitions
+ end: null, // callback invoked when the slideshow terminates (use with autostop or nowrap options): function(options)
+ fastOnEvent: 0, // force fast transitions when triggered manually (via pager or prev/next); value == time in ms
+ fit: 0, // force slides to fit container
+ fx: 'fade', // name of transition effect (or comma separated names, ex: 'fade,scrollUp,shuffle')
+ fxFn: null, // function used to control the transition: function(currSlideElement, nextSlideElement, options, afterCalback, forwardFlag)
+ height: 'auto', // container height (if the 'fit' option is true, the slides will be set to this height as well)
+ manualTrump: true, // causes manual transition to stop an active transition instead of being ignored
+ metaAttr: 'cycle',// data- attribute that holds the option data for the slideshow
+ next: null, // element, jQuery object, or jQuery selector string for the element to use as event trigger for next slide
+ nowrap: 0, // true to prevent slideshow from wrapping
+ onPagerEvent: null, // callback fn for pager events: function(zeroBasedSlideIndex, slideElement)
+ onPrevNextEvent: null,// callback fn for prev/next events: function(isNext, zeroBasedSlideIndex, slideElement)
+ pager: null, // element, jQuery object, or jQuery selector string for the element to use as pager container
+ pagerAnchorBuilder: null, // callback fn for building anchor links: function(index, DOMelement)
+ pagerEvent: 'click.cycle', // name of event which drives the pager navigation
+ pause: 0, // true to enable "pause on hover"
+ pauseOnPagerHover: 0, // true to pause when hovering over pager link
+ prev: null, // element, jQuery object, or jQuery selector string for the element to use as event trigger for previous slide
+ prevNextEvent:'click.cycle',// event which drives the manual transition to the previous or next slide
+ random: 0, // true for random, false for sequence (not applicable to shuffle fx)
+ randomizeEffects: 1, // valid when multiple effects are used; true to make the effect sequence random
+ requeueOnImageNotLoaded: true, // requeue the slideshow if any image slides are not yet loaded
+ requeueTimeout: 250, // ms delay for requeue
+ rev: 0, // causes animations to transition in reverse (for effects that support it such as scrollHorz/scrollVert/shuffle)
+ shuffle: null, // coords for shuffle animation, ex: { top:15, left: 200 }
+ skipInitializationCallbacks: false, // set to true to disable the first before/after callback that occurs prior to any transition
+ slideExpr: null, // expression for selecting slides (if something other than all children is required)
+ slideResize: 1, // force slide width/height to fixed size before every transition
+ speed: 1000, // speed of the transition (any valid fx speed value)
+ speedIn: null, // speed of the 'in' transition
+ speedOut: null, // speed of the 'out' transition
+ startingSlide: undefined, // zero-based index of the first slide to be displayed
+ sync: 1, // true if in/out transitions should occur simultaneously
+ timeout: 4000, // milliseconds between slide transitions (0 to disable auto advance)
+ timeoutFn: null, // callback for determining per-slide timeout value: function(currSlideElement, nextSlideElement, options, forwardFlag)
+ updateActivePagerLink: null, // callback fn invoked to update the active pager link (adds/removes activePagerClass style)
+ width: null // container width (if the 'fit' option is true, the slides will be set to this width as well)
+};
+
+})(jQuery);
+
+
+/*!
+ * jQuery Cycle Plugin Transition Definitions
+ * This script is a plugin for the jQuery Cycle Plugin
+ * Examples and documentation at: http://malsup.com/jquery/cycle/
+ * Copyright (c) 2007-2010 M. Alsup
+ * Version: 2.73
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+(function($) {
+
+//
+// These functions define slide initialization and properties for the named
+// transitions. To save file size feel free to remove any of these that you
+// don't need.
+//
+$.fn.cycle.transitions.none = function($cont, $slides, opts) {
+ opts.fxFn = function(curr,next,opts,after){
+ $(next).show();
+ $(curr).hide();
+ after();
+ };
+};
+
+// not a cross-fade, fadeout only fades out the top slide
+$.fn.cycle.transitions.fadeout = function($cont, $slides, opts) {
+ $slides.not(':eq('+opts.currSlide+')').css({ display: 'block', 'opacity': 1 });
+ opts.before.push(function(curr,next,opts,w,h,rev) {
+ $(curr).css('zIndex',opts.slideCount + (!rev === true ? 1 : 0));
+ $(next).css('zIndex',opts.slideCount + (!rev === true ? 0 : 1));
+ });
+ opts.animIn.opacity = 1;
+ opts.animOut.opacity = 0;
+ opts.cssBefore.opacity = 1;
+ opts.cssBefore.display = 'block';
+ opts.cssAfter.zIndex = 0;
+};
+
+// scrollUp/Down/Left/Right
+$.fn.cycle.transitions.scrollUp = function($cont, $slides, opts) {
+ $cont.css('overflow','hidden');
+ opts.before.push($.fn.cycle.commonReset);
+ var h = $cont.height();
+ opts.cssBefore.top = h;
+ opts.cssBefore.left = 0;
+ opts.cssFirst.top = 0;
+ opts.animIn.top = 0;
+ opts.animOut.top = -h;
+};
+$.fn.cycle.transitions.scrollDown = function($cont, $slides, opts) {
+ $cont.css('overflow','hidden');
+ opts.before.push($.fn.cycle.commonReset);
+ var h = $cont.height();
+ opts.cssFirst.top = 0;
+ opts.cssBefore.top = -h;
+ opts.cssBefore.left = 0;
+ opts.animIn.top = 0;
+ opts.animOut.top = h;
+};
+$.fn.cycle.transitions.scrollLeft = function($cont, $slides, opts) {
+ $cont.css('overflow','hidden');
+ opts.before.push($.fn.cycle.commonReset);
+ var w = $cont.width();
+ opts.cssFirst.left = 0;
+ opts.cssBefore.left = w;
+ opts.cssBefore.top = 0;
+ opts.animIn.left = 0;
+ opts.animOut.left = 0-w;
+};
+$.fn.cycle.transitions.scrollRight = function($cont, $slides, opts) {
+ $cont.css('overflow','hidden');
+ opts.before.push($.fn.cycle.commonReset);
+ var w = $cont.width();
+ opts.cssFirst.left = 0;
+ opts.cssBefore.left = -w;
+ opts.cssBefore.top = 0;
+ opts.animIn.left = 0;
+ opts.animOut.left = w;
+};
+$.fn.cycle.transitions.scrollHorz = function($cont, $slides, opts) {
+ $cont.css('overflow','hidden').width();
+ opts.before.push(function(curr, next, opts, fwd) {
+ if (opts.rev)
+ fwd = !fwd;
+ $.fn.cycle.commonReset(curr,next,opts);
+ opts.cssBefore.left = fwd ? (next.cycleW-1) : (1-next.cycleW);
+ opts.animOut.left = fwd ? -curr.cycleW : curr.cycleW;
+ });
+ opts.cssFirst.left = 0;
+ opts.cssBefore.top = 0;
+ opts.animIn.left = 0;
+ opts.animOut.top = 0;
+};
+$.fn.cycle.transitions.scrollVert = function($cont, $slides, opts) {
+ $cont.css('overflow','hidden');
+ opts.before.push(function(curr, next, opts, fwd) {
+ if (opts.rev)
+ fwd = !fwd;
+ $.fn.cycle.commonReset(curr,next,opts);
+ opts.cssBefore.top = fwd ? (1-next.cycleH) : (next.cycleH-1);
+ opts.animOut.top = fwd ? curr.cycleH : -curr.cycleH;
+ });
+ opts.cssFirst.top = 0;
+ opts.cssBefore.left = 0;
+ opts.animIn.top = 0;
+ opts.animOut.left = 0;
+};
+
+// slideX/slideY
+$.fn.cycle.transitions.slideX = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $(opts.elements).not(curr).hide();
+ $.fn.cycle.commonReset(curr,next,opts,false,true);
+ opts.animIn.width = next.cycleW;
+ });
+ opts.cssBefore.left = 0;
+ opts.cssBefore.top = 0;
+ opts.cssBefore.width = 0;
+ opts.animIn.width = 'show';
+ opts.animOut.width = 0;
+};
+$.fn.cycle.transitions.slideY = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $(opts.elements).not(curr).hide();
+ $.fn.cycle.commonReset(curr,next,opts,true,false);
+ opts.animIn.height = next.cycleH;
+ });
+ opts.cssBefore.left = 0;
+ opts.cssBefore.top = 0;
+ opts.cssBefore.height = 0;
+ opts.animIn.height = 'show';
+ opts.animOut.height = 0;
+};
+
+// shuffle
+$.fn.cycle.transitions.shuffle = function($cont, $slides, opts) {
+ var i, w = $cont.css('overflow', 'visible').width();
+ $slides.css({left: 0, top: 0});
+ opts.before.push(function(curr,next,opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,true,true);
+ });
+ // only adjust speed once!
+ if (!opts.speedAdjusted) {
+ opts.speed = opts.speed / 2; // shuffle has 2 transitions
+ opts.speedAdjusted = true;
+ }
+ opts.random = 0;
+ opts.shuffle = opts.shuffle || {left:-w, top:15};
+ opts.els = [];
+ for (i=0; i < $slides.length; i++)
+ opts.els.push($slides[i]);
+
+ for (i=0; i < opts.currSlide; i++)
+ opts.els.push(opts.els.shift());
+
+ // custom transition fn (hat tip to Benjamin Sterling for this bit of sweetness!)
+ opts.fxFn = function(curr, next, opts, cb, fwd) {
+ if (opts.rev)
+ fwd = !fwd;
+ var $el = fwd ? $(curr) : $(next);
+ $(next).css(opts.cssBefore);
+ var count = opts.slideCount;
+ $el.animate(opts.shuffle, opts.speedIn, opts.easeIn, function() {
+ var hops = $.fn.cycle.hopsFromLast(opts, fwd);
+ for (var k=0; k < hops; k++)
+ fwd ? opts.els.push(opts.els.shift()) : opts.els.unshift(opts.els.pop());
+ if (fwd) {
+ for (var i=0, len=opts.els.length; i < len; i++)
+ $(opts.els[i]).css('z-index', len-i+count);
+ }
+ else {
+ var z = $(curr).css('z-index');
+ $el.css('z-index', parseInt(z,10)+1+count);
+ }
+ $el.animate({left:0, top:0}, opts.speedOut, opts.easeOut, function() {
+ $(fwd ? this : curr).hide();
+ if (cb) cb();
+ });
+ });
+ };
+ $.extend(opts.cssBefore, { display: 'block', opacity: 1, top: 0, left: 0 });
+};
+
+// turnUp/Down/Left/Right
+$.fn.cycle.transitions.turnUp = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,false);
+ opts.cssBefore.top = next.cycleH;
+ opts.animIn.height = next.cycleH;
+ opts.animOut.width = next.cycleW;
+ });
+ opts.cssFirst.top = 0;
+ opts.cssBefore.left = 0;
+ opts.cssBefore.height = 0;
+ opts.animIn.top = 0;
+ opts.animOut.height = 0;
+};
+$.fn.cycle.transitions.turnDown = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,false);
+ opts.animIn.height = next.cycleH;
+ opts.animOut.top = curr.cycleH;
+ });
+ opts.cssFirst.top = 0;
+ opts.cssBefore.left = 0;
+ opts.cssBefore.top = 0;
+ opts.cssBefore.height = 0;
+ opts.animOut.height = 0;
+};
+$.fn.cycle.transitions.turnLeft = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,false,true);
+ opts.cssBefore.left = next.cycleW;
+ opts.animIn.width = next.cycleW;
+ });
+ opts.cssBefore.top = 0;
+ opts.cssBefore.width = 0;
+ opts.animIn.left = 0;
+ opts.animOut.width = 0;
+};
+$.fn.cycle.transitions.turnRight = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,false,true);
+ opts.animIn.width = next.cycleW;
+ opts.animOut.left = curr.cycleW;
+ });
+ $.extend(opts.cssBefore, { top: 0, left: 0, width: 0 });
+ opts.animIn.left = 0;
+ opts.animOut.width = 0;
+};
+
+// zoom
+$.fn.cycle.transitions.zoom = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,false,false,true);
+ opts.cssBefore.top = next.cycleH/2;
+ opts.cssBefore.left = next.cycleW/2;
+ $.extend(opts.animIn, { top: 0, left: 0, width: next.cycleW, height: next.cycleH });
+ $.extend(opts.animOut, { width: 0, height: 0, top: curr.cycleH/2, left: curr.cycleW/2 });
+ });
+ opts.cssFirst.top = 0;
+ opts.cssFirst.left = 0;
+ opts.cssBefore.width = 0;
+ opts.cssBefore.height = 0;
+};
+
+// fadeZoom
+$.fn.cycle.transitions.fadeZoom = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,false,false);
+ opts.cssBefore.left = next.cycleW/2;
+ opts.cssBefore.top = next.cycleH/2;
+ $.extend(opts.animIn, { top: 0, left: 0, width: next.cycleW, height: next.cycleH });
+ });
+ opts.cssBefore.width = 0;
+ opts.cssBefore.height = 0;
+ opts.animOut.opacity = 0;
+};
+
+// blindX
+$.fn.cycle.transitions.blindX = function($cont, $slides, opts) {
+ var w = $cont.css('overflow','hidden').width();
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts);
+ opts.animIn.width = next.cycleW;
+ opts.animOut.left = curr.cycleW;
+ });
+ opts.cssBefore.left = w;
+ opts.cssBefore.top = 0;
+ opts.animIn.left = 0;
+ opts.animOut.left = w;
+};
+// blindY
+$.fn.cycle.transitions.blindY = function($cont, $slides, opts) {
+ var h = $cont.css('overflow','hidden').height();
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts);
+ opts.animIn.height = next.cycleH;
+ opts.animOut.top = curr.cycleH;
+ });
+ opts.cssBefore.top = h;
+ opts.cssBefore.left = 0;
+ opts.animIn.top = 0;
+ opts.animOut.top = h;
+};
+// blindZ
+$.fn.cycle.transitions.blindZ = function($cont, $slides, opts) {
+ var h = $cont.css('overflow','hidden').height();
+ var w = $cont.width();
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts);
+ opts.animIn.height = next.cycleH;
+ opts.animOut.top = curr.cycleH;
+ });
+ opts.cssBefore.top = h;
+ opts.cssBefore.left = w;
+ opts.animIn.top = 0;
+ opts.animIn.left = 0;
+ opts.animOut.top = h;
+ opts.animOut.left = w;
+};
+
+// growX - grow horizontally from centered 0 width
+$.fn.cycle.transitions.growX = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,false,true);
+ opts.cssBefore.left = this.cycleW/2;
+ opts.animIn.left = 0;
+ opts.animIn.width = this.cycleW;
+ opts.animOut.left = 0;
+ });
+ opts.cssBefore.top = 0;
+ opts.cssBefore.width = 0;
+};
+// growY - grow vertically from centered 0 height
+$.fn.cycle.transitions.growY = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,false);
+ opts.cssBefore.top = this.cycleH/2;
+ opts.animIn.top = 0;
+ opts.animIn.height = this.cycleH;
+ opts.animOut.top = 0;
+ });
+ opts.cssBefore.height = 0;
+ opts.cssBefore.left = 0;
+};
+
+// curtainX - squeeze in both edges horizontally
+$.fn.cycle.transitions.curtainX = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,false,true,true);
+ opts.cssBefore.left = next.cycleW/2;
+ opts.animIn.left = 0;
+ opts.animIn.width = this.cycleW;
+ opts.animOut.left = curr.cycleW/2;
+ opts.animOut.width = 0;
+ });
+ opts.cssBefore.top = 0;
+ opts.cssBefore.width = 0;
+};
+// curtainY - squeeze in both edges vertically
+$.fn.cycle.transitions.curtainY = function($cont, $slides, opts) {
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,false,true);
+ opts.cssBefore.top = next.cycleH/2;
+ opts.animIn.top = 0;
+ opts.animIn.height = next.cycleH;
+ opts.animOut.top = curr.cycleH/2;
+ opts.animOut.height = 0;
+ });
+ opts.cssBefore.height = 0;
+ opts.cssBefore.left = 0;
+};
+
+// cover - curr slide covered by next slide
+$.fn.cycle.transitions.cover = function($cont, $slides, opts) {
+ var d = opts.direction || 'left';
+ var w = $cont.css('overflow','hidden').width();
+ var h = $cont.height();
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts);
+ if (d == 'right')
+ opts.cssBefore.left = -w;
+ else if (d == 'up')
+ opts.cssBefore.top = h;
+ else if (d == 'down')
+ opts.cssBefore.top = -h;
+ else
+ opts.cssBefore.left = w;
+ });
+ opts.animIn.left = 0;
+ opts.animIn.top = 0;
+ opts.cssBefore.top = 0;
+ opts.cssBefore.left = 0;
+};
+
+// uncover - curr slide moves off next slide
+$.fn.cycle.transitions.uncover = function($cont, $slides, opts) {
+ var d = opts.direction || 'left';
+ var w = $cont.css('overflow','hidden').width();
+ var h = $cont.height();
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,true,true);
+ if (d == 'right')
+ opts.animOut.left = w;
+ else if (d == 'up')
+ opts.animOut.top = -h;
+ else if (d == 'down')
+ opts.animOut.top = h;
+ else
+ opts.animOut.left = -w;
+ });
+ opts.animIn.left = 0;
+ opts.animIn.top = 0;
+ opts.cssBefore.top = 0;
+ opts.cssBefore.left = 0;
+};
+
+// toss - move top slide and fade away
+$.fn.cycle.transitions.toss = function($cont, $slides, opts) {
+ var w = $cont.css('overflow','visible').width();
+ var h = $cont.height();
+ opts.before.push(function(curr, next, opts) {
+ $.fn.cycle.commonReset(curr,next,opts,true,true,true);
+ // provide default toss settings if animOut not provided
+ if (!opts.animOut.left && !opts.animOut.top)
+ $.extend(opts.animOut, { left: w*2, top: -h/2, opacity: 0 });
+ else
+ opts.animOut.opacity = 0;
+ });
+ opts.cssBefore.left = 0;
+ opts.cssBefore.top = 0;
+ opts.animIn.left = 0;
+};
+
+// wipe - clip animation
+$.fn.cycle.transitions.wipe = function($cont, $slides, opts) {
+ var w = $cont.css('overflow','hidden').width();
+ var h = $cont.height();
+ opts.cssBefore = opts.cssBefore || {};
+ var clip;
+ if (opts.clip) {
+ if (/l2r/.test(opts.clip))
+ clip = 'rect(0px 0px '+h+'px 0px)';
+ else if (/r2l/.test(opts.clip))
+ clip = 'rect(0px '+w+'px '+h+'px '+w+'px)';
+ else if (/t2b/.test(opts.clip))
+ clip = 'rect(0px '+w+'px 0px 0px)';
+ else if (/b2t/.test(opts.clip))
+ clip = 'rect('+h+'px '+w+'px '+h+'px 0px)';
+ else if (/zoom/.test(opts.clip)) {
+ var top = parseInt(h/2,10);
+ var left = parseInt(w/2,10);
+ clip = 'rect('+top+'px '+left+'px '+top+'px '+left+'px)';
+ }
+ }
+
+ opts.cssBefore.clip = opts.cssBefore.clip || clip || 'rect(0px 0px 0px 0px)';
+
+ var d = opts.cssBefore.clip.match(/(\d+)/g);
+ var t = parseInt(d[0],10), r = parseInt(d[1],10), b = parseInt(d[2],10), l = parseInt(d[3],10);
+
+ opts.before.push(function(curr, next, opts) {
+ if (curr == next) return;
+ var $curr = $(curr), $next = $(next);
+ $.fn.cycle.commonReset(curr,next,opts,true,true,false);
+ opts.cssAfter.display = 'block';
+
+ var step = 1, count = parseInt((opts.speedIn / 13),10) - 1;
+ (function f() {
+ var tt = t ? t - parseInt(step * (t/count),10) : 0;
+ var ll = l ? l - parseInt(step * (l/count),10) : 0;
+ var bb = b < h ? b + parseInt(step * ((h-b)/count || 1),10) : h;
+ var rr = r < w ? r + parseInt(step * ((w-r)/count || 1),10) : w;
+ $next.css({ clip: 'rect('+tt+'px '+rr+'px '+bb+'px '+ll+'px)' });
+ (step++ <= count) ? setTimeout(f, 13) : $curr.css('display', 'none');
+ })();
+ });
+ $.extend(opts.cssBefore, { display: 'block', opacity: 1, top: 0, left: 0 });
+ opts.animIn = { left: 0 };
+ opts.animOut = { left: 0 };
+};
+
+})(jQuery);
diff --git a/resources/jquery/jquery.expandableField.js b/resources/jquery/jquery.expandableField.js
index ebe29a41..3c65d016 100644
--- a/resources/jquery/jquery.expandableField.js
+++ b/resources/jquery/jquery.expandableField.js
@@ -1,5 +1,5 @@
/**
- * This plugin provides functionallity to expand a text box on focus to double it's current width
+ * This plugin provides functionality to expand a text box on focus to double it's current width
*
* Usage:
*
diff --git a/resources/jquery/jquery.farbtastic.css b/resources/jquery/jquery.farbtastic.css
new file mode 100644
index 00000000..1c6428f8
--- /dev/null
+++ b/resources/jquery/jquery.farbtastic.css
@@ -0,0 +1,54 @@
+/**
+ * Farbtastic Color Picker 1.2
+ * © 2008 Steven Wittens
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+.farbtastic {
+ position: relative;
+}
+.farbtastic * {
+ position: absolute;
+ cursor: crosshair;
+}
+.farbtastic, .farbtastic .wheel {
+ width: 195px;
+ height: 195px;
+}
+.farbtastic .color, .farbtastic .overlay {
+ top: 47px;
+ left: 47px;
+ width: 101px;
+ height: 101px;
+}
+.farbtastic .wheel {
+ /* @embed */
+ background: url(images/wheel.png) no-repeat;
+ width: 195px;
+ height: 195px;
+}
+.farbtastic .overlay {
+ /* @embed */
+ background: url(images/mask.png) no-repeat;
+}
+.farbtastic .marker {
+ width: 17px;
+ height: 17px;
+ margin: -8px 0 0 -8px;
+ overflow: hidden;
+ /* @embed */
+ background: url(images/marker.png) no-repeat;
+}
+
diff --git a/resources/jquery/jquery.farbtastic.js b/resources/jquery/jquery.farbtastic.js
new file mode 100644
index 00000000..18810857
--- /dev/null
+++ b/resources/jquery/jquery.farbtastic.js
@@ -0,0 +1,286 @@
+/**
+ * Farbtastic Color Picker 1.2
+ * © 2008 Steven Wittens
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+//Adapted to uniform style with jQuery UI widgets and slightly change behavior
+//TODO:
+// - remove duplicated code by replacing it with jquery.colorUtils and modern jQuery
+// - uniform code style
+
+jQuery.fn.farbtastic = function (callback) {
+ $.farbtastic(this, callback);
+ return this;
+};
+
+jQuery.farbtastic = function (container, callback) {
+ var container = $(container).get(0);
+ return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback));
+}
+
+jQuery._farbtastic = function (container, callback) {
+ // Store farbtastic object
+ var fb = this;
+
+ // Insert markup
+ $(container).html('<div class="farbtastic ui-widget-content"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
+ $(container).addClass('ui-widget');
+ var e = $('.farbtastic', container);
+ fb.wheel = $('.wheel', container).get(0);
+ // Dimensions
+ fb.radius = 84;
+ fb.square = 100;
+ fb.width = 194;
+
+ // Fix background PNGs in IE6
+ if (navigator.appVersion.match(/MSIE [0-6]\./)) {
+ $('*', e).each(function () {
+ if (this.currentStyle.backgroundImage != 'none') {
+ var image = this.currentStyle.backgroundImage;
+ image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
+ $(this).css({
+ 'backgroundImage': 'none',
+ 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+ });
+ }
+ });
+ }
+
+ /**
+ * Link to the given element(s) or callback.
+ */
+ fb.linkTo = function (callback) {
+ // Unbind previous nodes
+ if (typeof fb.callback == 'object') {
+ $(fb.callback).unbind('keyup', fb.updateValue);
+ }
+
+ // Reset color
+ fb.color = null;
+
+ // Bind callback or elements
+ if (typeof callback == 'function') {
+ fb.callback = callback;
+ }
+ else if (typeof callback == 'object' || typeof callback == 'string') {
+ fb.callback = $(callback);
+ fb.callback.bind('keyup', fb.updateValue);
+ if (fb.callback.get(0).value) {
+ fb.setColor(fb.callback.get(0).value);
+ }
+ }
+ return this;
+ }
+ fb.updateValue = function (event) {
+ if (this.value != fb.color) {
+ fb.setColor(this.value);
+ }
+ }
+
+ /**
+ * Change color with HTML syntax #123456
+ */
+ fb.setColor = function (color) {
+ var rgb = $.colorUtil.getRGB( color );
+ if (fb.color != color && rgb) {
+ rgb = rgb.slice( 0 ); //make a clone
+ //TODO: rewrite code so that this is not needed
+ rgb[0] /= 255;
+ rgb[1] /= 255;
+ rgb[2] /= 255;
+ fb.color = color;
+ fb.rgb = rgb;
+ fb.hsl = fb.RGBToHSL(fb.rgb);
+ fb.updateDisplay();
+ }
+ return this;
+ }
+
+ /**
+ * Change color with HSL triplet [0..1, 0..1, 0..1]
+ */
+ fb.setHSL = function (hsl) {
+ fb.hsl = hsl;
+ fb.rgb = fb.HSLToRGB(hsl);
+ fb.color = fb.pack(fb.rgb);
+ fb.updateDisplay();
+ return this;
+ }
+
+ /////////////////////////////////////////////////////
+
+ /**
+ * Retrieve the coordinates of the given event relative to the center
+ * of the widget.
+ */
+ fb.widgetCoords = function (event) {
+ var ref = $( fb.wheel ).offset();
+ return {
+ x: event.pageX - ref.left - fb.width / 2,
+ y: event.pageY - ref.top - fb.width / 2
+ };
+ }
+
+ /**
+ * Mousedown handler
+ */
+ fb.mousedown = function (event) {
+ // Capture mouse
+ if (!document.dragging) {
+ $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);
+ document.dragging = true;
+ }
+
+ // Check which area is being dragged
+ var pos = fb.widgetCoords(event);
+ fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
+
+ // Process
+ fb.mousemove(event);
+ return false;
+ }
+
+ /**
+ * Mousemove handler
+ */
+ fb.mousemove = function (event) {
+ // Get coordinates relative to color picker center
+ var pos = fb.widgetCoords(event);
+
+ // Set new HSL parameters
+ if (fb.circleDrag) {
+ var hue = Math.atan2(pos.x, -pos.y) / 6.28;
+ if (hue < 0) hue += 1;
+ fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
+ }
+ else {
+ var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
+ var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
+ fb.setHSL([fb.hsl[0], sat, lum]);
+ }
+ return false;
+ }
+
+ /**
+ * Mouseup handler
+ */
+ fb.mouseup = function () {
+ // Uncapture mouse
+ $(document).unbind('mousemove', fb.mousemove);
+ $(document).unbind('mouseup', fb.mouseup);
+ document.dragging = false;
+ }
+
+ /**
+ * Update the markers and styles
+ */
+ fb.updateDisplay = function () {
+ // Markers
+ var angle = fb.hsl[0] * 6.28;
+ $('.h-marker', e).css({
+ left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
+ top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
+ });
+
+ $('.sl-marker', e).css({
+ left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
+ top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
+ });
+
+ // Saturation/Luminance gradient
+ $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
+
+ // Linked elements or callback
+ if (typeof fb.callback == 'object') {
+ // Set background/foreground color
+ $(fb.callback).css({
+ backgroundColor: fb.color,
+ color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
+ });
+
+ // Change linked value
+ $(fb.callback).each(function() {
+ if ( $( this ).val() != fb.color) {
+ $( this ).val( fb.color ).change();
+ }
+ });
+ }
+ else if (typeof fb.callback == 'function') {
+ fb.callback.call(fb, fb.color);
+ }
+ }
+
+ /* Various color utility functions */
+ fb.pack = function (rgb) {
+ var r = Math.round(rgb[0] * 255);
+ var g = Math.round(rgb[1] * 255);
+ var b = Math.round(rgb[2] * 255);
+ return '#' + (r < 16 ? '0' : '') + r.toString(16) +
+ (g < 16 ? '0' : '') + g.toString(16) +
+ (b < 16 ? '0' : '') + b.toString(16);
+ }
+
+ fb.HSLToRGB = function (hsl) {
+ var m1, m2, r, g, b;
+ var h = hsl[0], s = hsl[1], l = hsl[2];
+ m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
+ m1 = l * 2 - m2;
+ return [this.hueToRGB(m1, m2, h+0.33333),
+ this.hueToRGB(m1, m2, h),
+ this.hueToRGB(m1, m2, h-0.33333)];
+ }
+
+ fb.hueToRGB = function (m1, m2, h) {
+ h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
+ if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
+ if (h * 2 < 1) return m2;
+ if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
+ return m1;
+ }
+
+ fb.RGBToHSL = function (rgb) {
+ var min, max, delta, h, s, l;
+ var r = rgb[0], g = rgb[1], b = rgb[2];
+ min = Math.min(r, Math.min(g, b));
+ max = Math.max(r, Math.max(g, b));
+ delta = max - min;
+ l = (min + max) / 2;
+ s = 0;
+ if (l > 0 && l < 1) {
+ s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
+ }
+ h = 0;
+ if (delta > 0) {
+ if (max == r && max != g) h += (g - b) / delta;
+ if (max == g && max != b) h += (2 + (b - r) / delta);
+ if (max == b && max != r) h += (4 + (r - g) / delta);
+ h /= 6;
+ }
+ return [h, s, l];
+ }
+
+ // Install mousedown handler (the others are set on the document on-demand)
+ $('*', e).mousedown(fb.mousedown);
+
+ // Init color
+ fb.setColor('#000000');
+
+ // Set linked elements/callback
+ if (callback) {
+ fb.linkTo(callback);
+ }
+}
diff --git a/resources/jquery/jquery.footHovzer.css b/resources/jquery/jquery.footHovzer.css
new file mode 100644
index 00000000..77d9514c
--- /dev/null
+++ b/resources/jquery/jquery.footHovzer.css
@@ -0,0 +1,6 @@
+#jquery-foot-hovzer {
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ z-index: 1000;
+}
diff --git a/resources/jquery/jquery.footHovzer.js b/resources/jquery/jquery.footHovzer.js
new file mode 100644
index 00000000..56fc32d4
--- /dev/null
+++ b/resources/jquery/jquery.footHovzer.js
@@ -0,0 +1,45 @@
+/**
+ * Utility to stack stuff in an overlay fixed on the bottom of the page.
+ *
+ * Usage:
+ * <code>
+ * var hovzer = $.getFootHovzer();
+ * hovzer.$.append( $myCollection );
+ * hovzer.update();
+ * </code>
+ *
+ * @author Timo Tijhof, 2012
+ */
+( function ( $ ) {
+ var $hovzer, footHovzer, prevHeight, newHeight;
+
+ function getHovzer() {
+ if ( $hovzer === undefined ) {
+ $hovzer = $( '<div id="jquery-foot-hovzer"></div>' ).appendTo( 'body' );
+ }
+ return $hovzer;
+ }
+
+ footHovzer = {
+ update: function () {
+ var $body;
+
+ $body = $( 'body' );
+ if ( prevHeight === undefined ) {
+ prevHeight = getHovzer().outerHeight( /*includeMargin=*/true );
+ $body.css( 'paddingBottom', '+=' + prevHeight + 'px' );
+ } else {
+ newHeight = getHovzer().outerHeight( true );
+ $body.css( 'paddingBottom', ( parseFloat( $body.css( 'paddingBottom' ) ) - prevHeight ) + newHeight );
+
+ prevHeight = newHeight;
+ }
+ }
+ };
+
+ $.getFootHovzer = function () {
+ footHovzer.$ = getHovzer();
+ return footHovzer;
+ };
+
+}( jQuery ) );
diff --git a/resources/jquery/jquery.form.js b/resources/jquery/jquery.form.js
index 53c078f9..fdcdd15a 100644
--- a/resources/jquery/jquery.form.js
+++ b/resources/jquery/jquery.form.js
@@ -1,6 +1,6 @@
/*!
* jQuery Form Plugin
- * version: 2.52 (07-DEC-2010)
+ * version: 2.84 (12-AUG-2011)
* @requires jQuery v1.3.2 or later
*
* Examples and documentation at: http://malsup.com/jquery/form/
@@ -8,7 +8,7 @@
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
-(function($) {
+;(function($) {
/*
Usage Note:
@@ -49,22 +49,26 @@ $.fn.ajaxSubmit = function(options) {
log('ajaxSubmit: skipping submit process - no element selected');
return this;
}
+
+ var method, action, url, $form = this;
if (typeof options == 'function') {
options = { success: options };
}
- var action = this.attr('action');
- var url = (typeof action === 'string') ? $.trim(action) : '';
+ method = this.attr('method');
+ action = this.attr('action');
+ url = (typeof action === 'string') ? $.trim(action) : '';
+ url = url || window.location.href || '';
if (url) {
// clean url (don't include hash vaue)
url = (url.match(/^([^#]+)/)||[])[1];
}
- url = url || window.location.href || '';
options = $.extend(true, {
url: url,
- type: this.attr('method') || 'GET',
+ success: $.ajaxSettings.success,
+ type: method || 'GET',
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
}, options);
@@ -87,7 +91,7 @@ $.fn.ajaxSubmit = function(options) {
if (options.data) {
options.extraData = options.data;
for (n in options.data) {
- if(options.data[n] instanceof Array) {
+ if( $.isArray(options.data[n]) ) {
for (var k in options.data[n]) {
a.push( { name: n, value: options.data[n][k] } );
}
@@ -123,7 +127,7 @@ $.fn.ajaxSubmit = function(options) {
options.data = q; // data is the query string for 'post'
}
- var $form = this, callbacks = [];
+ var callbacks = [];
if (options.resetForm) {
callbacks.push(function() { $form.resetForm(); });
}
@@ -161,14 +165,20 @@ $.fn.ajaxSubmit = function(options) {
// hack to fix Safari hang (thanks to Tim Molendijk for this)
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
if (options.closeKeepAlive) {
- $.get(options.closeKeepAlive, fileUpload);
+ $.get(options.closeKeepAlive, function() { fileUpload(a); });
}
else {
- fileUpload();
+ fileUpload(a);
}
}
else {
- $.ajax(options);
+ // IE7 massage (see issue 57)
+ if ($.browser.msie && method == 'get') {
+ var ieMeth = $form[0].getAttribute('method');
+ if (typeof ieMeth === 'string')
+ options.type = ieMeth;
+ }
+ $.ajax(options);
}
// fire 'notify' event
@@ -177,8 +187,17 @@ $.fn.ajaxSubmit = function(options) {
// private function for handling file uploads (hat tip to YAHOO!)
- function fileUpload() {
- var form = $form[0];
+ function fileUpload(a) {
+ var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
+ var useProp = !!$.fn.prop;
+
+ if (a) {
+ // ensure that every serialized input is still enabled
+ for (i=0; i < a.length; i++) {
+ el = $(form[a[i].name]);
+ el[ useProp ? 'prop' : 'attr' ]('disabled', false);
+ }
+ }
if ($(':input[name=submit],:input[id=submit]', form).length) {
// if there is an input with a name or id of 'submit' then we won't be
@@ -187,23 +206,25 @@ $.fn.ajaxSubmit = function(options) {
return;
}
- var s = $.extend(true, {}, $.ajaxSettings, options);
+ s = $.extend(true, {}, $.ajaxSettings, options);
s.context = s.context || s;
- var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
- window[fn] = function() {
- var f = $io.data('form-plugin-onload');
- if (f) {
- f();
- window[fn] = undefined;
- try { delete window[fn]; } catch(e){}
- }
- };
- var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" onload="window[\'_\'+this.id]()" />');
- var io = $io[0];
+ id = 'jqFormIO' + (new Date().getTime());
+ if (s.iframeTarget) {
+ $io = $(s.iframeTarget);
+ n = $io.attr('name');
+ if (n == null)
+ $io.attr('name', id);
+ else
+ id = n;
+ }
+ else {
+ $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+ }
+ io = $io[0];
- $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
- var xhr = { // mock object
+ xhr = { // mock object
aborted: 0,
responseText: null,
responseXML: null,
@@ -212,13 +233,19 @@ $.fn.ajaxSubmit = function(options) {
getAllResponseHeaders: function() {},
getResponseHeader: function() {},
setRequestHeader: function() {},
- abort: function() {
+ abort: function(status) {
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
+ log('aborting upload... ' + e);
this.aborted = 1;
$io.attr('src', s.iframeSrc); // abort op in progress
+ xhr.error = e;
+ s.error && s.error.call(s.context, xhr, e, status);
+ g && $.event.trigger("ajaxError", [xhr, s, e]);
+ s.complete && s.complete.call(s.context, xhr, e);
}
};
- var g = s.global;
+ g = s.global;
// trigger ajax global events so that activity/block indicators work like normal
if (g && ! $.active++) {
$.event.trigger("ajaxStart");
@@ -228,7 +255,7 @@ $.fn.ajaxSubmit = function(options) {
}
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
- if (s.global) {
+ if (s.global) {
$.active--;
}
return;
@@ -237,13 +264,10 @@ $.fn.ajaxSubmit = function(options) {
return;
}
- var cbInvoked = false;
- var timedOut = 0;
-
// add submitting element to data if we know it
- var sub = form.clk;
+ sub = form.clk;
if (sub) {
- var n = sub.name;
+ n = sub.name;
if (n && !sub.disabled) {
s.extraData = s.extraData || {};
s.extraData[n] = sub.value;
@@ -253,7 +277,15 @@ $.fn.ajaxSubmit = function(options) {
}
}
}
+
+ var CLIENT_TIMEOUT_ABORT = 1;
+ var SERVER_ABORT = 2;
+ function getDoc(frame) {
+ var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
+ return doc;
+ }
+
// take a breath so that pending repaints get some cpu time before the upload starts
function doSubmit() {
// make sure form attrs are set
@@ -261,15 +293,15 @@ $.fn.ajaxSubmit = function(options) {
// update form attrs in IE friendly way
form.setAttribute('target',id);
- if (form.getAttribute('method') != 'POST') {
+ if (!method) {
form.setAttribute('method', 'POST');
}
- if (form.getAttribute('action') != s.url) {
+ if (a != s.url) {
form.setAttribute('action', s.url);
}
// ie borks in some cases when setting encoding
- if (! s.skipEncodingOverride) {
+ if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
$form.attr({
encoding: 'multipart/form-data',
enctype: 'multipart/form-data'
@@ -278,7 +310,23 @@ $.fn.ajaxSubmit = function(options) {
// support timout
if (s.timeout) {
- setTimeout(function() { timedOut = true; cb(); }, s.timeout);
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
+ }
+
+ // look for server aborts
+ function checkState() {
+ try {
+ var state = getDoc(io).readyState;
+ log('state = ' + state);
+ if (state.toLowerCase() == 'uninitialized')
+ setTimeout(checkState,50);
+ }
+ catch(e) {
+ log('Server abort: ' , e, ' (', e.name, ')');
+ cb(SERVER_ABORT);
+ timeoutHandle && clearTimeout(timeoutHandle);
+ timeoutHandle = undefined;
+ }
}
// add "extra" data to form if provided in options
@@ -287,14 +335,17 @@ $.fn.ajaxSubmit = function(options) {
if (s.extraData) {
for (var n in s.extraData) {
extraInputs.push(
- $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
+ $('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n])
.appendTo(form)[0]);
}
}
- // add iframe to doc and submit the form
- $io.appendTo('body');
- $io.data('form-plugin-onload', cb);
+ if (!s.iframeTarget) {
+ // add iframe to doc and submit the form
+ $io.appendTo('body');
+ io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
+ }
+ setTimeout(checkState,15);
form.submit();
}
finally {
@@ -315,24 +366,42 @@ $.fn.ajaxSubmit = function(options) {
else {
setTimeout(doSubmit, 10); // this lets dom updates render
}
-
- var data, doc, domCheckCount = 50;
- function cb() {
- if (cbInvoked) {
+ var data, doc, domCheckCount = 50, callbackProcessed;
+
+ function cb(e) {
+ if (xhr.aborted || callbackProcessed) {
+ return;
+ }
+ try {
+ doc = getDoc(io);
+ }
+ catch(ex) {
+ log('cannot access response document: ', ex);
+ e = SERVER_ABORT;
+ }
+ if (e === CLIENT_TIMEOUT_ABORT && xhr) {
+ xhr.abort('timeout');
+ return;
+ }
+ else if (e == SERVER_ABORT && xhr) {
+ xhr.abort('server abort');
return;
}
- $io.removeData('form-plugin-onload');
-
- var ok = true;
+ if (!doc || doc.location.href == s.iframeSrc) {
+ // response not received yet
+ if (!timedOut)
+ return;
+ }
+ io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
+
+ var status = 'success', errMsg;
try {
if (timedOut) {
throw 'timeout';
}
- // extract the server response from the iframe
- doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
-
+
var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
log('isXml='+isXml);
if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
@@ -349,76 +418,104 @@ $.fn.ajaxSubmit = function(options) {
}
//log('response detected');
- cbInvoked = true;
- xhr.responseText = doc.documentElement ? doc.documentElement.innerHTML : null;
+ var docRoot = doc.body ? doc.body : doc.documentElement;
+ xhr.responseText = docRoot ? docRoot.innerHTML : null;
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+ if (isXml)
+ s.dataType = 'xml';
xhr.getResponseHeader = function(header){
var headers = {'content-type': s.dataType};
return headers[header];
};
-
- var scr = /(json|script)/.test(s.dataType);
+ // support for XHR 'status' & 'statusText' emulation :
+ if (docRoot) {
+ xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
+ xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
+ }
+
+ var dt = s.dataType || '';
+ var scr = /(json|script|text)/.test(dt.toLowerCase());
if (scr || s.textarea) {
// see if user embedded response in textarea
var ta = doc.getElementsByTagName('textarea')[0];
if (ta) {
xhr.responseText = ta.value;
+ // support for XHR 'status' & 'statusText' emulation :
+ xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
+ xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
}
else if (scr) {
// account for browsers injecting pre around json response
var pre = doc.getElementsByTagName('pre')[0];
var b = doc.getElementsByTagName('body')[0];
if (pre) {
- xhr.responseText = pre.textContent;
+ xhr.responseText = pre.textContent ? pre.textContent : pre.innerHTML;
}
else if (b) {
xhr.responseText = b.innerHTML;
}
- }
+ }
}
else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
xhr.responseXML = toXml(xhr.responseText);
}
- data = $.httpData(xhr, s.dataType);
+
+ try {
+ data = httpData(xhr, s.dataType, s);
+ }
+ catch (e) {
+ status = 'parsererror';
+ xhr.error = errMsg = (e || status);
+ }
}
- catch(e){
- log('error caught:',e);
- ok = false;
- xhr.error = e;
- $.handleError(s, xhr, 'error', e);
+ catch (e) {
+ log('error caught: ',e);
+ status = 'error';
+ xhr.error = errMsg = (e || status);
}
-
+
if (xhr.aborted) {
log('upload aborted');
- ok = false;
+ status = null;
}
+ if (xhr.status) { // we've set xhr.status
+ status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
+ }
+
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
- if (ok) {
- s.success.call(s.context, data, 'success', xhr);
- if (g) {
- $.event.trigger("ajaxSuccess", [xhr, s]);
- }
- }
- if (g) {
- $.event.trigger("ajaxComplete", [xhr, s]);
+ if (status === 'success') {
+ s.success && s.success.call(s.context, data, 'success', xhr);
+ g && $.event.trigger("ajaxSuccess", [xhr, s]);
}
+ else if (status) {
+ if (errMsg == undefined)
+ errMsg = xhr.statusText;
+ s.error && s.error.call(s.context, xhr, status, errMsg);
+ g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
+ }
+
+ g && $.event.trigger("ajaxComplete", [xhr, s]);
+
if (g && ! --$.active) {
$.event.trigger("ajaxStop");
}
- if (s.complete) {
- s.complete.call(s.context, xhr, ok ? 'success' : 'error');
- }
+
+ s.complete && s.complete.call(s.context, xhr, status);
+
+ callbackProcessed = true;
+ if (s.timeout)
+ clearTimeout(timeoutHandle);
// clean up
setTimeout(function() {
- $io.removeData('form-plugin-onload');
- $io.remove();
+ if (!s.iframeTarget)
+ $io.remove();
xhr.responseXML = null;
}, 100);
}
- function toXml(s, doc) {
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
if (window.ActiveXObject) {
doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = 'false';
@@ -427,8 +524,33 @@ $.fn.ajaxSubmit = function(options) {
else {
doc = (new DOMParser()).parseFromString(s, 'text/xml');
}
- return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
- }
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+ };
+ var parseJSON = $.parseJSON || function(s) {
+ return window['eval']('(' + s + ')');
+ };
+
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+
+ var ct = xhr.getResponseHeader('content-type') || '',
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if (xml && data.documentElement.nodeName === 'parsererror') {
+ $.error && $.error('parsererror');
+ }
+ if (s && s.dataFilter) {
+ data = s.dataFilter(data, type);
+ }
+ if (typeof data === 'string') {
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+ data = parseJSON(data);
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+ $.globalEval(data);
+ }
+ }
+ return data;
+ };
}
};
@@ -462,7 +584,7 @@ $.fn.ajaxForm = function(options) {
log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
return this;
}
-
+
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
e.preventDefault();
@@ -526,7 +648,7 @@ $.fn.formToArray = function(semantic) {
if (!els) {
return a;
}
-
+
var i,j,n,v,el,max,jmax;
for(i=0, max=els.length; i < max; i++) {
el = els[i];
@@ -711,9 +833,10 @@ $.fn.clearForm = function() {
* Clears the selected form elements.
*/
$.fn.clearFields = $.fn.clearInputs = function() {
+ var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
return this.each(function() {
var t = this.type, tag = this.tagName.toLowerCase();
- if (t == 'text' || t == 'password' || tag == 'textarea') {
+ if (re.test(t) || tag == 'textarea') {
this.value = '';
}
else if (t == 'checkbox' || t == 'radio') {
@@ -775,16 +898,13 @@ $.fn.selected = function(select) {
};
// helper fn for console logging
-// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
- if ($.fn.ajaxSubmit.debug) {
- var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
- if (window.console && window.console.log) {
- window.console.log(msg);
- }
- else if (window.opera && window.opera.postError) {
- window.opera.postError(msg);
- }
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ else if (window.opera && window.opera.postError) {
+ window.opera.postError(msg);
}
};
diff --git a/resources/jquery/jquery.js b/resources/jquery/jquery.js
index 11e6d067..8ccd0ea7 100644
--- a/resources/jquery/jquery.js
+++ b/resources/jquery/jquery.js
@@ -1,5 +1,5 @@
/*!
- * jQuery JavaScript Library v1.6.4
+ * jQuery JavaScript Library v1.7.1
* http://jquery.com/
*
* Copyright 2011, John Resig
@@ -11,7 +11,7 @@
* Copyright 2011, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
- * Date: Mon Sep 12 18:54:48 2011 -0400
+ * Date: Mon Nov 21 21:11:03 2011 -0500
*/
(function( window, undefined ) {
@@ -47,9 +47,6 @@ var jQuery = function( selector, context ) {
trimLeft = /^\s+/,
trimRight = /\s+$/,
- // Check for digits
- rdigit = /\d/,
-
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
@@ -140,7 +137,7 @@ jQuery.fn = jQuery.prototype = {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
- doc = (context ? context.ownerDocument || context : document);
+ doc = ( context ? context.ownerDocument || context : document );
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
@@ -157,7 +154,7 @@ jQuery.fn = jQuery.prototype = {
} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
- selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
+ selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}
return jQuery.merge( this, selector );
@@ -187,7 +184,7 @@ jQuery.fn = jQuery.prototype = {
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
- return (context || rootjQuery).find( selector );
+ return ( context || rootjQuery ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
@@ -201,7 +198,7 @@ jQuery.fn = jQuery.prototype = {
return rootjQuery.ready( selector );
}
- if (selector.selector !== undefined) {
+ if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
@@ -213,7 +210,7 @@ jQuery.fn = jQuery.prototype = {
selector: "",
// The current version of jQuery being used
- jquery: "1.6.4",
+ jquery: "1.7.1",
// The default length of a jQuery object is 0
length: 0,
@@ -258,7 +255,7 @@ jQuery.fn = jQuery.prototype = {
ret.context = this.context;
if ( name === "find" ) {
- ret.selector = this.selector + (this.selector ? " " : "") + selector;
+ ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
@@ -279,15 +276,16 @@ jQuery.fn = jQuery.prototype = {
jQuery.bindReady();
// Add the callback
- readyList.done( fn );
+ readyList.add( fn );
return this;
},
eq: function( i ) {
+ i = +i;
return i === -1 ?
this.slice( i ) :
- this.slice( i, +i + 1 );
+ this.slice( i, i + 1 );
},
first: function() {
@@ -434,11 +432,11 @@ jQuery.extend({
}
// If there are functions bound, to execute
- readyList.resolveWith( document, [ jQuery ] );
+ readyList.fireWith( document, [ jQuery ] );
// Trigger any bound ready events
if ( jQuery.fn.trigger ) {
- jQuery( document ).trigger( "ready" ).unbind( "ready" );
+ jQuery( document ).trigger( "ready" ).off( "ready" );
}
}
},
@@ -448,7 +446,7 @@ jQuery.extend({
return;
}
- readyList = jQuery._Deferred();
+ readyList = jQuery.Callbacks( "once memory" );
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
@@ -504,8 +502,8 @@ jQuery.extend({
return obj && typeof obj === "object" && "setInterval" in obj;
},
- isNaN: function( obj ) {
- return obj == null || !rdigit.test( obj ) || isNaN( obj );
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
type: function( obj ) {
@@ -551,7 +549,7 @@ jQuery.extend({
},
error: function( msg ) {
- throw msg;
+ throw new Error( msg );
},
parseJSON: function( data ) {
@@ -573,7 +571,7 @@ jQuery.extend({
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
- return (new Function( "return " + data ))();
+ return ( new Function( "return " + data ) )();
}
jQuery.error( "Invalid JSON: " + data );
@@ -688,8 +686,6 @@ jQuery.extend({
if ( array != null ) {
// The window, strings (and functions) also have 'length'
- // The extra typeof function check is to prevent crashes
- // in Safari 2 (See: #3039)
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
var type = jQuery.type( array );
@@ -703,18 +699,22 @@ jQuery.extend({
return ret;
},
- inArray: function( elem, array ) {
- if ( !array ) {
- return -1;
- }
+ inArray: function( elem, array, i ) {
+ var len;
- if ( indexOf ) {
- return indexOf.call( array, elem );
- }
+ if ( array ) {
+ if ( indexOf ) {
+ return indexOf.call( array, elem, i );
+ }
+
+ len = array.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in array && array[ i ] === elem ) {
+ return i;
+ }
}
}
@@ -850,7 +850,7 @@ jQuery.extend({
},
now: function() {
- return (new Date()).getTime();
+ return ( new Date() ).getTime();
},
// Use of jQuery.browser is frowned upon.
@@ -957,188 +957,360 @@ return jQuery;
})();
-var // Promise methods
- promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
- // Static reference to slice
- sliceDeferred = [].slice;
+// String to Object flags format cache
+var flagsCache = {};
-jQuery.extend({
- // Create a simple deferred (one callbacks list)
- _Deferred: function() {
- var // callbacks list
- callbacks = [],
- // stored [ context , args ]
- fired,
- // to avoid firing when already doing so
- firing,
- // flag to know if the deferred has been cancelled
- cancelled,
- // the deferred itself
- deferred = {
-
- // done( f1, f2, ...)
- done: function() {
- if ( !cancelled ) {
- var args = arguments,
- i,
- length,
- elem,
- type,
- _fired;
- if ( fired ) {
- _fired = fired;
- fired = 0;
- }
- for ( i = 0, length = args.length; i < length; i++ ) {
- elem = args[ i ];
- type = jQuery.type( elem );
- if ( type === "array" ) {
- deferred.done.apply( deferred, elem );
- } else if ( type === "function" ) {
- callbacks.push( elem );
+// Convert String-formatted flags into Object-formatted ones and store in cache
+function createFlags( flags ) {
+ var object = flagsCache[ flags ] = {},
+ i, length;
+ flags = flags.split( /\s+/ );
+ for ( i = 0, length = flags.length; i < length; i++ ) {
+ object[ flags[i] ] = true;
+ }
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * flags: an optional list of space-separated flags that will change how
+ * the callback list behaves
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible flags:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( flags ) {
+
+ // Convert flags from String-formatted to Object-formatted
+ // (we check in cache first)
+ flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
+
+ var // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = [],
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Add one or several callbacks to the list
+ add = function( args ) {
+ var i,
+ length,
+ elem,
+ type,
+ actual;
+ for ( i = 0, length = args.length; i < length; i++ ) {
+ elem = args[ i ];
+ type = jQuery.type( elem );
+ if ( type === "array" ) {
+ // Inspect recursively
+ add( elem );
+ } else if ( type === "function" ) {
+ // Add if not in unique mode and callback is not in
+ if ( !flags.unique || !self.has( elem ) ) {
+ list.push( elem );
+ }
+ }
+ }
+ },
+ // Fire callbacks
+ fire = function( context, args ) {
+ args = args || [];
+ memory = !flags.memory || [ context, args ];
+ firing = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
+ memory = true; // Mark as halted
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( !flags.once ) {
+ if ( stack && stack.length ) {
+ memory = stack.shift();
+ self.fireWith( memory[ 0 ], memory[ 1 ] );
+ }
+ } else if ( memory === true ) {
+ self.disable();
+ } else {
+ list = [];
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ var length = list.length;
+ add( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away, unless previous
+ // firing was halted (stopOnFalse)
+ } else if ( memory && memory !== true ) {
+ firingStart = length;
+ fire( memory[ 0 ], memory[ 1 ] );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ var args = arguments,
+ argIndex = 0,
+ argLength = args.length;
+ for ( ; argIndex < argLength ; argIndex++ ) {
+ for ( var i = 0; i < list.length; i++ ) {
+ if ( args[ argIndex ] === list[ i ] ) {
+ // Handle firingIndex and firingLength
+ if ( firing ) {
+ if ( i <= firingLength ) {
+ firingLength--;
+ if ( i <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ // Remove the element
+ list.splice( i--, 1 );
+ // If we have some unicity property then
+ // we only need to do this once
+ if ( flags.unique ) {
+ break;
+ }
}
}
- if ( _fired ) {
- deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
- }
}
- return this;
- },
-
- // resolve with given context and args
- resolveWith: function( context, args ) {
- if ( !cancelled && !fired && !firing ) {
- // make sure args are available (#8421)
- args = args || [];
- firing = 1;
- try {
- while( callbacks[ 0 ] ) {
- callbacks.shift().apply( context, args );
- }
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ if ( list ) {
+ var i = 0,
+ length = list.length;
+ for ( ; i < length; i++ ) {
+ if ( fn === list[ i ] ) {
+ return true;
}
- finally {
- fired = [ context, args ];
- firing = 0;
+ }
+ }
+ return false;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory || memory === true ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( stack ) {
+ if ( firing ) {
+ if ( !flags.once ) {
+ stack.push( [ context, args ] );
}
+ } else if ( !( flags.once && memory ) ) {
+ fire( context, args );
}
- return this;
- },
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!memory;
+ }
+ };
- // resolve with this as context and given arguments
- resolve: function() {
- deferred.resolveWith( this, arguments );
- return this;
- },
+ return self;
+};
- // Has this deferred been resolved?
- isResolved: function() {
- return !!( firing || fired );
- },
- // Cancel
- cancel: function() {
- cancelled = 1;
- callbacks = [];
- return this;
- }
- };
- return deferred;
- },
- // Full fledged deferred (two callbacks list)
+var // Static reference to slice
+ sliceDeferred = [].slice;
+
+jQuery.extend({
+
Deferred: function( func ) {
- var deferred = jQuery._Deferred(),
- failDeferred = jQuery._Deferred(),
- promise;
- // Add errorDeferred methods, then and promise
- jQuery.extend( deferred, {
- then: function( doneCallbacks, failCallbacks ) {
- deferred.done( doneCallbacks ).fail( failCallbacks );
- return this;
- },
- always: function() {
- return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
+ var doneList = jQuery.Callbacks( "once memory" ),
+ failList = jQuery.Callbacks( "once memory" ),
+ progressList = jQuery.Callbacks( "memory" ),
+ state = "pending",
+ lists = {
+ resolve: doneList,
+ reject: failList,
+ notify: progressList
},
- fail: failDeferred.done,
- rejectWith: failDeferred.resolveWith,
- reject: failDeferred.resolve,
- isRejected: failDeferred.isResolved,
- pipe: function( fnDone, fnFail ) {
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( {
- done: [ fnDone, "resolve" ],
- fail: [ fnFail, "reject" ]
- }, function( handler, data ) {
- var fn = data[ 0 ],
- action = data[ 1 ],
- returned;
- if ( jQuery.isFunction( fn ) ) {
- deferred[ handler ](function() {
- returned = fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise().then( newDefer.resolve, newDefer.reject );
- } else {
- newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
- }
- });
- } else {
- deferred[ handler ]( newDefer[ action ] );
+ promise = {
+ done: doneList.add,
+ fail: failList.add,
+ progress: progressList.add,
+
+ state: function() {
+ return state;
+ },
+
+ // Deprecated
+ isResolved: doneList.fired,
+ isRejected: failList.fired,
+
+ then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
+ deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
+ return this;
+ },
+ always: function() {
+ deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
+ return this;
+ },
+ pipe: function( fnDone, fnFail, fnProgress ) {
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( {
+ done: [ fnDone, "resolve" ],
+ fail: [ fnFail, "reject" ],
+ progress: [ fnProgress, "notify" ]
+ }, function( handler, data ) {
+ var fn = data[ 0 ],
+ action = data[ 1 ],
+ returned;
+ if ( jQuery.isFunction( fn ) ) {
+ deferred[ handler ](function() {
+ returned = fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+ }
+ });
+ } else {
+ deferred[ handler ]( newDefer[ action ] );
+ }
+ });
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ if ( obj == null ) {
+ obj = promise;
+ } else {
+ for ( var key in promise ) {
+ obj[ key ] = promise[ key ];
}
- });
- }).promise();
- },
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- if ( obj == null ) {
- if ( promise ) {
- return promise;
}
- promise = obj = {};
+ return obj;
}
- var i = promiseMethods.length;
- while( i-- ) {
- obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
- }
- return obj;
- }
- });
- // Make sure only one callback list will be used
- deferred.done( failDeferred.cancel ).fail( deferred.cancel );
- // Unexpose cancel
- delete deferred.cancel;
+ },
+ deferred = promise.promise({}),
+ key;
+
+ for ( key in lists ) {
+ deferred[ key ] = lists[ key ].fire;
+ deferred[ key + "With" ] = lists[ key ].fireWith;
+ }
+
+ // Handle state
+ deferred.done( function() {
+ state = "resolved";
+ }, failList.disable, progressList.lock ).fail( function() {
+ state = "rejected";
+ }, doneList.disable, progressList.lock );
+
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
+
+ // All done!
return deferred;
},
// Deferred helper
when: function( firstParam ) {
- var args = arguments,
+ var args = sliceDeferred.call( arguments, 0 ),
i = 0,
length = args.length,
+ pValues = new Array( length ),
count = length,
+ pCount = length,
deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
firstParam :
- jQuery.Deferred();
+ jQuery.Deferred(),
+ promise = deferred.promise();
function resolveFunc( i ) {
return function( value ) {
args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
if ( !( --count ) ) {
- // Strange bug in FF4:
- // Values changed onto the arguments object sometimes end up as undefined values
- // outside the $.when method. Cloning the object into a fresh array solves the issue
- deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
+ deferred.resolveWith( deferred, args );
}
};
}
+ function progressFunc( i ) {
+ return function( value ) {
+ pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ deferred.notifyWith( promise, pValues );
+ };
+ }
if ( length > 1 ) {
- for( ; i < length; i++ ) {
- if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
- args[ i ].promise().then( resolveFunc(i), deferred.reject );
+ for ( ; i < length; i++ ) {
+ if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
+ args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
} else {
--count;
}
@@ -1149,39 +1321,35 @@ jQuery.extend({
} else if ( deferred !== firstParam ) {
deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
}
- return deferred.promise();
+ return promise;
}
});
+
jQuery.support = (function() {
- var div = document.createElement( "div" ),
- documentElement = document.documentElement,
+ var support,
all,
a,
select,
opt,
input,
marginDiv,
- support,
fragment,
- body,
- testElementParent,
- testElement,
- testElementStyle,
tds,
events,
eventName,
i,
- isSupported;
+ isSupported,
+ div = document.createElement( "div" ),
+ documentElement = document.documentElement;
// Preliminary tests
div.setAttribute("className", "t");
div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
all = div.getElementsByTagName( "*" );
a = div.getElementsByTagName( "a" )[ 0 ];
@@ -1201,11 +1369,11 @@ jQuery.support = (function() {
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
- tbody: !div.getElementsByTagName( "tbody" ).length,
+ tbody: !div.getElementsByTagName("tbody").length,
// Make sure that link elements get serialized correctly by innerHTML
// This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName( "link" ).length,
+ htmlSerialize: !!div.getElementsByTagName("link").length,
// Get the style information from getAttribute
// (IE uses .cssText instead)
@@ -1213,12 +1381,12 @@ jQuery.support = (function() {
// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
- hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
+ hrefNormalized: ( a.getAttribute("href") === "/a" ),
// Make sure that element opacity exists
// (IE uses filter instead)
// Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.55$/.test( a.style.opacity ),
+ opacity: /^0.55/.test( a.style.opacity ),
// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
@@ -1236,6 +1404,13 @@ jQuery.support = (function() {
// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
getSetAttribute: div.className !== "t",
+ // Tests for enctype support on a form(#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
// Will be defined later
submitBubbles: true,
changeBubbles: true,
@@ -1273,7 +1448,7 @@ jQuery.support = (function() {
div.cloneNode( true ).fireEvent( "onclick" );
}
- // Check if a radio maintains it's value
+ // Check if a radio maintains its value
// after being appended to the DOM
input = document.createElement("input");
input.value = "t";
@@ -1283,82 +1458,18 @@ jQuery.support = (function() {
input.setAttribute("checked", "checked");
div.appendChild( input );
fragment = document.createDocumentFragment();
- fragment.appendChild( div.firstChild );
+ fragment.appendChild( div.lastChild );
// WebKit doesn't clone checked state correctly in fragments
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
- div.innerHTML = "";
-
- // Figure out if the W3C box model works as expected
- div.style.width = div.style.paddingLeft = "1px";
-
- body = document.getElementsByTagName( "body" )[ 0 ];
- // We use our own, invisible, body unless the body is already present
- // in which case we use a div (#9239)
- testElement = document.createElement( body ? "div" : "body" );
- testElementStyle = {
- visibility: "hidden",
- width: 0,
- height: 0,
- border: 0,
- margin: 0,
- background: "none"
- };
- if ( body ) {
- jQuery.extend( testElementStyle, {
- position: "absolute",
- left: "-1000px",
- top: "-1000px"
- });
- }
- for ( i in testElementStyle ) {
- testElement.style[ i ] = testElementStyle[ i ];
- }
- testElement.appendChild( div );
- testElementParent = body || documentElement;
- testElementParent.insertBefore( testElement, testElementParent.firstChild );
-
// Check if a disconnected checkbox will retain its checked
// value of true after appended to the DOM (IE6/7)
support.appendChecked = input.checked;
- support.boxModel = div.offsetWidth === 2;
-
- if ( "zoom" in div.style ) {
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- // (IE < 8 does this)
- div.style.display = "inline";
- div.style.zoom = 1;
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
-
- // Check if elements with layout shrink-wrap their children
- // (IE 6 does this)
- div.style.display = "";
- div.innerHTML = "<div style='width:4px;'></div>";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
- }
-
- div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
- tds = div.getElementsByTagName( "td" );
+ fragment.removeChild( input );
+ fragment.appendChild( div );
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- // (only IE 8 fails this test)
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Check if empty table cells still have offsetWidth/Height
- // (IE < 8 fail this test)
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
div.innerHTML = "";
// Check if div with explicit width and no margin-right incorrectly
@@ -1366,21 +1477,18 @@ jQuery.support = (function() {
// info see bug #3333
// Fails in WebKit before Feb 2011 nightlies
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ if ( window.getComputedStyle ) {
marginDiv = document.createElement( "div" );
marginDiv.style.width = "0";
marginDiv.style.marginRight = "0";
+ div.style.width = "2px";
div.appendChild( marginDiv );
support.reliableMarginRight =
- ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+ ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
}
- // Remove the body element we added
- testElement.innerHTML = "";
- testElementParent.removeChild( testElement );
-
// Technique from Juriy Zaytsev
- // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+ // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
// We only care about the case where non-standard event systems
// are used, namely in IE. Short-circuiting here helps us to
// avoid an eval call (in setAttribute) which can cause CSP
@@ -1390,7 +1498,7 @@ jQuery.support = (function() {
submit: 1,
change: 1,
focusin: 1
- } ) {
+ }) {
eventName = "on" + i;
isSupported = ( eventName in div );
if ( !isSupported ) {
@@ -1401,15 +1509,111 @@ jQuery.support = (function() {
}
}
- // Null connected elements to avoid leaks in IE
- testElement = fragment = select = opt = body = marginDiv = div = input = null;
+ fragment.removeChild( div );
+
+ // Null elements to avoid leaks in IE
+ fragment = select = opt = marginDiv = div = input = null;
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, outer, inner, table, td, offsetSupport,
+ conMarginTop, ptlm, vb, style, html,
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ conMarginTop = 1;
+ ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";
+ vb = "visibility:hidden;border:0;";
+ style = "style='" + ptlm + "border:5px solid #000;padding:0;'";
+ html = "<div " + style + "><div></div></div>" +
+ "<table " + style + " cellpadding='0' cellspacing='0'>" +
+ "<tr><td></td></tr></table>";
+
+ container = document.createElement("div");
+ container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
+ body.insertBefore( container, body.firstChild );
+
+ // Construct the test element
+ div = document.createElement("div");
+ container.appendChild( div );
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName( "td" );
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE <= 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Figure out if the W3C box model works as expected
+ div.innerHTML = "";
+ div.style.width = div.style.paddingLeft = "1px";
+ jQuery.boxModel = support.boxModel = div.offsetWidth === 2;
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "";
+ div.innerHTML = "<div style='width:4px;'></div>";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
+ }
+
+ div.style.cssText = ptlm + vb;
+ div.innerHTML = html;
+
+ outer = div.firstChild;
+ inner = outer.firstChild;
+ td = outer.nextSibling.firstChild.firstChild;
+
+ offsetSupport = {
+ doesNotAddBorder: ( inner.offsetTop !== 5 ),
+ doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
+ };
+
+ inner.style.position = "fixed";
+ inner.style.top = "20px";
+
+ // safari subtracts parent border width here which is 5px
+ offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
+ inner.style.position = inner.style.top = "";
+
+ outer.style.overflow = "hidden";
+ outer.style.position = "relative";
+
+ offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
+ offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+
+ body.removeChild( container );
+ div = container = null;
+
+ jQuery.extend( support, offsetSupport );
+ });
return support;
})();
-// Keep track of boxModel
-jQuery.boxModel = jQuery.support.boxModel;
-
@@ -1437,7 +1641,6 @@ jQuery.extend({
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-
return !!elem && !isEmptyDataObject( elem );
},
@@ -1446,7 +1649,7 @@ jQuery.extend({
return;
}
- var thisCache, ret,
+ var privateCache, thisCache, ret,
internalKey = jQuery.expando,
getByName = typeof name === "string",
@@ -1460,11 +1663,12 @@ jQuery.extend({
// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
+ isEvents = name === "events";
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
- if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) {
+ if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
@@ -1472,18 +1676,17 @@ jQuery.extend({
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
- elem[ jQuery.expando ] = id = ++jQuery.uuid;
+ elem[ internalKey ] = id = ++jQuery.uuid;
} else {
- id = jQuery.expando;
+ id = internalKey;
}
}
if ( !cache[ id ] ) {
cache[ id ] = {};
- // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
- // metadata on plain JS objects when the object is serialized using
- // JSON.stringify
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
@@ -1493,34 +1696,33 @@ jQuery.extend({
// shallow copied over onto the existing cache
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
- cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+ cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
- cache[ id ] = jQuery.extend(cache[ id ], name);
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
- thisCache = cache[ id ];
+ privateCache = thisCache = cache[ id ];
- // Internal jQuery data is stored in a separate object inside the object's data
+ // jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
- // data
- if ( pvt ) {
- if ( !thisCache[ internalKey ] ) {
- thisCache[ internalKey ] = {};
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
}
- thisCache = thisCache[ internalKey ];
+ thisCache = thisCache.data;
}
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
- // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
- // not attempt to inspect the internal events object using jQuery.data, as this
- // internal data object is undocumented and subject to change.
- if ( name === "events" && !thisCache[name] ) {
- return thisCache[ internalKey ] && thisCache[ internalKey ].events;
+ // Users should not attempt to inspect the internal events object using jQuery.data,
+ // it is undocumented and subject to change. But does anyone listen? No.
+ if ( isEvents && !thisCache[ name ] ) {
+ return privateCache.events;
}
// Check for both converted-to-camel and non-converted data property names
@@ -1548,7 +1750,7 @@ jQuery.extend({
return;
}
- var thisCache,
+ var thisCache, i, l,
// Reference to internal data cache key
internalKey = jQuery.expando,
@@ -1559,7 +1761,7 @@ jQuery.extend({
cache = isNode ? jQuery.cache : elem,
// See jQuery.data for more information
- id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+ id = isNode ? elem[ internalKey ] : internalKey;
// If there is already no cache entry for this object, there is no
// purpose in continuing
@@ -1569,28 +1771,43 @@ jQuery.extend({
if ( name ) {
- thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
if ( thisCache ) {
- // Support interoperable removal of hyphenated or camelcased keys
- if ( !thisCache[ name ] ) {
- name = jQuery.camelCase( name );
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split( " " );
+ }
+ }
}
- delete thisCache[ name ];
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
- if ( !isEmptyDataObject(thisCache) ) {
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
return;
}
}
}
// See jQuery.data for more information
- if ( pvt ) {
- delete cache[ id ][ internalKey ];
+ if ( !pvt ) {
+ delete cache[ id ].data;
// Don't destroy the parent cache unless the internal data object
// had been the only thing left in it
@@ -1599,8 +1816,6 @@ jQuery.extend({
}
}
- var internalCache = cache[ id ][ internalKey ];
-
// Browsers that fail expando deletion also refuse to delete expandos on
// the window, but it will allow it on all other JS objects; other browsers
// don't care
@@ -1611,32 +1826,18 @@ jQuery.extend({
cache[ id ] = null;
}
- // We destroyed the entire user cache at once because it's faster than
- // iterating through each key, but we need to continue to persist internal
- // data if it existed
- if ( internalCache ) {
- cache[ id ] = {};
- // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
- // metadata on plain JS objects when the object is serialized using
- // JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
-
- cache[ id ][ internalKey ] = internalCache;
-
- // Otherwise, we need to eliminate the expando on the node to avoid
+ // We destroyed the cache and need to eliminate the expando on the node to avoid
// false lookups in the cache for entries that no longer exist
- } else if ( isNode ) {
+ if ( isNode ) {
// IE does not allow us to delete expando properties from nodes,
// nor does it have a removeAttribute function on Document nodes;
// we must handle all of these cases
if ( jQuery.support.deleteExpando ) {
- delete elem[ jQuery.expando ];
+ delete elem[ internalKey ];
} else if ( elem.removeAttribute ) {
- elem.removeAttribute( jQuery.expando );
+ elem.removeAttribute( internalKey );
} else {
- elem[ jQuery.expando ] = null;
+ elem[ internalKey ] = null;
}
}
},
@@ -1662,14 +1863,15 @@ jQuery.extend({
jQuery.fn.extend({
data: function( key, value ) {
- var data = null;
+ var parts, attr, name,
+ data = null;
if ( typeof key === "undefined" ) {
if ( this.length ) {
data = jQuery.data( this[0] );
- if ( this[0].nodeType === 1 ) {
- var attr = this[0].attributes, name;
+ if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
+ attr = this[0].attributes;
for ( var i = 0, l = attr.length; i < l; i++ ) {
name = attr[i].name;
@@ -1679,6 +1881,7 @@ jQuery.fn.extend({
dataAttr( this[0], name, data[ name ] );
}
}
+ jQuery._data( this[0], "parsedAttrs", true );
}
}
@@ -1690,7 +1893,7 @@ jQuery.fn.extend({
});
}
- var parts = key.split(".");
+ parts = key.split(".");
parts[1] = parts[1] ? "." + parts[1] : "";
if ( value === undefined ) {
@@ -1708,12 +1911,12 @@ jQuery.fn.extend({
} else {
return this.each(function() {
- var $this = jQuery( this ),
+ var self = jQuery( this ),
args = [ parts[0], value ];
- $this.triggerHandler( "setData" + parts[1] + "!", args );
+ self.triggerHandler( "setData" + parts[1] + "!", args );
jQuery.data( this, key, value );
- $this.triggerHandler( "changeData" + parts[1] + "!", args );
+ self.triggerHandler( "changeData" + parts[1] + "!", args );
});
}
},
@@ -1739,7 +1942,7 @@ function dataAttr( elem, key, data ) {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
- !jQuery.isNaN( data ) ? parseFloat( data ) :
+ jQuery.isNumeric( data ) ? parseFloat( data ) :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch( e ) {}
@@ -1755,11 +1958,14 @@ function dataAttr( elem, key, data ) {
return data;
}
-// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
-// property to be considered empty objects; this property always exists in
-// order to make sure JSON.stringify does not expose internal metadata
+// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
for ( var name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
if ( name !== "toJSON" ) {
return false;
}
@@ -1775,17 +1981,17 @@ function handleQueueMarkDefer( elem, type, src ) {
var deferDataKey = type + "defer",
queueDataKey = type + "queue",
markDataKey = type + "mark",
- defer = jQuery.data( elem, deferDataKey, undefined, true );
+ defer = jQuery._data( elem, deferDataKey );
if ( defer &&
- ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
- ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
+ ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
+ ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
// Give room for hard-coded callbacks to fire first
// and eventually mark/queue something else on the element
setTimeout( function() {
- if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
- !jQuery.data( elem, markDataKey, undefined, true ) ) {
+ if ( !jQuery._data( elem, queueDataKey ) &&
+ !jQuery._data( elem, markDataKey ) ) {
jQuery.removeData( elem, deferDataKey, true );
- defer.resolve();
+ defer.fire();
}
}, 0 );
}
@@ -1795,8 +2001,8 @@ jQuery.extend({
_mark: function( elem, type ) {
if ( elem ) {
- type = (type || "fx") + "mark";
- jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
+ type = ( type || "fx" ) + "mark";
+ jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
}
},
@@ -1809,9 +2015,9 @@ jQuery.extend({
if ( elem ) {
type = type || "fx";
var key = type + "mark",
- count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
+ count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
if ( count ) {
- jQuery.data( elem, key, count, true );
+ jQuery._data( elem, key, count );
} else {
jQuery.removeData( elem, key, true );
handleQueueMarkDefer( elem, type, "mark" );
@@ -1820,13 +2026,15 @@ jQuery.extend({
},
queue: function( elem, type, data ) {
+ var q;
if ( elem ) {
- type = (type || "fx") + "queue";
- var q = jQuery.data( elem, type, undefined, true );
+ type = ( type || "fx" ) + "queue";
+ q = jQuery._data( elem, type );
+
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !q || jQuery.isArray(data) ) {
- q = jQuery.data( elem, type, jQuery.makeArray(data), true );
+ q = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
q.push( data );
}
@@ -1840,7 +2048,7 @@ jQuery.extend({
var queue = jQuery.queue( elem, type ),
fn = queue.shift(),
- defer;
+ hooks = {};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
@@ -1851,16 +2059,17 @@ jQuery.extend({
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
- queue.unshift("inprogress");
+ queue.unshift( "inprogress" );
}
- fn.call(elem, function() {
- jQuery.dequeue(elem, type);
- });
+ jQuery._data( elem, type + ".run", hooks );
+ fn.call( elem, function() {
+ jQuery.dequeue( elem, type );
+ }, hooks );
}
if ( !queue.length ) {
- jQuery.removeData( elem, type + "queue", true );
+ jQuery.removeData( elem, type + "queue " + type + ".run", true );
handleQueueMarkDefer( elem, type, "queue" );
}
}
@@ -1892,14 +2101,14 @@ jQuery.fn.extend({
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
- return this.queue( type, function() {
- var elem = this;
- setTimeout(function() {
- jQuery.dequeue( elem, type );
- }, time );
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
});
},
clearQueue: function( type ) {
@@ -1930,9 +2139,9 @@ jQuery.fn.extend({
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
- jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+ jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
count++;
- tmp.done( resolve );
+ tmp.add( resolve );
}
}
resolve();
@@ -1950,7 +2159,8 @@ var rclass = /[\n\t\r]/g,
rfocusable = /^(?:button|input|object|select|textarea)$/i,
rclickable = /^a(?:rea)?$/i,
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
- nodeHook, boolHook;
+ getSetAttribute = jQuery.support.getSetAttribute,
+ nodeHook, boolHook, fixSpecified;
jQuery.fn.extend({
attr: function( name, value ) {
@@ -1962,11 +2172,11 @@ jQuery.fn.extend({
jQuery.removeAttr( this, name );
});
},
-
+
prop: function( name, value ) {
return jQuery.access( this, name, value, true, jQuery.prop );
},
-
+
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each(function() {
@@ -2025,7 +2235,7 @@ jQuery.fn.extend({
}
if ( (value && typeof value === "string") || value === undefined ) {
- classNames = (value || "").split( rspace );
+ classNames = ( value || "" ).split( rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
@@ -2086,8 +2296,10 @@ jQuery.fn.extend({
},
hasClass: function( selector ) {
- var className = " " + selector + " ";
- for ( var i = 0, l = this.length; i < l; i++ ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
return true;
}
@@ -2097,9 +2309,9 @@ jQuery.fn.extend({
},
val: function( value ) {
- var hooks, ret,
+ var hooks, ret, isFunction,
elem = this[0];
-
+
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
@@ -2110,17 +2322,17 @@ jQuery.fn.extend({
ret = elem.value;
- return typeof ret === "string" ?
+ return typeof ret === "string" ?
// handle most common string cases
- ret.replace(rreturn, "") :
+ ret.replace(rreturn, "") :
// handle cases where value is null/undef or number
ret == null ? "" : ret;
}
- return undefined;
+ return;
}
- var isFunction = jQuery.isFunction( value );
+ isFunction = jQuery.isFunction( value );
return this.each(function( i ) {
var self = jQuery(this), val;
@@ -2168,7 +2380,7 @@ jQuery.extend({
},
select: {
get: function( elem ) {
- var value,
+ var value, i, max, option,
index = elem.selectedIndex,
values = [],
options = elem.options,
@@ -2180,8 +2392,10 @@ jQuery.extend({
}
// Loop through all the selected options
- for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
- var option = options[ i ];
+ i = one ? index : 0;
+ max = one ? index + 1 : options.length;
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
// Don't return options that are disabled or in a disabled optgroup
if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
@@ -2233,18 +2447,14 @@ jQuery.extend({
height: true,
offset: true
},
-
- attrFix: {
- // Always normalize to ensure hook usage
- tabindex: "tabIndex"
- },
-
+
attr: function( elem, name, value, pass ) {
- var nType = elem.nodeType;
-
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
// don't get/set attributes on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return undefined;
+ return;
}
if ( pass && name in jQuery.attrFn ) {
@@ -2252,36 +2462,24 @@ jQuery.extend({
}
// Fallback to prop when attributes are not supported
- if ( !("getAttribute" in elem) ) {
+ if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
- var ret, hooks,
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
- // Normalize the name if needed
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
if ( notxml ) {
- name = jQuery.attrFix[ name ] || name;
-
- hooks = jQuery.attrHooks[ name ];
-
- if ( !hooks ) {
- // Use boolHook for boolean attributes
- if ( rboolean.test( name ) ) {
- hooks = boolHook;
-
- // Use nodeHook if available( IE6/7 )
- } else if ( nodeHook ) {
- hooks = nodeHook;
- }
- }
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
}
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
- return undefined;
+ return;
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
@@ -2305,17 +2503,29 @@ jQuery.extend({
}
},
- removeAttr: function( elem, name ) {
- var propName;
- if ( elem.nodeType === 1 ) {
- name = jQuery.attrFix[ name ] || name;
+ removeAttr: function( elem, value ) {
+ var propName, attrNames, name, l,
+ i = 0;
+
+ if ( value && elem.nodeType === 1 ) {
+ attrNames = value.toLowerCase().split( rspace );
+ l = attrNames.length;
+
+ for ( ; i < l; i++ ) {
+ name = attrNames[ i ];
+
+ if ( name ) {
+ propName = jQuery.propFix[ name ] || name;
- jQuery.attr( elem, name, "" );
- elem.removeAttribute( name );
+ // See #9699 for explanation of this approach (setting first, then removal)
+ jQuery.attr( elem, name, "" );
+ elem.removeAttribute( getSetAttribute ? name : propName );
- // Set corresponding property to false for boolean attributes
- if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
- elem[ propName ] = false;
+ // Set corresponding property to false for boolean attributes
+ if ( rboolean.test( name ) && propName in elem ) {
+ elem[ propName ] = false;
+ }
+ }
}
}
},
@@ -2374,17 +2584,17 @@ jQuery.extend({
frameborder: "frameBorder",
contenteditable: "contentEditable"
},
-
+
prop: function( elem, name, value ) {
- var nType = elem.nodeType;
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
// don't get/set properties on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return undefined;
+ return;
}
- var ret, hooks,
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
if ( notxml ) {
// Fix name and attach hooks
@@ -2397,7 +2607,7 @@ jQuery.extend({
return ret;
} else {
- return (elem[ name ] = value);
+ return ( elem[ name ] = value );
}
} else {
@@ -2409,7 +2619,7 @@ jQuery.extend({
}
}
},
-
+
propHooks: {
tabIndex: {
get: function( elem ) {
@@ -2427,16 +2637,17 @@ jQuery.extend({
}
});
-// Add the tabindex propHook to attrHooks for back-compat
-jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex;
+// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
+jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
// Hook for boolean attributes
boolHook = {
get: function( elem, name ) {
// Align boolean attributes with corresponding properties
// Fall back to attribute presence where some booleans are not supported
- var attrNode;
- return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ?
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
name.toLowerCase() :
undefined;
},
@@ -2461,16 +2672,20 @@ boolHook = {
};
// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !jQuery.support.getSetAttribute ) {
-
+if ( !getSetAttribute ) {
+
+ fixSpecified = {
+ name: true,
+ id: true
+ };
+
// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = jQuery.valHooks.button = {
get: function( elem, name ) {
var ret;
ret = elem.getAttributeNode( name );
- // Return undefined if nodeValue is empty string
- return ret && ret.nodeValue !== "" ?
+ return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
ret.nodeValue :
undefined;
},
@@ -2481,10 +2696,13 @@ if ( !jQuery.support.getSetAttribute ) {
ret = document.createAttribute( name );
elem.setAttributeNode( ret );
}
- return (ret.nodeValue = value + "");
+ return ( ret.nodeValue = value + "" );
}
};
+ // Apply the nodeHook to tabindex
+ jQuery.attrHooks.tabindex.set = nodeHook.set;
+
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each([ "width", "height" ], function( i, name ) {
@@ -2497,6 +2715,18 @@ if ( !jQuery.support.getSetAttribute ) {
}
});
});
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ if ( value === "" ) {
+ value = "false";
+ }
+ nodeHook.set( elem, value, name );
+ }
+ };
}
@@ -2520,7 +2750,7 @@ if ( !jQuery.support.style ) {
return elem.style.cssText.toLowerCase() || undefined;
},
set: function( elem, value ) {
- return (elem.style.cssText = "" + value);
+ return ( elem.style.cssText = "" + value );
}
};
}
@@ -2545,6 +2775,11 @@ if ( !jQuery.support.optSelected ) {
});
}
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
// Radios and checkboxes getter/setter
if ( !jQuery.support.checkOn ) {
jQuery.each([ "radio", "checkbox" ], function() {
@@ -2560,7 +2795,7 @@ jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
set: function( elem, value ) {
if ( jQuery.isArray( value ) ) {
- return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
}
}
});
@@ -2569,116 +2804,118 @@ jQuery.each([ "radio", "checkbox" ], function() {
-var rnamespaces = /\.(.*)$/,
- rformElems = /^(?:textarea|input|select)$/i,
- rperiod = /\./g,
- rspaces = / /g,
- rescape = /[^\w\s.|`]/g,
- fcleanup = function( nm ) {
- return nm.replace(rescape, "\\$&");
+var rformElems = /^(?:textarea|input|select)$/i,
+ rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
+ rhoverHack = /\bhover(\.\S+)?\b/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
+ quickParse = function( selector ) {
+ var quick = rquickIs.exec( selector );
+ if ( quick ) {
+ // 0 1 2 3
+ // [ _, tag, id, class ]
+ quick[1] = ( quick[1] || "" ).toLowerCase();
+ quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
+ }
+ return quick;
+ },
+ quickIs = function( elem, m ) {
+ var attrs = elem.attributes || {};
+ return (
+ (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
+ (!m[2] || (attrs.id || {}).value === m[2]) &&
+ (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
+ );
+ },
+ hoverHack = function( events ) {
+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
};
/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code originated from
- * Dean Edwards' addEvent library.
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
*/
jQuery.event = {
- // Bind an event to an element
- // Original by Dean Edwards
- add: function( elem, types, handler, data ) {
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, quick, handlers, special;
- if ( handler === false ) {
- handler = returnFalse;
- } else if ( !handler ) {
- // Fixes bug #7229. Fix recommended by jdalton
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
return;
}
- var handleObjIn, handleObj;
-
+ // Caller can pass in an object of custom data in lieu of the handler
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
}
- // Make sure that the function being executed has a unique ID
+ // Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
- // Init the element's event structure
- var elemData = jQuery._data( elem );
-
- // If no elemData is found then we must be trying to bind to one of the
- // banned noData elements
- if ( !elemData ) {
- return;
- }
-
- var events = elemData.events,
- eventHandle = elemData.handle;
-
+ // Init the element's event structure and main handler, if this is the first
+ events = elemData.events;
if ( !events ) {
elemData.events = events = {};
}
-
+ eventHandle = elemData.handle;
if ( !eventHandle ) {
elemData.handle = eventHandle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
}
- // Add elem as a property of the handle function
- // This is to prevent a memory leak with non-native events in IE.
- eventHandle.elem = elem;
-
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
- types = types.split(" ");
+ types = jQuery.trim( hoverHack(types) ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
- var type, i = 0, namespaces;
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = ( tns[2] || "" ).split( "." ).sort();
- while ( (type = types[ i++ ]) ) {
- handleObj = handleObjIn ?
- jQuery.extend({}, handleObjIn) :
- { handler: handler, data: data };
-
- // Namespaced event handlers
- if ( type.indexOf(".") > -1 ) {
- namespaces = type.split(".");
- type = namespaces.shift();
- handleObj.namespace = namespaces.slice(0).sort().join(".");
-
- } else {
- namespaces = [];
- handleObj.namespace = "";
- }
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
- handleObj.type = type;
- if ( !handleObj.guid ) {
- handleObj.guid = handler.guid;
- }
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
- // Get the current list of functions bound to this event
- var handlers = events[ type ],
- special = jQuery.event.special[ type ] || {};
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
- // Init the event handler queue
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ quick: quickParse( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
if ( !handlers ) {
handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
- // Check for a special event handler
- // Only use addEventListener/attachEvent if the special
- // events handler returns false
+ // Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
@@ -2698,10 +2935,14 @@ jQuery.event = {
}
}
- // Add the function to the element's handler list
- handlers.push( handleObj );
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
- // Keep track of which events have been used, for event optimization
+ // Keep track of which events have ever been used, for event optimization
jQuery.event.global[ type ] = true;
}
@@ -2712,129 +2953,80 @@ jQuery.event = {
global: {},
// Detach an event or set of events from an element
- remove: function( elem, types, handler, pos ) {
- // don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- if ( handler === false ) {
- handler = returnFalse;
- }
+ remove: function( elem, types, handler, selector, mappedTypes ) {
- var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
- events = elemData && elemData.events;
+ var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ t, tns, type, origType, namespaces, origCount,
+ j, events, special, handle, eventType, handleObj;
- if ( !elemData || !events ) {
+ if ( !elemData || !(events = elemData.events) ) {
return;
}
- // types is actually an event object here
- if ( types && types.type ) {
- handler = types.handler;
- types = types.type;
- }
-
- // Unbind all events for the element
- if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
- types = types || "";
+ // Once for each type.namespace in types; type may be omitted
+ types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tns[1];
+ namespaces = tns[2];
- for ( type in events ) {
- jQuery.event.remove( elem, type + types );
- }
-
- return;
- }
-
- // Handle multiple events separated by a space
- // jQuery(...).unbind("mouseover mouseout", fn);
- types = types.split(" ");
-
- while ( (type = types[ i++ ]) ) {
- origType = type;
- handleObj = null;
- all = type.indexOf(".") < 0;
- namespaces = [];
-
- if ( !all ) {
- // Namespaced event handlers
- namespaces = type.split(".");
- type = namespaces.shift();
-
- namespace = new RegExp("(^|\\.)" +
- jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
- }
-
- eventType = events[ type ];
-
- if ( !eventType ) {
- continue;
- }
-
- if ( !handler ) {
- for ( j = 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
-
- if ( all || namespace.test( handleObj.namespace ) ) {
- jQuery.event.remove( elem, origType, handleObj.handler, j );
- eventType.splice( j--, 1 );
- }
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
}
-
continue;
}
special = jQuery.event.special[ type ] || {};
+ type = ( selector? special.delegateType : special.bindType ) || type;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
- for ( j = pos || 0; j < eventType.length; j++ ) {
+ // Remove matching events
+ for ( j = 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
- if ( handler.guid === handleObj.guid ) {
- // remove the given handler for the given type
- if ( all || namespace.test( handleObj.namespace ) ) {
- if ( pos == null ) {
- eventType.splice( j--, 1 );
- }
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ eventType.splice( j--, 1 );
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
+ if ( handleObj.selector ) {
+ eventType.delegateCount--;
}
-
- if ( pos != null ) {
- break;
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
}
}
}
- // remove generic event handler if no more handlers exist
- if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( eventType.length === 0 && origCount !== eventType.length ) {
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
- ret = null;
delete events[ type ];
}
}
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
- var handle = elemData.handle;
+ handle = elemData.handle;
if ( handle ) {
handle.elem = null;
}
- delete elemData.events;
- delete elemData.handle;
-
- if ( jQuery.isEmptyObject( elemData ) ) {
- jQuery.removeData( elem, undefined, true );
- }
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, [ "events", "handle" ], true );
}
},
-
+
// Events that are safe to short-circuit if no handlers are attached.
// Native DOM events should not be added, they may have inline handlers.
customEvent: {
@@ -2844,18 +3036,28 @@ jQuery.event = {
},
trigger: function( event, data, elem, onlyHandlers ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
// Event object or event type
var type = event.type || event,
namespaces = [],
- exclusive;
+ cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
- if ( type.indexOf("!") >= 0 ) {
+ if ( type.indexOf( "!" ) >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces)
type = type.slice(0, -1);
exclusive = true;
}
- if ( type.indexOf(".") >= 0 ) {
+ if ( type.indexOf( "." ) >= 0 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split(".");
type = namespaces.shift();
@@ -2877,230 +3079,299 @@ jQuery.event = {
new jQuery.Event( type );
event.type = type;
+ event.isTrigger = true;
event.exclusive = exclusive;
- event.namespace = namespaces.join(".");
- event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
-
- // triggerHandler() and global events don't bubble or run the default action
- if ( onlyHandlers || !elem ) {
- event.preventDefault();
- event.stopPropagation();
- }
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
// Handle a global trigger
if ( !elem ) {
+
// TODO: Stop taunting the data cache; remove global events and always attach to document
- jQuery.each( jQuery.cache, function() {
- // internalKey variable is just used to make it easier to find
- // and potentially change this stuff later; currently it just
- // points to jQuery.expando
- var internalKey = jQuery.expando,
- internalCache = this[ internalKey ];
- if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
- jQuery.event.trigger( event, data, internalCache.handle.elem );
+ cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
}
- });
- return;
- }
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ }
return;
}
// Clean up the event in case it is being reused
event.result = undefined;
- event.target = elem;
+ if ( !event.target ) {
+ event.target = elem;
+ }
// Clone any incoming data and prepend the event, creating the handler arg list
data = data != null ? jQuery.makeArray( data ) : [];
data.unshift( event );
- var cur = elem,
- // IE doesn't like method names with a colon (#3533, #8272)
- ontype = type.indexOf(":") < 0 ? "on" + type : "";
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ eventPath = [[ elem, special.bindType || type ]];
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
- // Fire event on the current element, then bubble up the DOM tree
- do {
- var handle = jQuery._data( cur, "handle" );
+ bubbleType = special.delegateType || type;
+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+ old = null;
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push([ cur, bubbleType ]);
+ old = cur;
+ }
- event.currentTarget = cur;
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( old && old === elem.ownerDocument ) {
+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+ }
+ }
+
+ // Fire handlers on the event path
+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+ cur = eventPath[i][0];
+ event.type = eventPath[i][1];
+
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
-
- // Trigger an inline bound script
- if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
- event.result = false;
+ // Note that this is a bare JS function and not a jQuery handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
event.preventDefault();
}
-
- // Bubble up to document, then to window
- cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
- } while ( cur && !event.isPropagationStopped() );
+ }
+ event.type = type;
// If nobody prevented the default action, do it now
- if ( !event.isDefaultPrevented() ) {
- var old,
- special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
- if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction)() check here because IE6/7 fails that test.
- // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
- try {
- if ( ontype && elem[ type ] ) {
- // Don't re-trigger an onFOO event when we call its FOO() method
- old = elem[ ontype ];
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
- if ( old ) {
- elem[ ontype ] = null;
- }
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
- jQuery.event.triggered = type;
- elem[ type ]();
+ if ( old ) {
+ elem[ ontype ] = null;
}
- } catch ( ieError ) {}
- if ( old ) {
- elem[ ontype ] = old;
- }
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
- jQuery.event.triggered = undefined;
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+ }
}
}
-
+
return event.result;
},
- handle: function( event ) {
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event || window.event );
- // Snapshot the handlers list since a called handler may add/remove events.
- var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
+
+ var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = [].slice.call( arguments, 0 ),
run_all = !event.exclusive && !event.namespace,
- args = Array.prototype.slice.call( arguments, 0 );
+ handlerQueue = [],
+ i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
- // Use the fix-ed Event rather than the (read-only) native event
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
args[0] = event;
- event.currentTarget = this;
-
- for ( var j = 0, l = handlers.length; j < l; j++ ) {
- var handleObj = handlers[ j ];
-
- // Triggered event must 1) be non-exclusive and have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event.
- if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- event.handler = handleObj.handler;
- event.data = handleObj.data;
- event.handleObj = handleObj;
-
- var ret = handleObj.handler.apply( this, args );
-
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
+ event.delegateTarget = this;
+
+ // Determine handlers that should run if there are delegated events
+ // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
+
+ // Pregenerate a single jQuery object for reuse with .is()
+ jqcur = jQuery(this);
+ jqcur.context = this.ownerDocument || this;
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+ selMatch = {};
+ matches = [];
+ jqcur[0] = cur;
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = (
+ handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
+ );
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
}
}
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
+ }
+ }
+ }
- if ( event.isImmediatePropagationStopped() ) {
- break;
+ // Add the remaining (directly-bound) handlers
+ if ( handlers.length > delegateCount ) {
+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+ }
+
+ // Run delegates first; they may want to stop propagation beneath us
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ event.currentTarget = matched.elem;
+
+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = matched.matches[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
}
}
}
+
return event.result;
},
- props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
- // store a copy of the original event object
- // and "clone" to set read-only properties
- var originalEvent = event;
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop,
+ originalEvent = event,
+ fixHook = jQuery.event.fixHooks[ event.type ] || {},
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
event = jQuery.Event( originalEvent );
- for ( var i = this.props.length, prop; i; ) {
- prop = this.props[ --i ];
+ for ( i = copy.length; i; ) {
+ prop = copy[ --i ];
event[ prop ] = originalEvent[ prop ];
}
- // Fix target property, if necessary
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
if ( !event.target ) {
- // Fixes #1925 where srcElement might not be defined either
- event.target = event.srcElement || document;
+ event.target = originalEvent.srcElement || document;
}
- // check if target is a textnode (safari)
+ // Target should not be a text node (#504, Safari)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && event.fromElement ) {
- event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
- }
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && event.clientX != null ) {
- var eventDocument = event.target.ownerDocument || document,
- doc = eventDocument.documentElement,
- body = eventDocument.body;
-
- event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
- event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
- }
-
- // Add which for key events
- if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
- event.which = event.charCode != null ? event.charCode : event.keyCode;
- }
-
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if ( !event.metaKey && event.ctrlKey ) {
+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+ if ( event.metaKey === undefined ) {
event.metaKey = event.ctrlKey;
}
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && event.button !== undefined ) {
- event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
- }
-
- return event;
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
},
- // Deprecated, use jQuery.guid instead
- guid: 1E8,
-
- // Deprecated, use jQuery.proxy instead
- proxy: jQuery.proxy,
-
special: {
ready: {
// Make sure the ready event is setup
- setup: jQuery.bindReady,
- teardown: jQuery.noop
+ setup: jQuery.bindReady
},
- live: {
- add: function( handleObj ) {
- jQuery.event.add( this,
- liveConvert( handleObj.origType, handleObj.selector ),
- jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
- },
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
- remove: function( handleObj ) {
- jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
- }
+ focus: {
+ delegateType: "focusin"
+ },
+ blur: {
+ delegateType: "focusout"
},
beforeunload: {
@@ -3117,9 +3388,35 @@ jQuery.event = {
}
}
}
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
}
};
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
jQuery.removeEvent = document.removeEventListener ?
function( elem, type, handle ) {
if ( elem.removeEventListener ) {
@@ -3134,7 +3431,7 @@ jQuery.removeEvent = document.removeEventListener ?
jQuery.Event = function( src, props ) {
// Allow instantiation without the 'new' keyword
- if ( !this.preventDefault ) {
+ if ( !(this instanceof jQuery.Event) ) {
return new jQuery.Event( src, props );
}
@@ -3145,8 +3442,8 @@ jQuery.Event = function( src, props ) {
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
// Event type
} else {
@@ -3158,9 +3455,8 @@ jQuery.Event = function( src, props ) {
jQuery.extend( this, props );
}
- // timeStamp is buggy for some events on Firefox(#3843)
- // So we won't rely on the native value
- this.timeStamp = jQuery.now();
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
// Mark it as fixed
this[ jQuery.expando ] = true;
@@ -3216,216 +3512,130 @@ jQuery.Event.prototype = {
isImmediatePropagationStopped: returnFalse
};
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function( event ) {
-
- // Check if mouse(over|out) are still within the same parent element
- var related = event.relatedTarget,
- inside = false,
- eventType = event.type;
-
- event.type = event.data;
-
- if ( related !== this ) {
-
- if ( related ) {
- inside = jQuery.contains( this, related );
- }
-
- if ( !inside ) {
-
- jQuery.event.handle.apply( this, arguments );
-
- event.type = eventType;
- }
- }
-},
-
-// In case of event delegation, we only need to rename the event.type,
-// liveHandler will take care of the rest.
-delegate = function( event ) {
- event.type = event.data;
- jQuery.event.handle.apply( this, arguments );
-};
-
-// Create mouseenter and mouseleave events
+// Create mouseenter/leave events using mouseover/out and event-time checks
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
- setup: function( data ) {
- jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
- },
- teardown: function( data ) {
- jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector,
+ ret;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
}
};
});
-// submit delegation
+// IE submit delegation
if ( !jQuery.support.submitBubbles ) {
jQuery.event.special.submit = {
- setup: function( data, namespaces ) {
- if ( !jQuery.nodeName( this, "form" ) ) {
- jQuery.event.add(this, "click.specialSubmit", function( e ) {
- // Avoid triggering error on non-existent type attribute in IE VML (#7071)
- var elem = e.target,
- type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : "";
-
- if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
- trigger( "submit", this, arguments );
- }
- });
-
- jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
- var elem = e.target,
- type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : "";
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
- if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
- trigger( "submit", this, arguments );
- }
- });
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !form._submit_attached ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ });
+ form._submit_attached = true;
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
- } else {
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
- },
- teardown: function( namespaces ) {
- jQuery.event.remove( this, ".specialSubmit" );
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
}
};
-
}
-// change delegation, happens here so we have bind.
+// IE change delegation and checkbox/radio fix
if ( !jQuery.support.changeBubbles ) {
- var changeFilters,
-
- getVal = function( elem ) {
- var type = jQuery.nodeName( elem, "input" ) ? elem.type : "",
- val = elem.value;
-
- if ( type === "radio" || type === "checkbox" ) {
- val = elem.checked;
-
- } else if ( type === "select-multiple" ) {
- val = elem.selectedIndex > -1 ?
- jQuery.map( elem.options, function( elem ) {
- return elem.selected;
- }).join("-") :
- "";
-
- } else if ( jQuery.nodeName( elem, "select" ) ) {
- val = elem.selectedIndex;
- }
-
- return val;
- },
-
- testChange = function testChange( e ) {
- var elem = e.target, data, val;
-
- if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
- return;
- }
-
- data = jQuery._data( elem, "_change_data" );
- val = getVal(elem);
-
- // the current data will be also retrieved by beforeactivate
- if ( e.type !== "focusout" || elem.type !== "radio" ) {
- jQuery._data( elem, "_change_data", val );
- }
-
- if ( data === undefined || val === data ) {
- return;
- }
-
- if ( data != null || val ) {
- e.type = "change";
- e.liveFired = undefined;
- jQuery.event.trigger( e, arguments[1], elem );
- }
- };
-
jQuery.event.special.change = {
- filters: {
- focusout: testChange,
- beforedeactivate: testChange,
+ setup: function() {
- click: function( e ) {
- var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
-
- if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
- testChange.call( this, e );
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ jQuery.event.simulate( "change", this, event, true );
+ }
+ });
}
- },
-
- // Change has to be called before submit
- // Keydown will be called before keypress, which is used in submit-event delegation
- keydown: function( e ) {
- var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
- if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
- (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
- type === "select-multiple" ) {
- testChange.call( this, e );
+ if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ elem._change_attached = true;
}
- },
-
- // Beforeactivate happens also before the previous element is blurred
- // with this event you can't trigger a change event, but you can store
- // information
- beforeactivate: function( e ) {
- var elem = e.target;
- jQuery._data( elem, "_change_data", getVal(elem) );
- }
+ });
},
- setup: function( data, namespaces ) {
- if ( this.type === "file" ) {
- return false;
- }
+ handle: function( event ) {
+ var elem = event.target;
- for ( var type in changeFilters ) {
- jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
}
-
- return rformElems.test( this.nodeName );
},
- teardown: function( namespaces ) {
- jQuery.event.remove( this, ".specialChange" );
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
return rformElems.test( this.nodeName );
}
};
-
- changeFilters = jQuery.event.special.change.filters;
-
- // Handle when the input is .focus()'d
- changeFilters.focus = changeFilters.beforeactivate;
-}
-
-function trigger( type, elem, args ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- // Don't pass args or remember liveFired; they apply to the donor event.
- var event = jQuery.extend( {}, args[ 0 ] );
- event.type = type;
- event.originalEvent = {};
- event.liveFired = undefined;
- jQuery.event.handle.call( elem, event );
- if ( event.isDefaultPrevented() ) {
- args[ 0 ].preventDefault();
- }
}
// Create "bubbling" focus and blur events
@@ -3433,7 +3643,10 @@ if ( !jQuery.support.focusinBubbles ) {
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0;
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
jQuery.event.special[ fix ] = {
setup: function() {
@@ -3447,89 +3660,120 @@ if ( !jQuery.support.focusinBubbles ) {
}
}
};
-
- function handler( donor ) {
- // Donor event is always a native one; fix it and switch its type.
- // Let focusin/out handler cancel the donor focus/blur event.
- var e = jQuery.event.fix( donor );
- e.type = fix;
- e.originalEvent = {};
- jQuery.event.trigger( e, null, e.target );
- if ( e.isDefaultPrevented() ) {
- donor.preventDefault();
- }
- }
});
}
-jQuery.each(["bind", "one"], function( i, name ) {
- jQuery.fn[ name ] = function( type, data, fn ) {
- var handler;
+jQuery.fn.extend({
- // Handle object literals
- if ( typeof type === "object" ) {
- for ( var key in type ) {
- this[ name ](key, data, type[key], fn);
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
}
return this;
}
- if ( arguments.length === 2 || data === false ) {
- fn = data;
- data = undefined;
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
}
- if ( name === "one" ) {
- handler = function( event ) {
- jQuery( this ).unbind( event, handler );
- return fn.apply( this, arguments );
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
};
- handler.guid = fn.guid || jQuery.guid++;
- } else {
- handler = fn;
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
}
-
- if ( type === "unload" && name !== "one" ) {
- this.one( type, data, fn );
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.add( this[i], type, handler, data );
- }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on.call( this, types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ var handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
}
-
- return this;
- };
-});
-
-jQuery.fn.extend({
- unbind: function( type, fn ) {
- // Handle object literals
- if ( typeof type === "object" && !type.preventDefault ) {
- for ( var key in type ) {
- this.unbind(key, type[key]);
- }
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.remove( this[i], type, fn );
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( var type in types ) {
+ this.off( type, selector, types[ type ] );
}
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
}
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
},
delegate: function( selector, types, data, fn ) {
- return this.live( types, data, fn, selector );
+ return this.on( types, selector, data, fn );
},
-
undelegate: function( selector, types, fn ) {
- if ( arguments.length === 0 ) {
- return this.unbind( "live" );
-
- } else {
- return this.die( types, null, fn, selector );
- }
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
},
trigger: function( type, data ) {
@@ -3537,7 +3781,6 @@ jQuery.fn.extend({
jQuery.event.trigger( type, data, this );
});
},
-
triggerHandler: function( type, data ) {
if ( this[0] ) {
return jQuery.event.trigger( type, data, this[0], true );
@@ -3551,8 +3794,8 @@ jQuery.fn.extend({
i = 0,
toggler = function( event ) {
// Figure out which function to execute
- var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
@@ -3575,178 +3818,9 @@ jQuery.fn.extend({
}
});
-var liveMap = {
- focus: "focusin",
- blur: "focusout",
- mouseenter: "mouseover",
- mouseleave: "mouseout"
-};
-
-jQuery.each(["live", "die"], function( i, name ) {
- jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
- var type, i = 0, match, namespaces, preType,
- selector = origSelector || this.selector,
- context = origSelector ? this : jQuery( this.context );
-
- if ( typeof types === "object" && !types.preventDefault ) {
- for ( var key in types ) {
- context[ name ]( key, data, types[key], selector );
- }
-
- return this;
- }
-
- if ( name === "die" && !types &&
- origSelector && origSelector.charAt(0) === "." ) {
-
- context.unbind( origSelector );
-
- return this;
- }
-
- if ( data === false || jQuery.isFunction( data ) ) {
- fn = data || returnFalse;
- data = undefined;
- }
-
- types = (types || "").split(" ");
-
- while ( (type = types[ i++ ]) != null ) {
- match = rnamespaces.exec( type );
- namespaces = "";
-
- if ( match ) {
- namespaces = match[0];
- type = type.replace( rnamespaces, "" );
- }
-
- if ( type === "hover" ) {
- types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
- continue;
- }
-
- preType = type;
-
- if ( liveMap[ type ] ) {
- types.push( liveMap[ type ] + namespaces );
- type = type + namespaces;
-
- } else {
- type = (liveMap[ type ] || type) + namespaces;
- }
-
- if ( name === "live" ) {
- // bind live handler
- for ( var j = 0, l = context.length; j < l; j++ ) {
- jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
- { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
- }
-
- } else {
- // unbind live handler
- context.unbind( "live." + liveConvert( type, selector ), fn );
- }
- }
-
- return this;
- };
-});
-
-function liveHandler( event ) {
- var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
- elems = [],
- selectors = [],
- events = jQuery._data( this, "events" );
-
- // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
- if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
- return;
- }
-
- if ( event.namespace ) {
- namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
- }
-
- event.liveFired = this;
-
- var live = events.live.slice(0);
-
- for ( j = 0; j < live.length; j++ ) {
- handleObj = live[j];
-
- if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
- selectors.push( handleObj.selector );
-
- } else {
- live.splice( j--, 1 );
- }
- }
-
- match = jQuery( event.target ).closest( selectors, event.currentTarget );
-
- for ( i = 0, l = match.length; i < l; i++ ) {
- close = match[i];
-
- for ( j = 0; j < live.length; j++ ) {
- handleObj = live[j];
-
- if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
- elem = close.elem;
- related = null;
-
- // Those two events require additional checking
- if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
- event.type = handleObj.preType;
- related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
-
- // Make sure not to accidentally match a child element with the same selector
- if ( related && jQuery.contains( elem, related ) ) {
- related = elem;
- }
- }
-
- if ( !related || related !== elem ) {
- elems.push({ elem: elem, handleObj: handleObj, level: close.level });
- }
- }
- }
- }
-
- for ( i = 0, l = elems.length; i < l; i++ ) {
- match = elems[i];
-
- if ( maxLevel && match.level > maxLevel ) {
- break;
- }
-
- event.currentTarget = match.elem;
- event.data = match.handleObj.data;
- event.handleObj = match.handleObj;
-
- ret = match.handleObj.origHandler.apply( match.elem, arguments );
-
- if ( ret === false || event.isPropagationStopped() ) {
- maxLevel = match.level;
-
- if ( ret === false ) {
- stop = false;
- }
- if ( event.isImmediatePropagationStopped() ) {
- break;
- }
- }
- }
-
- return stop;
-}
-
-function liveConvert( type, selector ) {
- return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
-}
-
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
@@ -3756,13 +3830,21 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
}
return arguments.length > 0 ?
- this.bind( name, data, fn ) :
+ this.on( name, null, data, fn ) :
this.trigger( name );
};
if ( jQuery.attrFn ) {
jQuery.attrFn[ name ] = true;
}
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+ }
});
@@ -3776,11 +3858,13 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
(function(){
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ expando = "sizcache" + (Math.random() + '').replace('.', ''),
done = 0,
toString = Object.prototype.toString,
hasDuplicate = false,
baseHasDuplicate = true,
rBackslash = /\\/g,
+ rReturn = /\r\n/g,
rNonWord = /\W/;
// Here we check if the JavaScript engine is using some sort of
@@ -3832,7 +3916,7 @@ var Sizzle = function( selector, context, results, seed ) {
if ( parts.length > 1 && origPOS.exec( selector ) ) {
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
- set = posProcess( parts[0] + parts[1], context );
+ set = posProcess( parts[0] + parts[1], context, seed );
} else {
set = Expr.relative[ parts[0] ] ?
@@ -3846,7 +3930,7 @@ var Sizzle = function( selector, context, results, seed ) {
selector += parts.shift();
}
- set = posProcess( selector, set );
+ set = posProcess( selector, set, seed );
}
}
@@ -3965,18 +4049,17 @@ Sizzle.matchesSelector = function( node, expr ) {
};
Sizzle.find = function( expr, context, isXML ) {
- var set;
+ var set, i, len, match, type, left;
if ( !expr ) {
return [];
}
- for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
- var match,
- type = Expr.order[i];
+ for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+ type = Expr.order[i];
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
- var left = match[1];
+ left = match[1];
match.splice( 1, 1 );
if ( left.substr( left.length - 1 ) !== "\\" ) {
@@ -4002,17 +4085,18 @@ Sizzle.find = function( expr, context, isXML ) {
Sizzle.filter = function( expr, set, inplace, not ) {
var match, anyFound,
+ type, found, item, filter, left,
+ i, pass,
old = expr,
result = [],
curLoop = set,
isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
while ( expr && set.length ) {
- for ( var type in Expr.filter ) {
+ for ( type in Expr.filter ) {
if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
- var found, item,
- filter = Expr.filter[ type ],
- left = match[1];
+ filter = Expr.filter[ type ];
+ left = match[1];
anyFound = false;
@@ -4038,10 +4122,10 @@ Sizzle.filter = function( expr, set, inplace, not ) {
}
if ( match ) {
- for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ for ( i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
found = filter( item, match, i, curLoop );
- var pass = not ^ !!found;
+ pass = not ^ found;
if ( inplace && found != null ) {
if ( pass ) {
@@ -4092,7 +4176,46 @@ Sizzle.filter = function( expr, set, inplace, not ) {
};
Sizzle.error = function( msg ) {
- throw "Syntax error, unrecognized expression: " + msg;
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Utility function for retreiving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+var getText = Sizzle.getText = function( elem ) {
+ var i, node,
+ nodeType = elem.nodeType,
+ ret = "";
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 ) {
+ // Use textContent || innerText for elements
+ if ( typeof elem.textContent === 'string' ) {
+ return elem.textContent;
+ } else if ( typeof elem.innerText === 'string' ) {
+ // Replace IE's carriage returns
+ return elem.innerText.replace( rReturn, '' );
+ } else {
+ // Traverse it's children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( i = 0; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ if ( node.nodeType !== 8 ) {
+ ret += getText( node );
+ }
+ }
+ }
+ return ret;
};
var Expr = Sizzle.selectors = {
@@ -4482,7 +4605,7 @@ var Expr = Sizzle.selectors = {
return filter( elem, i, match, array );
} else if ( name === "contains" ) {
- return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
+ return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
} else if ( name === "not" ) {
var not = match[3];
@@ -4501,7 +4624,10 @@ var Expr = Sizzle.selectors = {
},
CHILD: function( elem, match ) {
- var type = match[1],
+ var first, last,
+ doneName, parent, cache,
+ count, diff,
+ type = match[1],
node = elem;
switch ( type ) {
@@ -4529,18 +4655,18 @@ var Expr = Sizzle.selectors = {
return true;
case "nth":
- var first = match[2],
- last = match[3];
+ first = match[2];
+ last = match[3];
if ( first === 1 && last === 0 ) {
return true;
}
- var doneName = match[0],
- parent = elem.parentNode;
+ doneName = match[0];
+ parent = elem.parentNode;
- if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
- var count = 0;
+ if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
+ count = 0;
for ( node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType === 1 ) {
@@ -4548,10 +4674,10 @@ var Expr = Sizzle.selectors = {
}
}
- parent.sizcache = doneName;
+ parent[ expando ] = doneName;
}
- var diff = elem.nodeIndex - last;
+ diff = elem.nodeIndex - last;
if ( first === 0 ) {
return diff === 0;
@@ -4567,7 +4693,7 @@ var Expr = Sizzle.selectors = {
},
TAG: function( elem, match ) {
- return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+ return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
},
CLASS: function( elem, match ) {
@@ -4577,7 +4703,9 @@ var Expr = Sizzle.selectors = {
ATTR: function( elem, match ) {
var name = match[1],
- result = Expr.attrHandle[ name ] ?
+ result = Sizzle.attr ?
+ Sizzle.attr( elem, name ) :
+ Expr.attrHandle[ name ] ?
Expr.attrHandle[ name ]( elem ) :
elem[ name ] != null ?
elem[ name ] :
@@ -4588,6 +4716,8 @@ var Expr = Sizzle.selectors = {
return result == null ?
type === "!=" :
+ !type && Sizzle.attr ?
+ result != null :
type === "=" ?
value === check :
type === "*=" ?
@@ -4768,26 +4898,6 @@ if ( document.documentElement.compareDocumentPosition ) {
};
}
-// Utility function for retreiving the text value of an array of DOM nodes
-Sizzle.getText = function( elems ) {
- var ret = "", elem;
-
- for ( var i = 0; elems[i]; i++ ) {
- elem = elems[i];
-
- // Get the text from text nodes and CDATA nodes
- if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
- ret += elem.nodeValue;
-
- // Traverse everything else, except comment nodes
- } else if ( elem.nodeType !== 8 ) {
- ret += Sizzle.getText( elem.childNodes );
- }
- }
-
- return ret;
-};
-
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
@@ -5065,13 +5175,13 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
elem = elem[dir];
while ( elem ) {
- if ( elem.sizcache === doneName ) {
+ if ( elem[ expando ] === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 && !isXML ){
- elem.sizcache = doneName;
+ elem[ expando ] = doneName;
elem.sizset = i;
}
@@ -5098,14 +5208,14 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
elem = elem[dir];
while ( elem ) {
- if ( elem.sizcache === doneName ) {
+ if ( elem[ expando ] === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML ) {
- elem.sizcache = doneName;
+ elem[ expando ] = doneName;
elem.sizset = i;
}
@@ -5153,7 +5263,7 @@ Sizzle.isXML = function( elem ) {
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
-var posProcess = function( selector, context ) {
+var posProcess = function( selector, context, seed ) {
var match,
tmpSet = [],
later = "",
@@ -5169,13 +5279,16 @@ var posProcess = function( selector, context ) {
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
- Sizzle( selector, root[i], tmpSet );
+ Sizzle( selector, root[i], tmpSet, seed );
}
return Sizzle.filter( later, tmpSet );
};
// EXPOSE
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+Sizzle.selectors.attrMap = {};
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
@@ -5261,43 +5374,33 @@ jQuery.fn.extend({
},
is: function( selector ) {
- return !!selector && ( typeof selector === "string" ?
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ POS.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
},
closest: function( selectors, context ) {
var ret = [], i, l, cur = this[0];
- // Array
+ // Array (deprecated as of jQuery 1.7)
if ( jQuery.isArray( selectors ) ) {
- var match, selector,
- matches = {},
- level = 1;
-
- if ( cur && selectors.length ) {
- for ( i = 0, l = selectors.length; i < l; i++ ) {
- selector = selectors[i];
-
- if ( !matches[ selector ] ) {
- matches[ selector ] = POS.test( selector ) ?
- jQuery( selector, context || this.context ) :
- selector;
- }
- }
+ var level = 1;
- while ( cur && cur.ownerDocument && cur !== context ) {
- for ( selector in matches ) {
- match = matches[ selector ];
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( i = 0; i < selectors.length; i++ ) {
- if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
- ret.push({ selector: selector, elem: cur, level: level });
- }
+ if ( jQuery( cur ).is( selectors[ i ] ) ) {
+ ret.push({ selector: selectors[ i ], elem: cur, level: level });
}
-
- cur = cur.parentNode;
- level++;
}
+
+ cur = cur.parentNode;
+ level++;
}
return ret;
@@ -5414,12 +5517,7 @@ jQuery.each({
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
+ var ret = jQuery.map( this, fn, until );
if ( !runtil.test( name ) ) {
selector = until;
@@ -5435,7 +5533,7 @@ jQuery.each({
ret = ret.reverse();
}
- return this.pushStack( ret, name, args.join(",") );
+ return this.pushStack( ret, name, slice.call( arguments ).join(",") );
};
});
@@ -5504,7 +5602,7 @@ function winnow( elements, qualifier, keep ) {
} else if ( qualifier.nodeType ) {
return jQuery.grep(elements, function( elem, i ) {
- return (elem === qualifier) === keep;
+ return ( elem === qualifier ) === keep;
});
} else if ( typeof qualifier === "string" ) {
@@ -5520,20 +5618,38 @@ function winnow( elements, qualifier, keep ) {
}
return jQuery.grep(elements, function( elem, i ) {
- return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
});
}
-var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
rleadingWhitespace = /^\s+/,
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
rtagName = /<([\w:]+)/,
rtbody = /<tbody/i,
rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style)/i,
rnocache = /<(?:script|object|embed|option|style)/i,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")", "i"),
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
rscriptType = /\/(java|ecma)script/i,
@@ -5547,7 +5663,8 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
area: [ 1, "<map>", "</map>" ],
_default: [ 0, "", "" ]
- };
+ },
+ safeFragment = createSafeFragment( document );
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
@@ -5625,8 +5742,10 @@ jQuery.fn.extend({
},
wrap: function( html ) {
- return this.each(function() {
- jQuery( this ).wrapAll( html );
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
});
},
@@ -5660,7 +5779,7 @@ jQuery.fn.extend({
this.parentNode.insertBefore( elem, this );
});
} else if ( arguments.length ) {
- var set = jQuery(arguments[0]);
+ var set = jQuery.clean( arguments );
set.push.apply( set, this.toArray() );
return this.pushStack( set, "before", arguments );
}
@@ -5673,7 +5792,7 @@ jQuery.fn.extend({
});
} else if ( arguments.length ) {
var set = this.pushStack( this, "after", arguments );
- set.push.apply( set, jQuery(arguments[0]).toArray() );
+ set.push.apply( set, jQuery.clean(arguments) );
return set;
}
},
@@ -5728,7 +5847,7 @@ jQuery.fn.extend({
null;
// See if we can take a shortcut and just use innerHTML
- } else if ( typeof value === "string" && !rnocache.test( value ) &&
+ } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
@@ -5854,7 +5973,7 @@ jQuery.fn.extend({
// in certain situations (Bug #8070).
// Fragments from the fragment cache must always be cloned and never used
// in place.
- results.cacheable || (l > 1 && i < lastIndex) ?
+ results.cacheable || ( l > 1 && i < lastIndex ) ?
jQuery.clone( fragment, true, true ) :
fragment
);
@@ -5883,27 +6002,26 @@ function cloneCopyEvent( src, dest ) {
return;
}
- var internalKey = jQuery.expando,
- oldData = jQuery.data( src ),
- curData = jQuery.data( dest, oldData );
-
- // Switch to use the internal data object, if it exists, for the next
- // stage of data copying
- if ( (oldData = oldData[ internalKey ]) ) {
- var events = oldData.events;
- curData = curData[ internalKey ] = jQuery.extend({}, oldData);
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
- if ( events ) {
- delete curData.handle;
- curData.events = {};
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
- for ( var type in events ) {
- for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
- }
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
}
}
}
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
}
function cloneFixAttributes( src, dest ) {
@@ -5965,16 +6083,17 @@ function cloneFixAttributes( src, dest ) {
}
jQuery.buildFragment = function( args, nodes, scripts ) {
- var fragment, cacheable, cacheresults, doc;
-
- // nodes may contain either an explicit document object,
- // a jQuery collection or context object.
- // If nodes[0] contains a valid object to assign to doc
- if ( nodes && nodes[0] ) {
- doc = nodes[0].ownerDocument || nodes[0];
- }
+ var fragment, cacheable, cacheresults, doc,
+ first = args[ 0 ];
+
+ // nodes may contain either an explicit document object,
+ // a jQuery collection or context object.
+ // If nodes[0] contains a valid object to assign to doc
+ if ( nodes && nodes[0] ) {
+ doc = nodes[0].ownerDocument || nodes[0];
+ }
- // Ensure that an attr object doesn't incorrectly stand in as a document object
+ // Ensure that an attr object doesn't incorrectly stand in as a document object
// Chrome and Firefox seem to allow this to occur and will throw exception
// Fixes #8950
if ( !doc.createDocumentFragment ) {
@@ -5985,12 +6104,15 @@ jQuery.buildFragment = function( args, nodes, scripts ) {
// Cloning options loses the selected state, so don't cache them
// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
- if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
- args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
+ // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+ if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
+ first.charAt(0) === "<" && !rnocache.test( first ) &&
+ (jQuery.support.checkClone || !rchecked.test( first )) &&
+ (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
cacheable = true;
- cacheresults = jQuery.fragments[ args[0] ];
+ cacheresults = jQuery.fragments[ first ];
if ( cacheresults && cacheresults !== 1 ) {
fragment = cacheresults;
}
@@ -6002,7 +6124,7 @@ jQuery.buildFragment = function( args, nodes, scripts ) {
}
if ( cacheable ) {
- jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
+ jQuery.fragments[ first ] = cacheresults ? fragment : 1;
}
return { fragment: fragment, cacheable: cacheable };
@@ -6028,7 +6150,7 @@ jQuery.each({
} else {
for ( var i = 0, l = insert.length; i < l; i++ ) {
- var elems = (i > 0 ? this.clone(true) : this).get();
+ var elems = ( i > 0 ? this.clone(true) : this ).get();
jQuery( insert[i] )[ original ]( elems );
ret = ret.concat( elems );
}
@@ -6039,10 +6161,10 @@ jQuery.each({
});
function getAll( elem ) {
- if ( "getElementsByTagName" in elem ) {
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
return elem.getElementsByTagName( "*" );
- } else if ( "querySelectorAll" in elem ) {
+ } else if ( typeof elem.querySelectorAll !== "undefined" ) {
return elem.querySelectorAll( "*" );
} else {
@@ -6058,19 +6180,33 @@ function fixDefaultChecked( elem ) {
}
// Finds all inputs and passes them to fixDefaultChecked
function findInputs( elem ) {
- if ( jQuery.nodeName( elem, "input" ) ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "input" ) {
fixDefaultChecked( elem );
- } else if ( "getElementsByTagName" in elem ) {
+ // Skip scripts, get other children
+ } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
}
}
+// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
+function shimCloneNode( elem ) {
+ var div = document.createElement( "div" );
+ safeFragment.appendChild( div );
+
+ div.innerHTML = elem.outerHTML;
+ return div.firstChild;
+}
+
jQuery.extend({
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var clone = elem.cloneNode(true),
- srcElements,
- destElements,
- i;
+ var srcElements,
+ destElements,
+ i,
+ // IE<=8 does not properly clone detached, unknown element nodes
+ clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?
+ elem.cloneNode( true ) :
+ shimCloneNode( elem );
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
@@ -6082,8 +6218,7 @@ jQuery.extend({
cloneFixAttributes( elem, clone );
- // Using Sizzle here is crazy slow, so we use getElementsByTagName
- // instead
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
srcElements = getAll( elem );
destElements = getAll( clone );
@@ -6148,11 +6283,20 @@ jQuery.extend({
elem = elem.replace(rxhtmlTag, "<$1></$2>");
// Trim whitespace, otherwise indexOf won't work as expected
- var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
+ var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
wrap = wrapMap[ tag ] || wrapMap._default,
depth = wrap[0],
div = context.createElement("div");
+ // Append wrapper element to unknown element safe doc fragment
+ if ( context === document ) {
+ // Use the fragment we've already created for this document
+ safeFragment.appendChild( div );
+ } else {
+ // Use a fragment created with the owner document
+ createSafeFragment( context ).appendChild( div );
+ }
+
// Go to html and back, then peel off extra wrappers
div.innerHTML = wrap[1] + elem + wrap[2];
@@ -6233,7 +6377,9 @@ jQuery.extend({
},
cleanData: function( elems ) {
- var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
+ var data, id,
+ cache = jQuery.cache,
+ special = jQuery.event.special,
deleteExpando = jQuery.support.deleteExpando;
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
@@ -6244,7 +6390,7 @@ jQuery.extend({
id = elem[ jQuery.expando ];
if ( id ) {
- data = cache[ id ] && cache[ id ][ internalKey ];
+ data = cache[ id ];
if ( data && data.events ) {
for ( var type in data.events ) {
@@ -6506,7 +6652,7 @@ if ( !jQuery.support.opacity ) {
set: function( elem, value ) {
var style = elem.style,
currentStyle = elem.currentStyle,
- opacity = jQuery.isNaN( value ) ? "" : "alpha(opacity=" + value * 100 + ")",
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
filter = currentStyle && currentStyle.filter || style.filter || "";
// IE has trouble with opacity if it does not have layout
@@ -6563,11 +6709,8 @@ if ( document.defaultView && document.defaultView.getComputedStyle ) {
name = name.replace( rupper, "-$1" ).toLowerCase();
- if ( !(defaultView = elem.ownerDocument.defaultView) ) {
- return undefined;
- }
-
- if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+ if ( (defaultView = elem.ownerDocument.defaultView) &&
+ (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
ret = computedStyle.getPropertyValue( name );
if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
ret = jQuery.style( elem, name );
@@ -6580,25 +6723,32 @@ if ( document.defaultView && document.defaultView.getComputedStyle ) {
if ( document.documentElement.currentStyle ) {
currentStyle = function( elem, name ) {
- var left,
+ var left, rsLeft, uncomputed,
ret = elem.currentStyle && elem.currentStyle[ name ],
- rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
style = elem.style;
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret === null && style && (uncomputed = style[ name ]) ) {
+ ret = uncomputed;
+ }
+
// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+
// Remember the original values
left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
// Put in the new values to get a computed value out
if ( rsLeft ) {
elem.runtimeStyle.left = elem.currentStyle.left;
}
- style.left = name === "fontSize" ? "1em" : (ret || 0);
+ style.left = name === "fontSize" ? "1em" : ( ret || 0 );
ret = style.pixelLeft + "px";
// Revert the changed values
@@ -6618,20 +6768,22 @@ function getWH( elem, name, extra ) {
// Start with offset property
var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
- which = name === "width" ? cssWidth : cssHeight;
+ which = name === "width" ? cssWidth : cssHeight,
+ i = 0,
+ len = which.length;
if ( val > 0 ) {
if ( extra !== "border" ) {
- jQuery.each( which, function() {
+ for ( ; i < len; i++ ) {
if ( !extra ) {
- val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
+ val -= parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
}
if ( extra === "margin" ) {
- val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
+ val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
} else {
- val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
+ val -= parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
}
- });
+ }
}
return val + "px";
@@ -6647,15 +6799,15 @@ function getWH( elem, name, extra ) {
// Add padding, border, margin
if ( extra ) {
- jQuery.each( which, function() {
- val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
+ for ( ; i < len; i++ ) {
+ val += parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
if ( extra !== "padding" ) {
- val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
+ val += parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
}
if ( extra === "margin" ) {
- val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
+ val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
}
- });
+ }
}
return val + "px";
@@ -6666,7 +6818,7 @@ if ( jQuery.expr && jQuery.expr.filters ) {
var width = elem.offsetWidth,
height = elem.offsetHeight;
- return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
+ return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
};
jQuery.expr.filters.visible = function( elem ) {
@@ -6720,7 +6872,7 @@ var r20 = /%20/g,
// Document location segments
ajaxLocParts,
-
+
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
allTypes = ["*/"] + ["*"];
@@ -6759,7 +6911,7 @@ function addToPrefiltersOrTransports( structure ) {
placeBefore;
// For each dataType in the dataTypeExpression
- for(; i < length; i++ ) {
+ for ( ; i < length; i++ ) {
dataType = dataTypes[ i ];
// We control if we're asked to add before
// any existing element
@@ -6790,7 +6942,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX
executeOnly = ( structure === prefilters ),
selection;
- for(; i < length && ( executeOnly || !selection ); i++ ) {
+ for ( ; i < length && ( executeOnly || !selection ); i++ ) {
selection = list[ i ]( options, originalOptions, jqXHR );
// If we got redirected to another dataType
// we try there if executing only and not done already
@@ -6821,7 +6973,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX
function ajaxExtend( target, src ) {
var key, deep,
flatOptions = jQuery.ajaxSettings.flatOptions || {};
- for( key in src ) {
+ for ( key in src ) {
if ( src[ key ] !== undefined ) {
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
}
@@ -6938,7 +7090,7 @@ jQuery.fn.extend({
// Attach a bunch of functions for handling common AJAX events
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
jQuery.fn[ o ] = function( f ){
- return this.bind( o, f );
+ return this.on( o, f );
};
});
@@ -7080,7 +7232,7 @@ jQuery.extend({
jQuery( callbackContext ) : jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
- completeDeferred = jQuery._Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
// Status-dependent callbacks
statusCode = s.statusCode || {},
// ifModified key
@@ -7230,7 +7382,7 @@ jQuery.extend({
// We extract error from statusText
// then normalize statusText and status for non-aborts
error = statusText;
- if( !statusText || status ) {
+ if ( !statusText || status ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
@@ -7259,7 +7411,7 @@ jQuery.extend({
}
// Complete
- completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
@@ -7274,14 +7426,14 @@ jQuery.extend({
deferred.promise( jqXHR );
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
- jqXHR.complete = completeDeferred.done;
+ jqXHR.complete = completeDeferred.add;
// Status-dependent callbacks
jqXHR.statusCode = function( map ) {
if ( map ) {
var tmp;
if ( state < 2 ) {
- for( tmp in map ) {
+ for ( tmp in map ) {
statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
}
} else {
@@ -7358,7 +7510,7 @@ jQuery.extend({
ret = s.url.replace( rts, "$1_=" + ts );
// if nothing was replaced, add timestamp to the end
- s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+ s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
}
}
@@ -7432,7 +7584,7 @@ jQuery.extend({
done( -1, e );
// Simply rethrow otherwise
} else {
- jQuery.error( e );
+ throw e;
}
}
}
@@ -7536,7 +7688,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) {
firstDataType;
// Fill responseXXX fields
- for( type in responseFields ) {
+ for ( type in responseFields ) {
if ( type in responses ) {
jqXHR[ responseFields[type] ] = responses[ type ];
}
@@ -7615,13 +7767,13 @@ function ajaxConvert( s, response ) {
conv2;
// For each dataType in the chain
- for( i = 1; i < length; i++ ) {
+ for ( i = 1; i < length; i++ ) {
// Create converters map
// with lowercased keys
if ( i === 1 ) {
- for( key in s.converters ) {
- if( typeof key === "string" ) {
+ for ( key in s.converters ) {
+ if ( typeof key === "string" ) {
converters[ key.toLowerCase() ] = s.converters[ key ];
}
}
@@ -7632,7 +7784,7 @@ function ajaxConvert( s, response ) {
current = dataTypes[ i ];
// If current is auto dataType, update it to prev
- if( current === "*" ) {
+ if ( current === "*" ) {
current = prev;
// If no auto and dataTypes are actually different
} else if ( prev !== "*" && prev !== current ) {
@@ -7644,7 +7796,7 @@ function ajaxConvert( s, response ) {
// If there is no direct converter, search transitively
if ( !conv ) {
conv2 = undefined;
- for( conv1 in converters ) {
+ for ( conv1 in converters ) {
tmp = conv1.split( " " );
if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
conv2 = converters[ tmp[1] + " " + current ];
@@ -8083,11 +8235,11 @@ jQuery.fn.extend({
var elem, display;
if ( speed || speed === 0 ) {
- return this.animate( genFx("show", 3), speed, easing, callback);
+ return this.animate( genFx("show", 3), speed, easing, callback );
} else {
for ( var i = 0, j = this.length; i < j; i++ ) {
- elem = this[i];
+ elem = this[ i ];
if ( elem.style ) {
display = elem.style.display;
@@ -8101,8 +8253,8 @@ jQuery.fn.extend({
// Set elements which have been overridden with display: none
// in a stylesheet to whatever the default browser style is
// for such an element
- if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
- jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
+ if ( display === "" && jQuery.css(elem, "display") === "none" ) {
+ jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
}
}
}
@@ -8110,13 +8262,13 @@ jQuery.fn.extend({
// Set the display of most of the elements in a second loop
// to avoid the constant reflow
for ( i = 0; i < j; i++ ) {
- elem = this[i];
+ elem = this[ i ];
if ( elem.style ) {
display = elem.style.display;
if ( display === "" || display === "none" ) {
- elem.style.display = jQuery._data(elem, "olddisplay") || "";
+ elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
}
}
}
@@ -8130,12 +8282,17 @@ jQuery.fn.extend({
return this.animate( genFx("hide", 3), speed, easing, callback);
} else {
- for ( var i = 0, j = this.length; i < j; i++ ) {
- if ( this[i].style ) {
- var display = jQuery.css( this[i], "display" );
+ var elem, display,
+ i = 0,
+ j = this.length;
+
+ for ( ; i < j; i++ ) {
+ elem = this[i];
+ if ( elem.style ) {
+ display = jQuery.css( elem, "display" );
- if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
- jQuery._data( this[i], "olddisplay", display );
+ if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
+ jQuery._data( elem, "olddisplay", display );
}
}
}
@@ -8180,7 +8337,7 @@ jQuery.fn.extend({
},
animate: function( prop, speed, easing, callback ) {
- var optall = jQuery.speed(speed, easing, callback);
+ var optall = jQuery.speed( speed, easing, callback );
if ( jQuery.isEmptyObject( prop ) ) {
return this.each( optall.complete, [ false ] );
@@ -8189,7 +8346,7 @@ jQuery.fn.extend({
// Do not change referenced properties as per-property easing will be lost
prop = jQuery.extend( {}, prop );
- return this[ optall.queue === false ? "each" : "queue" ](function() {
+ function doAnimation() {
// XXX 'this' does not always have a nodeName when running the
// test suite
@@ -8200,9 +8357,9 @@ jQuery.fn.extend({
var opt = jQuery.extend( {}, optall ),
isElement = this.nodeType === 1,
hidden = isElement && jQuery(this).is(":hidden"),
- name, val, p,
- display, e,
- parts, start, end, unit;
+ name, val, p, e,
+ parts, start, end, unit,
+ method;
// will store per property easing and be used to determine when an animation is complete
opt.animatedProperties = {};
@@ -8238,25 +8395,17 @@ jQuery.fn.extend({
opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
// Set display property to inline-block for height/width
- // animations on inline elements that are having width/height
- // animated
+ // animations on inline elements that are having width/height animated
if ( jQuery.css( this, "display" ) === "inline" &&
jQuery.css( this, "float" ) === "none" ) {
- if ( !jQuery.support.inlineBlockNeedsLayout ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
this.style.display = "inline-block";
} else {
- display = defaultDisplay( this.nodeName );
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( display === "inline" ) {
- this.style.display = "inline-block";
-
- } else {
- this.style.display = "inline";
- this.style.zoom = 1;
- }
+ this.style.zoom = 1;
}
}
}
@@ -8270,8 +8419,17 @@ jQuery.fn.extend({
e = new jQuery.fx( this, opt, p );
val = prop[ p ];
- if ( rfxtypes.test(val) ) {
- e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
+ if ( rfxtypes.test( val ) ) {
+
+ // Tracks whether to show or hide based on private
+ // data attached to the element
+ method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
+ if ( method ) {
+ jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+ e[ method ]();
+ } else {
+ e[ val ]();
+ }
} else {
parts = rfxnum.exec( val );
@@ -8284,7 +8442,7 @@ jQuery.fn.extend({
// We need to compute starting value
if ( unit !== "px" ) {
jQuery.style( this, p, (end || 1) + unit);
- start = ((end || 1) / e.cur()) * start;
+ start = ( (end || 1) / e.cur() ) * start;
jQuery.style( this, p, start + unit);
}
@@ -8303,39 +8461,71 @@ jQuery.fn.extend({
// For JS strict compliance
return true;
- });
+ }
+
+ return optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
},
- stop: function( clearQueue, gotoEnd ) {
- if ( clearQueue ) {
- this.queue([]);
+ stop: function( type, clearQueue, gotoEnd ) {
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
}
- this.each(function() {
- var timers = jQuery.timers,
- i = timers.length;
+ return this.each(function() {
+ var index,
+ hadTimers = false,
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
// clear marker counters if we know they won't be
if ( !gotoEnd ) {
jQuery._unmark( true, this );
}
- while ( i-- ) {
- if ( timers[i].elem === this ) {
- if (gotoEnd) {
- // force the next step to be the last
- timers[i](true);
- }
- timers.splice(i, 1);
+ function stopQueue( elem, data, index ) {
+ var hooks = data[ index ];
+ jQuery.removeData( elem, index, true );
+ hooks.stop( gotoEnd );
+ }
+
+ if ( type == null ) {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
+ stopQueue( this, data, index );
+ }
}
+ } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
+ stopQueue( this, data, index );
}
- });
- // start the next in the queue if the last step wasn't forced
- if ( !gotoEnd ) {
- this.dequeue();
- }
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ if ( gotoEnd ) {
- return this;
+ // force the next step to be the last
+ timers[ index ]( true );
+ } else {
+ timers[ index ].saveState();
+ }
+ hadTimers = true;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( !( gotoEnd && hadTimers ) ) {
+ jQuery.dequeue( this, type );
+ }
+ });
}
});
@@ -8354,7 +8544,7 @@ function clearFxNow() {
function genFx( type, num ) {
var obj = {};
- jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
obj[ this ] = type;
});
@@ -8363,9 +8553,9 @@ function genFx( type, num ) {
// Generate shortcuts for custom animations
jQuery.each({
- slideDown: genFx("show", 1),
- slideUp: genFx("hide", 1),
- slideToggle: genFx("toggle", 1),
+ slideDown: genFx( "show", 1 ),
+ slideUp: genFx( "hide", 1 ),
+ slideToggle: genFx( "toggle", 1 ),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
@@ -8377,25 +8567,31 @@ jQuery.each({
jQuery.extend({
speed: function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
// Queueing
opt.old = opt.complete;
+
opt.complete = function( noUnmark ) {
if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
- if ( opt.queue !== false ) {
- jQuery.dequeue( this );
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
} else if ( noUnmark !== false ) {
jQuery._unmark( this );
}
@@ -8409,7 +8605,7 @@ jQuery.extend({
return firstNum + diff * p;
},
swing: function( p, n, firstNum, diff ) {
- return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum;
}
},
@@ -8432,12 +8628,12 @@ jQuery.fx.prototype = {
this.options.step.call( this.elem, this.now, this );
}
- (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+ ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
},
// Get the current size
cur: function() {
- if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+ if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
return this.elem[ this.prop ];
}
@@ -8455,17 +8651,22 @@ jQuery.fx.prototype = {
fx = jQuery.fx;
this.startTime = fxNow || createFxNow();
- this.start = from;
this.end = to;
- this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
- this.now = this.start;
+ this.now = this.start = from;
this.pos = this.state = 0;
+ this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
function t( gotoEnd ) {
- return self.step(gotoEnd);
+ return self.step( gotoEnd );
}
+ t.queue = this.options.queue;
t.elem = this.elem;
+ t.saveState = function() {
+ if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ }
+ };
if ( t() && jQuery.timers.push(t) && !timerId ) {
timerId = setInterval( fx.tick, fx.interval );
@@ -8474,14 +8675,20 @@ jQuery.fx.prototype = {
// Simple 'show' function
show: function() {
+ var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
+
// Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
this.options.show = true;
// Begin the animation
- // Make sure that we start at a small width/height to avoid any
- // flash of content
- this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+ // Make sure that we start at a small width/height to avoid any flash of content
+ if ( dataShow !== undefined ) {
+ // This show is picking up where a previous hide or show left off
+ this.custom( this.cur(), dataShow );
+ } else {
+ this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+ }
// Start by showing the element
jQuery( this.elem ).show();
@@ -8490,20 +8697,20 @@ jQuery.fx.prototype = {
// Simple 'hide' function
hide: function() {
// Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
this.options.hide = true;
// Begin the animation
- this.custom(this.cur(), 0);
+ this.custom( this.cur(), 0 );
},
// Each step of an animation
step: function( gotoEnd ) {
- var t = fxNow || createFxNow(),
+ var p, n, complete,
+ t = fxNow || createFxNow(),
done = true,
elem = this.elem,
- options = this.options,
- i, n;
+ options = this.options;
if ( gotoEnd || t >= options.duration + this.startTime ) {
this.now = this.end;
@@ -8512,8 +8719,8 @@ jQuery.fx.prototype = {
options.animatedProperties[ this.prop ] = true;
- for ( i in options.animatedProperties ) {
- if ( options.animatedProperties[i] !== true ) {
+ for ( p in options.animatedProperties ) {
+ if ( options.animatedProperties[ p ] !== true ) {
done = false;
}
}
@@ -8522,25 +8729,36 @@ jQuery.fx.prototype = {
// Reset the overflow
if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
- jQuery.each( [ "", "X", "Y" ], function (index, value) {
- elem.style[ "overflow" + value ] = options.overflow[index];
+ jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+ elem.style[ "overflow" + value ] = options.overflow[ index ];
});
}
// Hide the element if the "hide" operation was done
if ( options.hide ) {
- jQuery(elem).hide();
+ jQuery( elem ).hide();
}
// Reset the properties, if the item has been hidden or shown
if ( options.hide || options.show ) {
- for ( var p in options.animatedProperties ) {
- jQuery.style( elem, p, options.orig[p] );
+ for ( p in options.animatedProperties ) {
+ jQuery.style( elem, p, options.orig[ p ] );
+ jQuery.removeData( elem, "fxshow" + p, true );
+ // Toggle data is no longer needed
+ jQuery.removeData( elem, "toggle" + p, true );
}
}
// Execute the complete function
- options.complete.call( elem );
+ // in the event that the complete function throws an exception
+ // we must ensure it won't be called twice. #5684
+
+ complete = options.complete;
+ if ( complete ) {
+
+ options.complete = false;
+ complete.call( elem );
+ }
}
return false;
@@ -8554,8 +8772,8 @@ jQuery.fx.prototype = {
this.state = n / options.duration;
// Perform the easing function, defaults to swing
- this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );
- this.now = this.start + ((this.end - this.start) * this.pos);
+ this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+ this.now = this.start + ( (this.end - this.start) * this.pos );
}
// Perform the next step of the animation
this.update();
@@ -8567,9 +8785,15 @@ jQuery.fx.prototype = {
jQuery.extend( jQuery.fx, {
tick: function() {
- for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
- if ( !timers[i]() ) {
- timers.splice(i--, 1);
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
}
}
@@ -8599,7 +8823,7 @@ jQuery.extend( jQuery.fx, {
_default: function( fx ) {
if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
- fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
} else {
fx.elem[ fx.prop ] = fx.now;
}
@@ -8607,6 +8831,14 @@ jQuery.extend( jQuery.fx, {
}
});
+// Adds width/height step functions
+// Do not set anything below 0
+jQuery.each([ "width", "height" ], function( i, prop ) {
+ jQuery.fx.step[ prop ] = function( fx ) {
+ jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+ };
+});
+
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.animated = function( elem ) {
return jQuery.grep(jQuery.timers, function( fn ) {
@@ -8623,7 +8855,6 @@ function defaultDisplay( nodeName ) {
var body = document.body,
elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
display = elem.css( "display" );
-
elem.remove();
// If the simple way fails,
@@ -8651,7 +8882,6 @@ function defaultDisplay( nodeName ) {
iframeDoc.body.appendChild( elem );
display = jQuery.css( elem, "display" );
-
body.removeChild( iframe );
}
@@ -8728,8 +8958,6 @@ if ( "getBoundingClientRect" in document.documentElement ) {
return jQuery.offset.bodyOffset( elem );
}
- jQuery.offset.initialize();
-
var computedStyle,
offsetParent = elem.offsetParent,
prevOffsetParent = elem,
@@ -8742,7 +8970,7 @@ if ( "getBoundingClientRect" in document.documentElement ) {
left = elem.offsetLeft;
while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
- if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
break;
}
@@ -8754,7 +8982,7 @@ if ( "getBoundingClientRect" in document.documentElement ) {
top += elem.offsetTop;
left += elem.offsetLeft;
- if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+ if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
top += parseFloat( computedStyle.borderTopWidth ) || 0;
left += parseFloat( computedStyle.borderLeftWidth ) || 0;
}
@@ -8763,7 +8991,7 @@ if ( "getBoundingClientRect" in document.documentElement ) {
offsetParent = elem.offsetParent;
}
- if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+ if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
top += parseFloat( computedStyle.borderTopWidth ) || 0;
left += parseFloat( computedStyle.borderLeftWidth ) || 0;
}
@@ -8776,7 +9004,7 @@ if ( "getBoundingClientRect" in document.documentElement ) {
left += body.offsetLeft;
}
- if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
top += Math.max( docElem.scrollTop, body.scrollTop );
left += Math.max( docElem.scrollLeft, body.scrollLeft );
}
@@ -8786,46 +9014,12 @@ if ( "getBoundingClientRect" in document.documentElement ) {
}
jQuery.offset = {
- initialize: function() {
- var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
- html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-
- jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
-
- container.innerHTML = html;
- body.insertBefore( container, body.firstChild );
- innerDiv = container.firstChild;
- checkDiv = innerDiv.firstChild;
- td = innerDiv.nextSibling.firstChild.firstChild;
-
- this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
- this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
-
- checkDiv.style.position = "fixed";
- checkDiv.style.top = "20px";
-
- // safari subtracts parent border width here which is 5px
- this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
- checkDiv.style.position = checkDiv.style.top = "";
-
- innerDiv.style.overflow = "hidden";
- innerDiv.style.position = "relative";
-
- this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
-
- this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
-
- body.removeChild( container );
- jQuery.offset.initialize = jQuery.noop;
- },
bodyOffset: function( body ) {
var top = body.offsetTop,
left = body.offsetLeft;
- jQuery.offset.initialize();
-
- if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
+ if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
}
@@ -8845,7 +9039,7 @@ jQuery.offset = {
curOffset = curElem.offset(),
curCSSTop = jQuery.css( elem, "top" ),
curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
props = {}, curPosition = {}, curTop, curLeft;
// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
@@ -8862,11 +9056,11 @@ jQuery.offset = {
options = options.call( elem, i, curOffset );
}
- if (options.top != null) {
- props.top = (options.top - curOffset.top) + curTop;
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
}
- if (options.left != null) {
- props.left = (options.left - curOffset.left) + curLeft;
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
}
if ( "using" in options ) {
@@ -8879,6 +9073,7 @@ jQuery.offset = {
jQuery.fn.extend({
+
position: function() {
if ( !this[0] ) {
return null;
@@ -8981,16 +9176,20 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
// innerHeight and innerWidth
jQuery.fn[ "inner" + name ] = function() {
var elem = this[0];
- return elem && elem.style ?
+ return elem ?
+ elem.style ?
parseFloat( jQuery.css( elem, type, "padding" ) ) :
+ this[ type ]() :
null;
};
// outerHeight and outerWidth
jQuery.fn[ "outer" + name ] = function( margin ) {
var elem = this[0];
- return elem && elem.style ?
+ return elem ?
+ elem.style ?
parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+ this[ type ]() :
null;
};
@@ -9030,7 +9229,7 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
var orig = jQuery.css( elem, type ),
ret = parseFloat( orig );
- return jQuery.isNaN( ret ) ? orig : ret;
+ return jQuery.isNumeric( ret ) ? ret : orig;
// Set the width or height on the element (default to pixels if value is unitless)
} else {
@@ -9041,6 +9240,27 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
});
+
+
// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;
-})(window);
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+ define( "jquery", [], function () { return jQuery; } );
+}
+
+
+
+})( window );
diff --git a/resources/jquery/jquery.makeCollapsible.js b/resources/jquery/jquery.makeCollapsible.js
index a84f405c..7a1897ce 100644
--- a/resources/jquery/jquery.makeCollapsible.js
+++ b/resources/jquery/jquery.makeCollapsible.js
@@ -38,13 +38,13 @@ $.fn.makeCollapsible = function() {
if ( typeof $defaultToggle == 'undefined' ) {
$defaultToggle = null;
}
- if ( $defaultToggle !== null && !($defaultToggle instanceof jQuery) ) {
+ if ( $defaultToggle !== null && !($defaultToggle instanceof $) ) {
// is optional (may be undefined), but if defined it must be an instance of jQuery.
// If it's not, abort right away.
// After this $defaultToggle is either null or a valid jQuery instance.
return;
}
-
+
var $containers = null;
if ( action == 'collapse' ) {
@@ -55,17 +55,17 @@ $.fn.makeCollapsible = function() {
// Slide doens't work with tables, but fade does as of jQuery 1.1.3
// http://stackoverflow.com/questions/467336#920480
$containers = $collapsible.find( '>tbody>tr' );
- if ( $defaultToggle ) {
+ if ( $defaultToggle ) {
// Exclude tablerow containing togglelink
$containers.not( $defaultToggle.closest( 'tr' ) ).stop(true, true).fadeOut();
} else {
- if ( instantHide ) {
+ if ( instantHide ) {
$containers.hide();
} else {
$containers.stop( true, true ).fadeOut();
}
}
-
+
} else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
$containers = $collapsible.find( '> li' );
if ( $defaultToggle ) {
@@ -78,10 +78,10 @@ $.fn.makeCollapsible = function() {
$containers.stop( true, true ).slideUp();
}
}
-
+
} else { // <div>, <p> etc.
var $collapsibleContent = $collapsible.find( '> .mw-collapsible-content' );
-
+
// If a collapsible-content is defined, collapse it
if ( $collapsibleContent.length ) {
if ( instantHide ) {
@@ -102,7 +102,7 @@ $.fn.makeCollapsible = function() {
}
} else {
-
+
// Expand the element
if ( $collapsible.is( 'table' ) ) {
$containers = $collapsible.find( '>tbody>tr' );
@@ -112,7 +112,7 @@ $.fn.makeCollapsible = function() {
} else {
$containers.stop(true, true).fadeIn();
}
-
+
} else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
$containers = $collapsible.find( '> li' );
if ( $defaultToggle ) {
@@ -121,10 +121,10 @@ $.fn.makeCollapsible = function() {
} else {
$containers.stop( true, true ).slideDown();
}
-
+
} else { // <div>, <p> etc.
var $collapsibleContent = $collapsible.find( '> .mw-collapsible-content' );
-
+
// If a collapsible-content is defined, collapse it
if ( $collapsibleContent.length ) {
$collapsibleContent.slideDown();
@@ -147,7 +147,7 @@ $.fn.makeCollapsible = function() {
$collapsible = $that.closest( '.mw-collapsible.mw-made-collapsible' ).toggleClass( 'mw-collapsed' );
e.preventDefault();
e.stopPropagation();
-
+
// It's expanded right now
if ( !$that.hasClass( 'mw-collapsible-toggle-collapsed' ) ) {
// Change link to "Show"
@@ -182,7 +182,7 @@ $.fn.makeCollapsible = function() {
}
e.preventDefault();
e.stopPropagation();
-
+
// It's expanded right now
if ( !$that.hasClass( 'mw-collapsible-toggle-collapsed' ) ) {
// Change toggle to collapsed
@@ -210,7 +210,7 @@ $.fn.makeCollapsible = function() {
var action = $collapsible.hasClass( 'mw-collapsed' ) ? 'expand' : 'collapse';
$collapsible.toggleClass( 'mw-collapsed' );
toggleElement( $collapsible, action, $that );
-
+
};
// Use custom text or default ?
@@ -239,7 +239,7 @@ $.fn.makeCollapsible = function() {
} else {
$that.addClass( 'mw-made-collapsible' );
}
-
+
// Check if this element has a custom position for the toggle link
// (ie. outside the container or deeper inside the tree)
// Then: Locate the custom toggle link(s) and bind them
@@ -248,7 +248,7 @@ $.fn.makeCollapsible = function() {
var thatId = $that.attr( 'id' ),
$customTogglers = $( '.' + thatId.replace( 'mw-customcollapsible', 'mw-customtoggle' ) );
mw.log( _fn + 'Found custom collapsible: #' + thatId );
-
+
// Double check that there is actually a customtoggle link
if ( $customTogglers.length ) {
$customTogglers.bind( 'click.mw-collapse', function( e ) {
@@ -257,7 +257,7 @@ $.fn.makeCollapsible = function() {
} else {
mw.log( _fn + '#' + thatId + ': Missing toggler!' );
}
-
+
// Initial state
if ( $that.hasClass( 'mw-collapsed' ) ) {
$that.removeClass( 'mw-collapsed' );
@@ -265,7 +265,7 @@ $.fn.makeCollapsible = function() {
}
// If this is not a custom case, do the default:
- // Wrap the contents add the toggle link
+ // Wrap the contents add the toggle link
} else {
// Elements are treated differently
@@ -273,7 +273,7 @@ $.fn.makeCollapsible = function() {
// The toggle-link will be in one the the cells (td or th) of the first row
var $firstRowCells = $( 'tr:first th, tr:first td', that ),
$toggle = $firstRowCells.find( '> .mw-collapsible-toggle' );
-
+
// If theres no toggle link, add it to the last cell
if ( !$toggle.length ) {
$firstRowCells.eq(-1).prepend( $toggleLink );
@@ -282,19 +282,19 @@ $.fn.makeCollapsible = function() {
toggleLinkPremade( $toggle, e );
} );
}
-
+
} else if ( $that.is( 'ul' ) || $that.is( 'ol' ) ) {
// The toggle-link will be in the first list-item
var $firstItem = $( 'li:first', $that),
$toggle = $firstItem.find( '> .mw-collapsible-toggle' );
-
+
// If theres no toggle link, add it
if ( !$toggle.length ) {
// Make sure the numeral order doesn't get messed up, force the first (soon to be second) item
// to be "1". Except if the value-attribute is already used.
// If no value was set WebKit returns "", Mozilla returns '-1', others return null or undefined.
var firstval = $firstItem.attr( 'value' );
- if ( firstval === undefined || !firstval || firstval == '-1' ) {
+ if ( firstval === undefined || !firstval || firstval == '-1' ) {
$firstItem.attr( 'value', '1' );
}
$that.prepend( $toggleLink.wrap( '<li class="mw-collapsible-toggle-li"></li>' ).parent() );
@@ -303,9 +303,9 @@ $.fn.makeCollapsible = function() {
toggleLinkPremade( $toggle, e );
} );
}
-
+
} else { // <div>, <p> etc.
-
+
// The toggle-link will be the first child of the element
var $toggle = $that.find( '> .mw-collapsible-toggle' );
@@ -313,7 +313,7 @@ $.fn.makeCollapsible = function() {
if ( !$that.find( '> .mw-collapsible-content' ).length ) {
$that.wrapInner( '<div class="mw-collapsible-content"></div>' );
}
-
+
// If theres no toggle link, add it
if ( !$toggle.length ) {
$that.prepend( $toggleLink );
@@ -336,4 +336,4 @@ $.fn.makeCollapsible = function() {
}
} );
};
-} )( jQuery, mediaWiki ); \ No newline at end of file
+} )( jQuery, mediaWiki );
diff --git a/resources/jquery/jquery.messageBox.js b/resources/jquery/jquery.messageBox.js
index a69fca59..690fedd2 100644
--- a/resources/jquery/jquery.messageBox.js
+++ b/resources/jquery/jquery.messageBox.js
@@ -11,7 +11,7 @@
* @license CC-BY 3.0 <http://creativecommons.org/licenses/by/3.0>
* @license GPL2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
*/
-( function( $, mw ) {
+( function( $ ) {
// @return jQuery object of the message box
$.messageBoxNew = function( options ) {
options = $.extend( {
@@ -19,16 +19,16 @@ $.messageBoxNew = function( options ) {
'parent': 'body', // jQuery/CSS selector
'insert': 'prepend' // 'prepend' or 'append'
}, options );
- var $curBox = $( '#'+ options.id );
+ var $curBox = $( '#' + options.id );
// Only create a new box if it doesn't exist already
- if ( $curBox.size() > 0 ) {
+ if ( $curBox.length > 0 ) {
if ( $curBox.hasClass( 'js-messagebox' ) ) {
return $curBox;
} else {
return $curBox.addClass( 'js-messagebox' );
}
} else {
- var $newBox = $( '<div/>', {
+ var $newBox = $( '<div>', {
'id': options.id,
'class': 'js-messagebox',
'css': {
@@ -58,13 +58,13 @@ $.messageBox = function( options ) {
'group': 'default',
'replace': false, // if true replaces any previous message in this group
'target': 'js-messagebox'
- }, options );
+ }, options );
var $target = $.messageBoxNew( { id: options.target } );
var groupID = options.target + '-' + options.group;
var $group = $( '#' + groupID );
// Create group container if not existant
- if ( $group.size() < 1 ) {
- $group = $( '<div/>', {
+ if ( $group.length < 1 ) {
+ $group = $( '<div>', {
'id': groupID,
'class': 'js-messagebox-group'
});
@@ -79,12 +79,12 @@ $.messageBox = function( options ) {
$group.hide();
} else {
// Actual message addition
- $group.prepend( $( '<p/>' ).append( options.message ) ).show();
+ $group.prepend( $( '<p>' ).append( options.message ) ).show();
$target.slideDown();
}
// If the last visible group was just hidden, slide the entire box up
// Othere wise slideDown (if already visible nothing will happen)
- if ( $target.find( '> *:visible' ).size() === 0 ) {
+ if ( $target.find( '> *:visible' ).length === 0 ) {
// to avoid a sudden dissapearance of the last group followed by
// a slide up of only the outline, show it for a second
$group.show();
@@ -95,4 +95,4 @@ $.messageBox = function( options ) {
}
return $group;
};
-} )( jQuery, mediaWiki ); \ No newline at end of file
+} )( jQuery );
diff --git a/resources/jquery/jquery.mockjax.js b/resources/jquery/jquery.mockjax.js
new file mode 100644
index 00000000..5f6e1306
--- /dev/null
+++ b/resources/jquery/jquery.mockjax.js
@@ -0,0 +1,382 @@
+/*!
+ * MockJax - jQuery Plugin to Mock Ajax requests
+ *
+ * Version: 1.4.0
+ * Released: 2011-02-04
+ * Source: http://github.com/appendto/jquery-mockjax
+ * Docs: http://enterprisejquery.com/2010/07/mock-your-ajax-requests-with-mockjax-for-rapid-development
+ * Plugin: mockjax
+ * Author: Jonathan Sharp (http://jdsharp.com)
+ * License: MIT,GPL
+ *
+ * Copyright (c) 2010 appendTo LLC.
+ * Dual licensed under the MIT or GPL licenses.
+ * http://appendto.com/open-source-licenses
+ */
+(function($) {
+ var _ajax = $.ajax,
+ mockHandlers = [];
+
+ function parseXML(xml) {
+ if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
+ DOMParser = function() { };
+ DOMParser.prototype.parseFromString = function( xmlString ) {
+ var doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML( xmlString );
+ return doc;
+ };
+ }
+
+ try {
+ var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
+ if ( $.isXMLDoc( xmlDoc ) ) {
+ var err = $('parsererror', xmlDoc);
+ if ( err.length == 1 ) {
+ throw('Error: ' + $(xmlDoc).text() );
+ }
+ } else {
+ throw('Unable to parse XML');
+ }
+ } catch( e ) {
+ var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
+ $(document).trigger('xmlParseError', [ msg ]);
+ return undefined;
+ }
+ return xmlDoc;
+ }
+
+ $.extend({
+ ajax: function(origSettings) {
+ var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings),
+ mock = false;
+ // Iterate over our mock handlers (in registration order) until we find
+ // one that is willing to intercept the request
+ $.each(mockHandlers, function(k, v) {
+ if ( !mockHandlers[k] ) {
+ return;
+ }
+ var m = null;
+ // If the mock was registered with a function, let the function decide if we
+ // want to mock this request
+ if ( $.isFunction(mockHandlers[k]) ) {
+ m = mockHandlers[k](s);
+ } else {
+ m = mockHandlers[k];
+ // Inspect the URL of the request and check if the mock handler's url
+ // matches the url for this ajax request
+ if ( $.isFunction(m.url.test) ) {
+ // The user provided a regex for the url, test it
+ if ( !m.url.test( s.url ) ) {
+ m = null;
+ }
+ } else {
+ // Look for a simple wildcard '*' or a direct URL match
+ var star = m.url.indexOf('*');
+ if ( ( m.url != '*' && m.url != s.url && star == -1 ) ||
+ ( star > -1 && m.url.substr(0, star) != s.url.substr(0, star) ) ) {
+ // The url we tested did not match the wildcard *
+ m = null;
+ }
+ }
+ if ( m ) {
+ // Inspect the data submitted in the request (either POST body or GET query string)
+ if ( m.data && s.data ) {
+ var identical = false;
+ // Deep inspect the identity of the objects
+ (function ident(mock, live) {
+ // Test for situations where the data is a querystring (not an object)
+ if (typeof live === 'string') {
+ // Querystring may be a regex
+ identical = $.isFunction( mock.test ) ? mock.test(live) : mock == live;
+ return identical;
+ }
+ $.each(mock, function(k, v) {
+ if ( live[k] === undefined ) {
+ identical = false;
+ return false;
+ } else {
+ identical = true;
+ if ( typeof live[k] == 'object' ) {
+ return ident(mock[k], live[k]);
+ } else {
+ if ( $.isFunction( mock[k].test ) ) {
+ identical = mock[k].test(live[k]);
+ } else {
+ identical = ( mock[k] == live[k] );
+ }
+ return identical;
+ }
+ }
+ });
+ })(m.data, s.data);
+ // They're not identical, do not mock this request
+ if ( identical == false ) {
+ m = null;
+ }
+ }
+ // Inspect the request type
+ if ( m && m.type && m.type != s.type ) {
+ // The request type doesn't match (GET vs. POST)
+ m = null;
+ }
+ }
+ }
+ if ( m ) {
+ mock = true;
+
+ // Handle console logging
+ var c = $.extend({}, $.mockjaxSettings, m);
+ if ( c.log && $.isFunction(c.log) ) {
+ c.log('MOCK ' + s.type.toUpperCase() + ': ' + s.url, $.extend({}, s));
+ }
+
+ var jsre = /=\?(&|$)/, jsc = (new Date()).getTime();
+
+ // Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
+ // because there isn't an easy hook for the cross domain script tag of jsonp
+ if ( s.dataType === "jsonp" ) {
+ if ( s.type.toUpperCase() === "GET" ) {
+ if ( !jsre.test( s.url ) ) {
+ s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+ }
+ } else if ( !s.data || !jsre.test(s.data) ) {
+ s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+ }
+ s.dataType = "json";
+ }
+
+ // Build temporary JSONP function
+ if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
+ jsonp = s.jsonpCallback || ("jsonp" + jsc++);
+
+ // Replace the =? sequence both in the query string and the data
+ if ( s.data ) {
+ s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+ }
+
+ s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+ s.dataType = "script";
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = window[ jsonp ] || function( tmp ) {
+ data = tmp;
+ success();
+ complete();
+ // Garbage collect
+ window[ jsonp ] = undefined;
+
+ try {
+ delete window[ jsonp ];
+ } catch(e) {}
+
+ if ( head ) {
+ head.removeChild( script );
+ }
+ };
+ }
+
+ var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
+ parts = rurl.exec( s.url ),
+ remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
+
+ // Test if we are going to create a script tag (if so, intercept & mock)
+ if ( s.dataType === "script" && s.type.toUpperCase() === "GET" && remote ) {
+ // Synthesize the mock request for adding a script tag
+ var callbackContext = origSettings && origSettings.context || s;
+
+ function success() {
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success ) {
+ s.success.call( callbackContext, ( m.response ? m.response.toString() : m.responseText || ''), status, {} );
+ }
+
+ // Fire the global callback
+ if ( s.global ) {
+ trigger( "ajaxSuccess", [{}, s] );
+ }
+ }
+
+ function complete() {
+ // Process result
+ if ( s.complete ) {
+ s.complete.call( callbackContext, {} , status );
+ }
+
+ // The request was completed
+ if ( s.global ) {
+ trigger( "ajaxComplete", [{}, s] );
+ }
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+
+ function trigger(type, args) {
+ (s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
+ }
+
+ if ( m.response && $.isFunction(m.response) ) {
+ m.response(origSettings);
+ } else {
+ $.globalEval(m.responseText);
+ }
+ success();
+ complete();
+ return false;
+ }
+ mock = _ajax.call($, $.extend(true, {}, origSettings, {
+ // Mock the XHR object
+ xhr: function() {
+ // Extend with our default mockjax settings
+ m = $.extend({}, $.mockjaxSettings, m);
+
+ if ( m.contentType ) {
+ m.headers['content-type'] = m.contentType;
+ }
+
+ // Return our mock xhr object
+ return {
+ status: m.status,
+ readyState: 1,
+ open: function() { },
+ send: function() {
+ // This is a substitute for < 1.4 which lacks $.proxy
+ var process = (function(that) {
+ return function() {
+ return (function() {
+ // The request has returned
+ this.status = m.status;
+ this.readyState = 4;
+
+ // We have an executable function, call it to give
+ // the mock handler a chance to update it's data
+ if ( $.isFunction(m.response) ) {
+ m.response(origSettings);
+ }
+ // Copy over our mock to our xhr object before passing control back to
+ // jQuery's onreadystatechange callback
+ if ( s.dataType == 'json' && ( typeof m.responseText == 'object' ) ) {
+ this.responseText = JSON.stringify(m.responseText);
+ } else if ( s.dataType == 'xml' ) {
+ if ( typeof m.responseXML == 'string' ) {
+ this.responseXML = parseXML(m.responseXML);
+ } else {
+ this.responseXML = m.responseXML;
+ }
+ } else {
+ this.responseText = m.responseText;
+ }
+ // jQuery < 1.4 doesn't have onreadystate change for xhr
+ if ( $.isFunction(this.onreadystatechange) ) {
+ this.onreadystatechange( m.isTimeout ? 'timeout' : undefined );
+ }
+ }).apply(that);
+ };
+ })(this);
+
+ if ( m.proxy ) {
+ // We're proxying this request and loading in an external file instead
+ _ajax({
+ global: false,
+ url: m.proxy,
+ type: m.proxyType,
+ data: m.data,
+ dataType: s.dataType,
+ complete: function(xhr, txt) {
+ m.responseXML = xhr.responseXML;
+ m.responseText = xhr.responseText;
+ this.responseTimer = setTimeout(process, m.responseTime || 0);
+ }
+ });
+ } else {
+ // type == 'POST' || 'GET' || 'DELETE'
+ if ( s.async === false ) {
+ // TODO: Blocking delay
+ process();
+ } else {
+ this.responseTimer = setTimeout(process, m.responseTime || 50);
+ }
+ }
+ },
+ abort: function() {
+ clearTimeout(this.responseTimer);
+ },
+ setRequestHeader: function() { },
+ getResponseHeader: function(header) {
+ // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
+ if ( m.headers && m.headers[header] ) {
+ // Return arbitrary headers
+ return m.headers[header];
+ } else if ( header.toLowerCase() == 'last-modified' ) {
+ return m.lastModified || (new Date()).toString();
+ } else if ( header.toLowerCase() == 'etag' ) {
+ return m.etag || '';
+ } else if ( header.toLowerCase() == 'content-type' ) {
+ return m.contentType || 'text/plain';
+ }
+ },
+ getAllResponseHeaders: function() {
+ var headers = '';
+ $.each(m.headers, function(k, v) {
+ headers += k + ': ' + v + "\n";
+ });
+ return headers;
+ }
+ };
+ }
+ }));
+ return false;
+ }
+ });
+ // We don't have a mock request, trigger a normal request
+ if ( !mock ) {
+ return _ajax.apply($, arguments);
+ } else {
+ return mock;
+ }
+ }
+ });
+
+ $.mockjaxSettings = {
+ //url: null,
+ //type: 'GET',
+ log: function(msg) {
+ window['console'] && window.console.log && window.console.log(msg);
+ },
+ status: 200,
+ responseTime: 500,
+ isTimeout: false,
+ contentType: 'text/plain',
+ response: '',
+ responseText: '',
+ responseXML: '',
+ proxy: '',
+ proxyType: 'GET',
+
+ lastModified: null,
+ etag: '',
+ headers: {
+ etag: 'IJF@H#@923uf8023hFO@I#H#',
+ 'content-type' : 'text/plain'
+ }
+ };
+
+ $.mockjax = function(settings) {
+ var i = mockHandlers.length;
+ mockHandlers[i] = settings;
+ return i;
+ };
+ $.mockjaxClear = function(i) {
+ if ( arguments.length == 1 ) {
+ mockHandlers[i] = null;
+ } else {
+ mockHandlers = [];
+ }
+ };
+})(jQuery);
diff --git a/resources/jquery/jquery.mw-jump.js b/resources/jquery/jquery.mw-jump.js
new file mode 100644
index 00000000..36b6690c
--- /dev/null
+++ b/resources/jquery/jquery.mw-jump.js
@@ -0,0 +1,15 @@
+/**
+ * JavaScript to show jump links to motor-impaired users when they are focused.
+ */
+jQuery( function( $ ) {
+
+ $('.mw-jump').delegate( 'a', 'focus blur', function( e ) {
+ // Confusingly jQuery leaves e.type as "focusout" for delegated blur events
+ if ( e.type === "blur" || e.type === "focusout" ) {
+ $( this ).closest( '.mw-jump' ).css({ height: '0' });
+ } else {
+ $( this ).closest( '.mw-jump' ).css({ height: 'auto' });
+ }
+ } );
+
+} );
diff --git a/resources/jquery/jquery.mwExtension.js b/resources/jquery/jquery.mwExtension.js
new file mode 100644
index 00000000..023ea7f3
--- /dev/null
+++ b/resources/jquery/jquery.mwExtension.js
@@ -0,0 +1,121 @@
+/*
+ * JavaScript backwards-compatibility alternatives and other convenience functions
+ */
+( function( $ ) {
+
+ $.extend({
+ trimLeft: function( str ) {
+ return str === null ? '' : str.toString().replace( /^\s+/, '' );
+ },
+ trimRight: function( str ) {
+ return str === null ?
+ '' : str.toString().replace( /\s+$/, '' );
+ },
+ ucFirst: function( str ) {
+ return str.charAt( 0 ).toUpperCase() + str.substr( 1 );
+ },
+ escapeRE: function( str ) {
+ return str.replace ( /([\\{}()|.?*+\-^$\[\]])/g, "\\$1" );
+ },
+ isDomElement: function( el ) {
+ return !!el && !!el.nodeType;
+ },
+ isEmpty: function( v ) {
+ if ( v === '' || v === 0 || v === '0' || v === null
+ || v === false || v === undefined )
+ {
+ return true;
+ }
+ // the for-loop could potentially contain prototypes
+ // to avoid that we check it's length first
+ if ( v.length === 0 ) {
+ return true;
+ }
+ if ( typeof v === 'object' ) {
+ for ( var key in v ) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ },
+ compareArray: function( arrThis, arrAgainst ) {
+ if ( arrThis.length != arrAgainst.length ) {
+ return false;
+ }
+ for ( var i = 0; i < arrThis.length; i++ ) {
+ if ( $.isArray( arrThis[i] ) ) {
+ if ( !$.compareArray( arrThis[i], arrAgainst[i] ) ) {
+ return false;
+ }
+ } else if ( arrThis[i] !== arrAgainst[i] ) {
+ return false;
+ }
+ }
+ return true;
+ },
+ compareObject: function( objectA, objectB ) {
+
+ // Do a simple check if the types match
+ if ( typeof objectA == typeof objectB ) {
+
+ // Only loop over the contents if it really is an object
+ if ( typeof objectA == 'object' ) {
+ // If they are aliases of the same object (ie. mw and mediaWiki) return now
+ if ( objectA === objectB ) {
+ return true;
+ } else {
+ var prop;
+ // Iterate over each property
+ for ( prop in objectA ) {
+ // Check if this property is also present in the other object
+ if ( prop in objectB ) {
+ // Compare the types of the properties
+ var type = typeof objectA[prop];
+ if ( type == typeof objectB[prop] ) {
+ // Recursively check objects inside this one
+ switch ( type ) {
+ case 'object' :
+ if ( !$.compareObject( objectA[prop], objectB[prop] ) ) {
+ return false;
+ }
+ break;
+ case 'function' :
+ // Functions need to be strings to compare them properly
+ if ( objectA[prop].toString() !== objectB[prop].toString() ) {
+ return false;
+ }
+ break;
+ default:
+ // Strings, numbers
+ if ( objectA[prop] !== objectB[prop] ) {
+ return false;
+ }
+ break;
+ }
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ // Check for properties in B but not in A
+ // This is about 15% faster (tested in Safari 5 and Firefox 3.6)
+ // ...than incrementing a count variable in the above and below loops
+ // See also: http://www.mediawiki.org/wiki/ResourceLoader/Default_modules/compareObject_test#Results
+ for ( prop in objectB ) {
+ if ( !( prop in objectA ) ) {
+ return false;
+ }
+ }
+ }
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+ });
+
+} )( jQuery );
diff --git a/resources/jquery/jquery.mwPrototypes.js b/resources/jquery/jquery.mwPrototypes.js
deleted file mode 100644
index e26a6be6..00000000
--- a/resources/jquery/jquery.mwPrototypes.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * JavaScript backwards-compatibility alternatives and other convenience functions
- */
-
-jQuery.extend({
- trimLeft : function( str ) {
- return str === null ? '' : str.toString().replace( /^\s+/, '' );
- },
- trimRight : function( str ) {
- return str === null ?
- '' : str.toString().replace( /\s+$/, '' );
- },
- ucFirst : function( str ) {
- return str.substr( 0, 1 ).toUpperCase() + str.substr( 1 );
- },
- escapeRE : function( str ) {
- return str.replace ( /([\\{}()|.?*+\-^$\[\]])/g, "\\$1" );
- },
- isDomElement : function( el ) {
- return !!el && !!el.nodeType;
- },
- isEmpty : function( v ) {
- var key;
- if ( v === "" || v === 0 || v === "0" || v === null
- || v === false || typeof v === 'undefined' )
- {
- return true;
- }
- // the for-loop could potentially contain prototypes
- // to avoid that we check it's length first
- if ( v.length === 0 ) {
- return true;
- }
- if ( typeof v === 'object' ) {
- for ( key in v ) {
- return false;
- }
- return true;
- }
- return false;
- },
- compareArray : function( arrThis, arrAgainst ) {
- if ( arrThis.length != arrAgainst.length ) {
- return false;
- }
- for ( var i = 0; i < arrThis.length; i++ ) {
- if ( arrThis[i] instanceof Array ) {
- if ( !$.compareArray( arrThis[i], arrAgainst[i] ) ) {
- return false;
- }
- } else if ( arrThis[i] !== arrAgainst[i] ) {
- return false;
- }
- }
- return true;
- },
- compareObject : function( objectA, objectB ) {
-
- // Do a simple check if the types match
- if ( typeof objectA == typeof objectB ) {
-
- // Only loop over the contents if it really is an object
- if ( typeof objectA == 'object' ) {
- // If they are aliases of the same object (ie. mw and mediaWiki) return now
- if ( objectA === objectB ) {
- return true;
- } else {
- var prop;
- // Iterate over each property
- for ( prop in objectA ) {
- // Check if this property is also present in the other object
- if ( prop in objectB ) {
- // Compare the types of the properties
- var type = typeof objectA[prop];
- if ( type == typeof objectB[prop] ) {
- // Recursively check objects inside this one
- switch ( type ) {
- case 'object' :
- if ( !$.compareObject( objectA[prop], objectB[prop] ) ) {
- return false;
- }
- break;
- case 'function' :
- // Functions need to be strings to compare them properly
- if ( objectA[prop].toString() !== objectB[prop].toString() ) {
- return false;
- }
- break;
- default:
- // Strings, numbers
- if ( objectA[prop] !== objectB[prop] ) {
- return false;
- }
- break;
- }
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- // Check for properties in B but not in A
- // This is about 15% faster (tested in Safari 5 and Firefox 3.6)
- // ...than incrementing a count variable in the above and below loops
- // See also: http://www.mediawiki.org/wiki/ResourceLoader/Default_modules/compareObject_test#Results
- for ( prop in objectB ) {
- if ( !( prop in objectA ) ) {
- return false;
- }
- }
- }
- }
- } else {
- return false;
- }
- return true;
- }
-});
-
diff --git a/resources/jquery/jquery.placeholder.js b/resources/jquery/jquery.placeholder.js
index 1bb69f00..8310cef9 100644
--- a/resources/jquery/jquery.placeholder.js
+++ b/resources/jquery/jquery.placeholder.js
@@ -46,7 +46,7 @@ $.fn.placeholder = function() {
// text somewhere in the middle of the placeholder string,
// we want to set the contents of the search box to the
// dropped text.
-
+
// IE wants getData( 'text' ) but Firefox wants getData( 'text/plain' )
// Firefox fails gracefully with an empty string, IE barfs with an error
try {
@@ -56,7 +56,7 @@ $.fn.placeholder = function() {
// Got an exception, so use the IE way
this.value = e.originalEvent.dataTransfer.getData( 'text' );
}
-
+
// On Firefox, drop fires after the dropped text has been inserted,
// but on IE it fires before. If we don't prevent the default action,
// IE will insert the dropped text twice.
diff --git a/resources/jquery/jquery.qunit.completenessTest.js b/resources/jquery/jquery.qunit.completenessTest.js
index 2244237c..5abb8691 100644
--- a/resources/jquery/jquery.qunit.completenessTest.js
+++ b/resources/jquery/jquery.qunit.completenessTest.js
@@ -2,10 +2,10 @@
* jQuery QUnit CompletenessTest 0.3
*
* Tests the completeness of test suites for object oriented javascript
- * libraries. Written to be used in enviroments with jQuery and QUnit.
+ * libraries. Written to be used in environments with jQuery and QUnit.
* Requires jQuery 1.5.2 or higher.
*
- * Globals: jQuery, $, QUnit, console.log
+ * Globals: jQuery, QUnit, console.log
*
* Built for and tested with:
* - Safari 5
@@ -13,11 +13,7 @@
*
* @author Timo Tijhof, 2011
*/
-(function(){
-
-/* Private members */
-var TYPE_SIMPLEFUNC = 101;
-var TYPE_OBJCONSTRFUNC = 100;
+( function( $ ) {
/**
* CompletenessTest
@@ -159,7 +155,7 @@ CompletenessTest.fn = CompletenessTest.prototype = {
$.each( currVar.prototype, function( key, value ) {
if ( key === 'constructor' ) return;
- // Clone and brake reference to parentPathArray
+ // Clone and break reference to parentPathArray
var tmpPathArray = $.extend( [], parentPathArray );
tmpPathArray.push( 'prototype' ); tmpPathArray.push( key );
@@ -174,11 +170,9 @@ CompletenessTest.fn = CompletenessTest.prototype = {
if ( !currVar.prototype || $.isEmptyObject( currVar.prototype ) ) {
// Inject check
- that.injectCheck( masterVariable, parentPathArray, function(){
-
+ that.injectCheck( masterVariable, parentPathArray, function() {
that.methodCallTracker[ parentPathArray.join( '.' ) ] = true;
-
- }, TYPE_SIMPLEFUNC );
+ } );
// We don't support checking object constructors yet...
} else {
@@ -187,7 +181,7 @@ CompletenessTest.fn = CompletenessTest.prototype = {
$.each( currVar.prototype, function( key, value ) {
if ( key === 'constructor' ) return;
- // Clone and brake reference to parentPathArray
+ // Clone and break reference to parentPathArray
var tmpPathArray = $.extend( [], parentPathArray );
tmpPathArray.push( 'prototype' ); tmpPathArray.push( key );
@@ -197,12 +191,12 @@ CompletenessTest.fn = CompletenessTest.prototype = {
}
- // Recursively. After all, this *is* the completness test
+ // Recursively. After all, this *is* the completeness test
} else if ( type === 'object' ) {
$.each( currVar, function( key, value ) {
- // Clone and brake reference to parentPathArray
+ // Clone and break reference to parentPathArray
var tmpPathArray = $.extend( [], parentPathArray );
tmpPathArray.push( key );
@@ -211,8 +205,6 @@ CompletenessTest.fn = CompletenessTest.prototype = {
} );
}
-
- return 'End of checkTests';
},
/**
@@ -220,13 +212,13 @@ CompletenessTest.fn = CompletenessTest.prototype = {
*
* Checks if the given method name (ie. 'my.foo.bar')
* was called during the test suite (as far as the tracker knows).
- * If so it adds it to missingTests.
+ * If not it adds it to missingTests.
*
* @param fnName {String}
* @return {Boolean}
*/
hasTest: function( fnName ) {
- if ( !(fnName in this.methodCallTracker) ) {
+ if ( !( fnName in this.methodCallTracker ) ) {
this.missingTests[fnName] = true;
return false;
}
@@ -248,14 +240,14 @@ CompletenessTest.fn = CompletenessTest.prototype = {
curr = masterVariable,
lastMember;
- $.each( objectPathArray, function(i, memberName){
+ $.each( objectPathArray, function( i, memberName ) {
prev = curr;
curr = prev[memberName];
lastMember = memberName;
});
// Objects are by reference, members (unless objects) are not.
- prev[lastMember] = function(){
+ prev[lastMember] = function() {
injectFn();
return curr.apply( this, arguments );
};
@@ -264,4 +256,4 @@ CompletenessTest.fn = CompletenessTest.prototype = {
window.CompletenessTest = CompletenessTest;
-})();
+} )( jQuery );
diff --git a/resources/jquery/jquery.qunit.css b/resources/jquery/jquery.qunit.css
index fa9156f9..bcecc4c0 100644
--- a/resources/jquery/jquery.qunit.css
+++ b/resources/jquery/jquery.qunit.css
@@ -1,9 +1,9 @@
/**
- * QUnit - A JavaScript Unit Testing Framework
- *
+ * QUnit v1.2.0 - A JavaScript Unit Testing Framework
+ *
* http://docs.jquery.com/QUnit
*
- * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
@@ -11,7 +11,7 @@
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
@@ -37,7 +37,7 @@
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
-
+
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
@@ -105,13 +105,13 @@
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
-
+
background-color: #fff;
-
+
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
-
+
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
@@ -174,7 +174,7 @@
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
-
+
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
@@ -186,6 +186,7 @@
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
+ white-space: pre;
}
#qunit-tests > li:last-child {
@@ -222,4 +223,4 @@
position: absolute;
top: -10000px;
left: -10000px;
-} \ No newline at end of file
+}
diff --git a/resources/jquery/jquery.qunit.js b/resources/jquery/jquery.qunit.js
index 1405e797..6d2a8a7b 100644
--- a/resources/jquery/jquery.qunit.js
+++ b/resources/jquery/jquery.qunit.js
@@ -1,6 +1,6 @@
/**
- * QUnit - A JavaScript Unit Testing Framework
- *
+ * QUnit v1.2.0 - A JavaScript Unit Testing Framework
+ *
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2011 John Resig, Jörn Zaefferer
@@ -15,13 +15,15 @@ var defined = {
sessionStorage: (function() {
try {
return !!sessionStorage.getItem;
- } catch(e){
+ } catch(e) {
return false;
}
- })()
+ })()
};
-var testId = 0;
+var testId = 0,
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty;
var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
this.name = name;
@@ -48,7 +50,7 @@ Test.prototype = {
setup: function() {
if (this.module != config.previousModule) {
if ( config.previousModule ) {
- QUnit.moduleDone( {
+ runLoggingCallbacks('moduleDone', QUnit, {
name: config.previousModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
@@ -57,7 +59,7 @@ Test.prototype = {
}
config.previousModule = this.module;
config.moduleStats = { all: 0, bad: 0 };
- QUnit.moduleStart( {
+ runLoggingCallbacks( 'moduleStart', QUnit, {
name: this.module
} );
}
@@ -71,14 +73,15 @@ Test.prototype = {
extend(this.testEnvironment, this.testEnvironmentArg);
}
- QUnit.testStart( {
- name: this.testName
- } );
+ runLoggingCallbacks( 'testStart', QUnit, {
+ name: this.testName,
+ module: this.module
+ });
// allow utility functions to access the current test environment
// TODO why??
QUnit.current_testEnvironment = this.testEnvironment;
-
+
try {
if ( !config.pollution ) {
saveGlobal();
@@ -90,6 +93,7 @@ Test.prototype = {
}
},
run: function() {
+ config.current = this;
if ( this.async ) {
QUnit.stop();
}
@@ -108,23 +112,25 @@ Test.prototype = {
// Restart the tests if they're blocking
if ( config.blocking ) {
- start();
+ QUnit.start();
}
}
},
teardown: function() {
+ config.current = this;
try {
- checkPollution();
this.testEnvironment.teardown.call(this.testEnvironment);
+ checkPollution();
} catch(e) {
QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
}
},
finish: function() {
- if ( this.expected && this.expected != this.assertions.length ) {
+ config.current = this;
+ if ( this.expected != null && this.expected != this.assertions.length ) {
QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
}
-
+
var good = 0, bad = 0,
tests = id("qunit-tests");
@@ -132,7 +138,7 @@ Test.prototype = {
config.moduleStats.all += this.assertions.length;
if ( tests ) {
- var ol = document.createElement("ol");
+ var ol = document.createElement("ol");
for ( var i = 0; i < this.assertions.length; i++ ) {
var assertion = this.assertions[i];
@@ -166,17 +172,17 @@ Test.prototype = {
var b = document.createElement("strong");
b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
-
+
var a = document.createElement("a");
a.innerHTML = "Rerun";
a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
-
+
addEvent(b, "click", function() {
var next = b.nextSibling.nextSibling,
display = next.style.display;
next.style.display = display === "none" ? "block" : "none";
});
-
+
addEvent(b, "dblclick", function(e) {
var target = e && e.target ? e.target : window.event.srcElement;
if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
@@ -210,14 +216,15 @@ Test.prototype = {
fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
}
- QUnit.testDone( {
+ runLoggingCallbacks( 'testDone', QUnit, {
name: this.testName,
+ module: this.module,
failed: bad,
passed: this.assertions.length - bad,
total: this.assertions.length
} );
},
-
+
queue: function() {
var test = this;
synchronize(function() {
@@ -243,10 +250,10 @@ Test.prototype = {
if (bad) {
run();
} else {
- synchronize(run);
+ synchronize(run, true);
};
}
-
+
};
var QUnit = {
@@ -260,12 +267,12 @@ var QUnit = {
asyncTest: function(testName, expected, callback) {
if ( arguments.length === 2 ) {
callback = expected;
- expected = 0;
+ expected = null;
}
QUnit.test(testName, expected, callback, true);
},
-
+
test: function(testName, expected, callback, async) {
var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
@@ -275,7 +282,7 @@ var QUnit = {
}
// is 2nd argument a testEnvironment?
if ( expected && typeof expected === 'object') {
- testEnvironmentArg = expected;
+ testEnvironmentArg = expected;
expected = null;
}
@@ -286,13 +293,13 @@ var QUnit = {
if ( !validTest(config.currentModule + ": " + testName) ) {
return;
}
-
+
var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
test.module = config.currentModule;
test.moduleTestEnvironment = config.currentModuleTestEnviroment;
test.queue();
},
-
+
/**
* Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
*/
@@ -310,8 +317,8 @@ var QUnit = {
result: a,
message: msg
};
- msg = escapeHtml(msg);
- QUnit.log(details);
+ msg = escapeInnerText(msg);
+ runLoggingCallbacks( 'log', QUnit, details );
config.current.assertions.push({
result: a,
message: msg
@@ -337,7 +344,7 @@ var QUnit = {
notEqual: function(actual, expected, message) {
QUnit.push(expected != actual, actual, expected, message);
},
-
+
deepEqual: function(actual, expected, message) {
QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
},
@@ -356,39 +363,39 @@ var QUnit = {
raises: function(block, expected, message) {
var actual, ok = false;
-
+
if (typeof expected === 'string') {
message = expected;
expected = null;
}
-
+
try {
block();
} catch (e) {
actual = e;
}
-
+
if (actual) {
// we don't want to validate thrown error
if (!expected) {
ok = true;
- // expected is a regexp
+ // expected is a regexp
} else if (QUnit.objectType(expected) === "regexp") {
ok = expected.test(actual);
- // expected is a constructor
+ // expected is a constructor
} else if (actual instanceof expected) {
ok = true;
- // expected is a validation function which returns true is validation passed
+ // expected is a validation function which returns true is validation passed
} else if (expected.call({}, actual) === true) {
ok = true;
}
}
-
+
QUnit.ok(ok, message);
},
- start: function() {
- config.semaphore--;
+ start: function(count) {
+ config.semaphore -= count || 1;
if (config.semaphore > 0) {
// don't start until equal number of stop-calls
return;
@@ -400,33 +407,46 @@ var QUnit = {
// A slight delay, to avoid any current callbacks
if ( defined.setTimeout ) {
window.setTimeout(function() {
+ if (config.semaphore > 0) {
+ return;
+ }
if ( config.timeout ) {
clearTimeout(config.timeout);
}
config.blocking = false;
- process();
+ process(true);
}, 13);
} else {
config.blocking = false;
- process();
+ process(true);
}
},
-
- stop: function(timeout) {
- config.semaphore++;
+
+ stop: function(count) {
+ config.semaphore += count || 1;
config.blocking = true;
- if ( timeout && defined.setTimeout ) {
+ if ( config.testTimeout && defined.setTimeout ) {
clearTimeout(config.timeout);
config.timeout = window.setTimeout(function() {
QUnit.ok( false, "Test timed out" );
+ config.semaphore = 1;
QUnit.start();
- }, timeout);
+ }, config.testTimeout);
}
}
};
+//We want access to the constructor's prototype
+(function() {
+ function F(){};
+ F.prototype = QUnit;
+ QUnit = new F();
+ //Make F QUnit's constructor so that we can add to the prototype later
+ QUnit.constructor = F;
+})();
+
// Backwards compatibility, deprecated
QUnit.equals = QUnit.equal;
QUnit.same = QUnit.deepEqual;
@@ -438,13 +458,28 @@ var config = {
// block until document ready
blocking: true,
-
+
+ // when enabled, show only failing tests
+ // gets persisted through sessionStorage and can be changed in UI via checkbox
+ hidepassed: false,
+
// by default, run previously failed tests first
// very useful in combination with "Hide passed tests" checked
reorder: true,
- noglobals: false,
- notrycatch: false
+ // by default, modify document.title when suite is done
+ altertitle: true,
+
+ urlConfig: ['noglobals', 'notrycatch'],
+
+ //logging callback queues
+ begin: [],
+ done: [],
+ log: [],
+ testStart: [],
+ testDone: [],
+ moduleStart: [],
+ moduleDone: []
};
// Load paramaters
@@ -462,9 +497,6 @@ var config = {
// allow just a key to turn on a flag, e.g., test.html?noglobals
current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
urlParams[ current[ 0 ] ] = current[ 1 ];
- if ( current[ 0 ] in config ) {
- config[ current[ 0 ] ] = current[ 1 ];
- }
}
}
@@ -519,7 +551,7 @@ extend(QUnit, {
if ( result ) {
result.parentNode.removeChild( result );
}
-
+
if ( tests ) {
result = document.createElement( "p" );
result.id = "qunit-testresult";
@@ -528,10 +560,10 @@ extend(QUnit, {
result.innerHTML = 'Running...<br/>&nbsp;';
}
},
-
+
/**
* Resets the test setup. Useful for tests that modify the DOM.
- *
+ *
* If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
*/
reset: function() {
@@ -544,7 +576,7 @@ extend(QUnit, {
}
}
},
-
+
/**
* Trigger an event on an element.
*
@@ -564,12 +596,12 @@ extend(QUnit, {
elem.fireEvent("on"+type);
}
},
-
+
// Safe object type checking
is: function( type, obj ) {
return QUnit.objectType( obj ) == type;
},
-
+
objectType: function( obj ) {
if (typeof obj === "undefined") {
return "undefined";
@@ -580,8 +612,7 @@ extend(QUnit, {
return "null";
}
- var type = Object.prototype.toString.call( obj )
- .match(/^\[object\s(.*)\]$/)[1] || '';
+ var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || '';
switch (type) {
case 'Number':
@@ -603,7 +634,7 @@ extend(QUnit, {
}
return undefined;
},
-
+
push: function(result, actual, expected, message) {
var details = {
result: result,
@@ -611,11 +642,11 @@ extend(QUnit, {
actual: actual,
expected: expected
};
-
- message = escapeHtml(message) || (result ? "okay" : "failed");
+
+ message = escapeInnerText(message) || (result ? "okay" : "failed");
message = '<span class="test-message">' + message + "</span>";
- expected = escapeHtml(QUnit.jsDump.parse(expected));
- actual = escapeHtml(QUnit.jsDump.parse(actual));
+ expected = escapeInnerText(QUnit.jsDump.parse(expected));
+ actual = escapeInnerText(QUnit.jsDump.parse(actual));
var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
if (actual != expected) {
output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
@@ -625,54 +656,66 @@ extend(QUnit, {
var source = sourceFromStacktrace();
if (source) {
details.source = source;
- output += '<tr class="test-source"><th>Source: </th><td><pre>' + source +'</pre></td></tr>';
+ output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>';
}
}
output += "</table>";
-
- QUnit.log(details);
-
+
+ runLoggingCallbacks( 'log', QUnit, details );
+
config.current.assertions.push({
result: !!result,
message: output
});
},
-
+
url: function( params ) {
params = extend( extend( {}, QUnit.urlParams ), params );
var querystring = "?",
key;
for ( key in params ) {
+ if ( !hasOwn.call( params, key ) ) {
+ continue;
+ }
querystring += encodeURIComponent( key ) + "=" +
encodeURIComponent( params[ key ] ) + "&";
}
return window.location.pathname + querystring.slice( 0, -1 );
},
-
+
+ extend: extend,
+ id: id,
+ addEvent: addEvent
+});
+
+//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later
+//Doing this allows us to tell if the following methods have been overwritten on the actual
+//QUnit object, which is a deprecated way of using the callbacks.
+extend(QUnit.constructor.prototype, {
// Logging callbacks; all receive a single argument with the listed properties
// run test/logs.html for any related changes
- begin: function() {},
+ begin: registerLoggingCallback('begin'),
// done: { failed, passed, total, runtime }
- done: function() {},
+ done: registerLoggingCallback('done'),
// log: { result, actual, expected, message }
- log: function() {},
+ log: registerLoggingCallback('log'),
// testStart: { name }
- testStart: function() {},
+ testStart: registerLoggingCallback('testStart'),
// testDone: { name, failed, passed, total }
- testDone: function() {},
+ testDone: registerLoggingCallback('testDone'),
// moduleStart: { name }
- moduleStart: function() {},
+ moduleStart: registerLoggingCallback('moduleStart'),
// moduleDone: { name, failed, passed, total }
- moduleDone: function() {}
+ moduleDone: registerLoggingCallback('moduleDone')
});
if ( typeof document === "undefined" || document.readyState === "complete" ) {
config.autorun = true;
}
-addEvent(window, "load", function() {
- QUnit.begin({});
-
+QUnit.load = function() {
+ runLoggingCallbacks( 'begin', QUnit, {} );
+
// Initialize the config, saving the execution queue
var oldconfig = extend({}, config);
QUnit.init();
@@ -680,22 +723,26 @@ addEvent(window, "load", function() {
config.blocking = false;
+ var urlConfigHtml = '', len = config.urlConfig.length;
+ for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
+ config[val] = QUnit.urlParams[val];
+ urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
+ }
+
var userAgent = id("qunit-userAgent");
if ( userAgent ) {
userAgent.innerHTML = navigator.userAgent;
}
var banner = id("qunit-header");
if ( banner ) {
- banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' +
- '<label><input name="noglobals" type="checkbox"' + ( config.noglobals ? ' checked="checked"' : '' ) + '>noglobals</label>' +
- '<label><input name="notrycatch" type="checkbox"' + ( config.notrycatch ? ' checked="checked"' : '' ) + '>notrycatch</label>';
+ banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml;
addEvent( banner, "change", function( event ) {
var params = {};
params[ event.target.name ] = event.target.checked ? true : undefined;
window.location = QUnit.url( params );
});
}
-
+
var toolbar = id("qunit-testrunner-toolbar");
if ( toolbar ) {
var filter = document.createElement("input");
@@ -711,13 +758,13 @@ addEvent(window, "load", function() {
}
if ( defined.sessionStorage ) {
if (filter.checked) {
- sessionStorage.setItem("qunit-filter-passed-tests", "true");
+ sessionStorage.setItem("qunit-filter-passed-tests", "true");
} else {
sessionStorage.removeItem("qunit-filter-passed-tests");
}
}
});
- if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
+ if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
filter.checked = true;
var ol = document.getElementById("qunit-tests");
ol.className = ol.className + " hidepass";
@@ -738,14 +785,27 @@ addEvent(window, "load", function() {
if (config.autostart) {
QUnit.start();
}
-});
+};
+
+addEvent(window, "load", QUnit.load);
+
+// addEvent(window, "error") gives us a useless event object
+window.onerror = function( message, file, line ) {
+ if ( QUnit.config.current ) {
+ ok( false, message + ", " + file + ":" + line );
+ } else {
+ test( "global failure", function() {
+ ok( false, message + ", " + file + ":" + line );
+ });
+ }
+};
function done() {
config.autorun = true;
// Log the last module results
if ( config.currentModule ) {
- QUnit.moduleDone( {
+ runLoggingCallbacks( 'moduleDone', QUnit, {
name: config.currentModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
@@ -774,13 +834,22 @@ function done() {
banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
}
- if ( tests ) {
+ if ( tests ) {
id( "qunit-testresult" ).innerHTML = html;
}
- QUnit.done( {
+ if ( config.altertitle && typeof document !== "undefined" && document.title ) {
+ // show ✖ for good, ✔ for bad suite result in title
+ // use escape sequences in case file gets loaded with non-utf-8-charset
+ document.title = [
+ (config.stats.bad ? "\u2716" : "\u2714"),
+ document.title.replace(/^[\u2714\u2716] /i, "")
+ ].join(" ");
+ }
+
+ runLoggingCallbacks( 'done', QUnit, {
failed: config.stats.bad,
- passed: passed,
+ passed: passed,
total: config.stats.all,
runtime: runtime
} );
@@ -794,7 +863,7 @@ function validTest( name ) {
return true;
}
- not = filter.charAt( 0 ) === "!";
+ var not = filter.charAt( 0 ) === "!";
if ( not ) {
filter = filter.slice( 1 );
}
@@ -822,20 +891,22 @@ function sourceFromStacktrace() {
} else if (e.stack) {
// Firefox, Chrome
return e.stack.split("\n")[4];
+ } else if (e.sourceURL) {
+ // Safari, PhantomJS
+ // TODO sourceURL points at the 'throw new Error' line above, useless
+ //return e.sourceURL + ":" + e.line;
}
}
}
-function escapeHtml(s) {
+function escapeInnerText(s) {
if (!s) {
return "";
}
s = s + "";
- return s.replace(/[\&"<>\\]/g, function(s) {
+ return s.replace(/[\&<>]/g, function(s) {
switch(s) {
case "&": return "&amp;";
- case "\\": return "\\\\";
- case '"': return '\"';
case "<": return "&lt;";
case ">": return "&gt;";
default: return s;
@@ -843,35 +914,42 @@ function escapeHtml(s) {
});
}
-function synchronize( callback ) {
+function synchronize( callback, last ) {
config.queue.push( callback );
if ( config.autorun && !config.blocking ) {
- process();
+ process(last);
}
}
-function process() {
- var start = (new Date()).getTime();
+function process( last ) {
+ var start = new Date().getTime();
+ config.depth = config.depth ? config.depth + 1 : 1;
while ( config.queue.length && !config.blocking ) {
- if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
+ if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
config.queue.shift()();
} else {
- window.setTimeout( process, 13 );
+ window.setTimeout( function(){
+ process( last );
+ }, 13 );
break;
}
}
- if (!config.blocking && !config.queue.length) {
- done();
- }
+ config.depth--;
+ if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
+ done();
+ }
}
function saveGlobal() {
config.pollution = [];
-
+
if ( config.noglobals ) {
for ( var key in window ) {
+ if ( !hasOwn.call( window, key ) ) {
+ continue;
+ }
config.pollution.push( key );
}
}
@@ -880,7 +958,7 @@ function saveGlobal() {
function checkPollution( name ) {
var old = config.pollution;
saveGlobal();
-
+
var newGlobals = diff( config.pollution, old );
if ( newGlobals.length > 0 ) {
ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
@@ -922,7 +1000,9 @@ function extend(a, b) {
for ( var prop in b ) {
if ( b[prop] === undefined ) {
delete a[prop];
- } else {
+
+ // Avoid "Member not found" error in IE8 caused by setting window.constructor
+ } else if ( prop !== "constructor" || a !== window ) {
a[prop] = b[prop];
}
}
@@ -945,176 +1025,216 @@ function id(name) {
document.getElementById( name );
}
+function registerLoggingCallback(key){
+ return function(callback){
+ config[key].push( callback );
+ };
+}
+
+// Supports deprecated method of completely overwriting logging callbacks
+function runLoggingCallbacks(key, scope, args) {
+ //debugger;
+ var callbacks;
+ if ( QUnit.hasOwnProperty(key) ) {
+ QUnit[key].call(scope, args);
+ } else {
+ callbacks = config[key];
+ for( var i = 0; i < callbacks.length; i++ ) {
+ callbacks[i].call( scope, args );
+ }
+ }
+}
+
// Test for equality any JavaScript type.
-// Discussions and reference: http://philrathe.com/articles/equiv
-// Test suites: http://philrathe.com/tests/equiv
// Author: Philippe Rathé <prathe@gmail.com>
QUnit.equiv = function () {
- var innerEquiv; // the real equiv function
- var callers = []; // stack to decide between skip/abort functions
- var parents = []; // stack to avoiding loops from circular referencing
-
- // Call the o related callback with the given arguments.
- function bindCallbacks(o, callbacks, args) {
- var prop = QUnit.objectType(o);
- if (prop) {
- if (QUnit.objectType(callbacks[prop]) === "function") {
- return callbacks[prop].apply(callbacks, args);
- } else {
- return callbacks[prop]; // or undefined
- }
- }
- }
-
- var callbacks = function () {
-
- // for string, boolean, number and null
- function useStrictEquality(b, a) {
- if (b instanceof a.constructor || a instanceof b.constructor) {
- // to catch short annotaion VS 'new' annotation of a declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function (b) {
- return isNaN(b);
- },
-
- "date": function (b, a) {
- return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function (b, a) {
- return QUnit.objectType(b) === "regexp" &&
- a.source === b.source && // the regex itself
- a.global === b.global && // and its modifers (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function () {
- var caller = callers[callers.length - 1];
- return caller !== Object &&
- typeof caller !== "undefined";
- },
-
- "array": function (b, a) {
- var i, j, loop;
- var len;
-
- // b could be an object literal here
- if ( ! (QUnit.objectType(b) === "array")) {
- return false;
- }
-
- len = a.length;
- if (len !== b.length) { // safe and faster
- return false;
- }
-
- //track reference to avoid circular references
- parents.push(a);
- for (i = 0; i < len; i++) {
- loop = false;
- for(j=0;j<parents.length;j++){
- if(parents[j] === a[i]){
- loop = true;//dont rewalk array
- }
- }
- if (!loop && ! innerEquiv(a[i], b[i])) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function (b, a) {
- var i, j, loop;
- var eq = true; // unless we can proove it
- var aProperties = [], bProperties = []; // collection of strings
-
- // comparing constructors is more strict than using instanceof
- if ( a.constructor !== b.constructor) {
- return false;
- }
+ var innerEquiv; // the real equiv function
+ var callers = []; // stack to decide between skip/abort functions
+ var parents = []; // stack to avoiding loops from circular referencing
- // stack constructor before traversing properties
- callers.push(a.constructor);
- //track reference to avoid circular references
- parents.push(a);
-
- for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
- loop = false;
- for(j=0;j<parents.length;j++){
- if(parents[j] === a[i])
- loop = true; //don't go down the same path twice
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && ! innerEquiv(a[i], b[i])) {
- eq = false;
- break;
- }
- }
+ // Call the o related callback with the given arguments.
+ function bindCallbacks(o, callbacks, args) {
+ var prop = QUnit.objectType(o);
+ if (prop) {
+ if (QUnit.objectType(callbacks[prop]) === "function") {
+ return callbacks[prop].apply(callbacks, args);
+ } else {
+ return callbacks[prop]; // or undefined
+ }
+ }
+ }
- callers.pop(); // unstack, we are done
- parents.pop();
+ var getProto = Object.getPrototypeOf || function (obj) {
+ return obj.__proto__;
+ };
- for (i in b) {
- bProperties.push(i); // collect b's properties
- }
+ var callbacks = function () {
+
+ // for string, boolean, number and null
+ function useStrictEquality(b, a) {
+ if (b instanceof a.constructor || a instanceof b.constructor) {
+ // to catch short annotaion VS 'new' annotation of a
+ // declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string" : useStrictEquality,
+ "boolean" : useStrictEquality,
+ "number" : useStrictEquality,
+ "null" : useStrictEquality,
+ "undefined" : useStrictEquality,
+
+ "nan" : function(b) {
+ return isNaN(b);
+ },
+
+ "date" : function(b, a) {
+ return QUnit.objectType(b) === "date"
+ && a.valueOf() === b.valueOf();
+ },
+
+ "regexp" : function(b, a) {
+ return QUnit.objectType(b) === "regexp"
+ && a.source === b.source && // the regex itself
+ a.global === b.global && // and its modifers
+ // (gmi) ...
+ a.ignoreCase === b.ignoreCase
+ && a.multiline === b.multiline;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function" : function() {
+ var caller = callers[callers.length - 1];
+ return caller !== Object && typeof caller !== "undefined";
+ },
+
+ "array" : function(b, a) {
+ var i, j, loop;
+ var len;
+
+ // b could be an object literal here
+ if (!(QUnit.objectType(b) === "array")) {
+ return false;
+ }
+
+ len = a.length;
+ if (len !== b.length) { // safe and faster
+ return false;
+ }
- // Ensures identical properties name
- return eq && innerEquiv(aProperties.sort(), bProperties.sort());
- }
- };
- }();
-
- innerEquiv = function () { // can take multiple arguments
- var args = Array.prototype.slice.apply(arguments);
- if (args.length < 2) {
- return true; // end transition
- }
-
- return (function (a, b) {
- if (a === b) {
- return true; // catch the most you can
- } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [b, a]);
- }
-
- // apply transition with (1..n) arguments
- })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
- };
-
- return innerEquiv;
+ // track reference to avoid circular references
+ parents.push(a);
+ for (i = 0; i < len; i++) {
+ loop = false;
+ for (j = 0; j < parents.length; j++) {
+ if (parents[j] === a[i]) {
+ loop = true;// dont rewalk array
+ }
+ }
+ if (!loop && !innerEquiv(a[i], b[i])) {
+ parents.pop();
+ return false;
+ }
+ }
+ parents.pop();
+ return true;
+ },
+
+ "object" : function(b, a) {
+ var i, j, loop;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of
+ // strings
+
+ // comparing constructors is more strict than using
+ // instanceof
+ if (a.constructor !== b.constructor) {
+ // Allow objects with no prototype to be equivalent to
+ // objects with Object as their constructor.
+ if (!((getProto(a) === null && getProto(b) === Object.prototype) ||
+ (getProto(b) === null && getProto(a) === Object.prototype)))
+ {
+ return false;
+ }
+ }
+
+ // stack constructor before traversing properties
+ callers.push(a.constructor);
+ // track reference to avoid circular references
+ parents.push(a);
+
+ for (i in a) { // be strict: don't ensures hasOwnProperty
+ // and go deep
+ loop = false;
+ for (j = 0; j < parents.length; j++) {
+ if (parents[j] === a[i])
+ loop = true; // don't go down the same path
+ // twice
+ }
+ aProperties.push(i); // collect a's properties
+
+ if (!loop && !innerEquiv(a[i], b[i])) {
+ eq = false;
+ break;
+ }
+ }
+
+ callers.pop(); // unstack, we are done
+ parents.pop();
+
+ for (i in b) {
+ bProperties.push(i); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq
+ && innerEquiv(aProperties.sort(), bProperties
+ .sort());
+ }
+ };
+ }();
+
+ innerEquiv = function() { // can take multiple arguments
+ var args = Array.prototype.slice.apply(arguments);
+ if (args.length < 2) {
+ return true; // end transition
+ }
+
+ return (function(a, b) {
+ if (a === b) {
+ return true; // catch the most you can
+ } else if (a === null || b === null || typeof a === "undefined"
+ || typeof b === "undefined"
+ || QUnit.objectType(a) !== QUnit.objectType(b)) {
+ return false; // don't lose time with error prone cases
+ } else {
+ return bindCallbacks(a, callbacks, [ b, a ]);
+ }
+
+ // apply transition with (1..n) arguments
+ })(args[0], args[1])
+ && arguments.callee.apply(this, args.splice(1,
+ args.length - 1));
+ };
+
+ return innerEquiv;
}();
/**
- * jsDump
- * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
- * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
- * Date: 5/15/2008
+ * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
+ * http://flesler.blogspot.com Licensed under BSD
+ * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
+ *
* @projectDescription Advanced and extensible data dumping for Javascript.
* @version 1.0.0
* @author Ariel Flesler
@@ -1125,7 +1245,7 @@ QUnit.jsDump = (function() {
return '"' + str.toString().replace(/"/g, '\\"') + '"';
};
function literal( o ) {
- return o + '';
+ return o + '';
};
function join( pre, arr, post ) {
var s = jsDump.separator(),
@@ -1137,25 +1257,35 @@ QUnit.jsDump = (function() {
return pre + post;
return [ pre, inner + arr, base + post ].join(s);
};
- function array( arr ) {
- var i = arr.length, ret = Array(i);
+ function array( arr, stack ) {
+ var i = arr.length, ret = Array(i);
this.up();
while ( i-- )
- ret[i] = this.parse( arr[i] );
+ ret[i] = this.parse( arr[i] , undefined , stack);
this.down();
return join( '[', ret, ']' );
};
-
+
var reName = /^function (\w+)/;
-
+
var jsDump = {
- parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
- var parser = this.parsers[ type || this.typeOf(obj) ];
- type = typeof parser;
-
- return type == 'function' ? parser.call( this, obj ) :
- type == 'string' ? parser :
- this.parsers.error;
+ parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
+ stack = stack || [ ];
+ var parser = this.parsers[ type || this.typeOf(obj) ];
+ type = typeof parser;
+ var inStack = inArray(obj, stack);
+ if (inStack != -1) {
+ return 'recursion('+(inStack - stack.length)+')';
+ }
+ //else
+ if (type == 'function') {
+ stack.push(obj);
+ var res = parser.call( this, obj, stack );
+ stack.pop();
+ return res;
+ }
+ // else
+ return (type == 'string') ? parser : this.parsers.error;
},
typeOf:function( obj ) {
var type;
@@ -1175,7 +1305,12 @@ QUnit.jsDump = (function() {
type = "document";
} else if (obj.nodeType) {
type = "node";
- } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
+ } else if (
+ // native arrays
+ toString.call( obj ) === "[object Array]" ||
+ // NodeList objects
+ ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
+ ) {
type = "array";
} else {
type = typeof obj;
@@ -1203,7 +1338,7 @@ QUnit.jsDump = (function() {
this.parsers[name] = parser;
},
// The next 3 are exposed so you can use them
- quote:quote,
+ quote:quote,
literal:literal,
join:join,
//
@@ -1222,28 +1357,30 @@ QUnit.jsDump = (function() {
if ( name )
ret += ' ' + name;
ret += '(';
-
+
ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
},
array: array,
nodelist: array,
arguments: array,
- object:function( map ) {
+ object:function( map, stack ) {
var ret = [ ];
QUnit.jsDump.up();
- for ( var key in map )
- ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) );
+ for ( var key in map ) {
+ var val = map[key];
+ ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
+ }
QUnit.jsDump.down();
return join( '{', ret, '}' );
},
node:function( node ) {
var open = QUnit.jsDump.HTML ? '&lt;' : '<',
close = QUnit.jsDump.HTML ? '&gt;' : '>';
-
+
var tag = node.nodeName.toLowerCase(),
ret = open + tag;
-
+
for ( var a in QUnit.jsDump.DOMAttrs ) {
var val = node[QUnit.jsDump.DOMAttrs[a]];
if ( val )
@@ -1253,8 +1390,8 @@ QUnit.jsDump = (function() {
},
functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
var l = fn.length;
- if ( !l ) return '';
-
+ if ( !l ) return '';
+
var args = Array(l);
while ( l-- )
args[l] = String.fromCharCode(97+l);//97 is 'a'
@@ -1302,6 +1439,21 @@ function getText( elems ) {
return ret;
};
+//from jquery.js
+function inArray( elem, array ) {
+ if ( array.indexOf ) {
+ return array.indexOf( elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
@@ -1311,35 +1463,38 @@ function getText( elems ) {
*
* More Info:
* http://ejohn.org/projects/javascript-diff-algorithm/
- *
+ *
* Usage: QUnit.diff(expected, actual)
- *
+ *
* QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
*/
QUnit.diff = (function() {
- function diff(o, n){
- var ns = new Object();
- var os = new Object();
-
+ function diff(o, n) {
+ var ns = {};
+ var os = {};
+
for (var i = 0; i < n.length; i++) {
- if (ns[n[i]] == null)
+ if (ns[n[i]] == null)
ns[n[i]] = {
- rows: new Array(),
+ rows: [],
o: null
};
ns[n[i]].rows.push(i);
}
-
+
for (var i = 0; i < o.length; i++) {
- if (os[o[i]] == null)
+ if (os[o[i]] == null)
os[o[i]] = {
- rows: new Array(),
+ rows: [],
n: null
};
os[o[i]].rows.push(i);
}
-
+
for (var i in ns) {
+ if ( !hasOwn.call( ns, i ) ) {
+ continue;
+ }
if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
n[ns[i].rows[0]] = {
text: n[ns[i].rows[0]],
@@ -1351,7 +1506,7 @@ QUnit.diff = (function() {
};
}
}
-
+
for (var i = 0; i < n.length - 1; i++) {
if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
n[i + 1] == o[n[i].row + 1]) {
@@ -1365,7 +1520,7 @@ QUnit.diff = (function() {
};
}
}
-
+
for (var i = n.length - 1; i > 0; i--) {
if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
n[i - 1] == o[n[i].row - 1]) {
@@ -1379,20 +1534,20 @@ QUnit.diff = (function() {
};
}
}
-
+
return {
o: o,
n: n
};
}
-
- return function(o, n){
+
+ return function(o, n) {
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
var str = "";
-
+
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = [" "];
@@ -1407,7 +1562,7 @@ QUnit.diff = (function() {
else {
nSpace.push(" ");
}
-
+
if (out.n.length == 0) {
for (var i = 0; i < out.o.length; i++) {
str += '<del>' + out.o[i] + oSpace[i] + "</del>";
@@ -1419,14 +1574,14 @@ QUnit.diff = (function() {
str += '<del>' + out.o[n] + oSpace[n] + "</del>";
}
}
-
+
for (var i = 0; i < out.n.length; i++) {
if (out.n[i].text == null) {
str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
}
else {
var pre = "";
-
+
for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
}
@@ -1434,9 +1589,9 @@ QUnit.diff = (function() {
}
}
}
-
+
return str;
};
})();
-})(this); \ No newline at end of file
+})(this);
diff --git a/resources/jquery/jquery.spinner.css b/resources/jquery/jquery.spinner.css
new file mode 100644
index 00000000..150a51b4
--- /dev/null
+++ b/resources/jquery/jquery.spinner.css
@@ -0,0 +1,12 @@
+.mw-spinner {
+ /* @embed */
+ background: transparent url(images/spinner.gif);
+ height: 20px;
+ width: 20px;
+ display: inline-block;
+ vertical-align: middle;
+
+ /* IE < 8 Hacks */
+ zoom: 1;
+ *display: inline;
+} \ No newline at end of file
diff --git a/resources/jquery/jquery.spinner.js b/resources/jquery/jquery.spinner.js
new file mode 100644
index 00000000..87e45382
--- /dev/null
+++ b/resources/jquery/jquery.spinner.js
@@ -0,0 +1,44 @@
+/**
+ * jQuery spinner
+ *
+ * Simple jQuery plugin to create, inject and remove spinners.
+ */
+( function( $ ) {
+
+$.extend( {
+ /**
+ * Creates a spinner element.
+ *
+ * @param id {String} id of the spinner
+ * @return {jQuery} spinner
+ */
+ createSpinner: function( id ) {
+ return $( '<div>' ).attr( {
+ id: 'mw-spinner-' + id,
+ 'class': 'mw-spinner',
+ title: '...'
+ } );
+ },
+
+ /**
+ * Removes a spinner element.
+ *
+ * @param id {String}
+ * @return {jQuery} spinner
+ */
+ removeSpinner: function( id ) {
+ return $( '#mw-spinner-' + id ).remove();
+ }
+} );
+
+/**
+ * Injects a spinner after the elements in the jQuery collection.
+ *
+ * @param id String id of the spinner
+ * @return {jQuery}
+ */
+$.fn.injectSpinner = function( id ) {
+ return this.after( $.createSpinner( id ) );
+};
+
+} )( jQuery );
diff --git a/resources/jquery/jquery.suggestions.css b/resources/jquery/jquery.suggestions.css
index 74094c53..3cbdad22 100644
--- a/resources/jquery/jquery.suggestions.css
+++ b/resources/jquery/jquery.suggestions.css
@@ -3,9 +3,9 @@
.suggestions {
overflow: hidden;
position: absolute;
- top: 0px;
- left: 0px;
- width: 0px;
+ top: 0;
+ left: 0;
+ width: 0;
border: none;
z-index: 1099;
padding: 0;
@@ -17,7 +17,7 @@ html > body .suggestions {
}
.suggestions-special {
position: relative;
- background-color: Window;
+ background-color: white;
font-size: 0.8em;
cursor: pointer;
border: solid 1px #aaaaaa;
@@ -30,7 +30,6 @@ html > body .suggestions {
}
.suggestions-results {
background-color: white;
- background-color: Window;
font-size: 0.8em;
cursor: pointer;
border: solid 1px #aaaaaa;
@@ -39,7 +38,6 @@ html > body .suggestions {
}
.suggestions-result {
color: black;
- color: WindowText;
margin: 0;
line-height: 1.5em;
padding: 0.01em 0.25em;
@@ -47,9 +45,7 @@ html > body .suggestions {
}
.suggestions-result-current {
background-color: #4C59A6;
- background-color: Highlight;
color: white;
- color: HighlightText;
}
.suggestions-special .special-label {
font-size: 0.8em;
@@ -67,7 +63,6 @@ html > body .suggestions {
.suggestions-result-current .special-label,
.suggestions-result-current .special-query {
color: white;
- color: HighlightText;
}
.autoellipsis-matched,
.highlight {
diff --git a/resources/jquery/jquery.suggestions.js b/resources/jquery/jquery.suggestions.js
index 90cf53b2..55c30010 100644
--- a/resources/jquery/jquery.suggestions.js
+++ b/resources/jquery/jquery.suggestions.js
@@ -4,36 +4,36 @@
* Usage:
*
* Set options:
- * $('#textbox').suggestions( { option1: value1, option2: value2 } );
- * $('#textbox').suggestions( option, value );
+ * $( '#textbox' ).suggestions( { option1: value1, option2: value2 } );
+ * $( '#textbox' ).suggestions( option, value );
* Get option:
- * value = $('#textbox').suggestions( option );
+ * value = $( '#textbox' ).suggestions( option );
* Initialize:
- * $('#textbox').suggestions();
+ * $( '#textbox' ).suggestions();
*
* Options:
*
* fetch(query): Callback that should fetch suggestions and set the suggestions property. Executed in the context of the
- * textbox
- * Type: Function
+ * textbox
+ * Type: Function
* cancel: Callback function to call when any pending asynchronous suggestions fetches should be canceled.
- * Executed in the context of the textbox
+ * Executed in the context of the textbox
* Type: Function
* special: Set of callbacks for rendering and selecting
* Type: Object of Functions 'render' and 'select'
* result: Set of callbacks for rendering and selecting
* Type: Object of Functions 'render' and 'select'
* $region: jQuery selection of element to place the suggestions below and match width of
- * Type: jQuery Object, Default: $(this)
+ * Type: jQuery Object, Default: $(this)
* suggestions: Suggestions to display
- * Type: Array of strings
+ * Type: Array of strings
* maxRows: Maximum number of suggestions to display at one time
- * Type: Number, Range: 1 - 100, Default: 7
+ * Type: Number, Range: 1 - 100, Default: 7
* delay: Number of ms to wait for the user to stop typing
- * Type: Number, Range: 0 - 1200, Default: 120
+ * Type: Number, Range: 0 - 1200, Default: 120
* submitOnClick: Whether to submit the form containing the textbox when a suggestion is clicked
* Type: Boolean, Default: false
- * maxExpandFactor: Maximum suggestions box width relative to the textbox width. If set to e.g. 2, the suggestions box
+ * maxExpandFactor: Maximum suggestions box width relative to the textbox width. If set to e.g. 2, the suggestions box
* will never be grown beyond 2 times the width of the textbox.
* Type: Number, Range: 1 - infinity, Default: 3
* positionFromLeft: Whether to position the suggestion box with the left attribute or the right
@@ -52,7 +52,7 @@ $.suggestions = {
if ( context.data.timerID != null ) {
clearTimeout( context.data.timerID );
}
- if ( typeof context.config.cancel == 'function' ) {
+ if ( $.isFunction( context.config.cancel ) ) {
context.config.cancel.call( context.data.$textbox );
}
},
@@ -66,7 +66,7 @@ $.suggestions = {
},
/**
* Ask the user-specified callback for new suggestions. Any previous delayed call to this function still pending
- * will be canceled. If the value in the textbox is empty or hasn't changed since the last time suggestions were fetched, this
+ * will be canceled. If the value in the textbox is empty or hasn't changed since the last time suggestions were fetched, this
* function does nothing.
* @param {Boolean} delayed Whether or not to delay this by the currently configured amount of time
*/
@@ -74,12 +74,12 @@ $.suggestions = {
// Only fetch if the value in the textbox changed and is not empty
// if the textbox is empty then clear the result div, but leave other settings intouched
function maybeFetch() {
- if ( context.data.$textbox.val().length == 0 ) {
+ if ( context.data.$textbox.val().length === 0 ) {
context.data.$container.hide();
context.data.prevText = '';
} else if ( context.data.$textbox.val() !== context.data.prevText ) {
- if ( typeof context.config.fetch == 'function' ) {
- context.data.prevText = context.data.$textbox.val();
+ if ( typeof context.config.fetch === 'function' ) {
+ context.data.prevText = context.data.$textbox.val();
context.config.fetch.call( context.data.$textbox, context.data.$textbox.val() );
}
}
@@ -99,7 +99,7 @@ $.suggestions = {
},
special: function( context ) {
// Allow custom rendering - but otherwise don't do any rendering
- if ( typeof context.config.special.render == 'function' ) {
+ if ( typeof context.config.special.render === 'function' ) {
// Wait for the browser to update the value
setTimeout( function() {
// Render special
@@ -126,8 +126,8 @@ $.suggestions = {
case 'suggestions':
context.config[property] = value;
// Update suggestions
- if ( typeof context.data !== 'undefined' ) {
- if ( context.data.$textbox.val().length == 0 ) {
+ if ( context.data !== undefined ) {
+ if ( context.data.$textbox.val().length === 0 ) {
// Hide the div when no suggestion exist
context.data.$container.hide();
} else {
@@ -135,17 +135,17 @@ $.suggestions = {
context.data.$container.show();
// Update the size and position of the list
var newCSS = {
- 'top': context.config.$region.offset().top + context.config.$region.outerHeight(),
- 'bottom': 'auto',
- 'width': context.config.$region.outerWidth(),
- 'height': 'auto'
+ top: context.config.$region.offset().top + context.config.$region.outerHeight(),
+ bottom: 'auto',
+ width: context.config.$region.outerWidth(),
+ height: 'auto'
};
if ( context.config.positionFromLeft ) {
- newCSS['left'] = context.config.$region.offset().left;
- newCSS['right'] = 'auto';
+ newCSS.left = context.config.$region.offset().left;
+ newCSS.right = 'auto';
} else {
- newCSS['left'] = 'auto';
- newCSS['right'] = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() );
+ newCSS.left = 'auto';
+ newCSS.right = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() );
}
context.data.$container.css( newCSS );
var $results = context.data.$container.children( '.suggestions-results' );
@@ -155,7 +155,7 @@ $.suggestions = {
var matchedText = null;
for ( var i = 0; i < context.config.suggestions.length; i++ ) {
var text = context.config.suggestions[i];
- var $result = $( '<div />' )
+ var $result = $( '<div>' )
.addClass( 'suggestions-result' )
.attr( 'rel', i )
.data( 'text', context.config.suggestions[i] )
@@ -167,18 +167,18 @@ $.suggestions = {
} )
.appendTo( $results );
// Allow custom rendering
- if ( typeof context.config.result.render == 'function' ) {
+ if ( typeof context.config.result.render === 'function' ) {
context.config.result.render.call( $result, context.config.suggestions[i] );
} else {
// Add <span> with text
if( context.config.highlightInput ) {
matchedText = context.data.prevText;
}
- $result.append( $( '<span />' )
+ $result.append( $( '<span>' )
.css( 'whiteSpace', 'nowrap' )
.text( text )
);
-
+
// Widen results box if needed
// New width is only calculated here, applied later
var $span = $result.children( 'span' );
@@ -223,25 +223,25 @@ $.suggestions = {
highlight: function( context, result, updateTextbox ) {
var selected = context.data.$container.find( '.suggestions-result-current' );
if ( !result.get || selected.get( 0 ) != result.get( 0 ) ) {
- if ( result == 'prev' ) {
+ if ( result === 'prev' ) {
if( selected.is( '.suggestions-special' ) ) {
- result = context.data.$container.find( '.suggestions-result:last' )
+ result = context.data.$container.find( '.suggestions-result:last' );
} else {
result = selected.prev();
- if ( selected.length == 0 ) {
+ if ( selected.length === 0 ) {
// we are at the beginning, so lets jump to the last item
- if ( context.data.$container.find( '.suggestions-special' ).html() != "" ) {
+ if ( context.data.$container.find( '.suggestions-special' ).html() !== '' ) {
result = context.data.$container.find( '.suggestions-special' );
} else {
result = context.data.$container.find( '.suggestions-results div:last' );
}
}
}
- } else if ( result == 'next' ) {
- if ( selected.length == 0 ) {
+ } else if ( result === 'next' ) {
+ if ( selected.length === 0 ) {
// No item selected, go to the first one
result = context.data.$container.find( '.suggestions-results div:first' );
- if ( result.length == 0 && context.data.$container.find( '.suggestions-special' ).html() != "" ) {
+ if ( result.length === 0 && context.data.$container.find( '.suggestions-special' ).html() !== '' ) {
// No suggestion exists, go to the special one directly
result = context.data.$container.find( '.suggestions-special' );
}
@@ -250,8 +250,8 @@ $.suggestions = {
if ( selected.is( '.suggestions-special' ) ) {
result = $( [] );
} else if (
- result.length == 0 &&
- context.data.$container.find( '.suggestions-special' ).html() != ""
+ result.length === 0 &&
+ context.data.$container.find( '.suggestions-special' ).html() !== ''
) {
// We were at the last item, jump to the specials!
result = context.data.$container.find( '.suggestions-special' );
@@ -262,7 +262,7 @@ $.suggestions = {
result.addClass( 'suggestions-result-current' );
}
if ( updateTextbox ) {
- if ( result.length == 0 || result.is( '.suggestions-special' ) ) {
+ if ( result.length === 0 || result.is( '.suggestions-special' ) ) {
$.suggestions.restore( context );
} else {
context.data.$textbox.val( result.data( 'text' ) );
@@ -278,8 +278,8 @@ $.suggestions = {
* @param key Integer Code of key pressed
*/
keypress: function( e, context, key ) {
- var wasVisible = context.data.$container.is( ':visible' );
- var preventDefault = false;
+ var wasVisible = context.data.$container.is( ':visible' ),
+ preventDefault = false;
switch ( key ) {
// Arrow down
case 40:
@@ -312,17 +312,17 @@ $.suggestions = {
context.data.$container.hide();
preventDefault = wasVisible;
selected = context.data.$container.find( '.suggestions-result-current' );
- if ( selected.size() == 0 || context.data.selectedWithMouse ) {
- // if nothing is selected OR if something was selected with the mouse,
+ if ( selected.length === 0 || context.data.selectedWithMouse ) {
+ // if nothing is selected OR if something was selected with the mouse,
// cancel any current requests and submit the form
$.suggestions.cancel( context );
context.config.$region.closest( 'form' ).submit();
} else if ( selected.is( '.suggestions-special' ) ) {
- if ( typeof context.config.special.select == 'function' ) {
+ if ( typeof context.config.special.select === 'function' ) {
context.config.special.select.call( selected, context.data.$textbox );
}
} else {
- if ( typeof context.config.result.select == 'function' ) {
+ if ( typeof context.config.result.select === 'function' ) {
$.suggestions.highlight( context, selected, true );
context.config.result.select.call( selected, context.data.$textbox );
} else {
@@ -341,17 +341,17 @@ $.suggestions = {
}
};
$.fn.suggestions = function() {
-
+
// Multi-context fields
var returnValue = null;
var args = arguments;
-
+
$(this).each( function() {
/* Construction / Loading */
-
+
var context = $(this).data( 'suggestions-context' );
- if ( typeof context == 'undefined' || context == null ) {
+ if ( context === undefined || context === null ) {
context = {
config: {
'fetch' : function() {},
@@ -369,17 +369,17 @@ $.fn.suggestions = function() {
}
};
}
-
+
/* API */
-
+
// Handle various calling styles
if ( args.length > 0 ) {
- if ( typeof args[0] == 'object' ) {
+ if ( typeof args[0] === 'object' ) {
// Apply set of properties
for ( var key in args[0] ) {
$.suggestions.configure( context, key, args[0][key] );
}
- } else if ( typeof args[0] == 'string' ) {
+ } else if ( typeof args[0] === 'string' ) {
if ( args.length > 1 ) {
// Set property values
$.suggestions.configure( context, args[0], args[1] );
@@ -389,10 +389,10 @@ $.fn.suggestions = function() {
}
}
}
-
+
/* Initialization */
-
- if ( typeof context.data == 'undefined' ) {
+
+ if ( context.data === undefined ) {
context.data = {
// ID of running timer
'timerID': null,
@@ -407,23 +407,23 @@ $.fn.suggestions = function() {
};
// Setup the css for positioning the results box
var newCSS = {
- 'top': Math.round( context.data.$textbox.offset().top + context.data.$textbox.outerHeight() ),
- 'width': context.data.$textbox.outerWidth(),
- 'display': 'none'
+ top: Math.round( context.data.$textbox.offset().top + context.data.$textbox.outerHeight() ),
+ width: context.data.$textbox.outerWidth(),
+ display: 'none'
};
if ( context.config.positionFromLeft ) {
- newCSS['left'] = context.config.$region.offset().left;
- newCSS['right'] = 'auto';
+ newCSS.left = context.config.$region.offset().left;
+ newCSS.right = 'auto';
} else {
- newCSS['left'] = 'auto';
- newCSS['right'] = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() );
+ newCSS.left = 'auto';
+ newCSS.right = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() );
}
-
- context.data.$container = $( '<div />' )
+
+ context.data.$container = $( '<div>' )
.css( newCSS )
.addClass( 'suggestions' )
.append(
- $( '<div />' ).addClass( 'suggestions-results' )
+ $( '<div>' ).addClass( 'suggestions-results' )
// Can't use click() because the container div is hidden when the textbox loses focus. Instead,
// listen for a mousedown followed by a mouseup on the same div
.mousedown( function( e ) {
@@ -438,14 +438,14 @@ $.fn.suggestions = function() {
}
$.suggestions.highlight( context, $result, true );
context.data.$container.hide();
- if ( typeof context.config.result.select == 'function' ) {
+ if ( typeof context.config.result.select === 'function' ) {
context.config.result.select.call( $result, context.data.$textbox );
}
context.data.$textbox.focus();
} )
)
.append(
- $( '<div />' ).addClass( 'suggestions-special' )
+ $( '<div>' ).addClass( 'suggestions-special' )
// Can't use click() because the container div is hidden when the textbox loses focus. Instead,
// listen for a mousedown followed by a mouseup on the same div
.mousedown( function( e ) {
@@ -459,7 +459,7 @@ $.fn.suggestions = function() {
return;
}
context.data.$container.hide();
- if ( typeof context.config.special.select == 'function' ) {
+ if ( typeof context.config.special.select === 'function' ) {
context.config.special.select.call( $special, context.data.$textbox );
}
context.data.$textbox.focus();
@@ -477,9 +477,9 @@ $.fn.suggestions = function() {
.attr( 'autocomplete', 'off')
.keydown( function( e ) {
// Store key pressed to handle later
- context.data.keypressed = ( e.keyCode == undefined ) ? e.which : e.keyCode;
+ context.data.keypressed = ( e.keyCode === undefined ) ? e.which : e.keyCode;
context.data.keypressedCount = 0;
-
+
switch ( context.data.keypressed ) {
// This preventDefault logic is duplicated from
// $.suggestions.keypress(), which sucks
@@ -503,7 +503,7 @@ $.fn.suggestions = function() {
.keyup( function( e ) {
// Some browsers won't throw keypress() for arrow keys. If we got a keydown and a keyup without a
// keypress in between, solve it
- if ( context.data.keypressedCount == 0 ) {
+ if ( context.data.keypressedCount === 0 ) {
$.suggestions.keypress( e, context, context.data.keypressed );
}
} )
diff --git a/resources/jquery/jquery.tabIndex.js b/resources/jquery/jquery.tabIndex.js
index 33e06047..75731d7c 100644
--- a/resources/jquery/jquery.tabIndex.js
+++ b/resources/jquery/jquery.tabIndex.js
@@ -4,13 +4,13 @@
( function( $ ) {
/**
* Finds the lowerst tabindex in use within a selection
- *
+ *
* @return number Lowest tabindex on the page
*/
$.fn.firstTabIndex = function() {
var minTabIndex = null;
$(this).find( '[tabindex]' ).each( function() {
- var tabIndex = parseInt( $(this).attr( 'tabindex' ), 10 );
+ var tabIndex = parseInt( $(this).prop( 'tabindex' ), 10 );
// In IE6/IE7 the above jQuery selector returns all elements,
// becuase it has a default value for tabIndex in IE6/IE7 of 0
// (rather than null/undefined). Therefore check "> 0" as well.
@@ -29,13 +29,13 @@ $.fn.firstTabIndex = function() {
/**
* Finds the highest tabindex in use within a selection
- *
+ *
* @return number Highest tabindex on the page
*/
$.fn.lastTabIndex = function() {
var maxTabIndex = null;
$(this).find( '[tabindex]' ).each( function() {
- var tabIndex = parseInt( $(this).attr( 'tabindex' ), 10 );
+ var tabIndex = parseInt( $(this).prop( 'tabindex' ), 10 );
if ( tabIndex > 0 && !isNaN( tabIndex ) ) {
// Initial value
if ( maxTabIndex === null ) {
diff --git a/resources/jquery/jquery.tablesorter.css b/resources/jquery/jquery.tablesorter.css
index 87719810..a88acc09 100644
--- a/resources/jquery/jquery.tablesorter.css
+++ b/resources/jquery/jquery.tablesorter.css
@@ -1,17 +1,17 @@
/* Table Sorting */
table.jquery-tablesorter th.headerSort {
/* @embed */
- background-image: url(images/sort_both.gif) !important;
+ background-image: url(images/sort_both.gif);
cursor: pointer;
- background-repeat: no-repeat !important;
- background-position: center right !important;
- padding-right: 21px !important;
+ background-repeat: no-repeat;
+ background-position: center right;
+ padding-right: 21px;
}
table.jquery-tablesorter th.headerSortUp {
/* @embed */
- background-image: url(images/sort_up.gif) !important;
+ background-image: url(images/sort_up.gif);
}
table.jquery-tablesorter th.headerSortDown {
/* @embed */
- background-image: url(images/sort_down.gif) !important;
+ background-image: url(images/sort_down.gif);
}
diff --git a/resources/jquery/jquery.tablesorter.js b/resources/jquery/jquery.tablesorter.js
index 5af27cc4..ea86b64e 100644
--- a/resources/jquery/jquery.tablesorter.js
+++ b/resources/jquery/jquery.tablesorter.js
@@ -8,8 +8,9 @@
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
- * @depends on mw.config (wgDigitTransformTable, wgMonthNames, wgMonthNamesShort,
+ * Depends on mw.config (wgDigitTransformTable, wgMonthNames, wgMonthNamesShort,
* wgDefaultDateFormat, wgContentLanguage)
+ * Uses 'tableSorterCollation' in mw.config (if available)
*/
/**
*
@@ -240,7 +241,7 @@
}
$thead.append( this );
} );
- $table.children('tbody').before( $thead );
+ $table.find(' > tbody:first').before( $thead );
}
if( !$table.get(0).tFoot ) {
var $tfoot = $( '<tfoot>' );
@@ -259,9 +260,9 @@
var maxSeen = 0,
longest,
realCellIndex = 0,
- $tableHeaders = $( 'thead:eq(0) tr', table );
+ $tableHeaders = $( 'thead:eq(0) > tr', table );
if ( $tableHeaders.length > 1 ) {
- $tableHeaders.each(function() {
+ $tableHeaders.each( function() {
if ( this.cells.length > maxSeen ) {
maxSeen = this.cells.length;
longest = this;
@@ -594,7 +595,7 @@
if ( firstTime ) {
firstTime = false;
-
+
// Legacy fix of .sortbottoms
// Wrap them inside inside a tfoot (because that's what they actually want to be) &
// and put the <tfoot> at the end of the <table>
@@ -604,10 +605,10 @@
if ( $tfoot.length ) {
$tfoot.eq(0).prepend( $sortbottoms );
} else {
- $table.append( $( '<tfoot>' ).append( $sortbottoms ) )
+ $table.append( $( '<tfoot>' ).append( $sortbottoms ) );
}
}
-
+
explodeRowspans( $table );
// try to auto detect column type, and store in tables config
table.config.parsers = buildParserCache( table, $headers );
diff --git a/resources/jquery/jquery.textSelection.js b/resources/jquery/jquery.textSelection.js
index f3d1a146..91b6e75d 100644
--- a/resources/jquery/jquery.textSelection.js
+++ b/resources/jquery/jquery.textSelection.js
@@ -87,7 +87,7 @@ getSelection: function() {
encapsulateSelection: function( options ) {
return this.each( function() {
var pre = options.pre, post = options.post;
-
+
/**
* Check if the selected text is the same as the insert text
*/
@@ -110,10 +110,10 @@ encapsulateSelection: function( options ) {
}
}
}
-
+
/**
* Do the splitlines stuff.
- *
+ *
* Wrap each line of the selected text with pre and post
*/
function doSplitLines( selText, pre, post ) {
@@ -127,12 +127,62 @@ encapsulateSelection: function( options ) {
}
return insertText;
}
-
+
var isSample = false;
if ( this.style.display == 'none' ) {
// Do nothing
+ } else if ( document.selection && document.selection.createRange ) {
+ // IE
+
+ // Note that IE9 will trigger the next section unless we check this first.
+ // See bug 35201.
+
+ activateElementOnIE( this );
+ if ( context ) {
+ context.fn.restoreCursorAndScrollTop();
+ }
+ if ( options.selectionStart !== undefined ) {
+ $(this).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
+ }
+
+ var selText = $(this).textSelection( 'getSelection' );
+ var scrollTop = this.scrollTop;
+ var range = document.selection.createRange();
+
+ checkSelectedText();
+ var insertText = pre + selText + post;
+ if ( options.splitlines ) {
+ insertText = doSplitLines( selText, pre, post );
+ }
+ if ( options.ownline && range.moveStart ) {
+ var range2 = document.selection.createRange();
+ range2.collapse();
+ range2.moveStart( 'character', -1 );
+ // FIXME: Which check is correct?
+ if ( range2.text != "\r" && range2.text != "\n" && range2.text != "" ) {
+ insertText = "\n" + insertText;
+ pre += "\n";
+ }
+ var range3 = document.selection.createRange();
+ range3.collapse( false );
+ range3.moveEnd( 'character', 1 );
+ if ( range3.text != "\r" && range3.text != "\n" && range3.text != "" ) {
+ insertText += "\n";
+ post += "\n";
+ }
+ }
+
+ range.text = insertText;
+ if ( isSample && options.selectPeri && range.moveStart ) {
+ range.moveStart( 'character', - post.length - selText.length );
+ range.moveEnd( 'character', - post.length );
+ }
+ range.select();
+ // Restore the scroll position
+ this.scrollTop = scrollTop;
} else if ( this.selectionStart || this.selectionStart == '0' ) {
// Mozilla/Opera
+
$(this).focus();
if ( options.selectionStart !== undefined ) {
$(this).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
@@ -143,7 +193,6 @@ encapsulateSelection: function( options ) {
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
checkSelectedText();
-
if ( options.selectionStart !== undefined
&& endPos - startPos != options.selectionEnd - options.selectionStart )
{
@@ -158,11 +207,13 @@ encapsulateSelection: function( options ) {
insertText = doSplitLines( selText, pre, post );
}
if ( options.ownline ) {
- if ( startPos != 0 && this.value.charAt( startPos - 1 ) != "\n" ) {
+ if ( startPos != 0 && this.value.charAt( startPos - 1 ) != "\n" && this.value.charAt( startPos - 1 ) != "\r" ) {
insertText = "\n" + insertText;
+ pre += "\n";
}
- if ( this.value.charAt( endPos ) != "\n" ) {
+ if ( this.value.charAt( endPos ) != "\n" && this.value.charAt( endPos ) != "\r" ) {
insertText += "\n";
+ post += "\n";
}
}
this.value = this.value.substring( 0, startPos ) + insertText +
@@ -181,49 +232,6 @@ encapsulateSelection: function( options ) {
this.selectionStart = startPos + insertText.length;
this.selectionEnd = this.selectionStart;
}
- } else if ( document.selection && document.selection.createRange ) {
- // IE
- activateElementOnIE( this );
- if ( context ) {
- context.fn.restoreCursorAndScrollTop();
- }
- if ( options.selectionStart !== undefined ) {
- $(this).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
- }
-
- var selText = $(this).textSelection( 'getSelection' );
- var scrollTop = this.scrollTop;
- var range = document.selection.createRange();
-
- checkSelectedText();
- var insertText = pre + selText + post;
- if ( options.splitlines ) {
- insertText = doSplitLines( selText, pre, post );
- }
- if ( options.ownline && range.moveStart ) {
- var range2 = document.selection.createRange();
- range2.collapse();
- range2.moveStart( 'character', -1 );
- // FIXME: Which check is correct?
- if ( range2.text != "\r" && range2.text != "\n" && range2.text != "" ) {
- insertText = "\n" + insertText;
- }
- var range3 = document.selection.createRange();
- range3.collapse( false );
- range3.moveEnd( 'character', 1 );
- if ( range3.text != "\r" && range3.text != "\n" && range3.text != "" ) {
- insertText += "\n";
- }
- }
-
- range.text = insertText;
- if ( isSample && options.selectPeri && range.moveStart ) {
- range.moveStart( 'character', - post.length - selText.length );
- range.moveEnd( 'character', - post.length );
- }
- range.select();
- // Restore the scroll position
- this.scrollTop = scrollTop;
}
$(this).trigger( 'encapsulateSelection', [ options.pre, options.peri, options.post, options.ownline,
options.replace, options.spitlines ] );
@@ -349,10 +357,10 @@ setSelection: function( options ) {
var length = this.value.length;
// IE doesn't count \n when computing the offset, so we won't either
var newLines = this.value.match( /\n/g );
- if ( newLines) length = length - newLines.length;
+ if ( newLines ) length = length - newLines.length;
selection.moveStart( 'character', options.start );
selection.moveEnd( 'character', -length + options.end );
-
+
// This line can cause an error under certain circumstances (textarea empty, no selection)
// Silence that error
try {
@@ -503,14 +511,14 @@ scrollToCaretPosition: function( options ) {
}
var context = $(this).data( 'wikiEditor-context' );
var hasIframe = typeof context !== 'undefined' && context && typeof context.$iframe !== 'undefined';
-
+
// IE selection restore voodoo
var needSave = false;
if ( hasIframe && context.savedSelection !== null ) {
context.fn.restoreSelection();
needSave = true;
}
- retval = ( hasIframe ? context.fn : fn )[command].call( this, options );
+ var retval = ( hasIframe ? context.fn : fn )[command].call( this, options );
if ( hasIframe && needSave ) {
context.fn.saveSelection();
}
diff --git a/resources/jquery/jquery.validate.js b/resources/jquery/jquery.validate.js
new file mode 100644
index 00000000..72296a61
--- /dev/null
+++ b/resources/jquery/jquery.validate.js
@@ -0,0 +1,1166 @@
+/**
+ * jQuery Validation Plugin 1.8.1
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
+ * http://docs.jquery.com/Plugins/Validation
+ *
+ * Copyright (c) 2006 - 2011 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+(function($) {
+
+$.extend($.fn, {
+ // http://docs.jquery.com/Plugins/Validation/validate
+ validate: function( options ) {
+
+ // if nothing is selected, return nothing; can't chain anyway
+ if (!this.length) {
+ options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
+ return;
+ }
+
+ // check if a validator for this form was already created
+ var validator = $.data(this[0], 'validator');
+ if ( validator ) {
+ return validator;
+ }
+
+ validator = new $.validator( options, this[0] );
+ $.data(this[0], 'validator', validator);
+
+ if ( validator.settings.onsubmit ) {
+
+ // allow suppresing validation by adding a cancel class to the submit button
+ this.find("input, button").filter(".cancel").click(function() {
+ validator.cancelSubmit = true;
+ });
+
+ // when a submitHandler is used, capture the submitting button
+ if (validator.settings.submitHandler) {
+ this.find("input, button").filter(":submit").click(function() {
+ validator.submitButton = this;
+ });
+ }
+
+ // validate the form on submit
+ this.submit( function( event ) {
+ if ( validator.settings.debug )
+ // prevent form submit to be able to see console output
+ event.preventDefault();
+
+ function handle() {
+ if ( validator.settings.submitHandler ) {
+ if (validator.submitButton) {
+ // insert a hidden input as a replacement for the missing submit button
+ var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
+ }
+ validator.settings.submitHandler.call( validator, validator.currentForm );
+ if (validator.submitButton) {
+ // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
+ hidden.remove();
+ }
+ return false;
+ }
+ return true;
+ }
+
+ // prevent submit for invalid forms or custom submit handlers
+ if ( validator.cancelSubmit ) {
+ validator.cancelSubmit = false;
+ return handle();
+ }
+ if ( validator.form() ) {
+ if ( validator.pendingRequest ) {
+ validator.formSubmitted = true;
+ return false;
+ }
+ return handle();
+ } else {
+ validator.focusInvalid();
+ return false;
+ }
+ });
+ }
+
+ return validator;
+ },
+ // http://docs.jquery.com/Plugins/Validation/valid
+ valid: function() {
+ if ( $(this[0]).is('form')) {
+ return this.validate().form();
+ } else {
+ var valid = true;
+ var validator = $(this[0].form).validate();
+ this.each(function() {
+ valid &= validator.element(this);
+ });
+ return valid;
+ }
+ },
+ // attributes: space seperated list of attributes to retrieve and remove
+ removeAttrs: function(attributes) {
+ var result = {},
+ $element = this;
+ $.each(attributes.split(/\s/), function(index, value) {
+ result[value] = $element.attr(value);
+ $element.removeAttr(value);
+ });
+ return result;
+ },
+ // http://docs.jquery.com/Plugins/Validation/rules
+ rules: function(command, argument) {
+ var element = this[0];
+
+ if (command) {
+ var settings = $.data(element.form, 'validator').settings;
+ var staticRules = settings.rules;
+ var existingRules = $.validator.staticRules(element);
+ switch(command) {
+ case "add":
+ $.extend(existingRules, $.validator.normalizeRule(argument));
+ staticRules[element.name] = existingRules;
+ if (argument.messages)
+ settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
+ break;
+ case "remove":
+ if (!argument) {
+ delete staticRules[element.name];
+ return existingRules;
+ }
+ var filtered = {};
+ $.each(argument.split(/\s/), function(index, method) {
+ filtered[method] = existingRules[method];
+ delete existingRules[method];
+ });
+ return filtered;
+ }
+ }
+
+ var data = $.validator.normalizeRules(
+ $.extend(
+ {},
+ $.validator.metadataRules(element),
+ $.validator.classRules(element),
+ $.validator.attributeRules(element),
+ $.validator.staticRules(element)
+ ), element);
+
+ // make sure required is at front
+ if (data.required) {
+ var param = data.required;
+ delete data.required;
+ data = $.extend({required: param}, data);
+ }
+
+ return data;
+ }
+});
+
+// Custom selectors
+$.extend($.expr[":"], {
+ // http://docs.jquery.com/Plugins/Validation/blank
+ blank: function(a) {return !$.trim("" + a.value);},
+ // http://docs.jquery.com/Plugins/Validation/filled
+ filled: function(a) {return !!$.trim("" + a.value);},
+ // http://docs.jquery.com/Plugins/Validation/unchecked
+ unchecked: function(a) {return !a.checked;}
+});
+
+// constructor for validator
+$.validator = function( options, form ) {
+ this.settings = $.extend( true, {}, $.validator.defaults, options );
+ this.currentForm = form;
+ this.init();
+};
+
+$.validator.format = function(source, params) {
+ if ( arguments.length == 1 )
+ return function() {
+ var args = $.makeArray(arguments);
+ args.unshift(source);
+ return $.validator.format.apply( this, args );
+ };
+ if ( arguments.length > 2 && params.constructor != Array ) {
+ params = $.makeArray(arguments).slice(1);
+ }
+ if ( params.constructor != Array ) {
+ params = [ params ];
+ }
+ $.each(params, function(i, n) {
+ source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
+ });
+ return source;
+};
+
+$.extend($.validator, {
+
+ defaults: {
+ messages: {},
+ groups: {},
+ rules: {},
+ errorClass: "error",
+ validClass: "valid",
+ errorElement: "label",
+ focusInvalid: true,
+ errorContainer: $( [] ),
+ errorLabelContainer: $( [] ),
+ onsubmit: true,
+ ignore: [],
+ ignoreTitle: false,
+ onfocusin: function(element) {
+ this.lastActive = element;
+
+ // hide error label and remove error class on focus if enabled
+ if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
+ this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
+ this.addWrapper(this.errorsFor(element)).hide();
+ }
+ },
+ onfocusout: function(element) {
+ if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
+ this.element(element);
+ }
+ },
+ onkeyup: function(element) {
+ if ( element.name in this.submitted || element == this.lastElement ) {
+ this.element(element);
+ }
+ },
+ onclick: function(element) {
+ // click on selects, radiobuttons and checkboxes
+ if ( element.name in this.submitted )
+ this.element(element);
+ // or option elements, check parent select in that case
+ else if (element.parentNode.name in this.submitted)
+ this.element(element.parentNode);
+ },
+ highlight: function(element, errorClass, validClass) {
+ if (element.type === 'radio') {
+ this.findByName(element.name).addClass(errorClass).removeClass(validClass);
+ } else {
+ $(element).addClass(errorClass).removeClass(validClass);
+ }
+ },
+ unhighlight: function(element, errorClass, validClass) {
+ if (element.type === 'radio') {
+ this.findByName(element.name).removeClass(errorClass).addClass(validClass);
+ } else {
+ $(element).removeClass(errorClass).addClass(validClass);
+ }
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
+ setDefaults: function(settings) {
+ $.extend( $.validator.defaults, settings );
+ },
+
+ messages: {
+ required: "This field is required.",
+ remote: "Please fix this field.",
+ email: "Please enter a valid email address.",
+ url: "Please enter a valid URL.",
+ date: "Please enter a valid date.",
+ dateISO: "Please enter a valid date (ISO).",
+ number: "Please enter a valid number.",
+ digits: "Please enter only digits.",
+ creditcard: "Please enter a valid credit card number.",
+ equalTo: "Please enter the same value again.",
+ accept: "Please enter a value with a valid extension.",
+ maxlength: $.validator.format("Please enter no more than {0} characters."),
+ minlength: $.validator.format("Please enter at least {0} characters."),
+ rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
+ range: $.validator.format("Please enter a value between {0} and {1}."),
+ max: $.validator.format("Please enter a value less than or equal to {0}."),
+ min: $.validator.format("Please enter a value greater than or equal to {0}.")
+ },
+
+ autoCreateRanges: false,
+
+ prototype: {
+
+ init: function() {
+ this.labelContainer = $(this.settings.errorLabelContainer);
+ this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
+ this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
+ this.submitted = {};
+ this.valueCache = {};
+ this.pendingRequest = 0;
+ this.pending = {};
+ this.invalid = {};
+ this.reset();
+
+ var groups = (this.groups = {});
+ $.each(this.settings.groups, function(key, value) {
+ $.each(value.split(/\s/), function(index, name) {
+ groups[name] = key;
+ });
+ });
+ var rules = this.settings.rules;
+ $.each(rules, function(key, value) {
+ rules[key] = $.validator.normalizeRule(value);
+ });
+
+ function delegate(event) {
+ var validator = $.data(this[0].form, "validator"),
+ eventType = "on" + event.type.replace(/^validate/, "");
+ validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
+ }
+ $(this.currentForm)
+ .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
+ .validateDelegate(":radio, :checkbox, select, option", "click", delegate);
+
+ if (this.settings.invalidHandler)
+ $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/form
+ form: function() {
+ this.checkForm();
+ $.extend(this.submitted, this.errorMap);
+ this.invalid = $.extend({}, this.errorMap);
+ if (!this.valid())
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
+ this.showErrors();
+ return this.valid();
+ },
+
+ checkForm: function() {
+ this.prepareForm();
+ for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
+ this.check( elements[i] );
+ }
+ return this.valid();
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/element
+ element: function( element ) {
+ element = this.clean( element );
+ this.lastElement = element;
+ this.prepareElement( element );
+ this.currentElements = $(element);
+ var result = this.check( element );
+ if ( result ) {
+ delete this.invalid[element.name];
+ } else {
+ this.invalid[element.name] = true;
+ }
+ if ( !this.numberOfInvalids() ) {
+ // Hide error containers on last error
+ this.toHide = this.toHide.add( this.containers );
+ }
+ this.showErrors();
+ return result;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
+ showErrors: function(errors) {
+ if(errors) {
+ // add items to error list and map
+ $.extend( this.errorMap, errors );
+ this.errorList = [];
+ for ( var name in errors ) {
+ this.errorList.push({
+ message: errors[name],
+ element: this.findByName(name)[0]
+ });
+ }
+ // remove items from success list
+ this.successList = $.grep( this.successList, function(element) {
+ return !(element.name in errors);
+ });
+ }
+ this.settings.showErrors
+ ? this.settings.showErrors.call( this, this.errorMap, this.errorList )
+ : this.defaultShowErrors();
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
+ resetForm: function() {
+ if ( $.fn.resetForm )
+ $( this.currentForm ).resetForm();
+ this.submitted = {};
+ this.prepareForm();
+ this.hideErrors();
+ this.elements().removeClass( this.settings.errorClass );
+ },
+
+ numberOfInvalids: function() {
+ return this.objectLength(this.invalid);
+ },
+
+ objectLength: function( obj ) {
+ var count = 0;
+ for ( var i in obj )
+ count++;
+ return count;
+ },
+
+ hideErrors: function() {
+ this.addWrapper( this.toHide ).hide();
+ },
+
+ valid: function() {
+ return this.size() == 0;
+ },
+
+ size: function() {
+ return this.errorList.length;
+ },
+
+ focusInvalid: function() {
+ if( this.settings.focusInvalid ) {
+ try {
+ $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
+ .filter(":visible")
+ .focus()
+ // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
+ .trigger("focusin");
+ } catch(e) {
+ // ignore IE throwing errors when focusing hidden elements
+ }
+ }
+ },
+
+ findLastActive: function() {
+ var lastActive = this.lastActive;
+ return lastActive && $.grep(this.errorList, function(n) {
+ return n.element.name == lastActive.name;
+ }).length == 1 && lastActive;
+ },
+
+ elements: function() {
+ var validator = this,
+ rulesCache = {};
+
+ // select all valid inputs inside the form (no submit or reset buttons)
+ return $(this.currentForm)
+ .find("input, select, textarea")
+ .not(":submit, :reset, :image, [disabled]")
+ .not( this.settings.ignore )
+ .filter(function() {
+ !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
+
+ // select only the first element for each name, and only those with rules specified
+ if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
+ return false;
+
+ rulesCache[this.name] = true;
+ return true;
+ });
+ },
+
+ clean: function( selector ) {
+ return $( selector )[0];
+ },
+
+ errors: function() {
+ return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
+ },
+
+ reset: function() {
+ this.successList = [];
+ this.errorList = [];
+ this.errorMap = {};
+ this.toShow = $([]);
+ this.toHide = $([]);
+ this.currentElements = $([]);
+ },
+
+ prepareForm: function() {
+ this.reset();
+ this.toHide = this.errors().add( this.containers );
+ },
+
+ prepareElement: function( element ) {
+ this.reset();
+ this.toHide = this.errorsFor(element);
+ },
+
+ check: function( element ) {
+ element = this.clean( element );
+
+ // if radio/checkbox, validate first element in group instead
+ if (this.checkable(element)) {
+ element = this.findByName( element.name ).not(this.settings.ignore)[0];
+ }
+
+ var rules = $(element).rules();
+ var dependencyMismatch = false;
+ for (var method in rules ) {
+ var rule = { method: method, parameters: rules[method] };
+ try {
+ var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
+
+ // if a method indicates that the field is optional and therefore valid,
+ // don't mark it as valid when there are no other rules
+ if ( result == "dependency-mismatch" ) {
+ dependencyMismatch = true;
+ continue;
+ }
+ dependencyMismatch = false;
+
+ if ( result == "pending" ) {
+ this.toHide = this.toHide.not( this.errorsFor(element) );
+ return;
+ }
+
+ if( !result ) {
+ this.formatAndAdd( element, rule );
+ return false;
+ }
+ } catch(e) {
+ this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
+ + ", check the '" + rule.method + "' method", e);
+ throw e;
+ }
+ }
+ if (dependencyMismatch)
+ return;
+ if ( this.objectLength(rules) )
+ this.successList.push(element);
+ return true;
+ },
+
+ // return the custom message for the given element and validation method
+ // specified in the element's "messages" metadata
+ customMetaMessage: function(element, method) {
+ if (!$.metadata)
+ return;
+
+ var meta = this.settings.meta
+ ? $(element).metadata()[this.settings.meta]
+ : $(element).metadata();
+
+ return meta && meta.messages && meta.messages[method];
+ },
+
+ // return the custom message for the given element name and validation method
+ customMessage: function( name, method ) {
+ var m = this.settings.messages[name];
+ return m && (m.constructor == String
+ ? m
+ : m[method]);
+ },
+
+ // return the first defined argument, allowing empty strings
+ findDefined: function() {
+ for(var i = 0; i < arguments.length; i++) {
+ if (arguments[i] !== undefined)
+ return arguments[i];
+ }
+ return undefined;
+ },
+
+ defaultMessage: function( element, method) {
+ return this.findDefined(
+ this.customMessage( element.name, method ),
+ this.customMetaMessage( element, method ),
+ // title is never undefined, so handle empty string as undefined
+ !this.settings.ignoreTitle && element.title || undefined,
+ $.validator.messages[method],
+ "<strong>Warning: No message defined for " + element.name + "</strong>"
+ );
+ },
+
+ formatAndAdd: function( element, rule ) {
+ var message = this.defaultMessage( element, rule.method ),
+ theregex = /\$?\{(\d+)\}/g;
+ if ( typeof message == "function" ) {
+ message = message.call(this, rule.parameters, element);
+ } else if (theregex.test(message)) {
+ message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
+ }
+ this.errorList.push({
+ message: message,
+ element: element
+ });
+
+ this.errorMap[element.name] = message;
+ this.submitted[element.name] = message;
+ },
+
+ addWrapper: function(toToggle) {
+ if ( this.settings.wrapper )
+ toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
+ return toToggle;
+ },
+
+ defaultShowErrors: function() {
+ for ( var i = 0; this.errorList[i]; i++ ) {
+ var error = this.errorList[i];
+ this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
+ this.showLabel( error.element, error.message );
+ }
+ if( this.errorList.length ) {
+ this.toShow = this.toShow.add( this.containers );
+ }
+ if (this.settings.success) {
+ for ( var i = 0; this.successList[i]; i++ ) {
+ this.showLabel( this.successList[i] );
+ }
+ }
+ if (this.settings.unhighlight) {
+ for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
+ this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
+ }
+ }
+ this.toHide = this.toHide.not( this.toShow );
+ this.hideErrors();
+ this.addWrapper( this.toShow ).show();
+ },
+
+ validElements: function() {
+ return this.currentElements.not(this.invalidElements());
+ },
+
+ invalidElements: function() {
+ return $(this.errorList).map(function() {
+ return this.element;
+ });
+ },
+
+ showLabel: function(element, message) {
+ var label = this.errorsFor( element );
+ if ( label.length ) {
+ // refresh error/success class
+ label.removeClass().addClass( this.settings.errorClass );
+
+ // check if we have a generated label, replace the message then
+ label.attr("generated") && label.html(message);
+ } else {
+ // create label
+ label = $("<" + this.settings.errorElement + "/>")
+ .attr({"for": this.idOrName(element), generated: true})
+ .addClass(this.settings.errorClass)
+ .html(message || "");
+ if ( this.settings.wrapper ) {
+ // make sure the element is visible, even in IE
+ // actually showing the wrapped element is handled elsewhere
+ label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
+ }
+ if ( !this.labelContainer.append(label).length )
+ this.settings.errorPlacement
+ ? this.settings.errorPlacement(label, $(element) )
+ : label.insertAfter(element);
+ }
+ if ( !message && this.settings.success ) {
+ label.text("");
+ typeof this.settings.success == "string"
+ ? label.addClass( this.settings.success )
+ : this.settings.success( label );
+ }
+ this.toShow = this.toShow.add(label);
+ },
+
+ errorsFor: function(element) {
+ var name = this.idOrName(element);
+ return this.errors().filter(function() {
+ return $(this).attr('for') == name;
+ });
+ },
+
+ idOrName: function(element) {
+ return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
+ },
+
+ checkable: function( element ) {
+ return /radio|checkbox/i.test(element.type);
+ },
+
+ findByName: function( name ) {
+ // select by name and filter by form for performance over form.find("[name=...]")
+ var form = this.currentForm;
+ return $(document.getElementsByName(name)).map(function(index, element) {
+ return element.form == form && element.name == name && element || null;
+ });
+ },
+
+ getLength: function(value, element) {
+ switch( element.nodeName.toLowerCase() ) {
+ case 'select':
+ return $("option:selected", element).length;
+ case 'input':
+ if( this.checkable( element) )
+ return this.findByName(element.name).filter(':checked').length;
+ }
+ return value.length;
+ },
+
+ depend: function(param, element) {
+ return this.dependTypes[typeof param]
+ ? this.dependTypes[typeof param](param, element)
+ : true;
+ },
+
+ dependTypes: {
+ "boolean": function(param, element) {
+ return param;
+ },
+ "string": function(param, element) {
+ return !!$(param, element.form).length;
+ },
+ "function": function(param, element) {
+ return param(element);
+ }
+ },
+
+ optional: function(element) {
+ return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
+ },
+
+ startRequest: function(element) {
+ if (!this.pending[element.name]) {
+ this.pendingRequest++;
+ this.pending[element.name] = true;
+ }
+ },
+
+ stopRequest: function(element, valid) {
+ this.pendingRequest--;
+ // sometimes synchronization fails, make sure pendingRequest is never < 0
+ if (this.pendingRequest < 0)
+ this.pendingRequest = 0;
+ delete this.pending[element.name];
+ if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
+ $(this.currentForm).submit();
+ this.formSubmitted = false;
+ } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
+ this.formSubmitted = false;
+ }
+ },
+
+ previousValue: function(element) {
+ return $.data(element, "previousValue") || $.data(element, "previousValue", {
+ old: null,
+ valid: true,
+ message: this.defaultMessage( element, "remote" )
+ });
+ }
+
+ },
+
+ classRuleSettings: {
+ required: {required: true},
+ email: {email: true},
+ url: {url: true},
+ date: {date: true},
+ dateISO: {dateISO: true},
+ dateDE: {dateDE: true},
+ number: {number: true},
+ numberDE: {numberDE: true},
+ digits: {digits: true},
+ creditcard: {creditcard: true}
+ },
+
+ addClassRules: function(className, rules) {
+ className.constructor == String ?
+ this.classRuleSettings[className] = rules :
+ $.extend(this.classRuleSettings, className);
+ },
+
+ classRules: function(element) {
+ var rules = {};
+ var classes = $(element).attr('class');
+ classes && $.each(classes.split(' '), function() {
+ if (this in $.validator.classRuleSettings) {
+ $.extend(rules, $.validator.classRuleSettings[this]);
+ }
+ });
+ return rules;
+ },
+
+ attributeRules: function(element) {
+ var rules = {};
+ var $element = $(element);
+
+ for (var method in $.validator.methods) {
+ var value = $element.attr(method);
+ if (value) {
+ rules[method] = value;
+ }
+ }
+
+ // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
+ if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
+ delete rules.maxlength;
+ }
+
+ return rules;
+ },
+
+ metadataRules: function(element) {
+ if (!$.metadata) return {};
+
+ var meta = $.data(element.form, 'validator').settings.meta;
+ return meta ?
+ $(element).metadata()[meta] :
+ $(element).metadata();
+ },
+
+ staticRules: function(element) {
+ var rules = {};
+ var validator = $.data(element.form, 'validator');
+ if (validator.settings.rules) {
+ rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
+ }
+ return rules;
+ },
+
+ normalizeRules: function(rules, element) {
+ // handle dependency check
+ $.each(rules, function(prop, val) {
+ // ignore rule when param is explicitly false, eg. required:false
+ if (val === false) {
+ delete rules[prop];
+ return;
+ }
+ if (val.param || val.depends) {
+ var keepRule = true;
+ switch (typeof val.depends) {
+ case "string":
+ keepRule = !!$(val.depends, element.form).length;
+ break;
+ case "function":
+ keepRule = val.depends.call(element, element);
+ break;
+ }
+ if (keepRule) {
+ rules[prop] = val.param !== undefined ? val.param : true;
+ } else {
+ delete rules[prop];
+ }
+ }
+ });
+
+ // evaluate parameters
+ $.each(rules, function(rule, parameter) {
+ rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
+ });
+
+ // clean number parameters
+ $.each(['minlength', 'maxlength', 'min', 'max'], function() {
+ if (rules[this]) {
+ rules[this] = Number(rules[this]);
+ }
+ });
+ $.each(['rangelength', 'range'], function() {
+ if (rules[this]) {
+ rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
+ }
+ });
+
+ if ($.validator.autoCreateRanges) {
+ // auto-create ranges
+ if (rules.min && rules.max) {
+ rules.range = [rules.min, rules.max];
+ delete rules.min;
+ delete rules.max;
+ }
+ if (rules.minlength && rules.maxlength) {
+ rules.rangelength = [rules.minlength, rules.maxlength];
+ delete rules.minlength;
+ delete rules.maxlength;
+ }
+ }
+
+ // To support custom messages in metadata ignore rule methods titled "messages"
+ if (rules.messages) {
+ delete rules.messages;
+ }
+
+ return rules;
+ },
+
+ // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
+ normalizeRule: function(data) {
+ if( typeof data == "string" ) {
+ var transformed = {};
+ $.each(data.split(/\s/), function() {
+ transformed[this] = true;
+ });
+ data = transformed;
+ }
+ return data;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
+ addMethod: function(name, method, message) {
+ $.validator.methods[name] = method;
+ $.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
+ if (method.length < 3) {
+ $.validator.addClassRules(name, $.validator.normalizeRule(name));
+ }
+ },
+
+ methods: {
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/required
+ required: function(value, element, param) {
+ // check if dependency is met
+ if ( !this.depend(param, element) )
+ return "dependency-mismatch";
+ switch( element.nodeName.toLowerCase() ) {
+ case 'select':
+ // could be an array for select-multiple or a string, both are fine this way
+ var val = $(element).val();
+ return val && val.length > 0;
+ case 'input':
+ if ( this.checkable(element) )
+ return this.getLength(value, element) > 0;
+ default:
+ return $.trim(value).length > 0;
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/remote
+ remote: function(value, element, param) {
+ if ( this.optional(element) )
+ return "dependency-mismatch";
+
+ var previous = this.previousValue(element);
+ if (!this.settings.messages[element.name] )
+ this.settings.messages[element.name] = {};
+ previous.originalMessage = this.settings.messages[element.name].remote;
+ this.settings.messages[element.name].remote = previous.message;
+
+ param = typeof param == "string" && {url:param} || param;
+
+ if ( this.pending[element.name] ) {
+ return "pending";
+ }
+ if ( previous.old === value ) {
+ return previous.valid;
+ }
+
+ previous.old = value;
+ var validator = this;
+ this.startRequest(element);
+ var data = {};
+ data[element.name] = value;
+ $.ajax($.extend(true, {
+ url: param,
+ mode: "abort",
+ port: "validate" + element.name,
+ dataType: "json",
+ data: data,
+ success: function(response) {
+ validator.settings.messages[element.name].remote = previous.originalMessage;
+ var valid = response === true;
+ if ( valid ) {
+ var submitted = validator.formSubmitted;
+ validator.prepareElement(element);
+ validator.formSubmitted = submitted;
+ validator.successList.push(element);
+ validator.showErrors();
+ } else {
+ var errors = {};
+ var message = response || validator.defaultMessage( element, "remote" );
+ errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
+ validator.showErrors(errors);
+ }
+ previous.valid = valid;
+ validator.stopRequest(element, valid);
+ }
+ }, param));
+ return "pending";
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/minlength
+ minlength: function(value, element, param) {
+ return this.optional(element) || this.getLength($.trim(value), element) >= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
+ maxlength: function(value, element, param) {
+ return this.optional(element) || this.getLength($.trim(value), element) <= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
+ rangelength: function(value, element, param) {
+ var length = this.getLength($.trim(value), element);
+ return this.optional(element) || ( length >= param[0] && length <= param[1] );
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/min
+ min: function( value, element, param ) {
+ return this.optional(element) || value >= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/max
+ max: function( value, element, param ) {
+ return this.optional(element) || value <= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/range
+ range: function( value, element, param ) {
+ return this.optional(element) || ( value >= param[0] && value <= param[1] );
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/email
+ email: function(value, element) {
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
+ return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/url
+ url: function(value, element) {
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
+ return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/date
+ date: function(value, element) {
+ return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
+ dateISO: function(value, element) {
+ return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/number
+ number: function(value, element) {
+ return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/digits
+ digits: function(value, element) {
+ return this.optional(element) || /^\d+$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
+ // based on http://en.wikipedia.org/wiki/Luhn
+ creditcard: function(value, element) {
+ if ( this.optional(element) )
+ return "dependency-mismatch";
+ // accept only digits and dashes
+ if (/[^0-9-]+/.test(value))
+ return false;
+ var nCheck = 0,
+ nDigit = 0,
+ bEven = false;
+
+ value = value.replace(/\D/g, "");
+
+ for (var n = value.length - 1; n >= 0; n--) {
+ var cDigit = value.charAt(n);
+ var nDigit = parseInt(cDigit, 10);
+ if (bEven) {
+ if ((nDigit *= 2) > 9)
+ nDigit -= 9;
+ }
+ nCheck += nDigit;
+ bEven = !bEven;
+ }
+
+ return (nCheck % 10) == 0;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/accept
+ accept: function(value, element, param) {
+ param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
+ return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
+ equalTo: function(value, element, param) {
+ // bind to the blur event of the target in order to revalidate whenever the target field is updated
+ // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
+ var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
+ $(element).valid();
+ });
+ return value == target.val();
+ }
+
+ }
+
+});
+
+// deprecated, use $.validator.format instead
+$.format = $.validator.format;
+
+})(jQuery);
+
+// ajax mode: abort
+// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
+// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
+;(function($) {
+ var pendingRequests = {};
+ // Use a prefilter if available (1.5+)
+ if ( $.ajaxPrefilter ) {
+ $.ajaxPrefilter(function(settings, _, xhr) {
+ var port = settings.port;
+ if (settings.mode == "abort") {
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ pendingRequests[port] = xhr;
+ }
+ });
+ } else {
+ // Proxy ajax
+ var ajax = $.ajax;
+ $.ajax = function(settings) {
+ var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
+ port = ( "port" in settings ? settings : $.ajaxSettings ).port;
+ if (mode == "abort") {
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ return (pendingRequests[port] = ajax.apply(this, arguments));
+ }
+ return ajax.apply(this, arguments);
+ };
+ }
+})(jQuery);
+
+// provides cross-browser focusin and focusout events
+// IE has native support, in other browsers, use event caputuring (neither bubbles)
+
+// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
+// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
+;(function($) {
+ // only implement if not provided by jQuery core (since 1.4)
+ // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
+ if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
+ $.each({
+ focus: 'focusin',
+ blur: 'focusout'
+ }, function( original, fix ){
+ $.event.special[fix] = {
+ setup:function() {
+ this.addEventListener( original, handler, true );
+ },
+ teardown:function() {
+ this.removeEventListener( original, handler, true );
+ },
+ handler: function(e) {
+ arguments[0] = $.event.fix(e);
+ arguments[0].type = fix;
+ return $.event.handle.apply(this, arguments);
+ }
+ };
+ function handler(e) {
+ e = $.event.fix(e);
+ e.type = fix;
+ return $.event.handle.call(this, e);
+ }
+ });
+ };
+ $.extend($.fn, {
+ validateDelegate: function(delegate, type, handler) {
+ return this.bind(type, function(event) {
+ var target = $(event.target);
+ if (target.is(delegate)) {
+ return handler.apply(target, arguments);
+ }
+ });
+ }
+ });
+})(jQuery);
diff --git a/resources/jquery/jquery.xmldom.js b/resources/jquery/jquery.xmldom.js
new file mode 100644
index 00000000..85d0083d
--- /dev/null
+++ b/resources/jquery/jquery.xmldom.js
@@ -0,0 +1,46 @@
+/*!
+ * jQuery xmlDOM Plugin v1.0
+ * http://outwestmedia.com/jquery-plugins/xmldom/
+ *
+ * Released: 2009-04-06
+ * Version: 1.0
+ *
+ * Copyright (c) 2009 Jonathan Sharp, Out West Media LLC.
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ */
+(function($) {
+ // IE DOMParser wrapper
+ if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
+ DOMParser = function() { };
+ DOMParser.prototype.parseFromString = function( xmlString ) {
+ var doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML( xmlString );
+ return doc;
+ };
+ }
+
+ $.xmlDOM = function(xml, onErrorFn) {
+ try {
+ var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
+ if ( $.isXMLDoc( xmlDoc ) ) {
+ var err = $('parsererror', xmlDoc);
+ if ( err.length == 1 ) {
+ throw('Error: ' + $(xmlDoc).text() );
+ }
+ } else {
+ throw('Unable to parse XML');
+ }
+ } catch( e ) {
+ var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
+ if ( $.isFunction( onErrorFn ) ) {
+ onErrorFn( msg );
+ } else {
+ $(document).trigger('xmlParseError', [ msg ]);
+ }
+ return $([]);
+ }
+ return $( xmlDoc );
+ };
+})(jQuery); \ No newline at end of file