From 63601400e476c6cf43d985f3e7b9864681695ed4 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Fri, 18 Jan 2013 16:46:04 +0100 Subject: Update to MediaWiki 1.20.2 this update includes: * adjusted Arch Linux skin * updated FluxBBAuthPlugin * patch for https://bugzilla.wikimedia.org/show_bug.cgi?id=44024 --- .../images/jquery.arrowSteps.divider-ltr.png | Bin 307 -> 135 bytes .../images/jquery.arrowSteps.divider-rtl.png | Bin 310 -> 139 bytes .../jquery/images/jquery.arrowSteps.head-ltr.png | Bin 939 -> 390 bytes .../jquery/images/jquery.arrowSteps.head-rtl.png | Bin 1006 -> 365 bytes .../jquery/images/jquery.arrowSteps.tail-ltr.png | Bin 338 -> 223 bytes .../jquery/images/jquery.arrowSteps.tail-rtl.png | Bin 485 -> 219 bytes resources/jquery/images/spinner-large.gif | Bin 0 -> 1788 bytes resources/jquery/images/spinner.gif | Bin 4648 -> 1819 bytes resources/jquery/images/wheel.png | Bin 11733 -> 11505 bytes resources/jquery/jquery.arrowSteps.css | 2 +- resources/jquery/jquery.arrowSteps.js | 50 +- resources/jquery/jquery.autoEllipsis.js | 82 +- resources/jquery/jquery.badge.css | 39 + resources/jquery/jquery.badge.js | 117 + resources/jquery/jquery.byteLength.js | 6 +- resources/jquery/jquery.byteLimit.js | 266 +- resources/jquery/jquery.checkboxShiftClick.js | 39 +- resources/jquery/jquery.client.js | 63 +- resources/jquery/jquery.collapsibleTabs.js | 95 +- resources/jquery/jquery.color.js | 64 +- resources/jquery/jquery.colorUtil.js | 379 +- resources/jquery/jquery.cookie.js | 127 +- resources/jquery/jquery.delayedBind.js | 29 +- resources/jquery/jquery.expandableField.js | 226 +- resources/jquery/jquery.form.js | 1654 ++-- resources/jquery/jquery.getAttrs.js | 4 +- resources/jquery/jquery.highlightText.js | 115 +- resources/jquery/jquery.jStorage.js | 532 ++ resources/jquery/jquery.js | 8450 ++++++++++---------- resources/jquery/jquery.json.js | 349 +- resources/jquery/jquery.localize.js | 206 +- resources/jquery/jquery.makeCollapsible.js | 72 +- resources/jquery/jquery.messageBox.css | 15 - resources/jquery/jquery.messageBox.js | 98 - resources/jquery/jquery.mwExtension.js | 34 +- resources/jquery/jquery.placeholder.js | 134 +- resources/jquery/jquery.qunit.completenessTest.js | 515 +- resources/jquery/jquery.qunit.css | 61 +- resources/jquery/jquery.qunit.js | 1972 +++-- resources/jquery/jquery.spinner.css | 34 +- resources/jquery/jquery.spinner.js | 119 +- resources/jquery/jquery.suggestions.css | 15 +- resources/jquery/jquery.suggestions.js | 185 +- resources/jquery/jquery.tabIndex.js | 90 +- resources/jquery/jquery.tablesorter.js | 291 +- resources/jquery/jquery.textSelection.js | 999 +-- 46 files changed, 9687 insertions(+), 7841 deletions(-) create mode 100644 resources/jquery/images/spinner-large.gif create mode 100644 resources/jquery/jquery.badge.css create mode 100644 resources/jquery/jquery.badge.js create mode 100644 resources/jquery/jquery.jStorage.js delete mode 100644 resources/jquery/jquery.messageBox.css delete mode 100644 resources/jquery/jquery.messageBox.js (limited to 'resources/jquery') diff --git a/resources/jquery/images/jquery.arrowSteps.divider-ltr.png b/resources/jquery/images/jquery.arrowSteps.divider-ltr.png index 0de1ae9c..83d6ff84 100644 Binary files a/resources/jquery/images/jquery.arrowSteps.divider-ltr.png and b/resources/jquery/images/jquery.arrowSteps.divider-ltr.png differ diff --git a/resources/jquery/images/jquery.arrowSteps.divider-rtl.png b/resources/jquery/images/jquery.arrowSteps.divider-rtl.png index f3f06519..529d7b84 100644 Binary files a/resources/jquery/images/jquery.arrowSteps.divider-rtl.png and b/resources/jquery/images/jquery.arrowSteps.divider-rtl.png differ diff --git a/resources/jquery/images/jquery.arrowSteps.head-ltr.png b/resources/jquery/images/jquery.arrowSteps.head-ltr.png index dbcc71b9..3289617d 100644 Binary files a/resources/jquery/images/jquery.arrowSteps.head-ltr.png and b/resources/jquery/images/jquery.arrowSteps.head-ltr.png differ diff --git a/resources/jquery/images/jquery.arrowSteps.head-rtl.png b/resources/jquery/images/jquery.arrowSteps.head-rtl.png index 760798bf..3d9f70cb 100644 Binary files a/resources/jquery/images/jquery.arrowSteps.head-rtl.png and b/resources/jquery/images/jquery.arrowSteps.head-rtl.png differ diff --git a/resources/jquery/images/jquery.arrowSteps.tail-ltr.png b/resources/jquery/images/jquery.arrowSteps.tail-ltr.png index 61340fa8..92b872b2 100644 Binary files a/resources/jquery/images/jquery.arrowSteps.tail-ltr.png and b/resources/jquery/images/jquery.arrowSteps.tail-ltr.png differ diff --git a/resources/jquery/images/jquery.arrowSteps.tail-rtl.png b/resources/jquery/images/jquery.arrowSteps.tail-rtl.png index dd2d8e8a..1d3048ef 100644 Binary files a/resources/jquery/images/jquery.arrowSteps.tail-rtl.png and b/resources/jquery/images/jquery.arrowSteps.tail-rtl.png differ diff --git a/resources/jquery/images/spinner-large.gif b/resources/jquery/images/spinner-large.gif new file mode 100644 index 00000000..72203fdd Binary files /dev/null and b/resources/jquery/images/spinner-large.gif differ diff --git a/resources/jquery/images/spinner.gif b/resources/jquery/images/spinner.gif index 37d3a43d..6146be4e 100644 Binary files a/resources/jquery/images/spinner.gif and b/resources/jquery/images/spinner.gif differ diff --git a/resources/jquery/images/wheel.png b/resources/jquery/images/wheel.png index 97b343d9..7e53103e 100644 Binary files a/resources/jquery/images/wheel.png and b/resources/jquery/images/wheel.png differ diff --git a/resources/jquery/jquery.arrowSteps.css b/resources/jquery/jquery.arrowSteps.css index 60461032..f8f6e951 100644 --- a/resources/jquery/jquery.arrowSteps.css +++ b/resources/jquery/jquery.arrowSteps.css @@ -42,4 +42,4 @@ /* 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 index f9637545..488d1065 100644 --- a/resources/jquery/jquery.arrowSteps.js +++ b/resources/jquery/jquery.arrowSteps.js @@ -1,21 +1,21 @@ /** * 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 + * + * 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 + * 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 + * SYNOPSIS * * * - * * */ - -( function( $j ) { - $j.fn.arrowSteps = function() { +( function ( $ ) { + $.fn.arrowSteps = function () { + var $steps, width, arrowWidth; this.addClass( 'arrowSteps' ); - var $steps = this.find( 'li' ); + $steps = this.find( 'li' ); - var width = parseInt( 100 / $steps.length, 10 ); + 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 + // 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 ); + 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 ); + + $.fn.arrowStepsHighlight = function ( selector ) { + var $previous, + $steps = this.data( 'arrowSteps' ); + $.each( $steps, function ( i, step ) { + var $step = $( step ); if ( $step.is( selector ) ) { if ($previous) { $previous.addClass( 'tail' ); @@ -75,7 +73,7 @@ $step.removeClass( 'head tail lasthead' ); } $previous = $step; - } ); + } ); }; -} )( jQuery ); +}( jQuery ) ); diff --git a/resources/jquery/jquery.autoEllipsis.js b/resources/jquery/jquery.autoEllipsis.js index 9a5fcc9c..49a932a1 100644 --- a/resources/jquery/jquery.autoEllipsis.js +++ b/resources/jquery/jquery.autoEllipsis.js @@ -1,53 +1,57 @@ /** - * Plugin that automatically truncates the plain text contents of an element and adds an ellipsis + * Plugin that automatically truncates the plain text contents of an element + * and adds an ellipsis. */ -( function( $ ) { +( function ( $ ) { -// Cache ellipsed substrings for every string-width-position combination -var cache = { }; -// Use a separate cache when match highlighting is enabled -var matchTextCache = { }; +var + // Cache ellipsed substrings for every string-width-position combination + cache = {}, -$.fn.autoEllipsis = function( options ) { + // Use a separate cache when match highlighting is enabled + matchTextCache = {}; + +$.fn.autoEllipsis = function ( options ) { options = $.extend( { - 'position': 'center', - 'tooltip': false, - 'restoreText': false, - 'hasSpan': false, - 'matchText': null + position: 'center', + tooltip: false, + restoreText: false, + hasSpan: false, + matchText: null }, options ); - $(this).each( function() { - var $el = $(this); + + return this.each( function () { + var $trimmableText, + text, trimmableText, w, pw, + l, r, i, side, m, + // container element - used for measuring against + $container = $(this); + if ( options.restoreText ) { - if ( !$el.data( 'autoEllipsis.originalText' ) ) { - $el.data( 'autoEllipsis.originalText', $el.text() ); + if ( !$container.data( 'autoEllipsis.originalText' ) ) { + $container.data( 'autoEllipsis.originalText', $container.text() ); } else { - $el.text( $el.data( 'autoEllipsis.originalText' ) ); + $container.text( $container.data( 'autoEllipsis.originalText' ) ); } } - // container element - used for measuring against - var $container = $el; // trimmable text element - only the text within this element will be trimmed - var $trimmableText = null; - // protected text element - the width of this element is counted, but next is never trimmed from it - var $protectedText = null; - if ( options.hasSpan ) { - $trimmableText = $el.children( options.selector ); + $trimmableText = $container.children( options.selector ); } else { - $trimmableText = $( '' ) + $trimmableText = $( '' ) .css( 'whiteSpace', 'nowrap' ) - .text( $el.text() ); - $el + .text( $container.text() ); + $container .empty() .append( $trimmableText ); } - var text = $container.text(); - var trimmableText = $trimmableText.text(); - var w = $container.width(); - var pw = $protectedText ? $protectedText.width() : 0; + text = $container.text(); + trimmableText = $trimmableText.text(); + w = $container.width(); + pw = 0; + // Try cache if ( options.matchText ) { if ( !( text in matchTextCache ) ) { @@ -86,9 +90,10 @@ $.fn.autoEllipsis = function( options ) { switch ( options.position ) { case 'right': // Use binary search-like technique for efficiency - var l = 0, r = trimmableText.length; + l = 0; + r = trimmableText.length; do { - var m = Math.ceil( ( l + r ) / 2 ); + m = Math.ceil( ( l + r ) / 2 ); $trimmableText.text( trimmableText.substr( 0, m ) + '...' ); if ( $trimmableText.width() + pw > w ) { // Text is too long @@ -101,9 +106,10 @@ $.fn.autoEllipsis = function( options ) { break; case 'center': // TODO: Use binary search like for 'right' - var i = [Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 )]; - var side = 1; // Begin with making the end shorter - while ( $trimmableText.outerWidth() + pw > w && i[0] > 0 ) { + i = [Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 )]; + // Begin with making the end shorter + side = 1; + while ( $trimmableText.outerWidth() + pw > w && i[0] > 0 ) { $trimmableText.text( trimmableText.substr( 0, i[0] ) + '...' + trimmableText.substr( i[1] ) ); // Alternate between trimming the end and begining if ( side === 0 ) { @@ -119,7 +125,7 @@ $.fn.autoEllipsis = function( options ) { break; case 'left': // TODO: Use binary search like for 'right' - var r = 0; + r = 0; while ( $trimmableText.outerWidth() + pw > w && r < trimmableText.length ) { $trimmableText.text( '...' + trimmableText.substr( r ) ); r++; @@ -140,4 +146,4 @@ $.fn.autoEllipsis = function( options ) { } ); }; -} )( jQuery ); \ No newline at end of file +}( jQuery ) ); \ No newline at end of file diff --git a/resources/jquery/jquery.badge.css b/resources/jquery/jquery.badge.css new file mode 100644 index 00000000..92e72555 --- /dev/null +++ b/resources/jquery/jquery.badge.css @@ -0,0 +1,39 @@ +.mw-badge { + min-width: 8px; + height: 14px; + border: 1px solid white; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; + -moz-box-shadow: 0px 1px 4px #ccc; + -webkit-box-shadow: 0px 1px 4px #ccc; + box-shadow: 0px 1px 4px #ccc; + background-color: #b60a00; + background-image: -o-linear-gradient(bottom, #a70802 0%, #cf0e00 100%); + background-image: -moz-linear-gradient(bottom, #a70802 0%, #cf0e00 100%); + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #a70802), color-stop(1, #cf0e00)); + background-image: -webkit-linear-gradient(bottom, #a70802 0%, #cf0e00 100%); + background-image: -ms-linear-gradient(bottom, #a70802 0%, #cf0e00 100%); + background-image: linear-gradient(bottom, #a70802 0%, #cf0e00 100%); + padding: 0 3px; + text-align: center; +} + +.mw-badge-content { + font-size: 12px; + line-height: 14px; + color: white; + vertical-align: top; +} + +.mw-badge-inline { + display: inline-block; + margin-left: 3px; +} + +.mw-badge-overlay { + position: absolute; + bottom: -1px; + right: -3px; + z-index: 50; +} diff --git a/resources/jquery/jquery.badge.js b/resources/jquery/jquery.badge.js new file mode 100644 index 00000000..04495b71 --- /dev/null +++ b/resources/jquery/jquery.badge.js @@ -0,0 +1,117 @@ +/** + * jQuery Badge plugin + * + * Based on Badger plugin by Daniel Raftery (http://thrivingkings.com/badger). + * + * @license MIT + */ + +/** + * @author Ryan Kaldari , 2012 + * @author Andrew Garrett , 2012 + * @author Marius Hoch , 2012 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * This program is distributed WITHOUT ANY WARRANTY. + */ +( function ( $ ) { + + /** + * Allows you to put a numeric "badge" on an item on the page. + * See mediawiki.org/wiki/ResourceLoader/Default_modules#jQuery.badge + * + * @param {string|number} badgeCount An explicit number, or "+n"/ "-n" + * to modify the existing value. If the new value is equal or lower than 0, + * any existing badge will be removed. The badge container will be appended + * to the selected element(s). + * @param {Object} options Optional parameters specified below + * type: 'inline' or 'overlay' (default) + * callback: will be called with the number now shown on the badge as a parameter + */ + $.fn.badge = function ( badgeCount, options ) { + var $badge, + oldBadgeCount, + newBadgeCount, + $existingBadge = this.find( '.mw-badge' ); + + options = $.extend( { type : 'overlay' }, options ); + + // If there is no existing badge, this will give an empty string + oldBadgeCount = Number( $existingBadge.text() ); + if ( isNaN( oldBadgeCount ) ) { + oldBadgeCount = 0; + } + + // If badgeCount is a number, use that as the new badge + if ( typeof badgeCount === 'number' ) { + newBadgeCount = badgeCount; + } else if ( typeof badgeCount === 'string' ) { + // If badgeCount is "+x", add x to the old badge + if ( badgeCount.charAt(0) === '+' ) { + newBadgeCount = oldBadgeCount + Number( badgeCount.substr(1) ); + // If badgeCount is "-x", subtract x from the old badge + } else if ( badgeCount.charAt(0) === '-' ) { + newBadgeCount = oldBadgeCount - Number( badgeCount.substr(1) ); + // If badgeCount can be converted into a number, convert it + } else if ( !isNaN( Number( badgeCount ) ) ) { + newBadgeCount = Number( badgeCount ); + } else { + newBadgeCount = 0; + } + // Other types are not supported, fall back to 0. + } else { + newBadgeCount = 0; + } + + // Badge count must be a whole number + newBadgeCount = Math.round( newBadgeCount ); + + if ( newBadgeCount <= 0 ) { + // Badges should only exist for values > 0. + $existingBadge.remove(); + } else { + // Don't add duplicates + if ( $existingBadge.length ) { + $badge = $existingBadge; + // Insert the new count into the badge + this.find( '.mw-badge-content' ).text( newBadgeCount ); + } else { + // Contruct a new badge with the count + $badge = $( '
' ) + .addClass( 'mw-badge' ) + .append( + $( '' ) + .addClass( 'mw-badge-content' ) + .text( newBadgeCount ) + ); + this.append( $badge ); + } + + if ( options.type === 'inline' ) { + $badge + .removeClass( 'mw-badge-overlay' ) + .addClass( 'mw-badge-inline' ); + // Default: overlay + } else { + $badge + .removeClass( 'mw-badge-inline' ) + .addClass( 'mw-badge-overlay' ); + + } + + // If a callback was specified, call it with the badge count + if ( $.isFunction( options.callback ) ) { + options.callback( newBadgeCount ); + } + } + }; +}( jQuery ) ); diff --git a/resources/jquery/jquery.byteLength.js b/resources/jquery/jquery.byteLength.js index 20fa5c8e..3d5b7206 100644 --- a/resources/jquery/jquery.byteLength.js +++ b/resources/jquery/jquery.byteLength.js @@ -3,9 +3,9 @@ * * Calculate the byte length of a string (accounting for UTF-8). * - * @author Jan Paul Posma + * @author Jan Paul Posma, 2011 */ -jQuery.byteLength = function( str ) { +jQuery.byteLength = function ( str ) { // This basically figures out how many bytes a UTF-16 string (which is what js sees) // will take in UTF-8 by replacing a 2 byte character with 2 *'s, etc, and counting that. @@ -16,4 +16,4 @@ jQuery.byteLength = function( str ) { .replace( /[\u0080-\u07FF\uD800-\uDFFF]/g, '**' ) .replace( /[\u0800-\uD7FF\uE000-\uFFFF]/g, '***' ) .length; -} +}; diff --git a/resources/jquery/jquery.byteLimit.js b/resources/jquery/jquery.byteLimit.js index 10411924..75dc2b90 100644 --- a/resources/jquery/jquery.byteLimit.js +++ b/resources/jquery/jquery.byteLimit.js @@ -1,87 +1,229 @@ /** - * jQuery byteLimit + * jQuery byteLimit plugin. * - * @author Jan Paul Posma + * @author Jan Paul Posma, 2011 + * @author Timo Tijhof, 2011-2012 */ -( function( $ ) { +( function ( $ ) { /** - * 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. + * Utility function to trim down a string, based on byteLimit + * and given a safe start position. It supports insertion anywhere + * in the string, so "foo" to "fobaro" if limit is 4 will result in + * "fobo", not "foba". Basically emulating the native maxlength by + * reconstructing where the insertion occured. * - * 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! + * @param {string} safeVal Known value that was previously returned by this + * function, if none, pass empty string. + * @param {string} newVal New value that may have to be trimmed down. + * @param {number} byteLimit Number of bytes the value may be in size. + * @param {Function} fn [optional] See $.fn.byteLimit. + * @return {Object} Object with: + * - {string} newVal + * - {boolean} trimmed + */ + function trimValForByteLength( safeVal, newVal, byteLimit, fn ) { + var startMatches, endMatches, matchesLen, inpParts, + oldVal = safeVal; + + // Run the hook if one was provided, but only on the length + // assessment. The value itself is not to be affected by the hook. + if ( $.byteLength( fn ? fn( newVal ) : newVal ) <= byteLimit ) { + // Limit was not reached, just remember the new value + // and let the user continue. + return { + newVal: newVal, + trimmed: false + }; + } + + // Current input is longer than the active limit. + // Figure out what was added and limit the addition. + startMatches = 0; + endMatches = 0; + + // It is important that we keep the search within the range of + // the shortest string's length. + // Imagine a user adds text that matches the end of the old value + // (e.g. "foo" -> "foofoo"). startMatches would be 3, but without + // limiting both searches to the shortest length, endMatches would + // also be 3. + matchesLen = Math.min( newVal.length, oldVal.length ); + + // Count same characters from the left, first. + // (if "foo" -> "foofoo", assume addition was at the end). + while ( + startMatches < matchesLen && + oldVal.charAt( startMatches ) === newVal.charAt( startMatches ) + ) { + startMatches += 1; + } + + while ( + endMatches < ( matchesLen - startMatches ) && + oldVal.charAt( oldVal.length - 1 - endMatches ) === newVal.charAt( newVal.length - 1 - endMatches ) + ) { + endMatches += 1; + } + + inpParts = [ + // Same start + newVal.substring( 0, startMatches ), + // Inserted content + newVal.substring( startMatches, newVal.length - endMatches ), + // Same end + newVal.substring( newVal.length - endMatches ) + ]; + + // Chop off characters from the end of the "inserted content" string + // until the limit is statisfied. + if ( fn ) { + while ( $.byteLength( fn( inpParts.join( '' ) ) ) > byteLimit ) { + inpParts[1] = inpParts[1].slice( 0, -1 ); + } + } else { + while ( $.byteLength( inpParts.join( '' ) ) > byteLimit ) { + inpParts[1] = inpParts[1].slice( 0, -1 ); + } + } + + newVal = inpParts.join( '' ); + + return { + newVal: newVal, + trimmed: true + }; + } + + var eventKeys = [ + 'keyup.byteLimit', + 'keydown.byteLimit', + 'change.byteLimit', + 'mouseup.byteLimit', + 'cut.byteLimit', + 'paste.byteLimit', + 'focus.byteLimit', + 'blur.byteLimit' + ].join( ' ' ); + + /** + * Enforces a byte limit on an input field, so that UTF-8 entries are counted as well, + * when, for example, a database 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 parameters 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 + * @param {Number} limit [optional] Limit to enforce, fallsback to maxLength-attribute, + * called with fetched value as argument. + * @param {Function} fn [optional] Function to call on the string before assessing the length. * @return {jQuery} The context */ - $.fn.byteLimit = function( limit, fn ) { + $.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; + // Either way, verify it is a function so we don't have to call + // isFunction again after this. + } else if ( !fn || !$.isFunction( fn ) ) { + fn = undefined; } - // Default limit to current attribute value - if ( limit === undefined ) { - limit = this.prop( 'maxLength' ); - } + // The following is specific to each element in the collection. + return this.each( function ( i, el ) { + var $el, elLimit, prevSafeVal; - // 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.removeProp( 'maxLength' ); - } + $el = $( el ); - // Nothing passed and/or empty attribute, return without binding an event. - if ( limit === undefined ) { - return this; - } + // If no limit was passed to byteLimit(), use the maxlength value. + // Can't re-use 'limit' variable because it's in the higher scope + // that would affect the next each() iteration as well. + // Note that we use attribute to read the value instead of property, + // because in Chrome the maxLength property by default returns the + // highest supported value (no indication that it is being enforced + // by choice). We don't want to bind all of this for some ridiculously + // high default number, unless it was explicitly set in the HTML. + // Also cast to a (primitive) number (most commonly because the maxlength + // attribute contains a string, but theoretically the limit parameter + // could be something else as well). + elLimit = Number( limit === undefined ? $el.attr( 'maxlength' ) : limit ); - // 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 - // being pressed. - // 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. + // If there is no (valid) limit passed or found in the property, + // skip this. The < 0 check is required for Firefox, which returns + // -1 (instead of undefined) for maxLength if it is not set. + if ( !elLimit || elLimit < 0 ) { + return; } - 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 ( fn ) { + // Save function for reference + $el.data( 'byteLimit.callback', fn ); + } + + // Remove old event handlers (if there are any) + $el.off( '.byteLimit' ); - if ( ( len + charLen ) > limit ) { - e.preventDefault(); + if ( fn ) { + // Disable the native maxLength (if there is any), because it interferes + // with the (differently calculated) byte limit. + // Aside from being differently calculated (average chars with byteLimit + // is lower), we also support a callback which can make it to allow longer + // values (e.g. count "Foo" from "User:Foo"). + // maxLength is a strange property. Removing or setting the property to + // undefined directly doesn't work. Instead, it can only be unset internally + // by the browser when removing the associated attribute (Firefox/Chrome). + // http://code.google.com/p/chromium/issues/detail?id=136004 + $el.removeAttr( 'maxlength' ); + + } else { + // If we don't have a callback the bytelimit can only be lower than the charlimit + // (that is, there are no characters less than 1 byte in size). So lets (re-)enforce + // the native limit for efficiency when possible (it will make the while-loop below + // faster by there being less left to interate over). + $el.attr( 'maxlength', elLimit ); } - }); - }; -} )( jQuery ); + + // Safe base value, used to determine the path between the previous state + // and the state that triggered the event handler below - and enforce the + // limit approppiately (e.g. don't chop from the end if text was inserted + // at the beginning of the string). + prevSafeVal = ''; + + // We need to listen to after the change has already happened because we've + // learned that trying to guess the new value and canceling the event + // accordingly doesn't work because the new value is not always as simple as: + // oldValue + String.fromCharCode( e.which ); because of cut, paste, select-drag + // replacements, and custom input methods and what not. + // Even though we only trim input after it was changed (never prevent it), we do + // listen on events that input text, because there are cases where the text has + // changed while text is being entered and keyup/change will not be fired yet + // (such as holding down a single key, fires keydown, and after each keydown, + // we can trim the previous one). + // See http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboard-event-order for + // the order and characteristics of the key events. + $el.on( eventKeys, function () { + var res = trimValForByteLength( + prevSafeVal, + this.value, + elLimit, + fn + ); + + // Only set value property if it was trimmed, because whenever the + // value property is set, the browser needs to re-initiate the text context, + // which moves the cursor at the end the input, moving it away from wherever it was. + // This is a side-effect of limiting after the fact. + if ( res.trimmed === true ) { + this.value = res.newVal; + prevSafeVal = res.newVal; + } + } ); + } ); + }; +}( jQuery ) ); diff --git a/resources/jquery/jquery.checkboxShiftClick.js b/resources/jquery/jquery.checkboxShiftClick.js index 0a1d7d7d..1990dc0d 100644 --- a/resources/jquery/jquery.checkboxShiftClick.js +++ b/resources/jquery/jquery.checkboxShiftClick.js @@ -6,23 +6,22 @@ * @author Krinkle * @license GPL v2 */ -( function( $ ) { -$.fn.checkboxShiftClick = function( text ) { - var prevCheckbox = null; - var $box = this; - // When our boxes are clicked.. - $box.click( function( e ) { - // And one has been clicked before... - 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 - ).prop( 'checked', e.target.checked ? true : false ); - } - // Either way, update the prevCheckbox variable to the one clicked now - prevCheckbox = e.target; - } ); - return $box; -}; -} )( jQuery ); \ No newline at end of file +( function ( $ ) { + $.fn.checkboxShiftClick = function ( text ) { + var prevCheckbox = null, $box = this; + // When our boxes are clicked.. + $box.click( function ( e ) { + // And one has been clicked before... + 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 + ).prop( 'checked', !!e.target.checked ); + } + // Either way, update the prevCheckbox variable to the one clicked now + prevCheckbox = e.target; + } ); + return $box; + }; +}( jQuery ) ); diff --git a/resources/jquery/jquery.client.js b/resources/jquery/jquery.client.js index ae74a324..24f8959e 100644 --- a/resources/jquery/jquery.client.js +++ b/resources/jquery/jquery.client.js @@ -1,7 +1,7 @@ /** * User-agent detection */ -( function( $ ) { +( function ( $ ) { /* Private Members */ @@ -18,7 +18,7 @@ /** * Get an object containing information about the client. * - * @param nav {Object} An object with atleast a 'userAgent' and 'platform' key.= + * @param nav {Object} An object with atleast a 'userAgent' and 'platform' key. * Defaults to the global Navigator object. * @return {Object} The resulting client object will be in the following format: * { @@ -31,7 +31,9 @@ * 'versionNumber': 3.5, * } */ - profile: function( nav ) { + profile: function ( nav ) { + /*jshint boss: true */ + if ( nav === undefined ) { nav = window.navigator; } @@ -64,15 +66,15 @@ // Strings which precede a version number in a user agent string - combined and used as match 1 in // version detectection var versionPrefixes = [ - 'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror', 'lynx', - 'msie', 'safari', 'ps3' + 'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror', + 'lynx', 'msie', 'safari', 'ps3' ]; // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number var versionSuffix = '(\\/|\\;?\\s|)([a-z0-9\\.\\+]*?)(\\;|dev|rel|\\)|\\s|$)'; // Names of known browsers var names = [ - 'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera', 'safari', 'ipod', - 'iphone', 'blackberry', 'ps3' + 'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera', + 'safari', 'ipod', 'iphone', 'blackberry', 'ps3', 'rekonq' ]; // Tanslations for conforming browser names var nameTranslations = []; @@ -89,9 +91,12 @@ /* Methods */ - // Performs multiple replacements on a string - var translate = function( source, translations ) { - for ( var i = 0; i < translations.length; i++ ) { + /** + * Performs multiple replacements on a string + */ + var translate = function ( source, translations ) { + var i; + for ( i = 0; i < translations.length; i++ ) { source = source.replace( translations[i][0], translations[i][1] ); } return source; @@ -147,13 +152,13 @@ /* Caching */ profileCache[nav.userAgent] = { - 'name': name, - 'layout': layout, - 'layoutVersion': layoutversion, - 'platform': platform, - 'version': version, - 'versionBase': ( version !== x ? Math.floor( versionNumber ).toString() : x ), - 'versionNumber': versionNumber + name: name, + layout: layout, + layoutVersion: layoutversion, + platform: platform, + version: version, + versionBase: ( version !== x ? Math.floor( versionNumber ).toString() : x ), + versionNumber: versionNumber }; } return profileCache[nav.userAgent]; @@ -185,26 +190,30 @@ * * @return Boolean true if browser known or assumed to be supported, false if blacklisted */ - test: function( map, profile ) { + test: function ( map, profile ) { + /*jshint evil:true */ + + var conditions, dir, i, op, val; profile = $.isPlainObject( profile ) ? profile : $.client.profile(); - var dir = $( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr'; + dir = $( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr'; // Check over each browser condition to determine if we are running in a compatible client - if ( typeof map[dir] !== 'object' || typeof map[dir][profile.name] === 'undefined' ) { + if ( typeof map[dir] !== 'object' || map[dir][profile.name] === undefined ) { // Unknown, so we assume it's working return true; } - var conditions = map[dir][profile.name]; - for ( var i = 0; i < conditions.length; i++ ) { - var op = conditions[i][0]; - var val = conditions[i][1]; + conditions = map[dir][profile.name]; + for ( i = 0; i < conditions.length; i++ ) { + op = conditions[i][0]; + val = conditions[i][1]; if ( val === false ) { return false; - } else if ( typeof val == 'string' ) { + } + if ( typeof val === 'string' ) { if ( !( eval( 'profile.version' + op + '"' + val + '"' ) ) ) { return false; } - } else if ( typeof val == 'number' ) { + } else if ( typeof val === 'number' ) { if ( !( eval( 'profile.versionNumber' + op + val ) ) ) { return false; } @@ -213,4 +222,4 @@ return true; } }; -} )( jQuery ); +}( jQuery ) ); diff --git a/resources/jquery/jquery.collapsibleTabs.js b/resources/jquery/jquery.collapsibleTabs.js index 1784f86a..cb25796f 100644 --- a/resources/jquery/jquery.collapsibleTabs.js +++ b/resources/jquery/jquery.collapsibleTabs.js @@ -1,30 +1,34 @@ -/* +/** * Collapsible tabs jQuery Plugin */ -( function( $ ) { - $.fn.collapsibleTabs = function( options ) { +( function ( $ ) { + $.fn.collapsibleTabs = function ( options ) { // return if the function is called on an empty jquery object - if( !this.length ) return this; - //merge options into the defaults + if ( !this.length ) { + return this; + } + // Merge options into the defaults var $settings = $.extend( {}, $.collapsibleTabs.defaults, options ); - this.each( function() { - var $this = $( this ); + this.each( function () { + var $el = $( this ); // add the element to our array of collapsible managers - $.collapsibleTabs.instances = ( $.collapsibleTabs.instances.length == 0 ? - $this : $.collapsibleTabs.instances.add( $this ) ); + $.collapsibleTabs.instances = ( $.collapsibleTabs.instances.length === 0 ? + $el : $.collapsibleTabs.instances.add( $el ) ); // attach the settings to the elements - $this.data( 'collapsibleTabsSettings', $settings ); + $el.data( 'collapsibleTabsSettings', $settings ); // attach data to our collapsible elements - $this.children( $settings.collapsible ).each( function() { + $el.children( $settings.collapsible ).each( function () { $.collapsibleTabs.addData( $( this ) ); } ); } ); // if we haven't already bound our resize hanlder, bind it now - if( !$.collapsibleTabs.boundEvent ) { + if ( !$.collapsibleTabs.boundEvent ) { $( window ) - .delayedBind( '500', 'resize', function( ) { $.collapsibleTabs.handleResize(); } ); + .delayedBind( '500', 'resize', function ( ) { + $.collapsibleTabs.handleResize(); + } ); } // call our resize handler to setup the page $.collapsibleTabs.handleResize(); @@ -38,63 +42,67 @@ collapsedContainer: '#p-cactions ul', collapsible: 'li.collapsible', shifting: false, - expandCondition: function( eleWidth ) { + expandCondition: function ( eleWidth ) { return ( $( '#left-navigation' ).position().left + $( '#left-navigation' ).width() ) < ( $( '#right-navigation' ).position().left - eleWidth ); }, - collapseCondition: function() { + collapseCondition: function () { return ( $( '#left-navigation' ).position().left + $( '#left-navigation' ).width() ) > $( '#right-navigation' ).position().left; } }, - addData: function( $collapsible ) { + addData: function ( $collapsible ) { var $settings = $collapsible.parent().data( 'collapsibleTabsSettings' ); - if ( $settings != null ) { + if ( $settings !== null ) { $collapsible.data( 'collapsibleTabsSettings', { - 'expandedContainer': $settings.expandedContainer, - 'collapsedContainer': $settings.collapsedContainer, - 'expandedWidth': $collapsible.width(), - 'prevElement': $collapsible.prev() + expandedContainer: $settings.expandedContainer, + collapsedContainer: $settings.collapsedContainer, + expandedWidth: $collapsible.width(), + prevElement: $collapsible.prev() } ); } }, - getSettings: function( $collapsible ) { + getSettings: function ( $collapsible ) { var $settings = $collapsible.data( 'collapsibleTabsSettings' ); - if ( typeof $settings == 'undefined' ) { + if ( $settings === undefined ) { $.collapsibleTabs.addData( $collapsible ); $settings = $collapsible.data( 'collapsibleTabsSettings' ); } return $settings; }, - handleResize: function( e ){ - $.collapsibleTabs.instances.each( function() { - var $this = $( this ), data = $.collapsibleTabs.getSettings( $this ); - if( data.shifting ) return; + handleResize: function ( e ) { + $.collapsibleTabs.instances.each( function () { + var $el = $( this ), + data = $.collapsibleTabs.getSettings( $el ); + + if ( data.shifting ) { + return; + } // if the two navigations are colliding - if( $this.children( data.collapsible ).length > 0 && data.collapseCondition() ) { + if ( $el.children( data.collapsible ).length > 0 && data.collapseCondition() ) { - $this.trigger( "beforeTabCollapse" ); + $el.trigger( 'beforeTabCollapse' ); // move the element to the dropdown menu - $.collapsibleTabs.moveToCollapsed( $this.children( data.collapsible + ':last' ) ); + $.collapsibleTabs.moveToCollapsed( $el.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 + if ( $( data.collapsedContainer + ' ' + data.collapsible ).length > 0 && data.expandCondition( $.collapsibleTabs.getSettings( $( data.collapsedContainer ).children( - data.collapsible+":first" ) ).expandedWidth ) ) { + data.collapsible + ':first' ) ).expandedWidth ) ) { //move the element from the dropdown to the tab - $this.trigger( "beforeTabExpand" ); + $el.trigger( 'beforeTabExpand' ); $.collapsibleTabs - .moveToExpanded( data.collapsedContainer + " " + data.collapsible + ':first' ); + .moveToExpanded( data.collapsedContainer + ' ' + data.collapsible + ':first' ); } }); }, - moveToCollapsed: function( ele ) { - var $moving = $( ele ); - var data = $.collapsibleTabs.getSettings( $moving ); - var dataExp = $.collapsibleTabs.getSettings( data.expandedContainer ); + moveToCollapsed: function ( ele ) { + var $moving = $( ele ), + data = $.collapsibleTabs.getSettings( $moving ), + dataExp = $.collapsibleTabs.getSettings( data.expandedContainer ); dataExp.shifting = true; $moving .detach() @@ -103,10 +111,10 @@ dataExp.shifting = false; $.collapsibleTabs.handleResize(); }, - moveToExpanded: function( ele ) { - var $moving = $( ele ); - var data = $.collapsibleTabs.getSettings( $moving ); - var dataExp = $.collapsibleTabs.getSettings( data.expandedContainer ); + moveToExpanded: function ( ele ) { + var $moving = $( ele ), + data = $.collapsibleTabs.getSettings( $moving ), + dataExp = $.collapsibleTabs.getSettings( data.expandedContainer ); dataExp.shifting = true; // remove this element from where it's at and put it in the dropdown menu $moving.detach().insertAfter( data.prevElement ).data( 'collapsibleTabsSettings', data ); @@ -114,4 +122,5 @@ $.collapsibleTabs.handleResize(); } }; -} )( jQuery ); + +}( jQuery ) ); diff --git a/resources/jquery/jquery.color.js b/resources/jquery/jquery.color.js index 8a619b5c..8bc45c97 100644 --- a/resources/jquery/jquery.color.js +++ b/resources/jquery/jquery.color.js @@ -1,44 +1,54 @@ /** * jQuery Color Animations - * Copyright 2007 John Resig + * + * @author John Resig, 2007 + * @author Krinkle, 2011 * Released under the MIT and GPL licenses. * - * - 2011-01-05: Modified by Krinkle to use the jQuery.colorUtil plugin (which has to be loaded first!) + * - 2011-01-05: Forked for MediaWiki. See also jQuery.colorUtil plugin */ -(function( $ ) { +( function ( $ ) { - // We override the animation for all of these color styles - $.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], - function( i, attr ) { - $.fx.step[attr] = function( fx ) { - if ( fx.state == 0 ) { - 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), - Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0) - ].join( ',' ) + ')'; - } - } - ); - - function getColor(elem, attr) { + function getColor( elem, attr ) { + /*jshint boss:true */ var color; do { - color = $.curCSS(elem, attr); + color = $.curCSS( elem, attr ); // Keep going until we find an element that has color, or we hit the body - if ( color != '' && color != 'transparent' || $.nodeName(elem, 'body') ) + if ( color !== '' && color !== 'transparent' || $.nodeName( elem, 'body' ) ) { break; + } attr = 'backgroundColor'; } while ( elem = elem.parentNode ); - return $.colorUtil.getRGB(color); - }; + return $.colorUtil.getRGB( color ); + } + + // We override the animation for all of these color styles + $.each([ + 'backgroundColor', + 'borderBottomColor', + 'borderLeftColor', + 'borderRightColor', + 'borderTopColor', + 'color', + 'outlineColor' + ], function ( i, attr ) { + $.fx.step[attr] = function ( fx ) { + if ( fx.state === 0 ) { + 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], 10 ), 255 ), 0 ), + Math.max( Math.min( parseInt( (fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10 ), 255 ), 0 ), + Math.max( Math.min( parseInt( (fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10 ), 255 ), 0 ) + ].join( ',' ) + ')'; + }; + } ); -} )( jQuery ); +}( jQuery ) ); diff --git a/resources/jquery/jquery.colorUtil.js b/resources/jquery/jquery.colorUtil.js index 1116aec6..c1fe7fe3 100644 --- a/resources/jquery/jquery.colorUtil.js +++ b/resources/jquery/jquery.colorUtil.js @@ -2,192 +2,215 @@ * jQuery Color Utilities * Written by Krinkle in 2011 * Released under the MIT and GPL licenses. - * Mostly based on other plugins and functions (taken through JSLint and optimized a little). - * Sources cited locally. + * Mostly based on other plugins and functions (linted and optimized a little). + * Sources cited inline. */ -( function( $ ) { -$.colorUtil = { - - // Color Conversion function from highlightFade - // By Blair Mitchelmore - // http://jquery.offput.ca/highlightFade/ - // Parse strings looking for color tuples [255,255,255] - getRGB : function( color ) { - var result; - - // Check if we're already dealing with an array of colors - if ( color && color.constructor == Array && color.length == 3 ){ - return color; - } +( function ( $ ) { + $.colorUtil = { - // Look for rgb(num,num,num) - if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) { - return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; - } + // Color Conversion function from highlightFade + // By Blair Mitchelmore + // http://jquery.offput.ca/highlightFade/ + // Parse strings looking for color tuples [255,255,255] + getRGB : function ( color ) { + /*jshint boss:true */ + var result; - // Look for rgb(num%,num%,num%) - if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) { - return [parseFloat(result[1],10)*2.55, parseFloat(result[2],10)*2.55, parseFloat(result[3])*2.55]; - } + // Check if we're already dealing with an array of colors + if ( color && $.isArray( color ) && color.length === 3 ) { + return color; + } - // Look for #a0b1c2 - if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) { - return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; - } + // Look for rgb(num,num,num) + if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) { + return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; + } - // Look for #fff - if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) { - return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; - } + // Look for rgb(num%,num%,num%) + if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) { + return [parseFloat(result[1],10)*2.55, parseFloat(result[2],10)*2.55, parseFloat(result[3])*2.55]; + } - // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 - if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) { - return $.colorUtil.colors.transparent; - } + // Look for #a0b1c2 + if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) { + return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; + } - // Otherwise, we're most likely dealing with a named color - return $.colorUtil.colors[$.trim(color).toLowerCase()]; - }, - - // Some named colors to work with - // From Interface by Stefan Petre - // http://interface.eyecon.ro/ - colors: { - aqua:[0,255,255], - azure:[240,255,255], - beige:[245,245,220], - black:[0,0,0], - blue:[0,0,255], - brown:[165,42,42], - cyan:[0,255,255], - darkblue:[0,0,139], - darkcyan:[0,139,139], - darkgrey:[169,169,169], - darkgreen:[0,100,0], - darkkhaki:[189,183,107], - darkmagenta:[139,0,139], - darkolivegreen:[85,107,47], - darkorange:[255,140,0], - darkorchid:[153,50,204], - darkred:[139,0,0], - darksalmon:[233,150,122], - darkviolet:[148,0,211], - fuchsia:[255,0,255], - gold:[255,215,0], - green:[0,128,0], - indigo:[75,0,130], - khaki:[240,230,140], - lightblue:[173,216,230], - lightcyan:[224,255,255], - lightgreen:[144,238,144], - lightgrey:[211,211,211], - lightpink:[255,182,193], - lightyellow:[255,255,224], - lime:[0,255,0], - magenta:[255,0,255], - maroon:[128,0,0], - navy:[0,0,128], - olive:[128,128,0], - orange:[255,165,0], - pink:[255,192,203], - purple:[128,0,128], - violet:[128,0,128], - red:[255,0,0], - silver:[192,192,192], - white:[255,255,255], - yellow:[255,255,0], - transparent: [255,255,255] - }, - /** - * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript - * Converts an RGB color value to HSL. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes r, g, and b are contained in the set [0, 255] and - * returns h, s, and l in the set [0, 1]. - * - * @param Number R The red color value - * @param Number G The green color value - * @param Number B The blue color value - * @return Array The HSL representation - */ - rgbToHsl: function( R, G, B ) { - var r = R / 255, - g = G / 255, - b = B / 255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min){ - h = s = 0; // achromatic - }else{ - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max){ - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; + // Look for #fff + if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) { + return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; + } + + // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 + if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) { + return $.colorUtil.colors.transparent; } - h /= 6; - } - return [h, s, l]; - }, - /** - * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript - * Converts an HSL color value to RGB. Conversion formula - * adapted from http://en.wikipedia.org/wiki/HSL_color_space. - * Assumes h, s, and l are contained in the set [0, 1] and - * returns r, g, and b in the set [0, 255]. - * - * @param Number h The hue - * @param Number s The saturation - * @param Number l The lightness - * @return Array The RGB representation - */ - hslToRgb: function( h, s, l ) { - var r, g, b; - - if(s === 0){ - r = g = b = l; // achromatic - }else{ - var hue2rgb = function(p, q, t){ - if(t < 0){ t += 1; } - if(t > 1){ t -= 1; } - if(t < 1/6){ return p + (q - p) * 6 * t; } - if(t < 1/2){ return q; } - if(t < 2/3){ return p + (q - p) * (2/3 - t) * 6; } - return p; - }; - - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); + // Otherwise, we're most likely dealing with a named color + return $.colorUtil.colors[$.trim(color).toLowerCase()]; + }, + + // Some named colors to work with + // From Interface by Stefan Petre + // http://interface.eyecon.ro/ + colors: { + aqua: [0,255,255], + azure: [240,255,255], + beige: [245,245,220], + black: [0,0,0], + blue: [0,0,255], + brown: [165,42,42], + cyan: [0,255,255], + darkblue: [0,0,139], + darkcyan: [0,139,139], + darkgrey: [169,169,169], + darkgreen: [0,100,0], + darkkhaki: [189,183,107], + darkmagenta: [139,0,139], + darkolivegreen: [85,107,47], + darkorange: [255,140,0], + darkorchid: [153,50,204], + darkred: [139,0,0], + darksalmon: [233,150,122], + darkviolet: [148,0,211], + fuchsia: [255,0,255], + gold: [255,215,0], + green: [0,128,0], + indigo: [75,0,130], + khaki: [240,230,140], + lightblue: [173,216,230], + lightcyan: [224,255,255], + lightgreen: [144,238,144], + lightgrey: [211,211,211], + lightpink: [255,182,193], + lightyellow: [255,255,224], + lime: [0,255,0], + magenta: [255,0,255], + maroon: [128,0,0], + navy: [0,0,128], + olive: [128,128,0], + orange: [255,165,0], + pink: [255,192,203], + purple: [128,0,128], + violet: [128,0,128], + red: [255,0,0], + silver: [192,192,192], + white: [255,255,255], + yellow: [255,255,0], + transparent: [255,255,255] + }, + + /** + * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes r, g, and b are contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + * + * @param Number R The red color value + * @param Number G The green color value + * @param Number B The blue color value + * @return Array The HSL representation + */ + rgbToHsl: function ( R, G, B ) { + var r = R / 255, + g = G / 255, + b = B / 255; + var max = Math.max( r, g, b ), min = Math.min( r, g, b ); + var h, s, l = (max + min) / 2; + + if ( max === min ) { + // achromatic + h = s = 0; + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch ( max ) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + + return [h, s, l]; + }, + + /** + * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. + * + * @param Number h The hue + * @param Number s The saturation + * @param Number l The lightness + * @return Array The RGB representation + */ + hslToRgb: function ( h, s, l ) { + var r, g, b; + + if ( s === 0 ) { + r = g = b = l; // achromatic + } else { + var hue2rgb = function ( p, q, t ) { + if ( t < 0 ) { + t += 1; + } + if ( t > 1 ) { + t -= 1; + } + if ( t < 1/6 ) { + return p + (q - p) * 6 * t; + } + if ( t < 1/2 ) { + return q; + } + if ( t < 2/3 ) { + return p + (q - p) * (2/3 - t) * 6; + } + return p; + }; + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb( p, q, h + 1/3 ); + g = hue2rgb( p, q, h ); + b = hue2rgb( p, q, h - 1/3 ); + } + + return [r * 255, g * 255, b * 255]; + }, + + /** + * Get's a brighter or darker rgb() value string. + * + * @author Krinkle + * + * @example getCSSColorMod( 'red', +0.1 ) + * @example getCSSColorMod( 'rgb(200,50,50)', -0.2 ) + * + * @param Mixed currentColor current value in css + * @param Number mod wanted brightness modification between -1 and 1 + * @return String 'rgb(r,g,b)' + */ + getColorBrightness: function ( currentColor, mod ) { + var rgbArr = $.colorUtil.getRGB( currentColor ), + hslArr = $.colorUtil.rgbToHsl(rgbArr[0], rgbArr[1], rgbArr[2] ); + rgbArr = $.colorUtil.hslToRgb(hslArr[0], hslArr[1], hslArr[2]+mod); + + return 'rgb(' + + [parseInt( rgbArr[0], 10), parseInt( rgbArr[1], 10 ), parseInt( rgbArr[2], 10 )].join( ',' ) + + ')'; } - return [r * 255, g * 255, b * 255]; - }, - /** - * Get's a brighter or darker rgb() value string. - * - * @author Krinkle - * - * @example getCSSColorMod( 'red', +0.1 ) - * @example getCSSColorMod( 'rgb(200,50,50)', -0.2 ) - * - * @param Mixed currentColor current value in css - * @param Number mod wanted brightness modification between -1 and 1 - * @return String 'rgb(r,g,b)' - */ - getColorBrightness: function( currentColor, mod ) { - var rgbArr = $.colorUtil.getRGB( currentColor ), - hslArr = $.colorUtil.rgbToHsl(rgbArr[0], rgbArr[1], rgbArr[2] ); - rgbArr = $.colorUtil.hslToRgb(hslArr[0], hslArr[1], hslArr[2]+mod); - return 'rgb(' + - [parseInt( rgbArr[0], 10), parseInt( rgbArr[1], 10 ), parseInt( rgbArr[2], 10 )].join( ',' ) + - ')'; - } - -}; -} )( jQuery ); \ No newline at end of file + }; + +}( jQuery ) ); diff --git a/resources/jquery/jquery.cookie.js b/resources/jquery/jquery.cookie.js index 79317f74..6d5974a2 100644 --- a/resources/jquery/jquery.cookie.js +++ b/resources/jquery/jquery.cookie.js @@ -1,96 +1,47 @@ -/** - * Cookie plugin +/*! + * jQuery Cookie Plugin + * https://github.com/carhartl/jquery-cookie * - * Copyright (c) 2006 Klaus Hartl (stilbuero.de) - * Dual licensed under the MIT and GPL licenses: + * Copyright 2011, Klaus Hartl + * Dual licensed under the MIT or GPL Version 2 licenses. * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * + * http://www.opensource.org/licenses/GPL-2.0 */ +(function($) { + $.cookie = function(key, value, options) { -/** - * Create a cookie with the given name and value and other optional parameters. - * - * @example $.cookie('the_cookie', 'the_value'); - * @desc Set the value of a cookie. - * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); - * @desc Create a cookie with all available options. - * @example $.cookie('the_cookie', 'the_value'); - * @desc Create a session cookie. - * @example $.cookie('the_cookie', null); - * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain - * used when the cookie was set. - * - * @param String name The name of the cookie. - * @param String value The value of the cookie. - * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. - * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. - * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. - * If set to null or omitted, the cookie will be a session cookie and will not be retained - * when the the browser exits. - * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). - * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). - * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will - * require a secure protocol (like HTTPS). - * @type undefined - * - * @name $.cookie - * @cat Plugins/Cookie - * @author Klaus Hartl/klaus.hartl@stilbuero.de - */ + // key and at least value given, set cookie... + if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { + options = $.extend({}, options); -/** - * Get the value of a cookie with the given name. - * - * @example $.cookie('the_cookie'); - * @desc Get the value of a cookie. - * - * @param String name The name of the cookie. - * @return The value of the cookie. - * @type String - * - * @name $.cookie - * @cat Plugins/Cookie - * @author Klaus Hartl/klaus.hartl@stilbuero.de - */ -jQuery.cookie = function(name, value, options) { - if (typeof value != 'undefined') { // name and value given, set cookie - options = options || {}; - if (value === null) { - value = ''; - options.expires = -1; - } - var expires = ''; - if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { - var date; - if (typeof options.expires == 'number') { - date = new Date(); - date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); - } else { - date = options.expires; + if (value === null || value === undefined) { + options.expires = -1; } - expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE - } - // CAUTION: Needed to parenthesize options.path and options.domain - // in the following expressions, otherwise they evaluate to undefined - // in the packed version for some reason... - var path = options.path ? '; path=' + (options.path) : ''; - var domain = options.domain ? '; domain=' + (options.domain) : ''; - var secure = options.secure ? '; secure' : ''; - document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); - } else { // only name given, get cookie - var cookieValue = null; - if (document.cookie && document.cookie != '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); } + + value = String(value); + + return (document.cookie = [ + encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // key and possibly options given, get cookie... + options = value || {}; + var decode = options.raw ? function(s) { return s; } : decodeURIComponent; + + var pairs = document.cookie.split('; '); + for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { + if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined } - return cookieValue; - } -}; + return null; + }; +})(jQuery); diff --git a/resources/jquery/jquery.delayedBind.js b/resources/jquery/jquery.delayedBind.js index d84ee267..5d32b6b0 100644 --- a/resources/jquery/jquery.delayedBind.js +++ b/resources/jquery/jquery.delayedBind.js @@ -1,4 +1,4 @@ -(function( $ ) { +( function ( $ ) { /** * Function that escapes spaces in event names. This is needed because * "_delayedBind-foo bar-1000" refers to two events @@ -18,25 +18,26 @@ $.fn.extend( { * @param data Data to pass to the event handler (optional) * @param callback Function to call */ - delayedBind: function( timeout, event, data, callback ) { - if ( arguments.length == 3 ) { + delayedBind: function ( timeout, event, data, callback ) { + if ( arguments.length === 3 ) { // Shift optional parameter down callback = data; data = undefined; } var encEvent = encodeEvent( event ); - return this.each( function() { + return this.each( function () { var that = this; // Bind the top half // Do this only once for every (event, timeout) pair if ( !( $(this).data( '_delayedBindBound-' + encEvent + '-' + timeout ) ) ) { $(this).data( '_delayedBindBound-' + encEvent + '-' + timeout, true ); - $(this).bind( event, function() { + $(this).bind( event, function () { var timerID = $(this).data( '_delayedBindTimerID-' + encEvent + '-' + timeout ); // Cancel the running timer - if ( typeof timerID != 'undefined' ) + if ( timerID !== null ) { clearTimeout( timerID ); - timerID = setTimeout( function() { + } + timerID = setTimeout( function () { $(that).trigger( '_delayedBind-' + encEvent + '-' + timeout ); }, timeout ); $(this).data( '_delayedBindTimerID-' + encEvent + '-' + timeout, timerID ); @@ -51,23 +52,25 @@ $.fn.extend( { /** * Cancel the timers for delayed events on the selected elements. */ - delayedBindCancel: function( timeout, event ) { + delayedBindCancel: function ( timeout, event ) { var encEvent = encodeEvent( event ); - return this.each( function() { + return this.each( function () { var timerID = $(this).data( '_delayedBindTimerID-' + encEvent + '-' + timeout ); - if ( typeof timerID != 'undefined' ) + if ( timerID !== null ) { clearTimeout( timerID ); + } } ); }, /** * Unbind an event bound with delayedBind() */ - delayedBindUnbind: function( timeout, event, callback ) { + delayedBindUnbind: function ( timeout, event, callback ) { var encEvent = encodeEvent( event ); - return this.each( function() { + return this.each( function () { $(this).unbind( '_delayedBind-' + encEvent + '-' + timeout, callback ); } ); } } ); -} )( jQuery ); \ No newline at end of file + +}( jQuery ) ); diff --git a/resources/jquery/jquery.expandableField.js b/resources/jquery/jquery.expandableField.js index 3c65d016..063f2609 100644 --- a/resources/jquery/jquery.expandableField.js +++ b/resources/jquery/jquery.expandableField.js @@ -14,116 +14,124 @@ * Options: * */ -( function( $ ) { - -$.expandableField = { - /** - * Expand the field, make the callback - */ - expandField: function( e, context ) { - context.config.beforeExpand.call( context.data.$field, context ); - context.data.$field - .animate( { 'width': context.data.expandedWidth }, 'fast', function() { - context.config.afterExpand.call( this, context ); - } ); - }, - /** - * Condense the field, make the callback - */ - condenseField: function( e, context ) { - context.config.beforeCondense.call( context.data.$field, context ); - context.data.$field - .animate( { 'width': context.data.condensedWidth }, 'fast', function() { - context.config.afterCondense.call( this, context ); - } ); - }, - /** - * Sets the value of a property, and updates the widget accordingly - * @param property String Name of property - * @param value Mixed Value to set property with - */ - configure: function( context, property, value ) { - // Validate creation using fallback values - switch( property ) { - default: - context.config[property] = value; - break; - } - } - -}; -$.fn.expandableField = function() { - - // Multi-context fields - var returnValue = null; - var args = arguments; - - $( this ).each( function() { - - /* Construction / Loading */ - - var context = $( this ).data( 'expandableField-context' ); - if ( context == null ) { - context = { - config: { - // callback function for before collapse - 'beforeCondense': function( context ) {}, - // callback function for before expand - 'beforeExpand': function( context ) {}, - // callback function for after collapse - 'afterCondense': function( context ) {}, - // callback function for after expand - 'afterExpand': function( context ) {}, - // Whether the field should expand to the left or the right -- defaults to left - 'expandToLeft': true - } - }; +( function ( $ ) { + + $.expandableField = { + /** + * Expand the field, make the callback + */ + expandField: function ( e, context ) { + context.config.beforeExpand.call( context.data.$field, context ); + context.data.$field + .animate( { 'width': context.data.expandedWidth }, 'fast', function () { + context.config.afterExpand.call( this, context ); + } ); + }, + /** + * Condense the field, make the callback + */ + condenseField: function ( e, context ) { + context.config.beforeCondense.call( context.data.$field, context ); + context.data.$field + .animate( { 'width': context.data.condensedWidth }, 'fast', function () { + context.config.afterCondense.call( this, context ); + } ); + }, + /** + * Sets the value of a property, and updates the widget accordingly + * @param property String Name of property + * @param value Mixed Value to set property with + */ + configure: function ( context, property, value ) { + // TODO: Validate creation using fallback values + context.config[property] = value; } - - /* API */ - // Handle various calling styles - if ( args.length > 0 ) { - if ( typeof args[0] == 'object' ) { - // Apply set of properties - for ( var key in args[0] ) { - $.expandableField.configure( context, key, args[0][key] ); - } - } else if ( typeof args[0] == 'string' ) { - if ( args.length > 1 ) { - // Set property values - $.expandableField.configure( context, args[0], args[1] ); - } else if ( returnValue == null ) { - // Get property values, but don't give access to internal data - returns only the first - returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] ); + + }; + + $.fn.expandableField = function () { + + // Multi-context fields + var returnValue, + args = arguments; + + $( this ).each( function () { + var key, context; + + /* Construction / Loading */ + + context = $( this ).data( 'expandableField-context' ); + + // TODO: Do we need to check both null and undefined? + if ( context === undefined || context === null ) { + context = { + config: { + // callback function for before collapse + beforeCondense: function ( context ) {}, + + // callback function for before expand + beforeExpand: function ( context ) {}, + + // callback function for after collapse + afterCondense: function ( context ) {}, + + // callback function for after expand + afterExpand: function ( context ) {}, + + // Whether the field should expand to the left or the right -- defaults to left + expandToLeft: true + } + }; + } + + /* API */ + // Handle various calling styles + if ( args.length > 0 ) { + if ( typeof args[0] === 'object' ) { + // Apply set of properties + for ( key in args[0] ) { + $.expandableField.configure( context, key, args[0][key] ); + } + } else if ( typeof args[0] === 'string' ) { + if ( args.length > 1 ) { + // Set property values + $.expandableField.configure( context, args[0], args[1] ); + + // TODO: Do we need to check both null and undefined? + } else if ( returnValue === null || returnValue === undefined ) { + // Get property values, but don't give access to internal data - returns only the first + returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] ); + } } } - } - - /* Initialization */ - - if ( typeof context.data == 'undefined' ) { - context.data = { - // The width of the field in it's condensed state - 'condensedWidth': $( this ).width(), - // The width of the field in it's expanded state - 'expandedWidth': $( this ).width() * 2, - // Reference to the field - '$field': $( this ) - }; - - $( this ) - .addClass( 'expandableField' ) - .focus( function( e ) { - $.expandableField.expandField( e, context ); - } ) - .delayedBind( 250, 'blur', function( e ) { - $.expandableField.condenseField( e, context ); - } ); - } - // Store the context for next time - $( this ).data( 'expandableField-context', context ); - } ); - return returnValue !== null ? returnValue : $(this); -}; -} )( jQuery ); + /* Initialization */ + + if ( context.data === undefined ) { + context.data = { + // The width of the field in it's condensed state + condensedWidth: $( this ).width(), + + // The width of the field in it's expanded state + expandedWidth: $( this ).width() * 2, + + // Reference to the field + $field: $( this ) + }; + + $( this ) + .addClass( 'expandableField' ) + .focus( function ( e ) { + $.expandableField.expandField( e, context ); + } ) + .delayedBind( 250, 'blur', function ( e ) { + $.expandableField.condenseField( e, context ); + } ); + } + // Store the context for next time + $( this ).data( 'expandableField-context', context ); + } ); + return returnValue !== undefined ? returnValue : $(this); + }; + +}( jQuery ) ); diff --git a/resources/jquery/jquery.form.js b/resources/jquery/jquery.form.js index fdcdd15a..13e9a55c 100644 --- a/resources/jquery/jquery.form.js +++ b/resources/jquery/jquery.form.js @@ -1,557 +1,677 @@ /*! * jQuery Form Plugin - * version: 2.84 (12-AUG-2011) + * version: 3.14 (30-JUL-2012) * @requires jQuery v1.3.2 or later * * Examples and documentation at: http://malsup.com/jquery/form/ + * Project repository: https://github.com/malsup/form * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html + * http://malsup.github.com/mit-license.txt + * http://malsup.github.com/gpl-license-v2.txt */ +/*global ActiveXObject alert */ ;(function($) { +"use strict"; /* - Usage Note: - ----------- - Do not use both ajaxSubmit and ajaxForm on the same form. These - functions are intended to be exclusive. Use ajaxSubmit if you want - to bind your own submit handler to the form. For example, - - $(document).ready(function() { - $('#myForm').bind('submit', function(e) { - e.preventDefault(); // <-- important - $(this).ajaxSubmit({ - target: '#output' - }); - }); - }); - - Use ajaxForm when you want the plugin to manage all the event binding - for you. For example, - - $(document).ready(function() { - $('#myForm').ajaxForm({ - target: '#output' - }); - }); - - When using ajaxForm, the ajaxSubmit function will be invoked for you - at the appropriate time. + Usage Note: + ----------- + Do not use both ajaxSubmit and ajaxForm on the same form. These + functions are mutually exclusive. Use ajaxSubmit if you want + to bind your own submit handler to the form. For example, + + $(document).ready(function() { + $('#myForm').on('submit', function(e) { + e.preventDefault(); // <-- important + $(this).ajaxSubmit({ + target: '#output' + }); + }); + }); + + Use ajaxForm when you want the plugin to manage all the event binding + for you. For example, + + $(document).ready(function() { + $('#myForm').ajaxForm({ + target: '#output' + }); + }); + + You can also use ajaxForm with delegation (requires jQuery v1.7+), so the + form does not have to exist when you invoke ajaxForm: + + $('#myForm').ajaxForm({ + delegation: true, + target: '#output' + }); + + When using ajaxForm, the ajaxSubmit function will be invoked for you + at the appropriate time. */ +/** + * Feature detection + */ +var feature = {}; +feature.fileapi = $("").get(0).files !== undefined; +feature.formdata = window.FormData !== undefined; + /** * ajaxSubmit() provides a mechanism for immediately submitting * an HTML form using AJAX. */ $.fn.ajaxSubmit = function(options) { - // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) - if (!this.length) { - log('ajaxSubmit: skipping submit process - no element selected'); - return this; - } - - var method, action, url, $form = this; - - if (typeof options == 'function') { - options = { success: options }; - } - - 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]; - } - - options = $.extend(true, { - url: url, - success: $.ajaxSettings.success, - type: method || 'GET', - iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' - }, options); - - // hook for manipulating the form data before it is extracted; - // convenient for use with rich editors like tinyMCE or FCKEditor - var veto = {}; - this.trigger('form-pre-serialize', [this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); - return this; - } - - // provide opportunity to alter form data before it is serialized - if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSerialize callback'); - return this; - } - - var n,v,a = this.formToArray(options.semantic); - if (options.data) { - options.extraData = options.data; - for (n in options.data) { - if( $.isArray(options.data[n]) ) { - for (var k in options.data[n]) { - a.push( { name: n, value: options.data[n][k] } ); - } - } - else { - v = options.data[n]; - v = $.isFunction(v) ? v() : v; // if value is fn, invoke it - a.push( { name: n, value: v } ); - } - } - } - - // give pre-submit callback an opportunity to abort the submit - if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { - log('ajaxSubmit: submit aborted via beforeSubmit callback'); - return this; - } - - // fire vetoable 'validate' event - this.trigger('form-submit-validate', [a, this, options, veto]); - if (veto.veto) { - log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); - return this; - } - - var q = $.param(a); - - if (options.type.toUpperCase() == 'GET') { - options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; - options.data = null; // data is null for 'get' - } - else { - options.data = q; // data is the query string for 'post' - } - - var callbacks = []; - if (options.resetForm) { - callbacks.push(function() { $form.resetForm(); }); - } - if (options.clearForm) { - callbacks.push(function() { $form.clearForm(); }); - } - - // perform a load on the target only if dataType is not provided - if (!options.dataType && options.target) { - var oldSuccess = options.success || function(){}; - callbacks.push(function(data) { - var fn = options.replaceTarget ? 'replaceWith' : 'html'; - $(options.target)[fn](data).each(oldSuccess, arguments); - }); - } - else if (options.success) { - callbacks.push(options.success); - } - - options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg - var context = options.context || options; // jQuery 1.4+ supports scope context - for (var i=0, max=callbacks.length; i < max; i++) { - callbacks[i].apply(context, [data, status, xhr || $form, $form]); - } - }; - - // are there files to upload? - var fileInputs = $('input:file', this).length > 0; - var mp = 'multipart/form-data'; - var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); - - // options.iframe allows user to force iframe mode - // 06-NOV-09: now defaulting to iframe mode if file input is detected - if (options.iframe !== false && (fileInputs || options.iframe || multipart)) { - // 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, function() { fileUpload(a); }); - } - else { - fileUpload(a); - } - } - else { - // 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 - this.trigger('form-submit-notify', [this, options]); - return this; - - - // private function for handling file uploads (hat tip to YAHOO!) - function fileUpload(a) { - var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; + /*jshint scripturl:true */ + + // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) + if (!this.length) { + log('ajaxSubmit: skipping submit process - no element selected'); + return this; + } + + var method, action, url, $form = this; + + if (typeof options == 'function') { + options = { success: options }; + } + + 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]; + } + + options = $.extend(true, { + url: url, + success: $.ajaxSettings.success, + type: method || 'GET', + iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' + }, options); + + // hook for manipulating the form data before it is extracted; + // convenient for use with rich editors like tinyMCE or FCKEditor + var veto = {}; + this.trigger('form-pre-serialize', [this, options, veto]); + if (veto.veto) { + log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); + return this; + } + + // provide opportunity to alter form data before it is serialized + if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { + log('ajaxSubmit: submit aborted via beforeSerialize callback'); + return this; + } + + var traditional = options.traditional; + if ( traditional === undefined ) { + traditional = $.ajaxSettings.traditional; + } + + var elements = []; + var qx, a = this.formToArray(options.semantic, elements); + if (options.data) { + options.extraData = options.data; + qx = $.param(options.data, traditional); + } + + // give pre-submit callback an opportunity to abort the submit + if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { + log('ajaxSubmit: submit aborted via beforeSubmit callback'); + return this; + } + + // fire vetoable 'validate' event + this.trigger('form-submit-validate', [a, this, options, veto]); + if (veto.veto) { + log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); + return this; + } + + var q = $.param(a, traditional); + if (qx) { + q = ( q ? (q + '&' + qx) : qx ); + } + if (options.type.toUpperCase() == 'GET') { + options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; + options.data = null; // data is null for 'get' + } + else { + options.data = q; // data is the query string for 'post' + } + + var callbacks = []; + if (options.resetForm) { + callbacks.push(function() { $form.resetForm(); }); + } + if (options.clearForm) { + callbacks.push(function() { $form.clearForm(options.includeHidden); }); + } + + // perform a load on the target only if dataType is not provided + if (!options.dataType && options.target) { + var oldSuccess = options.success || function(){}; + callbacks.push(function(data) { + var fn = options.replaceTarget ? 'replaceWith' : 'html'; + $(options.target)[fn](data).each(oldSuccess, arguments); + }); + } + else if (options.success) { + callbacks.push(options.success); + } + + options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg + var context = options.context || this ; // jQuery 1.4+ supports scope context + for (var i=0, max=callbacks.length; i < max; i++) { + callbacks[i].apply(context, [data, status, xhr || $form, $form]); + } + }; + + // are there files to upload? + var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113) + var hasFileInputs = fileInputs.length > 0; + var mp = 'multipart/form-data'; + var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); + + var fileAPI = feature.fileapi && feature.formdata; + log("fileAPI :" + fileAPI); + var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; + + // options.iframe allows user to force iframe mode + // 06-NOV-09: now defaulting to iframe mode if file input is detected + if (options.iframe !== false && (options.iframe || shouldUseFrame)) { + // 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, function() { + fileUploadIframe(a); + }); + } + else { + fileUploadIframe(a); + } + } + else if ((hasFileInputs || multipart) && fileAPI) { + fileUploadXhr(a); + } + else { + $.ajax(options); + } + + // clear element array + for (var k=0; k < elements.length; k++) + elements[k] = null; + + // fire 'notify' event + this.trigger('form-submit-notify', [this, options]); + return this; + + // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) + function fileUploadXhr(a) { + var formdata = new FormData(); + + for (var i=0; i < a.length; i++) { + formdata.append(a[i].name, a[i].value); + } + + if (options.extraData) { + for (var p in options.extraData) + if (options.extraData.hasOwnProperty(p)) + formdata.append(p, options.extraData[p]); + } + + options.data = null; + + var s = $.extend(true, {}, $.ajaxSettings, options, { + contentType: false, + processData: false, + cache: false, + type: 'POST' + }); + + if (options.uploadProgress) { + // workaround because jqXHR does not expose upload property + s.xhr = function() { + var xhr = jQuery.ajaxSettings.xhr(); + if (xhr.upload) { + xhr.upload.onprogress = function(event) { + var percent = 0; + var position = event.loaded || event.position; /*event.position is deprecated*/ + var total = event.total; + if (event.lengthComputable) { + percent = Math.ceil(position / total * 100); + } + options.uploadProgress(event, position, total, percent); + }; + } + return xhr; + }; + } + + s.data = null; + var beforeSend = s.beforeSend; + s.beforeSend = function(xhr, o) { + o.data = formdata; + if(beforeSend) + beforeSend.call(this, xhr, o); + }; + $.ajax(s); + } + + // private function for handling file uploads (hat tip to YAHOO!) + function fileUploadIframe(a) { + var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; var useProp = !!$.fn.prop; + 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 + // able to invoke the submit fn on the form (at least not x-browser) + alert('Error: Form elements must not have name or id of "submit".'); + return; + } + 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 - // able to invoke the submit fn on the form (at least not x-browser) - alert('Error: Form elements must not have name or id of "submit".'); - return; - } - - s = $.extend(true, {}, $.ajaxSettings, options); - s.context = s.context || s; - 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 = $('