mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-02-01 13:11:03 -05:00
23330 lines
760 KiB
JavaScript
23330 lines
760 KiB
JavaScript
/*!
|
||
* jQuery JavaScript Library v1.8.3
|
||
* http://jquery.com/
|
||
*
|
||
* Includes Sizzle.js
|
||
* http://sizzlejs.com/
|
||
*
|
||
* Copyright 2012 jQuery Foundation and other contributors
|
||
* Released under the MIT license
|
||
* http://jquery.org/license
|
||
*
|
||
* Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time)
|
||
*/
|
||
(function( window, undefined ) {
|
||
var
|
||
// A central reference to the root jQuery(document)
|
||
rootjQuery,
|
||
|
||
// The deferred used on DOM ready
|
||
readyList,
|
||
|
||
// Use the correct document accordingly with window argument (sandbox)
|
||
document = window.document,
|
||
location = window.location,
|
||
navigator = window.navigator,
|
||
|
||
// Map over jQuery in case of overwrite
|
||
_jQuery = window.jQuery,
|
||
|
||
// Map over the $ in case of overwrite
|
||
_$ = window.$,
|
||
|
||
// Save a reference to some core methods
|
||
core_push = Array.prototype.push,
|
||
core_slice = Array.prototype.slice,
|
||
core_indexOf = Array.prototype.indexOf,
|
||
core_toString = Object.prototype.toString,
|
||
core_hasOwn = Object.prototype.hasOwnProperty,
|
||
core_trim = String.prototype.trim,
|
||
|
||
// Define a local copy of jQuery
|
||
jQuery = function( selector, context ) {
|
||
// The jQuery object is actually just the init constructor 'enhanced'
|
||
return new jQuery.fn.init( selector, context, rootjQuery );
|
||
},
|
||
|
||
// Used for matching numbers
|
||
core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
|
||
|
||
// Used for detecting and trimming whitespace
|
||
core_rnotwhite = /\S/,
|
||
core_rspace = /\s+/,
|
||
|
||
// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
|
||
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
|
||
|
||
// A simple way to check for HTML strings
|
||
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
|
||
rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
|
||
|
||
// Match a standalone tag
|
||
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
|
||
|
||
// JSON RegExp
|
||
rvalidchars = /^[\],:{}\s]*$/,
|
||
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
|
||
rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
|
||
rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
|
||
|
||
// Matches dashed string for camelizing
|
||
rmsPrefix = /^-ms-/,
|
||
rdashAlpha = /-([\da-z])/gi,
|
||
|
||
// Used by jQuery.camelCase as callback to replace()
|
||
fcamelCase = function( all, letter ) {
|
||
return ( letter + "" ).toUpperCase();
|
||
},
|
||
|
||
// The ready event handler and self cleanup method
|
||
DOMContentLoaded = function() {
|
||
if ( document.addEventListener ) {
|
||
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
|
||
jQuery.ready();
|
||
} else if ( document.readyState === "complete" ) {
|
||
// we're here because readyState === "complete" in oldIE
|
||
// which is good enough for us to call the dom ready!
|
||
document.detachEvent( "onreadystatechange", DOMContentLoaded );
|
||
jQuery.ready();
|
||
}
|
||
},
|
||
|
||
// [[Class]] -> type pairs
|
||
class2type = {};
|
||
|
||
jQuery.fn = jQuery.prototype = {
|
||
constructor: jQuery,
|
||
init: function( selector, context, rootjQuery ) {
|
||
var match, elem, ret, doc;
|
||
|
||
// Handle $(""), $(null), $(undefined), $(false)
|
||
if ( !selector ) {
|
||
return this;
|
||
}
|
||
|
||
// Handle $(DOMElement)
|
||
if ( selector.nodeType ) {
|
||
this.context = this[0] = selector;
|
||
this.length = 1;
|
||
return this;
|
||
}
|
||
|
||
// Handle HTML strings
|
||
if ( typeof selector === "string" ) {
|
||
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
|
||
// Assume that strings that start and end with <> are HTML and skip the regex check
|
||
match = [ null, selector, null ];
|
||
|
||
} else {
|
||
match = rquickExpr.exec( selector );
|
||
}
|
||
|
||
// Match html or make sure no context is specified for #id
|
||
if ( match && (match[1] || !context) ) {
|
||
|
||
// HANDLE: $(html) -> $(array)
|
||
if ( match[1] ) {
|
||
context = context instanceof jQuery ? context[0] : context;
|
||
doc = ( context && context.nodeType ? context.ownerDocument || context : document );
|
||
|
||
// scripts is true for back-compat
|
||
selector = jQuery.parseHTML( match[1], doc, true );
|
||
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
|
||
this.attr.call( selector, context, true );
|
||
}
|
||
|
||
return jQuery.merge( this, selector );
|
||
|
||
// HANDLE: $(#id)
|
||
} else {
|
||
elem = document.getElementById( match[2] );
|
||
|
||
// Check parentNode to catch when Blackberry 4.6 returns
|
||
// nodes that are no longer in the document #6963
|
||
if ( elem && elem.parentNode ) {
|
||
// Handle the case where IE and Opera return items
|
||
// by name instead of ID
|
||
if ( elem.id !== match[2] ) {
|
||
return rootjQuery.find( selector );
|
||
}
|
||
|
||
// Otherwise, we inject the element directly into the jQuery object
|
||
this.length = 1;
|
||
this[0] = elem;
|
||
}
|
||
|
||
this.context = document;
|
||
this.selector = selector;
|
||
return this;
|
||
}
|
||
|
||
// HANDLE: $(expr, $(...))
|
||
} else if ( !context || context.jquery ) {
|
||
return ( context || rootjQuery ).find( selector );
|
||
|
||
// HANDLE: $(expr, context)
|
||
// (which is just equivalent to: $(context).find(expr)
|
||
} else {
|
||
return this.constructor( context ).find( selector );
|
||
}
|
||
|
||
// HANDLE: $(function)
|
||
// Shortcut for document ready
|
||
} else if ( jQuery.isFunction( selector ) ) {
|
||
return rootjQuery.ready( selector );
|
||
}
|
||
|
||
if ( selector.selector !== undefined ) {
|
||
this.selector = selector.selector;
|
||
this.context = selector.context;
|
||
}
|
||
|
||
return jQuery.makeArray( selector, this );
|
||
},
|
||
|
||
// Start with an empty selector
|
||
selector: "",
|
||
|
||
// The current version of jQuery being used
|
||
jquery: "1.8.3",
|
||
|
||
// The default length of a jQuery object is 0
|
||
length: 0,
|
||
|
||
// The number of elements contained in the matched element set
|
||
size: function() {
|
||
return this.length;
|
||
},
|
||
|
||
toArray: function() {
|
||
return core_slice.call( this );
|
||
},
|
||
|
||
// Get the Nth element in the matched element set OR
|
||
// Get the whole matched element set as a clean array
|
||
get: function( num ) {
|
||
return num == null ?
|
||
|
||
// Return a 'clean' array
|
||
this.toArray() :
|
||
|
||
// Return just the object
|
||
( num < 0 ? this[ this.length + num ] : this[ num ] );
|
||
},
|
||
|
||
// Take an array of elements and push it onto the stack
|
||
// (returning the new matched element set)
|
||
pushStack: function( elems, name, selector ) {
|
||
|
||
// Build a new jQuery matched element set
|
||
var ret = jQuery.merge( this.constructor(), elems );
|
||
|
||
// Add the old object onto the stack (as a reference)
|
||
ret.prevObject = this;
|
||
|
||
ret.context = this.context;
|
||
|
||
if ( name === "find" ) {
|
||
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
|
||
} else if ( name ) {
|
||
ret.selector = this.selector + "." + name + "(" + selector + ")";
|
||
}
|
||
|
||
// Return the newly-formed element set
|
||
return ret;
|
||
},
|
||
|
||
// Execute a callback for every element in the matched set.
|
||
// (You can seed the arguments with an array of args, but this is
|
||
// only used internally.)
|
||
each: function( callback, args ) {
|
||
return jQuery.each( this, callback, args );
|
||
},
|
||
|
||
ready: function( fn ) {
|
||
// Add the callback
|
||
jQuery.ready.promise().done( fn );
|
||
|
||
return this;
|
||
},
|
||
|
||
eq: function( i ) {
|
||
i = +i;
|
||
return i === -1 ?
|
||
this.slice( i ) :
|
||
this.slice( i, i + 1 );
|
||
},
|
||
|
||
first: function() {
|
||
return this.eq( 0 );
|
||
},
|
||
|
||
last: function() {
|
||
return this.eq( -1 );
|
||
},
|
||
|
||
slice: function() {
|
||
return this.pushStack( core_slice.apply( this, arguments ),
|
||
"slice", core_slice.call(arguments).join(",") );
|
||
},
|
||
|
||
map: function( callback ) {
|
||
return this.pushStack( jQuery.map(this, function( elem, i ) {
|
||
return callback.call( elem, i, elem );
|
||
}));
|
||
},
|
||
|
||
end: function() {
|
||
return this.prevObject || this.constructor(null);
|
||
},
|
||
|
||
// For internal use only.
|
||
// Behaves like an Array's method, not like a jQuery method.
|
||
push: core_push,
|
||
sort: [].sort,
|
||
splice: [].splice
|
||
};
|
||
|
||
// Give the init function the jQuery prototype for later instantiation
|
||
jQuery.fn.init.prototype = jQuery.fn;
|
||
|
||
jQuery.extend = jQuery.fn.extend = function() {
|
||
var options, name, src, copy, copyIsArray, clone,
|
||
target = arguments[0] || {},
|
||
i = 1,
|
||
length = arguments.length,
|
||
deep = false;
|
||
|
||
// Handle a deep copy situation
|
||
if ( typeof target === "boolean" ) {
|
||
deep = target;
|
||
target = arguments[1] || {};
|
||
// skip the boolean and the target
|
||
i = 2;
|
||
}
|
||
|
||
// Handle case when target is a string or something (possible in deep copy)
|
||
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
|
||
target = {};
|
||
}
|
||
|
||
// extend jQuery itself if only one argument is passed
|
||
if ( length === i ) {
|
||
target = this;
|
||
--i;
|
||
}
|
||
|
||
for ( ; i < length; i++ ) {
|
||
// Only deal with non-null/undefined values
|
||
if ( (options = arguments[ i ]) != null ) {
|
||
// Extend the base object
|
||
for ( name in options ) {
|
||
src = target[ name ];
|
||
copy = options[ name ];
|
||
|
||
// Prevent never-ending loop
|
||
if ( target === copy ) {
|
||
continue;
|
||
}
|
||
|
||
// Recurse if we're merging plain objects or arrays
|
||
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
|
||
if ( copyIsArray ) {
|
||
copyIsArray = false;
|
||
clone = src && jQuery.isArray(src) ? src : [];
|
||
|
||
} else {
|
||
clone = src && jQuery.isPlainObject(src) ? src : {};
|
||
}
|
||
|
||
// Never move original objects, clone them
|
||
target[ name ] = jQuery.extend( deep, clone, copy );
|
||
|
||
// Don't bring in undefined values
|
||
} else if ( copy !== undefined ) {
|
||
target[ name ] = copy;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Return the modified object
|
||
return target;
|
||
};
|
||
|
||
jQuery.extend({
|
||
noConflict: function( deep ) {
|
||
if ( window.$ === jQuery ) {
|
||
window.$ = _$;
|
||
}
|
||
|
||
if ( deep && window.jQuery === jQuery ) {
|
||
window.jQuery = _jQuery;
|
||
}
|
||
|
||
return jQuery;
|
||
},
|
||
|
||
// Is the DOM ready to be used? Set to true once it occurs.
|
||
isReady: false,
|
||
|
||
// A counter to track how many items to wait for before
|
||
// the ready event fires. See #6781
|
||
readyWait: 1,
|
||
|
||
// Hold (or release) the ready event
|
||
holdReady: function( hold ) {
|
||
if ( hold ) {
|
||
jQuery.readyWait++;
|
||
} else {
|
||
jQuery.ready( true );
|
||
}
|
||
},
|
||
|
||
// Handle when the DOM is ready
|
||
ready: function( wait ) {
|
||
|
||
// Abort if there are pending holds or we're already ready
|
||
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
|
||
return;
|
||
}
|
||
|
||
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
|
||
if ( !document.body ) {
|
||
return setTimeout( jQuery.ready, 1 );
|
||
}
|
||
|
||
// Remember that the DOM is ready
|
||
jQuery.isReady = true;
|
||
|
||
// If a normal DOM Ready event fired, decrement, and wait if need be
|
||
if ( wait !== true && --jQuery.readyWait > 0 ) {
|
||
return;
|
||
}
|
||
|
||
// If there are functions bound, to execute
|
||
readyList.resolveWith( document, [ jQuery ] );
|
||
|
||
// Trigger any bound ready events
|
||
if ( jQuery.fn.trigger ) {
|
||
jQuery( document ).trigger("ready").off("ready");
|
||
}
|
||
},
|
||
|
||
// See test/unit/core.js for details concerning isFunction.
|
||
// Since version 1.3, DOM methods and functions like alert
|
||
// aren't supported. They return false on IE (#2968).
|
||
isFunction: function( obj ) {
|
||
return jQuery.type(obj) === "function";
|
||
},
|
||
|
||
isArray: Array.isArray || function( obj ) {
|
||
return jQuery.type(obj) === "array";
|
||
},
|
||
|
||
isWindow: function( obj ) {
|
||
return obj != null && obj == obj.window;
|
||
},
|
||
|
||
isNumeric: function( obj ) {
|
||
return !isNaN( parseFloat(obj) ) && isFinite( obj );
|
||
},
|
||
|
||
type: function( obj ) {
|
||
return obj == null ?
|
||
String( obj ) :
|
||
class2type[ core_toString.call(obj) ] || "object";
|
||
},
|
||
|
||
isPlainObject: function( obj ) {
|
||
// Must be an Object.
|
||
// Because of IE, we also have to check the presence of the constructor property.
|
||
// Make sure that DOM nodes and window objects don't pass through, as well
|
||
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// Not own constructor property must be Object
|
||
if ( obj.constructor &&
|
||
!core_hasOwn.call(obj, "constructor") &&
|
||
!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
|
||
return false;
|
||
}
|
||
} catch ( e ) {
|
||
// IE8,9 Will throw exceptions on certain host objects #9897
|
||
return false;
|
||
}
|
||
|
||
// Own properties are enumerated firstly, so to speed up,
|
||
// if last one is own, then all properties are own.
|
||
|
||
var key;
|
||
for ( key in obj ) {}
|
||
|
||
return key === undefined || core_hasOwn.call( obj, key );
|
||
},
|
||
|
||
isEmptyObject: function( obj ) {
|
||
var name;
|
||
for ( name in obj ) {
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
|
||
error: function( msg ) {
|
||
throw new Error( msg );
|
||
},
|
||
|
||
// data: string of html
|
||
// context (optional): If specified, the fragment will be created in this context, defaults to document
|
||
// scripts (optional): If true, will include scripts passed in the html string
|
||
parseHTML: function( data, context, scripts ) {
|
||
var parsed;
|
||
if ( !data || typeof data !== "string" ) {
|
||
return null;
|
||
}
|
||
if ( typeof context === "boolean" ) {
|
||
scripts = context;
|
||
context = 0;
|
||
}
|
||
context = context || document;
|
||
|
||
// Single tag
|
||
if ( (parsed = rsingleTag.exec( data )) ) {
|
||
return [ context.createElement( parsed[1] ) ];
|
||
}
|
||
|
||
parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
|
||
return jQuery.merge( [],
|
||
(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
|
||
},
|
||
|
||
parseJSON: function( data ) {
|
||
if ( !data || typeof data !== "string") {
|
||
return null;
|
||
}
|
||
|
||
// Make sure leading/trailing whitespace is removed (IE can't handle it)
|
||
data = jQuery.trim( data );
|
||
|
||
// Attempt to parse using the native JSON parser first
|
||
if ( window.JSON && window.JSON.parse ) {
|
||
return window.JSON.parse( data );
|
||
}
|
||
|
||
// Make sure the incoming data is actual JSON
|
||
// Logic borrowed from http://json.org/json2.js
|
||
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
|
||
.replace( rvalidtokens, "]" )
|
||
.replace( rvalidbraces, "")) ) {
|
||
|
||
return ( new Function( "return " + data ) )();
|
||
|
||
}
|
||
jQuery.error( "Invalid JSON: " + data );
|
||
},
|
||
|
||
// Cross-browser xml parsing
|
||
parseXML: function( data ) {
|
||
var xml, tmp;
|
||
if ( !data || typeof data !== "string" ) {
|
||
return null;
|
||
}
|
||
try {
|
||
if ( window.DOMParser ) { // Standard
|
||
tmp = new DOMParser();
|
||
xml = tmp.parseFromString( data , "text/xml" );
|
||
} else { // IE
|
||
xml = new ActiveXObject( "Microsoft.XMLDOM" );
|
||
xml.async = "false";
|
||
xml.loadXML( data );
|
||
}
|
||
} catch( e ) {
|
||
xml = undefined;
|
||
}
|
||
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
|
||
jQuery.error( "Invalid XML: " + data );
|
||
}
|
||
return xml;
|
||
},
|
||
|
||
noop: function() {},
|
||
|
||
// Evaluates a script in a global context
|
||
// Workarounds based on findings by Jim Driscoll
|
||
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
|
||
globalEval: function( data ) {
|
||
if ( data && core_rnotwhite.test( data ) ) {
|
||
// We use execScript on Internet Explorer
|
||
// We use an anonymous function so that context is window
|
||
// rather than jQuery in Firefox
|
||
( window.execScript || function( data ) {
|
||
window[ "eval" ].call( window, data );
|
||
} )( data );
|
||
}
|
||
},
|
||
|
||
// Convert dashed to camelCase; used by the css and data modules
|
||
// Microsoft forgot to hump their vendor prefix (#9572)
|
||
camelCase: function( string ) {
|
||
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
||
},
|
||
|
||
nodeName: function( elem, name ) {
|
||
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
|
||
},
|
||
|
||
// args is for internal usage only
|
||
each: function( obj, callback, args ) {
|
||
var name,
|
||
i = 0,
|
||
length = obj.length,
|
||
isObj = length === undefined || jQuery.isFunction( obj );
|
||
|
||
if ( args ) {
|
||
if ( isObj ) {
|
||
for ( name in obj ) {
|
||
if ( callback.apply( obj[ name ], args ) === false ) {
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
for ( ; i < length; ) {
|
||
if ( callback.apply( obj[ i++ ], args ) === false ) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// A special, fast, case for the most common use of each
|
||
} else {
|
||
if ( isObj ) {
|
||
for ( name in obj ) {
|
||
if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
for ( ; i < length; ) {
|
||
if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return obj;
|
||
},
|
||
|
||
// Use native String.trim function wherever possible
|
||
trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
|
||
function( text ) {
|
||
return text == null ?
|
||
"" :
|
||
core_trim.call( text );
|
||
} :
|
||
|
||
// Otherwise use our own trimming functionality
|
||
function( text ) {
|
||
return text == null ?
|
||
"" :
|
||
( text + "" ).replace( rtrim, "" );
|
||
},
|
||
|
||
// results is for internal usage only
|
||
makeArray: function( arr, results ) {
|
||
var type,
|
||
ret = results || [];
|
||
|
||
if ( arr != null ) {
|
||
// The window, strings (and functions) also have 'length'
|
||
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
|
||
type = jQuery.type( arr );
|
||
|
||
if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
|
||
core_push.call( ret, arr );
|
||
} else {
|
||
jQuery.merge( ret, arr );
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
},
|
||
|
||
inArray: function( elem, arr, i ) {
|
||
var len;
|
||
|
||
if ( arr ) {
|
||
if ( core_indexOf ) {
|
||
return core_indexOf.call( arr, elem, i );
|
||
}
|
||
|
||
len = arr.length;
|
||
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
|
||
|
||
for ( ; i < len; i++ ) {
|
||
// Skip accessing in sparse arrays
|
||
if ( i in arr && arr[ i ] === elem ) {
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
},
|
||
|
||
merge: function( first, second ) {
|
||
var l = second.length,
|
||
i = first.length,
|
||
j = 0;
|
||
|
||
if ( typeof l === "number" ) {
|
||
for ( ; j < l; j++ ) {
|
||
first[ i++ ] = second[ j ];
|
||
}
|
||
|
||
} else {
|
||
while ( second[j] !== undefined ) {
|
||
first[ i++ ] = second[ j++ ];
|
||
}
|
||
}
|
||
|
||
first.length = i;
|
||
|
||
return first;
|
||
},
|
||
|
||
grep: function( elems, callback, inv ) {
|
||
var retVal,
|
||
ret = [],
|
||
i = 0,
|
||
length = elems.length;
|
||
inv = !!inv;
|
||
|
||
// Go through the array, only saving the items
|
||
// that pass the validator function
|
||
for ( ; i < length; i++ ) {
|
||
retVal = !!callback( elems[ i ], i );
|
||
if ( inv !== retVal ) {
|
||
ret.push( elems[ i ] );
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
},
|
||
|
||
// arg is for internal usage only
|
||
map: function( elems, callback, arg ) {
|
||
var value, key,
|
||
ret = [],
|
||
i = 0,
|
||
length = elems.length,
|
||
// jquery objects are treated as arrays
|
||
isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
|
||
|
||
// Go through the array, translating each of the items to their
|
||
if ( isArray ) {
|
||
for ( ; i < length; i++ ) {
|
||
value = callback( elems[ i ], i, arg );
|
||
|
||
if ( value != null ) {
|
||
ret[ ret.length ] = value;
|
||
}
|
||
}
|
||
|
||
// Go through every key on the object,
|
||
} else {
|
||
for ( key in elems ) {
|
||
value = callback( elems[ key ], key, arg );
|
||
|
||
if ( value != null ) {
|
||
ret[ ret.length ] = value;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Flatten any nested arrays
|
||
return ret.concat.apply( [], ret );
|
||
},
|
||
|
||
// A global GUID counter for objects
|
||
guid: 1,
|
||
|
||
// Bind a function to a context, optionally partially applying any
|
||
// arguments.
|
||
proxy: function( fn, context ) {
|
||
var tmp, args, proxy;
|
||
|
||
if ( typeof context === "string" ) {
|
||
tmp = fn[ context ];
|
||
context = fn;
|
||
fn = tmp;
|
||
}
|
||
|
||
// Quick check to determine if target is callable, in the spec
|
||
// this throws a TypeError, but we will just return undefined.
|
||
if ( !jQuery.isFunction( fn ) ) {
|
||
return undefined;
|
||
}
|
||
|
||
// Simulated bind
|
||
args = core_slice.call( arguments, 2 );
|
||
proxy = function() {
|
||
return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
|
||
};
|
||
|
||
// Set the guid of unique handler to the same of original handler, so it can be removed
|
||
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
|
||
|
||
return proxy;
|
||
},
|
||
|
||
// Multifunctional method to get and set values of a collection
|
||
// The value/s can optionally be executed if it's a function
|
||
access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
|
||
var exec,
|
||
bulk = key == null,
|
||
i = 0,
|
||
length = elems.length;
|
||
|
||
// Sets many values
|
||
if ( key && typeof key === "object" ) {
|
||
for ( i in key ) {
|
||
jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
|
||
}
|
||
chainable = 1;
|
||
|
||
// Sets one value
|
||
} else if ( value !== undefined ) {
|
||
// Optionally, function values get executed if exec is true
|
||
exec = pass === undefined && jQuery.isFunction( value );
|
||
|
||
if ( bulk ) {
|
||
// Bulk operations only iterate when executing function values
|
||
if ( exec ) {
|
||
exec = fn;
|
||
fn = function( elem, key, value ) {
|
||
return exec.call( jQuery( elem ), value );
|
||
};
|
||
|
||
// Otherwise they run against the entire set
|
||
} else {
|
||
fn.call( elems, value );
|
||
fn = null;
|
||
}
|
||
}
|
||
|
||
if ( fn ) {
|
||
for (; i < length; i++ ) {
|
||
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
|
||
}
|
||
}
|
||
|
||
chainable = 1;
|
||
}
|
||
|
||
return chainable ?
|
||
elems :
|
||
|
||
// Gets
|
||
bulk ?
|
||
fn.call( elems ) :
|
||
length ? fn( elems[0], key ) : emptyGet;
|
||
},
|
||
|
||
now: function() {
|
||
return ( new Date() ).getTime();
|
||
}
|
||
});
|
||
|
||
jQuery.ready.promise = function( obj ) {
|
||
if ( !readyList ) {
|
||
|
||
readyList = jQuery.Deferred();
|
||
|
||
// Catch cases where $(document).ready() is called after the browser event has already occurred.
|
||
// we once tried to use readyState "interactive" here, but it caused issues like the one
|
||
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
|
||
if ( document.readyState === "complete" ) {
|
||
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
||
setTimeout( jQuery.ready, 1 );
|
||
|
||
// Standards-based browsers support DOMContentLoaded
|
||
} else if ( document.addEventListener ) {
|
||
// Use the handy event callback
|
||
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
|
||
|
||
// A fallback to window.onload, that will always work
|
||
window.addEventListener( "load", jQuery.ready, false );
|
||
|
||
// If IE event model is used
|
||
} else {
|
||
// Ensure firing before onload, maybe late but safe also for iframes
|
||
document.attachEvent( "onreadystatechange", DOMContentLoaded );
|
||
|
||
// A fallback to window.onload, that will always work
|
||
window.attachEvent( "onload", jQuery.ready );
|
||
|
||
// If IE and not a frame
|
||
// continually check to see if the document is ready
|
||
var top = false;
|
||
|
||
try {
|
||
top = window.frameElement == null && document.documentElement;
|
||
} catch(e) {}
|
||
|
||
if ( top && top.doScroll ) {
|
||
(function doScrollCheck() {
|
||
if ( !jQuery.isReady ) {
|
||
|
||
try {
|
||
// Use the trick by Diego Perini
|
||
// http://javascript.nwbox.com/IEContentLoaded/
|
||
top.doScroll("left");
|
||
} catch(e) {
|
||
return setTimeout( doScrollCheck, 50 );
|
||
}
|
||
|
||
// and execute any waiting functions
|
||
jQuery.ready();
|
||
}
|
||
})();
|
||
}
|
||
}
|
||
}
|
||
return readyList.promise( obj );
|
||
};
|
||
|
||
// Populate the class2type map
|
||
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
|
||
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
||
});
|
||
|
||
// All jQuery objects should point back to these
|
||
rootjQuery = jQuery(document);
|
||
// String to Object options format cache
|
||
var optionsCache = {};
|
||
|
||
// Convert String-formatted options into Object-formatted ones and store in cache
|
||
function createOptions( options ) {
|
||
var object = optionsCache[ options ] = {};
|
||
jQuery.each( options.split( core_rspace ), function( _, flag ) {
|
||
object[ flag ] = true;
|
||
});
|
||
return object;
|
||
}
|
||
|
||
/*
|
||
* Create a callback list using the following parameters:
|
||
*
|
||
* options: an optional list of space-separated options that will change how
|
||
* the callback list behaves or a more traditional option object
|
||
*
|
||
* By default a callback list will act like an event callback list and can be
|
||
* "fired" multiple times.
|
||
*
|
||
* Possible options:
|
||
*
|
||
* 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( options ) {
|
||
|
||
// Convert options from String-formatted to Object-formatted if needed
|
||
// (we check in cache first)
|
||
options = typeof options === "string" ?
|
||
( optionsCache[ options ] || createOptions( options ) ) :
|
||
jQuery.extend( {}, options );
|
||
|
||
var // Last fire value (for non-forgettable lists)
|
||
memory,
|
||
// Flag to know if list was already fired
|
||
fired,
|
||
// 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,
|
||
// Actual callback list
|
||
list = [],
|
||
// Stack of fire calls for repeatable lists
|
||
stack = !options.once && [],
|
||
// Fire callbacks
|
||
fire = function( data ) {
|
||
memory = options.memory && data;
|
||
fired = true;
|
||
firingIndex = firingStart || 0;
|
||
firingStart = 0;
|
||
firingLength = list.length;
|
||
firing = true;
|
||
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
|
||
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
|
||
memory = false; // To prevent further calls using add
|
||
break;
|
||
}
|
||
}
|
||
firing = false;
|
||
if ( list ) {
|
||
if ( stack ) {
|
||
if ( stack.length ) {
|
||
fire( stack.shift() );
|
||
}
|
||
} else if ( memory ) {
|
||
list = [];
|
||
} else {
|
||
self.disable();
|
||
}
|
||
}
|
||
},
|
||
// Actual Callbacks object
|
||
self = {
|
||
// Add a callback or a collection of callbacks to the list
|
||
add: function() {
|
||
if ( list ) {
|
||
// First, we save the current length
|
||
var start = list.length;
|
||
(function add( args ) {
|
||
jQuery.each( args, function( _, arg ) {
|
||
var type = jQuery.type( arg );
|
||
if ( type === "function" ) {
|
||
if ( !options.unique || !self.has( arg ) ) {
|
||
list.push( arg );
|
||
}
|
||
} else if ( arg && arg.length && type !== "string" ) {
|
||
// Inspect recursively
|
||
add( arg );
|
||
}
|
||
});
|
||
})( 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
|
||
} else if ( memory ) {
|
||
firingStart = start;
|
||
fire( memory );
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
// Remove a callback from the list
|
||
remove: function() {
|
||
if ( list ) {
|
||
jQuery.each( arguments, function( _, arg ) {
|
||
var index;
|
||
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
|
||
list.splice( index, 1 );
|
||
// Handle firing indexes
|
||
if ( firing ) {
|
||
if ( index <= firingLength ) {
|
||
firingLength--;
|
||
}
|
||
if ( index <= firingIndex ) {
|
||
firingIndex--;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
},
|
||
// Control if a given callback is in the list
|
||
has: function( fn ) {
|
||
return jQuery.inArray( fn, list ) > -1;
|
||
},
|
||
// 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 ) {
|
||
self.disable();
|
||
}
|
||
return this;
|
||
},
|
||
// Is it locked?
|
||
locked: function() {
|
||
return !stack;
|
||
},
|
||
// Call all callbacks with the given context and arguments
|
||
fireWith: function( context, args ) {
|
||
args = args || [];
|
||
args = [ context, args.slice ? args.slice() : args ];
|
||
if ( list && ( !fired || stack ) ) {
|
||
if ( firing ) {
|
||
stack.push( args );
|
||
} else {
|
||
fire( args );
|
||
}
|
||
}
|
||
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 !!fired;
|
||
}
|
||
};
|
||
|
||
return self;
|
||
};
|
||
jQuery.extend({
|
||
|
||
Deferred: function( func ) {
|
||
var tuples = [
|
||
// action, add listener, listener list, final state
|
||
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
|
||
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
|
||
[ "notify", "progress", jQuery.Callbacks("memory") ]
|
||
],
|
||
state = "pending",
|
||
promise = {
|
||
state: function() {
|
||
return state;
|
||
},
|
||
always: function() {
|
||
deferred.done( arguments ).fail( arguments );
|
||
return this;
|
||
},
|
||
then: function( /* fnDone, fnFail, fnProgress */ ) {
|
||
var fns = arguments;
|
||
return jQuery.Deferred(function( newDefer ) {
|
||
jQuery.each( tuples, function( i, tuple ) {
|
||
var action = tuple[ 0 ],
|
||
fn = fns[ i ];
|
||
// deferred[ done | fail | progress ] for forwarding actions to newDefer
|
||
deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
|
||
function() {
|
||
var returned = fn.apply( this, arguments );
|
||
if ( returned && jQuery.isFunction( returned.promise ) ) {
|
||
returned.promise()
|
||
.done( newDefer.resolve )
|
||
.fail( newDefer.reject )
|
||
.progress( newDefer.notify );
|
||
} else {
|
||
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
|
||
}
|
||
} :
|
||
newDefer[ action ]
|
||
);
|
||
});
|
||
fns = null;
|
||
}).promise();
|
||
},
|
||
// Get a promise for this deferred
|
||
// If obj is provided, the promise aspect is added to the object
|
||
promise: function( obj ) {
|
||
return obj != null ? jQuery.extend( obj, promise ) : promise;
|
||
}
|
||
},
|
||
deferred = {};
|
||
|
||
// Keep pipe for back-compat
|
||
promise.pipe = promise.then;
|
||
|
||
// Add list-specific methods
|
||
jQuery.each( tuples, function( i, tuple ) {
|
||
var list = tuple[ 2 ],
|
||
stateString = tuple[ 3 ];
|
||
|
||
// promise[ done | fail | progress ] = list.add
|
||
promise[ tuple[1] ] = list.add;
|
||
|
||
// Handle state
|
||
if ( stateString ) {
|
||
list.add(function() {
|
||
// state = [ resolved | rejected ]
|
||
state = stateString;
|
||
|
||
// [ reject_list | resolve_list ].disable; progress_list.lock
|
||
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
|
||
}
|
||
|
||
// deferred[ resolve | reject | notify ] = list.fire
|
||
deferred[ tuple[0] ] = list.fire;
|
||
deferred[ tuple[0] + "With" ] = list.fireWith;
|
||
});
|
||
|
||
// Make the deferred a promise
|
||
promise.promise( deferred );
|
||
|
||
// Call given func if any
|
||
if ( func ) {
|
||
func.call( deferred, deferred );
|
||
}
|
||
|
||
// All done!
|
||
return deferred;
|
||
},
|
||
|
||
// Deferred helper
|
||
when: function( subordinate /* , ..., subordinateN */ ) {
|
||
var i = 0,
|
||
resolveValues = core_slice.call( arguments ),
|
||
length = resolveValues.length,
|
||
|
||
// the count of uncompleted subordinates
|
||
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
|
||
|
||
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
|
||
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
|
||
|
||
// Update function for both resolve and progress values
|
||
updateFunc = function( i, contexts, values ) {
|
||
return function( value ) {
|
||
contexts[ i ] = this;
|
||
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
|
||
if( values === progressValues ) {
|
||
deferred.notifyWith( contexts, values );
|
||
} else if ( !( --remaining ) ) {
|
||
deferred.resolveWith( contexts, values );
|
||
}
|
||
};
|
||
},
|
||
|
||
progressValues, progressContexts, resolveContexts;
|
||
|
||
// add listeners to Deferred subordinates; treat others as resolved
|
||
if ( length > 1 ) {
|
||
progressValues = new Array( length );
|
||
progressContexts = new Array( length );
|
||
resolveContexts = new Array( length );
|
||
for ( ; i < length; i++ ) {
|
||
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
|
||
resolveValues[ i ].promise()
|
||
.done( updateFunc( i, resolveContexts, resolveValues ) )
|
||
.fail( deferred.reject )
|
||
.progress( updateFunc( i, progressContexts, progressValues ) );
|
||
} else {
|
||
--remaining;
|
||
}
|
||
}
|
||
}
|
||
|
||
// if we're not waiting on anything, resolve the master
|
||
if ( !remaining ) {
|
||
deferred.resolveWith( resolveContexts, resolveValues );
|
||
}
|
||
|
||
return deferred.promise();
|
||
}
|
||
});
|
||
jQuery.support = (function() {
|
||
|
||
var support,
|
||
all,
|
||
a,
|
||
select,
|
||
opt,
|
||
input,
|
||
fragment,
|
||
eventName,
|
||
i,
|
||
isSupported,
|
||
clickFn,
|
||
div = document.createElement("div");
|
||
|
||
// Setup
|
||
div.setAttribute( "className", "t" );
|
||
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
|
||
|
||
// Support tests won't run in some limited or non-browser environments
|
||
all = div.getElementsByTagName("*");
|
||
a = div.getElementsByTagName("a")[ 0 ];
|
||
if ( !all || !a || !all.length ) {
|
||
return {};
|
||
}
|
||
|
||
// First batch of tests
|
||
select = document.createElement("select");
|
||
opt = select.appendChild( document.createElement("option") );
|
||
input = div.getElementsByTagName("input")[ 0 ];
|
||
|
||
a.style.cssText = "top:1px;float:left;opacity:.5";
|
||
support = {
|
||
// IE strips leading whitespace when .innerHTML is used
|
||
leadingWhitespace: ( div.firstChild.nodeType === 3 ),
|
||
|
||
// Make sure that tbody elements aren't automatically inserted
|
||
// IE will insert them into empty tables
|
||
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,
|
||
|
||
// Get the style information from getAttribute
|
||
// (IE uses .cssText instead)
|
||
style: /top/.test( a.getAttribute("style") ),
|
||
|
||
// Make sure that URLs aren't manipulated
|
||
// (IE normalizes it by default)
|
||
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.5/.test( a.style.opacity ),
|
||
|
||
// Verify style float existence
|
||
// (IE uses styleFloat instead of cssFloat)
|
||
cssFloat: !!a.style.cssFloat,
|
||
|
||
// Make sure that if no value is specified for a checkbox
|
||
// that it defaults to "on".
|
||
// (WebKit defaults to "" instead)
|
||
checkOn: ( input.value === "on" ),
|
||
|
||
// Make sure that a selected-by-default option has a working selected property.
|
||
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
|
||
optSelected: opt.selected,
|
||
|
||
// 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>",
|
||
|
||
// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
|
||
boxModel: ( document.compatMode === "CSS1Compat" ),
|
||
|
||
// Will be defined later
|
||
submitBubbles: true,
|
||
changeBubbles: true,
|
||
focusinBubbles: false,
|
||
deleteExpando: true,
|
||
noCloneEvent: true,
|
||
inlineBlockNeedsLayout: false,
|
||
shrinkWrapBlocks: false,
|
||
reliableMarginRight: true,
|
||
boxSizingReliable: true,
|
||
pixelPosition: false
|
||
};
|
||
|
||
// Make sure checked status is properly cloned
|
||
input.checked = true;
|
||
support.noCloneChecked = input.cloneNode( true ).checked;
|
||
|
||
// Make sure that the options inside disabled selects aren't marked as disabled
|
||
// (WebKit marks them as disabled)
|
||
select.disabled = true;
|
||
support.optDisabled = !opt.disabled;
|
||
|
||
// Test to see if it's possible to delete an expando from an element
|
||
// Fails in Internet Explorer
|
||
try {
|
||
delete div.test;
|
||
} catch( e ) {
|
||
support.deleteExpando = false;
|
||
}
|
||
|
||
if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
|
||
div.attachEvent( "onclick", clickFn = function() {
|
||
// Cloning a node shouldn't copy over any
|
||
// bound event handlers (IE does this)
|
||
support.noCloneEvent = false;
|
||
});
|
||
div.cloneNode( true ).fireEvent("onclick");
|
||
div.detachEvent( "onclick", clickFn );
|
||
}
|
||
|
||
// Check if a radio maintains its value
|
||
// after being appended to the DOM
|
||
input = document.createElement("input");
|
||
input.value = "t";
|
||
input.setAttribute( "type", "radio" );
|
||
support.radioValue = input.value === "t";
|
||
|
||
input.setAttribute( "checked", "checked" );
|
||
|
||
// #11217 - WebKit loses check when the name is after the checked attribute
|
||
input.setAttribute( "name", "t" );
|
||
|
||
div.appendChild( input );
|
||
fragment = document.createDocumentFragment();
|
||
fragment.appendChild( div.lastChild );
|
||
|
||
// WebKit doesn't clone checked state correctly in fragments
|
||
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
||
|
||
// Check if a disconnected checkbox will retain its checked
|
||
// value of true after appended to the DOM (IE6/7)
|
||
support.appendChecked = input.checked;
|
||
|
||
fragment.removeChild( input );
|
||
fragment.appendChild( div );
|
||
|
||
// Technique from Juriy Zaytsev
|
||
// 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
|
||
// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
|
||
if ( div.attachEvent ) {
|
||
for ( i in {
|
||
submit: true,
|
||
change: true,
|
||
focusin: true
|
||
}) {
|
||
eventName = "on" + i;
|
||
isSupported = ( eventName in div );
|
||
if ( !isSupported ) {
|
||
div.setAttribute( eventName, "return;" );
|
||
isSupported = ( typeof div[ eventName ] === "function" );
|
||
}
|
||
support[ i + "Bubbles" ] = isSupported;
|
||
}
|
||
}
|
||
|
||
// Run tests that need a body at doc ready
|
||
jQuery(function() {
|
||
var container, div, tds, marginDiv,
|
||
divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
|
||
body = document.getElementsByTagName("body")[0];
|
||
|
||
if ( !body ) {
|
||
// Return for frameset docs that don't have a body
|
||
return;
|
||
}
|
||
|
||
container = document.createElement("div");
|
||
container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
|
||
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></td><td>t</td></tr></table>";
|
||
tds = div.getElementsByTagName("td");
|
||
tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
|
||
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 );
|
||
|
||
// Check box-sizing and margin behavior
|
||
div.innerHTML = "";
|
||
div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
|
||
support.boxSizing = ( div.offsetWidth === 4 );
|
||
support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
|
||
|
||
// NOTE: To any future maintainer, we've window.getComputedStyle
|
||
// because jsdom on node.js will break without it.
|
||
if ( window.getComputedStyle ) {
|
||
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
|
||
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
|
||
|
||
// Check if div with explicit width and no margin-right incorrectly
|
||
// gets computed margin-right based on width of container. For more
|
||
// info see bug #3333
|
||
// Fails in WebKit before Feb 2011 nightlies
|
||
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
|
||
marginDiv = document.createElement("div");
|
||
marginDiv.style.cssText = div.style.cssText = divReset;
|
||
marginDiv.style.marginRight = marginDiv.style.width = "0";
|
||
div.style.width = "1px";
|
||
div.appendChild( marginDiv );
|
||
support.reliableMarginRight =
|
||
!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
|
||
}
|
||
|
||
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.innerHTML = "";
|
||
div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
|
||
support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
|
||
|
||
// Check if elements with layout shrink-wrap their children
|
||
// (IE 6 does this)
|
||
div.style.display = "block";
|
||
div.style.overflow = "visible";
|
||
div.innerHTML = "<div></div>";
|
||
div.firstChild.style.width = "5px";
|
||
support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
|
||
|
||
container.style.zoom = 1;
|
||
}
|
||
|
||
// Null elements to avoid leaks in IE
|
||
body.removeChild( container );
|
||
container = div = tds = marginDiv = null;
|
||
});
|
||
|
||
// Null elements to avoid leaks in IE
|
||
fragment.removeChild( div );
|
||
all = a = select = opt = input = fragment = div = null;
|
||
|
||
return support;
|
||
})();
|
||
var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
|
||
rmultiDash = /([A-Z])/g;
|
||
|
||
jQuery.extend({
|
||
cache: {},
|
||
|
||
deletedIds: [],
|
||
|
||
// Remove at next major release (1.9/2.0)
|
||
uuid: 0,
|
||
|
||
// Unique for each copy of jQuery on the page
|
||
// Non-digits removed to match rinlinejQuery
|
||
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
|
||
|
||
// The following elements throw uncatchable exceptions if you
|
||
// attempt to add expando properties to them.
|
||
noData: {
|
||
"embed": true,
|
||
// Ban all objects except for Flash (which handle expandos)
|
||
"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
|
||
"applet": true
|
||
},
|
||
|
||
hasData: function( elem ) {
|
||
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
|
||
return !!elem && !isEmptyDataObject( elem );
|
||
},
|
||
|
||
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
|
||
if ( !jQuery.acceptData( elem ) ) {
|
||
return;
|
||
}
|
||
|
||
var thisCache, ret,
|
||
internalKey = jQuery.expando,
|
||
getByName = typeof name === "string",
|
||
|
||
// We have to handle DOM nodes and JS objects differently because IE6-7
|
||
// can't GC object references properly across the DOM-JS boundary
|
||
isNode = elem.nodeType,
|
||
|
||
// Only DOM nodes need the global jQuery cache; JS object data is
|
||
// attached directly to the object so GC can occur automatically
|
||
cache = isNode ? jQuery.cache : elem,
|
||
|
||
// 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[ internalKey ] : elem[ internalKey ] && internalKey;
|
||
|
||
// 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 || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
|
||
return;
|
||
}
|
||
|
||
if ( !id ) {
|
||
// Only DOM nodes need a new unique ID for each element since their data
|
||
// ends up in the global cache
|
||
if ( isNode ) {
|
||
elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
|
||
} else {
|
||
id = internalKey;
|
||
}
|
||
}
|
||
|
||
if ( !cache[ id ] ) {
|
||
cache[ id ] = {};
|
||
|
||
// Avoids exposing jQuery metadata on plain JS objects when the object
|
||
// is serialized using JSON.stringify
|
||
if ( !isNode ) {
|
||
cache[ id ].toJSON = jQuery.noop;
|
||
}
|
||
}
|
||
|
||
// An object can be passed to jQuery.data instead of a key/value pair; this gets
|
||
// shallow copied over onto the existing cache
|
||
if ( typeof name === "object" || typeof name === "function" ) {
|
||
if ( pvt ) {
|
||
cache[ id ] = jQuery.extend( cache[ id ], name );
|
||
} else {
|
||
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
|
||
}
|
||
}
|
||
|
||
thisCache = cache[ id ];
|
||
|
||
// 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.data ) {
|
||
thisCache.data = {};
|
||
}
|
||
|
||
thisCache = thisCache.data;
|
||
}
|
||
|
||
if ( data !== undefined ) {
|
||
thisCache[ jQuery.camelCase( name ) ] = data;
|
||
}
|
||
|
||
// Check for both converted-to-camel and non-converted data property names
|
||
// If a data property was specified
|
||
if ( getByName ) {
|
||
|
||
// First Try to find as-is property data
|
||
ret = thisCache[ name ];
|
||
|
||
// Test for null|undefined property data
|
||
if ( ret == null ) {
|
||
|
||
// Try to find the camelCased property
|
||
ret = thisCache[ jQuery.camelCase( name ) ];
|
||
}
|
||
} else {
|
||
ret = thisCache;
|
||
}
|
||
|
||
return ret;
|
||
},
|
||
|
||
removeData: function( elem, name, pvt /* Internal Use Only */ ) {
|
||
if ( !jQuery.acceptData( elem ) ) {
|
||
return;
|
||
}
|
||
|
||
var thisCache, i, l,
|
||
|
||
isNode = elem.nodeType,
|
||
|
||
// See jQuery.data for more information
|
||
cache = isNode ? jQuery.cache : elem,
|
||
id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
|
||
|
||
// If there is already no cache entry for this object, there is no
|
||
// purpose in continuing
|
||
if ( !cache[ id ] ) {
|
||
return;
|
||
}
|
||
|
||
if ( name ) {
|
||
|
||
thisCache = pvt ? cache[ id ] : cache[ id ].data;
|
||
|
||
if ( thisCache ) {
|
||
|
||
// 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(" ");
|
||
}
|
||
}
|
||
}
|
||
|
||
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 ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
// See jQuery.data for more information
|
||
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
|
||
if ( !isEmptyDataObject( cache[ id ] ) ) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Destroy the cache
|
||
if ( isNode ) {
|
||
jQuery.cleanData( [ elem ], true );
|
||
|
||
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
|
||
} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
|
||
delete cache[ id ];
|
||
|
||
// When all else fails, null
|
||
} else {
|
||
cache[ id ] = null;
|
||
}
|
||
},
|
||
|
||
// For internal use only.
|
||
_data: function( elem, name, data ) {
|
||
return jQuery.data( elem, name, data, true );
|
||
},
|
||
|
||
// A method for determining if a DOM node can handle the data expando
|
||
acceptData: function( elem ) {
|
||
var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
|
||
|
||
// nodes accept data unless otherwise specified; rejection can be conditional
|
||
return !noData || noData !== true && elem.getAttribute("classid") === noData;
|
||
}
|
||
});
|
||
|
||
jQuery.fn.extend({
|
||
data: function( key, value ) {
|
||
var parts, part, attr, name, l,
|
||
elem = this[0],
|
||
i = 0,
|
||
data = null;
|
||
|
||
// Gets all values
|
||
if ( key === undefined ) {
|
||
if ( this.length ) {
|
||
data = jQuery.data( elem );
|
||
|
||
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
|
||
attr = elem.attributes;
|
||
for ( l = attr.length; i < l; i++ ) {
|
||
name = attr[i].name;
|
||
|
||
if ( !name.indexOf( "data-" ) ) {
|
||
name = jQuery.camelCase( name.substring(5) );
|
||
|
||
dataAttr( elem, name, data[ name ] );
|
||
}
|
||
}
|
||
jQuery._data( elem, "parsedAttrs", true );
|
||
}
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
// Sets multiple values
|
||
if ( typeof key === "object" ) {
|
||
return this.each(function() {
|
||
jQuery.data( this, key );
|
||
});
|
||
}
|
||
|
||
parts = key.split( ".", 2 );
|
||
parts[1] = parts[1] ? "." + parts[1] : "";
|
||
part = parts[1] + "!";
|
||
|
||
return jQuery.access( this, function( value ) {
|
||
|
||
if ( value === undefined ) {
|
||
data = this.triggerHandler( "getData" + part, [ parts[0] ] );
|
||
|
||
// Try to fetch any internally stored data first
|
||
if ( data === undefined && elem ) {
|
||
data = jQuery.data( elem, key );
|
||
data = dataAttr( elem, key, data );
|
||
}
|
||
|
||
return data === undefined && parts[1] ?
|
||
this.data( parts[0] ) :
|
||
data;
|
||
}
|
||
|
||
parts[1] = value;
|
||
this.each(function() {
|
||
var self = jQuery( this );
|
||
|
||
self.triggerHandler( "setData" + part, parts );
|
||
jQuery.data( this, key, value );
|
||
self.triggerHandler( "changeData" + part, parts );
|
||
});
|
||
}, null, value, arguments.length > 1, null, false );
|
||
},
|
||
|
||
removeData: function( key ) {
|
||
return this.each(function() {
|
||
jQuery.removeData( this, key );
|
||
});
|
||
}
|
||
});
|
||
|
||
function dataAttr( elem, key, data ) {
|
||
// If nothing was found internally, try to fetch any
|
||
// data from the HTML5 data-* attribute
|
||
if ( data === undefined && elem.nodeType === 1 ) {
|
||
|
||
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
|
||
|
||
data = elem.getAttribute( name );
|
||
|
||
if ( typeof data === "string" ) {
|
||
try {
|
||
data = data === "true" ? true :
|
||
data === "false" ? false :
|
||
data === "null" ? null :
|
||
// Only convert to a number if it doesn't change the string
|
||
+data + "" === data ? +data :
|
||
rbrace.test( data ) ? jQuery.parseJSON( data ) :
|
||
data;
|
||
} catch( e ) {}
|
||
|
||
// Make sure we set the data so it isn't changed later
|
||
jQuery.data( elem, key, data );
|
||
|
||
} else {
|
||
data = undefined;
|
||
}
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
// checks a cache object for emptiness
|
||
function isEmptyDataObject( obj ) {
|
||
var name;
|
||
for ( 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;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
jQuery.extend({
|
||
queue: function( elem, type, data ) {
|
||
var queue;
|
||
|
||
if ( elem ) {
|
||
type = ( type || "fx" ) + "queue";
|
||
queue = jQuery._data( elem, type );
|
||
|
||
// Speed up dequeue by getting out quickly if this is just a lookup
|
||
if ( data ) {
|
||
if ( !queue || jQuery.isArray(data) ) {
|
||
queue = jQuery._data( elem, type, jQuery.makeArray(data) );
|
||
} else {
|
||
queue.push( data );
|
||
}
|
||
}
|
||
return queue || [];
|
||
}
|
||
},
|
||
|
||
dequeue: function( elem, type ) {
|
||
type = type || "fx";
|
||
|
||
var queue = jQuery.queue( elem, type ),
|
||
startLength = queue.length,
|
||
fn = queue.shift(),
|
||
hooks = jQuery._queueHooks( elem, type ),
|
||
next = function() {
|
||
jQuery.dequeue( elem, type );
|
||
};
|
||
|
||
// If the fx queue is dequeued, always remove the progress sentinel
|
||
if ( fn === "inprogress" ) {
|
||
fn = queue.shift();
|
||
startLength--;
|
||
}
|
||
|
||
if ( fn ) {
|
||
|
||
// Add a progress sentinel to prevent the fx queue from being
|
||
// automatically dequeued
|
||
if ( type === "fx" ) {
|
||
queue.unshift( "inprogress" );
|
||
}
|
||
|
||
// clear up the last queue stop function
|
||
delete hooks.stop;
|
||
fn.call( elem, next, hooks );
|
||
}
|
||
|
||
if ( !startLength && hooks ) {
|
||
hooks.empty.fire();
|
||
}
|
||
},
|
||
|
||
// not intended for public consumption - generates a queueHooks object, or returns the current one
|
||
_queueHooks: function( elem, type ) {
|
||
var key = type + "queueHooks";
|
||
return jQuery._data( elem, key ) || jQuery._data( elem, key, {
|
||
empty: jQuery.Callbacks("once memory").add(function() {
|
||
jQuery.removeData( elem, type + "queue", true );
|
||
jQuery.removeData( elem, key, true );
|
||
})
|
||
});
|
||
}
|
||
});
|
||
|
||
jQuery.fn.extend({
|
||
queue: function( type, data ) {
|
||
var setter = 2;
|
||
|
||
if ( typeof type !== "string" ) {
|
||
data = type;
|
||
type = "fx";
|
||
setter--;
|
||
}
|
||
|
||
if ( arguments.length < setter ) {
|
||
return jQuery.queue( this[0], type );
|
||
}
|
||
|
||
return data === undefined ?
|
||
this :
|
||
this.each(function() {
|
||
var queue = jQuery.queue( this, type, data );
|
||
|
||
// ensure a hooks for this queue
|
||
jQuery._queueHooks( this, type );
|
||
|
||
if ( type === "fx" && queue[0] !== "inprogress" ) {
|
||
jQuery.dequeue( this, type );
|
||
}
|
||
});
|
||
},
|
||
dequeue: function( type ) {
|
||
return this.each(function() {
|
||
jQuery.dequeue( this, type );
|
||
});
|
||
},
|
||
// 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;
|
||
type = type || "fx";
|
||
|
||
return this.queue( type, function( next, hooks ) {
|
||
var timeout = setTimeout( next, time );
|
||
hooks.stop = function() {
|
||
clearTimeout( timeout );
|
||
};
|
||
});
|
||
},
|
||
clearQueue: function( type ) {
|
||
return this.queue( type || "fx", [] );
|
||
},
|
||
// Get a promise resolved when queues of a certain type
|
||
// are emptied (fx is the type by default)
|
||
promise: function( type, obj ) {
|
||
var tmp,
|
||
count = 1,
|
||
defer = jQuery.Deferred(),
|
||
elements = this,
|
||
i = this.length,
|
||
resolve = function() {
|
||
if ( !( --count ) ) {
|
||
defer.resolveWith( elements, [ elements ] );
|
||
}
|
||
};
|
||
|
||
if ( typeof type !== "string" ) {
|
||
obj = type;
|
||
type = undefined;
|
||
}
|
||
type = type || "fx";
|
||
|
||
while( i-- ) {
|
||
tmp = jQuery._data( elements[ i ], type + "queueHooks" );
|
||
if ( tmp && tmp.empty ) {
|
||
count++;
|
||
tmp.empty.add( resolve );
|
||
}
|
||
}
|
||
resolve();
|
||
return defer.promise( obj );
|
||
}
|
||
});
|
||
var nodeHook, boolHook, fixSpecified,
|
||
rclass = /[\t\r\n]/g,
|
||
rreturn = /\r/g,
|
||
rtype = /^(?:button|input)$/i,
|
||
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,
|
||
getSetAttribute = jQuery.support.getSetAttribute;
|
||
|
||
jQuery.fn.extend({
|
||
attr: function( name, value ) {
|
||
return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
|
||
},
|
||
|
||
removeAttr: function( name ) {
|
||
return this.each(function() {
|
||
jQuery.removeAttr( this, name );
|
||
});
|
||
},
|
||
|
||
prop: function( name, value ) {
|
||
return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
|
||
},
|
||
|
||
removeProp: function( name ) {
|
||
name = jQuery.propFix[ name ] || name;
|
||
return this.each(function() {
|
||
// try/catch handles cases where IE balks (such as removing a property on window)
|
||
try {
|
||
this[ name ] = undefined;
|
||
delete this[ name ];
|
||
} catch( e ) {}
|
||
});
|
||
},
|
||
|
||
addClass: function( value ) {
|
||
var classNames, i, l, elem,
|
||
setClass, c, cl;
|
||
|
||
if ( jQuery.isFunction( value ) ) {
|
||
return this.each(function( j ) {
|
||
jQuery( this ).addClass( value.call(this, j, this.className) );
|
||
});
|
||
}
|
||
|
||
if ( value && typeof value === "string" ) {
|
||
classNames = value.split( core_rspace );
|
||
|
||
for ( i = 0, l = this.length; i < l; i++ ) {
|
||
elem = this[ i ];
|
||
|
||
if ( elem.nodeType === 1 ) {
|
||
if ( !elem.className && classNames.length === 1 ) {
|
||
elem.className = value;
|
||
|
||
} else {
|
||
setClass = " " + elem.className + " ";
|
||
|
||
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
|
||
if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
|
||
setClass += classNames[ c ] + " ";
|
||
}
|
||
}
|
||
elem.className = jQuery.trim( setClass );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
removeClass: function( value ) {
|
||
var removes, className, elem, c, cl, i, l;
|
||
|
||
if ( jQuery.isFunction( value ) ) {
|
||
return this.each(function( j ) {
|
||
jQuery( this ).removeClass( value.call(this, j, this.className) );
|
||
});
|
||
}
|
||
if ( (value && typeof value === "string") || value === undefined ) {
|
||
removes = ( value || "" ).split( core_rspace );
|
||
|
||
for ( i = 0, l = this.length; i < l; i++ ) {
|
||
elem = this[ i ];
|
||
if ( elem.nodeType === 1 && elem.className ) {
|
||
|
||
className = (" " + elem.className + " ").replace( rclass, " " );
|
||
|
||
// loop over each item in the removal list
|
||
for ( c = 0, cl = removes.length; c < cl; c++ ) {
|
||
// Remove until there is nothing to remove,
|
||
while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
|
||
className = className.replace( " " + removes[ c ] + " " , " " );
|
||
}
|
||
}
|
||
elem.className = value ? jQuery.trim( className ) : "";
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
toggleClass: function( value, stateVal ) {
|
||
var type = typeof value,
|
||
isBool = typeof stateVal === "boolean";
|
||
|
||
if ( jQuery.isFunction( value ) ) {
|
||
return this.each(function( i ) {
|
||
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
|
||
});
|
||
}
|
||
|
||
return this.each(function() {
|
||
if ( type === "string" ) {
|
||
// toggle individual class names
|
||
var className,
|
||
i = 0,
|
||
self = jQuery( this ),
|
||
state = stateVal,
|
||
classNames = value.split( core_rspace );
|
||
|
||
while ( (className = classNames[ i++ ]) ) {
|
||
// check each className given, space separated list
|
||
state = isBool ? state : !self.hasClass( className );
|
||
self[ state ? "addClass" : "removeClass" ]( className );
|
||
}
|
||
|
||
} else if ( type === "undefined" || type === "boolean" ) {
|
||
if ( this.className ) {
|
||
// store className if set
|
||
jQuery._data( this, "__className__", this.className );
|
||
}
|
||
|
||
// toggle whole className
|
||
this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
|
||
}
|
||
});
|
||
},
|
||
|
||
hasClass: function( selector ) {
|
||
var className = " " + selector + " ",
|
||
i = 0,
|
||
l = this.length;
|
||
for ( ; i < l; i++ ) {
|
||
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
},
|
||
|
||
val: function( value ) {
|
||
var hooks, ret, isFunction,
|
||
elem = this[0];
|
||
|
||
if ( !arguments.length ) {
|
||
if ( elem ) {
|
||
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
|
||
|
||
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
|
||
return ret;
|
||
}
|
||
|
||
ret = elem.value;
|
||
|
||
return typeof ret === "string" ?
|
||
// handle most common string cases
|
||
ret.replace(rreturn, "") :
|
||
// handle cases where value is null/undef or number
|
||
ret == null ? "" : ret;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
isFunction = jQuery.isFunction( value );
|
||
|
||
return this.each(function( i ) {
|
||
var val,
|
||
self = jQuery(this);
|
||
|
||
if ( this.nodeType !== 1 ) {
|
||
return;
|
||
}
|
||
|
||
if ( isFunction ) {
|
||
val = value.call( this, i, self.val() );
|
||
} else {
|
||
val = value;
|
||
}
|
||
|
||
// Treat null/undefined as ""; convert numbers to string
|
||
if ( val == null ) {
|
||
val = "";
|
||
} else if ( typeof val === "number" ) {
|
||
val += "";
|
||
} else if ( jQuery.isArray( val ) ) {
|
||
val = jQuery.map(val, function ( value ) {
|
||
return value == null ? "" : value + "";
|
||
});
|
||
}
|
||
|
||
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
|
||
|
||
// If set returns undefined, fall back to normal setting
|
||
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
|
||
this.value = val;
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
jQuery.extend({
|
||
valHooks: {
|
||
option: {
|
||
get: function( elem ) {
|
||
// attributes.value is undefined in Blackberry 4.7 but
|
||
// uses .value. See #6932
|
||
var val = elem.attributes.value;
|
||
return !val || val.specified ? elem.value : elem.text;
|
||
}
|
||
},
|
||
select: {
|
||
get: function( elem ) {
|
||
var value, option,
|
||
options = elem.options,
|
||
index = elem.selectedIndex,
|
||
one = elem.type === "select-one" || index < 0,
|
||
values = one ? null : [],
|
||
max = one ? index + 1 : options.length,
|
||
i = index < 0 ?
|
||
max :
|
||
one ? index : 0;
|
||
|
||
// Loop through all the selected options
|
||
for ( ; i < max; i++ ) {
|
||
option = options[ i ];
|
||
|
||
// oldIE doesn't update selected after form reset (#2551)
|
||
if ( ( option.selected || i === index ) &&
|
||
// Don't return options that are disabled or in a disabled optgroup
|
||
( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
|
||
( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
|
||
|
||
// Get the specific value for the option
|
||
value = jQuery( option ).val();
|
||
|
||
// We don't need an array for one selects
|
||
if ( one ) {
|
||
return value;
|
||
}
|
||
|
||
// Multi-Selects return an array
|
||
values.push( value );
|
||
}
|
||
}
|
||
|
||
return values;
|
||
},
|
||
|
||
set: function( elem, value ) {
|
||
var values = jQuery.makeArray( value );
|
||
|
||
jQuery(elem).find("option").each(function() {
|
||
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
|
||
});
|
||
|
||
if ( !values.length ) {
|
||
elem.selectedIndex = -1;
|
||
}
|
||
return values;
|
||
}
|
||
}
|
||
},
|
||
|
||
// Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
|
||
attrFn: {},
|
||
|
||
attr: function( elem, name, value, pass ) {
|
||
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;
|
||
}
|
||
|
||
if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
|
||
return jQuery( elem )[ name ]( value );
|
||
}
|
||
|
||
// Fallback to prop when attributes are not supported
|
||
if ( typeof elem.getAttribute === "undefined" ) {
|
||
return jQuery.prop( elem, name, value );
|
||
}
|
||
|
||
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
|
||
|
||
// All attributes are lowercase
|
||
// Grab necessary hook if one is defined
|
||
if ( notxml ) {
|
||
name = name.toLowerCase();
|
||
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
|
||
}
|
||
|
||
if ( value !== undefined ) {
|
||
|
||
if ( value === null ) {
|
||
jQuery.removeAttr( elem, name );
|
||
return;
|
||
|
||
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
|
||
return ret;
|
||
|
||
} else {
|
||
elem.setAttribute( name, value + "" );
|
||
return value;
|
||
}
|
||
|
||
} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
|
||
return ret;
|
||
|
||
} else {
|
||
|
||
ret = elem.getAttribute( name );
|
||
|
||
// Non-existent attributes return null, we normalize to undefined
|
||
return ret === null ?
|
||
undefined :
|
||
ret;
|
||
}
|
||
},
|
||
|
||
removeAttr: function( elem, value ) {
|
||
var propName, attrNames, name, isBool,
|
||
i = 0;
|
||
|
||
if ( value && elem.nodeType === 1 ) {
|
||
|
||
attrNames = value.split( core_rspace );
|
||
|
||
for ( ; i < attrNames.length; i++ ) {
|
||
name = attrNames[ i ];
|
||
|
||
if ( name ) {
|
||
propName = jQuery.propFix[ name ] || name;
|
||
isBool = rboolean.test( name );
|
||
|
||
// See #9699 for explanation of this approach (setting first, then removal)
|
||
// Do not do this for boolean attributes (see #10870)
|
||
if ( !isBool ) {
|
||
jQuery.attr( elem, name, "" );
|
||
}
|
||
elem.removeAttribute( getSetAttribute ? name : propName );
|
||
|
||
// Set corresponding property to false for boolean attributes
|
||
if ( isBool && propName in elem ) {
|
||
elem[ propName ] = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
attrHooks: {
|
||
type: {
|
||
set: function( elem, value ) {
|
||
// We can't allow the type property to be changed (since it causes problems in IE)
|
||
if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
|
||
jQuery.error( "type property can't be changed" );
|
||
} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
|
||
// Setting the type on a radio button after the value resets the value in IE6-9
|
||
// Reset value to it's default in case type is set after value
|
||
// This is for element creation
|
||
var val = elem.value;
|
||
elem.setAttribute( "type", value );
|
||
if ( val ) {
|
||
elem.value = val;
|
||
}
|
||
return value;
|
||
}
|
||
}
|
||
},
|
||
// Use the value property for back compat
|
||
// Use the nodeHook for button elements in IE6/7 (#1954)
|
||
value: {
|
||
get: function( elem, name ) {
|
||
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
|
||
return nodeHook.get( elem, name );
|
||
}
|
||
return name in elem ?
|
||
elem.value :
|
||
null;
|
||
},
|
||
set: function( elem, value, name ) {
|
||
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
|
||
return nodeHook.set( elem, value, name );
|
||
}
|
||
// Does not return so that setAttribute is also used
|
||
elem.value = value;
|
||
}
|
||
}
|
||
},
|
||
|
||
propFix: {
|
||
tabindex: "tabIndex",
|
||
readonly: "readOnly",
|
||
"for": "htmlFor",
|
||
"class": "className",
|
||
maxlength: "maxLength",
|
||
cellspacing: "cellSpacing",
|
||
cellpadding: "cellPadding",
|
||
rowspan: "rowSpan",
|
||
colspan: "colSpan",
|
||
usemap: "useMap",
|
||
frameborder: "frameBorder",
|
||
contenteditable: "contentEditable"
|
||
},
|
||
|
||
prop: function( elem, name, value ) {
|
||
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;
|
||
}
|
||
|
||
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
|
||
|
||
if ( notxml ) {
|
||
// Fix name and attach hooks
|
||
name = jQuery.propFix[ name ] || name;
|
||
hooks = jQuery.propHooks[ name ];
|
||
}
|
||
|
||
if ( value !== undefined ) {
|
||
if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
|
||
return ret;
|
||
|
||
} else {
|
||
return ( elem[ name ] = value );
|
||
}
|
||
|
||
} else {
|
||
if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
|
||
return ret;
|
||
|
||
} else {
|
||
return elem[ name ];
|
||
}
|
||
}
|
||
},
|
||
|
||
propHooks: {
|
||
tabIndex: {
|
||
get: function( elem ) {
|
||
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
|
||
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
|
||
var attributeNode = elem.getAttributeNode("tabindex");
|
||
|
||
return attributeNode && attributeNode.specified ?
|
||
parseInt( attributeNode.value, 10 ) :
|
||
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
|
||
0 :
|
||
undefined;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// 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,
|
||
property = jQuery.prop( elem, name );
|
||
return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
|
||
name.toLowerCase() :
|
||
undefined;
|
||
},
|
||
set: function( elem, value, name ) {
|
||
var propName;
|
||
if ( value === false ) {
|
||
// Remove boolean attributes when set to false
|
||
jQuery.removeAttr( elem, name );
|
||
} else {
|
||
// value is true since we know at this point it's type boolean and not false
|
||
// Set boolean attributes to the same name and set the DOM property
|
||
propName = jQuery.propFix[ name ] || name;
|
||
if ( propName in elem ) {
|
||
// Only set the IDL specifically if it already exists on the element
|
||
elem[ propName ] = true;
|
||
}
|
||
|
||
elem.setAttribute( name, name.toLowerCase() );
|
||
}
|
||
return name;
|
||
}
|
||
};
|
||
|
||
// IE6/7 do not support getting/setting some attributes with get/setAttribute
|
||
if ( !getSetAttribute ) {
|
||
|
||
fixSpecified = {
|
||
name: true,
|
||
id: true,
|
||
coords: 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 ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
|
||
ret.value :
|
||
undefined;
|
||
},
|
||
set: function( elem, value, name ) {
|
||
// Set the existing or create a new attribute node
|
||
var ret = elem.getAttributeNode( name );
|
||
if ( !ret ) {
|
||
ret = document.createAttribute( name );
|
||
elem.setAttributeNode( ret );
|
||
}
|
||
return ( ret.value = value + "" );
|
||
}
|
||
};
|
||
|
||
// 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 ) {
|
||
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
|
||
set: function( elem, value ) {
|
||
if ( value === "" ) {
|
||
elem.setAttribute( name, "auto" );
|
||
return value;
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
// 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 );
|
||
}
|
||
};
|
||
}
|
||
|
||
|
||
// Some attributes require a special call on IE
|
||
if ( !jQuery.support.hrefNormalized ) {
|
||
jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
|
||
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
|
||
get: function( elem ) {
|
||
var ret = elem.getAttribute( name, 2 );
|
||
return ret === null ? undefined : ret;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
if ( !jQuery.support.style ) {
|
||
jQuery.attrHooks.style = {
|
||
get: function( elem ) {
|
||
// Return undefined in the case of empty string
|
||
// Normalize to lowercase since IE uppercases css property names
|
||
return elem.style.cssText.toLowerCase() || undefined;
|
||
},
|
||
set: function( elem, value ) {
|
||
return ( elem.style.cssText = value + "" );
|
||
}
|
||
};
|
||
}
|
||
|
||
// Safari mis-reports the default selected property of an option
|
||
// Accessing the parent's selectedIndex property fixes it
|
||
if ( !jQuery.support.optSelected ) {
|
||
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
|
||
get: function( elem ) {
|
||
var parent = elem.parentNode;
|
||
|
||
if ( parent ) {
|
||
parent.selectedIndex;
|
||
|
||
// Make sure that it also works with optgroups, see #5701
|
||
if ( parent.parentNode ) {
|
||
parent.parentNode.selectedIndex;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
});
|
||
}
|
||
|
||
// 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() {
|
||
jQuery.valHooks[ this ] = {
|
||
get: function( elem ) {
|
||
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
|
||
return elem.getAttribute("value") === null ? "on" : elem.value;
|
||
}
|
||
};
|
||
});
|
||
}
|
||
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 );
|
||
}
|
||
}
|
||
});
|
||
});
|
||
var rformElems = /^(?:textarea|input|select)$/i,
|
||
rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
|
||
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
|
||
rkeyEvent = /^key/,
|
||
rmouseEvent = /^(?:mouse|contextmenu)|click/,
|
||
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
|
||
hoverHack = function( events ) {
|
||
return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
|
||
};
|
||
|
||
/*
|
||
* Helper functions for managing events -- not part of the public interface.
|
||
* Props to Dean Edwards' addEvent library for many of the ideas.
|
||
*/
|
||
jQuery.event = {
|
||
|
||
add: function( elem, types, handler, data, selector ) {
|
||
|
||
var elemData, eventHandle, events,
|
||
t, tns, type, namespaces, handleObj,
|
||
handleObjIn, handlers, special;
|
||
|
||
// 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;
|
||
}
|
||
|
||
// Caller can pass in an object of custom data in lieu of the handler
|
||
if ( handler.handler ) {
|
||
handleObjIn = handler;
|
||
handler = handleObjIn.handler;
|
||
selector = handleObjIn.selector;
|
||
}
|
||
|
||
// 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 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.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;
|
||
}
|
||
|
||
// Handle multiple events separated by a space
|
||
// jQuery(...).bind("mouseover mouseout", fn);
|
||
types = jQuery.trim( hoverHack(types) ).split( " " );
|
||
for ( t = 0; t < types.length; t++ ) {
|
||
|
||
tns = rtypenamespace.exec( types[t] ) || [];
|
||
type = tns[1];
|
||
namespaces = ( tns[2] || "" ).split( "." ).sort();
|
||
|
||
// If event changes its type, use the special event handlers for the changed type
|
||
special = jQuery.event.special[ type ] || {};
|
||
|
||
// If selector defined, determine special event api type, otherwise given type
|
||
type = ( selector ? special.delegateType : special.bindType ) || type;
|
||
|
||
// Update special based on newly reset type
|
||
special = jQuery.event.special[ type ] || {};
|
||
|
||
// handleObj is passed to all event handlers
|
||
handleObj = jQuery.extend({
|
||
type: type,
|
||
origType: tns[1],
|
||
data: data,
|
||
handler: handler,
|
||
guid: handler.guid,
|
||
selector: selector,
|
||
needsContext: selector && jQuery.expr.match.needsContext.test( 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;
|
||
|
||
// 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 ) {
|
||
elem.addEventListener( type, eventHandle, false );
|
||
|
||
} else if ( elem.attachEvent ) {
|
||
elem.attachEvent( "on" + type, eventHandle );
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( special.add ) {
|
||
special.add.call( elem, handleObj );
|
||
|
||
if ( !handleObj.handler.guid ) {
|
||
handleObj.handler.guid = handler.guid;
|
||
}
|
||
}
|
||
|
||
// 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 ever been used, for event optimization
|
||
jQuery.event.global[ type ] = true;
|
||
}
|
||
|
||
// Nullify elem to prevent memory leaks in IE
|
||
elem = null;
|
||
},
|
||
|
||
global: {},
|
||
|
||
// Detach an event or set of events from an element
|
||
remove: function( elem, types, handler, selector, mappedTypes ) {
|
||
|
||
var t, tns, type, origType, namespaces, origCount,
|
||
j, events, special, eventType, handleObj,
|
||
elemData = jQuery.hasData( elem ) && jQuery._data( elem );
|
||
|
||
if ( !elemData || !(events = elemData.events) ) {
|
||
return;
|
||
}
|
||
|
||
// 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];
|
||
|
||
// 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;
|
||
|
||
// Remove matching events
|
||
for ( j = 0; j < eventType.length; j++ ) {
|
||
handleObj = eventType[ j ];
|
||
|
||
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 ( handleObj.selector ) {
|
||
eventType.delegateCount--;
|
||
}
|
||
if ( special.remove ) {
|
||
special.remove.call( elem, handleObj );
|
||
}
|
||
}
|
||
}
|
||
|
||
// 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, elemData.handle ) === false ) {
|
||
jQuery.removeEvent( elem, type, elemData.handle );
|
||
}
|
||
|
||
delete events[ type ];
|
||
}
|
||
}
|
||
|
||
// Remove the expando if it's no longer used
|
||
if ( jQuery.isEmptyObject( events ) ) {
|
||
delete elemData.handle;
|
||
|
||
// removeData also checks for emptiness and clears the expando if empty
|
||
// so use it instead of delete
|
||
jQuery.removeData( elem, "events", 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: {
|
||
"getData": true,
|
||
"setData": true,
|
||
"changeData": true
|
||
},
|
||
|
||
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 cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
|
||
type = event.type || event,
|
||
namespaces = [];
|
||
|
||
// 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 ) {
|
||
// Exclusive events trigger only for the exact event (no namespaces)
|
||
type = type.slice(0, -1);
|
||
exclusive = true;
|
||
}
|
||
|
||
if ( type.indexOf( "." ) >= 0 ) {
|
||
// Namespaced trigger; create a regexp to match event type in handle()
|
||
namespaces = type.split(".");
|
||
type = namespaces.shift();
|
||
namespaces.sort();
|
||
}
|
||
|
||
if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
|
||
// No jQuery handlers for this event type, and it can't have inline handlers
|
||
return;
|
||
}
|
||
|
||
// Caller can pass in an Event, Object, or just an event type string
|
||
event = typeof event === "object" ?
|
||
// jQuery.Event object
|
||
event[ jQuery.expando ] ? event :
|
||
// Object literal
|
||
new jQuery.Event( type, event ) :
|
||
// Just the event type (string)
|
||
new jQuery.Event( type );
|
||
|
||
event.type = type;
|
||
event.isTrigger = true;
|
||
event.exclusive = exclusive;
|
||
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
|
||
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;
|
||
}
|
||
|
||
// Clean up the event in case it is being reused
|
||
event.result = undefined;
|
||
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 );
|
||
|
||
// 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 ) ) {
|
||
|
||
bubbleType = special.delegateType || type;
|
||
cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
|
||
for ( old = elem; cur; cur = cur.parentNode ) {
|
||
eventPath.push([ cur, bubbleType ]);
|
||
old = cur;
|
||
}
|
||
|
||
// Only add window if we got to document (e.g., not plain obj or detached DOM)
|
||
if ( old === (elem.ownerDocument || document) ) {
|
||
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 );
|
||
}
|
||
// Note that this is a bare JS function and not a jQuery handler
|
||
handle = ontype && cur[ ontype ];
|
||
if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
|
||
event.preventDefault();
|
||
}
|
||
}
|
||
event.type = type;
|
||
|
||
// If nobody prevented the default action, do it now
|
||
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
|
||
|
||
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.
|
||
// 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 ) ) {
|
||
|
||
// Don't re-trigger an onFOO event when we call its FOO() method
|
||
old = elem[ ontype ];
|
||
|
||
if ( old ) {
|
||
elem[ ontype ] = null;
|
||
}
|
||
|
||
// Prevent re-triggering of the same event, since we already bubbled it above
|
||
jQuery.event.triggered = type;
|
||
elem[ type ]();
|
||
jQuery.event.triggered = undefined;
|
||
|
||
if ( old ) {
|
||
elem[ ontype ] = old;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return event.result;
|
||
},
|
||
|
||
dispatch: function( event ) {
|
||
|
||
// Make a writable jQuery.Event from the native event object
|
||
event = jQuery.event.fix( event || window.event );
|
||
|
||
var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
|
||
handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
|
||
delegateCount = handlers.delegateCount,
|
||
args = core_slice.call( arguments ),
|
||
run_all = !event.exclusive && !event.namespace,
|
||
special = jQuery.event.special[ event.type ] || {},
|
||
handlerQueue = [];
|
||
|
||
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
||
args[0] = event;
|
||
event.delegateTarget = this;
|
||
|
||
// Call the preDispatch hook for the mapped type, and let it bail if desired
|
||
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
|
||
return;
|
||
}
|
||
|
||
// Determine handlers that should run if there are delegated events
|
||
// Avoid non-left-click bubbling in Firefox (#3861)
|
||
if ( delegateCount && !(event.button && event.type === "click") ) {
|
||
|
||
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
|
||
|
||
// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
|
||
if ( cur.disabled !== true || event.type !== "click" ) {
|
||
selMatch = {};
|
||
matches = [];
|
||
for ( i = 0; i < delegateCount; i++ ) {
|
||
handleObj = handlers[ i ];
|
||
sel = handleObj.selector;
|
||
|
||
if ( selMatch[ sel ] === undefined ) {
|
||
selMatch[ sel ] = handleObj.needsContext ?
|
||
jQuery( sel, this ).index( cur ) >= 0 :
|
||
jQuery.find( sel, this, null, [ cur ] ).length;
|
||
}
|
||
if ( selMatch[ sel ] ) {
|
||
matches.push( handleObj );
|
||
}
|
||
}
|
||
if ( matches.length ) {
|
||
handlerQueue.push({ elem: cur, matches: matches });
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 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();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Call the postDispatch hook for the mapped type
|
||
if ( special.postDispatch ) {
|
||
special.postDispatch.call( this, event );
|
||
}
|
||
|
||
return event.result;
|
||
},
|
||
|
||
// 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;
|
||
}
|
||
|
||
// 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 ( i = copy.length; i; ) {
|
||
prop = copy[ --i ];
|
||
event[ prop ] = originalEvent[ prop ];
|
||
}
|
||
|
||
// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
|
||
if ( !event.target ) {
|
||
event.target = originalEvent.srcElement || document;
|
||
}
|
||
|
||
// Target should not be a text node (#504, Safari)
|
||
if ( event.target.nodeType === 3 ) {
|
||
event.target = event.target.parentNode;
|
||
}
|
||
|
||
// For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
|
||
event.metaKey = !!event.metaKey;
|
||
|
||
return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
|
||
},
|
||
|
||
special: {
|
||
load: {
|
||
// Prevent triggered image.load events from bubbling to window.load
|
||
noBubble: true
|
||
},
|
||
|
||
focus: {
|
||
delegateType: "focusin"
|
||
},
|
||
blur: {
|
||
delegateType: "focusout"
|
||
},
|
||
|
||
beforeunload: {
|
||
setup: function( data, namespaces, eventHandle ) {
|
||
// We only want to do this special case on windows
|
||
if ( jQuery.isWindow( this ) ) {
|
||
this.onbeforeunload = eventHandle;
|
||
}
|
||
},
|
||
|
||
teardown: function( namespaces, eventHandle ) {
|
||
if ( this.onbeforeunload === eventHandle ) {
|
||
this.onbeforeunload = null;
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
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 ) {
|
||
elem.removeEventListener( type, handle, false );
|
||
}
|
||
} :
|
||
function( elem, type, handle ) {
|
||
var name = "on" + type;
|
||
|
||
if ( elem.detachEvent ) {
|
||
|
||
// #8545, #7054, preventing memory leaks for custom events in IE6-8
|
||
// detachEvent needed property on element, by name of that event, to properly expose it to GC
|
||
if ( typeof elem[ name ] === "undefined" ) {
|
||
elem[ name ] = null;
|
||
}
|
||
|
||
elem.detachEvent( name, handle );
|
||
}
|
||
};
|
||
|
||
jQuery.Event = function( src, props ) {
|
||
// Allow instantiation without the 'new' keyword
|
||
if ( !(this instanceof jQuery.Event) ) {
|
||
return new jQuery.Event( src, props );
|
||
}
|
||
|
||
// Event object
|
||
if ( src && src.type ) {
|
||
this.originalEvent = src;
|
||
this.type = src.type;
|
||
|
||
// 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;
|
||
|
||
// Event type
|
||
} else {
|
||
this.type = src;
|
||
}
|
||
|
||
// Put explicitly provided properties onto the event object
|
||
if ( props ) {
|
||
jQuery.extend( this, props );
|
||
}
|
||
|
||
// 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;
|
||
};
|
||
|
||
function returnFalse() {
|
||
return false;
|
||
}
|
||
function returnTrue() {
|
||
return true;
|
||
}
|
||
|
||
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
|
||
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
||
jQuery.Event.prototype = {
|
||
preventDefault: function() {
|
||
this.isDefaultPrevented = returnTrue;
|
||
|
||
var e = this.originalEvent;
|
||
if ( !e ) {
|
||
return;
|
||
}
|
||
|
||
// if preventDefault exists run it on the original event
|
||
if ( e.preventDefault ) {
|
||
e.preventDefault();
|
||
|
||
// otherwise set the returnValue property of the original event to false (IE)
|
||
} else {
|
||
e.returnValue = false;
|
||
}
|
||
},
|
||
stopPropagation: function() {
|
||
this.isPropagationStopped = returnTrue;
|
||
|
||
var e = this.originalEvent;
|
||
if ( !e ) {
|
||
return;
|
||
}
|
||
// if stopPropagation exists run it on the original event
|
||
if ( e.stopPropagation ) {
|
||
e.stopPropagation();
|
||
}
|
||
// otherwise set the cancelBubble property of the original event to true (IE)
|
||
e.cancelBubble = true;
|
||
},
|
||
stopImmediatePropagation: function() {
|
||
this.isImmediatePropagationStopped = returnTrue;
|
||
this.stopPropagation();
|
||
},
|
||
isDefaultPrevented: returnFalse,
|
||
isPropagationStopped: returnFalse,
|
||
isImmediatePropagationStopped: returnFalse
|
||
};
|
||
|
||
// Create mouseenter/leave events using mouseover/out and event-time checks
|
||
jQuery.each({
|
||
mouseenter: "mouseover",
|
||
mouseleave: "mouseout"
|
||
}, function( orig, fix ) {
|
||
jQuery.event.special[ orig ] = {
|
||
delegateType: fix,
|
||
bindType: fix,
|
||
|
||
handle: function( event ) {
|
||
var ret,
|
||
target = this,
|
||
related = event.relatedTarget,
|
||
handleObj = event.handleObj,
|
||
selector = handleObj.selector;
|
||
|
||
// 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;
|
||
}
|
||
};
|
||
});
|
||
|
||
// IE submit delegation
|
||
if ( !jQuery.support.submitBubbles ) {
|
||
|
||
jQuery.event.special.submit = {
|
||
setup: function() {
|
||
// Only need this for delegated form submit events
|
||
if ( jQuery.nodeName( this, "form" ) ) {
|
||
return false;
|
||
}
|
||
|
||
// 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 && !jQuery._data( form, "_submit_attached" ) ) {
|
||
jQuery.event.add( form, "submit._submit", function( event ) {
|
||
event._submit_bubble = true;
|
||
});
|
||
jQuery._data( form, "_submit_attached", true );
|
||
}
|
||
});
|
||
// return undefined since we don't need an event listener
|
||
},
|
||
|
||
postDispatch: function( event ) {
|
||
// If form was submitted by the user, bubble the event up the tree
|
||
if ( event._submit_bubble ) {
|
||
delete event._submit_bubble;
|
||
if ( this.parentNode && !event.isTrigger ) {
|
||
jQuery.event.simulate( "submit", this.parentNode, event, true );
|
||
}
|
||
}
|
||
},
|
||
|
||
teardown: function() {
|
||
// Only need this for delegated form submit events
|
||
if ( jQuery.nodeName( this, "form" ) ) {
|
||
return false;
|
||
}
|
||
|
||
// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
|
||
jQuery.event.remove( this, "._submit" );
|
||
}
|
||
};
|
||
}
|
||
|
||
// IE change delegation and checkbox/radio fix
|
||
if ( !jQuery.support.changeBubbles ) {
|
||
|
||
jQuery.event.special.change = {
|
||
|
||
setup: function() {
|
||
|
||
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;
|
||
}
|
||
// Allow triggered, simulated change events (#11500)
|
||
jQuery.event.simulate( "change", this, event, true );
|
||
});
|
||
}
|
||
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 ( rformElems.test( elem.nodeName ) && !jQuery._data( 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 );
|
||
}
|
||
});
|
||
jQuery._data( elem, "_change_attached", true );
|
||
}
|
||
});
|
||
},
|
||
|
||
handle: function( event ) {
|
||
var elem = event.target;
|
||
|
||
// 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 );
|
||
}
|
||
},
|
||
|
||
teardown: function() {
|
||
jQuery.event.remove( this, "._change" );
|
||
|
||
return !rformElems.test( this.nodeName );
|
||
}
|
||
};
|
||
}
|
||
|
||
// Create "bubbling" focus and blur events
|
||
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,
|
||
handler = function( event ) {
|
||
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
|
||
};
|
||
|
||
jQuery.event.special[ fix ] = {
|
||
setup: function() {
|
||
if ( attaches++ === 0 ) {
|
||
document.addEventListener( orig, handler, true );
|
||
}
|
||
},
|
||
teardown: function() {
|
||
if ( --attaches === 0 ) {
|
||
document.removeEventListener( orig, handler, true );
|
||
}
|
||
}
|
||
};
|
||
});
|
||
}
|
||
|
||
jQuery.fn.extend({
|
||
|
||
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" ) { // && selector != null
|
||
// ( types-Object, data )
|
||
data = data || selector;
|
||
selector = undefined;
|
||
}
|
||
for ( type in types ) {
|
||
this.on( type, selector, data, types[ type ], one );
|
||
}
|
||
return this;
|
||
}
|
||
|
||
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 ( 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 );
|
||
};
|
||
// Use same guid so caller can remove using origFn
|
||
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
|
||
}
|
||
return this.each( function() {
|
||
jQuery.event.add( this, types, fn, data, selector );
|
||
});
|
||
},
|
||
one: function( types, selector, data, fn ) {
|
||
return this.on( types, selector, data, fn, 1 );
|
||
},
|
||
off: function( types, selector, fn ) {
|
||
var handleObj, type;
|
||
if ( types && types.preventDefault && types.handleObj ) {
|
||
// ( event ) dispatched jQuery.Event
|
||
handleObj = types.handleObj;
|
||
jQuery( types.delegateTarget ).off(
|
||
handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
|
||
handleObj.selector,
|
||
handleObj.handler
|
||
);
|
||
return this;
|
||
}
|
||
if ( typeof types === "object" ) {
|
||
// ( types-object [, selector] )
|
||
for ( 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.on( types, selector, data, fn );
|
||
},
|
||
undelegate: function( selector, types, fn ) {
|
||
// ( namespace ) or ( selector, types [, fn] )
|
||
return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
|
||
},
|
||
|
||
trigger: function( type, data ) {
|
||
return this.each(function() {
|
||
jQuery.event.trigger( type, data, this );
|
||
});
|
||
},
|
||
triggerHandler: function( type, data ) {
|
||
if ( this[0] ) {
|
||
return jQuery.event.trigger( type, data, this[0], true );
|
||
}
|
||
},
|
||
|
||
toggle: function( fn ) {
|
||
// Save reference to arguments for access in closure
|
||
var args = arguments,
|
||
guid = fn.guid || jQuery.guid++,
|
||
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 );
|
||
|
||
// Make sure that clicks stop
|
||
event.preventDefault();
|
||
|
||
// and execute the function
|
||
return args[ lastToggle ].apply( this, arguments ) || false;
|
||
};
|
||
|
||
// link all the functions, so any of them can unbind this click handler
|
||
toggler.guid = guid;
|
||
while ( i < args.length ) {
|
||
args[ i++ ].guid = guid;
|
||
}
|
||
|
||
return this.click( toggler );
|
||
},
|
||
|
||
hover: function( fnOver, fnOut ) {
|
||
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
|
||
}
|
||
});
|
||
|
||
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 contextmenu").split(" "), function( i, name ) {
|
||
|
||
// Handle event binding
|
||
jQuery.fn[ name ] = function( data, fn ) {
|
||
if ( fn == null ) {
|
||
fn = data;
|
||
data = null;
|
||
}
|
||
|
||
return arguments.length > 0 ?
|
||
this.on( name, null, data, fn ) :
|
||
this.trigger( name );
|
||
};
|
||
|
||
if ( rkeyEvent.test( name ) ) {
|
||
jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
|
||
}
|
||
|
||
if ( rmouseEvent.test( name ) ) {
|
||
jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
|
||
}
|
||
});
|
||
/*!
|
||
* Sizzle CSS Selector Engine
|
||
* Copyright 2012 jQuery Foundation and other contributors
|
||
* Released under the MIT license
|
||
* http://sizzlejs.com/
|
||
*/
|
||
(function( window, undefined ) {
|
||
|
||
var cachedruns,
|
||
assertGetIdNotName,
|
||
Expr,
|
||
getText,
|
||
isXML,
|
||
contains,
|
||
compile,
|
||
sortOrder,
|
||
hasDuplicate,
|
||
outermostContext,
|
||
|
||
baseHasDuplicate = true,
|
||
strundefined = "undefined",
|
||
|
||
expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
|
||
|
||
Token = String,
|
||
document = window.document,
|
||
docElem = document.documentElement,
|
||
dirruns = 0,
|
||
done = 0,
|
||
pop = [].pop,
|
||
push = [].push,
|
||
slice = [].slice,
|
||
// Use a stripped-down indexOf if a native one is unavailable
|
||
indexOf = [].indexOf || function( elem ) {
|
||
var i = 0,
|
||
len = this.length;
|
||
for ( ; i < len; i++ ) {
|
||
if ( this[i] === elem ) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
},
|
||
|
||
// Augment a function for special use by Sizzle
|
||
markFunction = function( fn, value ) {
|
||
fn[ expando ] = value == null || value;
|
||
return fn;
|
||
},
|
||
|
||
createCache = function() {
|
||
var cache = {},
|
||
keys = [];
|
||
|
||
return markFunction(function( key, value ) {
|
||
// Only keep the most recent entries
|
||
if ( keys.push( key ) > Expr.cacheLength ) {
|
||
delete cache[ keys.shift() ];
|
||
}
|
||
|
||
// Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157)
|
||
return (cache[ key + " " ] = value);
|
||
}, cache );
|
||
},
|
||
|
||
classCache = createCache(),
|
||
tokenCache = createCache(),
|
||
compilerCache = createCache(),
|
||
|
||
// Regex
|
||
|
||
// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
|
||
whitespace = "[\\x20\\t\\r\\n\\f]",
|
||
// http://www.w3.org/TR/css3-syntax/#characters
|
||
characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
|
||
|
||
// Loosely modeled on CSS identifier characters
|
||
// An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
|
||
// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
|
||
identifier = characterEncoding.replace( "w", "w#" ),
|
||
|
||
// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
|
||
operators = "([*^$|!~]?=)",
|
||
attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
|
||
"*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
|
||
|
||
// Prefer arguments not in parens/brackets,
|
||
// then attribute selectors and non-pseudos (denoted by :),
|
||
// then anything else
|
||
// These preferences are here to reduce the number of selectors
|
||
// needing tokenize in the PSEUDO preFilter
|
||
pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",
|
||
|
||
// For matchExpr.POS and matchExpr.needsContext
|
||
pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
|
||
"*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",
|
||
|
||
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
|
||
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
|
||
|
||
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
|
||
rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
|
||
rpseudo = new RegExp( pseudos ),
|
||
|
||
// Easily-parseable/retrievable ID or TAG or CLASS selectors
|
||
rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
|
||
|
||
rnot = /^:not/,
|
||
rsibling = /[\x20\t\r\n\f]*[+~]/,
|
||
rendsWithNot = /:not\($/,
|
||
|
||
rheader = /h\d/i,
|
||
rinputs = /input|select|textarea|button/i,
|
||
|
||
rbackslash = /\\(?!\\)/g,
|
||
|
||
matchExpr = {
|
||
"ID": new RegExp( "^#(" + characterEncoding + ")" ),
|
||
"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
|
||
"NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
|
||
"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
|
||
"ATTR": new RegExp( "^" + attributes ),
|
||
"PSEUDO": new RegExp( "^" + pseudos ),
|
||
"POS": new RegExp( pos, "i" ),
|
||
"CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace +
|
||
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
|
||
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
|
||
// For use in libraries implementing .is()
|
||
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
|
||
},
|
||
|
||
// Support
|
||
|
||
// Used for testing something on an element
|
||
assert = function( fn ) {
|
||
var div = document.createElement("div");
|
||
|
||
try {
|
||
return fn( div );
|
||
} catch (e) {
|
||
return false;
|
||
} finally {
|
||
// release memory in IE
|
||
div = null;
|
||
}
|
||
},
|
||
|
||
// Check if getElementsByTagName("*") returns only elements
|
||
assertTagNameNoComments = assert(function( div ) {
|
||
div.appendChild( document.createComment("") );
|
||
return !div.getElementsByTagName("*").length;
|
||
}),
|
||
|
||
// Check if getAttribute returns normalized href attributes
|
||
assertHrefNotNormalized = assert(function( div ) {
|
||
div.innerHTML = "<a href='#'></a>";
|
||
return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
|
||
div.firstChild.getAttribute("href") === "#";
|
||
}),
|
||
|
||
// Check if attributes should be retrieved by attribute nodes
|
||
assertAttributes = assert(function( div ) {
|
||
div.innerHTML = "<select></select>";
|
||
var type = typeof div.lastChild.getAttribute("multiple");
|
||
// IE8 returns a string for some attributes even when not present
|
||
return type !== "boolean" && type !== "string";
|
||
}),
|
||
|
||
// Check if getElementsByClassName can be trusted
|
||
assertUsableClassName = assert(function( div ) {
|
||
// Opera can't find a second classname (in 9.6)
|
||
div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
|
||
if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
|
||
return false;
|
||
}
|
||
|
||
// Safari 3.2 caches class attributes and doesn't catch changes
|
||
div.lastChild.className = "e";
|
||
return div.getElementsByClassName("e").length === 2;
|
||
}),
|
||
|
||
// Check if getElementById returns elements by name
|
||
// Check if getElementsByName privileges form controls or returns elements by ID
|
||
assertUsableName = assert(function( div ) {
|
||
// Inject content
|
||
div.id = expando + 0;
|
||
div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
|
||
docElem.insertBefore( div, docElem.firstChild );
|
||
|
||
// Test
|
||
var pass = document.getElementsByName &&
|
||
// buggy browsers will return fewer than the correct 2
|
||
document.getElementsByName( expando ).length === 2 +
|
||
// buggy browsers will return more than the correct 0
|
||
document.getElementsByName( expando + 0 ).length;
|
||
assertGetIdNotName = !document.getElementById( expando );
|
||
|
||
// Cleanup
|
||
docElem.removeChild( div );
|
||
|
||
return pass;
|
||
});
|
||
|
||
// If slice is not available, provide a backup
|
||
try {
|
||
slice.call( docElem.childNodes, 0 )[0].nodeType;
|
||
} catch ( e ) {
|
||
slice = function( i ) {
|
||
var elem,
|
||
results = [];
|
||
for ( ; (elem = this[i]); i++ ) {
|
||
results.push( elem );
|
||
}
|
||
return results;
|
||
};
|
||
}
|
||
|
||
function Sizzle( selector, context, results, seed ) {
|
||
results = results || [];
|
||
context = context || document;
|
||
var match, elem, xml, m,
|
||
nodeType = context.nodeType;
|
||
|
||
if ( !selector || typeof selector !== "string" ) {
|
||
return results;
|
||
}
|
||
|
||
if ( nodeType !== 1 && nodeType !== 9 ) {
|
||
return [];
|
||
}
|
||
|
||
xml = isXML( context );
|
||
|
||
if ( !xml && !seed ) {
|
||
if ( (match = rquickExpr.exec( selector )) ) {
|
||
// Speed-up: Sizzle("#ID")
|
||
if ( (m = match[1]) ) {
|
||
if ( nodeType === 9 ) {
|
||
elem = context.getElementById( m );
|
||
// Check parentNode to catch when Blackberry 4.6 returns
|
||
// nodes that are no longer in the document #6963
|
||
if ( elem && elem.parentNode ) {
|
||
// Handle the case where IE, Opera, and Webkit return items
|
||
// by name instead of ID
|
||
if ( elem.id === m ) {
|
||
results.push( elem );
|
||
return results;
|
||
}
|
||
} else {
|
||
return results;
|
||
}
|
||
} else {
|
||
// Context is not a document
|
||
if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
|
||
contains( context, elem ) && elem.id === m ) {
|
||
results.push( elem );
|
||
return results;
|
||
}
|
||
}
|
||
|
||
// Speed-up: Sizzle("TAG")
|
||
} else if ( match[2] ) {
|
||
push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
|
||
return results;
|
||
|
||
// Speed-up: Sizzle(".CLASS")
|
||
} else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
|
||
push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
|
||
return results;
|
||
}
|
||
}
|
||
}
|
||
|
||
// All others
|
||
return select( selector.replace( rtrim, "$1" ), context, results, seed, xml );
|
||
}
|
||
|
||
Sizzle.matches = function( expr, elements ) {
|
||
return Sizzle( expr, null, null, elements );
|
||
};
|
||
|
||
Sizzle.matchesSelector = function( elem, expr ) {
|
||
return Sizzle( expr, null, null, [ elem ] ).length > 0;
|
||
};
|
||
|
||
// Returns a function to use in pseudos for input types
|
||
function createInputPseudo( type ) {
|
||
return function( elem ) {
|
||
var name = elem.nodeName.toLowerCase();
|
||
return name === "input" && elem.type === type;
|
||
};
|
||
}
|
||
|
||
// Returns a function to use in pseudos for buttons
|
||
function createButtonPseudo( type ) {
|
||
return function( elem ) {
|
||
var name = elem.nodeName.toLowerCase();
|
||
return (name === "input" || name === "button") && elem.type === type;
|
||
};
|
||
}
|
||
|
||
// Returns a function to use in pseudos for positionals
|
||
function createPositionalPseudo( fn ) {
|
||
return markFunction(function( argument ) {
|
||
argument = +argument;
|
||
return markFunction(function( seed, matches ) {
|
||
var j,
|
||
matchIndexes = fn( [], seed.length, argument ),
|
||
i = matchIndexes.length;
|
||
|
||
// Match elements found at the specified indexes
|
||
while ( i-- ) {
|
||
if ( seed[ (j = matchIndexes[i]) ] ) {
|
||
seed[j] = !(matches[j] = seed[j]);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Utility function for retrieving the text value of an array of DOM nodes
|
||
* @param {Array|Element} elem
|
||
*/
|
||
getText = Sizzle.getText = function( elem ) {
|
||
var node,
|
||
ret = "",
|
||
i = 0,
|
||
nodeType = elem.nodeType;
|
||
|
||
if ( nodeType ) {
|
||
if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
|
||
// Use textContent for elements
|
||
// innerText usage removed for consistency of new lines (see #11153)
|
||
if ( typeof elem.textContent === "string" ) {
|
||
return elem.textContent;
|
||
} else {
|
||
// Traverse its children
|
||
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
||
ret += getText( elem );
|
||
}
|
||
}
|
||
} else if ( nodeType === 3 || nodeType === 4 ) {
|
||
return elem.nodeValue;
|
||
}
|
||
// Do not include comment or processing instruction nodes
|
||
} else {
|
||
|
||
// If no nodeType, this is expected to be an array
|
||
for ( ; (node = elem[i]); i++ ) {
|
||
// Do not traverse comment nodes
|
||
ret += getText( node );
|
||
}
|
||
}
|
||
return ret;
|
||
};
|
||
|
||
isXML = Sizzle.isXML = function( elem ) {
|
||
// documentElement is verified for cases where it doesn't yet exist
|
||
// (such as loading iframes in IE - #4833)
|
||
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
|
||
return documentElement ? documentElement.nodeName !== "HTML" : false;
|
||
};
|
||
|
||
// Element contains another
|
||
contains = Sizzle.contains = docElem.contains ?
|
||
function( a, b ) {
|
||
var adown = a.nodeType === 9 ? a.documentElement : a,
|
||
bup = b && b.parentNode;
|
||
return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
|
||
} :
|
||
docElem.compareDocumentPosition ?
|
||
function( a, b ) {
|
||
return b && !!( a.compareDocumentPosition( b ) & 16 );
|
||
} :
|
||
function( a, b ) {
|
||
while ( (b = b.parentNode) ) {
|
||
if ( b === a ) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
Sizzle.attr = function( elem, name ) {
|
||
var val,
|
||
xml = isXML( elem );
|
||
|
||
if ( !xml ) {
|
||
name = name.toLowerCase();
|
||
}
|
||
if ( (val = Expr.attrHandle[ name ]) ) {
|
||
return val( elem );
|
||
}
|
||
if ( xml || assertAttributes ) {
|
||
return elem.getAttribute( name );
|
||
}
|
||
val = elem.getAttributeNode( name );
|
||
return val ?
|
||
typeof elem[ name ] === "boolean" ?
|
||
elem[ name ] ? name : null :
|
||
val.specified ? val.value : null :
|
||
null;
|
||
};
|
||
|
||
Expr = Sizzle.selectors = {
|
||
|
||
// Can be adjusted by the user
|
||
cacheLength: 50,
|
||
|
||
createPseudo: markFunction,
|
||
|
||
match: matchExpr,
|
||
|
||
// IE6/7 return a modified href
|
||
attrHandle: assertHrefNotNormalized ?
|
||
{} :
|
||
{
|
||
"href": function( elem ) {
|
||
return elem.getAttribute( "href", 2 );
|
||
},
|
||
"type": function( elem ) {
|
||
return elem.getAttribute("type");
|
||
}
|
||
},
|
||
|
||
find: {
|
||
"ID": assertGetIdNotName ?
|
||
function( id, context, xml ) {
|
||
if ( typeof context.getElementById !== strundefined && !xml ) {
|
||
var m = context.getElementById( id );
|
||
// Check parentNode to catch when Blackberry 4.6 returns
|
||
// nodes that are no longer in the document #6963
|
||
return m && m.parentNode ? [m] : [];
|
||
}
|
||
} :
|
||
function( id, context, xml ) {
|
||
if ( typeof context.getElementById !== strundefined && !xml ) {
|
||
var m = context.getElementById( id );
|
||
|
||
return m ?
|
||
m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
|
||
[m] :
|
||
undefined :
|
||
[];
|
||
}
|
||
},
|
||
|
||
"TAG": assertTagNameNoComments ?
|
||
function( tag, context ) {
|
||
if ( typeof context.getElementsByTagName !== strundefined ) {
|
||
return context.getElementsByTagName( tag );
|
||
}
|
||
} :
|
||
function( tag, context ) {
|
||
var results = context.getElementsByTagName( tag );
|
||
|
||
// Filter out possible comments
|
||
if ( tag === "*" ) {
|
||
var elem,
|
||
tmp = [],
|
||
i = 0;
|
||
|
||
for ( ; (elem = results[i]); i++ ) {
|
||
if ( elem.nodeType === 1 ) {
|
||
tmp.push( elem );
|
||
}
|
||
}
|
||
|
||
return tmp;
|
||
}
|
||
return results;
|
||
},
|
||
|
||
"NAME": assertUsableName && function( tag, context ) {
|
||
if ( typeof context.getElementsByName !== strundefined ) {
|
||
return context.getElementsByName( name );
|
||
}
|
||
},
|
||
|
||
"CLASS": assertUsableClassName && function( className, context, xml ) {
|
||
if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
|
||
return context.getElementsByClassName( className );
|
||
}
|
||
}
|
||
},
|
||
|
||
relative: {
|
||
">": { dir: "parentNode", first: true },
|
||
" ": { dir: "parentNode" },
|
||
"+": { dir: "previousSibling", first: true },
|
||
"~": { dir: "previousSibling" }
|
||
},
|
||
|
||
preFilter: {
|
||
"ATTR": function( match ) {
|
||
match[1] = match[1].replace( rbackslash, "" );
|
||
|
||
// Move the given value to match[3] whether quoted or unquoted
|
||
match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
|
||
|
||
if ( match[2] === "~=" ) {
|
||
match[3] = " " + match[3] + " ";
|
||
}
|
||
|
||
return match.slice( 0, 4 );
|
||
},
|
||
|
||
"CHILD": function( match ) {
|
||
/* matches from matchExpr["CHILD"]
|
||
1 type (only|nth|...)
|
||
2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
|
||
3 xn-component of xn+y argument ([+-]?\d*n|)
|
||
4 sign of xn-component
|
||
5 x of xn-component
|
||
6 sign of y-component
|
||
7 y of y-component
|
||
*/
|
||
match[1] = match[1].toLowerCase();
|
||
|
||
if ( match[1] === "nth" ) {
|
||
// nth-child requires argument
|
||
if ( !match[2] ) {
|
||
Sizzle.error( match[0] );
|
||
}
|
||
|
||
// numeric x and y parameters for Expr.filter.CHILD
|
||
// remember that false/true cast respectively to 0/1
|
||
match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
|
||
match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
|
||
|
||
// other types prohibit arguments
|
||
} else if ( match[2] ) {
|
||
Sizzle.error( match[0] );
|
||
}
|
||
|
||
return match;
|
||
},
|
||
|
||
"PSEUDO": function( match ) {
|
||
var unquoted, excess;
|
||
if ( matchExpr["CHILD"].test( match[0] ) ) {
|
||
return null;
|
||
}
|
||
|
||
if ( match[3] ) {
|
||
match[2] = match[3];
|
||
} else if ( (unquoted = match[4]) ) {
|
||
// Only check arguments that contain a pseudo
|
||
if ( rpseudo.test(unquoted) &&
|
||
// Get excess from tokenize (recursively)
|
||
(excess = tokenize( unquoted, true )) &&
|
||
// advance to the next closing parenthesis
|
||
(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
|
||
|
||
// excess is a negative index
|
||
unquoted = unquoted.slice( 0, excess );
|
||
match[0] = match[0].slice( 0, excess );
|
||
}
|
||
match[2] = unquoted;
|
||
}
|
||
|
||
// Return only captures needed by the pseudo filter method (type and argument)
|
||
return match.slice( 0, 3 );
|
||
}
|
||
},
|
||
|
||
filter: {
|
||
"ID": assertGetIdNotName ?
|
||
function( id ) {
|
||
id = id.replace( rbackslash, "" );
|
||
return function( elem ) {
|
||
return elem.getAttribute("id") === id;
|
||
};
|
||
} :
|
||
function( id ) {
|
||
id = id.replace( rbackslash, "" );
|
||
return function( elem ) {
|
||
var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
|
||
return node && node.value === id;
|
||
};
|
||
},
|
||
|
||
"TAG": function( nodeName ) {
|
||
if ( nodeName === "*" ) {
|
||
return function() { return true; };
|
||
}
|
||
nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
|
||
|
||
return function( elem ) {
|
||
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
|
||
};
|
||
},
|
||
|
||
"CLASS": function( className ) {
|
||
var pattern = classCache[ expando ][ className + " " ];
|
||
|
||
return pattern ||
|
||
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
|
||
classCache( className, function( elem ) {
|
||
return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
|
||
});
|
||
},
|
||
|
||
"ATTR": function( name, operator, check ) {
|
||
return function( elem, context ) {
|
||
var result = Sizzle.attr( elem, name );
|
||
|
||
if ( result == null ) {
|
||
return operator === "!=";
|
||
}
|
||
if ( !operator ) {
|
||
return true;
|
||
}
|
||
|
||
result += "";
|
||
|
||
return operator === "=" ? result === check :
|
||
operator === "!=" ? result !== check :
|
||
operator === "^=" ? check && result.indexOf( check ) === 0 :
|
||
operator === "*=" ? check && result.indexOf( check ) > -1 :
|
||
operator === "$=" ? check && result.substr( result.length - check.length ) === check :
|
||
operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
|
||
operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
|
||
false;
|
||
};
|
||
},
|
||
|
||
"CHILD": function( type, argument, first, last ) {
|
||
|
||
if ( type === "nth" ) {
|
||
return function( elem ) {
|
||
var node, diff,
|
||
parent = elem.parentNode;
|
||
|
||
if ( first === 1 && last === 0 ) {
|
||
return true;
|
||
}
|
||
|
||
if ( parent ) {
|
||
diff = 0;
|
||
for ( node = parent.firstChild; node; node = node.nextSibling ) {
|
||
if ( node.nodeType === 1 ) {
|
||
diff++;
|
||
if ( elem === node ) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Incorporate the offset (or cast to NaN), then check against cycle size
|
||
diff -= last;
|
||
return diff === first || ( diff % first === 0 && diff / first >= 0 );
|
||
};
|
||
}
|
||
|
||
return function( elem ) {
|
||
var node = elem;
|
||
|
||
switch ( type ) {
|
||
case "only":
|
||
case "first":
|
||
while ( (node = node.previousSibling) ) {
|
||
if ( node.nodeType === 1 ) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if ( type === "first" ) {
|
||
return true;
|
||
}
|
||
|
||
node = elem;
|
||
|
||
/* falls through */
|
||
case "last":
|
||
while ( (node = node.nextSibling) ) {
|
||
if ( node.nodeType === 1 ) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
};
|
||
},
|
||
|
||
"PSEUDO": function( pseudo, argument ) {
|
||
// pseudo-class names are case-insensitive
|
||
// http://www.w3.org/TR/selectors/#pseudo-classes
|
||
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
|
||
// Remember that setFilters inherits from pseudos
|
||
var args,
|
||
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
|
||
Sizzle.error( "unsupported pseudo: " + pseudo );
|
||
|
||
// The user may use createPseudo to indicate that
|
||
// arguments are needed to create the filter function
|
||
// just as Sizzle does
|
||
if ( fn[ expando ] ) {
|
||
return fn( argument );
|
||
}
|
||
|
||
// But maintain support for old signatures
|
||
if ( fn.length > 1 ) {
|
||
args = [ pseudo, pseudo, "", argument ];
|
||
return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
|
||
markFunction(function( seed, matches ) {
|
||
var idx,
|
||
matched = fn( seed, argument ),
|
||
i = matched.length;
|
||
while ( i-- ) {
|
||
idx = indexOf.call( seed, matched[i] );
|
||
seed[ idx ] = !( matches[ idx ] = matched[i] );
|
||
}
|
||
}) :
|
||
function( elem ) {
|
||
return fn( elem, 0, args );
|
||
};
|
||
}
|
||
|
||
return fn;
|
||
}
|
||
},
|
||
|
||
pseudos: {
|
||
"not": markFunction(function( selector ) {
|
||
// Trim the selector passed to compile
|
||
// to avoid treating leading and trailing
|
||
// spaces as combinators
|
||
var input = [],
|
||
results = [],
|
||
matcher = compile( selector.replace( rtrim, "$1" ) );
|
||
|
||
return matcher[ expando ] ?
|
||
markFunction(function( seed, matches, context, xml ) {
|
||
var elem,
|
||
unmatched = matcher( seed, null, xml, [] ),
|
||
i = seed.length;
|
||
|
||
// Match elements unmatched by `matcher`
|
||
while ( i-- ) {
|
||
if ( (elem = unmatched[i]) ) {
|
||
seed[i] = !(matches[i] = elem);
|
||
}
|
||
}
|
||
}) :
|
||
function( elem, context, xml ) {
|
||
input[0] = elem;
|
||
matcher( input, null, xml, results );
|
||
return !results.pop();
|
||
};
|
||
}),
|
||
|
||
"has": markFunction(function( selector ) {
|
||
return function( elem ) {
|
||
return Sizzle( selector, elem ).length > 0;
|
||
};
|
||
}),
|
||
|
||
"contains": markFunction(function( text ) {
|
||
return function( elem ) {
|
||
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
|
||
};
|
||
}),
|
||
|
||
"enabled": function( elem ) {
|
||
return elem.disabled === false;
|
||
},
|
||
|
||
"disabled": function( elem ) {
|
||
return elem.disabled === true;
|
||
},
|
||
|
||
"checked": function( elem ) {
|
||
// In CSS3, :checked should return both checked and selected elements
|
||
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
||
var nodeName = elem.nodeName.toLowerCase();
|
||
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
|
||
},
|
||
|
||
"selected": function( elem ) {
|
||
// Accessing this property makes selected-by-default
|
||
// options in Safari work properly
|
||
if ( elem.parentNode ) {
|
||
elem.parentNode.selectedIndex;
|
||
}
|
||
|
||
return elem.selected === true;
|
||
},
|
||
|
||
"parent": function( elem ) {
|
||
return !Expr.pseudos["empty"]( elem );
|
||
},
|
||
|
||
"empty": function( elem ) {
|
||
// http://www.w3.org/TR/selectors/#empty-pseudo
|
||
// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
|
||
// not comment, processing instructions, or others
|
||
// Thanks to Diego Perini for the nodeName shortcut
|
||
// Greater than "@" means alpha characters (specifically not starting with "#" or "?")
|
||
var nodeType;
|
||
elem = elem.firstChild;
|
||
while ( elem ) {
|
||
if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
|
||
return false;
|
||
}
|
||
elem = elem.nextSibling;
|
||
}
|
||
return true;
|
||
},
|
||
|
||
"header": function( elem ) {
|
||
return rheader.test( elem.nodeName );
|
||
},
|
||
|
||
"text": function( elem ) {
|
||
var type, attr;
|
||
// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
|
||
// use getAttribute instead to test this case
|
||
return elem.nodeName.toLowerCase() === "input" &&
|
||
(type = elem.type) === "text" &&
|
||
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
|
||
},
|
||
|
||
// Input types
|
||
"radio": createInputPseudo("radio"),
|
||
"checkbox": createInputPseudo("checkbox"),
|
||
"file": createInputPseudo("file"),
|
||
"password": createInputPseudo("password"),
|
||
"image": createInputPseudo("image"),
|
||
|
||
"submit": createButtonPseudo("submit"),
|
||
"reset": createButtonPseudo("reset"),
|
||
|
||
"button": function( elem ) {
|
||
var name = elem.nodeName.toLowerCase();
|
||
return name === "input" && elem.type === "button" || name === "button";
|
||
},
|
||
|
||
"input": function( elem ) {
|
||
return rinputs.test( elem.nodeName );
|
||
},
|
||
|
||
"focus": function( elem ) {
|
||
var doc = elem.ownerDocument;
|
||
return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
|
||
},
|
||
|
||
"active": function( elem ) {
|
||
return elem === elem.ownerDocument.activeElement;
|
||
},
|
||
|
||
// Positional types
|
||
"first": createPositionalPseudo(function() {
|
||
return [ 0 ];
|
||
}),
|
||
|
||
"last": createPositionalPseudo(function( matchIndexes, length ) {
|
||
return [ length - 1 ];
|
||
}),
|
||
|
||
"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
||
return [ argument < 0 ? argument + length : argument ];
|
||
}),
|
||
|
||
"even": createPositionalPseudo(function( matchIndexes, length ) {
|
||
for ( var i = 0; i < length; i += 2 ) {
|
||
matchIndexes.push( i );
|
||
}
|
||
return matchIndexes;
|
||
}),
|
||
|
||
"odd": createPositionalPseudo(function( matchIndexes, length ) {
|
||
for ( var i = 1; i < length; i += 2 ) {
|
||
matchIndexes.push( i );
|
||
}
|
||
return matchIndexes;
|
||
}),
|
||
|
||
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
||
for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) {
|
||
matchIndexes.push( i );
|
||
}
|
||
return matchIndexes;
|
||
}),
|
||
|
||
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
||
for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) {
|
||
matchIndexes.push( i );
|
||
}
|
||
return matchIndexes;
|
||
})
|
||
}
|
||
};
|
||
|
||
function siblingCheck( a, b, ret ) {
|
||
if ( a === b ) {
|
||
return ret;
|
||
}
|
||
|
||
var cur = a.nextSibling;
|
||
|
||
while ( cur ) {
|
||
if ( cur === b ) {
|
||
return -1;
|
||
}
|
||
|
||
cur = cur.nextSibling;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
sortOrder = docElem.compareDocumentPosition ?
|
||
function( a, b ) {
|
||
if ( a === b ) {
|
||
hasDuplicate = true;
|
||
return 0;
|
||
}
|
||
|
||
return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
|
||
a.compareDocumentPosition :
|
||
a.compareDocumentPosition(b) & 4
|
||
) ? -1 : 1;
|
||
} :
|
||
function( a, b ) {
|
||
// The nodes are identical, we can exit early
|
||
if ( a === b ) {
|
||
hasDuplicate = true;
|
||
return 0;
|
||
|
||
// Fallback to using sourceIndex (in IE) if it's available on both nodes
|
||
} else if ( a.sourceIndex && b.sourceIndex ) {
|
||
return a.sourceIndex - b.sourceIndex;
|
||
}
|
||
|
||
var al, bl,
|
||
ap = [],
|
||
bp = [],
|
||
aup = a.parentNode,
|
||
bup = b.parentNode,
|
||
cur = aup;
|
||
|
||
// If the nodes are siblings (or identical) we can do a quick check
|
||
if ( aup === bup ) {
|
||
return siblingCheck( a, b );
|
||
|
||
// If no parents were found then the nodes are disconnected
|
||
} else if ( !aup ) {
|
||
return -1;
|
||
|
||
} else if ( !bup ) {
|
||
return 1;
|
||
}
|
||
|
||
// Otherwise they're somewhere else in the tree so we need
|
||
// to build up a full list of the parentNodes for comparison
|
||
while ( cur ) {
|
||
ap.unshift( cur );
|
||
cur = cur.parentNode;
|
||
}
|
||
|
||
cur = bup;
|
||
|
||
while ( cur ) {
|
||
bp.unshift( cur );
|
||
cur = cur.parentNode;
|
||
}
|
||
|
||
al = ap.length;
|
||
bl = bp.length;
|
||
|
||
// Start walking down the tree looking for a discrepancy
|
||
for ( var i = 0; i < al && i < bl; i++ ) {
|
||
if ( ap[i] !== bp[i] ) {
|
||
return siblingCheck( ap[i], bp[i] );
|
||
}
|
||
}
|
||
|
||
// We ended someplace up the tree so do a sibling check
|
||
return i === al ?
|
||
siblingCheck( a, bp[i], -1 ) :
|
||
siblingCheck( ap[i], b, 1 );
|
||
};
|
||
|
||
// Always assume the presence of duplicates if sort doesn't
|
||
// pass them to our comparison function (as in Google Chrome).
|
||
[0, 0].sort( sortOrder );
|
||
baseHasDuplicate = !hasDuplicate;
|
||
|
||
// Document sorting and removing duplicates
|
||
Sizzle.uniqueSort = function( results ) {
|
||
var elem,
|
||
duplicates = [],
|
||
i = 1,
|
||
j = 0;
|
||
|
||
hasDuplicate = baseHasDuplicate;
|
||
results.sort( sortOrder );
|
||
|
||
if ( hasDuplicate ) {
|
||
for ( ; (elem = results[i]); i++ ) {
|
||
if ( elem === results[ i - 1 ] ) {
|
||
j = duplicates.push( i );
|
||
}
|
||
}
|
||
while ( j-- ) {
|
||
results.splice( duplicates[ j ], 1 );
|
||
}
|
||
}
|
||
|
||
return results;
|
||
};
|
||
|
||
Sizzle.error = function( msg ) {
|
||
throw new Error( "Syntax error, unrecognized expression: " + msg );
|
||
};
|
||
|
||
function tokenize( selector, parseOnly ) {
|
||
var matched, match, tokens, type,
|
||
soFar, groups, preFilters,
|
||
cached = tokenCache[ expando ][ selector + " " ];
|
||
|
||
if ( cached ) {
|
||
return parseOnly ? 0 : cached.slice( 0 );
|
||
}
|
||
|
||
soFar = selector;
|
||
groups = [];
|
||
preFilters = Expr.preFilter;
|
||
|
||
while ( soFar ) {
|
||
|
||
// Comma and first run
|
||
if ( !matched || (match = rcomma.exec( soFar )) ) {
|
||
if ( match ) {
|
||
// Don't consume trailing commas as valid
|
||
soFar = soFar.slice( match[0].length ) || soFar;
|
||
}
|
||
groups.push( tokens = [] );
|
||
}
|
||
|
||
matched = false;
|
||
|
||
// Combinators
|
||
if ( (match = rcombinators.exec( soFar )) ) {
|
||
tokens.push( matched = new Token( match.shift() ) );
|
||
soFar = soFar.slice( matched.length );
|
||
|
||
// Cast descendant combinators to space
|
||
matched.type = match[0].replace( rtrim, " " );
|
||
}
|
||
|
||
// Filters
|
||
for ( type in Expr.filter ) {
|
||
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
|
||
(match = preFilters[ type ]( match ))) ) {
|
||
|
||
tokens.push( matched = new Token( match.shift() ) );
|
||
soFar = soFar.slice( matched.length );
|
||
matched.type = type;
|
||
matched.matches = match;
|
||
}
|
||
}
|
||
|
||
if ( !matched ) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Return the length of the invalid excess
|
||
// if we're just parsing
|
||
// Otherwise, throw an error or return tokens
|
||
return parseOnly ?
|
||
soFar.length :
|
||
soFar ?
|
||
Sizzle.error( selector ) :
|
||
// Cache the tokens
|
||
tokenCache( selector, groups ).slice( 0 );
|
||
}
|
||
|
||
function addCombinator( matcher, combinator, base ) {
|
||
var dir = combinator.dir,
|
||
checkNonElements = base && combinator.dir === "parentNode",
|
||
doneName = done++;
|
||
|
||
return combinator.first ?
|
||
// Check against closest ancestor/preceding element
|
||
function( elem, context, xml ) {
|
||
while ( (elem = elem[ dir ]) ) {
|
||
if ( checkNonElements || elem.nodeType === 1 ) {
|
||
return matcher( elem, context, xml );
|
||
}
|
||
}
|
||
} :
|
||
|
||
// Check against all ancestor/preceding elements
|
||
function( elem, context, xml ) {
|
||
// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
|
||
if ( !xml ) {
|
||
var cache,
|
||
dirkey = dirruns + " " + doneName + " ",
|
||
cachedkey = dirkey + cachedruns;
|
||
while ( (elem = elem[ dir ]) ) {
|
||
if ( checkNonElements || elem.nodeType === 1 ) {
|
||
if ( (cache = elem[ expando ]) === cachedkey ) {
|
||
return elem.sizset;
|
||
} else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
|
||
if ( elem.sizset ) {
|
||
return elem;
|
||
}
|
||
} else {
|
||
elem[ expando ] = cachedkey;
|
||
if ( matcher( elem, context, xml ) ) {
|
||
elem.sizset = true;
|
||
return elem;
|
||
}
|
||
elem.sizset = false;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
while ( (elem = elem[ dir ]) ) {
|
||
if ( checkNonElements || elem.nodeType === 1 ) {
|
||
if ( matcher( elem, context, xml ) ) {
|
||
return elem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
function elementMatcher( matchers ) {
|
||
return matchers.length > 1 ?
|
||
function( elem, context, xml ) {
|
||
var i = matchers.length;
|
||
while ( i-- ) {
|
||
if ( !matchers[i]( elem, context, xml ) ) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
} :
|
||
matchers[0];
|
||
}
|
||
|
||
function condense( unmatched, map, filter, context, xml ) {
|
||
var elem,
|
||
newUnmatched = [],
|
||
i = 0,
|
||
len = unmatched.length,
|
||
mapped = map != null;
|
||
|
||
for ( ; i < len; i++ ) {
|
||
if ( (elem = unmatched[i]) ) {
|
||
if ( !filter || filter( elem, context, xml ) ) {
|
||
newUnmatched.push( elem );
|
||
if ( mapped ) {
|
||
map.push( i );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return newUnmatched;
|
||
}
|
||
|
||
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
|
||
if ( postFilter && !postFilter[ expando ] ) {
|
||
postFilter = setMatcher( postFilter );
|
||
}
|
||
if ( postFinder && !postFinder[ expando ] ) {
|
||
postFinder = setMatcher( postFinder, postSelector );
|
||
}
|
||
return markFunction(function( seed, results, context, xml ) {
|
||
var temp, i, elem,
|
||
preMap = [],
|
||
postMap = [],
|
||
preexisting = results.length,
|
||
|
||
// Get initial elements from seed or context
|
||
elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
|
||
|
||
// Prefilter to get matcher input, preserving a map for seed-results synchronization
|
||
matcherIn = preFilter && ( seed || !selector ) ?
|
||
condense( elems, preMap, preFilter, context, xml ) :
|
||
elems,
|
||
|
||
matcherOut = matcher ?
|
||
// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
|
||
postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
|
||
|
||
// ...intermediate processing is necessary
|
||
[] :
|
||
|
||
// ...otherwise use results directly
|
||
results :
|
||
matcherIn;
|
||
|
||
// Find primary matches
|
||
if ( matcher ) {
|
||
matcher( matcherIn, matcherOut, context, xml );
|
||
}
|
||
|
||
// Apply postFilter
|
||
if ( postFilter ) {
|
||
temp = condense( matcherOut, postMap );
|
||
postFilter( temp, [], context, xml );
|
||
|
||
// Un-match failing elements by moving them back to matcherIn
|
||
i = temp.length;
|
||
while ( i-- ) {
|
||
if ( (elem = temp[i]) ) {
|
||
matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( seed ) {
|
||
if ( postFinder || preFilter ) {
|
||
if ( postFinder ) {
|
||
// Get the final matcherOut by condensing this intermediate into postFinder contexts
|
||
temp = [];
|
||
i = matcherOut.length;
|
||
while ( i-- ) {
|
||
if ( (elem = matcherOut[i]) ) {
|
||
// Restore matcherIn since elem is not yet a final match
|
||
temp.push( (matcherIn[i] = elem) );
|
||
}
|
||
}
|
||
postFinder( null, (matcherOut = []), temp, xml );
|
||
}
|
||
|
||
// Move matched elements from seed to results to keep them synchronized
|
||
i = matcherOut.length;
|
||
while ( i-- ) {
|
||
if ( (elem = matcherOut[i]) &&
|
||
(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
|
||
|
||
seed[temp] = !(results[temp] = elem);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Add elements to results, through postFinder if defined
|
||
} else {
|
||
matcherOut = condense(
|
||
matcherOut === results ?
|
||
matcherOut.splice( preexisting, matcherOut.length ) :
|
||
matcherOut
|
||
);
|
||
if ( postFinder ) {
|
||
postFinder( null, results, matcherOut, xml );
|
||
} else {
|
||
push.apply( results, matcherOut );
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function matcherFromTokens( tokens ) {
|
||
var checkContext, matcher, j,
|
||
len = tokens.length,
|
||
leadingRelative = Expr.relative[ tokens[0].type ],
|
||
implicitRelative = leadingRelative || Expr.relative[" "],
|
||
i = leadingRelative ? 1 : 0,
|
||
|
||
// The foundational matcher ensures that elements are reachable from top-level context(s)
|
||
matchContext = addCombinator( function( elem ) {
|
||
return elem === checkContext;
|
||
}, implicitRelative, true ),
|
||
matchAnyContext = addCombinator( function( elem ) {
|
||
return indexOf.call( checkContext, elem ) > -1;
|
||
}, implicitRelative, true ),
|
||
matchers = [ function( elem, context, xml ) {
|
||
return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
|
||
(checkContext = context).nodeType ?
|
||
matchContext( elem, context, xml ) :
|
||
matchAnyContext( elem, context, xml ) );
|
||
} ];
|
||
|
||
for ( ; i < len; i++ ) {
|
||
if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
|
||
matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
|
||
} else {
|
||
matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
|
||
|
||
// Return special upon seeing a positional matcher
|
||
if ( matcher[ expando ] ) {
|
||
// Find the next relative operator (if any) for proper handling
|
||
j = ++i;
|
||
for ( ; j < len; j++ ) {
|
||
if ( Expr.relative[ tokens[j].type ] ) {
|
||
break;
|
||
}
|
||
}
|
||
return setMatcher(
|
||
i > 1 && elementMatcher( matchers ),
|
||
i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ),
|
||
matcher,
|
||
i < j && matcherFromTokens( tokens.slice( i, j ) ),
|
||
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
|
||
j < len && tokens.join("")
|
||
);
|
||
}
|
||
matchers.push( matcher );
|
||
}
|
||
}
|
||
|
||
return elementMatcher( matchers );
|
||
}
|
||
|
||
function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
|
||
var bySet = setMatchers.length > 0,
|
||
byElement = elementMatchers.length > 0,
|
||
superMatcher = function( seed, context, xml, results, expandContext ) {
|
||
var elem, j, matcher,
|
||
setMatched = [],
|
||
matchedCount = 0,
|
||
i = "0",
|
||
unmatched = seed && [],
|
||
outermost = expandContext != null,
|
||
contextBackup = outermostContext,
|
||
// We must always have either seed elements or context
|
||
elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
|
||
// Nested matchers should use non-integer dirruns
|
||
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
|
||
|
||
if ( outermost ) {
|
||
outermostContext = context !== document && context;
|
||
cachedruns = superMatcher.el;
|
||
}
|
||
|
||
// Add elements passing elementMatchers directly to results
|
||
for ( ; (elem = elems[i]) != null; i++ ) {
|
||
if ( byElement && elem ) {
|
||
for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
|
||
if ( matcher( elem, context, xml ) ) {
|
||
results.push( elem );
|
||
break;
|
||
}
|
||
}
|
||
if ( outermost ) {
|
||
dirruns = dirrunsUnique;
|
||
cachedruns = ++superMatcher.el;
|
||
}
|
||
}
|
||
|
||
// Track unmatched elements for set filters
|
||
if ( bySet ) {
|
||
// They will have gone through all possible matchers
|
||
if ( (elem = !matcher && elem) ) {
|
||
matchedCount--;
|
||
}
|
||
|
||
// Lengthen the array for every element, matched or not
|
||
if ( seed ) {
|
||
unmatched.push( elem );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Apply set filters to unmatched elements
|
||
matchedCount += i;
|
||
if ( bySet && i !== matchedCount ) {
|
||
for ( j = 0; (matcher = setMatchers[j]); j++ ) {
|
||
matcher( unmatched, setMatched, context, xml );
|
||
}
|
||
|
||
if ( seed ) {
|
||
// Reintegrate element matches to eliminate the need for sorting
|
||
if ( matchedCount > 0 ) {
|
||
while ( i-- ) {
|
||
if ( !(unmatched[i] || setMatched[i]) ) {
|
||
setMatched[i] = pop.call( results );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Discard index placeholder values to get only actual matches
|
||
setMatched = condense( setMatched );
|
||
}
|
||
|
||
// Add matches to results
|
||
push.apply( results, setMatched );
|
||
|
||
// Seedless set matches succeeding multiple successful matchers stipulate sorting
|
||
if ( outermost && !seed && setMatched.length > 0 &&
|
||
( matchedCount + setMatchers.length ) > 1 ) {
|
||
|
||
Sizzle.uniqueSort( results );
|
||
}
|
||
}
|
||
|
||
// Override manipulation of globals by nested matchers
|
||
if ( outermost ) {
|
||
dirruns = dirrunsUnique;
|
||
outermostContext = contextBackup;
|
||
}
|
||
|
||
return unmatched;
|
||
};
|
||
|
||
superMatcher.el = 0;
|
||
return bySet ?
|
||
markFunction( superMatcher ) :
|
||
superMatcher;
|
||
}
|
||
|
||
compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
|
||
var i,
|
||
setMatchers = [],
|
||
elementMatchers = [],
|
||
cached = compilerCache[ expando ][ selector + " " ];
|
||
|
||
if ( !cached ) {
|
||
// Generate a function of recursive functions that can be used to check each element
|
||
if ( !group ) {
|
||
group = tokenize( selector );
|
||
}
|
||
i = group.length;
|
||
while ( i-- ) {
|
||
cached = matcherFromTokens( group[i] );
|
||
if ( cached[ expando ] ) {
|
||
setMatchers.push( cached );
|
||
} else {
|
||
elementMatchers.push( cached );
|
||
}
|
||
}
|
||
|
||
// Cache the compiled function
|
||
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
|
||
}
|
||
return cached;
|
||
};
|
||
|
||
function multipleContexts( selector, contexts, results ) {
|
||
var i = 0,
|
||
len = contexts.length;
|
||
for ( ; i < len; i++ ) {
|
||
Sizzle( selector, contexts[i], results );
|
||
}
|
||
return results;
|
||
}
|
||
|
||
function select( selector, context, results, seed, xml ) {
|
||
var i, tokens, token, type, find,
|
||
match = tokenize( selector ),
|
||
j = match.length;
|
||
|
||
if ( !seed ) {
|
||
// Try to minimize operations if there is only one group
|
||
if ( match.length === 1 ) {
|
||
|
||
// Take a shortcut and set the context if the root selector is an ID
|
||
tokens = match[0] = match[0].slice( 0 );
|
||
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
|
||
context.nodeType === 9 && !xml &&
|
||
Expr.relative[ tokens[1].type ] ) {
|
||
|
||
context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
|
||
if ( !context ) {
|
||
return results;
|
||
}
|
||
|
||
selector = selector.slice( tokens.shift().length );
|
||
}
|
||
|
||
// Fetch a seed set for right-to-left matching
|
||
for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
|
||
token = tokens[i];
|
||
|
||
// Abort if we hit a combinator
|
||
if ( Expr.relative[ (type = token.type) ] ) {
|
||
break;
|
||
}
|
||
if ( (find = Expr.find[ type ]) ) {
|
||
// Search, expanding context for leading sibling combinators
|
||
if ( (seed = find(
|
||
token.matches[0].replace( rbackslash, "" ),
|
||
rsibling.test( tokens[0].type ) && context.parentNode || context,
|
||
xml
|
||
)) ) {
|
||
|
||
// If seed is empty or no tokens remain, we can return early
|
||
tokens.splice( i, 1 );
|
||
selector = seed.length && tokens.join("");
|
||
if ( !selector ) {
|
||
push.apply( results, slice.call( seed, 0 ) );
|
||
return results;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Compile and execute a filtering function
|
||
// Provide `match` to avoid retokenization if we modified the selector above
|
||
compile( selector, match )(
|
||
seed,
|
||
context,
|
||
xml,
|
||
results,
|
||
rsibling.test( selector )
|
||
);
|
||
return results;
|
||
}
|
||
|
||
if ( document.querySelectorAll ) {
|
||
(function() {
|
||
var disconnectedMatch,
|
||
oldSelect = select,
|
||
rescape = /'|\\/g,
|
||
rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
|
||
|
||
// qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA
|
||
// A support test would require too much code (would include document ready)
|
||
rbuggyQSA = [ ":focus" ],
|
||
|
||
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
|
||
// A support test would require too much code (would include document ready)
|
||
// just skip matchesSelector for :active
|
||
rbuggyMatches = [ ":active" ],
|
||
matches = docElem.matchesSelector ||
|
||
docElem.mozMatchesSelector ||
|
||
docElem.webkitMatchesSelector ||
|
||
docElem.oMatchesSelector ||
|
||
docElem.msMatchesSelector;
|
||
|
||
// Build QSA regex
|
||
// Regex strategy adopted from Diego Perini
|
||
assert(function( div ) {
|
||
// Select is set to empty string on purpose
|
||
// This is to test IE's treatment of not explictly
|
||
// setting a boolean content attribute,
|
||
// since its presence should be enough
|
||
// http://bugs.jquery.com/ticket/12359
|
||
div.innerHTML = "<select><option selected=''></option></select>";
|
||
|
||
// IE8 - Some boolean attributes are not treated correctly
|
||
if ( !div.querySelectorAll("[selected]").length ) {
|
||
rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
|
||
}
|
||
|
||
// Webkit/Opera - :checked should return selected option elements
|
||
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
||
// IE8 throws error here (do not put tests after this one)
|
||
if ( !div.querySelectorAll(":checked").length ) {
|
||
rbuggyQSA.push(":checked");
|
||
}
|
||
});
|
||
|
||
assert(function( div ) {
|
||
|
||
// Opera 10-12/IE9 - ^= $= *= and empty values
|
||
// Should not select anything
|
||
div.innerHTML = "<p test=''></p>";
|
||
if ( div.querySelectorAll("[test^='']").length ) {
|
||
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
|
||
}
|
||
|
||
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
|
||
// IE8 throws error here (do not put tests after this one)
|
||
div.innerHTML = "<input type='hidden'/>";
|
||
if ( !div.querySelectorAll(":enabled").length ) {
|
||
rbuggyQSA.push(":enabled", ":disabled");
|
||
}
|
||
});
|
||
|
||
// rbuggyQSA always contains :focus, so no need for a length check
|
||
rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") );
|
||
|
||
select = function( selector, context, results, seed, xml ) {
|
||
// Only use querySelectorAll when not filtering,
|
||
// when this is not xml,
|
||
// and when no QSA bugs apply
|
||
if ( !seed && !xml && !rbuggyQSA.test( selector ) ) {
|
||
var groups, i,
|
||
old = true,
|
||
nid = expando,
|
||
newContext = context,
|
||
newSelector = context.nodeType === 9 && selector;
|
||
|
||
// qSA works strangely on Element-rooted queries
|
||
// We can work around this by specifying an extra ID on the root
|
||
// and working up from there (Thanks to Andrew Dupont for the technique)
|
||
// IE 8 doesn't work on object elements
|
||
if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
|
||
groups = tokenize( selector );
|
||
|
||
if ( (old = context.getAttribute("id")) ) {
|
||
nid = old.replace( rescape, "\\$&" );
|
||
} else {
|
||
context.setAttribute( "id", nid );
|
||
}
|
||
nid = "[id='" + nid + "'] ";
|
||
|
||
i = groups.length;
|
||
while ( i-- ) {
|
||
groups[i] = nid + groups[i].join("");
|
||
}
|
||
newContext = rsibling.test( selector ) && context.parentNode || context;
|
||
newSelector = groups.join(",");
|
||
}
|
||
|
||
if ( newSelector ) {
|
||
try {
|
||
push.apply( results, slice.call( newContext.querySelectorAll(
|
||
newSelector
|
||
), 0 ) );
|
||
return results;
|
||
} catch(qsaError) {
|
||
} finally {
|
||
if ( !old ) {
|
||
context.removeAttribute("id");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return oldSelect( selector, context, results, seed, xml );
|
||
};
|
||
|
||
if ( matches ) {
|
||
assert(function( div ) {
|
||
// Check to see if it's possible to do matchesSelector
|
||
// on a disconnected node (IE 9)
|
||
disconnectedMatch = matches.call( div, "div" );
|
||
|
||
// This should fail with an exception
|
||
// Gecko does not error, returns false instead
|
||
try {
|
||
matches.call( div, "[test!='']:sizzle" );
|
||
rbuggyMatches.push( "!=", pseudos );
|
||
} catch ( e ) {}
|
||
});
|
||
|
||
// rbuggyMatches always contains :active and :focus, so no need for a length check
|
||
rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
|
||
|
||
Sizzle.matchesSelector = function( elem, expr ) {
|
||
// Make sure that attribute selectors are quoted
|
||
expr = expr.replace( rattributeQuotes, "='$1']" );
|
||
|
||
// rbuggyMatches always contains :active, so no need for an existence check
|
||
if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) {
|
||
try {
|
||
var ret = matches.call( elem, expr );
|
||
|
||
// IE 9's matchesSelector returns false on disconnected nodes
|
||
if ( ret || disconnectedMatch ||
|
||
// As well, disconnected nodes are said to be in a document
|
||
// fragment in IE 9
|
||
elem.document && elem.document.nodeType !== 11 ) {
|
||
return ret;
|
||
}
|
||
} catch(e) {}
|
||
}
|
||
|
||
return Sizzle( expr, null, null, [ elem ] ).length > 0;
|
||
};
|
||
}
|
||
})();
|
||
}
|
||
|
||
// Deprecated
|
||
Expr.pseudos["nth"] = Expr.pseudos["eq"];
|
||
|
||
// Back-compat
|
||
function setFilters() {}
|
||
Expr.filters = setFilters.prototype = Expr.pseudos;
|
||
Expr.setFilters = new setFilters();
|
||
|
||
// Override sizzle attribute retrieval
|
||
Sizzle.attr = jQuery.attr;
|
||
jQuery.find = Sizzle;
|
||
jQuery.expr = Sizzle.selectors;
|
||
jQuery.expr[":"] = jQuery.expr.pseudos;
|
||
jQuery.unique = Sizzle.uniqueSort;
|
||
jQuery.text = Sizzle.getText;
|
||
jQuery.isXMLDoc = Sizzle.isXML;
|
||
jQuery.contains = Sizzle.contains;
|
||
|
||
|
||
})( window );
|
||
var runtil = /Until$/,
|
||
rparentsprev = /^(?:parents|prev(?:Until|All))/,
|
||
isSimple = /^.[^:#\[\.,]*$/,
|
||
rneedsContext = jQuery.expr.match.needsContext,
|
||
// methods guaranteed to produce a unique set when starting from a unique set
|
||
guaranteedUnique = {
|
||
children: true,
|
||
contents: true,
|
||
next: true,
|
||
prev: true
|
||
};
|
||
|
||
jQuery.fn.extend({
|
||
find: function( selector ) {
|
||
var i, l, length, n, r, ret,
|
||
self = this;
|
||
|
||
if ( typeof selector !== "string" ) {
|
||
return jQuery( selector ).filter(function() {
|
||
for ( i = 0, l = self.length; i < l; i++ ) {
|
||
if ( jQuery.contains( self[ i ], this ) ) {
|
||
return true;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
ret = this.pushStack( "", "find", selector );
|
||
|
||
for ( i = 0, l = this.length; i < l; i++ ) {
|
||
length = ret.length;
|
||
jQuery.find( selector, this[i], ret );
|
||
|
||
if ( i > 0 ) {
|
||
// Make sure that the results are unique
|
||
for ( n = length; n < ret.length; n++ ) {
|
||
for ( r = 0; r < length; r++ ) {
|
||
if ( ret[r] === ret[n] ) {
|
||
ret.splice(n--, 1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
},
|
||
|
||
has: function( target ) {
|
||
var i,
|
||
targets = jQuery( target, this ),
|
||
len = targets.length;
|
||
|
||
return this.filter(function() {
|
||
for ( i = 0; i < len; i++ ) {
|
||
if ( jQuery.contains( this, targets[i] ) ) {
|
||
return true;
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
not: function( selector ) {
|
||
return this.pushStack( winnow(this, selector, false), "not", selector);
|
||
},
|
||
|
||
filter: function( selector ) {
|
||
return this.pushStack( winnow(this, selector, true), "filter", selector );
|
||
},
|
||
|
||
is: function( selector ) {
|
||
return !!selector && (
|
||
typeof selector === "string" ?
|
||
// If this is a positional/relative selector, check membership in the returned set
|
||
// so $("p:first").is("p:last") won't return true for a doc with two "p".
|
||
rneedsContext.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 cur,
|
||
i = 0,
|
||
l = this.length,
|
||
ret = [],
|
||
pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
|
||
jQuery( selectors, context || this.context ) :
|
||
0;
|
||
|
||
for ( ; i < l; i++ ) {
|
||
cur = this[i];
|
||
|
||
while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
|
||
if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
|
||
ret.push( cur );
|
||
break;
|
||
}
|
||
cur = cur.parentNode;
|
||
}
|
||
}
|
||
|
||
ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
|
||
|
||
return this.pushStack( ret, "closest", selectors );
|
||
},
|
||
|
||
// Determine the position of an element within
|
||
// the matched set of elements
|
||
index: function( elem ) {
|
||
|
||
// No argument, return index in parent
|
||
if ( !elem ) {
|
||
return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
|
||
}
|
||
|
||
// index in selector
|
||
if ( typeof elem === "string" ) {
|
||
return jQuery.inArray( this[0], jQuery( elem ) );
|
||
}
|
||
|
||
// Locate the position of the desired element
|
||
return jQuery.inArray(
|
||
// If it receives a jQuery object, the first element is used
|
||
elem.jquery ? elem[0] : elem, this );
|
||
},
|
||
|
||
add: function( selector, context ) {
|
||
var set = typeof selector === "string" ?
|
||
jQuery( selector, context ) :
|
||
jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
|
||
all = jQuery.merge( this.get(), set );
|
||
|
||
return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
|
||
all :
|
||
jQuery.unique( all ) );
|
||
},
|
||
|
||
addBack: function( selector ) {
|
||
return this.add( selector == null ?
|
||
this.prevObject : this.prevObject.filter(selector)
|
||
);
|
||
}
|
||
});
|
||
|
||
jQuery.fn.andSelf = jQuery.fn.addBack;
|
||
|
||
// A painfully simple check to see if an element is disconnected
|
||
// from a document (should be improved, where feasible).
|
||
function isDisconnected( node ) {
|
||
return !node || !node.parentNode || node.parentNode.nodeType === 11;
|
||
}
|
||
|
||
function sibling( cur, dir ) {
|
||
do {
|
||
cur = cur[ dir ];
|
||
} while ( cur && cur.nodeType !== 1 );
|
||
|
||
return cur;
|
||
}
|
||
|
||
jQuery.each({
|
||
parent: function( elem ) {
|
||
var parent = elem.parentNode;
|
||
return parent && parent.nodeType !== 11 ? parent : null;
|
||
},
|
||
parents: function( elem ) {
|
||
return jQuery.dir( elem, "parentNode" );
|
||
},
|
||
parentsUntil: function( elem, i, until ) {
|
||
return jQuery.dir( elem, "parentNode", until );
|
||
},
|
||
next: function( elem ) {
|
||
return sibling( elem, "nextSibling" );
|
||
},
|
||
prev: function( elem ) {
|
||
return sibling( elem, "previousSibling" );
|
||
},
|
||
nextAll: function( elem ) {
|
||
return jQuery.dir( elem, "nextSibling" );
|
||
},
|
||
prevAll: function( elem ) {
|
||
return jQuery.dir( elem, "previousSibling" );
|
||
},
|
||
nextUntil: function( elem, i, until ) {
|
||
return jQuery.dir( elem, "nextSibling", until );
|
||
},
|
||
prevUntil: function( elem, i, until ) {
|
||
return jQuery.dir( elem, "previousSibling", until );
|
||
},
|
||
siblings: function( elem ) {
|
||
return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
|
||
},
|
||
children: function( elem ) {
|
||
return jQuery.sibling( elem.firstChild );
|
||
},
|
||
contents: function( elem ) {
|
||
return jQuery.nodeName( elem, "iframe" ) ?
|
||
elem.contentDocument || elem.contentWindow.document :
|
||
jQuery.merge( [], elem.childNodes );
|
||
}
|
||
}, function( name, fn ) {
|
||
jQuery.fn[ name ] = function( until, selector ) {
|
||
var ret = jQuery.map( this, fn, until );
|
||
|
||
if ( !runtil.test( name ) ) {
|
||
selector = until;
|
||
}
|
||
|
||
if ( selector && typeof selector === "string" ) {
|
||
ret = jQuery.filter( selector, ret );
|
||
}
|
||
|
||
ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
|
||
|
||
if ( this.length > 1 && rparentsprev.test( name ) ) {
|
||
ret = ret.reverse();
|
||
}
|
||
|
||
return this.pushStack( ret, name, core_slice.call( arguments ).join(",") );
|
||
};
|
||
});
|
||
|
||
jQuery.extend({
|
||
filter: function( expr, elems, not ) {
|
||
if ( not ) {
|
||
expr = ":not(" + expr + ")";
|
||
}
|
||
|
||
return elems.length === 1 ?
|
||
jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
|
||
jQuery.find.matches(expr, elems);
|
||
},
|
||
|
||
dir: function( elem, dir, until ) {
|
||
var matched = [],
|
||
cur = elem[ dir ];
|
||
|
||
while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
|
||
if ( cur.nodeType === 1 ) {
|
||
matched.push( cur );
|
||
}
|
||
cur = cur[dir];
|
||
}
|
||
return matched;
|
||
},
|
||
|
||
sibling: function( n, elem ) {
|
||
var r = [];
|
||
|
||
for ( ; n; n = n.nextSibling ) {
|
||
if ( n.nodeType === 1 && n !== elem ) {
|
||
r.push( n );
|
||
}
|
||
}
|
||
|
||
return r;
|
||
}
|
||
});
|
||
|
||
// Implement the identical functionality for filter and not
|
||
function winnow( elements, qualifier, keep ) {
|
||
|
||
// Can't pass null or undefined to indexOf in Firefox 4
|
||
// Set to 0 to skip string check
|
||
qualifier = qualifier || 0;
|
||
|
||
if ( jQuery.isFunction( qualifier ) ) {
|
||
return jQuery.grep(elements, function( elem, i ) {
|
||
var retVal = !!qualifier.call( elem, i, elem );
|
||
return retVal === keep;
|
||
});
|
||
|
||
} else if ( qualifier.nodeType ) {
|
||
return jQuery.grep(elements, function( elem, i ) {
|
||
return ( elem === qualifier ) === keep;
|
||
});
|
||
|
||
} else if ( typeof qualifier === "string" ) {
|
||
var filtered = jQuery.grep(elements, function( elem ) {
|
||
return elem.nodeType === 1;
|
||
});
|
||
|
||
if ( isSimple.test( qualifier ) ) {
|
||
return jQuery.filter(qualifier, filtered, !keep);
|
||
} else {
|
||
qualifier = jQuery.filter( qualifier, filtered );
|
||
}
|
||
}
|
||
|
||
return jQuery.grep(elements, function( elem, i ) {
|
||
return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
|
||
});
|
||
}
|
||
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|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
|
||
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
|
||
rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
|
||
rleadingWhitespace = /^\s+/,
|
||
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
|
||
rtagName = /<([\w:]+)/,
|
||
rtbody = /<tbody/i,
|
||
rhtml = /<|&#?\w+;/,
|
||
rnoInnerhtml = /<(?:script|style|link)/i,
|
||
rnocache = /<(?:script|object|embed|option|style)/i,
|
||
rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
|
||
rcheckableType = /^(?:checkbox|radio)$/,
|
||
// checked="checked" or checked
|
||
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
||
rscriptType = /\/(java|ecma)script/i,
|
||
rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,
|
||
wrapMap = {
|
||
option: [ 1, "<select multiple='multiple'>", "</select>" ],
|
||
legend: [ 1, "<fieldset>", "</fieldset>" ],
|
||
thead: [ 1, "<table>", "</table>" ],
|
||
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
|
||
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
|
||
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
|
||
area: [ 1, "<map>", "</map>" ],
|
||
_default: [ 0, "", "" ]
|
||
},
|
||
safeFragment = createSafeFragment( document ),
|
||
fragmentDiv = safeFragment.appendChild( document.createElement("div") );
|
||
|
||
wrapMap.optgroup = wrapMap.option;
|
||
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
|
||
wrapMap.th = wrapMap.td;
|
||
|
||
// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
|
||
// unless wrapped in a div with non-breaking characters in front of it.
|
||
if ( !jQuery.support.htmlSerialize ) {
|
||
wrapMap._default = [ 1, "X<div>", "</div>" ];
|
||
}
|
||
|
||
jQuery.fn.extend({
|
||
text: function( value ) {
|
||
return jQuery.access( this, function( value ) {
|
||
return value === undefined ?
|
||
jQuery.text( this ) :
|
||
this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
|
||
}, null, value, arguments.length );
|
||
},
|
||
|
||
wrapAll: function( html ) {
|
||
if ( jQuery.isFunction( html ) ) {
|
||
return this.each(function(i) {
|
||
jQuery(this).wrapAll( html.call(this, i) );
|
||
});
|
||
}
|
||
|
||
if ( this[0] ) {
|
||
// The elements to wrap the target around
|
||
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
|
||
|
||
if ( this[0].parentNode ) {
|
||
wrap.insertBefore( this[0] );
|
||
}
|
||
|
||
wrap.map(function() {
|
||
var elem = this;
|
||
|
||
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
|
||
elem = elem.firstChild;
|
||
}
|
||
|
||
return elem;
|
||
}).append( this );
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
wrapInner: function( html ) {
|
||
if ( jQuery.isFunction( html ) ) {
|
||
return this.each(function(i) {
|
||
jQuery(this).wrapInner( html.call(this, i) );
|
||
});
|
||
}
|
||
|
||
return this.each(function() {
|
||
var self = jQuery( this ),
|
||
contents = self.contents();
|
||
|
||
if ( contents.length ) {
|
||
contents.wrapAll( html );
|
||
|
||
} else {
|
||
self.append( html );
|
||
}
|
||
});
|
||
},
|
||
|
||
wrap: function( html ) {
|
||
var isFunction = jQuery.isFunction( html );
|
||
|
||
return this.each(function(i) {
|
||
jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
|
||
});
|
||
},
|
||
|
||
unwrap: function() {
|
||
return this.parent().each(function() {
|
||
if ( !jQuery.nodeName( this, "body" ) ) {
|
||
jQuery( this ).replaceWith( this.childNodes );
|
||
}
|
||
}).end();
|
||
},
|
||
|
||
append: function() {
|
||
return this.domManip(arguments, true, function( elem ) {
|
||
if ( this.nodeType === 1 || this.nodeType === 11 ) {
|
||
this.appendChild( elem );
|
||
}
|
||
});
|
||
},
|
||
|
||
prepend: function() {
|
||
return this.domManip(arguments, true, function( elem ) {
|
||
if ( this.nodeType === 1 || this.nodeType === 11 ) {
|
||
this.insertBefore( elem, this.firstChild );
|
||
}
|
||
});
|
||
},
|
||
|
||
before: function() {
|
||
if ( !isDisconnected( this[0] ) ) {
|
||
return this.domManip(arguments, false, function( elem ) {
|
||
this.parentNode.insertBefore( elem, this );
|
||
});
|
||
}
|
||
|
||
if ( arguments.length ) {
|
||
var set = jQuery.clean( arguments );
|
||
return this.pushStack( jQuery.merge( set, this ), "before", this.selector );
|
||
}
|
||
},
|
||
|
||
after: function() {
|
||
if ( !isDisconnected( this[0] ) ) {
|
||
return this.domManip(arguments, false, function( elem ) {
|
||
this.parentNode.insertBefore( elem, this.nextSibling );
|
||
});
|
||
}
|
||
|
||
if ( arguments.length ) {
|
||
var set = jQuery.clean( arguments );
|
||
return this.pushStack( jQuery.merge( this, set ), "after", this.selector );
|
||
}
|
||
},
|
||
|
||
// keepData is for internal use only--do not document
|
||
remove: function( selector, keepData ) {
|
||
var elem,
|
||
i = 0;
|
||
|
||
for ( ; (elem = this[i]) != null; i++ ) {
|
||
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
|
||
if ( !keepData && elem.nodeType === 1 ) {
|
||
jQuery.cleanData( elem.getElementsByTagName("*") );
|
||
jQuery.cleanData( [ elem ] );
|
||
}
|
||
|
||
if ( elem.parentNode ) {
|
||
elem.parentNode.removeChild( elem );
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
empty: function() {
|
||
var elem,
|
||
i = 0;
|
||
|
||
for ( ; (elem = this[i]) != null; i++ ) {
|
||
// Remove element nodes and prevent memory leaks
|
||
if ( elem.nodeType === 1 ) {
|
||
jQuery.cleanData( elem.getElementsByTagName("*") );
|
||
}
|
||
|
||
// Remove any remaining nodes
|
||
while ( elem.firstChild ) {
|
||
elem.removeChild( elem.firstChild );
|
||
}
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
clone: function( dataAndEvents, deepDataAndEvents ) {
|
||
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
||
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
||
|
||
return this.map( function () {
|
||
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
|
||
});
|
||
},
|
||
|
||
html: function( value ) {
|
||
return jQuery.access( this, function( value ) {
|
||
var elem = this[0] || {},
|
||
i = 0,
|
||
l = this.length;
|
||
|
||
if ( value === undefined ) {
|
||
return elem.nodeType === 1 ?
|
||
elem.innerHTML.replace( rinlinejQuery, "" ) :
|
||
undefined;
|
||
}
|
||
|
||
// See if we can take a shortcut and just use innerHTML
|
||
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
|
||
( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
|
||
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
|
||
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
|
||
|
||
value = value.replace( rxhtmlTag, "<$1></$2>" );
|
||
|
||
try {
|
||
for (; i < l; i++ ) {
|
||
// Remove element nodes and prevent memory leaks
|
||
elem = this[i] || {};
|
||
if ( elem.nodeType === 1 ) {
|
||
jQuery.cleanData( elem.getElementsByTagName( "*" ) );
|
||
elem.innerHTML = value;
|
||
}
|
||
}
|
||
|
||
elem = 0;
|
||
|
||
// If using innerHTML throws an exception, use the fallback method
|
||
} catch(e) {}
|
||
}
|
||
|
||
if ( elem ) {
|
||
this.empty().append( value );
|
||
}
|
||
}, null, value, arguments.length );
|
||
},
|
||
|
||
replaceWith: function( value ) {
|
||
if ( !isDisconnected( this[0] ) ) {
|
||
// Make sure that the elements are removed from the DOM before they are inserted
|
||
// this can help fix replacing a parent with child elements
|
||
if ( jQuery.isFunction( value ) ) {
|
||
return this.each(function(i) {
|
||
var self = jQuery(this), old = self.html();
|
||
self.replaceWith( value.call( this, i, old ) );
|
||
});
|
||
}
|
||
|
||
if ( typeof value !== "string" ) {
|
||
value = jQuery( value ).detach();
|
||
}
|
||
|
||
return this.each(function() {
|
||
var next = this.nextSibling,
|
||
parent = this.parentNode;
|
||
|
||
jQuery( this ).remove();
|
||
|
||
if ( next ) {
|
||
jQuery(next).before( value );
|
||
} else {
|
||
jQuery(parent).append( value );
|
||
}
|
||
});
|
||
}
|
||
|
||
return this.length ?
|
||
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
|
||
this;
|
||
},
|
||
|
||
detach: function( selector ) {
|
||
return this.remove( selector, true );
|
||
},
|
||
|
||
domManip: function( args, table, callback ) {
|
||
|
||
// Flatten any nested arrays
|
||
args = [].concat.apply( [], args );
|
||
|
||
var results, first, fragment, iNoClone,
|
||
i = 0,
|
||
value = args[0],
|
||
scripts = [],
|
||
l = this.length;
|
||
|
||
// We can't cloneNode fragments that contain checked, in WebKit
|
||
if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
|
||
return this.each(function() {
|
||
jQuery(this).domManip( args, table, callback );
|
||
});
|
||
}
|
||
|
||
if ( jQuery.isFunction(value) ) {
|
||
return this.each(function(i) {
|
||
var self = jQuery(this);
|
||
args[0] = value.call( this, i, table ? self.html() : undefined );
|
||
self.domManip( args, table, callback );
|
||
});
|
||
}
|
||
|
||
if ( this[0] ) {
|
||
results = jQuery.buildFragment( args, this, scripts );
|
||
fragment = results.fragment;
|
||
first = fragment.firstChild;
|
||
|
||
if ( fragment.childNodes.length === 1 ) {
|
||
fragment = first;
|
||
}
|
||
|
||
if ( first ) {
|
||
table = table && jQuery.nodeName( first, "tr" );
|
||
|
||
// Use the original fragment for the last item instead of the first because it can end up
|
||
// being emptied incorrectly in certain situations (#8070).
|
||
// Fragments from the fragment cache must always be cloned and never used in place.
|
||
for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
|
||
callback.call(
|
||
table && jQuery.nodeName( this[i], "table" ) ?
|
||
findOrAppend( this[i], "tbody" ) :
|
||
this[i],
|
||
i === iNoClone ?
|
||
fragment :
|
||
jQuery.clone( fragment, true, true )
|
||
);
|
||
}
|
||
}
|
||
|
||
// Fix #11809: Avoid leaking memory
|
||
fragment = first = null;
|
||
|
||
if ( scripts.length ) {
|
||
jQuery.each( scripts, function( i, elem ) {
|
||
if ( elem.src ) {
|
||
if ( jQuery.ajax ) {
|
||
jQuery.ajax({
|
||
url: elem.src,
|
||
type: "GET",
|
||
dataType: "script",
|
||
async: false,
|
||
global: false,
|
||
"throws": true
|
||
});
|
||
} else {
|
||
jQuery.error("no ajax");
|
||
}
|
||
} else {
|
||
jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
|
||
}
|
||
|
||
if ( elem.parentNode ) {
|
||
elem.parentNode.removeChild( elem );
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
return this;
|
||
}
|
||
});
|
||
|
||
function findOrAppend( elem, tag ) {
|
||
return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
|
||
}
|
||
|
||
function cloneCopyEvent( src, dest ) {
|
||
|
||
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
|
||
return;
|
||
}
|
||
|
||
var type, i, l,
|
||
oldData = jQuery._data( src ),
|
||
curData = jQuery._data( dest, oldData ),
|
||
events = oldData.events;
|
||
|
||
if ( events ) {
|
||
delete curData.handle;
|
||
curData.events = {};
|
||
|
||
for ( type in events ) {
|
||
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
||
jQuery.event.add( dest, type, events[ type ][ i ] );
|
||
}
|
||
}
|
||
}
|
||
|
||
// make the cloned public data object a copy from the original
|
||
if ( curData.data ) {
|
||
curData.data = jQuery.extend( {}, curData.data );
|
||
}
|
||
}
|
||
|
||
function cloneFixAttributes( src, dest ) {
|
||
var nodeName;
|
||
|
||
// We do not need to do anything for non-Elements
|
||
if ( dest.nodeType !== 1 ) {
|
||
return;
|
||
}
|
||
|
||
// clearAttributes removes the attributes, which we don't want,
|
||
// but also removes the attachEvent events, which we *do* want
|
||
if ( dest.clearAttributes ) {
|
||
dest.clearAttributes();
|
||
}
|
||
|
||
// mergeAttributes, in contrast, only merges back on the
|
||
// original attributes, not the events
|
||
if ( dest.mergeAttributes ) {
|
||
dest.mergeAttributes( src );
|
||
}
|
||
|
||
nodeName = dest.nodeName.toLowerCase();
|
||
|
||
if ( nodeName === "object" ) {
|
||
// IE6-10 improperly clones children of object elements using classid.
|
||
// IE10 throws NoModificationAllowedError if parent is null, #12132.
|
||
if ( dest.parentNode ) {
|
||
dest.outerHTML = src.outerHTML;
|
||
}
|
||
|
||
// This path appears unavoidable for IE9. When cloning an object
|
||
// element in IE9, the outerHTML strategy above is not sufficient.
|
||
// If the src has innerHTML and the destination does not,
|
||
// copy the src.innerHTML into the dest.innerHTML. #10324
|
||
if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) {
|
||
dest.innerHTML = src.innerHTML;
|
||
}
|
||
|
||
} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
|
||
// IE6-8 fails to persist the checked state of a cloned checkbox
|
||
// or radio button. Worse, IE6-7 fail to give the cloned element
|
||
// a checked appearance if the defaultChecked value isn't also set
|
||
|
||
dest.defaultChecked = dest.checked = src.checked;
|
||
|
||
// IE6-7 get confused and end up setting the value of a cloned
|
||
// checkbox/radio button to an empty string instead of "on"
|
||
if ( dest.value !== src.value ) {
|
||
dest.value = src.value;
|
||
}
|
||
|
||
// IE6-8 fails to return the selected option to the default selected
|
||
// state when cloning options
|
||
} else if ( nodeName === "option" ) {
|
||
dest.selected = src.defaultSelected;
|
||
|
||
// IE6-8 fails to set the defaultValue to the correct value when
|
||
// cloning other types of input fields
|
||
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
||
dest.defaultValue = src.defaultValue;
|
||
|
||
// IE blanks contents when cloning scripts
|
||
} else if ( nodeName === "script" && dest.text !== src.text ) {
|
||
dest.text = src.text;
|
||
}
|
||
|
||
// Event data gets referenced instead of copied if the expando
|
||
// gets copied too
|
||
dest.removeAttribute( jQuery.expando );
|
||
}
|
||
|
||
jQuery.buildFragment = function( args, context, scripts ) {
|
||
var fragment, cacheable, cachehit,
|
||
first = args[ 0 ];
|
||
|
||
// Set context from what may come in as undefined or a jQuery collection or a node
|
||
// Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 &
|
||
// also doubles as fix for #8950 where plain objects caused createDocumentFragment exception
|
||
context = context || document;
|
||
context = !context.nodeType && context[0] || context;
|
||
context = context.ownerDocument || context;
|
||
|
||
// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
|
||
// 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
|
||
// 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 && context === document &&
|
||
first.charAt(0) === "<" && !rnocache.test( first ) &&
|
||
(jQuery.support.checkClone || !rchecked.test( first )) &&
|
||
(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
|
||
|
||
// Mark cacheable and look for a hit
|
||
cacheable = true;
|
||
fragment = jQuery.fragments[ first ];
|
||
cachehit = fragment !== undefined;
|
||
}
|
||
|
||
if ( !fragment ) {
|
||
fragment = context.createDocumentFragment();
|
||
jQuery.clean( args, context, fragment, scripts );
|
||
|
||
// Update the cache, but only store false
|
||
// unless this is a second parsing of the same content
|
||
if ( cacheable ) {
|
||
jQuery.fragments[ first ] = cachehit && fragment;
|
||
}
|
||
}
|
||
|
||
return { fragment: fragment, cacheable: cacheable };
|
||
};
|
||
|
||
jQuery.fragments = {};
|
||
|
||
jQuery.each({
|
||
appendTo: "append",
|
||
prependTo: "prepend",
|
||
insertBefore: "before",
|
||
insertAfter: "after",
|
||
replaceAll: "replaceWith"
|
||
}, function( name, original ) {
|
||
jQuery.fn[ name ] = function( selector ) {
|
||
var elems,
|
||
i = 0,
|
||
ret = [],
|
||
insert = jQuery( selector ),
|
||
l = insert.length,
|
||
parent = this.length === 1 && this[0].parentNode;
|
||
|
||
if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) {
|
||
insert[ original ]( this[0] );
|
||
return this;
|
||
} else {
|
||
for ( ; i < l; i++ ) {
|
||
elems = ( i > 0 ? this.clone(true) : this ).get();
|
||
jQuery( insert[i] )[ original ]( elems );
|
||
ret = ret.concat( elems );
|
||
}
|
||
|
||
return this.pushStack( ret, name, insert.selector );
|
||
}
|
||
};
|
||
});
|
||
|
||
function getAll( elem ) {
|
||
if ( typeof elem.getElementsByTagName !== "undefined" ) {
|
||
return elem.getElementsByTagName( "*" );
|
||
|
||
} else if ( typeof elem.querySelectorAll !== "undefined" ) {
|
||
return elem.querySelectorAll( "*" );
|
||
|
||
} else {
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Used in clean, fixes the defaultChecked property
|
||
function fixDefaultChecked( elem ) {
|
||
if ( rcheckableType.test( elem.type ) ) {
|
||
elem.defaultChecked = elem.checked;
|
||
}
|
||
}
|
||
|
||
jQuery.extend({
|
||
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
|
||
var srcElements,
|
||
destElements,
|
||
i,
|
||
clone;
|
||
|
||
if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
|
||
clone = elem.cloneNode( true );
|
||
|
||
// IE<=8 does not properly clone detached, unknown element nodes
|
||
} else {
|
||
fragmentDiv.innerHTML = elem.outerHTML;
|
||
fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
|
||
}
|
||
|
||
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
|
||
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
|
||
// IE copies events bound via attachEvent when using cloneNode.
|
||
// Calling detachEvent on the clone will also remove the events
|
||
// from the original. In order to get around this, we use some
|
||
// proprietary methods to clear the events. Thanks to MooTools
|
||
// guys for this hotness.
|
||
|
||
cloneFixAttributes( elem, clone );
|
||
|
||
// Using Sizzle here is crazy slow, so we use getElementsByTagName instead
|
||
srcElements = getAll( elem );
|
||
destElements = getAll( clone );
|
||
|
||
// Weird iteration because IE will replace the length property
|
||
// with an element if you are cloning the body and one of the
|
||
// elements on the page has a name or id of "length"
|
||
for ( i = 0; srcElements[i]; ++i ) {
|
||
// Ensure that the destination node is not null; Fixes #9587
|
||
if ( destElements[i] ) {
|
||
cloneFixAttributes( srcElements[i], destElements[i] );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Copy the events from the original to the clone
|
||
if ( dataAndEvents ) {
|
||
cloneCopyEvent( elem, clone );
|
||
|
||
if ( deepDataAndEvents ) {
|
||
srcElements = getAll( elem );
|
||
destElements = getAll( clone );
|
||
|
||
for ( i = 0; srcElements[i]; ++i ) {
|
||
cloneCopyEvent( srcElements[i], destElements[i] );
|
||
}
|
||
}
|
||
}
|
||
|
||
srcElements = destElements = null;
|
||
|
||
// Return the cloned set
|
||
return clone;
|
||
},
|
||
|
||
clean: function( elems, context, fragment, scripts ) {
|
||
var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
|
||
safe = context === document && safeFragment,
|
||
ret = [];
|
||
|
||
// Ensure that context is a document
|
||
if ( !context || typeof context.createDocumentFragment === "undefined" ) {
|
||
context = document;
|
||
}
|
||
|
||
// Use the already-created safe fragment if context permits
|
||
for ( i = 0; (elem = elems[i]) != null; i++ ) {
|
||
if ( typeof elem === "number" ) {
|
||
elem += "";
|
||
}
|
||
|
||
if ( !elem ) {
|
||
continue;
|
||
}
|
||
|
||
// Convert html string into DOM nodes
|
||
if ( typeof elem === "string" ) {
|
||
if ( !rhtml.test( elem ) ) {
|
||
elem = context.createTextNode( elem );
|
||
} else {
|
||
// Ensure a safe container in which to render the html
|
||
safe = safe || createSafeFragment( context );
|
||
div = context.createElement("div");
|
||
safe.appendChild( div );
|
||
|
||
// Fix "XHTML"-style tags in all browsers
|
||
elem = elem.replace(rxhtmlTag, "<$1></$2>");
|
||
|
||
// Go to html and back, then peel off extra wrappers
|
||
tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
|
||
wrap = wrapMap[ tag ] || wrapMap._default;
|
||
depth = wrap[0];
|
||
div.innerHTML = wrap[1] + elem + wrap[2];
|
||
|
||
// Move to the right depth
|
||
while ( depth-- ) {
|
||
div = div.lastChild;
|
||
}
|
||
|
||
// Remove IE's autoinserted <tbody> from table fragments
|
||
if ( !jQuery.support.tbody ) {
|
||
|
||
// String was a <table>, *may* have spurious <tbody>
|
||
hasBody = rtbody.test(elem);
|
||
tbody = tag === "table" && !hasBody ?
|
||
div.firstChild && div.firstChild.childNodes :
|
||
|
||
// String was a bare <thead> or <tfoot>
|
||
wrap[1] === "<table>" && !hasBody ?
|
||
div.childNodes :
|
||
[];
|
||
|
||
for ( j = tbody.length - 1; j >= 0 ; --j ) {
|
||
if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
|
||
tbody[ j ].parentNode.removeChild( tbody[ j ] );
|
||
}
|
||
}
|
||
}
|
||
|
||
// IE completely kills leading whitespace when innerHTML is used
|
||
if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
|
||
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
|
||
}
|
||
|
||
elem = div.childNodes;
|
||
|
||
// Take out of fragment container (we need a fresh div each time)
|
||
div.parentNode.removeChild( div );
|
||
}
|
||
}
|
||
|
||
if ( elem.nodeType ) {
|
||
ret.push( elem );
|
||
} else {
|
||
jQuery.merge( ret, elem );
|
||
}
|
||
}
|
||
|
||
// Fix #11356: Clear elements from safeFragment
|
||
if ( div ) {
|
||
elem = div = safe = null;
|
||
}
|
||
|
||
// Reset defaultChecked for any radios and checkboxes
|
||
// about to be appended to the DOM in IE 6/7 (#8060)
|
||
if ( !jQuery.support.appendChecked ) {
|
||
for ( i = 0; (elem = ret[i]) != null; i++ ) {
|
||
if ( jQuery.nodeName( elem, "input" ) ) {
|
||
fixDefaultChecked( elem );
|
||
} else if ( typeof elem.getElementsByTagName !== "undefined" ) {
|
||
jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Append elements to a provided document fragment
|
||
if ( fragment ) {
|
||
// Special handling of each script element
|
||
handleScript = function( elem ) {
|
||
// Check if we consider it executable
|
||
if ( !elem.type || rscriptType.test( elem.type ) ) {
|
||
// Detach the script and store it in the scripts array (if provided) or the fragment
|
||
// Return truthy to indicate that it has been handled
|
||
return scripts ?
|
||
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
|
||
fragment.appendChild( elem );
|
||
}
|
||
};
|
||
|
||
for ( i = 0; (elem = ret[i]) != null; i++ ) {
|
||
// Check if we're done after handling an executable script
|
||
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
|
||
// Append to fragment and handle embedded scripts
|
||
fragment.appendChild( elem );
|
||
if ( typeof elem.getElementsByTagName !== "undefined" ) {
|
||
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
|
||
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
|
||
|
||
// Splice the scripts into ret after their former ancestor and advance our index beyond them
|
||
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
|
||
i += jsTags.length;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
},
|
||
|
||
cleanData: function( elems, /* internal */ acceptData ) {
|
||
var data, id, elem, type,
|
||
i = 0,
|
||
internalKey = jQuery.expando,
|
||
cache = jQuery.cache,
|
||
deleteExpando = jQuery.support.deleteExpando,
|
||
special = jQuery.event.special;
|
||
|
||
for ( ; (elem = elems[i]) != null; i++ ) {
|
||
|
||
if ( acceptData || jQuery.acceptData( elem ) ) {
|
||
|
||
id = elem[ internalKey ];
|
||
data = id && cache[ id ];
|
||
|
||
if ( data ) {
|
||
if ( data.events ) {
|
||
for ( type in data.events ) {
|
||
if ( special[ type ] ) {
|
||
jQuery.event.remove( elem, type );
|
||
|
||
// This is a shortcut to avoid jQuery.event.remove's overhead
|
||
} else {
|
||
jQuery.removeEvent( elem, type, data.handle );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Remove cache only if it was not already removed by jQuery.event.remove
|
||
if ( cache[ id ] ) {
|
||
|
||
delete cache[ id ];
|
||
|
||
// 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 ( deleteExpando ) {
|
||
delete elem[ internalKey ];
|
||
|
||
} else if ( elem.removeAttribute ) {
|
||
elem.removeAttribute( internalKey );
|
||
|
||
} else {
|
||
elem[ internalKey ] = null;
|
||
}
|
||
|
||
jQuery.deletedIds.push( id );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
// Limit scope pollution from any deprecated API
|
||
(function() {
|
||
|
||
var matched, browser;
|
||
|
||
// Use of jQuery.browser is frowned upon.
|
||
// More details: http://api.jquery.com/jQuery.browser
|
||
// jQuery.uaMatch maintained for back-compat
|
||
jQuery.uaMatch = function( ua ) {
|
||
ua = ua.toLowerCase();
|
||
|
||
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
|
||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
|
||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
||
/(msie) ([\w.]+)/.exec( ua ) ||
|
||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
||
[];
|
||
|
||
return {
|
||
browser: match[ 1 ] || "",
|
||
version: match[ 2 ] || "0"
|
||
};
|
||
};
|
||
|
||
matched = jQuery.uaMatch( navigator.userAgent );
|
||
browser = {};
|
||
|
||
if ( matched.browser ) {
|
||
browser[ matched.browser ] = true;
|
||
browser.version = matched.version;
|
||
}
|
||
|
||
// Chrome is Webkit, but Webkit is also Safari.
|
||
if ( browser.chrome ) {
|
||
browser.webkit = true;
|
||
} else if ( browser.webkit ) {
|
||
browser.safari = true;
|
||
}
|
||
|
||
jQuery.browser = browser;
|
||
|
||
jQuery.sub = function() {
|
||
function jQuerySub( selector, context ) {
|
||
return new jQuerySub.fn.init( selector, context );
|
||
}
|
||
jQuery.extend( true, jQuerySub, this );
|
||
jQuerySub.superclass = this;
|
||
jQuerySub.fn = jQuerySub.prototype = this();
|
||
jQuerySub.fn.constructor = jQuerySub;
|
||
jQuerySub.sub = this.sub;
|
||
jQuerySub.fn.init = function init( selector, context ) {
|
||
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
|
||
context = jQuerySub( context );
|
||
}
|
||
|
||
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
|
||
};
|
||
jQuerySub.fn.init.prototype = jQuerySub.fn;
|
||
var rootjQuerySub = jQuerySub(document);
|
||
return jQuerySub;
|
||
};
|
||
|
||
})();
|
||
var curCSS, iframe, iframeDoc,
|
||
ralpha = /alpha\([^)]*\)/i,
|
||
ropacity = /opacity=([^)]*)/,
|
||
rposition = /^(top|right|bottom|left)$/,
|
||
// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
|
||
// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
|
||
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
|
||
rmargin = /^margin/,
|
||
rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
|
||
rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
|
||
rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
|
||
elemdisplay = { BODY: "block" },
|
||
|
||
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
||
cssNormalTransform = {
|
||
letterSpacing: 0,
|
||
fontWeight: 400
|
||
},
|
||
|
||
cssExpand = [ "Top", "Right", "Bottom", "Left" ],
|
||
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
|
||
|
||
eventsToggle = jQuery.fn.toggle;
|
||
|
||
// return a css property mapped to a potentially vendor prefixed property
|
||
function vendorPropName( style, name ) {
|
||
|
||
// shortcut for names that are not vendor prefixed
|
||
if ( name in style ) {
|
||
return name;
|
||
}
|
||
|
||
// check for vendor prefixed names
|
||
var capName = name.charAt(0).toUpperCase() + name.slice(1),
|
||
origName = name,
|
||
i = cssPrefixes.length;
|
||
|
||
while ( i-- ) {
|
||
name = cssPrefixes[ i ] + capName;
|
||
if ( name in style ) {
|
||
return name;
|
||
}
|
||
}
|
||
|
||
return origName;
|
||
}
|
||
|
||
function isHidden( elem, el ) {
|
||
elem = el || elem;
|
||
return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
|
||
}
|
||
|
||
function showHide( elements, show ) {
|
||
var elem, display,
|
||
values = [],
|
||
index = 0,
|
||
length = elements.length;
|
||
|
||
for ( ; index < length; index++ ) {
|
||
elem = elements[ index ];
|
||
if ( !elem.style ) {
|
||
continue;
|
||
}
|
||
values[ index ] = jQuery._data( elem, "olddisplay" );
|
||
if ( show ) {
|
||
// Reset the inline display of this element to learn if it is
|
||
// being hidden by cascaded rules or not
|
||
if ( !values[ index ] && elem.style.display === "none" ) {
|
||
elem.style.display = "";
|
||
}
|
||
|
||
// Set elements which have been overridden with display: none
|
||
// in a stylesheet to whatever the default browser style is
|
||
// for such an element
|
||
if ( elem.style.display === "" && isHidden( elem ) ) {
|
||
values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
|
||
}
|
||
} else {
|
||
display = curCSS( elem, "display" );
|
||
|
||
if ( !values[ index ] && display !== "none" ) {
|
||
jQuery._data( elem, "olddisplay", display );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Set the display of most of the elements in a second loop
|
||
// to avoid the constant reflow
|
||
for ( index = 0; index < length; index++ ) {
|
||
elem = elements[ index ];
|
||
if ( !elem.style ) {
|
||
continue;
|
||
}
|
||
if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
|
||
elem.style.display = show ? values[ index ] || "" : "none";
|
||
}
|
||
}
|
||
|
||
return elements;
|
||
}
|
||
|
||
jQuery.fn.extend({
|
||
css: function( name, value ) {
|
||
return jQuery.access( this, function( elem, name, value ) {
|
||
return value !== undefined ?
|
||
jQuery.style( elem, name, value ) :
|
||
jQuery.css( elem, name );
|
||
}, name, value, arguments.length > 1 );
|
||
},
|
||
show: function() {
|
||
return showHide( this, true );
|
||
},
|
||
hide: function() {
|
||
return showHide( this );
|
||
},
|
||
toggle: function( state, fn2 ) {
|
||
var bool = typeof state === "boolean";
|
||
|
||
if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) {
|
||
return eventsToggle.apply( this, arguments );
|
||
}
|
||
|
||
return this.each(function() {
|
||
if ( bool ? state : isHidden( this ) ) {
|
||
jQuery( this ).show();
|
||
} else {
|
||
jQuery( this ).hide();
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
jQuery.extend({
|
||
// Add in style property hooks for overriding the default
|
||
// behavior of getting and setting a style property
|
||
cssHooks: {
|
||
opacity: {
|
||
get: function( elem, computed ) {
|
||
if ( computed ) {
|
||
// We should always get a number back from opacity
|
||
var ret = curCSS( elem, "opacity" );
|
||
return ret === "" ? "1" : ret;
|
||
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
// Exclude the following css properties to add px
|
||
cssNumber: {
|
||
"fillOpacity": true,
|
||
"fontWeight": true,
|
||
"lineHeight": true,
|
||
"opacity": true,
|
||
"orphans": true,
|
||
"widows": true,
|
||
"zIndex": true,
|
||
"zoom": true
|
||
},
|
||
|
||
// Add in properties whose names you wish to fix before
|
||
// setting or getting the value
|
||
cssProps: {
|
||
// normalize float css property
|
||
"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
|
||
},
|
||
|
||
// Get and set the style property on a DOM Node
|
||
style: function( elem, name, value, extra ) {
|
||
// Don't set styles on text and comment nodes
|
||
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
|
||
return;
|
||
}
|
||
|
||
// Make sure that we're working with the right name
|
||
var ret, type, hooks,
|
||
origName = jQuery.camelCase( name ),
|
||
style = elem.style;
|
||
|
||
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
|
||
|
||
// gets hook for the prefixed version
|
||
// followed by the unprefixed version
|
||
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
||
|
||
// Check if we're setting a value
|
||
if ( value !== undefined ) {
|
||
type = typeof value;
|
||
|
||
// convert relative number strings (+= or -=) to relative numbers. #7345
|
||
if ( type === "string" && (ret = rrelNum.exec( value )) ) {
|
||
value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
|
||
// Fixes bug #9237
|
||
type = "number";
|
||
}
|
||
|
||
// Make sure that NaN and null values aren't set. See: #7116
|
||
if ( value == null || type === "number" && isNaN( value ) ) {
|
||
return;
|
||
}
|
||
|
||
// If a number was passed in, add 'px' to the (except for certain CSS properties)
|
||
if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
|
||
value += "px";
|
||
}
|
||
|
||
// If a hook was provided, use that value, otherwise just set the specified value
|
||
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
|
||
// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
|
||
// Fixes bug #5509
|
||
try {
|
||
style[ name ] = value;
|
||
} catch(e) {}
|
||
}
|
||
|
||
} else {
|
||
// If a hook was provided get the non-computed value from there
|
||
if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
|
||
return ret;
|
||
}
|
||
|
||
// Otherwise just get the value from the style object
|
||
return style[ name ];
|
||
}
|
||
},
|
||
|
||
css: function( elem, name, numeric, extra ) {
|
||
var val, num, hooks,
|
||
origName = jQuery.camelCase( name );
|
||
|
||
// Make sure that we're working with the right name
|
||
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
|
||
|
||
// gets hook for the prefixed version
|
||
// followed by the unprefixed version
|
||
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
||
|
||
// If a hook was provided get the computed value from there
|
||
if ( hooks && "get" in hooks ) {
|
||
val = hooks.get( elem, true, extra );
|
||
}
|
||
|
||
// Otherwise, if a way to get the computed value exists, use that
|
||
if ( val === undefined ) {
|
||
val = curCSS( elem, name );
|
||
}
|
||
|
||
//convert "normal" to computed value
|
||
if ( val === "normal" && name in cssNormalTransform ) {
|
||
val = cssNormalTransform[ name ];
|
||
}
|
||
|
||
// Return, converting to number if forced or a qualifier was provided and val looks numeric
|
||
if ( numeric || extra !== undefined ) {
|
||
num = parseFloat( val );
|
||
return numeric || jQuery.isNumeric( num ) ? num || 0 : val;
|
||
}
|
||
return val;
|
||
},
|
||
|
||
// A method for quickly swapping in/out CSS properties to get correct calculations
|
||
swap: function( elem, options, callback ) {
|
||
var ret, name,
|
||
old = {};
|
||
|
||
// Remember the old values, and insert the new ones
|
||
for ( name in options ) {
|
||
old[ name ] = elem.style[ name ];
|
||
elem.style[ name ] = options[ name ];
|
||
}
|
||
|
||
ret = callback.call( elem );
|
||
|
||
// Revert the old values
|
||
for ( name in options ) {
|
||
elem.style[ name ] = old[ name ];
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
});
|
||
|
||
// NOTE: To any future maintainer, we've window.getComputedStyle
|
||
// because jsdom on node.js will break without it.
|
||
if ( window.getComputedStyle ) {
|
||
curCSS = function( elem, name ) {
|
||
var ret, width, minWidth, maxWidth,
|
||
computed = window.getComputedStyle( elem, null ),
|
||
style = elem.style;
|
||
|
||
if ( computed ) {
|
||
|
||
// getPropertyValue is only needed for .css('filter') in IE9, see #12537
|
||
ret = computed.getPropertyValue( name ) || computed[ name ];
|
||
|
||
if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
|
||
ret = jQuery.style( elem, name );
|
||
}
|
||
|
||
// A tribute to the "awesome hack by Dean Edwards"
|
||
// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
|
||
// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
|
||
// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
|
||
if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
|
||
width = style.width;
|
||
minWidth = style.minWidth;
|
||
maxWidth = style.maxWidth;
|
||
|
||
style.minWidth = style.maxWidth = style.width = ret;
|
||
ret = computed.width;
|
||
|
||
style.width = width;
|
||
style.minWidth = minWidth;
|
||
style.maxWidth = maxWidth;
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
};
|
||
} else if ( document.documentElement.currentStyle ) {
|
||
curCSS = function( elem, name ) {
|
||
var left, rsLeft,
|
||
ret = elem.currentStyle && elem.currentStyle[ name ],
|
||
style = elem.style;
|
||
|
||
// Avoid setting ret to empty string here
|
||
// so we don't default to auto
|
||
if ( ret == null && style && style[ name ] ) {
|
||
ret = style[ name ];
|
||
}
|
||
|
||
// 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
|
||
// but not position css attributes, as those are proportional to the parent element instead
|
||
// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
|
||
if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
|
||
|
||
// 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;
|
||
ret = style.pixelLeft + "px";
|
||
|
||
// Revert the changed values
|
||
style.left = left;
|
||
if ( rsLeft ) {
|
||
elem.runtimeStyle.left = rsLeft;
|
||
}
|
||
}
|
||
|
||
return ret === "" ? "auto" : ret;
|
||
};
|
||
}
|
||
|
||
function setPositiveNumber( elem, value, subtract ) {
|
||
var matches = rnumsplit.exec( value );
|
||
return matches ?
|
||
Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
|
||
value;
|
||
}
|
||
|
||
function augmentWidthOrHeight( elem, name, extra, isBorderBox ) {
|
||
var i = extra === ( isBorderBox ? "border" : "content" ) ?
|
||
// If we already have the right measurement, avoid augmentation
|
||
4 :
|
||
// Otherwise initialize for horizontal or vertical properties
|
||
name === "width" ? 1 : 0,
|
||
|
||
val = 0;
|
||
|
||
for ( ; i < 4; i += 2 ) {
|
||
// both box models exclude margin, so add it if we want it
|
||
if ( extra === "margin" ) {
|
||
// we use jQuery.css instead of curCSS here
|
||
// because of the reliableMarginRight CSS hook!
|
||
val += jQuery.css( elem, extra + cssExpand[ i ], true );
|
||
}
|
||
|
||
// From this point on we use curCSS for maximum performance (relevant in animations)
|
||
if ( isBorderBox ) {
|
||
// border-box includes padding, so remove it if we want content
|
||
if ( extra === "content" ) {
|
||
val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
|
||
}
|
||
|
||
// at this point, extra isn't border nor margin, so remove border
|
||
if ( extra !== "margin" ) {
|
||
val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
|
||
}
|
||
} else {
|
||
// at this point, extra isn't content, so add padding
|
||
val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
|
||
|
||
// at this point, extra isn't content nor padding, so add border
|
||
if ( extra !== "padding" ) {
|
||
val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return val;
|
||
}
|
||
|
||
function getWidthOrHeight( elem, name, extra ) {
|
||
|
||
// Start with offset property, which is equivalent to the border-box value
|
||
var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
|
||
valueIsBorderBox = true,
|
||
isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
|
||
|
||
// some non-html elements return undefined for offsetWidth, so check for null/undefined
|
||
// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
|
||
// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
|
||
if ( val <= 0 || val == null ) {
|
||
// Fall back to computed then uncomputed css if necessary
|
||
val = curCSS( elem, name );
|
||
if ( val < 0 || val == null ) {
|
||
val = elem.style[ name ];
|
||
}
|
||
|
||
// Computed unit is not pixels. Stop here and return.
|
||
if ( rnumnonpx.test(val) ) {
|
||
return val;
|
||
}
|
||
|
||
// we need the check for style in case a browser which returns unreliable values
|
||
// for getComputedStyle silently falls back to the reliable elem.style
|
||
valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
|
||
|
||
// Normalize "", auto, and prepare for extra
|
||
val = parseFloat( val ) || 0;
|
||
}
|
||
|
||
// use the active box-sizing model to add/subtract irrelevant styles
|
||
return ( val +
|
||
augmentWidthOrHeight(
|
||
elem,
|
||
name,
|
||
extra || ( isBorderBox ? "border" : "content" ),
|
||
valueIsBorderBox
|
||
)
|
||
) + "px";
|
||
}
|
||
|
||
|
||
// Try to determine the default display value of an element
|
||
function css_defaultDisplay( nodeName ) {
|
||
if ( elemdisplay[ nodeName ] ) {
|
||
return elemdisplay[ nodeName ];
|
||
}
|
||
|
||
var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ),
|
||
display = elem.css("display");
|
||
elem.remove();
|
||
|
||
// If the simple way fails,
|
||
// get element's real default display by attaching it to a temp iframe
|
||
if ( display === "none" || display === "" ) {
|
||
// Use the already-created iframe if possible
|
||
iframe = document.body.appendChild(
|
||
iframe || jQuery.extend( document.createElement("iframe"), {
|
||
frameBorder: 0,
|
||
width: 0,
|
||
height: 0
|
||
})
|
||
);
|
||
|
||
// Create a cacheable copy of the iframe document on first call.
|
||
// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
|
||
// document to it; WebKit & Firefox won't allow reusing the iframe document.
|
||
if ( !iframeDoc || !iframe.createElement ) {
|
||
iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
|
||
iframeDoc.write("<!doctype html><html><body>");
|
||
iframeDoc.close();
|
||
}
|
||
|
||
elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) );
|
||
|
||
display = curCSS( elem, "display" );
|
||
document.body.removeChild( iframe );
|
||
}
|
||
|
||
// Store the correct default display
|
||
elemdisplay[ nodeName ] = display;
|
||
|
||
return display;
|
||
}
|
||
|
||
jQuery.each([ "height", "width" ], function( i, name ) {
|
||
jQuery.cssHooks[ name ] = {
|
||
get: function( elem, computed, extra ) {
|
||
if ( computed ) {
|
||
// certain elements can have dimension info if we invisibly show them
|
||
// however, it must have a current display style that would benefit from this
|
||
if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) {
|
||
return jQuery.swap( elem, cssShow, function() {
|
||
return getWidthOrHeight( elem, name, extra );
|
||
});
|
||
} else {
|
||
return getWidthOrHeight( elem, name, extra );
|
||
}
|
||
}
|
||
},
|
||
|
||
set: function( elem, value, extra ) {
|
||
return setPositiveNumber( elem, value, extra ?
|
||
augmentWidthOrHeight(
|
||
elem,
|
||
name,
|
||
extra,
|
||
jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"
|
||
) : 0
|
||
);
|
||
}
|
||
};
|
||
});
|
||
|
||
if ( !jQuery.support.opacity ) {
|
||
jQuery.cssHooks.opacity = {
|
||
get: function( elem, computed ) {
|
||
// IE uses filters for opacity
|
||
return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
|
||
( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
|
||
computed ? "1" : "";
|
||
},
|
||
|
||
set: function( elem, value ) {
|
||
var style = elem.style,
|
||
currentStyle = elem.currentStyle,
|
||
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
|
||
// Force it by setting the zoom level
|
||
style.zoom = 1;
|
||
|
||
// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
|
||
if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
|
||
style.removeAttribute ) {
|
||
|
||
// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
|
||
// if "filter:" is present at all, clearType is disabled, we want to avoid this
|
||
// style.removeAttribute is IE Only, but so apparently is this code path...
|
||
style.removeAttribute( "filter" );
|
||
|
||
// if there there is no filter style applied in a css rule, we are done
|
||
if ( currentStyle && !currentStyle.filter ) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
// otherwise, set new filter values
|
||
style.filter = ralpha.test( filter ) ?
|
||
filter.replace( ralpha, opacity ) :
|
||
filter + " " + opacity;
|
||
}
|
||
};
|
||
}
|
||
|
||
// These hooks cannot be added until DOM ready because the support test
|
||
// for it is not run until after DOM ready
|
||
jQuery(function() {
|
||
if ( !jQuery.support.reliableMarginRight ) {
|
||
jQuery.cssHooks.marginRight = {
|
||
get: function( elem, computed ) {
|
||
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
|
||
// Work around by temporarily setting element display to inline-block
|
||
return jQuery.swap( elem, { "display": "inline-block" }, function() {
|
||
if ( computed ) {
|
||
return curCSS( elem, "marginRight" );
|
||
}
|
||
});
|
||
}
|
||
};
|
||
}
|
||
|
||
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
|
||
// getComputedStyle returns percent when specified for top/left/bottom/right
|
||
// rather than make the css module depend on the offset module, we just check for it here
|
||
if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
|
||
jQuery.each( [ "top", "left" ], function( i, prop ) {
|
||
jQuery.cssHooks[ prop ] = {
|
||
get: function( elem, computed ) {
|
||
if ( computed ) {
|
||
var ret = curCSS( elem, prop );
|
||
// if curCSS returns percentage, fallback to offset
|
||
return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret;
|
||
}
|
||
}
|
||
};
|
||
});
|
||
}
|
||
|
||
});
|
||
|
||
if ( jQuery.expr && jQuery.expr.filters ) {
|
||
jQuery.expr.filters.hidden = function( elem ) {
|
||
return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none");
|
||
};
|
||
|
||
jQuery.expr.filters.visible = function( elem ) {
|
||
return !jQuery.expr.filters.hidden( elem );
|
||
};
|
||
}
|
||
|
||
// These hooks are used by animate to expand properties
|
||
jQuery.each({
|
||
margin: "",
|
||
padding: "",
|
||
border: "Width"
|
||
}, function( prefix, suffix ) {
|
||
jQuery.cssHooks[ prefix + suffix ] = {
|
||
expand: function( value ) {
|
||
var i,
|
||
|
||
// assumes a single number if not a string
|
||
parts = typeof value === "string" ? value.split(" ") : [ value ],
|
||
expanded = {};
|
||
|
||
for ( i = 0; i < 4; i++ ) {
|
||
expanded[ prefix + cssExpand[ i ] + suffix ] =
|
||
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
|
||
}
|
||
|
||
return expanded;
|
||
}
|
||
};
|
||
|
||
if ( !rmargin.test( prefix ) ) {
|
||
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
|
||
}
|
||
});
|
||
var r20 = /%20/g,
|
||
rbracket = /\[\]$/,
|
||
rCRLF = /\r?\n/g,
|
||
rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
|
||
rselectTextarea = /^(?:select|textarea)/i;
|
||
|
||
jQuery.fn.extend({
|
||
serialize: function() {
|
||
return jQuery.param( this.serializeArray() );
|
||
},
|
||
serializeArray: function() {
|
||
return this.map(function(){
|
||
return this.elements ? jQuery.makeArray( this.elements ) : this;
|
||
})
|
||
.filter(function(){
|
||
return this.name && !this.disabled &&
|
||
( this.checked || rselectTextarea.test( this.nodeName ) ||
|
||
rinput.test( this.type ) );
|
||
})
|
||
.map(function( i, elem ){
|
||
var val = jQuery( this ).val();
|
||
|
||
return val == null ?
|
||
null :
|
||
jQuery.isArray( val ) ?
|
||
jQuery.map( val, function( val, i ){
|
||
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
||
}) :
|
||
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
||
}).get();
|
||
}
|
||
});
|
||
|
||
//Serialize an array of form elements or a set of
|
||
//key/values into a query string
|
||
jQuery.param = function( a, traditional ) {
|
||
var prefix,
|
||
s = [],
|
||
add = function( key, value ) {
|
||
// If value is a function, invoke it and return its value
|
||
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
|
||
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
|
||
};
|
||
|
||
// Set traditional to true for jQuery <= 1.3.2 behavior.
|
||
if ( traditional === undefined ) {
|
||
traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
|
||
}
|
||
|
||
// If an array was passed in, assume that it is an array of form elements.
|
||
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
|
||
// Serialize the form elements
|
||
jQuery.each( a, function() {
|
||
add( this.name, this.value );
|
||
});
|
||
|
||
} else {
|
||
// If traditional, encode the "old" way (the way 1.3.2 or older
|
||
// did it), otherwise encode params recursively.
|
||
for ( prefix in a ) {
|
||
buildParams( prefix, a[ prefix ], traditional, add );
|
||
}
|
||
}
|
||
|
||
// Return the resulting serialization
|
||
return s.join( "&" ).replace( r20, "+" );
|
||
};
|
||
|
||
function buildParams( prefix, obj, traditional, add ) {
|
||
var name;
|
||
|
||
if ( jQuery.isArray( obj ) ) {
|
||
// Serialize array item.
|
||
jQuery.each( obj, function( i, v ) {
|
||
if ( traditional || rbracket.test( prefix ) ) {
|
||
// Treat each array item as a scalar.
|
||
add( prefix, v );
|
||
|
||
} else {
|
||
// If array item is non-scalar (array or object), encode its
|
||
// numeric index to resolve deserialization ambiguity issues.
|
||
// Note that rack (as of 1.0.0) can't currently deserialize
|
||
// nested arrays properly, and attempting to do so may cause
|
||
// a server error. Possible fixes are to modify rack's
|
||
// deserialization algorithm or to provide an option or flag
|
||
// to force array serialization to be shallow.
|
||
buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
|
||
}
|
||
});
|
||
|
||
} else if ( !traditional && jQuery.type( obj ) === "object" ) {
|
||
// Serialize object item.
|
||
for ( name in obj ) {
|
||
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
|
||
}
|
||
|
||
} else {
|
||
// Serialize scalar item.
|
||
add( prefix, obj );
|
||
}
|
||
}
|
||
var
|
||
// Document location
|
||
ajaxLocParts,
|
||
ajaxLocation,
|
||
|
||
rhash = /#.*$/,
|
||
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
|
||
// #7653, #8125, #8152: local protocol detection
|
||
rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
|
||
rnoContent = /^(?:GET|HEAD)$/,
|
||
rprotocol = /^\/\//,
|
||
rquery = /\?/,
|
||
rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||
rts = /([?&])_=[^&]*/,
|
||
rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
|
||
|
||
// Keep a copy of the old load method
|
||
_load = jQuery.fn.load,
|
||
|
||
/* Prefilters
|
||
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
|
||
* 2) These are called:
|
||
* - BEFORE asking for a transport
|
||
* - AFTER param serialization (s.data is a string if s.processData is true)
|
||
* 3) key is the dataType
|
||
* 4) the catchall symbol "*" can be used
|
||
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
|
||
*/
|
||
prefilters = {},
|
||
|
||
/* Transports bindings
|
||
* 1) key is the dataType
|
||
* 2) the catchall symbol "*" can be used
|
||
* 3) selection will start with transport dataType and THEN go to "*" if needed
|
||
*/
|
||
transports = {},
|
||
|
||
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
|
||
allTypes = ["*/"] + ["*"];
|
||
|
||
// #8138, IE may throw an exception when accessing
|
||
// a field from window.location if document.domain has been set
|
||
try {
|
||
ajaxLocation = location.href;
|
||
} catch( e ) {
|
||
// Use the href attribute of an A element
|
||
// since IE will modify it given document.location
|
||
ajaxLocation = document.createElement( "a" );
|
||
ajaxLocation.href = "";
|
||
ajaxLocation = ajaxLocation.href;
|
||
}
|
||
|
||
// Segment location into parts
|
||
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
|
||
|
||
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
|
||
function addToPrefiltersOrTransports( structure ) {
|
||
|
||
// dataTypeExpression is optional and defaults to "*"
|
||
return function( dataTypeExpression, func ) {
|
||
|
||
if ( typeof dataTypeExpression !== "string" ) {
|
||
func = dataTypeExpression;
|
||
dataTypeExpression = "*";
|
||
}
|
||
|
||
var dataType, list, placeBefore,
|
||
dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ),
|
||
i = 0,
|
||
length = dataTypes.length;
|
||
|
||
if ( jQuery.isFunction( func ) ) {
|
||
// For each dataType in the dataTypeExpression
|
||
for ( ; i < length; i++ ) {
|
||
dataType = dataTypes[ i ];
|
||
// We control if we're asked to add before
|
||
// any existing element
|
||
placeBefore = /^\+/.test( dataType );
|
||
if ( placeBefore ) {
|
||
dataType = dataType.substr( 1 ) || "*";
|
||
}
|
||
list = structure[ dataType ] = structure[ dataType ] || [];
|
||
// then we add to the structure accordingly
|
||
list[ placeBefore ? "unshift" : "push" ]( func );
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
// Base inspection function for prefilters and transports
|
||
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
|
||
dataType /* internal */, inspected /* internal */ ) {
|
||
|
||
dataType = dataType || options.dataTypes[ 0 ];
|
||
inspected = inspected || {};
|
||
|
||
inspected[ dataType ] = true;
|
||
|
||
var selection,
|
||
list = structure[ dataType ],
|
||
i = 0,
|
||
length = list ? list.length : 0,
|
||
executeOnly = ( structure === prefilters );
|
||
|
||
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
|
||
if ( typeof selection === "string" ) {
|
||
if ( !executeOnly || inspected[ selection ] ) {
|
||
selection = undefined;
|
||
} else {
|
||
options.dataTypes.unshift( selection );
|
||
selection = inspectPrefiltersOrTransports(
|
||
structure, options, originalOptions, jqXHR, selection, inspected );
|
||
}
|
||
}
|
||
}
|
||
// If we're only executing or nothing was selected
|
||
// we try the catchall dataType if not done already
|
||
if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
|
||
selection = inspectPrefiltersOrTransports(
|
||
structure, options, originalOptions, jqXHR, "*", inspected );
|
||
}
|
||
// unnecessary when only executing (prefilters)
|
||
// but it'll be ignored by the caller in that case
|
||
return selection;
|
||
}
|
||
|
||
// A special extend for ajax options
|
||
// that takes "flat" options (not to be deep extended)
|
||
// Fixes #9887
|
||
function ajaxExtend( target, src ) {
|
||
var key, deep,
|
||
flatOptions = jQuery.ajaxSettings.flatOptions || {};
|
||
for ( key in src ) {
|
||
if ( src[ key ] !== undefined ) {
|
||
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
|
||
}
|
||
}
|
||
if ( deep ) {
|
||
jQuery.extend( true, target, deep );
|
||
}
|
||
}
|
||
|
||
jQuery.fn.load = function( url, params, callback ) {
|
||
if ( typeof url !== "string" && _load ) {
|
||
return _load.apply( this, arguments );
|
||
}
|
||
|
||
// Don't do a request if no elements are being requested
|
||
if ( !this.length ) {
|
||
return this;
|
||
}
|
||
|
||
var selector, type, response,
|
||
self = this,
|
||
off = url.indexOf(" ");
|
||
|
||
if ( off >= 0 ) {
|
||
selector = url.slice( off, url.length );
|
||
url = url.slice( 0, off );
|
||
}
|
||
|
||
// If it's a function
|
||
if ( jQuery.isFunction( params ) ) {
|
||
|
||
// We assume that it's the callback
|
||
callback = params;
|
||
params = undefined;
|
||
|
||
// Otherwise, build a param string
|
||
} else if ( params && typeof params === "object" ) {
|
||
type = "POST";
|
||
}
|
||
|
||
// Request the remote document
|
||
jQuery.ajax({
|
||
url: url,
|
||
|
||
// if "type" variable is undefined, then "GET" method will be used
|
||
type: type,
|
||
dataType: "html",
|
||
data: params,
|
||
complete: function( jqXHR, status ) {
|
||
if ( callback ) {
|
||
self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
|
||
}
|
||
}
|
||
}).done(function( responseText ) {
|
||
|
||
// Save response for use in complete callback
|
||
response = arguments;
|
||
|
||
// See if a selector was specified
|
||
self.html( selector ?
|
||
|
||
// Create a dummy div to hold the results
|
||
jQuery("<div>")
|
||
|
||
// inject the contents of the document in, removing the scripts
|
||
// to avoid any 'Permission Denied' errors in IE
|
||
.append( responseText.replace( rscript, "" ) )
|
||
|
||
// Locate the specified elements
|
||
.find( selector ) :
|
||
|
||
// If not, just inject the full result
|
||
responseText );
|
||
|
||
});
|
||
|
||
return this;
|
||
};
|
||
|
||
// 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.on( o, f );
|
||
};
|
||
});
|
||
|
||
jQuery.each( [ "get", "post" ], function( i, method ) {
|
||
jQuery[ method ] = function( url, data, callback, type ) {
|
||
// shift arguments if data argument was omitted
|
||
if ( jQuery.isFunction( data ) ) {
|
||
type = type || callback;
|
||
callback = data;
|
||
data = undefined;
|
||
}
|
||
|
||
return jQuery.ajax({
|
||
type: method,
|
||
url: url,
|
||
data: data,
|
||
success: callback,
|
||
dataType: type
|
||
});
|
||
};
|
||
});
|
||
|
||
jQuery.extend({
|
||
|
||
getScript: function( url, callback ) {
|
||
return jQuery.get( url, undefined, callback, "script" );
|
||
},
|
||
|
||
getJSON: function( url, data, callback ) {
|
||
return jQuery.get( url, data, callback, "json" );
|
||
},
|
||
|
||
// Creates a full fledged settings object into target
|
||
// with both ajaxSettings and settings fields.
|
||
// If target is omitted, writes into ajaxSettings.
|
||
ajaxSetup: function( target, settings ) {
|
||
if ( settings ) {
|
||
// Building a settings object
|
||
ajaxExtend( target, jQuery.ajaxSettings );
|
||
} else {
|
||
// Extending ajaxSettings
|
||
settings = target;
|
||
target = jQuery.ajaxSettings;
|
||
}
|
||
ajaxExtend( target, settings );
|
||
return target;
|
||
},
|
||
|
||
ajaxSettings: {
|
||
url: ajaxLocation,
|
||
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
|
||
global: true,
|
||
type: "GET",
|
||
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
||
processData: true,
|
||
async: true,
|
||
/*
|
||
timeout: 0,
|
||
data: null,
|
||
dataType: null,
|
||
username: null,
|
||
password: null,
|
||
cache: null,
|
||
throws: false,
|
||
traditional: false,
|
||
headers: {},
|
||
*/
|
||
|
||
accepts: {
|
||
xml: "application/xml, text/xml",
|
||
html: "text/html",
|
||
text: "text/plain",
|
||
json: "application/json, text/javascript",
|
||
"*": allTypes
|
||
},
|
||
|
||
contents: {
|
||
xml: /xml/,
|
||
html: /html/,
|
||
json: /json/
|
||
},
|
||
|
||
responseFields: {
|
||
xml: "responseXML",
|
||
text: "responseText"
|
||
},
|
||
|
||
// List of data converters
|
||
// 1) key format is "source_type destination_type" (a single space in-between)
|
||
// 2) the catchall symbol "*" can be used for source_type
|
||
converters: {
|
||
|
||
// Convert anything to text
|
||
"* text": window.String,
|
||
|
||
// Text to html (true = no transformation)
|
||
"text html": true,
|
||
|
||
// Evaluate text as a json expression
|
||
"text json": jQuery.parseJSON,
|
||
|
||
// Parse text as xml
|
||
"text xml": jQuery.parseXML
|
||
},
|
||
|
||
// For options that shouldn't be deep extended:
|
||
// you can add your own custom options here if
|
||
// and when you create one that shouldn't be
|
||
// deep extended (see ajaxExtend)
|
||
flatOptions: {
|
||
context: true,
|
||
url: true
|
||
}
|
||
},
|
||
|
||
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
|
||
ajaxTransport: addToPrefiltersOrTransports( transports ),
|
||
|
||
// Main method
|
||
ajax: function( url, options ) {
|
||
|
||
// If url is an object, simulate pre-1.5 signature
|
||
if ( typeof url === "object" ) {
|
||
options = url;
|
||
url = undefined;
|
||
}
|
||
|
||
// Force options to be an object
|
||
options = options || {};
|
||
|
||
var // ifModified key
|
||
ifModifiedKey,
|
||
// Response headers
|
||
responseHeadersString,
|
||
responseHeaders,
|
||
// transport
|
||
transport,
|
||
// timeout handle
|
||
timeoutTimer,
|
||
// Cross-domain detection vars
|
||
parts,
|
||
// To know if global events are to be dispatched
|
||
fireGlobals,
|
||
// Loop variable
|
||
i,
|
||
// Create the final options object
|
||
s = jQuery.ajaxSetup( {}, options ),
|
||
// Callbacks context
|
||
callbackContext = s.context || s,
|
||
// Context for global events
|
||
// It's the callbackContext if one was provided in the options
|
||
// and if it's a DOM node or a jQuery collection
|
||
globalEventContext = callbackContext !== s &&
|
||
( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
|
||
jQuery( callbackContext ) : jQuery.event,
|
||
// Deferreds
|
||
deferred = jQuery.Deferred(),
|
||
completeDeferred = jQuery.Callbacks( "once memory" ),
|
||
// Status-dependent callbacks
|
||
statusCode = s.statusCode || {},
|
||
// Headers (they are sent all at once)
|
||
requestHeaders = {},
|
||
requestHeadersNames = {},
|
||
// The jqXHR state
|
||
state = 0,
|
||
// Default abort message
|
||
strAbort = "canceled",
|
||
// Fake xhr
|
||
jqXHR = {
|
||
|
||
readyState: 0,
|
||
|
||
// Caches the header
|
||
setRequestHeader: function( name, value ) {
|
||
if ( !state ) {
|
||
var lname = name.toLowerCase();
|
||
name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
|
||
requestHeaders[ name ] = value;
|
||
}
|
||
return this;
|
||
},
|
||
|
||
// Raw string
|
||
getAllResponseHeaders: function() {
|
||
return state === 2 ? responseHeadersString : null;
|
||
},
|
||
|
||
// Builds headers hashtable if needed
|
||
getResponseHeader: function( key ) {
|
||
var match;
|
||
if ( state === 2 ) {
|
||
if ( !responseHeaders ) {
|
||
responseHeaders = {};
|
||
while( ( match = rheaders.exec( responseHeadersString ) ) ) {
|
||
responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
|
||
}
|
||
}
|
||
match = responseHeaders[ key.toLowerCase() ];
|
||
}
|
||
return match === undefined ? null : match;
|
||
},
|
||
|
||
// Overrides response content-type header
|
||
overrideMimeType: function( type ) {
|
||
if ( !state ) {
|
||
s.mimeType = type;
|
||
}
|
||
return this;
|
||
},
|
||
|
||
// Cancel the request
|
||
abort: function( statusText ) {
|
||
statusText = statusText || strAbort;
|
||
if ( transport ) {
|
||
transport.abort( statusText );
|
||
}
|
||
done( 0, statusText );
|
||
return this;
|
||
}
|
||
};
|
||
|
||
// Callback for when everything is done
|
||
// It is defined here because jslint complains if it is declared
|
||
// at the end of the function (which would be more logical and readable)
|
||
function done( status, nativeStatusText, responses, headers ) {
|
||
var isSuccess, success, error, response, modified,
|
||
statusText = nativeStatusText;
|
||
|
||
// Called once
|
||
if ( state === 2 ) {
|
||
return;
|
||
}
|
||
|
||
// State is "done" now
|
||
state = 2;
|
||
|
||
// Clear timeout if it exists
|
||
if ( timeoutTimer ) {
|
||
clearTimeout( timeoutTimer );
|
||
}
|
||
|
||
// Dereference transport for early garbage collection
|
||
// (no matter how long the jqXHR object will be used)
|
||
transport = undefined;
|
||
|
||
// Cache response headers
|
||
responseHeadersString = headers || "";
|
||
|
||
// Set readyState
|
||
jqXHR.readyState = status > 0 ? 4 : 0;
|
||
|
||
// Get response data
|
||
if ( responses ) {
|
||
response = ajaxHandleResponses( s, jqXHR, responses );
|
||
}
|
||
|
||
// If successful, handle type chaining
|
||
if ( status >= 200 && status < 300 || status === 304 ) {
|
||
|
||
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
||
if ( s.ifModified ) {
|
||
|
||
modified = jqXHR.getResponseHeader("Last-Modified");
|
||
if ( modified ) {
|
||
jQuery.lastModified[ ifModifiedKey ] = modified;
|
||
}
|
||
modified = jqXHR.getResponseHeader("Etag");
|
||
if ( modified ) {
|
||
jQuery.etag[ ifModifiedKey ] = modified;
|
||
}
|
||
}
|
||
|
||
// If not modified
|
||
if ( status === 304 ) {
|
||
|
||
statusText = "notmodified";
|
||
isSuccess = true;
|
||
|
||
// If we have data
|
||
} else {
|
||
|
||
isSuccess = ajaxConvert( s, response );
|
||
statusText = isSuccess.state;
|
||
success = isSuccess.data;
|
||
error = isSuccess.error;
|
||
isSuccess = !error;
|
||
}
|
||
} else {
|
||
// We extract error from statusText
|
||
// then normalize statusText and status for non-aborts
|
||
error = statusText;
|
||
if ( !statusText || status ) {
|
||
statusText = "error";
|
||
if ( status < 0 ) {
|
||
status = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Set data for the fake xhr object
|
||
jqXHR.status = status;
|
||
jqXHR.statusText = ( nativeStatusText || statusText ) + "";
|
||
|
||
// Success/Error
|
||
if ( isSuccess ) {
|
||
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
|
||
} else {
|
||
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
|
||
}
|
||
|
||
// Status-dependent callbacks
|
||
jqXHR.statusCode( statusCode );
|
||
statusCode = undefined;
|
||
|
||
if ( fireGlobals ) {
|
||
globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
|
||
[ jqXHR, s, isSuccess ? success : error ] );
|
||
}
|
||
|
||
// Complete
|
||
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
|
||
|
||
if ( fireGlobals ) {
|
||
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
|
||
// Handle the global AJAX counter
|
||
if ( !( --jQuery.active ) ) {
|
||
jQuery.event.trigger( "ajaxStop" );
|
||
}
|
||
}
|
||
}
|
||
|
||
// Attach deferreds
|
||
deferred.promise( jqXHR );
|
||
jqXHR.success = jqXHR.done;
|
||
jqXHR.error = jqXHR.fail;
|
||
jqXHR.complete = completeDeferred.add;
|
||
|
||
// Status-dependent callbacks
|
||
jqXHR.statusCode = function( map ) {
|
||
if ( map ) {
|
||
var tmp;
|
||
if ( state < 2 ) {
|
||
for ( tmp in map ) {
|
||
statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
|
||
}
|
||
} else {
|
||
tmp = map[ jqXHR.status ];
|
||
jqXHR.always( tmp );
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// Remove hash character (#7531: and string promotion)
|
||
// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
|
||
// We also use the url parameter if available
|
||
s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
|
||
|
||
// Extract dataTypes list
|
||
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace );
|
||
|
||
// A cross-domain request is in order when we have a protocol:host:port mismatch
|
||
if ( s.crossDomain == null ) {
|
||
parts = rurl.exec( s.url.toLowerCase() );
|
||
s.crossDomain = !!( parts &&
|
||
( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
|
||
( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
|
||
( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
|
||
);
|
||
}
|
||
|
||
// Convert data if not already a string
|
||
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
||
s.data = jQuery.param( s.data, s.traditional );
|
||
}
|
||
|
||
// Apply prefilters
|
||
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
|
||
|
||
// If request was aborted inside a prefilter, stop there
|
||
if ( state === 2 ) {
|
||
return jqXHR;
|
||
}
|
||
|
||
// We can fire global events as of now if asked to
|
||
fireGlobals = s.global;
|
||
|
||
// Uppercase the type
|
||
s.type = s.type.toUpperCase();
|
||
|
||
// Determine if request has content
|
||
s.hasContent = !rnoContent.test( s.type );
|
||
|
||
// Watch for a new set of requests
|
||
if ( fireGlobals && jQuery.active++ === 0 ) {
|
||
jQuery.event.trigger( "ajaxStart" );
|
||
}
|
||
|
||
// More options handling for requests with no content
|
||
if ( !s.hasContent ) {
|
||
|
||
// If data is available, append data to url
|
||
if ( s.data ) {
|
||
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
|
||
// #9682: remove data so that it's not used in an eventual retry
|
||
delete s.data;
|
||
}
|
||
|
||
// Get ifModifiedKey before adding the anti-cache parameter
|
||
ifModifiedKey = s.url;
|
||
|
||
// Add anti-cache in url if needed
|
||
if ( s.cache === false ) {
|
||
|
||
var ts = jQuery.now(),
|
||
// try replacing _= if it is there
|
||
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 : "" );
|
||
}
|
||
}
|
||
|
||
// Set the correct header, if data is being sent
|
||
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
|
||
jqXHR.setRequestHeader( "Content-Type", s.contentType );
|
||
}
|
||
|
||
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
||
if ( s.ifModified ) {
|
||
ifModifiedKey = ifModifiedKey || s.url;
|
||
if ( jQuery.lastModified[ ifModifiedKey ] ) {
|
||
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
|
||
}
|
||
if ( jQuery.etag[ ifModifiedKey ] ) {
|
||
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
|
||
}
|
||
}
|
||
|
||
// Set the Accepts header for the server, depending on the dataType
|
||
jqXHR.setRequestHeader(
|
||
"Accept",
|
||
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
|
||
s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
|
||
s.accepts[ "*" ]
|
||
);
|
||
|
||
// Check for headers option
|
||
for ( i in s.headers ) {
|
||
jqXHR.setRequestHeader( i, s.headers[ i ] );
|
||
}
|
||
|
||
// Allow custom headers/mimetypes and early abort
|
||
if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
|
||
// Abort if not done already and return
|
||
return jqXHR.abort();
|
||
|
||
}
|
||
|
||
// aborting is no longer a cancellation
|
||
strAbort = "abort";
|
||
|
||
// Install callbacks on deferreds
|
||
for ( i in { success: 1, error: 1, complete: 1 } ) {
|
||
jqXHR[ i ]( s[ i ] );
|
||
}
|
||
|
||
// Get transport
|
||
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
|
||
|
||
// If no transport, we auto-abort
|
||
if ( !transport ) {
|
||
done( -1, "No Transport" );
|
||
} else {
|
||
jqXHR.readyState = 1;
|
||
// Send global event
|
||
if ( fireGlobals ) {
|
||
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
|
||
}
|
||
// Timeout
|
||
if ( s.async && s.timeout > 0 ) {
|
||
timeoutTimer = setTimeout( function(){
|
||
jqXHR.abort( "timeout" );
|
||
}, s.timeout );
|
||
}
|
||
|
||
try {
|
||
state = 1;
|
||
transport.send( requestHeaders, done );
|
||
} catch (e) {
|
||
// Propagate exception as error if not done
|
||
if ( state < 2 ) {
|
||
done( -1, e );
|
||
// Simply rethrow otherwise
|
||
} else {
|
||
throw e;
|
||
}
|
||
}
|
||
}
|
||
|
||
return jqXHR;
|
||
},
|
||
|
||
// Counter for holding the number of active queries
|
||
active: 0,
|
||
|
||
// Last-Modified header cache for next request
|
||
lastModified: {},
|
||
etag: {}
|
||
|
||
});
|
||
|
||
/* Handles responses to an ajax request:
|
||
* - sets all responseXXX fields accordingly
|
||
* - finds the right dataType (mediates between content-type and expected dataType)
|
||
* - returns the corresponding response
|
||
*/
|
||
function ajaxHandleResponses( s, jqXHR, responses ) {
|
||
|
||
var ct, type, finalDataType, firstDataType,
|
||
contents = s.contents,
|
||
dataTypes = s.dataTypes,
|
||
responseFields = s.responseFields;
|
||
|
||
// Fill responseXXX fields
|
||
for ( type in responseFields ) {
|
||
if ( type in responses ) {
|
||
jqXHR[ responseFields[type] ] = responses[ type ];
|
||
}
|
||
}
|
||
|
||
// Remove auto dataType and get content-type in the process
|
||
while( dataTypes[ 0 ] === "*" ) {
|
||
dataTypes.shift();
|
||
if ( ct === undefined ) {
|
||
ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
|
||
}
|
||
}
|
||
|
||
// Check if we're dealing with a known content-type
|
||
if ( ct ) {
|
||
for ( type in contents ) {
|
||
if ( contents[ type ] && contents[ type ].test( ct ) ) {
|
||
dataTypes.unshift( type );
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Check to see if we have a response for the expected dataType
|
||
if ( dataTypes[ 0 ] in responses ) {
|
||
finalDataType = dataTypes[ 0 ];
|
||
} else {
|
||
// Try convertible dataTypes
|
||
for ( type in responses ) {
|
||
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
|
||
finalDataType = type;
|
||
break;
|
||
}
|
||
if ( !firstDataType ) {
|
||
firstDataType = type;
|
||
}
|
||
}
|
||
// Or just use first one
|
||
finalDataType = finalDataType || firstDataType;
|
||
}
|
||
|
||
// If we found a dataType
|
||
// We add the dataType to the list if needed
|
||
// and return the corresponding response
|
||
if ( finalDataType ) {
|
||
if ( finalDataType !== dataTypes[ 0 ] ) {
|
||
dataTypes.unshift( finalDataType );
|
||
}
|
||
return responses[ finalDataType ];
|
||
}
|
||
}
|
||
|
||
// Chain conversions given the request and the original response
|
||
function ajaxConvert( s, response ) {
|
||
|
||
var conv, conv2, current, tmp,
|
||
// Work with a copy of dataTypes in case we need to modify it for conversion
|
||
dataTypes = s.dataTypes.slice(),
|
||
prev = dataTypes[ 0 ],
|
||
converters = {},
|
||
i = 0;
|
||
|
||
// Apply the dataFilter if provided
|
||
if ( s.dataFilter ) {
|
||
response = s.dataFilter( response, s.dataType );
|
||
}
|
||
|
||
// Create converters map with lowercased keys
|
||
if ( dataTypes[ 1 ] ) {
|
||
for ( conv in s.converters ) {
|
||
converters[ conv.toLowerCase() ] = s.converters[ conv ];
|
||
}
|
||
}
|
||
|
||
// Convert to each sequential dataType, tolerating list modification
|
||
for ( ; (current = dataTypes[++i]); ) {
|
||
|
||
// There's only work to do if current dataType is non-auto
|
||
if ( current !== "*" ) {
|
||
|
||
// Convert response if prev dataType is non-auto and differs from current
|
||
if ( prev !== "*" && prev !== current ) {
|
||
|
||
// Seek a direct converter
|
||
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
|
||
|
||
// If none found, seek a pair
|
||
if ( !conv ) {
|
||
for ( conv2 in converters ) {
|
||
|
||
// If conv2 outputs current
|
||
tmp = conv2.split(" ");
|
||
if ( tmp[ 1 ] === current ) {
|
||
|
||
// If prev can be converted to accepted input
|
||
conv = converters[ prev + " " + tmp[ 0 ] ] ||
|
||
converters[ "* " + tmp[ 0 ] ];
|
||
if ( conv ) {
|
||
// Condense equivalence converters
|
||
if ( conv === true ) {
|
||
conv = converters[ conv2 ];
|
||
|
||
// Otherwise, insert the intermediate dataType
|
||
} else if ( converters[ conv2 ] !== true ) {
|
||
current = tmp[ 0 ];
|
||
dataTypes.splice( i--, 0, current );
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Apply converter (if not an equivalence)
|
||
if ( conv !== true ) {
|
||
|
||
// Unless errors are allowed to bubble, catch and return them
|
||
if ( conv && s["throws"] ) {
|
||
response = conv( response );
|
||
} else {
|
||
try {
|
||
response = conv( response );
|
||
} catch ( e ) {
|
||
return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Update prev for next iteration
|
||
prev = current;
|
||
}
|
||
}
|
||
|
||
return { state: "success", data: response };
|
||
}
|
||
var oldCallbacks = [],
|
||
rquestion = /\?/,
|
||
rjsonp = /(=)\?(?=&|$)|\?\?/,
|
||
nonce = jQuery.now();
|
||
|
||
// Default jsonp settings
|
||
jQuery.ajaxSetup({
|
||
jsonp: "callback",
|
||
jsonpCallback: function() {
|
||
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
|
||
this[ callback ] = true;
|
||
return callback;
|
||
}
|
||
});
|
||
|
||
// Detect, normalize options and install callbacks for jsonp requests
|
||
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
|
||
|
||
var callbackName, overwritten, responseContainer,
|
||
data = s.data,
|
||
url = s.url,
|
||
hasCallback = s.jsonp !== false,
|
||
replaceInUrl = hasCallback && rjsonp.test( url ),
|
||
replaceInData = hasCallback && !replaceInUrl && typeof data === "string" &&
|
||
!( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") &&
|
||
rjsonp.test( data );
|
||
|
||
// Handle iff the expected data type is "jsonp" or we have a parameter to set
|
||
if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) {
|
||
|
||
// Get callback name, remembering preexisting value associated with it
|
||
callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
|
||
s.jsonpCallback() :
|
||
s.jsonpCallback;
|
||
overwritten = window[ callbackName ];
|
||
|
||
// Insert callback into url or form data
|
||
if ( replaceInUrl ) {
|
||
s.url = url.replace( rjsonp, "$1" + callbackName );
|
||
} else if ( replaceInData ) {
|
||
s.data = data.replace( rjsonp, "$1" + callbackName );
|
||
} else if ( hasCallback ) {
|
||
s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
|
||
}
|
||
|
||
// Use data converter to retrieve json after script execution
|
||
s.converters["script json"] = function() {
|
||
if ( !responseContainer ) {
|
||
jQuery.error( callbackName + " was not called" );
|
||
}
|
||
return responseContainer[ 0 ];
|
||
};
|
||
|
||
// force json dataType
|
||
s.dataTypes[ 0 ] = "json";
|
||
|
||
// Install callback
|
||
window[ callbackName ] = function() {
|
||
responseContainer = arguments;
|
||
};
|
||
|
||
// Clean-up function (fires after converters)
|
||
jqXHR.always(function() {
|
||
// Restore preexisting value
|
||
window[ callbackName ] = overwritten;
|
||
|
||
// Save back as free
|
||
if ( s[ callbackName ] ) {
|
||
// make sure that re-using the options doesn't screw things around
|
||
s.jsonpCallback = originalSettings.jsonpCallback;
|
||
|
||
// save the callback name for future use
|
||
oldCallbacks.push( callbackName );
|
||
}
|
||
|
||
// Call if it was a function and we have a response
|
||
if ( responseContainer && jQuery.isFunction( overwritten ) ) {
|
||
overwritten( responseContainer[ 0 ] );
|
||
}
|
||
|
||
responseContainer = overwritten = undefined;
|
||
});
|
||
|
||
// Delegate to script
|
||
return "script";
|
||
}
|
||
});
|
||
// Install script dataType
|
||
jQuery.ajaxSetup({
|
||
accepts: {
|
||
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
|
||
},
|
||
contents: {
|
||
script: /javascript|ecmascript/
|
||
},
|
||
converters: {
|
||
"text script": function( text ) {
|
||
jQuery.globalEval( text );
|
||
return text;
|
||
}
|
||
}
|
||
});
|
||
|
||
// Handle cache's special case and global
|
||
jQuery.ajaxPrefilter( "script", function( s ) {
|
||
if ( s.cache === undefined ) {
|
||
s.cache = false;
|
||
}
|
||
if ( s.crossDomain ) {
|
||
s.type = "GET";
|
||
s.global = false;
|
||
}
|
||
});
|
||
|
||
// Bind script tag hack transport
|
||
jQuery.ajaxTransport( "script", function(s) {
|
||
|
||
// This transport only deals with cross domain requests
|
||
if ( s.crossDomain ) {
|
||
|
||
var script,
|
||
head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
|
||
|
||
return {
|
||
|
||
send: function( _, callback ) {
|
||
|
||
script = document.createElement( "script" );
|
||
|
||
script.async = "async";
|
||
|
||
if ( s.scriptCharset ) {
|
||
script.charset = s.scriptCharset;
|
||
}
|
||
|
||
script.src = s.url;
|
||
|
||
// Attach handlers for all browsers
|
||
script.onload = script.onreadystatechange = function( _, isAbort ) {
|
||
|
||
if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
|
||
|
||
// Handle memory leak in IE
|
||
script.onload = script.onreadystatechange = null;
|
||
|
||
// Remove the script
|
||
if ( head && script.parentNode ) {
|
||
head.removeChild( script );
|
||
}
|
||
|
||
// Dereference the script
|
||
script = undefined;
|
||
|
||
// Callback if not abort
|
||
if ( !isAbort ) {
|
||
callback( 200, "success" );
|
||
}
|
||
}
|
||
};
|
||
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
|
||
// This arises when a base node is used (#2709 and #4378).
|
||
head.insertBefore( script, head.firstChild );
|
||
},
|
||
|
||
abort: function() {
|
||
if ( script ) {
|
||
script.onload( 0, 1 );
|
||
}
|
||
}
|
||
};
|
||
}
|
||
});
|
||
var xhrCallbacks,
|
||
// #5280: Internet Explorer will keep connections alive if we don't abort on unload
|
||
xhrOnUnloadAbort = window.ActiveXObject ? function() {
|
||
// Abort all pending requests
|
||
for ( var key in xhrCallbacks ) {
|
||
xhrCallbacks[ key ]( 0, 1 );
|
||
}
|
||
} : false,
|
||
xhrId = 0;
|
||
|
||
// Functions to create xhrs
|
||
function createStandardXHR() {
|
||
try {
|
||
return new window.XMLHttpRequest();
|
||
} catch( e ) {}
|
||
}
|
||
|
||
function createActiveXHR() {
|
||
try {
|
||
return new window.ActiveXObject( "Microsoft.XMLHTTP" );
|
||
} catch( e ) {}
|
||
}
|
||
|
||
// Create the request object
|
||
// (This is still attached to ajaxSettings for backward compatibility)
|
||
jQuery.ajaxSettings.xhr = window.ActiveXObject ?
|
||
/* Microsoft failed to properly
|
||
* implement the XMLHttpRequest in IE7 (can't request local files),
|
||
* so we use the ActiveXObject when it is available
|
||
* Additionally XMLHttpRequest can be disabled in IE7/IE8 so
|
||
* we need a fallback.
|
||
*/
|
||
function() {
|
||
return !this.isLocal && createStandardXHR() || createActiveXHR();
|
||
} :
|
||
// For all other browsers, use the standard XMLHttpRequest object
|
||
createStandardXHR;
|
||
|
||
// Determine support properties
|
||
(function( xhr ) {
|
||
jQuery.extend( jQuery.support, {
|
||
ajax: !!xhr,
|
||
cors: !!xhr && ( "withCredentials" in xhr )
|
||
});
|
||
})( jQuery.ajaxSettings.xhr() );
|
||
|
||
// Create transport if the browser can provide an xhr
|
||
if ( jQuery.support.ajax ) {
|
||
|
||
jQuery.ajaxTransport(function( s ) {
|
||
// Cross domain only allowed if supported through XMLHttpRequest
|
||
if ( !s.crossDomain || jQuery.support.cors ) {
|
||
|
||
var callback;
|
||
|
||
return {
|
||
send: function( headers, complete ) {
|
||
|
||
// Get a new xhr
|
||
var handle, i,
|
||
xhr = s.xhr();
|
||
|
||
// Open the socket
|
||
// Passing null username, generates a login popup on Opera (#2865)
|
||
if ( s.username ) {
|
||
xhr.open( s.type, s.url, s.async, s.username, s.password );
|
||
} else {
|
||
xhr.open( s.type, s.url, s.async );
|
||
}
|
||
|
||
// Apply custom fields if provided
|
||
if ( s.xhrFields ) {
|
||
for ( i in s.xhrFields ) {
|
||
xhr[ i ] = s.xhrFields[ i ];
|
||
}
|
||
}
|
||
|
||
// Override mime type if needed
|
||
if ( s.mimeType && xhr.overrideMimeType ) {
|
||
xhr.overrideMimeType( s.mimeType );
|
||
}
|
||
|
||
// X-Requested-With header
|
||
// For cross-domain requests, seeing as conditions for a preflight are
|
||
// akin to a jigsaw puzzle, we simply never set it to be sure.
|
||
// (it can always be set on a per-request basis or even using ajaxSetup)
|
||
// For same-domain requests, won't change header if already provided.
|
||
if ( !s.crossDomain && !headers["X-Requested-With"] ) {
|
||
headers[ "X-Requested-With" ] = "XMLHttpRequest";
|
||
}
|
||
|
||
// Need an extra try/catch for cross domain requests in Firefox 3
|
||
try {
|
||
for ( i in headers ) {
|
||
xhr.setRequestHeader( i, headers[ i ] );
|
||
}
|
||
} catch( _ ) {}
|
||
|
||
// Do send the request
|
||
// This may raise an exception which is actually
|
||
// handled in jQuery.ajax (so no try/catch here)
|
||
xhr.send( ( s.hasContent && s.data ) || null );
|
||
|
||
// Listener
|
||
callback = function( _, isAbort ) {
|
||
|
||
var status,
|
||
statusText,
|
||
responseHeaders,
|
||
responses,
|
||
xml;
|
||
|
||
// Firefox throws exceptions when accessing properties
|
||
// of an xhr when a network error occurred
|
||
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
|
||
try {
|
||
|
||
// Was never called and is aborted or complete
|
||
if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
|
||
|
||
// Only called once
|
||
callback = undefined;
|
||
|
||
// Do not keep as active anymore
|
||
if ( handle ) {
|
||
xhr.onreadystatechange = jQuery.noop;
|
||
if ( xhrOnUnloadAbort ) {
|
||
delete xhrCallbacks[ handle ];
|
||
}
|
||
}
|
||
|
||
// If it's an abort
|
||
if ( isAbort ) {
|
||
// Abort it manually if needed
|
||
if ( xhr.readyState !== 4 ) {
|
||
xhr.abort();
|
||
}
|
||
} else {
|
||
status = xhr.status;
|
||
responseHeaders = xhr.getAllResponseHeaders();
|
||
responses = {};
|
||
xml = xhr.responseXML;
|
||
|
||
// Construct response list
|
||
if ( xml && xml.documentElement /* #4958 */ ) {
|
||
responses.xml = xml;
|
||
}
|
||
|
||
// When requesting binary data, IE6-9 will throw an exception
|
||
// on any attempt to access responseText (#11426)
|
||
try {
|
||
responses.text = xhr.responseText;
|
||
} catch( e ) {
|
||
}
|
||
|
||
// Firefox throws an exception when accessing
|
||
// statusText for faulty cross-domain requests
|
||
try {
|
||
statusText = xhr.statusText;
|
||
} catch( e ) {
|
||
// We normalize with Webkit giving an empty statusText
|
||
statusText = "";
|
||
}
|
||
|
||
// Filter status for non standard behaviors
|
||
|
||
// If the request is local and we have data: assume a success
|
||
// (success with no data won't get notified, that's the best we
|
||
// can do given current implementations)
|
||
if ( !status && s.isLocal && !s.crossDomain ) {
|
||
status = responses.text ? 200 : 404;
|
||
// IE - #1450: sometimes returns 1223 when it should be 204
|
||
} else if ( status === 1223 ) {
|
||
status = 204;
|
||
}
|
||
}
|
||
}
|
||
} catch( firefoxAccessException ) {
|
||
if ( !isAbort ) {
|
||
complete( -1, firefoxAccessException );
|
||
}
|
||
}
|
||
|
||
// Call complete if needed
|
||
if ( responses ) {
|
||
complete( status, statusText, responses, responseHeaders );
|
||
}
|
||
};
|
||
|
||
if ( !s.async ) {
|
||
// if we're in sync mode we fire the callback
|
||
callback();
|
||
} else if ( xhr.readyState === 4 ) {
|
||
// (IE6 & IE7) if it's in cache and has been
|
||
// retrieved directly we need to fire the callback
|
||
setTimeout( callback, 0 );
|
||
} else {
|
||
handle = ++xhrId;
|
||
if ( xhrOnUnloadAbort ) {
|
||
// Create the active xhrs callbacks list if needed
|
||
// and attach the unload handler
|
||
if ( !xhrCallbacks ) {
|
||
xhrCallbacks = {};
|
||
jQuery( window ).unload( xhrOnUnloadAbort );
|
||
}
|
||
// Add to list of active xhrs callbacks
|
||
xhrCallbacks[ handle ] = callback;
|
||
}
|
||
xhr.onreadystatechange = callback;
|
||
}
|
||
},
|
||
|
||
abort: function() {
|
||
if ( callback ) {
|
||
callback(0,1);
|
||
}
|
||
}
|
||
};
|
||
}
|
||
});
|
||
}
|
||
var fxNow, timerId,
|
||
rfxtypes = /^(?:toggle|show|hide)$/,
|
||
rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
|
||
rrun = /queueHooks$/,
|
||
animationPrefilters = [ defaultPrefilter ],
|
||
tweeners = {
|
||
"*": [function( prop, value ) {
|
||
var end, unit,
|
||
tween = this.createTween( prop, value ),
|
||
parts = rfxnum.exec( value ),
|
||
target = tween.cur(),
|
||
start = +target || 0,
|
||
scale = 1,
|
||
maxIterations = 20;
|
||
|
||
if ( parts ) {
|
||
end = +parts[2];
|
||
unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
|
||
|
||
// We need to compute starting value
|
||
if ( unit !== "px" && start ) {
|
||
// Iteratively approximate from a nonzero starting point
|
||
// Prefer the current property, because this process will be trivial if it uses the same units
|
||
// Fallback to end or a simple constant
|
||
start = jQuery.css( tween.elem, prop, true ) || end || 1;
|
||
|
||
do {
|
||
// If previous iteration zeroed out, double until we get *something*
|
||
// Use a string for doubling factor so we don't accidentally see scale as unchanged below
|
||
scale = scale || ".5";
|
||
|
||
// Adjust and apply
|
||
start = start / scale;
|
||
jQuery.style( tween.elem, prop, start + unit );
|
||
|
||
// Update scale, tolerating zero or NaN from tween.cur()
|
||
// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
|
||
} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
|
||
}
|
||
|
||
tween.unit = unit;
|
||
tween.start = start;
|
||
// If a +=/-= token was provided, we're doing a relative animation
|
||
tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
|
||
}
|
||
return tween;
|
||
}]
|
||
};
|
||
|
||
// Animations created synchronously will run synchronously
|
||
function createFxNow() {
|
||
setTimeout(function() {
|
||
fxNow = undefined;
|
||
}, 0 );
|
||
return ( fxNow = jQuery.now() );
|
||
}
|
||
|
||
function createTweens( animation, props ) {
|
||
jQuery.each( props, function( prop, value ) {
|
||
var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
|
||
index = 0,
|
||
length = collection.length;
|
||
for ( ; index < length; index++ ) {
|
||
if ( collection[ index ].call( animation, prop, value ) ) {
|
||
|
||
// we're done with this property
|
||
return;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function Animation( elem, properties, options ) {
|
||
var result,
|
||
index = 0,
|
||
tweenerIndex = 0,
|
||
length = animationPrefilters.length,
|
||
deferred = jQuery.Deferred().always( function() {
|
||
// don't match elem in the :animated selector
|
||
delete tick.elem;
|
||
}),
|
||
tick = function() {
|
||
var currentTime = fxNow || createFxNow(),
|
||
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
|
||
// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
|
||
temp = remaining / animation.duration || 0,
|
||
percent = 1 - temp,
|
||
index = 0,
|
||
length = animation.tweens.length;
|
||
|
||
for ( ; index < length ; index++ ) {
|
||
animation.tweens[ index ].run( percent );
|
||
}
|
||
|
||
deferred.notifyWith( elem, [ animation, percent, remaining ]);
|
||
|
||
if ( percent < 1 && length ) {
|
||
return remaining;
|
||
} else {
|
||
deferred.resolveWith( elem, [ animation ] );
|
||
return false;
|
||
}
|
||
},
|
||
animation = deferred.promise({
|
||
elem: elem,
|
||
props: jQuery.extend( {}, properties ),
|
||
opts: jQuery.extend( true, { specialEasing: {} }, options ),
|
||
originalProperties: properties,
|
||
originalOptions: options,
|
||
startTime: fxNow || createFxNow(),
|
||
duration: options.duration,
|
||
tweens: [],
|
||
createTween: function( prop, end, easing ) {
|
||
var tween = jQuery.Tween( elem, animation.opts, prop, end,
|
||
animation.opts.specialEasing[ prop ] || animation.opts.easing );
|
||
animation.tweens.push( tween );
|
||
return tween;
|
||
},
|
||
stop: function( gotoEnd ) {
|
||
var index = 0,
|
||
// if we are going to the end, we want to run all the tweens
|
||
// otherwise we skip this part
|
||
length = gotoEnd ? animation.tweens.length : 0;
|
||
|
||
for ( ; index < length ; index++ ) {
|
||
animation.tweens[ index ].run( 1 );
|
||
}
|
||
|
||
// resolve when we played the last frame
|
||
// otherwise, reject
|
||
if ( gotoEnd ) {
|
||
deferred.resolveWith( elem, [ animation, gotoEnd ] );
|
||
} else {
|
||
deferred.rejectWith( elem, [ animation, gotoEnd ] );
|
||
}
|
||
return this;
|
||
}
|
||
}),
|
||
props = animation.props;
|
||
|
||
propFilter( props, animation.opts.specialEasing );
|
||
|
||
for ( ; index < length ; index++ ) {
|
||
result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
|
||
if ( result ) {
|
||
return result;
|
||
}
|
||
}
|
||
|
||
createTweens( animation, props );
|
||
|
||
if ( jQuery.isFunction( animation.opts.start ) ) {
|
||
animation.opts.start.call( elem, animation );
|
||
}
|
||
|
||
jQuery.fx.timer(
|
||
jQuery.extend( tick, {
|
||
anim: animation,
|
||
queue: animation.opts.queue,
|
||
elem: elem
|
||
})
|
||
);
|
||
|
||
// attach callbacks from options
|
||
return animation.progress( animation.opts.progress )
|
||
.done( animation.opts.done, animation.opts.complete )
|
||
.fail( animation.opts.fail )
|
||
.always( animation.opts.always );
|
||
}
|
||
|
||
function propFilter( props, specialEasing ) {
|
||
var index, name, easing, value, hooks;
|
||
|
||
// camelCase, specialEasing and expand cssHook pass
|
||
for ( index in props ) {
|
||
name = jQuery.camelCase( index );
|
||
easing = specialEasing[ name ];
|
||
value = props[ index ];
|
||
if ( jQuery.isArray( value ) ) {
|
||
easing = value[ 1 ];
|
||
value = props[ index ] = value[ 0 ];
|
||
}
|
||
|
||
if ( index !== name ) {
|
||
props[ name ] = value;
|
||
delete props[ index ];
|
||
}
|
||
|
||
hooks = jQuery.cssHooks[ name ];
|
||
if ( hooks && "expand" in hooks ) {
|
||
value = hooks.expand( value );
|
||
delete props[ name ];
|
||
|
||
// not quite $.extend, this wont overwrite keys already present.
|
||
// also - reusing 'index' from above because we have the correct "name"
|
||
for ( index in value ) {
|
||
if ( !( index in props ) ) {
|
||
props[ index ] = value[ index ];
|
||
specialEasing[ index ] = easing;
|
||
}
|
||
}
|
||
} else {
|
||
specialEasing[ name ] = easing;
|
||
}
|
||
}
|
||
}
|
||
|
||
jQuery.Animation = jQuery.extend( Animation, {
|
||
|
||
tweener: function( props, callback ) {
|
||
if ( jQuery.isFunction( props ) ) {
|
||
callback = props;
|
||
props = [ "*" ];
|
||
} else {
|
||
props = props.split(" ");
|
||
}
|
||
|
||
var prop,
|
||
index = 0,
|
||
length = props.length;
|
||
|
||
for ( ; index < length ; index++ ) {
|
||
prop = props[ index ];
|
||
tweeners[ prop ] = tweeners[ prop ] || [];
|
||
tweeners[ prop ].unshift( callback );
|
||
}
|
||
},
|
||
|
||
prefilter: function( callback, prepend ) {
|
||
if ( prepend ) {
|
||
animationPrefilters.unshift( callback );
|
||
} else {
|
||
animationPrefilters.push( callback );
|
||
}
|
||
}
|
||
});
|
||
|
||
function defaultPrefilter( elem, props, opts ) {
|
||
var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,
|
||
anim = this,
|
||
style = elem.style,
|
||
orig = {},
|
||
handled = [],
|
||
hidden = elem.nodeType && isHidden( elem );
|
||
|
||
// handle queue: false promises
|
||
if ( !opts.queue ) {
|
||
hooks = jQuery._queueHooks( elem, "fx" );
|
||
if ( hooks.unqueued == null ) {
|
||
hooks.unqueued = 0;
|
||
oldfire = hooks.empty.fire;
|
||
hooks.empty.fire = function() {
|
||
if ( !hooks.unqueued ) {
|
||
oldfire();
|
||
}
|
||
};
|
||
}
|
||
hooks.unqueued++;
|
||
|
||
anim.always(function() {
|
||
// doing this makes sure that the complete handler will be called
|
||
// before this completes
|
||
anim.always(function() {
|
||
hooks.unqueued--;
|
||
if ( !jQuery.queue( elem, "fx" ).length ) {
|
||
hooks.empty.fire();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// height/width overflow pass
|
||
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
|
||
// Make sure that nothing sneaks out
|
||
// Record all 3 overflow attributes because IE does not
|
||
// change the overflow attribute when overflowX and
|
||
// overflowY are set to the same value
|
||
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
|
||
|
||
// Set display property to inline-block for height/width
|
||
// animations on inline elements that are having width/height animated
|
||
if ( jQuery.css( elem, "display" ) === "inline" &&
|
||
jQuery.css( elem, "float" ) === "none" ) {
|
||
|
||
// inline-level elements accept inline-block;
|
||
// block-level elements need to be inline with layout
|
||
if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
|
||
style.display = "inline-block";
|
||
|
||
} else {
|
||
style.zoom = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( opts.overflow ) {
|
||
style.overflow = "hidden";
|
||
if ( !jQuery.support.shrinkWrapBlocks ) {
|
||
anim.done(function() {
|
||
style.overflow = opts.overflow[ 0 ];
|
||
style.overflowX = opts.overflow[ 1 ];
|
||
style.overflowY = opts.overflow[ 2 ];
|
||
});
|
||
}
|
||
}
|
||
|
||
|
||
// show/hide pass
|
||
for ( index in props ) {
|
||
value = props[ index ];
|
||
if ( rfxtypes.exec( value ) ) {
|
||
delete props[ index ];
|
||
toggle = toggle || value === "toggle";
|
||
if ( value === ( hidden ? "hide" : "show" ) ) {
|
||
continue;
|
||
}
|
||
handled.push( index );
|
||
}
|
||
}
|
||
|
||
length = handled.length;
|
||
if ( length ) {
|
||
dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
|
||
if ( "hidden" in dataShow ) {
|
||
hidden = dataShow.hidden;
|
||
}
|
||
|
||
// store state if its toggle - enables .stop().toggle() to "reverse"
|
||
if ( toggle ) {
|
||
dataShow.hidden = !hidden;
|
||
}
|
||
if ( hidden ) {
|
||
jQuery( elem ).show();
|
||
} else {
|
||
anim.done(function() {
|
||
jQuery( elem ).hide();
|
||
});
|
||
}
|
||
anim.done(function() {
|
||
var prop;
|
||
jQuery.removeData( elem, "fxshow", true );
|
||
for ( prop in orig ) {
|
||
jQuery.style( elem, prop, orig[ prop ] );
|
||
}
|
||
});
|
||
for ( index = 0 ; index < length ; index++ ) {
|
||
prop = handled[ index ];
|
||
tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
|
||
orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
|
||
|
||
if ( !( prop in dataShow ) ) {
|
||
dataShow[ prop ] = tween.start;
|
||
if ( hidden ) {
|
||
tween.end = tween.start;
|
||
tween.start = prop === "width" || prop === "height" ? 1 : 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function Tween( elem, options, prop, end, easing ) {
|
||
return new Tween.prototype.init( elem, options, prop, end, easing );
|
||
}
|
||
jQuery.Tween = Tween;
|
||
|
||
Tween.prototype = {
|
||
constructor: Tween,
|
||
init: function( elem, options, prop, end, easing, unit ) {
|
||
this.elem = elem;
|
||
this.prop = prop;
|
||
this.easing = easing || "swing";
|
||
this.options = options;
|
||
this.start = this.now = this.cur();
|
||
this.end = end;
|
||
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
|
||
},
|
||
cur: function() {
|
||
var hooks = Tween.propHooks[ this.prop ];
|
||
|
||
return hooks && hooks.get ?
|
||
hooks.get( this ) :
|
||
Tween.propHooks._default.get( this );
|
||
},
|
||
run: function( percent ) {
|
||
var eased,
|
||
hooks = Tween.propHooks[ this.prop ];
|
||
|
||
if ( this.options.duration ) {
|
||
this.pos = eased = jQuery.easing[ this.easing ](
|
||
percent, this.options.duration * percent, 0, 1, this.options.duration
|
||
);
|
||
} else {
|
||
this.pos = eased = percent;
|
||
}
|
||
this.now = ( this.end - this.start ) * eased + this.start;
|
||
|
||
if ( this.options.step ) {
|
||
this.options.step.call( this.elem, this.now, this );
|
||
}
|
||
|
||
if ( hooks && hooks.set ) {
|
||
hooks.set( this );
|
||
} else {
|
||
Tween.propHooks._default.set( this );
|
||
}
|
||
return this;
|
||
}
|
||
};
|
||
|
||
Tween.prototype.init.prototype = Tween.prototype;
|
||
|
||
Tween.propHooks = {
|
||
_default: {
|
||
get: function( tween ) {
|
||
var result;
|
||
|
||
if ( tween.elem[ tween.prop ] != null &&
|
||
(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
|
||
return tween.elem[ tween.prop ];
|
||
}
|
||
|
||
// passing any value as a 4th parameter to .css will automatically
|
||
// attempt a parseFloat and fallback to a string if the parse fails
|
||
// so, simple values such as "10px" are parsed to Float.
|
||
// complex values such as "rotate(1rad)" are returned as is.
|
||
result = jQuery.css( tween.elem, tween.prop, false, "" );
|
||
// Empty strings, null, undefined and "auto" are converted to 0.
|
||
return !result || result === "auto" ? 0 : result;
|
||
},
|
||
set: function( tween ) {
|
||
// use step hook for back compat - use cssHook if its there - use .style if its
|
||
// available and use plain properties where available
|
||
if ( jQuery.fx.step[ tween.prop ] ) {
|
||
jQuery.fx.step[ tween.prop ]( tween );
|
||
} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
|
||
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
|
||
} else {
|
||
tween.elem[ tween.prop ] = tween.now;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// Remove in 2.0 - this supports IE8's panic based approach
|
||
// to setting things on disconnected nodes
|
||
|
||
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
|
||
set: function( tween ) {
|
||
if ( tween.elem.nodeType && tween.elem.parentNode ) {
|
||
tween.elem[ tween.prop ] = tween.now;
|
||
}
|
||
}
|
||
};
|
||
|
||
jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
|
||
var cssFn = jQuery.fn[ name ];
|
||
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
||
return speed == null || typeof speed === "boolean" ||
|
||
// special check for .toggle( handler, handler, ... )
|
||
( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ?
|
||
cssFn.apply( this, arguments ) :
|
||
this.animate( genFx( name, true ), speed, easing, callback );
|
||
};
|
||
});
|
||
|
||
jQuery.fn.extend({
|
||
fadeTo: function( speed, to, easing, callback ) {
|
||
|
||
// show any hidden elements after setting opacity to 0
|
||
return this.filter( isHidden ).css( "opacity", 0 ).show()
|
||
|
||
// animate to the value specified
|
||
.end().animate({ opacity: to }, speed, easing, callback );
|
||
},
|
||
animate: function( prop, speed, easing, callback ) {
|
||
var empty = jQuery.isEmptyObject( prop ),
|
||
optall = jQuery.speed( speed, easing, callback ),
|
||
doAnimation = function() {
|
||
// Operate on a copy of prop so per-property easing won't be lost
|
||
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
|
||
|
||
// Empty animations resolve immediately
|
||
if ( empty ) {
|
||
anim.stop( true );
|
||
}
|
||
};
|
||
|
||
return empty || optall.queue === false ?
|
||
this.each( doAnimation ) :
|
||
this.queue( optall.queue, doAnimation );
|
||
},
|
||
stop: function( type, clearQueue, gotoEnd ) {
|
||
var stopQueue = function( hooks ) {
|
||
var stop = hooks.stop;
|
||
delete hooks.stop;
|
||
stop( gotoEnd );
|
||
};
|
||
|
||
if ( typeof type !== "string" ) {
|
||
gotoEnd = clearQueue;
|
||
clearQueue = type;
|
||
type = undefined;
|
||
}
|
||
if ( clearQueue && type !== false ) {
|
||
this.queue( type || "fx", [] );
|
||
}
|
||
|
||
return this.each(function() {
|
||
var dequeue = true,
|
||
index = type != null && type + "queueHooks",
|
||
timers = jQuery.timers,
|
||
data = jQuery._data( this );
|
||
|
||
if ( index ) {
|
||
if ( data[ index ] && data[ index ].stop ) {
|
||
stopQueue( data[ index ] );
|
||
}
|
||
} else {
|
||
for ( index in data ) {
|
||
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
|
||
stopQueue( data[ index ] );
|
||
}
|
||
}
|
||
}
|
||
|
||
for ( index = timers.length; index--; ) {
|
||
if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
|
||
timers[ index ].anim.stop( gotoEnd );
|
||
dequeue = false;
|
||
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 ( dequeue || !gotoEnd ) {
|
||
jQuery.dequeue( this, type );
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
// Generate parameters to create a standard animation
|
||
function genFx( type, includeWidth ) {
|
||
var which,
|
||
attrs = { height: type },
|
||
i = 0;
|
||
|
||
// if we include width, step value is 1 to do all cssExpand values,
|
||
// if we don't include width, step value is 2 to skip over Left and Right
|
||
includeWidth = includeWidth? 1 : 0;
|
||
for( ; i < 4 ; i += 2 - includeWidth ) {
|
||
which = cssExpand[ i ];
|
||
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
|
||
}
|
||
|
||
if ( includeWidth ) {
|
||
attrs.opacity = attrs.width = type;
|
||
}
|
||
|
||
return attrs;
|
||
}
|
||
|
||
// Generate shortcuts for custom animations
|
||
jQuery.each({
|
||
slideDown: genFx("show"),
|
||
slideUp: genFx("hide"),
|
||
slideToggle: genFx("toggle"),
|
||
fadeIn: { opacity: "show" },
|
||
fadeOut: { opacity: "hide" },
|
||
fadeToggle: { opacity: "toggle" }
|
||
}, function( name, props ) {
|
||
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
||
return this.animate( props, speed, easing, callback );
|
||
};
|
||
});
|
||
|
||
jQuery.speed = function( speed, easing, fn ) {
|
||
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
|
||
};
|
||
|
||
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;
|
||
|
||
// 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() {
|
||
if ( jQuery.isFunction( opt.old ) ) {
|
||
opt.old.call( this );
|
||
}
|
||
|
||
if ( opt.queue ) {
|
||
jQuery.dequeue( this, opt.queue );
|
||
}
|
||
};
|
||
|
||
return opt;
|
||
};
|
||
|
||
jQuery.easing = {
|
||
linear: function( p ) {
|
||
return p;
|
||
},
|
||
swing: function( p ) {
|
||
return 0.5 - Math.cos( p*Math.PI ) / 2;
|
||
}
|
||
};
|
||
|
||
jQuery.timers = [];
|
||
jQuery.fx = Tween.prototype.init;
|
||
jQuery.fx.tick = function() {
|
||
var timer,
|
||
timers = jQuery.timers,
|
||
i = 0;
|
||
|
||
fxNow = jQuery.now();
|
||
|
||
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 );
|
||
}
|
||
}
|
||
|
||
if ( !timers.length ) {
|
||
jQuery.fx.stop();
|
||
}
|
||
fxNow = undefined;
|
||
};
|
||
|
||
jQuery.fx.timer = function( timer ) {
|
||
if ( timer() && jQuery.timers.push( timer ) && !timerId ) {
|
||
timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
|
||
}
|
||
};
|
||
|
||
jQuery.fx.interval = 13;
|
||
|
||
jQuery.fx.stop = function() {
|
||
clearInterval( timerId );
|
||
timerId = null;
|
||
};
|
||
|
||
jQuery.fx.speeds = {
|
||
slow: 600,
|
||
fast: 200,
|
||
// Default speed
|
||
_default: 400
|
||
};
|
||
|
||
// Back Compat <1.8 extension point
|
||
jQuery.fx.step = {};
|
||
|
||
if ( jQuery.expr && jQuery.expr.filters ) {
|
||
jQuery.expr.filters.animated = function( elem ) {
|
||
return jQuery.grep(jQuery.timers, function( fn ) {
|
||
return elem === fn.elem;
|
||
}).length;
|
||
};
|
||
}
|
||
var rroot = /^(?:body|html)$/i;
|
||
|
||
jQuery.fn.offset = function( options ) {
|
||
if ( arguments.length ) {
|
||
return options === undefined ?
|
||
this :
|
||
this.each(function( i ) {
|
||
jQuery.offset.setOffset( this, options, i );
|
||
});
|
||
}
|
||
|
||
var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft,
|
||
box = { top: 0, left: 0 },
|
||
elem = this[ 0 ],
|
||
doc = elem && elem.ownerDocument;
|
||
|
||
if ( !doc ) {
|
||
return;
|
||
}
|
||
|
||
if ( (body = doc.body) === elem ) {
|
||
return jQuery.offset.bodyOffset( elem );
|
||
}
|
||
|
||
docElem = doc.documentElement;
|
||
|
||
// Make sure it's not a disconnected DOM node
|
||
if ( !jQuery.contains( docElem, elem ) ) {
|
||
return box;
|
||
}
|
||
|
||
// If we don't have gBCR, just use 0,0 rather than error
|
||
// BlackBerry 5, iOS 3 (original iPhone)
|
||
if ( typeof elem.getBoundingClientRect !== "undefined" ) {
|
||
box = elem.getBoundingClientRect();
|
||
}
|
||
win = getWindow( doc );
|
||
clientTop = docElem.clientTop || body.clientTop || 0;
|
||
clientLeft = docElem.clientLeft || body.clientLeft || 0;
|
||
scrollTop = win.pageYOffset || docElem.scrollTop;
|
||
scrollLeft = win.pageXOffset || docElem.scrollLeft;
|
||
return {
|
||
top: box.top + scrollTop - clientTop,
|
||
left: box.left + scrollLeft - clientLeft
|
||
};
|
||
};
|
||
|
||
jQuery.offset = {
|
||
|
||
bodyOffset: function( body ) {
|
||
var top = body.offsetTop,
|
||
left = body.offsetLeft;
|
||
|
||
if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
|
||
top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
|
||
left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
|
||
}
|
||
|
||
return { top: top, left: left };
|
||
},
|
||
|
||
setOffset: function( elem, options, i ) {
|
||
var position = jQuery.css( elem, "position" );
|
||
|
||
// set position first, in-case top/left are set even on static elem
|
||
if ( position === "static" ) {
|
||
elem.style.position = "relative";
|
||
}
|
||
|
||
var curElem = jQuery( elem ),
|
||
curOffset = curElem.offset(),
|
||
curCSSTop = jQuery.css( elem, "top" ),
|
||
curCSSLeft = jQuery.css( elem, "left" ),
|
||
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
|
||
if ( calculatePosition ) {
|
||
curPosition = curElem.position();
|
||
curTop = curPosition.top;
|
||
curLeft = curPosition.left;
|
||
} else {
|
||
curTop = parseFloat( curCSSTop ) || 0;
|
||
curLeft = parseFloat( curCSSLeft ) || 0;
|
||
}
|
||
|
||
if ( jQuery.isFunction( options ) ) {
|
||
options = options.call( elem, i, curOffset );
|
||
}
|
||
|
||
if ( options.top != null ) {
|
||
props.top = ( options.top - curOffset.top ) + curTop;
|
||
}
|
||
if ( options.left != null ) {
|
||
props.left = ( options.left - curOffset.left ) + curLeft;
|
||
}
|
||
|
||
if ( "using" in options ) {
|
||
options.using.call( elem, props );
|
||
} else {
|
||
curElem.css( props );
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
jQuery.fn.extend({
|
||
|
||
position: function() {
|
||
if ( !this[0] ) {
|
||
return;
|
||
}
|
||
|
||
var elem = this[0],
|
||
|
||
// Get *real* offsetParent
|
||
offsetParent = this.offsetParent(),
|
||
|
||
// Get correct offsets
|
||
offset = this.offset(),
|
||
parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
|
||
|
||
// Subtract element margins
|
||
// note: when an element has margin: auto the offsetLeft and marginLeft
|
||
// are the same in Safari causing offset.left to incorrectly be 0
|
||
offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
|
||
offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
|
||
|
||
// Add offsetParent borders
|
||
parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
|
||
parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
|
||
|
||
// Subtract the two offsets
|
||
return {
|
||
top: offset.top - parentOffset.top,
|
||
left: offset.left - parentOffset.left
|
||
};
|
||
},
|
||
|
||
offsetParent: function() {
|
||
return this.map(function() {
|
||
var offsetParent = this.offsetParent || document.body;
|
||
while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
|
||
offsetParent = offsetParent.offsetParent;
|
||
}
|
||
return offsetParent || document.body;
|
||
});
|
||
}
|
||
});
|
||
|
||
|
||
// Create scrollLeft and scrollTop methods
|
||
jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
|
||
var top = /Y/.test( prop );
|
||
|
||
jQuery.fn[ method ] = function( val ) {
|
||
return jQuery.access( this, function( elem, method, val ) {
|
||
var win = getWindow( elem );
|
||
|
||
if ( val === undefined ) {
|
||
return win ? (prop in win) ? win[ prop ] :
|
||
win.document.documentElement[ method ] :
|
||
elem[ method ];
|
||
}
|
||
|
||
if ( win ) {
|
||
win.scrollTo(
|
||
!top ? val : jQuery( win ).scrollLeft(),
|
||
top ? val : jQuery( win ).scrollTop()
|
||
);
|
||
|
||
} else {
|
||
elem[ method ] = val;
|
||
}
|
||
}, method, val, arguments.length, null );
|
||
};
|
||
});
|
||
|
||
function getWindow( elem ) {
|
||
return jQuery.isWindow( elem ) ?
|
||
elem :
|
||
elem.nodeType === 9 ?
|
||
elem.defaultView || elem.parentWindow :
|
||
false;
|
||
}
|
||
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
|
||
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
|
||
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
|
||
// margin is only for outerHeight, outerWidth
|
||
jQuery.fn[ funcName ] = function( margin, value ) {
|
||
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
|
||
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
|
||
|
||
return jQuery.access( this, function( elem, type, value ) {
|
||
var doc;
|
||
|
||
if ( jQuery.isWindow( elem ) ) {
|
||
// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
|
||
// isn't a whole lot we can do. See pull request at this URL for discussion:
|
||
// https://github.com/jquery/jquery/pull/764
|
||
return elem.document.documentElement[ "client" + name ];
|
||
}
|
||
|
||
// Get document width or height
|
||
if ( elem.nodeType === 9 ) {
|
||
doc = elem.documentElement;
|
||
|
||
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
|
||
// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
|
||
return Math.max(
|
||
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
|
||
elem.body[ "offset" + name ], doc[ "offset" + name ],
|
||
doc[ "client" + name ]
|
||
);
|
||
}
|
||
|
||
return value === undefined ?
|
||
// Get width or height on the element, requesting but not forcing parseFloat
|
||
jQuery.css( elem, type, value, extra ) :
|
||
|
||
// Set width or height on the element
|
||
jQuery.style( elem, type, value, extra );
|
||
}, type, chainable ? margin : undefined, chainable, null );
|
||
};
|
||
});
|
||
});
|
||
// Expose jQuery to the global object
|
||
window.jQuery = window.$ = jQuery;
|
||
|
||
// 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 );
|
||
;/*! jQuery UI - v1.11.4 - 2015-10-16
|
||
* http://jqueryui.com
|
||
* Includes: core.js, widget.js, mouse.js, position.js, datepicker.js, slider.js, tooltip.js
|
||
* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
|
||
|
||
(function( factory ) {
|
||
if ( typeof define === "function" && define.amd ) {
|
||
|
||
// AMD. Register as an anonymous module.
|
||
define([ "jquery" ], factory );
|
||
} else {
|
||
|
||
// Browser globals
|
||
factory( jQuery );
|
||
}
|
||
}(function( $ ) {
|
||
/*!
|
||
* jQuery UI Core 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/category/ui-core/
|
||
*/
|
||
|
||
|
||
// $.ui might exist from components with no dependencies, e.g., $.ui.position
|
||
$.ui = $.ui || {};
|
||
|
||
$.extend( $.ui, {
|
||
version: "1.11.4",
|
||
|
||
keyCode: {
|
||
BACKSPACE: 8,
|
||
COMMA: 188,
|
||
DELETE: 46,
|
||
DOWN: 40,
|
||
END: 35,
|
||
ENTER: 13,
|
||
ESCAPE: 27,
|
||
HOME: 36,
|
||
LEFT: 37,
|
||
PAGE_DOWN: 34,
|
||
PAGE_UP: 33,
|
||
PERIOD: 190,
|
||
RIGHT: 39,
|
||
SPACE: 32,
|
||
TAB: 9,
|
||
UP: 38
|
||
}
|
||
});
|
||
|
||
// plugins
|
||
$.fn.extend({
|
||
scrollParent: function( includeHidden ) {
|
||
var position = this.css( "position" ),
|
||
excludeStaticParent = position === "absolute",
|
||
overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
|
||
scrollParent = this.parents().filter( function() {
|
||
var parent = $( this );
|
||
if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
|
||
return false;
|
||
}
|
||
return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
|
||
}).eq( 0 );
|
||
|
||
return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
|
||
},
|
||
|
||
uniqueId: (function() {
|
||
var uuid = 0;
|
||
|
||
return function() {
|
||
return this.each(function() {
|
||
if ( !this.id ) {
|
||
this.id = "ui-id-" + ( ++uuid );
|
||
}
|
||
});
|
||
};
|
||
})(),
|
||
|
||
removeUniqueId: function() {
|
||
return this.each(function() {
|
||
if ( /^ui-id-\d+$/.test( this.id ) ) {
|
||
$( this ).removeAttr( "id" );
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
// selectors
|
||
function focusable( element, isTabIndexNotNaN ) {
|
||
var map, mapName, img,
|
||
nodeName = element.nodeName.toLowerCase();
|
||
if ( "area" === nodeName ) {
|
||
map = element.parentNode;
|
||
mapName = map.name;
|
||
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
|
||
return false;
|
||
}
|
||
img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
|
||
return !!img && visible( img );
|
||
}
|
||
return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
|
||
!element.disabled :
|
||
"a" === nodeName ?
|
||
element.href || isTabIndexNotNaN :
|
||
isTabIndexNotNaN) &&
|
||
// the element and all of its ancestors must be visible
|
||
visible( element );
|
||
}
|
||
|
||
function visible( element ) {
|
||
return $.expr.filters.visible( element ) &&
|
||
!$( element ).parents().addBack().filter(function() {
|
||
return $.css( this, "visibility" ) === "hidden";
|
||
}).length;
|
||
}
|
||
|
||
$.extend( $.expr[ ":" ], {
|
||
data: $.expr.createPseudo ?
|
||
$.expr.createPseudo(function( dataName ) {
|
||
return function( elem ) {
|
||
return !!$.data( elem, dataName );
|
||
};
|
||
}) :
|
||
// support: jQuery <1.8
|
||
function( elem, i, match ) {
|
||
return !!$.data( elem, match[ 3 ] );
|
||
},
|
||
|
||
focusable: function( element ) {
|
||
return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
|
||
},
|
||
|
||
tabbable: function( element ) {
|
||
var tabIndex = $.attr( element, "tabindex" ),
|
||
isTabIndexNaN = isNaN( tabIndex );
|
||
return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
|
||
}
|
||
});
|
||
|
||
// support: jQuery <1.8
|
||
if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
|
||
$.each( [ "Width", "Height" ], function( i, name ) {
|
||
var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
|
||
type = name.toLowerCase(),
|
||
orig = {
|
||
innerWidth: $.fn.innerWidth,
|
||
innerHeight: $.fn.innerHeight,
|
||
outerWidth: $.fn.outerWidth,
|
||
outerHeight: $.fn.outerHeight
|
||
};
|
||
|
||
function reduce( elem, size, border, margin ) {
|
||
$.each( side, function() {
|
||
size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
|
||
if ( border ) {
|
||
size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
|
||
}
|
||
if ( margin ) {
|
||
size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
|
||
}
|
||
});
|
||
return size;
|
||
}
|
||
|
||
$.fn[ "inner" + name ] = function( size ) {
|
||
if ( size === undefined ) {
|
||
return orig[ "inner" + name ].call( this );
|
||
}
|
||
|
||
return this.each(function() {
|
||
$( this ).css( type, reduce( this, size ) + "px" );
|
||
});
|
||
};
|
||
|
||
$.fn[ "outer" + name] = function( size, margin ) {
|
||
if ( typeof size !== "number" ) {
|
||
return orig[ "outer" + name ].call( this, size );
|
||
}
|
||
|
||
return this.each(function() {
|
||
$( this).css( type, reduce( this, size, true, margin ) + "px" );
|
||
});
|
||
};
|
||
});
|
||
}
|
||
|
||
// support: jQuery <1.8
|
||
if ( !$.fn.addBack ) {
|
||
$.fn.addBack = function( selector ) {
|
||
return this.add( selector == null ?
|
||
this.prevObject : this.prevObject.filter( selector )
|
||
);
|
||
};
|
||
}
|
||
|
||
// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
|
||
if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
|
||
$.fn.removeData = (function( removeData ) {
|
||
return function( key ) {
|
||
if ( arguments.length ) {
|
||
return removeData.call( this, $.camelCase( key ) );
|
||
} else {
|
||
return removeData.call( this );
|
||
}
|
||
};
|
||
})( $.fn.removeData );
|
||
}
|
||
|
||
// deprecated
|
||
$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
|
||
|
||
$.fn.extend({
|
||
focus: (function( orig ) {
|
||
return function( delay, fn ) {
|
||
return typeof delay === "number" ?
|
||
this.each(function() {
|
||
var elem = this;
|
||
setTimeout(function() {
|
||
$( elem ).focus();
|
||
if ( fn ) {
|
||
fn.call( elem );
|
||
}
|
||
}, delay );
|
||
}) :
|
||
orig.apply( this, arguments );
|
||
};
|
||
})( $.fn.focus ),
|
||
|
||
disableSelection: (function() {
|
||
var eventType = "onselectstart" in document.createElement( "div" ) ?
|
||
"selectstart" :
|
||
"mousedown";
|
||
|
||
return function() {
|
||
return this.bind( eventType + ".ui-disableSelection", function( event ) {
|
||
event.preventDefault();
|
||
});
|
||
};
|
||
})(),
|
||
|
||
enableSelection: function() {
|
||
return this.unbind( ".ui-disableSelection" );
|
||
},
|
||
|
||
zIndex: function( zIndex ) {
|
||
if ( zIndex !== undefined ) {
|
||
return this.css( "zIndex", zIndex );
|
||
}
|
||
|
||
if ( this.length ) {
|
||
var elem = $( this[ 0 ] ), position, value;
|
||
while ( elem.length && elem[ 0 ] !== document ) {
|
||
// Ignore z-index if position is set to a value where z-index is ignored by the browser
|
||
// This makes behavior of this function consistent across browsers
|
||
// WebKit always returns auto if the element is positioned
|
||
position = elem.css( "position" );
|
||
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
|
||
// IE returns 0 when zIndex is not specified
|
||
// other browsers return a string
|
||
// we ignore the case of nested elements with an explicit value of 0
|
||
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
|
||
value = parseInt( elem.css( "zIndex" ), 10 );
|
||
if ( !isNaN( value ) && value !== 0 ) {
|
||
return value;
|
||
}
|
||
}
|
||
elem = elem.parent();
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
});
|
||
|
||
// $.ui.plugin is deprecated. Use $.widget() extensions instead.
|
||
$.ui.plugin = {
|
||
add: function( module, option, set ) {
|
||
var i,
|
||
proto = $.ui[ module ].prototype;
|
||
for ( i in set ) {
|
||
proto.plugins[ i ] = proto.plugins[ i ] || [];
|
||
proto.plugins[ i ].push( [ option, set[ i ] ] );
|
||
}
|
||
},
|
||
call: function( instance, name, args, allowDisconnected ) {
|
||
var i,
|
||
set = instance.plugins[ name ];
|
||
|
||
if ( !set ) {
|
||
return;
|
||
}
|
||
|
||
if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
|
||
return;
|
||
}
|
||
|
||
for ( i = 0; i < set.length; i++ ) {
|
||
if ( instance.options[ set[ i ][ 0 ] ] ) {
|
||
set[ i ][ 1 ].apply( instance.element, args );
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
/*!
|
||
* jQuery UI Widget 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/jQuery.widget/
|
||
*/
|
||
|
||
|
||
var widget_uuid = 0,
|
||
widget_slice = Array.prototype.slice;
|
||
|
||
$.cleanData = (function( orig ) {
|
||
return function( elems ) {
|
||
var events, elem, i;
|
||
for ( i = 0; (elem = elems[i]) != null; i++ ) {
|
||
try {
|
||
|
||
// Only trigger remove when necessary to save time
|
||
events = $._data( elem, "events" );
|
||
if ( events && events.remove ) {
|
||
$( elem ).triggerHandler( "remove" );
|
||
}
|
||
|
||
// http://bugs.jquery.com/ticket/8235
|
||
} catch ( e ) {}
|
||
}
|
||
orig( elems );
|
||
};
|
||
})( $.cleanData );
|
||
|
||
$.widget = function( name, base, prototype ) {
|
||
var fullName, existingConstructor, constructor, basePrototype,
|
||
// proxiedPrototype allows the provided prototype to remain unmodified
|
||
// so that it can be used as a mixin for multiple widgets (#8876)
|
||
proxiedPrototype = {},
|
||
namespace = name.split( "." )[ 0 ];
|
||
|
||
name = name.split( "." )[ 1 ];
|
||
fullName = namespace + "-" + name;
|
||
|
||
if ( !prototype ) {
|
||
prototype = base;
|
||
base = $.Widget;
|
||
}
|
||
|
||
// create selector for plugin
|
||
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
|
||
return !!$.data( elem, fullName );
|
||
};
|
||
|
||
$[ namespace ] = $[ namespace ] || {};
|
||
existingConstructor = $[ namespace ][ name ];
|
||
constructor = $[ namespace ][ name ] = function( options, element ) {
|
||
// allow instantiation without "new" keyword
|
||
if ( !this._createWidget ) {
|
||
return new constructor( options, element );
|
||
}
|
||
|
||
// allow instantiation without initializing for simple inheritance
|
||
// must use "new" keyword (the code above always passes args)
|
||
if ( arguments.length ) {
|
||
this._createWidget( options, element );
|
||
}
|
||
};
|
||
// extend with the existing constructor to carry over any static properties
|
||
$.extend( constructor, existingConstructor, {
|
||
version: prototype.version,
|
||
// copy the object used to create the prototype in case we need to
|
||
// redefine the widget later
|
||
_proto: $.extend( {}, prototype ),
|
||
// track widgets that inherit from this widget in case this widget is
|
||
// redefined after a widget inherits from it
|
||
_childConstructors: []
|
||
});
|
||
|
||
basePrototype = new base();
|
||
// we need to make the options hash a property directly on the new instance
|
||
// otherwise we'll modify the options hash on the prototype that we're
|
||
// inheriting from
|
||
basePrototype.options = $.widget.extend( {}, basePrototype.options );
|
||
$.each( prototype, function( prop, value ) {
|
||
if ( !$.isFunction( value ) ) {
|
||
proxiedPrototype[ prop ] = value;
|
||
return;
|
||
}
|
||
proxiedPrototype[ prop ] = (function() {
|
||
var _super = function() {
|
||
return base.prototype[ prop ].apply( this, arguments );
|
||
},
|
||
_superApply = function( args ) {
|
||
return base.prototype[ prop ].apply( this, args );
|
||
};
|
||
return function() {
|
||
var __super = this._super,
|
||
__superApply = this._superApply,
|
||
returnValue;
|
||
|
||
this._super = _super;
|
||
this._superApply = _superApply;
|
||
|
||
returnValue = value.apply( this, arguments );
|
||
|
||
this._super = __super;
|
||
this._superApply = __superApply;
|
||
|
||
return returnValue;
|
||
};
|
||
})();
|
||
});
|
||
constructor.prototype = $.widget.extend( basePrototype, {
|
||
// TODO: remove support for widgetEventPrefix
|
||
// always use the name + a colon as the prefix, e.g., draggable:start
|
||
// don't prefix for widgets that aren't DOM-based
|
||
widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
|
||
}, proxiedPrototype, {
|
||
constructor: constructor,
|
||
namespace: namespace,
|
||
widgetName: name,
|
||
widgetFullName: fullName
|
||
});
|
||
|
||
// If this widget is being redefined then we need to find all widgets that
|
||
// are inheriting from it and redefine all of them so that they inherit from
|
||
// the new version of this widget. We're essentially trying to replace one
|
||
// level in the prototype chain.
|
||
if ( existingConstructor ) {
|
||
$.each( existingConstructor._childConstructors, function( i, child ) {
|
||
var childPrototype = child.prototype;
|
||
|
||
// redefine the child widget using the same prototype that was
|
||
// originally used, but inherit from the new version of the base
|
||
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
|
||
});
|
||
// remove the list of existing child constructors from the old constructor
|
||
// so the old child constructors can be garbage collected
|
||
delete existingConstructor._childConstructors;
|
||
} else {
|
||
base._childConstructors.push( constructor );
|
||
}
|
||
|
||
$.widget.bridge( name, constructor );
|
||
|
||
return constructor;
|
||
};
|
||
|
||
$.widget.extend = function( target ) {
|
||
var input = widget_slice.call( arguments, 1 ),
|
||
inputIndex = 0,
|
||
inputLength = input.length,
|
||
key,
|
||
value;
|
||
for ( ; inputIndex < inputLength; inputIndex++ ) {
|
||
for ( key in input[ inputIndex ] ) {
|
||
value = input[ inputIndex ][ key ];
|
||
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
|
||
// Clone objects
|
||
if ( $.isPlainObject( value ) ) {
|
||
target[ key ] = $.isPlainObject( target[ key ] ) ?
|
||
$.widget.extend( {}, target[ key ], value ) :
|
||
// Don't extend strings, arrays, etc. with objects
|
||
$.widget.extend( {}, value );
|
||
// Copy everything else by reference
|
||
} else {
|
||
target[ key ] = value;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return target;
|
||
};
|
||
|
||
$.widget.bridge = function( name, object ) {
|
||
var fullName = object.prototype.widgetFullName || name;
|
||
$.fn[ name ] = function( options ) {
|
||
var isMethodCall = typeof options === "string",
|
||
args = widget_slice.call( arguments, 1 ),
|
||
returnValue = this;
|
||
|
||
if ( isMethodCall ) {
|
||
this.each(function() {
|
||
var methodValue,
|
||
instance = $.data( this, fullName );
|
||
if ( options === "instance" ) {
|
||
returnValue = instance;
|
||
return false;
|
||
}
|
||
if ( !instance ) {
|
||
return $.error( "cannot call methods on " + name + " prior to initialization; " +
|
||
"attempted to call method '" + options + "'" );
|
||
}
|
||
if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
|
||
return $.error( "no such method '" + options + "' for " + name + " widget instance" );
|
||
}
|
||
methodValue = instance[ options ].apply( instance, args );
|
||
if ( methodValue !== instance && methodValue !== undefined ) {
|
||
returnValue = methodValue && methodValue.jquery ?
|
||
returnValue.pushStack( methodValue.get() ) :
|
||
methodValue;
|
||
return false;
|
||
}
|
||
});
|
||
} else {
|
||
|
||
// Allow multiple hashes to be passed on init
|
||
if ( args.length ) {
|
||
options = $.widget.extend.apply( null, [ options ].concat(args) );
|
||
}
|
||
|
||
this.each(function() {
|
||
var instance = $.data( this, fullName );
|
||
if ( instance ) {
|
||
instance.option( options || {} );
|
||
if ( instance._init ) {
|
||
instance._init();
|
||
}
|
||
} else {
|
||
$.data( this, fullName, new object( options, this ) );
|
||
}
|
||
});
|
||
}
|
||
|
||
return returnValue;
|
||
};
|
||
};
|
||
|
||
$.Widget = function( /* options, element */ ) {};
|
||
$.Widget._childConstructors = [];
|
||
|
||
$.Widget.prototype = {
|
||
widgetName: "widget",
|
||
widgetEventPrefix: "",
|
||
defaultElement: "<div>",
|
||
options: {
|
||
disabled: false,
|
||
|
||
// callbacks
|
||
create: null
|
||
},
|
||
_createWidget: function( options, element ) {
|
||
element = $( element || this.defaultElement || this )[ 0 ];
|
||
this.element = $( element );
|
||
this.uuid = widget_uuid++;
|
||
this.eventNamespace = "." + this.widgetName + this.uuid;
|
||
|
||
this.bindings = $();
|
||
this.hoverable = $();
|
||
this.focusable = $();
|
||
|
||
if ( element !== this ) {
|
||
$.data( element, this.widgetFullName, this );
|
||
this._on( true, this.element, {
|
||
remove: function( event ) {
|
||
if ( event.target === element ) {
|
||
this.destroy();
|
||
}
|
||
}
|
||
});
|
||
this.document = $( element.style ?
|
||
// element within the document
|
||
element.ownerDocument :
|
||
// element is window or document
|
||
element.document || element );
|
||
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
|
||
}
|
||
|
||
this.options = $.widget.extend( {},
|
||
this.options,
|
||
this._getCreateOptions(),
|
||
options );
|
||
|
||
this._create();
|
||
this._trigger( "create", null, this._getCreateEventData() );
|
||
this._init();
|
||
},
|
||
_getCreateOptions: $.noop,
|
||
_getCreateEventData: $.noop,
|
||
_create: $.noop,
|
||
_init: $.noop,
|
||
|
||
destroy: function() {
|
||
this._destroy();
|
||
// we can probably remove the unbind calls in 2.0
|
||
// all event bindings should go through this._on()
|
||
this.element
|
||
.unbind( this.eventNamespace )
|
||
.removeData( this.widgetFullName )
|
||
// support: jquery <1.6.3
|
||
// http://bugs.jquery.com/ticket/9413
|
||
.removeData( $.camelCase( this.widgetFullName ) );
|
||
this.widget()
|
||
.unbind( this.eventNamespace )
|
||
.removeAttr( "aria-disabled" )
|
||
.removeClass(
|
||
this.widgetFullName + "-disabled " +
|
||
"ui-state-disabled" );
|
||
|
||
// clean up events and states
|
||
this.bindings.unbind( this.eventNamespace );
|
||
this.hoverable.removeClass( "ui-state-hover" );
|
||
this.focusable.removeClass( "ui-state-focus" );
|
||
},
|
||
_destroy: $.noop,
|
||
|
||
widget: function() {
|
||
return this.element;
|
||
},
|
||
|
||
option: function( key, value ) {
|
||
var options = key,
|
||
parts,
|
||
curOption,
|
||
i;
|
||
|
||
if ( arguments.length === 0 ) {
|
||
// don't return a reference to the internal hash
|
||
return $.widget.extend( {}, this.options );
|
||
}
|
||
|
||
if ( typeof key === "string" ) {
|
||
// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
|
||
options = {};
|
||
parts = key.split( "." );
|
||
key = parts.shift();
|
||
if ( parts.length ) {
|
||
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
|
||
for ( i = 0; i < parts.length - 1; i++ ) {
|
||
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
|
||
curOption = curOption[ parts[ i ] ];
|
||
}
|
||
key = parts.pop();
|
||
if ( arguments.length === 1 ) {
|
||
return curOption[ key ] === undefined ? null : curOption[ key ];
|
||
}
|
||
curOption[ key ] = value;
|
||
} else {
|
||
if ( arguments.length === 1 ) {
|
||
return this.options[ key ] === undefined ? null : this.options[ key ];
|
||
}
|
||
options[ key ] = value;
|
||
}
|
||
}
|
||
|
||
this._setOptions( options );
|
||
|
||
return this;
|
||
},
|
||
_setOptions: function( options ) {
|
||
var key;
|
||
|
||
for ( key in options ) {
|
||
this._setOption( key, options[ key ] );
|
||
}
|
||
|
||
return this;
|
||
},
|
||
_setOption: function( key, value ) {
|
||
this.options[ key ] = value;
|
||
|
||
if ( key === "disabled" ) {
|
||
this.widget()
|
||
.toggleClass( this.widgetFullName + "-disabled", !!value );
|
||
|
||
// If the widget is becoming disabled, then nothing is interactive
|
||
if ( value ) {
|
||
this.hoverable.removeClass( "ui-state-hover" );
|
||
this.focusable.removeClass( "ui-state-focus" );
|
||
}
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
enable: function() {
|
||
return this._setOptions({ disabled: false });
|
||
},
|
||
disable: function() {
|
||
return this._setOptions({ disabled: true });
|
||
},
|
||
|
||
_on: function( suppressDisabledCheck, element, handlers ) {
|
||
var delegateElement,
|
||
instance = this;
|
||
|
||
// no suppressDisabledCheck flag, shuffle arguments
|
||
if ( typeof suppressDisabledCheck !== "boolean" ) {
|
||
handlers = element;
|
||
element = suppressDisabledCheck;
|
||
suppressDisabledCheck = false;
|
||
}
|
||
|
||
// no element argument, shuffle and use this.element
|
||
if ( !handlers ) {
|
||
handlers = element;
|
||
element = this.element;
|
||
delegateElement = this.widget();
|
||
} else {
|
||
element = delegateElement = $( element );
|
||
this.bindings = this.bindings.add( element );
|
||
}
|
||
|
||
$.each( handlers, function( event, handler ) {
|
||
function handlerProxy() {
|
||
// allow widgets to customize the disabled handling
|
||
// - disabled as an array instead of boolean
|
||
// - disabled class as method for disabling individual parts
|
||
if ( !suppressDisabledCheck &&
|
||
( instance.options.disabled === true ||
|
||
$( this ).hasClass( "ui-state-disabled" ) ) ) {
|
||
return;
|
||
}
|
||
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
||
.apply( instance, arguments );
|
||
}
|
||
|
||
// copy the guid so direct unbinding works
|
||
if ( typeof handler !== "string" ) {
|
||
handlerProxy.guid = handler.guid =
|
||
handler.guid || handlerProxy.guid || $.guid++;
|
||
}
|
||
|
||
var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
|
||
eventName = match[1] + instance.eventNamespace,
|
||
selector = match[2];
|
||
if ( selector ) {
|
||
delegateElement.delegate( selector, eventName, handlerProxy );
|
||
} else {
|
||
element.bind( eventName, handlerProxy );
|
||
}
|
||
});
|
||
},
|
||
|
||
_off: function( element, eventName ) {
|
||
eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
|
||
this.eventNamespace;
|
||
element.unbind( eventName ).undelegate( eventName );
|
||
|
||
// Clear the stack to avoid memory leaks (#10056)
|
||
this.bindings = $( this.bindings.not( element ).get() );
|
||
this.focusable = $( this.focusable.not( element ).get() );
|
||
this.hoverable = $( this.hoverable.not( element ).get() );
|
||
},
|
||
|
||
_delay: function( handler, delay ) {
|
||
function handlerProxy() {
|
||
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
||
.apply( instance, arguments );
|
||
}
|
||
var instance = this;
|
||
return setTimeout( handlerProxy, delay || 0 );
|
||
},
|
||
|
||
_hoverable: function( element ) {
|
||
this.hoverable = this.hoverable.add( element );
|
||
this._on( element, {
|
||
mouseenter: function( event ) {
|
||
$( event.currentTarget ).addClass( "ui-state-hover" );
|
||
},
|
||
mouseleave: function( event ) {
|
||
$( event.currentTarget ).removeClass( "ui-state-hover" );
|
||
}
|
||
});
|
||
},
|
||
|
||
_focusable: function( element ) {
|
||
this.focusable = this.focusable.add( element );
|
||
this._on( element, {
|
||
focusin: function( event ) {
|
||
$( event.currentTarget ).addClass( "ui-state-focus" );
|
||
},
|
||
focusout: function( event ) {
|
||
$( event.currentTarget ).removeClass( "ui-state-focus" );
|
||
}
|
||
});
|
||
},
|
||
|
||
_trigger: function( type, event, data ) {
|
||
var prop, orig,
|
||
callback = this.options[ type ];
|
||
|
||
data = data || {};
|
||
event = $.Event( event );
|
||
event.type = ( type === this.widgetEventPrefix ?
|
||
type :
|
||
this.widgetEventPrefix + type ).toLowerCase();
|
||
// the original event may come from any element
|
||
// so we need to reset the target on the new event
|
||
event.target = this.element[ 0 ];
|
||
|
||
// copy original event properties over to the new event
|
||
orig = event.originalEvent;
|
||
if ( orig ) {
|
||
for ( prop in orig ) {
|
||
if ( !( prop in event ) ) {
|
||
event[ prop ] = orig[ prop ];
|
||
}
|
||
}
|
||
}
|
||
|
||
this.element.trigger( event, data );
|
||
return !( $.isFunction( callback ) &&
|
||
callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
|
||
event.isDefaultPrevented() );
|
||
}
|
||
};
|
||
|
||
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
|
||
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
|
||
if ( typeof options === "string" ) {
|
||
options = { effect: options };
|
||
}
|
||
var hasOptions,
|
||
effectName = !options ?
|
||
method :
|
||
options === true || typeof options === "number" ?
|
||
defaultEffect :
|
||
options.effect || defaultEffect;
|
||
options = options || {};
|
||
if ( typeof options === "number" ) {
|
||
options = { duration: options };
|
||
}
|
||
hasOptions = !$.isEmptyObject( options );
|
||
options.complete = callback;
|
||
if ( options.delay ) {
|
||
element.delay( options.delay );
|
||
}
|
||
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
|
||
element[ method ]( options );
|
||
} else if ( effectName !== method && element[ effectName ] ) {
|
||
element[ effectName ]( options.duration, options.easing, callback );
|
||
} else {
|
||
element.queue(function( next ) {
|
||
$( this )[ method ]();
|
||
if ( callback ) {
|
||
callback.call( element[ 0 ] );
|
||
}
|
||
next();
|
||
});
|
||
}
|
||
};
|
||
});
|
||
|
||
var widget = $.widget;
|
||
|
||
|
||
/*!
|
||
* jQuery UI Mouse 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/mouse/
|
||
*/
|
||
|
||
|
||
var mouseHandled = false;
|
||
$( document ).mouseup( function() {
|
||
mouseHandled = false;
|
||
});
|
||
|
||
var mouse = $.widget("ui.mouse", {
|
||
version: "1.11.4",
|
||
options: {
|
||
cancel: "input,textarea,button,select,option",
|
||
distance: 1,
|
||
delay: 0
|
||
},
|
||
_mouseInit: function() {
|
||
var that = this;
|
||
|
||
this.element
|
||
.bind("mousedown." + this.widgetName, function(event) {
|
||
return that._mouseDown(event);
|
||
})
|
||
.bind("click." + this.widgetName, function(event) {
|
||
if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
|
||
$.removeData(event.target, that.widgetName + ".preventClickEvent");
|
||
event.stopImmediatePropagation();
|
||
return false;
|
||
}
|
||
});
|
||
|
||
this.started = false;
|
||
},
|
||
|
||
// TODO: make sure destroying one instance of mouse doesn't mess with
|
||
// other instances of mouse
|
||
_mouseDestroy: function() {
|
||
this.element.unbind("." + this.widgetName);
|
||
if ( this._mouseMoveDelegate ) {
|
||
this.document
|
||
.unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
|
||
.unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
|
||
}
|
||
},
|
||
|
||
_mouseDown: function(event) {
|
||
// don't let more than one widget handle mouseStart
|
||
if ( mouseHandled ) {
|
||
return;
|
||
}
|
||
|
||
this._mouseMoved = false;
|
||
|
||
// we may have missed mouseup (out of window)
|
||
(this._mouseStarted && this._mouseUp(event));
|
||
|
||
this._mouseDownEvent = event;
|
||
|
||
var that = this,
|
||
btnIsLeft = (event.which === 1),
|
||
// event.target.nodeName works around a bug in IE 8 with
|
||
// disabled inputs (#7620)
|
||
elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
|
||
if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
|
||
return true;
|
||
}
|
||
|
||
this.mouseDelayMet = !this.options.delay;
|
||
if (!this.mouseDelayMet) {
|
||
this._mouseDelayTimer = setTimeout(function() {
|
||
that.mouseDelayMet = true;
|
||
}, this.options.delay);
|
||
}
|
||
|
||
if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
|
||
this._mouseStarted = (this._mouseStart(event) !== false);
|
||
if (!this._mouseStarted) {
|
||
event.preventDefault();
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// Click event may never have fired (Gecko & Opera)
|
||
if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
|
||
$.removeData(event.target, this.widgetName + ".preventClickEvent");
|
||
}
|
||
|
||
// these delegates are required to keep context
|
||
this._mouseMoveDelegate = function(event) {
|
||
return that._mouseMove(event);
|
||
};
|
||
this._mouseUpDelegate = function(event) {
|
||
return that._mouseUp(event);
|
||
};
|
||
|
||
this.document
|
||
.bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
|
||
.bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
|
||
|
||
event.preventDefault();
|
||
|
||
mouseHandled = true;
|
||
return true;
|
||
},
|
||
|
||
_mouseMove: function(event) {
|
||
// Only check for mouseups outside the document if you've moved inside the document
|
||
// at least once. This prevents the firing of mouseup in the case of IE<9, which will
|
||
// fire a mousemove event if content is placed under the cursor. See #7778
|
||
// Support: IE <9
|
||
if ( this._mouseMoved ) {
|
||
// IE mouseup check - mouseup happened when mouse was out of window
|
||
if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
|
||
return this._mouseUp(event);
|
||
|
||
// Iframe mouseup check - mouseup occurred in another document
|
||
} else if ( !event.which ) {
|
||
return this._mouseUp( event );
|
||
}
|
||
}
|
||
|
||
if ( event.which || event.button ) {
|
||
this._mouseMoved = true;
|
||
}
|
||
|
||
if (this._mouseStarted) {
|
||
this._mouseDrag(event);
|
||
return event.preventDefault();
|
||
}
|
||
|
||
if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
|
||
this._mouseStarted =
|
||
(this._mouseStart(this._mouseDownEvent, event) !== false);
|
||
(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
|
||
}
|
||
|
||
return !this._mouseStarted;
|
||
},
|
||
|
||
_mouseUp: function(event) {
|
||
this.document
|
||
.unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
|
||
.unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
|
||
|
||
if (this._mouseStarted) {
|
||
this._mouseStarted = false;
|
||
|
||
if (event.target === this._mouseDownEvent.target) {
|
||
$.data(event.target, this.widgetName + ".preventClickEvent", true);
|
||
}
|
||
|
||
this._mouseStop(event);
|
||
}
|
||
|
||
mouseHandled = false;
|
||
return false;
|
||
},
|
||
|
||
_mouseDistanceMet: function(event) {
|
||
return (Math.max(
|
||
Math.abs(this._mouseDownEvent.pageX - event.pageX),
|
||
Math.abs(this._mouseDownEvent.pageY - event.pageY)
|
||
) >= this.options.distance
|
||
);
|
||
},
|
||
|
||
_mouseDelayMet: function(/* event */) {
|
||
return this.mouseDelayMet;
|
||
},
|
||
|
||
// These are placeholder methods, to be overriden by extending plugin
|
||
_mouseStart: function(/* event */) {},
|
||
_mouseDrag: function(/* event */) {},
|
||
_mouseStop: function(/* event */) {},
|
||
_mouseCapture: function(/* event */) { return true; }
|
||
});
|
||
|
||
|
||
/*!
|
||
* jQuery UI Position 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/position/
|
||
*/
|
||
|
||
(function() {
|
||
|
||
$.ui = $.ui || {};
|
||
|
||
var cachedScrollbarWidth, supportsOffsetFractions,
|
||
max = Math.max,
|
||
abs = Math.abs,
|
||
round = Math.round,
|
||
rhorizontal = /left|center|right/,
|
||
rvertical = /top|center|bottom/,
|
||
roffset = /[\+\-]\d+(\.[\d]+)?%?/,
|
||
rposition = /^\w+/,
|
||
rpercent = /%$/,
|
||
_position = $.fn.position;
|
||
|
||
function getOffsets( offsets, width, height ) {
|
||
return [
|
||
parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
|
||
parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
|
||
];
|
||
}
|
||
|
||
function parseCss( element, property ) {
|
||
return parseInt( $.css( element, property ), 10 ) || 0;
|
||
}
|
||
|
||
function getDimensions( elem ) {
|
||
var raw = elem[0];
|
||
if ( raw.nodeType === 9 ) {
|
||
return {
|
||
width: elem.width(),
|
||
height: elem.height(),
|
||
offset: { top: 0, left: 0 }
|
||
};
|
||
}
|
||
if ( $.isWindow( raw ) ) {
|
||
return {
|
||
width: elem.width(),
|
||
height: elem.height(),
|
||
offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
|
||
};
|
||
}
|
||
if ( raw.preventDefault ) {
|
||
return {
|
||
width: 0,
|
||
height: 0,
|
||
offset: { top: raw.pageY, left: raw.pageX }
|
||
};
|
||
}
|
||
return {
|
||
width: elem.outerWidth(),
|
||
height: elem.outerHeight(),
|
||
offset: elem.offset()
|
||
};
|
||
}
|
||
|
||
$.position = {
|
||
scrollbarWidth: function() {
|
||
if ( cachedScrollbarWidth !== undefined ) {
|
||
return cachedScrollbarWidth;
|
||
}
|
||
var w1, w2,
|
||
div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
|
||
innerDiv = div.children()[0];
|
||
|
||
$( "body" ).append( div );
|
||
w1 = innerDiv.offsetWidth;
|
||
div.css( "overflow", "scroll" );
|
||
|
||
w2 = innerDiv.offsetWidth;
|
||
|
||
if ( w1 === w2 ) {
|
||
w2 = div[0].clientWidth;
|
||
}
|
||
|
||
div.remove();
|
||
|
||
return (cachedScrollbarWidth = w1 - w2);
|
||
},
|
||
getScrollInfo: function( within ) {
|
||
var overflowX = within.isWindow || within.isDocument ? "" :
|
||
within.element.css( "overflow-x" ),
|
||
overflowY = within.isWindow || within.isDocument ? "" :
|
||
within.element.css( "overflow-y" ),
|
||
hasOverflowX = overflowX === "scroll" ||
|
||
( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
|
||
hasOverflowY = overflowY === "scroll" ||
|
||
( overflowY === "auto" && within.height < within.element[0].scrollHeight );
|
||
return {
|
||
width: hasOverflowY ? $.position.scrollbarWidth() : 0,
|
||
height: hasOverflowX ? $.position.scrollbarWidth() : 0
|
||
};
|
||
},
|
||
getWithinInfo: function( element ) {
|
||
var withinElement = $( element || window ),
|
||
isWindow = $.isWindow( withinElement[0] ),
|
||
isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
|
||
return {
|
||
element: withinElement,
|
||
isWindow: isWindow,
|
||
isDocument: isDocument,
|
||
offset: withinElement.offset() || { left: 0, top: 0 },
|
||
scrollLeft: withinElement.scrollLeft(),
|
||
scrollTop: withinElement.scrollTop(),
|
||
|
||
// support: jQuery 1.6.x
|
||
// jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
|
||
width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
|
||
height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
|
||
};
|
||
}
|
||
};
|
||
|
||
$.fn.position = function( options ) {
|
||
if ( !options || !options.of ) {
|
||
return _position.apply( this, arguments );
|
||
}
|
||
|
||
// make a copy, we don't want to modify arguments
|
||
options = $.extend( {}, options );
|
||
|
||
var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
|
||
target = $( options.of ),
|
||
within = $.position.getWithinInfo( options.within ),
|
||
scrollInfo = $.position.getScrollInfo( within ),
|
||
collision = ( options.collision || "flip" ).split( " " ),
|
||
offsets = {};
|
||
|
||
dimensions = getDimensions( target );
|
||
if ( target[0].preventDefault ) {
|
||
// force left top to allow flipping
|
||
options.at = "left top";
|
||
}
|
||
targetWidth = dimensions.width;
|
||
targetHeight = dimensions.height;
|
||
targetOffset = dimensions.offset;
|
||
// clone to reuse original targetOffset later
|
||
basePosition = $.extend( {}, targetOffset );
|
||
|
||
// force my and at to have valid horizontal and vertical positions
|
||
// if a value is missing or invalid, it will be converted to center
|
||
$.each( [ "my", "at" ], function() {
|
||
var pos = ( options[ this ] || "" ).split( " " ),
|
||
horizontalOffset,
|
||
verticalOffset;
|
||
|
||
if ( pos.length === 1) {
|
||
pos = rhorizontal.test( pos[ 0 ] ) ?
|
||
pos.concat( [ "center" ] ) :
|
||
rvertical.test( pos[ 0 ] ) ?
|
||
[ "center" ].concat( pos ) :
|
||
[ "center", "center" ];
|
||
}
|
||
pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
|
||
pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
|
||
|
||
// calculate offsets
|
||
horizontalOffset = roffset.exec( pos[ 0 ] );
|
||
verticalOffset = roffset.exec( pos[ 1 ] );
|
||
offsets[ this ] = [
|
||
horizontalOffset ? horizontalOffset[ 0 ] : 0,
|
||
verticalOffset ? verticalOffset[ 0 ] : 0
|
||
];
|
||
|
||
// reduce to just the positions without the offsets
|
||
options[ this ] = [
|
||
rposition.exec( pos[ 0 ] )[ 0 ],
|
||
rposition.exec( pos[ 1 ] )[ 0 ]
|
||
];
|
||
});
|
||
|
||
// normalize collision option
|
||
if ( collision.length === 1 ) {
|
||
collision[ 1 ] = collision[ 0 ];
|
||
}
|
||
|
||
if ( options.at[ 0 ] === "right" ) {
|
||
basePosition.left += targetWidth;
|
||
} else if ( options.at[ 0 ] === "center" ) {
|
||
basePosition.left += targetWidth / 2;
|
||
}
|
||
|
||
if ( options.at[ 1 ] === "bottom" ) {
|
||
basePosition.top += targetHeight;
|
||
} else if ( options.at[ 1 ] === "center" ) {
|
||
basePosition.top += targetHeight / 2;
|
||
}
|
||
|
||
atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
|
||
basePosition.left += atOffset[ 0 ];
|
||
basePosition.top += atOffset[ 1 ];
|
||
|
||
return this.each(function() {
|
||
var collisionPosition, using,
|
||
elem = $( this ),
|
||
elemWidth = elem.outerWidth(),
|
||
elemHeight = elem.outerHeight(),
|
||
marginLeft = parseCss( this, "marginLeft" ),
|
||
marginTop = parseCss( this, "marginTop" ),
|
||
collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
|
||
collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
|
||
position = $.extend( {}, basePosition ),
|
||
myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
|
||
|
||
if ( options.my[ 0 ] === "right" ) {
|
||
position.left -= elemWidth;
|
||
} else if ( options.my[ 0 ] === "center" ) {
|
||
position.left -= elemWidth / 2;
|
||
}
|
||
|
||
if ( options.my[ 1 ] === "bottom" ) {
|
||
position.top -= elemHeight;
|
||
} else if ( options.my[ 1 ] === "center" ) {
|
||
position.top -= elemHeight / 2;
|
||
}
|
||
|
||
position.left += myOffset[ 0 ];
|
||
position.top += myOffset[ 1 ];
|
||
|
||
// if the browser doesn't support fractions, then round for consistent results
|
||
if ( !supportsOffsetFractions ) {
|
||
position.left = round( position.left );
|
||
position.top = round( position.top );
|
||
}
|
||
|
||
collisionPosition = {
|
||
marginLeft: marginLeft,
|
||
marginTop: marginTop
|
||
};
|
||
|
||
$.each( [ "left", "top" ], function( i, dir ) {
|
||
if ( $.ui.position[ collision[ i ] ] ) {
|
||
$.ui.position[ collision[ i ] ][ dir ]( position, {
|
||
targetWidth: targetWidth,
|
||
targetHeight: targetHeight,
|
||
elemWidth: elemWidth,
|
||
elemHeight: elemHeight,
|
||
collisionPosition: collisionPosition,
|
||
collisionWidth: collisionWidth,
|
||
collisionHeight: collisionHeight,
|
||
offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
|
||
my: options.my,
|
||
at: options.at,
|
||
within: within,
|
||
elem: elem
|
||
});
|
||
}
|
||
});
|
||
|
||
if ( options.using ) {
|
||
// adds feedback as second argument to using callback, if present
|
||
using = function( props ) {
|
||
var left = targetOffset.left - position.left,
|
||
right = left + targetWidth - elemWidth,
|
||
top = targetOffset.top - position.top,
|
||
bottom = top + targetHeight - elemHeight,
|
||
feedback = {
|
||
target: {
|
||
element: target,
|
||
left: targetOffset.left,
|
||
top: targetOffset.top,
|
||
width: targetWidth,
|
||
height: targetHeight
|
||
},
|
||
element: {
|
||
element: elem,
|
||
left: position.left,
|
||
top: position.top,
|
||
width: elemWidth,
|
||
height: elemHeight
|
||
},
|
||
horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
|
||
vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
|
||
};
|
||
if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
|
||
feedback.horizontal = "center";
|
||
}
|
||
if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
|
||
feedback.vertical = "middle";
|
||
}
|
||
if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
|
||
feedback.important = "horizontal";
|
||
} else {
|
||
feedback.important = "vertical";
|
||
}
|
||
options.using.call( this, props, feedback );
|
||
};
|
||
}
|
||
|
||
elem.offset( $.extend( position, { using: using } ) );
|
||
});
|
||
};
|
||
|
||
$.ui.position = {
|
||
fit: {
|
||
left: function( position, data ) {
|
||
var within = data.within,
|
||
withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
|
||
outerWidth = within.width,
|
||
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
|
||
overLeft = withinOffset - collisionPosLeft,
|
||
overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
|
||
newOverRight;
|
||
|
||
// element is wider than within
|
||
if ( data.collisionWidth > outerWidth ) {
|
||
// element is initially over the left side of within
|
||
if ( overLeft > 0 && overRight <= 0 ) {
|
||
newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
|
||
position.left += overLeft - newOverRight;
|
||
// element is initially over right side of within
|
||
} else if ( overRight > 0 && overLeft <= 0 ) {
|
||
position.left = withinOffset;
|
||
// element is initially over both left and right sides of within
|
||
} else {
|
||
if ( overLeft > overRight ) {
|
||
position.left = withinOffset + outerWidth - data.collisionWidth;
|
||
} else {
|
||
position.left = withinOffset;
|
||
}
|
||
}
|
||
// too far left -> align with left edge
|
||
} else if ( overLeft > 0 ) {
|
||
position.left += overLeft;
|
||
// too far right -> align with right edge
|
||
} else if ( overRight > 0 ) {
|
||
position.left -= overRight;
|
||
// adjust based on position and margin
|
||
} else {
|
||
position.left = max( position.left - collisionPosLeft, position.left );
|
||
}
|
||
},
|
||
top: function( position, data ) {
|
||
var within = data.within,
|
||
withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
|
||
outerHeight = data.within.height,
|
||
collisionPosTop = position.top - data.collisionPosition.marginTop,
|
||
overTop = withinOffset - collisionPosTop,
|
||
overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
|
||
newOverBottom;
|
||
|
||
// element is taller than within
|
||
if ( data.collisionHeight > outerHeight ) {
|
||
// element is initially over the top of within
|
||
if ( overTop > 0 && overBottom <= 0 ) {
|
||
newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
|
||
position.top += overTop - newOverBottom;
|
||
// element is initially over bottom of within
|
||
} else if ( overBottom > 0 && overTop <= 0 ) {
|
||
position.top = withinOffset;
|
||
// element is initially over both top and bottom of within
|
||
} else {
|
||
if ( overTop > overBottom ) {
|
||
position.top = withinOffset + outerHeight - data.collisionHeight;
|
||
} else {
|
||
position.top = withinOffset;
|
||
}
|
||
}
|
||
// too far up -> align with top
|
||
} else if ( overTop > 0 ) {
|
||
position.top += overTop;
|
||
// too far down -> align with bottom edge
|
||
} else if ( overBottom > 0 ) {
|
||
position.top -= overBottom;
|
||
// adjust based on position and margin
|
||
} else {
|
||
position.top = max( position.top - collisionPosTop, position.top );
|
||
}
|
||
}
|
||
},
|
||
flip: {
|
||
left: function( position, data ) {
|
||
var within = data.within,
|
||
withinOffset = within.offset.left + within.scrollLeft,
|
||
outerWidth = within.width,
|
||
offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
|
||
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
|
||
overLeft = collisionPosLeft - offsetLeft,
|
||
overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
|
||
myOffset = data.my[ 0 ] === "left" ?
|
||
-data.elemWidth :
|
||
data.my[ 0 ] === "right" ?
|
||
data.elemWidth :
|
||
0,
|
||
atOffset = data.at[ 0 ] === "left" ?
|
||
data.targetWidth :
|
||
data.at[ 0 ] === "right" ?
|
||
-data.targetWidth :
|
||
0,
|
||
offset = -2 * data.offset[ 0 ],
|
||
newOverRight,
|
||
newOverLeft;
|
||
|
||
if ( overLeft < 0 ) {
|
||
newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
|
||
if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
|
||
position.left += myOffset + atOffset + offset;
|
||
}
|
||
} else if ( overRight > 0 ) {
|
||
newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
|
||
if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
|
||
position.left += myOffset + atOffset + offset;
|
||
}
|
||
}
|
||
},
|
||
top: function( position, data ) {
|
||
var within = data.within,
|
||
withinOffset = within.offset.top + within.scrollTop,
|
||
outerHeight = within.height,
|
||
offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
|
||
collisionPosTop = position.top - data.collisionPosition.marginTop,
|
||
overTop = collisionPosTop - offsetTop,
|
||
overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
|
||
top = data.my[ 1 ] === "top",
|
||
myOffset = top ?
|
||
-data.elemHeight :
|
||
data.my[ 1 ] === "bottom" ?
|
||
data.elemHeight :
|
||
0,
|
||
atOffset = data.at[ 1 ] === "top" ?
|
||
data.targetHeight :
|
||
data.at[ 1 ] === "bottom" ?
|
||
-data.targetHeight :
|
||
0,
|
||
offset = -2 * data.offset[ 1 ],
|
||
newOverTop,
|
||
newOverBottom;
|
||
if ( overTop < 0 ) {
|
||
newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
|
||
if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
|
||
position.top += myOffset + atOffset + offset;
|
||
}
|
||
} else if ( overBottom > 0 ) {
|
||
newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
|
||
if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
|
||
position.top += myOffset + atOffset + offset;
|
||
}
|
||
}
|
||
}
|
||
},
|
||
flipfit: {
|
||
left: function() {
|
||
$.ui.position.flip.left.apply( this, arguments );
|
||
$.ui.position.fit.left.apply( this, arguments );
|
||
},
|
||
top: function() {
|
||
$.ui.position.flip.top.apply( this, arguments );
|
||
$.ui.position.fit.top.apply( this, arguments );
|
||
}
|
||
}
|
||
};
|
||
|
||
// fraction support test
|
||
(function() {
|
||
var testElement, testElementParent, testElementStyle, offsetLeft, i,
|
||
body = document.getElementsByTagName( "body" )[ 0 ],
|
||
div = document.createElement( "div" );
|
||
|
||
//Create a "fake body" for testing based on method used in jQuery.support
|
||
testElement = document.createElement( body ? "div" : "body" );
|
||
testElementStyle = {
|
||
visibility: "hidden",
|
||
width: 0,
|
||
height: 0,
|
||
border: 0,
|
||
margin: 0,
|
||
background: "none"
|
||
};
|
||
if ( body ) {
|
||
$.extend( testElementStyle, {
|
||
position: "absolute",
|
||
left: "-1000px",
|
||
top: "-1000px"
|
||
});
|
||
}
|
||
for ( i in testElementStyle ) {
|
||
testElement.style[ i ] = testElementStyle[ i ];
|
||
}
|
||
testElement.appendChild( div );
|
||
testElementParent = body || document.documentElement;
|
||
testElementParent.insertBefore( testElement, testElementParent.firstChild );
|
||
|
||
div.style.cssText = "position: absolute; left: 10.7432222px;";
|
||
|
||
offsetLeft = $( div ).offset().left;
|
||
supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
|
||
|
||
testElement.innerHTML = "";
|
||
testElementParent.removeChild( testElement );
|
||
})();
|
||
|
||
})();
|
||
|
||
var position = $.ui.position;
|
||
|
||
|
||
/*!
|
||
* jQuery UI Datepicker 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/datepicker/
|
||
*/
|
||
|
||
|
||
$.extend($.ui, { datepicker: { version: "1.11.4" } });
|
||
|
||
var datepicker_instActive;
|
||
|
||
function datepicker_getZindex( elem ) {
|
||
var position, value;
|
||
while ( elem.length && elem[ 0 ] !== document ) {
|
||
// Ignore z-index if position is set to a value where z-index is ignored by the browser
|
||
// This makes behavior of this function consistent across browsers
|
||
// WebKit always returns auto if the element is positioned
|
||
position = elem.css( "position" );
|
||
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
|
||
// IE returns 0 when zIndex is not specified
|
||
// other browsers return a string
|
||
// we ignore the case of nested elements with an explicit value of 0
|
||
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
|
||
value = parseInt( elem.css( "zIndex" ), 10 );
|
||
if ( !isNaN( value ) && value !== 0 ) {
|
||
return value;
|
||
}
|
||
}
|
||
elem = elem.parent();
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
/* Date picker manager.
|
||
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
|
||
Settings for (groups of) date pickers are maintained in an instance object,
|
||
allowing multiple different settings on the same page. */
|
||
|
||
function Datepicker() {
|
||
this._curInst = null; // The current instance in use
|
||
this._keyEvent = false; // If the last event was a key event
|
||
this._disabledInputs = []; // List of date picker inputs that have been disabled
|
||
this._datepickerShowing = false; // True if the popup picker is showing , false if not
|
||
this._inDialog = false; // True if showing within a "dialog", false if not
|
||
this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
|
||
this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
|
||
this._appendClass = "ui-datepicker-append"; // The name of the append marker class
|
||
this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
|
||
this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
|
||
this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
|
||
this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
|
||
this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
|
||
this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
|
||
this.regional = []; // Available regional settings, indexed by language code
|
||
this.regional[""] = { // Default regional settings
|
||
closeText: "Done", // Display text for close link
|
||
prevText: "Prev", // Display text for previous month link
|
||
nextText: "Next", // Display text for next month link
|
||
currentText: "Today", // Display text for current month link
|
||
monthNames: ["January","February","March","April","May","June",
|
||
"July","August","September","October","November","December"], // Names of months for drop-down and formatting
|
||
monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
|
||
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
|
||
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
|
||
dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
|
||
weekHeader: "Wk", // Column header for week of the year
|
||
dateFormat: "mm/dd/yy", // See format options on parseDate
|
||
firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
|
||
isRTL: false, // True if right-to-left language, false if left-to-right
|
||
showMonthAfterYear: false, // True if the year select precedes month, false for month then year
|
||
yearSuffix: "" // Additional text to append to the year in the month headers
|
||
};
|
||
this._defaults = { // Global defaults for all the date picker instances
|
||
showOn: "focus", // "focus" for popup on focus,
|
||
// "button" for trigger button, or "both" for either
|
||
showAnim: "fadeIn", // Name of jQuery animation for popup
|
||
showOptions: {}, // Options for enhanced animations
|
||
defaultDate: null, // Used when field is blank: actual date,
|
||
// +/-number for offset from today, null for today
|
||
appendText: "", // Display text following the input box, e.g. showing the format
|
||
buttonText: "...", // Text for trigger button
|
||
buttonImage: "", // URL for trigger button image
|
||
buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
|
||
hideIfNoPrevNext: false, // True to hide next/previous month links
|
||
// if not applicable, false to just disable them
|
||
navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
|
||
gotoCurrent: false, // True if today link goes back to current selection instead
|
||
changeMonth: false, // True if month can be selected directly, false if only prev/next
|
||
changeYear: false, // True if year can be selected directly, false if only prev/next
|
||
yearRange: "c-10:c+10", // Range of years to display in drop-down,
|
||
// either relative to today's year (-nn:+nn), relative to currently displayed year
|
||
// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
|
||
showOtherMonths: false, // True to show dates in other months, false to leave blank
|
||
selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
|
||
showWeek: false, // True to show week of the year, false to not show it
|
||
calculateWeek: this.iso8601Week, // How to calculate the week of the year,
|
||
// takes a Date and returns the number of the week for it
|
||
shortYearCutoff: "+10", // Short year values < this are in the current century,
|
||
// > this are in the previous century,
|
||
// string value starting with "+" for current year + value
|
||
minDate: null, // The earliest selectable date, or null for no limit
|
||
maxDate: null, // The latest selectable date, or null for no limit
|
||
duration: "fast", // Duration of display/closure
|
||
beforeShowDay: null, // Function that takes a date and returns an array with
|
||
// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
|
||
// [2] = cell title (optional), e.g. $.datepicker.noWeekends
|
||
beforeShow: null, // Function that takes an input field and
|
||
// returns a set of custom settings for the date picker
|
||
onSelect: null, // Define a callback function when a date is selected
|
||
onChangeMonthYear: null, // Define a callback function when the month or year is changed
|
||
onClose: null, // Define a callback function when the datepicker is closed
|
||
numberOfMonths: 1, // Number of months to show at a time
|
||
showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
|
||
stepMonths: 1, // Number of months to step back/forward
|
||
stepBigMonths: 12, // Number of months to step back/forward for the big links
|
||
altField: "", // Selector for an alternate field to store selected dates into
|
||
altFormat: "", // The date format to use for the alternate field
|
||
constrainInput: true, // The input is constrained by the current date format
|
||
showButtonPanel: false, // True to show button panel, false to not show it
|
||
autoSize: false, // True to size the input for the date format, false to leave as is
|
||
disabled: false // The initial disabled state
|
||
};
|
||
$.extend(this._defaults, this.regional[""]);
|
||
this.regional.en = $.extend( true, {}, this.regional[ "" ]);
|
||
this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
|
||
this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
|
||
}
|
||
|
||
$.extend(Datepicker.prototype, {
|
||
/* Class name added to elements to indicate already configured with a date picker. */
|
||
markerClassName: "hasDatepicker",
|
||
|
||
//Keep track of the maximum number of rows displayed (see #7043)
|
||
maxRows: 4,
|
||
|
||
// TODO rename to "widget" when switching to widget factory
|
||
_widgetDatepicker: function() {
|
||
return this.dpDiv;
|
||
},
|
||
|
||
/* Override the default settings for all instances of the date picker.
|
||
* @param settings object - the new settings to use as defaults (anonymous object)
|
||
* @return the manager object
|
||
*/
|
||
setDefaults: function(settings) {
|
||
datepicker_extendRemove(this._defaults, settings || {});
|
||
return this;
|
||
},
|
||
|
||
/* Attach the date picker to a jQuery selection.
|
||
* @param target element - the target input field or division or span
|
||
* @param settings object - the new settings to use for this date picker instance (anonymous)
|
||
*/
|
||
_attachDatepicker: function(target, settings) {
|
||
var nodeName, inline, inst;
|
||
nodeName = target.nodeName.toLowerCase();
|
||
inline = (nodeName === "div" || nodeName === "span");
|
||
if (!target.id) {
|
||
this.uuid += 1;
|
||
target.id = "dp" + this.uuid;
|
||
}
|
||
inst = this._newInst($(target), inline);
|
||
inst.settings = $.extend({}, settings || {});
|
||
if (nodeName === "input") {
|
||
this._connectDatepicker(target, inst);
|
||
} else if (inline) {
|
||
this._inlineDatepicker(target, inst);
|
||
}
|
||
},
|
||
|
||
/* Create a new instance object. */
|
||
_newInst: function(target, inline) {
|
||
var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
|
||
return {id: id, input: target, // associated target
|
||
selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
|
||
drawMonth: 0, drawYear: 0, // month being drawn
|
||
inline: inline, // is datepicker inline or not
|
||
dpDiv: (!inline ? this.dpDiv : // presentation div
|
||
datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
|
||
},
|
||
|
||
/* Attach the date picker to an input field. */
|
||
_connectDatepicker: function(target, inst) {
|
||
var input = $(target);
|
||
inst.append = $([]);
|
||
inst.trigger = $([]);
|
||
if (input.hasClass(this.markerClassName)) {
|
||
return;
|
||
}
|
||
this._attachments(input, inst);
|
||
input.addClass(this.markerClassName).keydown(this._doKeyDown).
|
||
keypress(this._doKeyPress).keyup(this._doKeyUp);
|
||
this._autoSize(inst);
|
||
$.data(target, "datepicker", inst);
|
||
//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
|
||
if( inst.settings.disabled ) {
|
||
this._disableDatepicker( target );
|
||
}
|
||
},
|
||
|
||
/* Make attachments based on settings. */
|
||
_attachments: function(input, inst) {
|
||
var showOn, buttonText, buttonImage,
|
||
appendText = this._get(inst, "appendText"),
|
||
isRTL = this._get(inst, "isRTL");
|
||
|
||
if (inst.append) {
|
||
inst.append.remove();
|
||
}
|
||
if (appendText) {
|
||
inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
|
||
input[isRTL ? "before" : "after"](inst.append);
|
||
}
|
||
|
||
input.unbind("focus", this._showDatepicker);
|
||
|
||
if (inst.trigger) {
|
||
inst.trigger.remove();
|
||
}
|
||
|
||
showOn = this._get(inst, "showOn");
|
||
if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
|
||
input.focus(this._showDatepicker);
|
||
}
|
||
if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
|
||
buttonText = this._get(inst, "buttonText");
|
||
buttonImage = this._get(inst, "buttonImage");
|
||
inst.trigger = $(this._get(inst, "buttonImageOnly") ?
|
||
$("<img/>").addClass(this._triggerClass).
|
||
attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
|
||
$("<button type='button'></button>").addClass(this._triggerClass).
|
||
html(!buttonImage ? buttonText : $("<img/>").attr(
|
||
{ src:buttonImage, alt:buttonText, title:buttonText })));
|
||
input[isRTL ? "before" : "after"](inst.trigger);
|
||
inst.trigger.click(function() {
|
||
if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
|
||
$.datepicker._hideDatepicker();
|
||
} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
|
||
$.datepicker._hideDatepicker();
|
||
$.datepicker._showDatepicker(input[0]);
|
||
} else {
|
||
$.datepicker._showDatepicker(input[0]);
|
||
}
|
||
return false;
|
||
});
|
||
}
|
||
},
|
||
|
||
/* Apply the maximum length for the date format. */
|
||
_autoSize: function(inst) {
|
||
if (this._get(inst, "autoSize") && !inst.inline) {
|
||
var findMax, max, maxI, i,
|
||
date = new Date(2009, 12 - 1, 20), // Ensure double digits
|
||
dateFormat = this._get(inst, "dateFormat");
|
||
|
||
if (dateFormat.match(/[DM]/)) {
|
||
findMax = function(names) {
|
||
max = 0;
|
||
maxI = 0;
|
||
for (i = 0; i < names.length; i++) {
|
||
if (names[i].length > max) {
|
||
max = names[i].length;
|
||
maxI = i;
|
||
}
|
||
}
|
||
return maxI;
|
||
};
|
||
date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
|
||
"monthNames" : "monthNamesShort"))));
|
||
date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
|
||
"dayNames" : "dayNamesShort"))) + 20 - date.getDay());
|
||
}
|
||
inst.input.attr("size", this._formatDate(inst, date).length);
|
||
}
|
||
},
|
||
|
||
/* Attach an inline date picker to a div. */
|
||
_inlineDatepicker: function(target, inst) {
|
||
var divSpan = $(target);
|
||
if (divSpan.hasClass(this.markerClassName)) {
|
||
return;
|
||
}
|
||
divSpan.addClass(this.markerClassName).append(inst.dpDiv);
|
||
$.data(target, "datepicker", inst);
|
||
this._setDate(inst, this._getDefaultDate(inst), true);
|
||
this._updateDatepicker(inst);
|
||
this._updateAlternate(inst);
|
||
//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
|
||
if( inst.settings.disabled ) {
|
||
this._disableDatepicker( target );
|
||
}
|
||
// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
|
||
// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
|
||
inst.dpDiv.css( "display", "block" );
|
||
},
|
||
|
||
/* Pop-up the date picker in a "dialog" box.
|
||
* @param input element - ignored
|
||
* @param date string or Date - the initial date to display
|
||
* @param onSelect function - the function to call when a date is selected
|
||
* @param settings object - update the dialog date picker instance's settings (anonymous object)
|
||
* @param pos int[2] - coordinates for the dialog's position within the screen or
|
||
* event - with x/y coordinates or
|
||
* leave empty for default (screen centre)
|
||
* @return the manager object
|
||
*/
|
||
_dialogDatepicker: function(input, date, onSelect, settings, pos) {
|
||
var id, browserWidth, browserHeight, scrollX, scrollY,
|
||
inst = this._dialogInst; // internal instance
|
||
|
||
if (!inst) {
|
||
this.uuid += 1;
|
||
id = "dp" + this.uuid;
|
||
this._dialogInput = $("<input type='text' id='" + id +
|
||
"' style='position: absolute; top: -100px; width: 0px;'/>");
|
||
this._dialogInput.keydown(this._doKeyDown);
|
||
$("body").append(this._dialogInput);
|
||
inst = this._dialogInst = this._newInst(this._dialogInput, false);
|
||
inst.settings = {};
|
||
$.data(this._dialogInput[0], "datepicker", inst);
|
||
}
|
||
datepicker_extendRemove(inst.settings, settings || {});
|
||
date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
|
||
this._dialogInput.val(date);
|
||
|
||
this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
|
||
if (!this._pos) {
|
||
browserWidth = document.documentElement.clientWidth;
|
||
browserHeight = document.documentElement.clientHeight;
|
||
scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||
scrollY = document.documentElement.scrollTop || document.body.scrollTop;
|
||
this._pos = // should use actual width/height below
|
||
[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
|
||
}
|
||
|
||
// move input on screen for focus, but hidden behind dialog
|
||
this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
|
||
inst.settings.onSelect = onSelect;
|
||
this._inDialog = true;
|
||
this.dpDiv.addClass(this._dialogClass);
|
||
this._showDatepicker(this._dialogInput[0]);
|
||
if ($.blockUI) {
|
||
$.blockUI(this.dpDiv);
|
||
}
|
||
$.data(this._dialogInput[0], "datepicker", inst);
|
||
return this;
|
||
},
|
||
|
||
/* Detach a datepicker from its control.
|
||
* @param target element - the target input field or division or span
|
||
*/
|
||
_destroyDatepicker: function(target) {
|
||
var nodeName,
|
||
$target = $(target),
|
||
inst = $.data(target, "datepicker");
|
||
|
||
if (!$target.hasClass(this.markerClassName)) {
|
||
return;
|
||
}
|
||
|
||
nodeName = target.nodeName.toLowerCase();
|
||
$.removeData(target, "datepicker");
|
||
if (nodeName === "input") {
|
||
inst.append.remove();
|
||
inst.trigger.remove();
|
||
$target.removeClass(this.markerClassName).
|
||
unbind("focus", this._showDatepicker).
|
||
unbind("keydown", this._doKeyDown).
|
||
unbind("keypress", this._doKeyPress).
|
||
unbind("keyup", this._doKeyUp);
|
||
} else if (nodeName === "div" || nodeName === "span") {
|
||
$target.removeClass(this.markerClassName).empty();
|
||
}
|
||
|
||
if ( datepicker_instActive === inst ) {
|
||
datepicker_instActive = null;
|
||
}
|
||
},
|
||
|
||
/* Enable the date picker to a jQuery selection.
|
||
* @param target element - the target input field or division or span
|
||
*/
|
||
_enableDatepicker: function(target) {
|
||
var nodeName, inline,
|
||
$target = $(target),
|
||
inst = $.data(target, "datepicker");
|
||
|
||
if (!$target.hasClass(this.markerClassName)) {
|
||
return;
|
||
}
|
||
|
||
nodeName = target.nodeName.toLowerCase();
|
||
if (nodeName === "input") {
|
||
target.disabled = false;
|
||
inst.trigger.filter("button").
|
||
each(function() { this.disabled = false; }).end().
|
||
filter("img").css({opacity: "1.0", cursor: ""});
|
||
} else if (nodeName === "div" || nodeName === "span") {
|
||
inline = $target.children("." + this._inlineClass);
|
||
inline.children().removeClass("ui-state-disabled");
|
||
inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
|
||
prop("disabled", false);
|
||
}
|
||
this._disabledInputs = $.map(this._disabledInputs,
|
||
function(value) { return (value === target ? null : value); }); // delete entry
|
||
},
|
||
|
||
/* Disable the date picker to a jQuery selection.
|
||
* @param target element - the target input field or division or span
|
||
*/
|
||
_disableDatepicker: function(target) {
|
||
var nodeName, inline,
|
||
$target = $(target),
|
||
inst = $.data(target, "datepicker");
|
||
|
||
if (!$target.hasClass(this.markerClassName)) {
|
||
return;
|
||
}
|
||
|
||
nodeName = target.nodeName.toLowerCase();
|
||
if (nodeName === "input") {
|
||
target.disabled = true;
|
||
inst.trigger.filter("button").
|
||
each(function() { this.disabled = true; }).end().
|
||
filter("img").css({opacity: "0.5", cursor: "default"});
|
||
} else if (nodeName === "div" || nodeName === "span") {
|
||
inline = $target.children("." + this._inlineClass);
|
||
inline.children().addClass("ui-state-disabled");
|
||
inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
|
||
prop("disabled", true);
|
||
}
|
||
this._disabledInputs = $.map(this._disabledInputs,
|
||
function(value) { return (value === target ? null : value); }); // delete entry
|
||
this._disabledInputs[this._disabledInputs.length] = target;
|
||
},
|
||
|
||
/* Is the first field in a jQuery collection disabled as a datepicker?
|
||
* @param target element - the target input field or division or span
|
||
* @return boolean - true if disabled, false if enabled
|
||
*/
|
||
_isDisabledDatepicker: function(target) {
|
||
if (!target) {
|
||
return false;
|
||
}
|
||
for (var i = 0; i < this._disabledInputs.length; i++) {
|
||
if (this._disabledInputs[i] === target) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
},
|
||
|
||
/* Retrieve the instance data for the target control.
|
||
* @param target element - the target input field or division or span
|
||
* @return object - the associated instance data
|
||
* @throws error if a jQuery problem getting data
|
||
*/
|
||
_getInst: function(target) {
|
||
try {
|
||
return $.data(target, "datepicker");
|
||
}
|
||
catch (err) {
|
||
throw "Missing instance data for this datepicker";
|
||
}
|
||
},
|
||
|
||
/* Update or retrieve the settings for a date picker attached to an input field or division.
|
||
* @param target element - the target input field or division or span
|
||
* @param name object - the new settings to update or
|
||
* string - the name of the setting to change or retrieve,
|
||
* when retrieving also "all" for all instance settings or
|
||
* "defaults" for all global defaults
|
||
* @param value any - the new value for the setting
|
||
* (omit if above is an object or to retrieve a value)
|
||
*/
|
||
_optionDatepicker: function(target, name, value) {
|
||
var settings, date, minDate, maxDate,
|
||
inst = this._getInst(target);
|
||
|
||
if (arguments.length === 2 && typeof name === "string") {
|
||
return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
|
||
(inst ? (name === "all" ? $.extend({}, inst.settings) :
|
||
this._get(inst, name)) : null));
|
||
}
|
||
|
||
settings = name || {};
|
||
if (typeof name === "string") {
|
||
settings = {};
|
||
settings[name] = value;
|
||
}
|
||
|
||
if (inst) {
|
||
if (this._curInst === inst) {
|
||
this._hideDatepicker();
|
||
}
|
||
|
||
date = this._getDateDatepicker(target, true);
|
||
minDate = this._getMinMaxDate(inst, "min");
|
||
maxDate = this._getMinMaxDate(inst, "max");
|
||
datepicker_extendRemove(inst.settings, settings);
|
||
// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
|
||
if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
|
||
inst.settings.minDate = this._formatDate(inst, minDate);
|
||
}
|
||
if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
|
||
inst.settings.maxDate = this._formatDate(inst, maxDate);
|
||
}
|
||
if ( "disabled" in settings ) {
|
||
if ( settings.disabled ) {
|
||
this._disableDatepicker(target);
|
||
} else {
|
||
this._enableDatepicker(target);
|
||
}
|
||
}
|
||
this._attachments($(target), inst);
|
||
this._autoSize(inst);
|
||
this._setDate(inst, date);
|
||
this._updateAlternate(inst);
|
||
this._updateDatepicker(inst);
|
||
}
|
||
},
|
||
|
||
// change method deprecated
|
||
_changeDatepicker: function(target, name, value) {
|
||
this._optionDatepicker(target, name, value);
|
||
},
|
||
|
||
/* Redraw the date picker attached to an input field or division.
|
||
* @param target element - the target input field or division or span
|
||
*/
|
||
_refreshDatepicker: function(target) {
|
||
var inst = this._getInst(target);
|
||
if (inst) {
|
||
this._updateDatepicker(inst);
|
||
}
|
||
},
|
||
|
||
/* Set the dates for a jQuery selection.
|
||
* @param target element - the target input field or division or span
|
||
* @param date Date - the new date
|
||
*/
|
||
_setDateDatepicker: function(target, date) {
|
||
var inst = this._getInst(target);
|
||
if (inst) {
|
||
this._setDate(inst, date);
|
||
this._updateDatepicker(inst);
|
||
this._updateAlternate(inst);
|
||
}
|
||
},
|
||
|
||
/* Get the date(s) for the first entry in a jQuery selection.
|
||
* @param target element - the target input field or division or span
|
||
* @param noDefault boolean - true if no default date is to be used
|
||
* @return Date - the current date
|
||
*/
|
||
_getDateDatepicker: function(target, noDefault) {
|
||
var inst = this._getInst(target);
|
||
if (inst && !inst.inline) {
|
||
this._setDateFromField(inst, noDefault);
|
||
}
|
||
return (inst ? this._getDate(inst) : null);
|
||
},
|
||
|
||
/* Handle keystrokes. */
|
||
_doKeyDown: function(event) {
|
||
var onSelect, dateStr, sel,
|
||
inst = $.datepicker._getInst(event.target),
|
||
handled = true,
|
||
isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
|
||
|
||
inst._keyEvent = true;
|
||
if ($.datepicker._datepickerShowing) {
|
||
switch (event.keyCode) {
|
||
case 9: $.datepicker._hideDatepicker();
|
||
handled = false;
|
||
break; // hide on tab out
|
||
case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
|
||
$.datepicker._currentClass + ")", inst.dpDiv);
|
||
if (sel[0]) {
|
||
$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
|
||
}
|
||
|
||
onSelect = $.datepicker._get(inst, "onSelect");
|
||
if (onSelect) {
|
||
dateStr = $.datepicker._formatDate(inst);
|
||
|
||
// trigger custom callback
|
||
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
|
||
} else {
|
||
$.datepicker._hideDatepicker();
|
||
}
|
||
|
||
return false; // don't submit the form
|
||
case 27: $.datepicker._hideDatepicker();
|
||
break; // hide on escape
|
||
case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
||
-$.datepicker._get(inst, "stepBigMonths") :
|
||
-$.datepicker._get(inst, "stepMonths")), "M");
|
||
break; // previous month/year on page up/+ ctrl
|
||
case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
||
+$.datepicker._get(inst, "stepBigMonths") :
|
||
+$.datepicker._get(inst, "stepMonths")), "M");
|
||
break; // next month/year on page down/+ ctrl
|
||
case 35: if (event.ctrlKey || event.metaKey) {
|
||
$.datepicker._clearDate(event.target);
|
||
}
|
||
handled = event.ctrlKey || event.metaKey;
|
||
break; // clear on ctrl or command +end
|
||
case 36: if (event.ctrlKey || event.metaKey) {
|
||
$.datepicker._gotoToday(event.target);
|
||
}
|
||
handled = event.ctrlKey || event.metaKey;
|
||
break; // current on ctrl or command +home
|
||
case 37: if (event.ctrlKey || event.metaKey) {
|
||
$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
|
||
}
|
||
handled = event.ctrlKey || event.metaKey;
|
||
// -1 day on ctrl or command +left
|
||
if (event.originalEvent.altKey) {
|
||
$.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
||
-$.datepicker._get(inst, "stepBigMonths") :
|
||
-$.datepicker._get(inst, "stepMonths")), "M");
|
||
}
|
||
// next month/year on alt +left on Mac
|
||
break;
|
||
case 38: if (event.ctrlKey || event.metaKey) {
|
||
$.datepicker._adjustDate(event.target, -7, "D");
|
||
}
|
||
handled = event.ctrlKey || event.metaKey;
|
||
break; // -1 week on ctrl or command +up
|
||
case 39: if (event.ctrlKey || event.metaKey) {
|
||
$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
|
||
}
|
||
handled = event.ctrlKey || event.metaKey;
|
||
// +1 day on ctrl or command +right
|
||
if (event.originalEvent.altKey) {
|
||
$.datepicker._adjustDate(event.target, (event.ctrlKey ?
|
||
+$.datepicker._get(inst, "stepBigMonths") :
|
||
+$.datepicker._get(inst, "stepMonths")), "M");
|
||
}
|
||
// next month/year on alt +right
|
||
break;
|
||
case 40: if (event.ctrlKey || event.metaKey) {
|
||
$.datepicker._adjustDate(event.target, +7, "D");
|
||
}
|
||
handled = event.ctrlKey || event.metaKey;
|
||
break; // +1 week on ctrl or command +down
|
||
default: handled = false;
|
||
}
|
||
} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
|
||
$.datepicker._showDatepicker(this);
|
||
} else {
|
||
handled = false;
|
||
}
|
||
|
||
if (handled) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
}
|
||
},
|
||
|
||
/* Filter entered characters - based on date format. */
|
||
_doKeyPress: function(event) {
|
||
var chars, chr,
|
||
inst = $.datepicker._getInst(event.target);
|
||
|
||
if ($.datepicker._get(inst, "constrainInput")) {
|
||
chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
|
||
chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
|
||
return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
|
||
}
|
||
},
|
||
|
||
/* Synchronise manual entry and field/alternate field. */
|
||
_doKeyUp: function(event) {
|
||
var date,
|
||
inst = $.datepicker._getInst(event.target);
|
||
|
||
if (inst.input.val() !== inst.lastVal) {
|
||
try {
|
||
date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
|
||
(inst.input ? inst.input.val() : null),
|
||
$.datepicker._getFormatConfig(inst));
|
||
|
||
if (date) { // only if valid
|
||
$.datepicker._setDateFromField(inst);
|
||
$.datepicker._updateAlternate(inst);
|
||
$.datepicker._updateDatepicker(inst);
|
||
}
|
||
}
|
||
catch (err) {
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
|
||
/* Pop-up the date picker for a given input field.
|
||
* If false returned from beforeShow event handler do not show.
|
||
* @param input element - the input field attached to the date picker or
|
||
* event - if triggered by focus
|
||
*/
|
||
_showDatepicker: function(input) {
|
||
input = input.target || input;
|
||
if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
|
||
input = $("input", input.parentNode)[0];
|
||
}
|
||
|
||
if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
|
||
return;
|
||
}
|
||
|
||
var inst, beforeShow, beforeShowSettings, isFixed,
|
||
offset, showAnim, duration;
|
||
|
||
inst = $.datepicker._getInst(input);
|
||
if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
|
||
$.datepicker._curInst.dpDiv.stop(true, true);
|
||
if ( inst && $.datepicker._datepickerShowing ) {
|
||
$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
|
||
}
|
||
}
|
||
|
||
beforeShow = $.datepicker._get(inst, "beforeShow");
|
||
beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
|
||
if(beforeShowSettings === false){
|
||
return;
|
||
}
|
||
datepicker_extendRemove(inst.settings, beforeShowSettings);
|
||
|
||
inst.lastVal = null;
|
||
$.datepicker._lastInput = input;
|
||
$.datepicker._setDateFromField(inst);
|
||
|
||
if ($.datepicker._inDialog) { // hide cursor
|
||
input.value = "";
|
||
}
|
||
if (!$.datepicker._pos) { // position below input
|
||
$.datepicker._pos = $.datepicker._findPos(input);
|
||
$.datepicker._pos[1] += input.offsetHeight; // add the height
|
||
}
|
||
|
||
isFixed = false;
|
||
$(input).parents().each(function() {
|
||
isFixed |= $(this).css("position") === "fixed";
|
||
return !isFixed;
|
||
});
|
||
|
||
offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
|
||
$.datepicker._pos = null;
|
||
//to avoid flashes on Firefox
|
||
inst.dpDiv.empty();
|
||
// determine sizing offscreen
|
||
inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
|
||
$.datepicker._updateDatepicker(inst);
|
||
// fix width for dynamic number of date pickers
|
||
// and adjust position before showing
|
||
offset = $.datepicker._checkOffset(inst, offset, isFixed);
|
||
inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
|
||
"static" : (isFixed ? "fixed" : "absolute")), display: "none",
|
||
left: offset.left + "px", top: offset.top + "px"});
|
||
|
||
if (!inst.inline) {
|
||
showAnim = $.datepicker._get(inst, "showAnim");
|
||
duration = $.datepicker._get(inst, "duration");
|
||
inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
|
||
$.datepicker._datepickerShowing = true;
|
||
|
||
if ( $.effects && $.effects.effect[ showAnim ] ) {
|
||
inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
|
||
} else {
|
||
inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
|
||
}
|
||
|
||
if ( $.datepicker._shouldFocusInput( inst ) ) {
|
||
inst.input.focus();
|
||
}
|
||
|
||
$.datepicker._curInst = inst;
|
||
}
|
||
},
|
||
|
||
/* Generate the date picker content. */
|
||
_updateDatepicker: function(inst) {
|
||
this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
|
||
datepicker_instActive = inst; // for delegate hover events
|
||
inst.dpDiv.empty().append(this._generateHTML(inst));
|
||
this._attachHandlers(inst);
|
||
|
||
var origyearshtml,
|
||
numMonths = this._getNumberOfMonths(inst),
|
||
cols = numMonths[1],
|
||
width = 17,
|
||
activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
|
||
|
||
if ( activeCell.length > 0 ) {
|
||
datepicker_handleMouseover.apply( activeCell.get( 0 ) );
|
||
}
|
||
|
||
inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
|
||
if (cols > 1) {
|
||
inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
|
||
}
|
||
inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
|
||
"Class"]("ui-datepicker-multi");
|
||
inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
|
||
"Class"]("ui-datepicker-rtl");
|
||
|
||
if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
|
||
inst.input.focus();
|
||
}
|
||
|
||
// deffered render of the years select (to avoid flashes on Firefox)
|
||
if( inst.yearshtml ){
|
||
origyearshtml = inst.yearshtml;
|
||
setTimeout(function(){
|
||
//assure that inst.yearshtml didn't change.
|
||
if( origyearshtml === inst.yearshtml && inst.yearshtml ){
|
||
inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
|
||
}
|
||
origyearshtml = inst.yearshtml = null;
|
||
}, 0);
|
||
}
|
||
},
|
||
|
||
// #6694 - don't focus the input if it's already focused
|
||
// this breaks the change event in IE
|
||
// Support: IE and jQuery <1.9
|
||
_shouldFocusInput: function( inst ) {
|
||
return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
|
||
},
|
||
|
||
/* Check positioning to remain on screen. */
|
||
_checkOffset: function(inst, offset, isFixed) {
|
||
var dpWidth = inst.dpDiv.outerWidth(),
|
||
dpHeight = inst.dpDiv.outerHeight(),
|
||
inputWidth = inst.input ? inst.input.outerWidth() : 0,
|
||
inputHeight = inst.input ? inst.input.outerHeight() : 0,
|
||
viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
|
||
viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
|
||
|
||
offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
|
||
offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
|
||
offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
|
||
|
||
// now check if datepicker is showing outside window viewport - move to a better place if so.
|
||
offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
|
||
Math.abs(offset.left + dpWidth - viewWidth) : 0);
|
||
offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
|
||
Math.abs(dpHeight + inputHeight) : 0);
|
||
|
||
return offset;
|
||
},
|
||
|
||
/* Find an object's position on the screen. */
|
||
_findPos: function(obj) {
|
||
var position,
|
||
inst = this._getInst(obj),
|
||
isRTL = this._get(inst, "isRTL");
|
||
|
||
while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
|
||
obj = obj[isRTL ? "previousSibling" : "nextSibling"];
|
||
}
|
||
|
||
position = $(obj).offset();
|
||
return [position.left, position.top];
|
||
},
|
||
|
||
/* Hide the date picker from view.
|
||
* @param input element - the input field attached to the date picker
|
||
*/
|
||
_hideDatepicker: function(input) {
|
||
var showAnim, duration, postProcess, onClose,
|
||
inst = this._curInst;
|
||
|
||
if (!inst || (input && inst !== $.data(input, "datepicker"))) {
|
||
return;
|
||
}
|
||
|
||
if (this._datepickerShowing) {
|
||
showAnim = this._get(inst, "showAnim");
|
||
duration = this._get(inst, "duration");
|
||
postProcess = function() {
|
||
$.datepicker._tidyDialog(inst);
|
||
};
|
||
|
||
// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
|
||
if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
|
||
inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
|
||
} else {
|
||
inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
|
||
(showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
|
||
}
|
||
|
||
if (!showAnim) {
|
||
postProcess();
|
||
}
|
||
this._datepickerShowing = false;
|
||
|
||
onClose = this._get(inst, "onClose");
|
||
if (onClose) {
|
||
onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
|
||
}
|
||
|
||
this._lastInput = null;
|
||
if (this._inDialog) {
|
||
this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
|
||
if ($.blockUI) {
|
||
$.unblockUI();
|
||
$("body").append(this.dpDiv);
|
||
}
|
||
}
|
||
this._inDialog = false;
|
||
}
|
||
},
|
||
|
||
/* Tidy up after a dialog display. */
|
||
_tidyDialog: function(inst) {
|
||
inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
|
||
},
|
||
|
||
/* Close date picker if clicked elsewhere. */
|
||
_checkExternalClick: function(event) {
|
||
if (!$.datepicker._curInst) {
|
||
return;
|
||
}
|
||
|
||
var $target = $(event.target),
|
||
inst = $.datepicker._getInst($target[0]);
|
||
|
||
if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
|
||
$target.parents("#" + $.datepicker._mainDivId).length === 0 &&
|
||
!$target.hasClass($.datepicker.markerClassName) &&
|
||
!$target.closest("." + $.datepicker._triggerClass).length &&
|
||
$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
|
||
( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
|
||
$.datepicker._hideDatepicker();
|
||
}
|
||
},
|
||
|
||
/* Adjust one of the date sub-fields. */
|
||
_adjustDate: function(id, offset, period) {
|
||
var target = $(id),
|
||
inst = this._getInst(target[0]);
|
||
|
||
if (this._isDisabledDatepicker(target[0])) {
|
||
return;
|
||
}
|
||
this._adjustInstDate(inst, offset +
|
||
(period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
|
||
period);
|
||
this._updateDatepicker(inst);
|
||
},
|
||
|
||
/* Action for current link. */
|
||
_gotoToday: function(id) {
|
||
var date,
|
||
target = $(id),
|
||
inst = this._getInst(target[0]);
|
||
|
||
if (this._get(inst, "gotoCurrent") && inst.currentDay) {
|
||
inst.selectedDay = inst.currentDay;
|
||
inst.drawMonth = inst.selectedMonth = inst.currentMonth;
|
||
inst.drawYear = inst.selectedYear = inst.currentYear;
|
||
} else {
|
||
date = new Date();
|
||
inst.selectedDay = date.getDate();
|
||
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
||
inst.drawYear = inst.selectedYear = date.getFullYear();
|
||
}
|
||
this._notifyChange(inst);
|
||
this._adjustDate(target);
|
||
},
|
||
|
||
/* Action for selecting a new month/year. */
|
||
_selectMonthYear: function(id, select, period) {
|
||
var target = $(id),
|
||
inst = this._getInst(target[0]);
|
||
|
||
inst["selected" + (period === "M" ? "Month" : "Year")] =
|
||
inst["draw" + (period === "M" ? "Month" : "Year")] =
|
||
parseInt(select.options[select.selectedIndex].value,10);
|
||
|
||
this._notifyChange(inst);
|
||
this._adjustDate(target);
|
||
},
|
||
|
||
/* Action for selecting a day. */
|
||
_selectDay: function(id, month, year, td) {
|
||
var inst,
|
||
target = $(id);
|
||
|
||
if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
|
||
return;
|
||
}
|
||
|
||
inst = this._getInst(target[0]);
|
||
inst.selectedDay = inst.currentDay = $("a", td).html();
|
||
inst.selectedMonth = inst.currentMonth = month;
|
||
inst.selectedYear = inst.currentYear = year;
|
||
this._selectDate(id, this._formatDate(inst,
|
||
inst.currentDay, inst.currentMonth, inst.currentYear));
|
||
},
|
||
|
||
/* Erase the input field and hide the date picker. */
|
||
_clearDate: function(id) {
|
||
var target = $(id);
|
||
this._selectDate(target, "");
|
||
},
|
||
|
||
/* Update the input field with the selected date. */
|
||
_selectDate: function(id, dateStr) {
|
||
var onSelect,
|
||
target = $(id),
|
||
inst = this._getInst(target[0]);
|
||
|
||
dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
|
||
if (inst.input) {
|
||
inst.input.val(dateStr);
|
||
}
|
||
this._updateAlternate(inst);
|
||
|
||
onSelect = this._get(inst, "onSelect");
|
||
if (onSelect) {
|
||
onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
|
||
} else if (inst.input) {
|
||
inst.input.trigger("change"); // fire the change event
|
||
}
|
||
|
||
if (inst.inline){
|
||
this._updateDatepicker(inst);
|
||
} else {
|
||
this._hideDatepicker();
|
||
this._lastInput = inst.input[0];
|
||
if (typeof(inst.input[0]) !== "object") {
|
||
inst.input.focus(); // restore focus
|
||
}
|
||
this._lastInput = null;
|
||
}
|
||
},
|
||
|
||
/* Update any alternate field to synchronise with the main field. */
|
||
_updateAlternate: function(inst) {
|
||
var altFormat, date, dateStr,
|
||
altField = this._get(inst, "altField");
|
||
|
||
if (altField) { // update alternate field too
|
||
altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
|
||
date = this._getDate(inst);
|
||
dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
|
||
$(altField).each(function() { $(this).val(dateStr); });
|
||
}
|
||
},
|
||
|
||
/* Set as beforeShowDay function to prevent selection of weekends.
|
||
* @param date Date - the date to customise
|
||
* @return [boolean, string] - is this date selectable?, what is its CSS class?
|
||
*/
|
||
noWeekends: function(date) {
|
||
var day = date.getDay();
|
||
return [(day > 0 && day < 6), ""];
|
||
},
|
||
|
||
/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
|
||
* @param date Date - the date to get the week for
|
||
* @return number - the number of the week within the year that contains this date
|
||
*/
|
||
iso8601Week: function(date) {
|
||
var time,
|
||
checkDate = new Date(date.getTime());
|
||
|
||
// Find Thursday of this week starting on Monday
|
||
checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
|
||
|
||
time = checkDate.getTime();
|
||
checkDate.setMonth(0); // Compare with Jan 1
|
||
checkDate.setDate(1);
|
||
return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
|
||
},
|
||
|
||
/* Parse a string value into a date object.
|
||
* See formatDate below for the possible formats.
|
||
*
|
||
* @param format string - the expected format of the date
|
||
* @param value string - the date in the above format
|
||
* @param settings Object - attributes include:
|
||
* shortYearCutoff number - the cutoff year for determining the century (optional)
|
||
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
||
* dayNames string[7] - names of the days from Sunday (optional)
|
||
* monthNamesShort string[12] - abbreviated names of the months (optional)
|
||
* monthNames string[12] - names of the months (optional)
|
||
* @return Date - the extracted date value or null if value is blank
|
||
*/
|
||
parseDate: function (format, value, settings) {
|
||
if (format == null || value == null) {
|
||
throw "Invalid arguments";
|
||
}
|
||
|
||
value = (typeof value === "object" ? value.toString() : value + "");
|
||
if (value === "") {
|
||
return null;
|
||
}
|
||
|
||
var iFormat, dim, extra,
|
||
iValue = 0,
|
||
shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
|
||
shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
|
||
new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
|
||
dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
|
||
dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
|
||
monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
|
||
monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
|
||
year = -1,
|
||
month = -1,
|
||
day = -1,
|
||
doy = -1,
|
||
literal = false,
|
||
date,
|
||
// Check whether a format character is doubled
|
||
lookAhead = function(match) {
|
||
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
||
if (matches) {
|
||
iFormat++;
|
||
}
|
||
return matches;
|
||
},
|
||
// Extract a number from the string value
|
||
getNumber = function(match) {
|
||
var isDoubled = lookAhead(match),
|
||
size = (match === "@" ? 14 : (match === "!" ? 20 :
|
||
(match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
|
||
minSize = (match === "y" ? size : 1),
|
||
digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
|
||
num = value.substring(iValue).match(digits);
|
||
if (!num) {
|
||
throw "Missing number at position " + iValue;
|
||
}
|
||
iValue += num[0].length;
|
||
return parseInt(num[0], 10);
|
||
},
|
||
// Extract a name from the string value and convert to an index
|
||
getName = function(match, shortNames, longNames) {
|
||
var index = -1,
|
||
names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
|
||
return [ [k, v] ];
|
||
}).sort(function (a, b) {
|
||
return -(a[1].length - b[1].length);
|
||
});
|
||
|
||
$.each(names, function (i, pair) {
|
||
var name = pair[1];
|
||
if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
|
||
index = pair[0];
|
||
iValue += name.length;
|
||
return false;
|
||
}
|
||
});
|
||
if (index !== -1) {
|
||
return index + 1;
|
||
} else {
|
||
throw "Unknown name at position " + iValue;
|
||
}
|
||
},
|
||
// Confirm that a literal character matches the string value
|
||
checkLiteral = function() {
|
||
if (value.charAt(iValue) !== format.charAt(iFormat)) {
|
||
throw "Unexpected literal at position " + iValue;
|
||
}
|
||
iValue++;
|
||
};
|
||
|
||
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
||
if (literal) {
|
||
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
||
literal = false;
|
||
} else {
|
||
checkLiteral();
|
||
}
|
||
} else {
|
||
switch (format.charAt(iFormat)) {
|
||
case "d":
|
||
day = getNumber("d");
|
||
break;
|
||
case "D":
|
||
getName("D", dayNamesShort, dayNames);
|
||
break;
|
||
case "o":
|
||
doy = getNumber("o");
|
||
break;
|
||
case "m":
|
||
month = getNumber("m");
|
||
break;
|
||
case "M":
|
||
month = getName("M", monthNamesShort, monthNames);
|
||
break;
|
||
case "y":
|
||
year = getNumber("y");
|
||
break;
|
||
case "@":
|
||
date = new Date(getNumber("@"));
|
||
year = date.getFullYear();
|
||
month = date.getMonth() + 1;
|
||
day = date.getDate();
|
||
break;
|
||
case "!":
|
||
date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
|
||
year = date.getFullYear();
|
||
month = date.getMonth() + 1;
|
||
day = date.getDate();
|
||
break;
|
||
case "'":
|
||
if (lookAhead("'")){
|
||
checkLiteral();
|
||
} else {
|
||
literal = true;
|
||
}
|
||
break;
|
||
default:
|
||
checkLiteral();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (iValue < value.length){
|
||
extra = value.substr(iValue);
|
||
if (!/^\s+/.test(extra)) {
|
||
throw "Extra/unparsed characters found in date: " + extra;
|
||
}
|
||
}
|
||
|
||
if (year === -1) {
|
||
year = new Date().getFullYear();
|
||
} else if (year < 100) {
|
||
year += new Date().getFullYear() - new Date().getFullYear() % 100 +
|
||
(year <= shortYearCutoff ? 0 : -100);
|
||
}
|
||
|
||
if (doy > -1) {
|
||
month = 1;
|
||
day = doy;
|
||
do {
|
||
dim = this._getDaysInMonth(year, month - 1);
|
||
if (day <= dim) {
|
||
break;
|
||
}
|
||
month++;
|
||
day -= dim;
|
||
} while (true);
|
||
}
|
||
|
||
date = this._daylightSavingAdjust(new Date(year, month - 1, day));
|
||
if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
|
||
throw "Invalid date"; // E.g. 31/02/00
|
||
}
|
||
return date;
|
||
},
|
||
|
||
/* Standard date formats. */
|
||
ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
|
||
COOKIE: "D, dd M yy",
|
||
ISO_8601: "yy-mm-dd",
|
||
RFC_822: "D, d M y",
|
||
RFC_850: "DD, dd-M-y",
|
||
RFC_1036: "D, d M y",
|
||
RFC_1123: "D, d M yy",
|
||
RFC_2822: "D, d M yy",
|
||
RSS: "D, d M y", // RFC 822
|
||
TICKS: "!",
|
||
TIMESTAMP: "@",
|
||
W3C: "yy-mm-dd", // ISO 8601
|
||
|
||
_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
|
||
Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
|
||
|
||
/* Format a date object into a string value.
|
||
* The format can be combinations of the following:
|
||
* d - day of month (no leading zero)
|
||
* dd - day of month (two digit)
|
||
* o - day of year (no leading zeros)
|
||
* oo - day of year (three digit)
|
||
* D - day name short
|
||
* DD - day name long
|
||
* m - month of year (no leading zero)
|
||
* mm - month of year (two digit)
|
||
* M - month name short
|
||
* MM - month name long
|
||
* y - year (two digit)
|
||
* yy - year (four digit)
|
||
* @ - Unix timestamp (ms since 01/01/1970)
|
||
* ! - Windows ticks (100ns since 01/01/0001)
|
||
* "..." - literal text
|
||
* '' - single quote
|
||
*
|
||
* @param format string - the desired format of the date
|
||
* @param date Date - the date value to format
|
||
* @param settings Object - attributes include:
|
||
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
|
||
* dayNames string[7] - names of the days from Sunday (optional)
|
||
* monthNamesShort string[12] - abbreviated names of the months (optional)
|
||
* monthNames string[12] - names of the months (optional)
|
||
* @return string - the date in the above format
|
||
*/
|
||
formatDate: function (format, date, settings) {
|
||
if (!date) {
|
||
return "";
|
||
}
|
||
|
||
var iFormat,
|
||
dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
|
||
dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
|
||
monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
|
||
monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
|
||
// Check whether a format character is doubled
|
||
lookAhead = function(match) {
|
||
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
||
if (matches) {
|
||
iFormat++;
|
||
}
|
||
return matches;
|
||
},
|
||
// Format a number, with leading zero if necessary
|
||
formatNumber = function(match, value, len) {
|
||
var num = "" + value;
|
||
if (lookAhead(match)) {
|
||
while (num.length < len) {
|
||
num = "0" + num;
|
||
}
|
||
}
|
||
return num;
|
||
},
|
||
// Format a name, short or long as requested
|
||
formatName = function(match, value, shortNames, longNames) {
|
||
return (lookAhead(match) ? longNames[value] : shortNames[value]);
|
||
},
|
||
output = "",
|
||
literal = false;
|
||
|
||
if (date) {
|
||
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
||
if (literal) {
|
||
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
||
literal = false;
|
||
} else {
|
||
output += format.charAt(iFormat);
|
||
}
|
||
} else {
|
||
switch (format.charAt(iFormat)) {
|
||
case "d":
|
||
output += formatNumber("d", date.getDate(), 2);
|
||
break;
|
||
case "D":
|
||
output += formatName("D", date.getDay(), dayNamesShort, dayNames);
|
||
break;
|
||
case "o":
|
||
output += formatNumber("o",
|
||
Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
|
||
break;
|
||
case "m":
|
||
output += formatNumber("m", date.getMonth() + 1, 2);
|
||
break;
|
||
case "M":
|
||
output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
|
||
break;
|
||
case "y":
|
||
output += (lookAhead("y") ? date.getFullYear() :
|
||
(date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
|
||
break;
|
||
case "@":
|
||
output += date.getTime();
|
||
break;
|
||
case "!":
|
||
output += date.getTime() * 10000 + this._ticksTo1970;
|
||
break;
|
||
case "'":
|
||
if (lookAhead("'")) {
|
||
output += "'";
|
||
} else {
|
||
literal = true;
|
||
}
|
||
break;
|
||
default:
|
||
output += format.charAt(iFormat);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return output;
|
||
},
|
||
|
||
/* Extract all possible characters from the date format. */
|
||
_possibleChars: function (format) {
|
||
var iFormat,
|
||
chars = "",
|
||
literal = false,
|
||
// Check whether a format character is doubled
|
||
lookAhead = function(match) {
|
||
var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
|
||
if (matches) {
|
||
iFormat++;
|
||
}
|
||
return matches;
|
||
};
|
||
|
||
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
||
if (literal) {
|
||
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
||
literal = false;
|
||
} else {
|
||
chars += format.charAt(iFormat);
|
||
}
|
||
} else {
|
||
switch (format.charAt(iFormat)) {
|
||
case "d": case "m": case "y": case "@":
|
||
chars += "0123456789";
|
||
break;
|
||
case "D": case "M":
|
||
return null; // Accept anything
|
||
case "'":
|
||
if (lookAhead("'")) {
|
||
chars += "'";
|
||
} else {
|
||
literal = true;
|
||
}
|
||
break;
|
||
default:
|
||
chars += format.charAt(iFormat);
|
||
}
|
||
}
|
||
}
|
||
return chars;
|
||
},
|
||
|
||
/* Get a setting value, defaulting if necessary. */
|
||
_get: function(inst, name) {
|
||
return inst.settings[name] !== undefined ?
|
||
inst.settings[name] : this._defaults[name];
|
||
},
|
||
|
||
/* Parse existing date and initialise date picker. */
|
||
_setDateFromField: function(inst, noDefault) {
|
||
if (inst.input.val() === inst.lastVal) {
|
||
return;
|
||
}
|
||
|
||
var dateFormat = this._get(inst, "dateFormat"),
|
||
dates = inst.lastVal = inst.input ? inst.input.val() : null,
|
||
defaultDate = this._getDefaultDate(inst),
|
||
date = defaultDate,
|
||
settings = this._getFormatConfig(inst);
|
||
|
||
try {
|
||
date = this.parseDate(dateFormat, dates, settings) || defaultDate;
|
||
} catch (event) {
|
||
dates = (noDefault ? "" : dates);
|
||
}
|
||
inst.selectedDay = date.getDate();
|
||
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
||
inst.drawYear = inst.selectedYear = date.getFullYear();
|
||
inst.currentDay = (dates ? date.getDate() : 0);
|
||
inst.currentMonth = (dates ? date.getMonth() : 0);
|
||
inst.currentYear = (dates ? date.getFullYear() : 0);
|
||
this._adjustInstDate(inst);
|
||
},
|
||
|
||
/* Retrieve the default date shown on opening. */
|
||
_getDefaultDate: function(inst) {
|
||
return this._restrictMinMax(inst,
|
||
this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
|
||
},
|
||
|
||
/* A date may be specified as an exact value or a relative one. */
|
||
_determineDate: function(inst, date, defaultDate) {
|
||
var offsetNumeric = function(offset) {
|
||
var date = new Date();
|
||
date.setDate(date.getDate() + offset);
|
||
return date;
|
||
},
|
||
offsetString = function(offset) {
|
||
try {
|
||
return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
|
||
offset, $.datepicker._getFormatConfig(inst));
|
||
}
|
||
catch (e) {
|
||
// Ignore
|
||
}
|
||
|
||
var date = (offset.toLowerCase().match(/^c/) ?
|
||
$.datepicker._getDate(inst) : null) || new Date(),
|
||
year = date.getFullYear(),
|
||
month = date.getMonth(),
|
||
day = date.getDate(),
|
||
pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
|
||
matches = pattern.exec(offset);
|
||
|
||
while (matches) {
|
||
switch (matches[2] || "d") {
|
||
case "d" : case "D" :
|
||
day += parseInt(matches[1],10); break;
|
||
case "w" : case "W" :
|
||
day += parseInt(matches[1],10) * 7; break;
|
||
case "m" : case "M" :
|
||
month += parseInt(matches[1],10);
|
||
day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
|
||
break;
|
||
case "y": case "Y" :
|
||
year += parseInt(matches[1],10);
|
||
day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
|
||
break;
|
||
}
|
||
matches = pattern.exec(offset);
|
||
}
|
||
return new Date(year, month, day);
|
||
},
|
||
newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
|
||
(typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
|
||
|
||
newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
|
||
if (newDate) {
|
||
newDate.setHours(0);
|
||
newDate.setMinutes(0);
|
||
newDate.setSeconds(0);
|
||
newDate.setMilliseconds(0);
|
||
}
|
||
return this._daylightSavingAdjust(newDate);
|
||
},
|
||
|
||
/* Handle switch to/from daylight saving.
|
||
* Hours may be non-zero on daylight saving cut-over:
|
||
* > 12 when midnight changeover, but then cannot generate
|
||
* midnight datetime, so jump to 1AM, otherwise reset.
|
||
* @param date (Date) the date to check
|
||
* @return (Date) the corrected date
|
||
*/
|
||
_daylightSavingAdjust: function(date) {
|
||
if (!date) {
|
||
return null;
|
||
}
|
||
date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
|
||
return date;
|
||
},
|
||
|
||
/* Set the date(s) directly. */
|
||
_setDate: function(inst, date, noChange) {
|
||
var clear = !date,
|
||
origMonth = inst.selectedMonth,
|
||
origYear = inst.selectedYear,
|
||
newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
|
||
|
||
inst.selectedDay = inst.currentDay = newDate.getDate();
|
||
inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
|
||
inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
|
||
if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
|
||
this._notifyChange(inst);
|
||
}
|
||
this._adjustInstDate(inst);
|
||
if (inst.input) {
|
||
inst.input.val(clear ? "" : this._formatDate(inst));
|
||
}
|
||
},
|
||
|
||
/* Retrieve the date(s) directly. */
|
||
_getDate: function(inst) {
|
||
var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
|
||
this._daylightSavingAdjust(new Date(
|
||
inst.currentYear, inst.currentMonth, inst.currentDay)));
|
||
return startDate;
|
||
},
|
||
|
||
/* Attach the onxxx handlers. These are declared statically so
|
||
* they work with static code transformers like Caja.
|
||
*/
|
||
_attachHandlers: function(inst) {
|
||
var stepMonths = this._get(inst, "stepMonths"),
|
||
id = "#" + inst.id.replace( /\\\\/g, "\\" );
|
||
inst.dpDiv.find("[data-handler]").map(function () {
|
||
var handler = {
|
||
prev: function () {
|
||
$.datepicker._adjustDate(id, -stepMonths, "M");
|
||
},
|
||
next: function () {
|
||
$.datepicker._adjustDate(id, +stepMonths, "M");
|
||
},
|
||
hide: function () {
|
||
$.datepicker._hideDatepicker();
|
||
},
|
||
today: function () {
|
||
$.datepicker._gotoToday(id);
|
||
},
|
||
selectDay: function () {
|
||
$.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
|
||
return false;
|
||
},
|
||
selectMonth: function () {
|
||
$.datepicker._selectMonthYear(id, this, "M");
|
||
return false;
|
||
},
|
||
selectYear: function () {
|
||
$.datepicker._selectMonthYear(id, this, "Y");
|
||
return false;
|
||
}
|
||
};
|
||
$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
|
||
});
|
||
},
|
||
|
||
/* Generate the HTML for the current state of the date picker. */
|
||
_generateHTML: function(inst) {
|
||
var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
|
||
controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
|
||
monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
|
||
selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
|
||
cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
|
||
printDate, dRow, tbody, daySettings, otherMonth, unselectable,
|
||
tempDate = new Date(),
|
||
today = this._daylightSavingAdjust(
|
||
new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
|
||
isRTL = this._get(inst, "isRTL"),
|
||
showButtonPanel = this._get(inst, "showButtonPanel"),
|
||
hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
|
||
navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
|
||
numMonths = this._getNumberOfMonths(inst),
|
||
showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
|
||
stepMonths = this._get(inst, "stepMonths"),
|
||
isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
|
||
currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
|
||
new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
|
||
minDate = this._getMinMaxDate(inst, "min"),
|
||
maxDate = this._getMinMaxDate(inst, "max"),
|
||
drawMonth = inst.drawMonth - showCurrentAtPos,
|
||
drawYear = inst.drawYear;
|
||
|
||
if (drawMonth < 0) {
|
||
drawMonth += 12;
|
||
drawYear--;
|
||
}
|
||
if (maxDate) {
|
||
maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
|
||
maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
|
||
maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
|
||
while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
|
||
drawMonth--;
|
||
if (drawMonth < 0) {
|
||
drawMonth = 11;
|
||
drawYear--;
|
||
}
|
||
}
|
||
}
|
||
inst.drawMonth = drawMonth;
|
||
inst.drawYear = drawYear;
|
||
|
||
prevText = this._get(inst, "prevText");
|
||
prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
|
||
this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
|
||
this._getFormatConfig(inst)));
|
||
|
||
prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
|
||
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
|
||
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
|
||
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
|
||
|
||
nextText = this._get(inst, "nextText");
|
||
nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
|
||
this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
|
||
this._getFormatConfig(inst)));
|
||
|
||
next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
|
||
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
|
||
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
|
||
(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
|
||
|
||
currentText = this._get(inst, "currentText");
|
||
gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
|
||
currentText = (!navigationAsDateFormat ? currentText :
|
||
this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
|
||
|
||
controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
|
||
this._get(inst, "closeText") + "</button>" : "");
|
||
|
||
buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
|
||
(this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
|
||
">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
|
||
|
||
firstDay = parseInt(this._get(inst, "firstDay"),10);
|
||
firstDay = (isNaN(firstDay) ? 0 : firstDay);
|
||
|
||
showWeek = this._get(inst, "showWeek");
|
||
dayNames = this._get(inst, "dayNames");
|
||
dayNamesMin = this._get(inst, "dayNamesMin");
|
||
monthNames = this._get(inst, "monthNames");
|
||
monthNamesShort = this._get(inst, "monthNamesShort");
|
||
beforeShowDay = this._get(inst, "beforeShowDay");
|
||
showOtherMonths = this._get(inst, "showOtherMonths");
|
||
selectOtherMonths = this._get(inst, "selectOtherMonths");
|
||
defaultDate = this._getDefaultDate(inst);
|
||
html = "";
|
||
dow;
|
||
for (row = 0; row < numMonths[0]; row++) {
|
||
group = "";
|
||
this.maxRows = 4;
|
||
for (col = 0; col < numMonths[1]; col++) {
|
||
selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
|
||
cornerClass = " ui-corner-all";
|
||
calender = "";
|
||
if (isMultiMonth) {
|
||
calender += "<div class='ui-datepicker-group";
|
||
if (numMonths[1] > 1) {
|
||
switch (col) {
|
||
case 0: calender += " ui-datepicker-group-first";
|
||
cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
|
||
case numMonths[1]-1: calender += " ui-datepicker-group-last";
|
||
cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
|
||
default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
|
||
}
|
||
}
|
||
calender += "'>";
|
||
}
|
||
calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
|
||
(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
|
||
(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
|
||
this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
|
||
row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
|
||
"</div><table class='ui-datepicker-calendar'><thead>" +
|
||
"<tr>";
|
||
thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
|
||
for (dow = 0; dow < 7; dow++) { // days of the week
|
||
day = (dow + firstDay) % 7;
|
||
thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
|
||
"<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
|
||
}
|
||
calender += thead + "</tr></thead><tbody>";
|
||
daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
|
||
if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
|
||
inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
|
||
}
|
||
leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
|
||
curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
|
||
numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
|
||
this.maxRows = numRows;
|
||
printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
|
||
for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
|
||
calender += "<tr>";
|
||
tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
|
||
this._get(inst, "calculateWeek")(printDate) + "</td>");
|
||
for (dow = 0; dow < 7; dow++) { // create date picker days
|
||
daySettings = (beforeShowDay ?
|
||
beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
|
||
otherMonth = (printDate.getMonth() !== drawMonth);
|
||
unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
|
||
(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
|
||
tbody += "<td class='" +
|
||
((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
|
||
(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
|
||
((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
|
||
(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
|
||
// or defaultDate is current printedDate and defaultDate is selectedDate
|
||
" " + this._dayOverClass : "") + // highlight selected day
|
||
(unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
|
||
(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
|
||
(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
|
||
(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
|
||
((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
|
||
(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
|
||
(otherMonth && !showOtherMonths ? " " : // display for other months
|
||
(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
|
||
(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
|
||
(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
|
||
(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
|
||
"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
|
||
printDate.setDate(printDate.getDate() + 1);
|
||
printDate = this._daylightSavingAdjust(printDate);
|
||
}
|
||
calender += tbody + "</tr>";
|
||
}
|
||
drawMonth++;
|
||
if (drawMonth > 11) {
|
||
drawMonth = 0;
|
||
drawYear++;
|
||
}
|
||
calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
|
||
((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
|
||
group += calender;
|
||
}
|
||
html += group;
|
||
}
|
||
html += buttonPanel;
|
||
inst._keyEvent = false;
|
||
return html;
|
||
},
|
||
|
||
/* Generate the month and year header. */
|
||
_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
|
||
secondary, monthNames, monthNamesShort) {
|
||
|
||
var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
|
||
changeMonth = this._get(inst, "changeMonth"),
|
||
changeYear = this._get(inst, "changeYear"),
|
||
showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
|
||
html = "<div class='ui-datepicker-title'>",
|
||
monthHtml = "";
|
||
|
||
// month selection
|
||
if (secondary || !changeMonth) {
|
||
monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
|
||
} else {
|
||
inMinYear = (minDate && minDate.getFullYear() === drawYear);
|
||
inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
|
||
monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
|
||
for ( month = 0; month < 12; month++) {
|
||
if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
|
||
monthHtml += "<option value='" + month + "'" +
|
||
(month === drawMonth ? " selected='selected'" : "") +
|
||
">" + monthNamesShort[month] + "</option>";
|
||
}
|
||
}
|
||
monthHtml += "</select>";
|
||
}
|
||
|
||
if (!showMonthAfterYear) {
|
||
html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
|
||
}
|
||
|
||
// year selection
|
||
if ( !inst.yearshtml ) {
|
||
inst.yearshtml = "";
|
||
if (secondary || !changeYear) {
|
||
html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
|
||
} else {
|
||
// determine range of years to display
|
||
years = this._get(inst, "yearRange").split(":");
|
||
thisYear = new Date().getFullYear();
|
||
determineYear = function(value) {
|
||
var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
|
||
(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
|
||
parseInt(value, 10)));
|
||
return (isNaN(year) ? thisYear : year);
|
||
};
|
||
year = determineYear(years[0]);
|
||
endYear = Math.max(year, determineYear(years[1] || ""));
|
||
year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
|
||
endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
|
||
inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
|
||
for (; year <= endYear; year++) {
|
||
inst.yearshtml += "<option value='" + year + "'" +
|
||
(year === drawYear ? " selected='selected'" : "") +
|
||
">" + year + "</option>";
|
||
}
|
||
inst.yearshtml += "</select>";
|
||
|
||
html += inst.yearshtml;
|
||
inst.yearshtml = null;
|
||
}
|
||
}
|
||
|
||
html += this._get(inst, "yearSuffix");
|
||
if (showMonthAfterYear) {
|
||
html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
|
||
}
|
||
html += "</div>"; // Close datepicker_header
|
||
return html;
|
||
},
|
||
|
||
/* Adjust one of the date sub-fields. */
|
||
_adjustInstDate: function(inst, offset, period) {
|
||
var year = inst.drawYear + (period === "Y" ? offset : 0),
|
||
month = inst.drawMonth + (period === "M" ? offset : 0),
|
||
day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
|
||
date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
|
||
|
||
inst.selectedDay = date.getDate();
|
||
inst.drawMonth = inst.selectedMonth = date.getMonth();
|
||
inst.drawYear = inst.selectedYear = date.getFullYear();
|
||
if (period === "M" || period === "Y") {
|
||
this._notifyChange(inst);
|
||
}
|
||
},
|
||
|
||
/* Ensure a date is within any min/max bounds. */
|
||
_restrictMinMax: function(inst, date) {
|
||
var minDate = this._getMinMaxDate(inst, "min"),
|
||
maxDate = this._getMinMaxDate(inst, "max"),
|
||
newDate = (minDate && date < minDate ? minDate : date);
|
||
return (maxDate && newDate > maxDate ? maxDate : newDate);
|
||
},
|
||
|
||
/* Notify change of month/year. */
|
||
_notifyChange: function(inst) {
|
||
var onChange = this._get(inst, "onChangeMonthYear");
|
||
if (onChange) {
|
||
onChange.apply((inst.input ? inst.input[0] : null),
|
||
[inst.selectedYear, inst.selectedMonth + 1, inst]);
|
||
}
|
||
},
|
||
|
||
/* Determine the number of months to show. */
|
||
_getNumberOfMonths: function(inst) {
|
||
var numMonths = this._get(inst, "numberOfMonths");
|
||
return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
|
||
},
|
||
|
||
/* Determine the current maximum date - ensure no time components are set. */
|
||
_getMinMaxDate: function(inst, minMax) {
|
||
return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
|
||
},
|
||
|
||
/* Find the number of days in a given month. */
|
||
_getDaysInMonth: function(year, month) {
|
||
return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
|
||
},
|
||
|
||
/* Find the day of the week of the first of a month. */
|
||
_getFirstDayOfMonth: function(year, month) {
|
||
return new Date(year, month, 1).getDay();
|
||
},
|
||
|
||
/* Determines if we should allow a "next/prev" month display change. */
|
||
_canAdjustMonth: function(inst, offset, curYear, curMonth) {
|
||
var numMonths = this._getNumberOfMonths(inst),
|
||
date = this._daylightSavingAdjust(new Date(curYear,
|
||
curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
|
||
|
||
if (offset < 0) {
|
||
date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
|
||
}
|
||
return this._isInRange(inst, date);
|
||
},
|
||
|
||
/* Is the given date in the accepted range? */
|
||
_isInRange: function(inst, date) {
|
||
var yearSplit, currentYear,
|
||
minDate = this._getMinMaxDate(inst, "min"),
|
||
maxDate = this._getMinMaxDate(inst, "max"),
|
||
minYear = null,
|
||
maxYear = null,
|
||
years = this._get(inst, "yearRange");
|
||
if (years){
|
||
yearSplit = years.split(":");
|
||
currentYear = new Date().getFullYear();
|
||
minYear = parseInt(yearSplit[0], 10);
|
||
maxYear = parseInt(yearSplit[1], 10);
|
||
if ( yearSplit[0].match(/[+\-].*/) ) {
|
||
minYear += currentYear;
|
||
}
|
||
if ( yearSplit[1].match(/[+\-].*/) ) {
|
||
maxYear += currentYear;
|
||
}
|
||
}
|
||
|
||
return ((!minDate || date.getTime() >= minDate.getTime()) &&
|
||
(!maxDate || date.getTime() <= maxDate.getTime()) &&
|
||
(!minYear || date.getFullYear() >= minYear) &&
|
||
(!maxYear || date.getFullYear() <= maxYear));
|
||
},
|
||
|
||
/* Provide the configuration settings for formatting/parsing. */
|
||
_getFormatConfig: function(inst) {
|
||
var shortYearCutoff = this._get(inst, "shortYearCutoff");
|
||
shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
|
||
new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
|
||
return {shortYearCutoff: shortYearCutoff,
|
||
dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
|
||
monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
|
||
},
|
||
|
||
/* Format the given date for display. */
|
||
_formatDate: function(inst, day, month, year) {
|
||
if (!day) {
|
||
inst.currentDay = inst.selectedDay;
|
||
inst.currentMonth = inst.selectedMonth;
|
||
inst.currentYear = inst.selectedYear;
|
||
}
|
||
var date = (day ? (typeof day === "object" ? day :
|
||
this._daylightSavingAdjust(new Date(year, month, day))) :
|
||
this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
|
||
return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
|
||
}
|
||
});
|
||
|
||
/*
|
||
* Bind hover events for datepicker elements.
|
||
* Done via delegate so the binding only occurs once in the lifetime of the parent div.
|
||
* Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
|
||
*/
|
||
function datepicker_bindHover(dpDiv) {
|
||
var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
|
||
return dpDiv.delegate(selector, "mouseout", function() {
|
||
$(this).removeClass("ui-state-hover");
|
||
if (this.className.indexOf("ui-datepicker-prev") !== -1) {
|
||
$(this).removeClass("ui-datepicker-prev-hover");
|
||
}
|
||
if (this.className.indexOf("ui-datepicker-next") !== -1) {
|
||
$(this).removeClass("ui-datepicker-next-hover");
|
||
}
|
||
})
|
||
.delegate( selector, "mouseover", datepicker_handleMouseover );
|
||
}
|
||
|
||
function datepicker_handleMouseover() {
|
||
if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
|
||
$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
|
||
$(this).addClass("ui-state-hover");
|
||
if (this.className.indexOf("ui-datepicker-prev") !== -1) {
|
||
$(this).addClass("ui-datepicker-prev-hover");
|
||
}
|
||
if (this.className.indexOf("ui-datepicker-next") !== -1) {
|
||
$(this).addClass("ui-datepicker-next-hover");
|
||
}
|
||
}
|
||
}
|
||
|
||
/* jQuery extend now ignores nulls! */
|
||
function datepicker_extendRemove(target, props) {
|
||
$.extend(target, props);
|
||
for (var name in props) {
|
||
if (props[name] == null) {
|
||
target[name] = props[name];
|
||
}
|
||
}
|
||
return target;
|
||
}
|
||
|
||
/* Invoke the datepicker functionality.
|
||
@param options string - a command, optionally followed by additional parameters or
|
||
Object - settings for attaching new datepicker functionality
|
||
@return jQuery object */
|
||
$.fn.datepicker = function(options){
|
||
|
||
/* Verify an empty collection wasn't passed - Fixes #6976 */
|
||
if ( !this.length ) {
|
||
return this;
|
||
}
|
||
|
||
/* Initialise the date picker. */
|
||
if (!$.datepicker.initialized) {
|
||
$(document).mousedown($.datepicker._checkExternalClick);
|
||
$.datepicker.initialized = true;
|
||
}
|
||
|
||
/* Append datepicker main container to body if not exist. */
|
||
if ($("#"+$.datepicker._mainDivId).length === 0) {
|
||
$("body").append($.datepicker.dpDiv);
|
||
}
|
||
|
||
var otherArgs = Array.prototype.slice.call(arguments, 1);
|
||
if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
|
||
return $.datepicker["_" + options + "Datepicker"].
|
||
apply($.datepicker, [this[0]].concat(otherArgs));
|
||
}
|
||
if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
|
||
return $.datepicker["_" + options + "Datepicker"].
|
||
apply($.datepicker, [this[0]].concat(otherArgs));
|
||
}
|
||
return this.each(function() {
|
||
typeof options === "string" ?
|
||
$.datepicker["_" + options + "Datepicker"].
|
||
apply($.datepicker, [this].concat(otherArgs)) :
|
||
$.datepicker._attachDatepicker(this, options);
|
||
});
|
||
};
|
||
|
||
$.datepicker = new Datepicker(); // singleton instance
|
||
$.datepicker.initialized = false;
|
||
$.datepicker.uuid = new Date().getTime();
|
||
$.datepicker.version = "1.11.4";
|
||
|
||
var datepicker = $.datepicker;
|
||
|
||
|
||
/*!
|
||
* jQuery UI Slider 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/slider/
|
||
*/
|
||
|
||
|
||
var slider = $.widget( "ui.slider", $.ui.mouse, {
|
||
version: "1.11.4",
|
||
widgetEventPrefix: "slide",
|
||
|
||
options: {
|
||
animate: false,
|
||
distance: 0,
|
||
max: 100,
|
||
min: 0,
|
||
orientation: "horizontal",
|
||
range: false,
|
||
step: 1,
|
||
value: 0,
|
||
values: null,
|
||
|
||
// callbacks
|
||
change: null,
|
||
slide: null,
|
||
start: null,
|
||
stop: null
|
||
},
|
||
|
||
// number of pages in a slider
|
||
// (how many times can you page up/down to go through the whole range)
|
||
numPages: 5,
|
||
|
||
_create: function() {
|
||
this._keySliding = false;
|
||
this._mouseSliding = false;
|
||
this._animateOff = true;
|
||
this._handleIndex = null;
|
||
this._detectOrientation();
|
||
this._mouseInit();
|
||
this._calculateNewMax();
|
||
|
||
this.element
|
||
.addClass( "ui-slider" +
|
||
" ui-slider-" + this.orientation +
|
||
" ui-widget" +
|
||
" ui-widget-content" +
|
||
" ui-corner-all");
|
||
|
||
this._refresh();
|
||
this._setOption( "disabled", this.options.disabled );
|
||
|
||
this._animateOff = false;
|
||
},
|
||
|
||
_refresh: function() {
|
||
this._createRange();
|
||
this._createHandles();
|
||
this._setupEvents();
|
||
this._refreshValue();
|
||
},
|
||
|
||
_createHandles: function() {
|
||
var i, handleCount,
|
||
options = this.options,
|
||
existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
|
||
handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
|
||
handles = [];
|
||
|
||
handleCount = ( options.values && options.values.length ) || 1;
|
||
|
||
if ( existingHandles.length > handleCount ) {
|
||
existingHandles.slice( handleCount ).remove();
|
||
existingHandles = existingHandles.slice( 0, handleCount );
|
||
}
|
||
|
||
for ( i = existingHandles.length; i < handleCount; i++ ) {
|
||
handles.push( handle );
|
||
}
|
||
|
||
this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
|
||
|
||
this.handle = this.handles.eq( 0 );
|
||
|
||
this.handles.each(function( i ) {
|
||
$( this ).data( "ui-slider-handle-index", i );
|
||
});
|
||
},
|
||
|
||
_createRange: function() {
|
||
var options = this.options,
|
||
classes = "";
|
||
|
||
if ( options.range ) {
|
||
if ( options.range === true ) {
|
||
if ( !options.values ) {
|
||
options.values = [ this._valueMin(), this._valueMin() ];
|
||
} else if ( options.values.length && options.values.length !== 2 ) {
|
||
options.values = [ options.values[0], options.values[0] ];
|
||
} else if ( $.isArray( options.values ) ) {
|
||
options.values = options.values.slice(0);
|
||
}
|
||
}
|
||
|
||
if ( !this.range || !this.range.length ) {
|
||
this.range = $( "<div></div>" )
|
||
.appendTo( this.element );
|
||
|
||
classes = "ui-slider-range" +
|
||
// note: this isn't the most fittingly semantic framework class for this element,
|
||
// but worked best visually with a variety of themes
|
||
" ui-widget-header ui-corner-all";
|
||
} else {
|
||
this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
|
||
// Handle range switching from true to min/max
|
||
.css({
|
||
"left": "",
|
||
"bottom": ""
|
||
});
|
||
}
|
||
|
||
this.range.addClass( classes +
|
||
( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
|
||
} else {
|
||
if ( this.range ) {
|
||
this.range.remove();
|
||
}
|
||
this.range = null;
|
||
}
|
||
},
|
||
|
||
_setupEvents: function() {
|
||
this._off( this.handles );
|
||
this._on( this.handles, this._handleEvents );
|
||
this._hoverable( this.handles );
|
||
this._focusable( this.handles );
|
||
},
|
||
|
||
_destroy: function() {
|
||
this.handles.remove();
|
||
if ( this.range ) {
|
||
this.range.remove();
|
||
}
|
||
|
||
this.element
|
||
.removeClass( "ui-slider" +
|
||
" ui-slider-horizontal" +
|
||
" ui-slider-vertical" +
|
||
" ui-widget" +
|
||
" ui-widget-content" +
|
||
" ui-corner-all" );
|
||
|
||
this._mouseDestroy();
|
||
},
|
||
|
||
_mouseCapture: function( event ) {
|
||
var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
|
||
that = this,
|
||
o = this.options;
|
||
|
||
if ( o.disabled ) {
|
||
return false;
|
||
}
|
||
|
||
this.elementSize = {
|
||
width: this.element.outerWidth(),
|
||
height: this.element.outerHeight()
|
||
};
|
||
this.elementOffset = this.element.offset();
|
||
|
||
position = { x: event.pageX, y: event.pageY };
|
||
normValue = this._normValueFromMouse( position );
|
||
distance = this._valueMax() - this._valueMin() + 1;
|
||
this.handles.each(function( i ) {
|
||
var thisDistance = Math.abs( normValue - that.values(i) );
|
||
if (( distance > thisDistance ) ||
|
||
( distance === thisDistance &&
|
||
(i === that._lastChangedValue || that.values(i) === o.min ))) {
|
||
distance = thisDistance;
|
||
closestHandle = $( this );
|
||
index = i;
|
||
}
|
||
});
|
||
|
||
allowed = this._start( event, index );
|
||
if ( allowed === false ) {
|
||
return false;
|
||
}
|
||
this._mouseSliding = true;
|
||
|
||
this._handleIndex = index;
|
||
|
||
closestHandle
|
||
.addClass( "ui-state-active" )
|
||
.focus();
|
||
|
||
offset = closestHandle.offset();
|
||
mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
|
||
this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
|
||
left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
|
||
top: event.pageY - offset.top -
|
||
( closestHandle.height() / 2 ) -
|
||
( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
|
||
( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
|
||
( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
|
||
};
|
||
|
||
if ( !this.handles.hasClass( "ui-state-hover" ) ) {
|
||
this._slide( event, index, normValue );
|
||
}
|
||
this._animateOff = true;
|
||
return true;
|
||
},
|
||
|
||
_mouseStart: function() {
|
||
return true;
|
||
},
|
||
|
||
_mouseDrag: function( event ) {
|
||
var position = { x: event.pageX, y: event.pageY },
|
||
normValue = this._normValueFromMouse( position );
|
||
|
||
this._slide( event, this._handleIndex, normValue );
|
||
|
||
return false;
|
||
},
|
||
|
||
_mouseStop: function( event ) {
|
||
this.handles.removeClass( "ui-state-active" );
|
||
this._mouseSliding = false;
|
||
|
||
this._stop( event, this._handleIndex );
|
||
this._change( event, this._handleIndex );
|
||
|
||
this._handleIndex = null;
|
||
this._clickOffset = null;
|
||
this._animateOff = false;
|
||
|
||
return false;
|
||
},
|
||
|
||
_detectOrientation: function() {
|
||
this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
|
||
},
|
||
|
||
_normValueFromMouse: function( position ) {
|
||
var pixelTotal,
|
||
pixelMouse,
|
||
percentMouse,
|
||
valueTotal,
|
||
valueMouse;
|
||
|
||
if ( this.orientation === "horizontal" ) {
|
||
pixelTotal = this.elementSize.width;
|
||
pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
|
||
} else {
|
||
pixelTotal = this.elementSize.height;
|
||
pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
|
||
}
|
||
|
||
percentMouse = ( pixelMouse / pixelTotal );
|
||
if ( percentMouse > 1 ) {
|
||
percentMouse = 1;
|
||
}
|
||
if ( percentMouse < 0 ) {
|
||
percentMouse = 0;
|
||
}
|
||
if ( this.orientation === "vertical" ) {
|
||
percentMouse = 1 - percentMouse;
|
||
}
|
||
|
||
valueTotal = this._valueMax() - this._valueMin();
|
||
valueMouse = this._valueMin() + percentMouse * valueTotal;
|
||
|
||
return this._trimAlignValue( valueMouse );
|
||
},
|
||
|
||
_start: function( event, index ) {
|
||
var uiHash = {
|
||
handle: this.handles[ index ],
|
||
value: this.value()
|
||
};
|
||
if ( this.options.values && this.options.values.length ) {
|
||
uiHash.value = this.values( index );
|
||
uiHash.values = this.values();
|
||
}
|
||
return this._trigger( "start", event, uiHash );
|
||
},
|
||
|
||
_slide: function( event, index, newVal ) {
|
||
var otherVal,
|
||
newValues,
|
||
allowed;
|
||
|
||
if ( this.options.values && this.options.values.length ) {
|
||
otherVal = this.values( index ? 0 : 1 );
|
||
|
||
if ( ( this.options.values.length === 2 && this.options.range === true ) &&
|
||
( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
|
||
) {
|
||
newVal = otherVal;
|
||
}
|
||
|
||
if ( newVal !== this.values( index ) ) {
|
||
newValues = this.values();
|
||
newValues[ index ] = newVal;
|
||
// A slide can be canceled by returning false from the slide callback
|
||
allowed = this._trigger( "slide", event, {
|
||
handle: this.handles[ index ],
|
||
value: newVal,
|
||
values: newValues
|
||
} );
|
||
otherVal = this.values( index ? 0 : 1 );
|
||
if ( allowed !== false ) {
|
||
this.values( index, newVal );
|
||
}
|
||
}
|
||
} else {
|
||
if ( newVal !== this.value() ) {
|
||
// A slide can be canceled by returning false from the slide callback
|
||
allowed = this._trigger( "slide", event, {
|
||
handle: this.handles[ index ],
|
||
value: newVal
|
||
} );
|
||
if ( allowed !== false ) {
|
||
this.value( newVal );
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
_stop: function( event, index ) {
|
||
var uiHash = {
|
||
handle: this.handles[ index ],
|
||
value: this.value()
|
||
};
|
||
if ( this.options.values && this.options.values.length ) {
|
||
uiHash.value = this.values( index );
|
||
uiHash.values = this.values();
|
||
}
|
||
|
||
this._trigger( "stop", event, uiHash );
|
||
},
|
||
|
||
_change: function( event, index ) {
|
||
if ( !this._keySliding && !this._mouseSliding ) {
|
||
var uiHash = {
|
||
handle: this.handles[ index ],
|
||
value: this.value()
|
||
};
|
||
if ( this.options.values && this.options.values.length ) {
|
||
uiHash.value = this.values( index );
|
||
uiHash.values = this.values();
|
||
}
|
||
|
||
//store the last changed value index for reference when handles overlap
|
||
this._lastChangedValue = index;
|
||
|
||
this._trigger( "change", event, uiHash );
|
||
}
|
||
},
|
||
|
||
value: function( newValue ) {
|
||
if ( arguments.length ) {
|
||
this.options.value = this._trimAlignValue( newValue );
|
||
this._refreshValue();
|
||
this._change( null, 0 );
|
||
return;
|
||
}
|
||
|
||
return this._value();
|
||
},
|
||
|
||
values: function( index, newValue ) {
|
||
var vals,
|
||
newValues,
|
||
i;
|
||
|
||
if ( arguments.length > 1 ) {
|
||
this.options.values[ index ] = this._trimAlignValue( newValue );
|
||
this._refreshValue();
|
||
this._change( null, index );
|
||
return;
|
||
}
|
||
|
||
if ( arguments.length ) {
|
||
if ( $.isArray( arguments[ 0 ] ) ) {
|
||
vals = this.options.values;
|
||
newValues = arguments[ 0 ];
|
||
for ( i = 0; i < vals.length; i += 1 ) {
|
||
vals[ i ] = this._trimAlignValue( newValues[ i ] );
|
||
this._change( null, i );
|
||
}
|
||
this._refreshValue();
|
||
} else {
|
||
if ( this.options.values && this.options.values.length ) {
|
||
return this._values( index );
|
||
} else {
|
||
return this.value();
|
||
}
|
||
}
|
||
} else {
|
||
return this._values();
|
||
}
|
||
},
|
||
|
||
_setOption: function( key, value ) {
|
||
var i,
|
||
valsLength = 0;
|
||
|
||
if ( key === "range" && this.options.range === true ) {
|
||
if ( value === "min" ) {
|
||
this.options.value = this._values( 0 );
|
||
this.options.values = null;
|
||
} else if ( value === "max" ) {
|
||
this.options.value = this._values( this.options.values.length - 1 );
|
||
this.options.values = null;
|
||
}
|
||
}
|
||
|
||
if ( $.isArray( this.options.values ) ) {
|
||
valsLength = this.options.values.length;
|
||
}
|
||
|
||
if ( key === "disabled" ) {
|
||
this.element.toggleClass( "ui-state-disabled", !!value );
|
||
}
|
||
|
||
this._super( key, value );
|
||
|
||
switch ( key ) {
|
||
case "orientation":
|
||
this._detectOrientation();
|
||
this.element
|
||
.removeClass( "ui-slider-horizontal ui-slider-vertical" )
|
||
.addClass( "ui-slider-" + this.orientation );
|
||
this._refreshValue();
|
||
|
||
// Reset positioning from previous orientation
|
||
this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
|
||
break;
|
||
case "value":
|
||
this._animateOff = true;
|
||
this._refreshValue();
|
||
this._change( null, 0 );
|
||
this._animateOff = false;
|
||
break;
|
||
case "values":
|
||
this._animateOff = true;
|
||
this._refreshValue();
|
||
for ( i = 0; i < valsLength; i += 1 ) {
|
||
this._change( null, i );
|
||
}
|
||
this._animateOff = false;
|
||
break;
|
||
case "step":
|
||
case "min":
|
||
case "max":
|
||
this._animateOff = true;
|
||
this._calculateNewMax();
|
||
this._refreshValue();
|
||
this._animateOff = false;
|
||
break;
|
||
case "range":
|
||
this._animateOff = true;
|
||
this._refresh();
|
||
this._animateOff = false;
|
||
break;
|
||
}
|
||
},
|
||
|
||
//internal value getter
|
||
// _value() returns value trimmed by min and max, aligned by step
|
||
_value: function() {
|
||
var val = this.options.value;
|
||
val = this._trimAlignValue( val );
|
||
|
||
return val;
|
||
},
|
||
|
||
//internal values getter
|
||
// _values() returns array of values trimmed by min and max, aligned by step
|
||
// _values( index ) returns single value trimmed by min and max, aligned by step
|
||
_values: function( index ) {
|
||
var val,
|
||
vals,
|
||
i;
|
||
|
||
if ( arguments.length ) {
|
||
val = this.options.values[ index ];
|
||
val = this._trimAlignValue( val );
|
||
|
||
return val;
|
||
} else if ( this.options.values && this.options.values.length ) {
|
||
// .slice() creates a copy of the array
|
||
// this copy gets trimmed by min and max and then returned
|
||
vals = this.options.values.slice();
|
||
for ( i = 0; i < vals.length; i += 1) {
|
||
vals[ i ] = this._trimAlignValue( vals[ i ] );
|
||
}
|
||
|
||
return vals;
|
||
} else {
|
||
return [];
|
||
}
|
||
},
|
||
|
||
// returns the step-aligned value that val is closest to, between (inclusive) min and max
|
||
_trimAlignValue: function( val ) {
|
||
if ( val <= this._valueMin() ) {
|
||
return this._valueMin();
|
||
}
|
||
if ( val >= this._valueMax() ) {
|
||
return this._valueMax();
|
||
}
|
||
var step = ( this.options.step > 0 ) ? this.options.step : 1,
|
||
valModStep = (val - this._valueMin()) % step,
|
||
alignValue = val - valModStep;
|
||
|
||
if ( Math.abs(valModStep) * 2 >= step ) {
|
||
alignValue += ( valModStep > 0 ) ? step : ( -step );
|
||
}
|
||
|
||
// Since JavaScript has problems with large floats, round
|
||
// the final value to 5 digits after the decimal point (see #4124)
|
||
return parseFloat( alignValue.toFixed(5) );
|
||
},
|
||
|
||
_calculateNewMax: function() {
|
||
var max = this.options.max,
|
||
min = this._valueMin(),
|
||
step = this.options.step,
|
||
aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step;
|
||
max = aboveMin + min;
|
||
this.max = parseFloat( max.toFixed( this._precision() ) );
|
||
},
|
||
|
||
_precision: function() {
|
||
var precision = this._precisionOf( this.options.step );
|
||
if ( this.options.min !== null ) {
|
||
precision = Math.max( precision, this._precisionOf( this.options.min ) );
|
||
}
|
||
return precision;
|
||
},
|
||
|
||
_precisionOf: function( num ) {
|
||
var str = num.toString(),
|
||
decimal = str.indexOf( "." );
|
||
return decimal === -1 ? 0 : str.length - decimal - 1;
|
||
},
|
||
|
||
_valueMin: function() {
|
||
return this.options.min;
|
||
},
|
||
|
||
_valueMax: function() {
|
||
return this.max;
|
||
},
|
||
|
||
_refreshValue: function() {
|
||
var lastValPercent, valPercent, value, valueMin, valueMax,
|
||
oRange = this.options.range,
|
||
o = this.options,
|
||
that = this,
|
||
animate = ( !this._animateOff ) ? o.animate : false,
|
||
_set = {};
|
||
|
||
if ( this.options.values && this.options.values.length ) {
|
||
this.handles.each(function( i ) {
|
||
valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
|
||
_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
|
||
$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
|
||
if ( that.options.range === true ) {
|
||
if ( that.orientation === "horizontal" ) {
|
||
if ( i === 0 ) {
|
||
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
|
||
}
|
||
if ( i === 1 ) {
|
||
that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
|
||
}
|
||
} else {
|
||
if ( i === 0 ) {
|
||
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
|
||
}
|
||
if ( i === 1 ) {
|
||
that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
|
||
}
|
||
}
|
||
}
|
||
lastValPercent = valPercent;
|
||
});
|
||
} else {
|
||
value = this.value();
|
||
valueMin = this._valueMin();
|
||
valueMax = this._valueMax();
|
||
valPercent = ( valueMax !== valueMin ) ?
|
||
( value - valueMin ) / ( valueMax - valueMin ) * 100 :
|
||
0;
|
||
_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
|
||
this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
|
||
|
||
if ( oRange === "min" && this.orientation === "horizontal" ) {
|
||
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
|
||
}
|
||
if ( oRange === "max" && this.orientation === "horizontal" ) {
|
||
this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
|
||
}
|
||
if ( oRange === "min" && this.orientation === "vertical" ) {
|
||
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
|
||
}
|
||
if ( oRange === "max" && this.orientation === "vertical" ) {
|
||
this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
|
||
}
|
||
}
|
||
},
|
||
|
||
_handleEvents: {
|
||
keydown: function( event ) {
|
||
var allowed, curVal, newVal, step,
|
||
index = $( event.target ).data( "ui-slider-handle-index" );
|
||
|
||
switch ( event.keyCode ) {
|
||
case $.ui.keyCode.HOME:
|
||
case $.ui.keyCode.END:
|
||
case $.ui.keyCode.PAGE_UP:
|
||
case $.ui.keyCode.PAGE_DOWN:
|
||
case $.ui.keyCode.UP:
|
||
case $.ui.keyCode.RIGHT:
|
||
case $.ui.keyCode.DOWN:
|
||
case $.ui.keyCode.LEFT:
|
||
event.preventDefault();
|
||
if ( !this._keySliding ) {
|
||
this._keySliding = true;
|
||
$( event.target ).addClass( "ui-state-active" );
|
||
allowed = this._start( event, index );
|
||
if ( allowed === false ) {
|
||
return;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
step = this.options.step;
|
||
if ( this.options.values && this.options.values.length ) {
|
||
curVal = newVal = this.values( index );
|
||
} else {
|
||
curVal = newVal = this.value();
|
||
}
|
||
|
||
switch ( event.keyCode ) {
|
||
case $.ui.keyCode.HOME:
|
||
newVal = this._valueMin();
|
||
break;
|
||
case $.ui.keyCode.END:
|
||
newVal = this._valueMax();
|
||
break;
|
||
case $.ui.keyCode.PAGE_UP:
|
||
newVal = this._trimAlignValue(
|
||
curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
|
||
);
|
||
break;
|
||
case $.ui.keyCode.PAGE_DOWN:
|
||
newVal = this._trimAlignValue(
|
||
curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
|
||
break;
|
||
case $.ui.keyCode.UP:
|
||
case $.ui.keyCode.RIGHT:
|
||
if ( curVal === this._valueMax() ) {
|
||
return;
|
||
}
|
||
newVal = this._trimAlignValue( curVal + step );
|
||
break;
|
||
case $.ui.keyCode.DOWN:
|
||
case $.ui.keyCode.LEFT:
|
||
if ( curVal === this._valueMin() ) {
|
||
return;
|
||
}
|
||
newVal = this._trimAlignValue( curVal - step );
|
||
break;
|
||
}
|
||
|
||
this._slide( event, index, newVal );
|
||
},
|
||
keyup: function( event ) {
|
||
var index = $( event.target ).data( "ui-slider-handle-index" );
|
||
|
||
if ( this._keySliding ) {
|
||
this._keySliding = false;
|
||
this._stop( event, index );
|
||
this._change( event, index );
|
||
$( event.target ).removeClass( "ui-state-active" );
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
/*!
|
||
* jQuery UI Tooltip 1.11.4
|
||
* http://jqueryui.com
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* http://api.jqueryui.com/tooltip/
|
||
*/
|
||
|
||
|
||
var tooltip = $.widget( "ui.tooltip", {
|
||
version: "1.11.4",
|
||
options: {
|
||
content: function() {
|
||
// support: IE<9, Opera in jQuery <1.7
|
||
// .text() can't accept undefined, so coerce to a string
|
||
var title = $( this ).attr( "title" ) || "";
|
||
// Escape title, since we're going from an attribute to raw HTML
|
||
return $( "<a>" ).text( title ).html();
|
||
},
|
||
hide: true,
|
||
// Disabled elements have inconsistent behavior across browsers (#8661)
|
||
items: "[title]:not([disabled])",
|
||
position: {
|
||
my: "left top+15",
|
||
at: "left bottom",
|
||
collision: "flipfit flip"
|
||
},
|
||
show: true,
|
||
tooltipClass: null,
|
||
track: false,
|
||
|
||
// callbacks
|
||
close: null,
|
||
open: null
|
||
},
|
||
|
||
_addDescribedBy: function( elem, id ) {
|
||
var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
|
||
describedby.push( id );
|
||
elem
|
||
.data( "ui-tooltip-id", id )
|
||
.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
|
||
},
|
||
|
||
_removeDescribedBy: function( elem ) {
|
||
var id = elem.data( "ui-tooltip-id" ),
|
||
describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
|
||
index = $.inArray( id, describedby );
|
||
|
||
if ( index !== -1 ) {
|
||
describedby.splice( index, 1 );
|
||
}
|
||
|
||
elem.removeData( "ui-tooltip-id" );
|
||
describedby = $.trim( describedby.join( " " ) );
|
||
if ( describedby ) {
|
||
elem.attr( "aria-describedby", describedby );
|
||
} else {
|
||
elem.removeAttr( "aria-describedby" );
|
||
}
|
||
},
|
||
|
||
_create: function() {
|
||
this._on({
|
||
mouseover: "open",
|
||
focusin: "open"
|
||
});
|
||
|
||
// IDs of generated tooltips, needed for destroy
|
||
this.tooltips = {};
|
||
|
||
// IDs of parent tooltips where we removed the title attribute
|
||
this.parents = {};
|
||
|
||
if ( this.options.disabled ) {
|
||
this._disable();
|
||
}
|
||
|
||
// Append the aria-live region so tooltips announce correctly
|
||
this.liveRegion = $( "<div>" )
|
||
.attr({
|
||
role: "log",
|
||
"aria-live": "assertive",
|
||
"aria-relevant": "additions"
|
||
})
|
||
.addClass( "ui-helper-hidden-accessible" )
|
||
.appendTo( this.document[ 0 ].body );
|
||
},
|
||
|
||
_setOption: function( key, value ) {
|
||
var that = this;
|
||
|
||
if ( key === "disabled" ) {
|
||
this[ value ? "_disable" : "_enable" ]();
|
||
this.options[ key ] = value;
|
||
// disable element style changes
|
||
return;
|
||
}
|
||
|
||
this._super( key, value );
|
||
|
||
if ( key === "content" ) {
|
||
$.each( this.tooltips, function( id, tooltipData ) {
|
||
that._updateContent( tooltipData.element );
|
||
});
|
||
}
|
||
},
|
||
|
||
_disable: function() {
|
||
var that = this;
|
||
|
||
// close open tooltips
|
||
$.each( this.tooltips, function( id, tooltipData ) {
|
||
var event = $.Event( "blur" );
|
||
event.target = event.currentTarget = tooltipData.element[ 0 ];
|
||
that.close( event, true );
|
||
});
|
||
|
||
// remove title attributes to prevent native tooltips
|
||
this.element.find( this.options.items ).addBack().each(function() {
|
||
var element = $( this );
|
||
if ( element.is( "[title]" ) ) {
|
||
element
|
||
.data( "ui-tooltip-title", element.attr( "title" ) )
|
||
.removeAttr( "title" );
|
||
}
|
||
});
|
||
},
|
||
|
||
_enable: function() {
|
||
// restore title attributes
|
||
this.element.find( this.options.items ).addBack().each(function() {
|
||
var element = $( this );
|
||
if ( element.data( "ui-tooltip-title" ) ) {
|
||
element.attr( "title", element.data( "ui-tooltip-title" ) );
|
||
}
|
||
});
|
||
},
|
||
|
||
open: function( event ) {
|
||
var that = this,
|
||
target = $( event ? event.target : this.element )
|
||
// we need closest here due to mouseover bubbling,
|
||
// but always pointing at the same event target
|
||
.closest( this.options.items );
|
||
|
||
// No element to show a tooltip for or the tooltip is already open
|
||
if ( !target.length || target.data( "ui-tooltip-id" ) ) {
|
||
return;
|
||
}
|
||
|
||
if ( target.attr( "title" ) ) {
|
||
target.data( "ui-tooltip-title", target.attr( "title" ) );
|
||
}
|
||
|
||
target.data( "ui-tooltip-open", true );
|
||
|
||
// kill parent tooltips, custom or native, for hover
|
||
if ( event && event.type === "mouseover" ) {
|
||
target.parents().each(function() {
|
||
var parent = $( this ),
|
||
blurEvent;
|
||
if ( parent.data( "ui-tooltip-open" ) ) {
|
||
blurEvent = $.Event( "blur" );
|
||
blurEvent.target = blurEvent.currentTarget = this;
|
||
that.close( blurEvent, true );
|
||
}
|
||
if ( parent.attr( "title" ) ) {
|
||
parent.uniqueId();
|
||
that.parents[ this.id ] = {
|
||
element: this,
|
||
title: parent.attr( "title" )
|
||
};
|
||
parent.attr( "title", "" );
|
||
}
|
||
});
|
||
}
|
||
|
||
this._registerCloseHandlers( event, target );
|
||
this._updateContent( target, event );
|
||
},
|
||
|
||
_updateContent: function( target, event ) {
|
||
var content,
|
||
contentOption = this.options.content,
|
||
that = this,
|
||
eventType = event ? event.type : null;
|
||
|
||
if ( typeof contentOption === "string" ) {
|
||
return this._open( event, target, contentOption );
|
||
}
|
||
|
||
content = contentOption.call( target[0], function( response ) {
|
||
|
||
// IE may instantly serve a cached response for ajax requests
|
||
// delay this call to _open so the other call to _open runs first
|
||
that._delay(function() {
|
||
|
||
// Ignore async response if tooltip was closed already
|
||
if ( !target.data( "ui-tooltip-open" ) ) {
|
||
return;
|
||
}
|
||
|
||
// jQuery creates a special event for focusin when it doesn't
|
||
// exist natively. To improve performance, the native event
|
||
// object is reused and the type is changed. Therefore, we can't
|
||
// rely on the type being correct after the event finished
|
||
// bubbling, so we set it back to the previous value. (#8740)
|
||
if ( event ) {
|
||
event.type = eventType;
|
||
}
|
||
this._open( event, target, response );
|
||
});
|
||
});
|
||
if ( content ) {
|
||
this._open( event, target, content );
|
||
}
|
||
},
|
||
|
||
_open: function( event, target, content ) {
|
||
var tooltipData, tooltip, delayedShow, a11yContent,
|
||
positionOption = $.extend( {}, this.options.position );
|
||
|
||
if ( !content ) {
|
||
return;
|
||
}
|
||
|
||
// Content can be updated multiple times. If the tooltip already
|
||
// exists, then just update the content and bail.
|
||
tooltipData = this._find( target );
|
||
if ( tooltipData ) {
|
||
tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
|
||
return;
|
||
}
|
||
|
||
// if we have a title, clear it to prevent the native tooltip
|
||
// we have to check first to avoid defining a title if none exists
|
||
// (we don't want to cause an element to start matching [title])
|
||
//
|
||
// We use removeAttr only for key events, to allow IE to export the correct
|
||
// accessible attributes. For mouse events, set to empty string to avoid
|
||
// native tooltip showing up (happens only when removing inside mouseover).
|
||
if ( target.is( "[title]" ) ) {
|
||
if ( event && event.type === "mouseover" ) {
|
||
target.attr( "title", "" );
|
||
} else {
|
||
target.removeAttr( "title" );
|
||
}
|
||
}
|
||
|
||
tooltipData = this._tooltip( target );
|
||
tooltip = tooltipData.tooltip;
|
||
this._addDescribedBy( target, tooltip.attr( "id" ) );
|
||
tooltip.find( ".ui-tooltip-content" ).html( content );
|
||
|
||
// Support: Voiceover on OS X, JAWS on IE <= 9
|
||
// JAWS announces deletions even when aria-relevant="additions"
|
||
// Voiceover will sometimes re-read the entire log region's contents from the beginning
|
||
this.liveRegion.children().hide();
|
||
if ( content.clone ) {
|
||
a11yContent = content.clone();
|
||
a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
|
||
} else {
|
||
a11yContent = content;
|
||
}
|
||
$( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
|
||
|
||
function position( event ) {
|
||
positionOption.of = event;
|
||
if ( tooltip.is( ":hidden" ) ) {
|
||
return;
|
||
}
|
||
tooltip.position( positionOption );
|
||
}
|
||
if ( this.options.track && event && /^mouse/.test( event.type ) ) {
|
||
this._on( this.document, {
|
||
mousemove: position
|
||
});
|
||
// trigger once to override element-relative positioning
|
||
position( event );
|
||
} else {
|
||
tooltip.position( $.extend({
|
||
of: target
|
||
}, this.options.position ) );
|
||
}
|
||
|
||
tooltip.hide();
|
||
|
||
this._show( tooltip, this.options.show );
|
||
// Handle tracking tooltips that are shown with a delay (#8644). As soon
|
||
// as the tooltip is visible, position the tooltip using the most recent
|
||
// event.
|
||
if ( this.options.show && this.options.show.delay ) {
|
||
delayedShow = this.delayedShow = setInterval(function() {
|
||
if ( tooltip.is( ":visible" ) ) {
|
||
position( positionOption.of );
|
||
clearInterval( delayedShow );
|
||
}
|
||
}, $.fx.interval );
|
||
}
|
||
|
||
this._trigger( "open", event, { tooltip: tooltip } );
|
||
},
|
||
|
||
_registerCloseHandlers: function( event, target ) {
|
||
var events = {
|
||
keyup: function( event ) {
|
||
if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
|
||
var fakeEvent = $.Event(event);
|
||
fakeEvent.currentTarget = target[0];
|
||
this.close( fakeEvent, true );
|
||
}
|
||
}
|
||
};
|
||
|
||
// Only bind remove handler for delegated targets. Non-delegated
|
||
// tooltips will handle this in destroy.
|
||
if ( target[ 0 ] !== this.element[ 0 ] ) {
|
||
events.remove = function() {
|
||
this._removeTooltip( this._find( target ).tooltip );
|
||
};
|
||
}
|
||
|
||
if ( !event || event.type === "mouseover" ) {
|
||
events.mouseleave = "close";
|
||
}
|
||
if ( !event || event.type === "focusin" ) {
|
||
events.focusout = "close";
|
||
}
|
||
this._on( true, target, events );
|
||
},
|
||
|
||
close: function( event ) {
|
||
var tooltip,
|
||
that = this,
|
||
target = $( event ? event.currentTarget : this.element ),
|
||
tooltipData = this._find( target );
|
||
|
||
// The tooltip may already be closed
|
||
if ( !tooltipData ) {
|
||
|
||
// We set ui-tooltip-open immediately upon open (in open()), but only set the
|
||
// additional data once there's actually content to show (in _open()). So even if the
|
||
// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
|
||
// the period between open() and _open().
|
||
target.removeData( "ui-tooltip-open" );
|
||
return;
|
||
}
|
||
|
||
tooltip = tooltipData.tooltip;
|
||
|
||
// disabling closes the tooltip, so we need to track when we're closing
|
||
// to avoid an infinite loop in case the tooltip becomes disabled on close
|
||
if ( tooltipData.closing ) {
|
||
return;
|
||
}
|
||
|
||
// Clear the interval for delayed tracking tooltips
|
||
clearInterval( this.delayedShow );
|
||
|
||
// only set title if we had one before (see comment in _open())
|
||
// If the title attribute has changed since open(), don't restore
|
||
if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
|
||
target.attr( "title", target.data( "ui-tooltip-title" ) );
|
||
}
|
||
|
||
this._removeDescribedBy( target );
|
||
|
||
tooltipData.hiding = true;
|
||
tooltip.stop( true );
|
||
this._hide( tooltip, this.options.hide, function() {
|
||
that._removeTooltip( $( this ) );
|
||
});
|
||
|
||
target.removeData( "ui-tooltip-open" );
|
||
this._off( target, "mouseleave focusout keyup" );
|
||
|
||
// Remove 'remove' binding only on delegated targets
|
||
if ( target[ 0 ] !== this.element[ 0 ] ) {
|
||
this._off( target, "remove" );
|
||
}
|
||
this._off( this.document, "mousemove" );
|
||
|
||
if ( event && event.type === "mouseleave" ) {
|
||
$.each( this.parents, function( id, parent ) {
|
||
$( parent.element ).attr( "title", parent.title );
|
||
delete that.parents[ id ];
|
||
});
|
||
}
|
||
|
||
tooltipData.closing = true;
|
||
this._trigger( "close", event, { tooltip: tooltip } );
|
||
if ( !tooltipData.hiding ) {
|
||
tooltipData.closing = false;
|
||
}
|
||
},
|
||
|
||
_tooltip: function( element ) {
|
||
var tooltip = $( "<div>" )
|
||
.attr( "role", "tooltip" )
|
||
.addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
|
||
( this.options.tooltipClass || "" ) ),
|
||
id = tooltip.uniqueId().attr( "id" );
|
||
|
||
$( "<div>" )
|
||
.addClass( "ui-tooltip-content" )
|
||
.appendTo( tooltip );
|
||
|
||
tooltip.appendTo( this.document[0].body );
|
||
|
||
return this.tooltips[ id ] = {
|
||
element: element,
|
||
tooltip: tooltip
|
||
};
|
||
},
|
||
|
||
_find: function( target ) {
|
||
var id = target.data( "ui-tooltip-id" );
|
||
return id ? this.tooltips[ id ] : null;
|
||
},
|
||
|
||
_removeTooltip: function( tooltip ) {
|
||
tooltip.remove();
|
||
delete this.tooltips[ tooltip.attr( "id" ) ];
|
||
},
|
||
|
||
_destroy: function() {
|
||
var that = this;
|
||
|
||
// close open tooltips
|
||
$.each( this.tooltips, function( id, tooltipData ) {
|
||
// Delegate to close method to handle common cleanup
|
||
var event = $.Event( "blur" ),
|
||
element = tooltipData.element;
|
||
event.target = event.currentTarget = element[ 0 ];
|
||
that.close( event, true );
|
||
|
||
// Remove immediately; destroying an open tooltip doesn't use the
|
||
// hide animation
|
||
$( "#" + id ).remove();
|
||
|
||
// Restore the title
|
||
if ( element.data( "ui-tooltip-title" ) ) {
|
||
// If the title attribute has changed since open(), don't restore
|
||
if ( !element.attr( "title" ) ) {
|
||
element.attr( "title", element.data( "ui-tooltip-title" ) );
|
||
}
|
||
element.removeData( "ui-tooltip-title" );
|
||
}
|
||
});
|
||
this.liveRegion.remove();
|
||
}
|
||
});
|
||
|
||
|
||
|
||
}));;/*! jQuery Timepicker Addon - v1.5.3 - 2015-04-19
|
||
* http://trentrichardson.com/examples/timepicker
|
||
* Copyright (c) 2015 Trent Richardson; Licensed MIT */
|
||
(function (factory) {
|
||
if (typeof define === 'function' && define.amd) {
|
||
define(['jquery', 'jquery.ui'], factory);
|
||
} else {
|
||
factory(jQuery);
|
||
}
|
||
}(function ($) {
|
||
|
||
/*
|
||
* Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
|
||
*/
|
||
$.ui.timepicker = $.ui.timepicker || {};
|
||
if ($.ui.timepicker.version) {
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* Extend jQueryUI, get it started with our version number
|
||
*/
|
||
$.extend($.ui, {
|
||
timepicker: {
|
||
version: "1.5.3"
|
||
}
|
||
});
|
||
|
||
/*
|
||
* Timepicker manager.
|
||
* Use the singleton instance of this class, $.timepicker, to interact with the time picker.
|
||
* Settings for (groups of) time pickers are maintained in an instance object,
|
||
* allowing multiple different settings on the same page.
|
||
*/
|
||
var Timepicker = function () {
|
||
this.regional = []; // Available regional settings, indexed by language code
|
||
this.regional[''] = { // Default regional settings
|
||
currentText: 'Now',
|
||
closeText: 'Done',
|
||
amNames: ['AM', 'A'],
|
||
pmNames: ['PM', 'P'],
|
||
timeFormat: 'HH:mm',
|
||
timeSuffix: '',
|
||
timeOnlyTitle: 'Choose Time',
|
||
timeText: 'Time',
|
||
hourText: 'Hour',
|
||
minuteText: 'Minute',
|
||
secondText: 'Second',
|
||
millisecText: 'Millisecond',
|
||
microsecText: 'Microsecond',
|
||
timezoneText: 'Time Zone',
|
||
isRTL: false
|
||
};
|
||
this._defaults = { // Global defaults for all the datetime picker instances
|
||
showButtonPanel: true,
|
||
timeOnly: false,
|
||
timeOnlyShowDate: false,
|
||
showHour: null,
|
||
showMinute: null,
|
||
showSecond: null,
|
||
showMillisec: null,
|
||
showMicrosec: null,
|
||
showTimezone: null,
|
||
showTime: true,
|
||
stepHour: 1,
|
||
stepMinute: 1,
|
||
stepSecond: 1,
|
||
stepMillisec: 1,
|
||
stepMicrosec: 1,
|
||
hour: 0,
|
||
minute: 0,
|
||
second: 0,
|
||
millisec: 0,
|
||
microsec: 0,
|
||
timezone: null,
|
||
hourMin: 0,
|
||
minuteMin: 0,
|
||
secondMin: 0,
|
||
millisecMin: 0,
|
||
microsecMin: 0,
|
||
hourMax: 23,
|
||
minuteMax: 59,
|
||
secondMax: 59,
|
||
millisecMax: 999,
|
||
microsecMax: 999,
|
||
minDateTime: null,
|
||
maxDateTime: null,
|
||
maxTime: null,
|
||
minTime: null,
|
||
onSelect: null,
|
||
hourGrid: 0,
|
||
minuteGrid: 0,
|
||
secondGrid: 0,
|
||
millisecGrid: 0,
|
||
microsecGrid: 0,
|
||
alwaysSetTime: true,
|
||
separator: ' ',
|
||
altFieldTimeOnly: true,
|
||
altTimeFormat: null,
|
||
altSeparator: null,
|
||
altTimeSuffix: null,
|
||
altRedirectFocus: true,
|
||
pickerTimeFormat: null,
|
||
pickerTimeSuffix: null,
|
||
showTimepicker: true,
|
||
timezoneList: null,
|
||
addSliderAccess: false,
|
||
sliderAccessArgs: null,
|
||
controlType: 'slider',
|
||
oneLine: false,
|
||
defaultValue: null,
|
||
parse: 'strict',
|
||
afterInject: null
|
||
};
|
||
$.extend(this._defaults, this.regional['']);
|
||
};
|
||
|
||
$.extend(Timepicker.prototype, {
|
||
$input: null,
|
||
$altInput: null,
|
||
$timeObj: null,
|
||
inst: null,
|
||
hour_slider: null,
|
||
minute_slider: null,
|
||
second_slider: null,
|
||
millisec_slider: null,
|
||
microsec_slider: null,
|
||
timezone_select: null,
|
||
maxTime: null,
|
||
minTime: null,
|
||
hour: 0,
|
||
minute: 0,
|
||
second: 0,
|
||
millisec: 0,
|
||
microsec: 0,
|
||
timezone: null,
|
||
hourMinOriginal: null,
|
||
minuteMinOriginal: null,
|
||
secondMinOriginal: null,
|
||
millisecMinOriginal: null,
|
||
microsecMinOriginal: null,
|
||
hourMaxOriginal: null,
|
||
minuteMaxOriginal: null,
|
||
secondMaxOriginal: null,
|
||
millisecMaxOriginal: null,
|
||
microsecMaxOriginal: null,
|
||
ampm: '',
|
||
formattedDate: '',
|
||
formattedTime: '',
|
||
formattedDateTime: '',
|
||
timezoneList: null,
|
||
units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
|
||
support: {},
|
||
control: null,
|
||
|
||
/*
|
||
* Override the default settings for all instances of the time picker.
|
||
* @param {Object} settings object - the new settings to use as defaults (anonymous object)
|
||
* @return {Object} the manager object
|
||
*/
|
||
setDefaults: function (settings) {
|
||
extendRemove(this._defaults, settings || {});
|
||
return this;
|
||
},
|
||
|
||
/*
|
||
* Create a new Timepicker instance
|
||
*/
|
||
_newInst: function ($input, opts) {
|
||
var tp_inst = new Timepicker(),
|
||
inlineSettings = {},
|
||
fns = {},
|
||
overrides, i;
|
||
|
||
for (var attrName in this._defaults) {
|
||
if (this._defaults.hasOwnProperty(attrName)) {
|
||
var attrValue = $input.attr('time:' + attrName);
|
||
if (attrValue) {
|
||
try {
|
||
inlineSettings[attrName] = eval(attrValue);
|
||
} catch (err) {
|
||
inlineSettings[attrName] = attrValue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
overrides = {
|
||
beforeShow: function (input, dp_inst) {
|
||
if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
|
||
return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
|
||
}
|
||
},
|
||
onChangeMonthYear: function (year, month, dp_inst) {
|
||
// Update the time as well : this prevents the time from disappearing from the $input field.
|
||
// tp_inst._updateDateTime(dp_inst);
|
||
if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
|
||
tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
|
||
}
|
||
},
|
||
onClose: function (dateText, dp_inst) {
|
||
if (tp_inst.timeDefined === true && $input.val() !== '') {
|
||
tp_inst._updateDateTime(dp_inst);
|
||
}
|
||
if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
|
||
tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
|
||
}
|
||
}
|
||
};
|
||
for (i in overrides) {
|
||
if (overrides.hasOwnProperty(i)) {
|
||
fns[i] = opts[i] || null;
|
||
}
|
||
}
|
||
|
||
tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
|
||
evnts: fns,
|
||
timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
|
||
});
|
||
tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
|
||
return val.toUpperCase();
|
||
});
|
||
tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
|
||
return val.toUpperCase();
|
||
});
|
||
|
||
// detect which units are supported
|
||
tp_inst.support = detectSupport(
|
||
tp_inst._defaults.timeFormat +
|
||
(tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
|
||
(tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
|
||
|
||
// controlType is string - key to our this._controls
|
||
if (typeof(tp_inst._defaults.controlType) === 'string') {
|
||
if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
|
||
tp_inst._defaults.controlType = 'select';
|
||
}
|
||
tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
|
||
}
|
||
// controlType is an object and must implement create, options, value methods
|
||
else {
|
||
tp_inst.control = tp_inst._defaults.controlType;
|
||
}
|
||
|
||
// prep the timezone options
|
||
var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
|
||
0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
|
||
if (tp_inst._defaults.timezoneList !== null) {
|
||
timezoneList = tp_inst._defaults.timezoneList;
|
||
}
|
||
var tzl = timezoneList.length, tzi = 0, tzv = null;
|
||
if (tzl > 0 && typeof timezoneList[0] !== 'object') {
|
||
for (; tzi < tzl; tzi++) {
|
||
tzv = timezoneList[tzi];
|
||
timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
|
||
}
|
||
}
|
||
tp_inst._defaults.timezoneList = timezoneList;
|
||
|
||
// set the default units
|
||
tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
|
||
((new Date()).getTimezoneOffset() * -1);
|
||
tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
|
||
tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
|
||
tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
|
||
tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
|
||
tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
|
||
tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
|
||
tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
|
||
tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
|
||
tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
|
||
tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
|
||
tp_inst.ampm = '';
|
||
tp_inst.$input = $input;
|
||
|
||
if (tp_inst._defaults.altField) {
|
||
tp_inst.$altInput = $(tp_inst._defaults.altField);
|
||
if (tp_inst._defaults.altRedirectFocus === true) {
|
||
tp_inst.$altInput.css({
|
||
cursor: 'pointer'
|
||
}).focus(function () {
|
||
$input.trigger("focus");
|
||
});
|
||
}
|
||
}
|
||
|
||
if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
|
||
tp_inst._defaults.minDate = new Date();
|
||
}
|
||
if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
|
||
tp_inst._defaults.maxDate = new Date();
|
||
}
|
||
|
||
// datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
|
||
if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
|
||
tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
|
||
}
|
||
if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
|
||
tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
|
||
}
|
||
if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
|
||
tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
|
||
}
|
||
if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
|
||
tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
|
||
}
|
||
tp_inst.$input.bind('focus', function () {
|
||
tp_inst._onFocus();
|
||
});
|
||
|
||
return tp_inst;
|
||
},
|
||
|
||
/*
|
||
* add our sliders to the calendar
|
||
*/
|
||
_addTimePicker: function (dp_inst) {
|
||
var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());
|
||
|
||
this.timeDefined = this._parseTime(currDT);
|
||
this._limitMinMaxDateTime(dp_inst, false);
|
||
this._injectTimePicker();
|
||
this._afterInject();
|
||
},
|
||
|
||
/*
|
||
* parse the time string from input value or _setTime
|
||
*/
|
||
_parseTime: function (timeString, withDate) {
|
||
if (!this.inst) {
|
||
this.inst = $.datepicker._getInst(this.$input[0]);
|
||
}
|
||
|
||
if (withDate || !this._defaults.timeOnly) {
|
||
var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
|
||
try {
|
||
var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
|
||
if (!parseRes.timeObj) {
|
||
return false;
|
||
}
|
||
$.extend(this, parseRes.timeObj);
|
||
} catch (err) {
|
||
$.timepicker.log("Error parsing the date/time string: " + err +
|
||
"\ndate/time string = " + timeString +
|
||
"\ntimeFormat = " + this._defaults.timeFormat +
|
||
"\ndateFormat = " + dp_dateFormat);
|
||
return false;
|
||
}
|
||
return true;
|
||
} else {
|
||
var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
|
||
if (!timeObj) {
|
||
return false;
|
||
}
|
||
$.extend(this, timeObj);
|
||
return true;
|
||
}
|
||
},
|
||
|
||
/*
|
||
* Handle callback option after injecting timepicker
|
||
*/
|
||
_afterInject: function() {
|
||
var o = this.inst.settings;
|
||
if ($.isFunction(o.afterInject)) {
|
||
o.afterInject.call(this);
|
||
}
|
||
},
|
||
|
||
/*
|
||
* generate and inject html for timepicker into ui datepicker
|
||
*/
|
||
_injectTimePicker: function () {
|
||
var $dp = this.inst.dpDiv,
|
||
o = this.inst.settings,
|
||
tp_inst = this,
|
||
litem = '',
|
||
uitem = '',
|
||
show = null,
|
||
max = {},
|
||
gridSize = {},
|
||
size = null,
|
||
i = 0,
|
||
l = 0;
|
||
|
||
// Prevent displaying twice
|
||
if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
|
||
var noDisplay = ' ui_tpicker_unit_hide',
|
||
html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + (o.oneLine && o.controlType === 'select' ? ' ui-timepicker-oneLine' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
|
||
'<dd class="ui_tpicker_time '+ ((o.showTime) ? '' : noDisplay) + '"></dd>';
|
||
|
||
// Create the markup
|
||
for (i = 0, l = this.units.length; i < l; i++) {
|
||
litem = this.units[i];
|
||
uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
|
||
show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
|
||
|
||
// Added by Peter Medeiros:
|
||
// - Figure out what the hour/minute/second max should be based on the step values.
|
||
// - Example: if stepMinute is 15, then minMax is 45.
|
||
max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
|
||
gridSize[litem] = 0;
|
||
|
||
html += '<dt class="ui_tpicker_' + litem + '_label' + (show ? '' : noDisplay) + '">' + o[litem + 'Text'] + '</dt>' +
|
||
'<dd class="ui_tpicker_' + litem + (show ? '' : noDisplay) + '"><div class="ui_tpicker_' + litem + '_slider' + (show ? '' : noDisplay) + '"></div>';
|
||
|
||
if (show && o[litem + 'Grid'] > 0) {
|
||
html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
|
||
|
||
if (litem === 'hour') {
|
||
for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
|
||
gridSize[litem]++;
|
||
var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
|
||
html += '<td data-for="' + litem + '">' + tmph + '</td>';
|
||
}
|
||
}
|
||
else {
|
||
for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
|
||
gridSize[litem]++;
|
||
html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
|
||
}
|
||
}
|
||
|
||
html += '</tr></table></div>';
|
||
}
|
||
html += '</dd>';
|
||
}
|
||
|
||
// Timezone
|
||
var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
|
||
html += '<dt class="ui_tpicker_timezone_label' + (showTz ? '' : noDisplay) + '">' + o.timezoneText + '</dt>';
|
||
html += '<dd class="ui_tpicker_timezone' + (showTz ? '' : noDisplay) + '"></dd>';
|
||
|
||
// Create the elements from string
|
||
html += '</dl></div>';
|
||
var $tp = $(html);
|
||
|
||
// if we only want time picker...
|
||
if (o.timeOnly === true) {
|
||
$tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
|
||
$dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
|
||
}
|
||
|
||
// add sliders, adjust grids, add events
|
||
for (i = 0, l = tp_inst.units.length; i < l; i++) {
|
||
litem = tp_inst.units[i];
|
||
uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
|
||
show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
|
||
|
||
// add the slider
|
||
tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
|
||
|
||
// adjust the grid and add click event
|
||
if (show && o[litem + 'Grid'] > 0) {
|
||
size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
|
||
$tp.find('.ui_tpicker_' + litem + ' table').css({
|
||
width: size + "%",
|
||
marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
|
||
marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
|
||
borderCollapse: 'collapse'
|
||
}).find("td").click(function (e) {
|
||
var $t = $(this),
|
||
h = $t.html(),
|
||
n = parseInt(h.replace(/[^0-9]/g), 10),
|
||
ap = h.replace(/[^apm]/ig),
|
||
f = $t.data('for'); // loses scope, so we use data-for
|
||
|
||
if (f === 'hour') {
|
||
if (ap.indexOf('p') !== -1 && n < 12) {
|
||
n += 12;
|
||
}
|
||
else {
|
||
if (ap.indexOf('a') !== -1 && n === 12) {
|
||
n = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
|
||
|
||
tp_inst._onTimeChange();
|
||
tp_inst._onSelectHandler();
|
||
}).css({
|
||
cursor: 'pointer',
|
||
width: (100 / gridSize[litem]) + '%',
|
||
textAlign: 'center',
|
||
overflow: 'hidden'
|
||
});
|
||
} // end if grid > 0
|
||
} // end for loop
|
||
|
||
// Add timezone options
|
||
this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
|
||
$.fn.append.apply(this.timezone_select,
|
||
$.map(o.timezoneList, function (val, idx) {
|
||
return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
|
||
}));
|
||
if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
|
||
var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
|
||
if (local_timezone === this.timezone) {
|
||
selectLocalTimezone(tp_inst);
|
||
} else {
|
||
this.timezone_select.val(this.timezone);
|
||
}
|
||
} else {
|
||
if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
|
||
this.timezone_select.val(o.timezone);
|
||
} else {
|
||
selectLocalTimezone(tp_inst);
|
||
}
|
||
}
|
||
this.timezone_select.change(function () {
|
||
tp_inst._onTimeChange();
|
||
tp_inst._onSelectHandler();
|
||
tp_inst._afterInject();
|
||
});
|
||
// End timezone options
|
||
|
||
// inject timepicker into datepicker
|
||
var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
|
||
if ($buttonPanel.length) {
|
||
$buttonPanel.before($tp);
|
||
} else {
|
||
$dp.append($tp);
|
||
}
|
||
|
||
this.$timeObj = $tp.find('.ui_tpicker_time');
|
||
|
||
if (this.inst !== null) {
|
||
var timeDefined = this.timeDefined;
|
||
this._onTimeChange();
|
||
this.timeDefined = timeDefined;
|
||
}
|
||
|
||
// slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
|
||
if (this._defaults.addSliderAccess) {
|
||
var sliderAccessArgs = this._defaults.sliderAccessArgs,
|
||
rtl = this._defaults.isRTL;
|
||
sliderAccessArgs.isRTL = rtl;
|
||
|
||
setTimeout(function () { // fix for inline mode
|
||
if ($tp.find('.ui-slider-access').length === 0) {
|
||
$tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
|
||
|
||
// fix any grids since sliders are shorter
|
||
var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
|
||
if (sliderAccessWidth) {
|
||
$tp.find('table:visible').each(function () {
|
||
var $g = $(this),
|
||
oldWidth = $g.outerWidth(),
|
||
oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
|
||
newWidth = oldWidth - sliderAccessWidth,
|
||
newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
|
||
css = { width: newWidth, marginRight: 0, marginLeft: 0 };
|
||
css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
|
||
$g.css(css);
|
||
});
|
||
}
|
||
}
|
||
}, 10);
|
||
}
|
||
// end slideAccess integration
|
||
|
||
tp_inst._limitMinMaxDateTime(this.inst, true);
|
||
}
|
||
},
|
||
|
||
/*
|
||
* This function tries to limit the ability to go outside the
|
||
* min/max date range
|
||
*/
|
||
_limitMinMaxDateTime: function (dp_inst, adjustSliders) {
|
||
var o = this._defaults,
|
||
dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
|
||
|
||
if (!this._defaults.showTimepicker) {
|
||
return;
|
||
} // No time so nothing to check here
|
||
|
||
if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
|
||
var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
|
||
minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
|
||
|
||
if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
|
||
this.hourMinOriginal = o.hourMin;
|
||
this.minuteMinOriginal = o.minuteMin;
|
||
this.secondMinOriginal = o.secondMin;
|
||
this.millisecMinOriginal = o.millisecMin;
|
||
this.microsecMinOriginal = o.microsecMin;
|
||
}
|
||
|
||
if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
|
||
this._defaults.hourMin = minDateTime.getHours();
|
||
if (this.hour <= this._defaults.hourMin) {
|
||
this.hour = this._defaults.hourMin;
|
||
this._defaults.minuteMin = minDateTime.getMinutes();
|
||
if (this.minute <= this._defaults.minuteMin) {
|
||
this.minute = this._defaults.minuteMin;
|
||
this._defaults.secondMin = minDateTime.getSeconds();
|
||
if (this.second <= this._defaults.secondMin) {
|
||
this.second = this._defaults.secondMin;
|
||
this._defaults.millisecMin = minDateTime.getMilliseconds();
|
||
if (this.millisec <= this._defaults.millisecMin) {
|
||
this.millisec = this._defaults.millisecMin;
|
||
this._defaults.microsecMin = minDateTime.getMicroseconds();
|
||
} else {
|
||
if (this.microsec < this._defaults.microsecMin) {
|
||
this.microsec = this._defaults.microsecMin;
|
||
}
|
||
this._defaults.microsecMin = this.microsecMinOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.millisecMin = this.millisecMinOriginal;
|
||
this._defaults.microsecMin = this.microsecMinOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.secondMin = this.secondMinOriginal;
|
||
this._defaults.millisecMin = this.millisecMinOriginal;
|
||
this._defaults.microsecMin = this.microsecMinOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.minuteMin = this.minuteMinOriginal;
|
||
this._defaults.secondMin = this.secondMinOriginal;
|
||
this._defaults.millisecMin = this.millisecMinOriginal;
|
||
this._defaults.microsecMin = this.microsecMinOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.hourMin = this.hourMinOriginal;
|
||
this._defaults.minuteMin = this.minuteMinOriginal;
|
||
this._defaults.secondMin = this.secondMinOriginal;
|
||
this._defaults.millisecMin = this.millisecMinOriginal;
|
||
this._defaults.microsecMin = this.microsecMinOriginal;
|
||
}
|
||
}
|
||
|
||
if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
|
||
var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
|
||
maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
|
||
|
||
if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
|
||
this.hourMaxOriginal = o.hourMax;
|
||
this.minuteMaxOriginal = o.minuteMax;
|
||
this.secondMaxOriginal = o.secondMax;
|
||
this.millisecMaxOriginal = o.millisecMax;
|
||
this.microsecMaxOriginal = o.microsecMax;
|
||
}
|
||
|
||
if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
|
||
this._defaults.hourMax = maxDateTime.getHours();
|
||
if (this.hour >= this._defaults.hourMax) {
|
||
this.hour = this._defaults.hourMax;
|
||
this._defaults.minuteMax = maxDateTime.getMinutes();
|
||
if (this.minute >= this._defaults.minuteMax) {
|
||
this.minute = this._defaults.minuteMax;
|
||
this._defaults.secondMax = maxDateTime.getSeconds();
|
||
if (this.second >= this._defaults.secondMax) {
|
||
this.second = this._defaults.secondMax;
|
||
this._defaults.millisecMax = maxDateTime.getMilliseconds();
|
||
if (this.millisec >= this._defaults.millisecMax) {
|
||
this.millisec = this._defaults.millisecMax;
|
||
this._defaults.microsecMax = maxDateTime.getMicroseconds();
|
||
} else {
|
||
if (this.microsec > this._defaults.microsecMax) {
|
||
this.microsec = this._defaults.microsecMax;
|
||
}
|
||
this._defaults.microsecMax = this.microsecMaxOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.millisecMax = this.millisecMaxOriginal;
|
||
this._defaults.microsecMax = this.microsecMaxOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.secondMax = this.secondMaxOriginal;
|
||
this._defaults.millisecMax = this.millisecMaxOriginal;
|
||
this._defaults.microsecMax = this.microsecMaxOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.minuteMax = this.minuteMaxOriginal;
|
||
this._defaults.secondMax = this.secondMaxOriginal;
|
||
this._defaults.millisecMax = this.millisecMaxOriginal;
|
||
this._defaults.microsecMax = this.microsecMaxOriginal;
|
||
}
|
||
} else {
|
||
this._defaults.hourMax = this.hourMaxOriginal;
|
||
this._defaults.minuteMax = this.minuteMaxOriginal;
|
||
this._defaults.secondMax = this.secondMaxOriginal;
|
||
this._defaults.millisecMax = this.millisecMaxOriginal;
|
||
this._defaults.microsecMax = this.microsecMaxOriginal;
|
||
}
|
||
}
|
||
|
||
if (dp_inst.settings.minTime!==null) {
|
||
var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);
|
||
if (this.hour<tempMinTime.getHours()) {
|
||
this.hour=this._defaults.hourMin=tempMinTime.getHours();
|
||
this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
|
||
} else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {
|
||
this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
|
||
} else {
|
||
if (this._defaults.hourMin<tempMinTime.getHours()) {
|
||
this._defaults.hourMin=tempMinTime.getHours();
|
||
this._defaults.minuteMin=tempMinTime.getMinutes();
|
||
} else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {
|
||
this._defaults.minuteMin=tempMinTime.getMinutes();
|
||
} else {
|
||
this._defaults.minuteMin=0;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (dp_inst.settings.maxTime!==null) {
|
||
var tempMaxTime=new Date("01/01/1970 " + dp_inst.settings.maxTime);
|
||
if (this.hour>tempMaxTime.getHours()) {
|
||
this.hour=this._defaults.hourMax=tempMaxTime.getHours();
|
||
this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
|
||
} else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {
|
||
this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
|
||
} else {
|
||
if (this._defaults.hourMax>tempMaxTime.getHours()) {
|
||
this._defaults.hourMax=tempMaxTime.getHours();
|
||
this._defaults.minuteMax=tempMaxTime.getMinutes();
|
||
} else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
|
||
this._defaults.minuteMax=tempMaxTime.getMinutes();
|
||
} else {
|
||
this._defaults.minuteMax=59;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (adjustSliders !== undefined && adjustSliders === true) {
|
||
var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
|
||
minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
|
||
secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
|
||
millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
|
||
microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
|
||
|
||
if (this.hour_slider) {
|
||
this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
|
||
this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
|
||
}
|
||
if (this.minute_slider) {
|
||
this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
|
||
this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
|
||
}
|
||
if (this.second_slider) {
|
||
this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
|
||
this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
|
||
}
|
||
if (this.millisec_slider) {
|
||
this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
|
||
this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
|
||
}
|
||
if (this.microsec_slider) {
|
||
this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
|
||
this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
|
||
}
|
||
}
|
||
|
||
},
|
||
|
||
/*
|
||
* when a slider moves, set the internal time...
|
||
* on time change is also called when the time is updated in the text field
|
||
*/
|
||
_onTimeChange: function () {
|
||
if (!this._defaults.showTimepicker) {
|
||
return;
|
||
}
|
||
var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
|
||
minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
|
||
second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
|
||
millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
|
||
microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
|
||
timezone = (this.timezone_select) ? this.timezone_select.val() : false,
|
||
o = this._defaults,
|
||
pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
|
||
pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
|
||
|
||
if (typeof(hour) === 'object') {
|
||
hour = false;
|
||
}
|
||
if (typeof(minute) === 'object') {
|
||
minute = false;
|
||
}
|
||
if (typeof(second) === 'object') {
|
||
second = false;
|
||
}
|
||
if (typeof(millisec) === 'object') {
|
||
millisec = false;
|
||
}
|
||
if (typeof(microsec) === 'object') {
|
||
microsec = false;
|
||
}
|
||
if (typeof(timezone) === 'object') {
|
||
timezone = false;
|
||
}
|
||
|
||
if (hour !== false) {
|
||
hour = parseInt(hour, 10);
|
||
}
|
||
if (minute !== false) {
|
||
minute = parseInt(minute, 10);
|
||
}
|
||
if (second !== false) {
|
||
second = parseInt(second, 10);
|
||
}
|
||
if (millisec !== false) {
|
||
millisec = parseInt(millisec, 10);
|
||
}
|
||
if (microsec !== false) {
|
||
microsec = parseInt(microsec, 10);
|
||
}
|
||
if (timezone !== false) {
|
||
timezone = timezone.toString();
|
||
}
|
||
|
||
var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
|
||
|
||
// If the update was done in the input field, the input field should not be updated.
|
||
// If the update was done using the sliders, update the input field.
|
||
var hasChanged = (
|
||
hour !== parseInt(this.hour,10) || // sliders should all be numeric
|
||
minute !== parseInt(this.minute,10) ||
|
||
second !== parseInt(this.second,10) ||
|
||
millisec !== parseInt(this.millisec,10) ||
|
||
microsec !== parseInt(this.microsec,10) ||
|
||
(this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
|
||
(this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
|
||
);
|
||
|
||
if (hasChanged) {
|
||
|
||
if (hour !== false) {
|
||
this.hour = hour;
|
||
}
|
||
if (minute !== false) {
|
||
this.minute = minute;
|
||
}
|
||
if (second !== false) {
|
||
this.second = second;
|
||
}
|
||
if (millisec !== false) {
|
||
this.millisec = millisec;
|
||
}
|
||
if (microsec !== false) {
|
||
this.microsec = microsec;
|
||
}
|
||
if (timezone !== false) {
|
||
this.timezone = timezone;
|
||
}
|
||
|
||
if (!this.inst) {
|
||
this.inst = $.datepicker._getInst(this.$input[0]);
|
||
}
|
||
|
||
this._limitMinMaxDateTime(this.inst, true);
|
||
}
|
||
if (this.support.ampm) {
|
||
this.ampm = ampm;
|
||
}
|
||
|
||
// Updates the time within the timepicker
|
||
this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
|
||
if (this.$timeObj) {
|
||
if (pickerTimeFormat === o.timeFormat) {
|
||
this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
|
||
}
|
||
else {
|
||
this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
|
||
}
|
||
}
|
||
|
||
this.timeDefined = true;
|
||
if (hasChanged) {
|
||
this._updateDateTime();
|
||
//this.$input.focus(); // may automatically open the picker on setDate
|
||
}
|
||
},
|
||
|
||
/*
|
||
* call custom onSelect.
|
||
* bind to sliders slidestop, and grid click.
|
||
*/
|
||
_onSelectHandler: function () {
|
||
var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
|
||
var inputEl = this.$input ? this.$input[0] : null;
|
||
if (onSelect && inputEl) {
|
||
onSelect.apply(inputEl, [this.formattedDateTime, this]);
|
||
}
|
||
},
|
||
|
||
/*
|
||
* update our input with the new date time..
|
||
*/
|
||
_updateDateTime: function (dp_inst) {
|
||
dp_inst = this.inst || dp_inst;
|
||
var dtTmp = (dp_inst.currentYear > 0?
|
||
new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
|
||
new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
|
||
dt = $.datepicker._daylightSavingAdjust(dtTmp),
|
||
//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
|
||
//dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
|
||
dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
|
||
formatCfg = $.datepicker._getFormatConfig(dp_inst),
|
||
timeAvailable = dt !== null && this.timeDefined;
|
||
this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
|
||
var formattedDateTime = this.formattedDate;
|
||
|
||
// if a slider was changed but datepicker doesn't have a value yet, set it
|
||
if (dp_inst.lastVal === "") {
|
||
dp_inst.currentYear = dp_inst.selectedYear;
|
||
dp_inst.currentMonth = dp_inst.selectedMonth;
|
||
dp_inst.currentDay = dp_inst.selectedDay;
|
||
}
|
||
|
||
/*
|
||
* remove following lines to force every changes in date picker to change the input value
|
||
* Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
|
||
* If the user manually empty the value in the input field, the date picker will never change selected value.
|
||
*/
|
||
//if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
|
||
// return;
|
||
//}
|
||
|
||
if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
|
||
formattedDateTime = this.formattedTime;
|
||
} else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
|
||
formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
|
||
}
|
||
|
||
this.formattedDateTime = formattedDateTime;
|
||
|
||
if (!this._defaults.showTimepicker) {
|
||
this.$input.val(this.formattedDate);
|
||
} else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
|
||
this.$altInput.val(this.formattedTime);
|
||
this.$input.val(this.formattedDate);
|
||
} else if (this.$altInput) {
|
||
this.$input.val(formattedDateTime);
|
||
var altFormattedDateTime = '',
|
||
altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
|
||
altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
|
||
|
||
if (!this._defaults.timeOnly) {
|
||
if (this._defaults.altFormat) {
|
||
altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
|
||
}
|
||
else {
|
||
altFormattedDateTime = this.formattedDate;
|
||
}
|
||
|
||
if (altFormattedDateTime) {
|
||
altFormattedDateTime += altSeparator;
|
||
}
|
||
}
|
||
|
||
if (this._defaults.altTimeFormat !== null) {
|
||
altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
|
||
}
|
||
else {
|
||
altFormattedDateTime += this.formattedTime + altTimeSuffix;
|
||
}
|
||
this.$altInput.val(altFormattedDateTime);
|
||
} else {
|
||
this.$input.val(formattedDateTime);
|
||
}
|
||
|
||
this.$input.trigger("change");
|
||
},
|
||
|
||
_onFocus: function () {
|
||
if (!this.$input.val() && this._defaults.defaultValue) {
|
||
this.$input.val(this._defaults.defaultValue);
|
||
var inst = $.datepicker._getInst(this.$input.get(0)),
|
||
tp_inst = $.datepicker._get(inst, 'timepicker');
|
||
if (tp_inst) {
|
||
if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
|
||
try {
|
||
$.datepicker._updateDatepicker(inst);
|
||
} catch (err) {
|
||
$.timepicker.log(err);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
/*
|
||
* Small abstraction to control types
|
||
* We can add more, just be sure to follow the pattern: create, options, value
|
||
*/
|
||
_controls: {
|
||
// slider methods
|
||
slider: {
|
||
create: function (tp_inst, obj, unit, val, min, max, step) {
|
||
var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
|
||
return obj.prop('slide', null).slider({
|
||
orientation: "horizontal",
|
||
value: rtl ? val * -1 : val,
|
||
min: rtl ? max * -1 : min,
|
||
max: rtl ? min * -1 : max,
|
||
step: step,
|
||
slide: function (event, ui) {
|
||
tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
|
||
tp_inst._onTimeChange();
|
||
},
|
||
stop: function (event, ui) {
|
||
tp_inst._onSelectHandler();
|
||
}
|
||
});
|
||
},
|
||
options: function (tp_inst, obj, unit, opts, val) {
|
||
if (tp_inst._defaults.isRTL) {
|
||
if (typeof(opts) === 'string') {
|
||
if (opts === 'min' || opts === 'max') {
|
||
if (val !== undefined) {
|
||
return obj.slider(opts, val * -1);
|
||
}
|
||
return Math.abs(obj.slider(opts));
|
||
}
|
||
return obj.slider(opts);
|
||
}
|
||
var min = opts.min,
|
||
max = opts.max;
|
||
opts.min = opts.max = null;
|
||
if (min !== undefined) {
|
||
opts.max = min * -1;
|
||
}
|
||
if (max !== undefined) {
|
||
opts.min = max * -1;
|
||
}
|
||
return obj.slider(opts);
|
||
}
|
||
if (typeof(opts) === 'string' && val !== undefined) {
|
||
return obj.slider(opts, val);
|
||
}
|
||
return obj.slider(opts);
|
||
},
|
||
value: function (tp_inst, obj, unit, val) {
|
||
if (tp_inst._defaults.isRTL) {
|
||
if (val !== undefined) {
|
||
return obj.slider('value', val * -1);
|
||
}
|
||
return Math.abs(obj.slider('value'));
|
||
}
|
||
if (val !== undefined) {
|
||
return obj.slider('value', val);
|
||
}
|
||
return obj.slider('value');
|
||
}
|
||
},
|
||
// select methods
|
||
select: {
|
||
create: function (tp_inst, obj, unit, val, min, max, step) {
|
||
var sel = '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
|
||
format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
|
||
|
||
for (var i = min; i <= max; i += step) {
|
||
sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
|
||
if (unit === 'hour') {
|
||
sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
|
||
}
|
||
else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
|
||
else {sel += '0' + i.toString(); }
|
||
sel += '</option>';
|
||
}
|
||
sel += '</select>';
|
||
|
||
obj.children('select').remove();
|
||
|
||
$(sel).appendTo(obj).change(function (e) {
|
||
tp_inst._onTimeChange();
|
||
tp_inst._onSelectHandler();
|
||
tp_inst._afterInject();
|
||
});
|
||
|
||
return obj;
|
||
},
|
||
options: function (tp_inst, obj, unit, opts, val) {
|
||
var o = {},
|
||
$t = obj.children('select');
|
||
if (typeof(opts) === 'string') {
|
||
if (val === undefined) {
|
||
return $t.data(opts);
|
||
}
|
||
o[opts] = val;
|
||
}
|
||
else { o = opts; }
|
||
return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min>=0 ? o.min : $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
|
||
},
|
||
value: function (tp_inst, obj, unit, val) {
|
||
var $t = obj.children('select');
|
||
if (val !== undefined) {
|
||
return $t.val(val);
|
||
}
|
||
return $t.val();
|
||
}
|
||
}
|
||
} // end _controls
|
||
|
||
});
|
||
|
||
$.fn.extend({
|
||
/*
|
||
* shorthand just to use timepicker.
|
||
*/
|
||
timepicker: function (o) {
|
||
o = o || {};
|
||
var tmp_args = Array.prototype.slice.call(arguments);
|
||
|
||
if (typeof o === 'object') {
|
||
tmp_args[0] = $.extend(o, {
|
||
timeOnly: true
|
||
});
|
||
}
|
||
|
||
return $(this).each(function () {
|
||
$.fn.datetimepicker.apply($(this), tmp_args);
|
||
});
|
||
},
|
||
|
||
/*
|
||
* extend timepicker to datepicker
|
||
*/
|
||
datetimepicker: function (o) {
|
||
o = o || {};
|
||
var tmp_args = arguments;
|
||
|
||
if (typeof(o) === 'string') {
|
||
if (o === 'getDate' || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
|
||
return $.fn.datepicker.apply($(this[0]), tmp_args);
|
||
} else {
|
||
return this.each(function () {
|
||
var $t = $(this);
|
||
$t.datepicker.apply($t, tmp_args);
|
||
});
|
||
}
|
||
} else {
|
||
return this.each(function () {
|
||
var $t = $(this);
|
||
$t.datepicker($.timepicker._newInst($t, o)._defaults);
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
/*
|
||
* Public Utility to parse date and time
|
||
*/
|
||
$.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
|
||
var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
|
||
if (parseRes.timeObj) {
|
||
var t = parseRes.timeObj;
|
||
parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
|
||
parseRes.date.setMicroseconds(t.microsec);
|
||
}
|
||
|
||
return parseRes.date;
|
||
};
|
||
|
||
/*
|
||
* Public utility to parse time
|
||
*/
|
||
$.datepicker.parseTime = function (timeFormat, timeString, options) {
|
||
var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
|
||
iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
|
||
|
||
// Strict parse requires the timeString to match the timeFormat exactly
|
||
var strictParse = function (f, s, o) {
|
||
|
||
// pattern for standard and localized AM/PM markers
|
||
var getPatternAmpm = function (amNames, pmNames) {
|
||
var markers = [];
|
||
if (amNames) {
|
||
$.merge(markers, amNames);
|
||
}
|
||
if (pmNames) {
|
||
$.merge(markers, pmNames);
|
||
}
|
||
markers = $.map(markers, function (val) {
|
||
return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
|
||
});
|
||
return '(' + markers.join('|') + ')?';
|
||
};
|
||
|
||
// figure out position of time elements.. cause js cant do named captures
|
||
var getFormatPositions = function (timeFormat) {
|
||
var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
|
||
orders = {
|
||
h: -1,
|
||
m: -1,
|
||
s: -1,
|
||
l: -1,
|
||
c: -1,
|
||
t: -1,
|
||
z: -1
|
||
};
|
||
|
||
if (finds) {
|
||
for (var i = 0; i < finds.length; i++) {
|
||
if (orders[finds[i].toString().charAt(0)] === -1) {
|
||
orders[finds[i].toString().charAt(0)] = i + 1;
|
||
}
|
||
}
|
||
}
|
||
return orders;
|
||
};
|
||
|
||
var regstr = '^' + f.toString()
|
||
.replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
|
||
var ml = match.length;
|
||
switch (match.charAt(0).toLowerCase()) {
|
||
case 'h':
|
||
return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
|
||
case 'm':
|
||
return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
|
||
case 's':
|
||
return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
|
||
case 'l':
|
||
return '(\\d?\\d?\\d)';
|
||
case 'c':
|
||
return '(\\d?\\d?\\d)';
|
||
case 'z':
|
||
return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
|
||
case 't':
|
||
return getPatternAmpm(o.amNames, o.pmNames);
|
||
default: // literal escaped in quotes
|
||
return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
|
||
}
|
||
})
|
||
.replace(/\s/g, '\\s?') +
|
||
o.timeSuffix + '$',
|
||
order = getFormatPositions(f),
|
||
ampm = '',
|
||
treg;
|
||
|
||
treg = s.match(new RegExp(regstr, 'i'));
|
||
|
||
var resTime = {
|
||
hour: 0,
|
||
minute: 0,
|
||
second: 0,
|
||
millisec: 0,
|
||
microsec: 0
|
||
};
|
||
|
||
if (treg) {
|
||
if (order.t !== -1) {
|
||
if (treg[order.t] === undefined || treg[order.t].length === 0) {
|
||
ampm = '';
|
||
resTime.ampm = '';
|
||
} else {
|
||
ampm = $.inArray(treg[order.t].toUpperCase(), $.map(o.amNames, function (x,i) { return x.toUpperCase(); })) !== -1 ? 'AM' : 'PM';
|
||
resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
|
||
}
|
||
}
|
||
|
||
if (order.h !== -1) {
|
||
if (ampm === 'AM' && treg[order.h] === '12') {
|
||
resTime.hour = 0; // 12am = 0 hour
|
||
} else {
|
||
if (ampm === 'PM' && treg[order.h] !== '12') {
|
||
resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
|
||
} else {
|
||
resTime.hour = Number(treg[order.h]);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (order.m !== -1) {
|
||
resTime.minute = Number(treg[order.m]);
|
||
}
|
||
if (order.s !== -1) {
|
||
resTime.second = Number(treg[order.s]);
|
||
}
|
||
if (order.l !== -1) {
|
||
resTime.millisec = Number(treg[order.l]);
|
||
}
|
||
if (order.c !== -1) {
|
||
resTime.microsec = Number(treg[order.c]);
|
||
}
|
||
if (order.z !== -1 && treg[order.z] !== undefined) {
|
||
resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
|
||
}
|
||
|
||
|
||
return resTime;
|
||
}
|
||
return false;
|
||
};// end strictParse
|
||
|
||
// First try JS Date, if that fails, use strictParse
|
||
var looseParse = function (f, s, o) {
|
||
try {
|
||
var d = new Date('2012-01-01 ' + s);
|
||
if (isNaN(d.getTime())) {
|
||
d = new Date('2012-01-01T' + s);
|
||
if (isNaN(d.getTime())) {
|
||
d = new Date('01/01/2012 ' + s);
|
||
if (isNaN(d.getTime())) {
|
||
throw "Unable to parse time with native Date: " + s;
|
||
}
|
||
}
|
||
}
|
||
|
||
return {
|
||
hour: d.getHours(),
|
||
minute: d.getMinutes(),
|
||
second: d.getSeconds(),
|
||
millisec: d.getMilliseconds(),
|
||
microsec: d.getMicroseconds(),
|
||
timezone: d.getTimezoneOffset() * -1
|
||
};
|
||
}
|
||
catch (err) {
|
||
try {
|
||
return strictParse(f, s, o);
|
||
}
|
||
catch (err2) {
|
||
$.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
|
||
}
|
||
}
|
||
return false;
|
||
}; // end looseParse
|
||
|
||
if (typeof o.parse === "function") {
|
||
return o.parse(timeFormat, timeString, o);
|
||
}
|
||
if (o.parse === 'loose') {
|
||
return looseParse(timeFormat, timeString, o);
|
||
}
|
||
return strictParse(timeFormat, timeString, o);
|
||
};
|
||
|
||
/**
|
||
* Public utility to format the time
|
||
* @param {string} format format of the time
|
||
* @param {Object} time Object not a Date for timezones
|
||
* @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
|
||
* @returns {string} the formatted time
|
||
*/
|
||
$.datepicker.formatTime = function (format, time, options) {
|
||
options = options || {};
|
||
options = $.extend({}, $.timepicker._defaults, options);
|
||
time = $.extend({
|
||
hour: 0,
|
||
minute: 0,
|
||
second: 0,
|
||
millisec: 0,
|
||
microsec: 0,
|
||
timezone: null
|
||
}, time);
|
||
|
||
var tmptime = format,
|
||
ampmName = options.amNames[0],
|
||
hour = parseInt(time.hour, 10);
|
||
|
||
if (hour > 11) {
|
||
ampmName = options.pmNames[0];
|
||
}
|
||
|
||
tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
|
||
switch (match) {
|
||
case 'HH':
|
||
return ('0' + hour).slice(-2);
|
||
case 'H':
|
||
return hour;
|
||
case 'hh':
|
||
return ('0' + convert24to12(hour)).slice(-2);
|
||
case 'h':
|
||
return convert24to12(hour);
|
||
case 'mm':
|
||
return ('0' + time.minute).slice(-2);
|
||
case 'm':
|
||
return time.minute;
|
||
case 'ss':
|
||
return ('0' + time.second).slice(-2);
|
||
case 's':
|
||
return time.second;
|
||
case 'l':
|
||
return ('00' + time.millisec).slice(-3);
|
||
case 'c':
|
||
return ('00' + time.microsec).slice(-3);
|
||
case 'z':
|
||
return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
|
||
case 'Z':
|
||
return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
|
||
case 'T':
|
||
return ampmName.charAt(0).toUpperCase();
|
||
case 'TT':
|
||
return ampmName.toUpperCase();
|
||
case 't':
|
||
return ampmName.charAt(0).toLowerCase();
|
||
case 'tt':
|
||
return ampmName.toLowerCase();
|
||
default:
|
||
return match.replace(/'/g, "");
|
||
}
|
||
});
|
||
|
||
return tmptime;
|
||
};
|
||
|
||
/*
|
||
* the bad hack :/ override datepicker so it doesn't close on select
|
||
// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
|
||
*/
|
||
$.datepicker._base_selectDate = $.datepicker._selectDate;
|
||
$.datepicker._selectDate = function (id, dateStr) {
|
||
var inst = this._getInst($(id)[0]),
|
||
tp_inst = this._get(inst, 'timepicker'),
|
||
was_inline;
|
||
|
||
if (tp_inst && inst.settings.showTimepicker) {
|
||
tp_inst._limitMinMaxDateTime(inst, true);
|
||
was_inline = inst.inline;
|
||
inst.inline = inst.stay_open = true;
|
||
//This way the onSelect handler called from calendarpicker get the full dateTime
|
||
this._base_selectDate(id, dateStr);
|
||
inst.inline = was_inline;
|
||
inst.stay_open = false;
|
||
this._notifyChange(inst);
|
||
this._updateDatepicker(inst);
|
||
} else {
|
||
this._base_selectDate(id, dateStr);
|
||
}
|
||
};
|
||
|
||
/*
|
||
* second bad hack :/ override datepicker so it triggers an event when changing the input field
|
||
* and does not redraw the datepicker on every selectDate event
|
||
*/
|
||
$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
|
||
$.datepicker._updateDatepicker = function (inst) {
|
||
|
||
// don't popup the datepicker if there is another instance already opened
|
||
var input = inst.input[0];
|
||
if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
|
||
return;
|
||
}
|
||
|
||
if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
|
||
|
||
this._base_updateDatepicker(inst);
|
||
|
||
// Reload the time control when changing something in the input text field.
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
if (tp_inst) {
|
||
tp_inst._addTimePicker(inst);
|
||
}
|
||
}
|
||
};
|
||
|
||
/*
|
||
* third bad hack :/ override datepicker so it allows spaces and colon in the input field
|
||
*/
|
||
$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
|
||
$.datepicker._doKeyPress = function (event) {
|
||
var inst = $.datepicker._getInst(event.target),
|
||
tp_inst = $.datepicker._get(inst, 'timepicker');
|
||
|
||
if (tp_inst) {
|
||
if ($.datepicker._get(inst, 'constrainInput')) {
|
||
var ampm = tp_inst.support.ampm,
|
||
tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
|
||
dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
|
||
datetimeChars = tp_inst._defaults.timeFormat.toString()
|
||
.replace(/[hms]/g, '')
|
||
.replace(/TT/g, ampm ? 'APM' : '')
|
||
.replace(/Tt/g, ampm ? 'AaPpMm' : '')
|
||
.replace(/tT/g, ampm ? 'AaPpMm' : '')
|
||
.replace(/T/g, ampm ? 'AP' : '')
|
||
.replace(/tt/g, ampm ? 'apm' : '')
|
||
.replace(/t/g, ampm ? 'ap' : '') +
|
||
" " + tp_inst._defaults.separator +
|
||
tp_inst._defaults.timeSuffix +
|
||
(tz ? tp_inst._defaults.timezoneList.join('') : '') +
|
||
(tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
|
||
dateChars,
|
||
chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
|
||
return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
|
||
}
|
||
}
|
||
|
||
return $.datepicker._base_doKeyPress(event);
|
||
};
|
||
|
||
/*
|
||
* Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
|
||
* Update any alternate field to synchronise with the main field.
|
||
*/
|
||
$.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
|
||
$.datepicker._updateAlternate = function (inst) {
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
if (tp_inst) {
|
||
var altField = tp_inst._defaults.altField;
|
||
if (altField) { // update alternate field too
|
||
var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
|
||
date = this._getDate(inst),
|
||
formatCfg = $.datepicker._getFormatConfig(inst),
|
||
altFormattedDateTime = '',
|
||
altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
|
||
altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
|
||
altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
|
||
|
||
altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
|
||
if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
|
||
if (tp_inst._defaults.altFormat) {
|
||
altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
|
||
}
|
||
else {
|
||
altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
|
||
}
|
||
}
|
||
$(altField).val( inst.input.val() ? altFormattedDateTime : "");
|
||
}
|
||
}
|
||
else {
|
||
$.datepicker._base_updateAlternate(inst);
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Override key up event to sync manual input changes.
|
||
*/
|
||
$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
|
||
$.datepicker._doKeyUp = function (event) {
|
||
var inst = $.datepicker._getInst(event.target),
|
||
tp_inst = $.datepicker._get(inst, 'timepicker');
|
||
|
||
if (tp_inst) {
|
||
if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
|
||
try {
|
||
$.datepicker._updateDatepicker(inst);
|
||
} catch (err) {
|
||
$.timepicker.log(err);
|
||
}
|
||
}
|
||
}
|
||
|
||
return $.datepicker._base_doKeyUp(event);
|
||
};
|
||
|
||
/*
|
||
* override "Today" button to also grab the time.
|
||
*/
|
||
$.datepicker._base_gotoToday = $.datepicker._gotoToday;
|
||
$.datepicker._gotoToday = function (id) {
|
||
var inst = this._getInst($(id)[0]),
|
||
$dp = inst.dpDiv;
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
selectLocalTimezone(tp_inst);
|
||
var now = new Date();
|
||
this._setTime(inst, now);
|
||
this._setDate(inst, now);
|
||
this._base_gotoToday(id);
|
||
};
|
||
|
||
/*
|
||
* Disable & enable the Time in the datetimepicker
|
||
*/
|
||
$.datepicker._disableTimepickerDatepicker = function (target) {
|
||
var inst = this._getInst(target);
|
||
if (!inst) {
|
||
return;
|
||
}
|
||
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
|
||
if (tp_inst) {
|
||
inst.settings.showTimepicker = false;
|
||
tp_inst._defaults.showTimepicker = false;
|
||
tp_inst._updateDateTime(inst);
|
||
}
|
||
};
|
||
|
||
$.datepicker._enableTimepickerDatepicker = function (target) {
|
||
var inst = this._getInst(target);
|
||
if (!inst) {
|
||
return;
|
||
}
|
||
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
|
||
if (tp_inst) {
|
||
inst.settings.showTimepicker = true;
|
||
tp_inst._defaults.showTimepicker = true;
|
||
tp_inst._addTimePicker(inst); // Could be disabled on page load
|
||
tp_inst._updateDateTime(inst);
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Create our own set time function
|
||
*/
|
||
$.datepicker._setTime = function (inst, date) {
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
if (tp_inst) {
|
||
var defaults = tp_inst._defaults;
|
||
|
||
// calling _setTime with no date sets time to defaults
|
||
tp_inst.hour = date ? date.getHours() : defaults.hour;
|
||
tp_inst.minute = date ? date.getMinutes() : defaults.minute;
|
||
tp_inst.second = date ? date.getSeconds() : defaults.second;
|
||
tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
|
||
tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
|
||
|
||
//check if within min/max times..
|
||
tp_inst._limitMinMaxDateTime(inst, true);
|
||
|
||
tp_inst._onTimeChange();
|
||
tp_inst._updateDateTime(inst);
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Create new public method to set only time, callable as $().datepicker('setTime', date)
|
||
*/
|
||
$.datepicker._setTimeDatepicker = function (target, date, withDate) {
|
||
var inst = this._getInst(target);
|
||
if (!inst) {
|
||
return;
|
||
}
|
||
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
|
||
if (tp_inst) {
|
||
this._setDateFromField(inst);
|
||
var tp_date;
|
||
if (date) {
|
||
if (typeof date === "string") {
|
||
tp_inst._parseTime(date, withDate);
|
||
tp_date = new Date();
|
||
tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
|
||
tp_date.setMicroseconds(tp_inst.microsec);
|
||
} else {
|
||
tp_date = new Date(date.getTime());
|
||
tp_date.setMicroseconds(date.getMicroseconds());
|
||
}
|
||
if (tp_date.toString() === 'Invalid Date') {
|
||
tp_date = undefined;
|
||
}
|
||
this._setTime(inst, tp_date);
|
||
}
|
||
}
|
||
|
||
};
|
||
|
||
/*
|
||
* override setDate() to allow setting time too within Date object
|
||
*/
|
||
$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
|
||
$.datepicker._setDateDatepicker = function (target, _date) {
|
||
var inst = this._getInst(target);
|
||
var date = _date;
|
||
if (!inst) {
|
||
return;
|
||
}
|
||
|
||
if (typeof(_date) === 'string') {
|
||
date = new Date(_date);
|
||
if (!date.getTime()) {
|
||
this._base_setDateDatepicker.apply(this, arguments);
|
||
date = $(target).datepicker('getDate');
|
||
}
|
||
}
|
||
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
var tp_date;
|
||
if (date instanceof Date) {
|
||
tp_date = new Date(date.getTime());
|
||
tp_date.setMicroseconds(date.getMicroseconds());
|
||
} else {
|
||
tp_date = date;
|
||
}
|
||
|
||
// This is important if you are using the timezone option, javascript's Date
|
||
// object will only return the timezone offset for the current locale, so we
|
||
// adjust it accordingly. If not using timezone option this won't matter..
|
||
// If a timezone is different in tp, keep the timezone as is
|
||
if (tp_inst && tp_date) {
|
||
// look out for DST if tz wasn't specified
|
||
if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
|
||
tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
|
||
}
|
||
date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
|
||
tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
|
||
}
|
||
|
||
this._updateDatepicker(inst);
|
||
this._base_setDateDatepicker.apply(this, arguments);
|
||
this._setTimeDatepicker(target, tp_date, true);
|
||
};
|
||
|
||
/*
|
||
* override getDate() to allow getting time too within Date object
|
||
*/
|
||
$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
|
||
$.datepicker._getDateDatepicker = function (target, noDefault) {
|
||
var inst = this._getInst(target);
|
||
if (!inst) {
|
||
return;
|
||
}
|
||
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
|
||
if (tp_inst) {
|
||
// if it hasn't yet been defined, grab from field
|
||
if (inst.lastVal === undefined) {
|
||
this._setDateFromField(inst, noDefault);
|
||
}
|
||
|
||
var date = this._getDate(inst);
|
||
var currDT = $.trim((tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly) ? tp_inst.$input.val() + ' ' + tp_inst.$altInput.val() : tp_inst.$input.val());
|
||
if (date && tp_inst._parseTime(currDT, !inst.settings.timeOnly)) {
|
||
date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
|
||
date.setMicroseconds(tp_inst.microsec);
|
||
|
||
// This is important if you are using the timezone option, javascript's Date
|
||
// object will only return the timezone offset for the current locale, so we
|
||
// adjust it accordingly. If not using timezone option this won't matter..
|
||
if (tp_inst.timezone != null) {
|
||
// look out for DST if tz wasn't specified
|
||
if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
|
||
tp_inst.timezone = date.getTimezoneOffset() * -1;
|
||
}
|
||
date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
|
||
}
|
||
}
|
||
return date;
|
||
}
|
||
return this._base_getDateDatepicker(target, noDefault);
|
||
};
|
||
|
||
/*
|
||
* override parseDate() because UI 1.8.14 throws an error about "Extra characters"
|
||
* An option in datapicker to ignore extra format characters would be nicer.
|
||
*/
|
||
$.datepicker._base_parseDate = $.datepicker.parseDate;
|
||
$.datepicker.parseDate = function (format, value, settings) {
|
||
var date;
|
||
try {
|
||
date = this._base_parseDate(format, value, settings);
|
||
} catch (err) {
|
||
// Hack! The error message ends with a colon, a space, and
|
||
// the "extra" characters. We rely on that instead of
|
||
// attempting to perfectly reproduce the parsing algorithm.
|
||
if (err.indexOf(":") >= 0) {
|
||
date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
|
||
$.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
|
||
} else {
|
||
throw err;
|
||
}
|
||
}
|
||
return date;
|
||
};
|
||
|
||
/*
|
||
* override formatDate to set date with time to the input
|
||
*/
|
||
$.datepicker._base_formatDate = $.datepicker._formatDate;
|
||
$.datepicker._formatDate = function (inst, day, month, year) {
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
if (tp_inst) {
|
||
tp_inst._updateDateTime(inst);
|
||
return tp_inst.$input.val();
|
||
}
|
||
return this._base_formatDate(inst);
|
||
};
|
||
|
||
/*
|
||
* override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
|
||
*/
|
||
$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
|
||
$.datepicker._optionDatepicker = function (target, name, value) {
|
||
var inst = this._getInst(target),
|
||
name_clone;
|
||
if (!inst) {
|
||
return null;
|
||
}
|
||
|
||
var tp_inst = this._get(inst, 'timepicker');
|
||
if (tp_inst) {
|
||
var min = null,
|
||
max = null,
|
||
onselect = null,
|
||
overrides = tp_inst._defaults.evnts,
|
||
fns = {},
|
||
prop,
|
||
ret,
|
||
oldVal,
|
||
$target;
|
||
if (typeof name === 'string') { // if min/max was set with the string
|
||
if (name === 'minDate' || name === 'minDateTime') {
|
||
min = value;
|
||
} else if (name === 'maxDate' || name === 'maxDateTime') {
|
||
max = value;
|
||
} else if (name === 'onSelect') {
|
||
onselect = value;
|
||
} else if (overrides.hasOwnProperty(name)) {
|
||
if (typeof (value) === 'undefined') {
|
||
return overrides[name];
|
||
}
|
||
fns[name] = value;
|
||
name_clone = {}; //empty results in exiting function after overrides updated
|
||
}
|
||
} else if (typeof name === 'object') { //if min/max was set with the JSON
|
||
if (name.minDate) {
|
||
min = name.minDate;
|
||
} else if (name.minDateTime) {
|
||
min = name.minDateTime;
|
||
} else if (name.maxDate) {
|
||
max = name.maxDate;
|
||
} else if (name.maxDateTime) {
|
||
max = name.maxDateTime;
|
||
}
|
||
for (prop in overrides) {
|
||
if (overrides.hasOwnProperty(prop) && name[prop]) {
|
||
fns[prop] = name[prop];
|
||
}
|
||
}
|
||
}
|
||
for (prop in fns) {
|
||
if (fns.hasOwnProperty(prop)) {
|
||
overrides[prop] = fns[prop];
|
||
if (!name_clone) { name_clone = $.extend({}, name); }
|
||
delete name_clone[prop];
|
||
}
|
||
}
|
||
if (name_clone && isEmptyObject(name_clone)) { return; }
|
||
if (min) { //if min was set
|
||
if (min === 0) {
|
||
min = new Date();
|
||
} else {
|
||
min = new Date(min);
|
||
}
|
||
tp_inst._defaults.minDate = min;
|
||
tp_inst._defaults.minDateTime = min;
|
||
} else if (max) { //if max was set
|
||
if (max === 0) {
|
||
max = new Date();
|
||
} else {
|
||
max = new Date(max);
|
||
}
|
||
tp_inst._defaults.maxDate = max;
|
||
tp_inst._defaults.maxDateTime = max;
|
||
} else if (onselect) {
|
||
tp_inst._defaults.onSelect = onselect;
|
||
}
|
||
|
||
// Datepicker will override our date when we call _base_optionDatepicker when
|
||
// calling minDate/maxDate, so we will first grab the value, call
|
||
// _base_optionDatepicker, then set our value back.
|
||
if(min || max){
|
||
$target = $(target);
|
||
oldVal = $target.datetimepicker('getDate');
|
||
ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
|
||
$target.datetimepicker('setDate', oldVal);
|
||
return ret;
|
||
}
|
||
}
|
||
if (value === undefined) {
|
||
return this._base_optionDatepicker.call($.datepicker, target, name);
|
||
}
|
||
return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
|
||
};
|
||
|
||
/*
|
||
* jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
|
||
* it will return false for all objects
|
||
*/
|
||
var isEmptyObject = function (obj) {
|
||
var prop;
|
||
for (prop in obj) {
|
||
if (obj.hasOwnProperty(prop)) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
};
|
||
|
||
/*
|
||
* jQuery extend now ignores nulls!
|
||
*/
|
||
var extendRemove = function (target, props) {
|
||
$.extend(target, props);
|
||
for (var name in props) {
|
||
if (props[name] === null || props[name] === undefined) {
|
||
target[name] = props[name];
|
||
}
|
||
}
|
||
return target;
|
||
};
|
||
|
||
/*
|
||
* Determine by the time format which units are supported
|
||
* Returns an object of booleans for each unit
|
||
*/
|
||
var detectSupport = function (timeFormat) {
|
||
var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
|
||
isIn = function (f, t) { // does the format contain the token?
|
||
return f.indexOf(t) !== -1 ? true : false;
|
||
};
|
||
return {
|
||
hour: isIn(tf, 'h'),
|
||
minute: isIn(tf, 'm'),
|
||
second: isIn(tf, 's'),
|
||
millisec: isIn(tf, 'l'),
|
||
microsec: isIn(tf, 'c'),
|
||
timezone: isIn(tf, 'z'),
|
||
ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
|
||
iso8601: isIn(timeFormat, 'Z')
|
||
};
|
||
};
|
||
|
||
/*
|
||
* Converts 24 hour format into 12 hour
|
||
* Returns 12 hour without leading 0
|
||
*/
|
||
var convert24to12 = function (hour) {
|
||
hour %= 12;
|
||
|
||
if (hour === 0) {
|
||
hour = 12;
|
||
}
|
||
|
||
return String(hour);
|
||
};
|
||
|
||
var computeEffectiveSetting = function (settings, property) {
|
||
return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
|
||
};
|
||
|
||
/*
|
||
* Splits datetime string into date and time substrings.
|
||
* Throws exception when date can't be parsed
|
||
* Returns {dateString: dateString, timeString: timeString}
|
||
*/
|
||
var splitDateTime = function (dateTimeString, timeSettings) {
|
||
// The idea is to get the number separator occurrences in datetime and the time format requested (since time has
|
||
// fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
|
||
var separator = computeEffectiveSetting(timeSettings, 'separator'),
|
||
format = computeEffectiveSetting(timeSettings, 'timeFormat'),
|
||
timeParts = format.split(separator), // how many occurrences of separator may be in our format?
|
||
timePartsLen = timeParts.length,
|
||
allParts = dateTimeString.split(separator),
|
||
allPartsLen = allParts.length;
|
||
|
||
if (allPartsLen > 1) {
|
||
return {
|
||
dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
|
||
timeString: allParts.splice(0, timePartsLen).join(separator)
|
||
};
|
||
}
|
||
|
||
return {
|
||
dateString: dateTimeString,
|
||
timeString: ''
|
||
};
|
||
};
|
||
|
||
/*
|
||
* Internal function to parse datetime interval
|
||
* Returns: {date: Date, timeObj: Object}, where
|
||
* date - parsed date without time (type Date)
|
||
* timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
|
||
*/
|
||
var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
|
||
var date,
|
||
parts,
|
||
parsedTime;
|
||
|
||
parts = splitDateTime(dateTimeString, timeSettings);
|
||
date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
|
||
|
||
if (parts.timeString === '') {
|
||
return {
|
||
date: date
|
||
};
|
||
}
|
||
|
||
parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
|
||
|
||
if (!parsedTime) {
|
||
throw 'Wrong time format';
|
||
}
|
||
|
||
return {
|
||
date: date,
|
||
timeObj: parsedTime
|
||
};
|
||
};
|
||
|
||
/*
|
||
* Internal function to set timezone_select to the local timezone
|
||
*/
|
||
var selectLocalTimezone = function (tp_inst, date) {
|
||
if (tp_inst && tp_inst.timezone_select) {
|
||
var now = date || new Date();
|
||
tp_inst.timezone_select.val(-now.getTimezoneOffset());
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Create a Singleton Instance
|
||
*/
|
||
$.timepicker = new Timepicker();
|
||
|
||
/**
|
||
* Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
|
||
* @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
|
||
* @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
|
||
* @return {string}
|
||
*/
|
||
$.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
|
||
if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
|
||
return tzMinutes;
|
||
}
|
||
|
||
var off = tzMinutes,
|
||
minutes = off % 60,
|
||
hours = (off - minutes) / 60,
|
||
iso = iso8601 ? ':' : '',
|
||
tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
|
||
|
||
if (tz === '+00:00') {
|
||
return 'Z';
|
||
}
|
||
return tz;
|
||
};
|
||
|
||
/**
|
||
* Get the number in minutes that represents a timezone string
|
||
* @param {string} tzString formatted like "+0500", "-1245", "Z"
|
||
* @return {number} the offset minutes or the original string if it doesn't match expectations
|
||
*/
|
||
$.timepicker.timezoneOffsetNumber = function (tzString) {
|
||
var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
|
||
|
||
if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
|
||
return 0;
|
||
}
|
||
|
||
if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
|
||
return tzString;
|
||
}
|
||
|
||
return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
|
||
((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
|
||
parseInt(normalized.substr(3, 2), 10))); // minutes
|
||
};
|
||
|
||
/**
|
||
* No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
|
||
* @param {Date} date
|
||
* @param {string} toTimezone formatted like "+0500", "-1245"
|
||
* @return {Date}
|
||
*/
|
||
$.timepicker.timezoneAdjust = function (date, toTimezone) {
|
||
var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
|
||
if (!isNaN(toTz)) {
|
||
date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
|
||
}
|
||
return date;
|
||
};
|
||
|
||
/**
|
||
* Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
|
||
* enforce date range limits.
|
||
* n.b. The input value must be correctly formatted (reformatting is not supported)
|
||
* @param {Element} startTime
|
||
* @param {Element} endTime
|
||
* @param {Object} options Options for the timepicker() call
|
||
* @return {jQuery}
|
||
*/
|
||
$.timepicker.timeRange = function (startTime, endTime, options) {
|
||
return $.timepicker.handleRange('timepicker', startTime, endTime, options);
|
||
};
|
||
|
||
/**
|
||
* Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
|
||
* enforce date range limits.
|
||
* @param {Element} startTime
|
||
* @param {Element} endTime
|
||
* @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
|
||
* a boolean value that can be used to reformat the input values to the `dateFormat`.
|
||
* @param {string} method Can be used to specify the type of picker to be added
|
||
* @return {jQuery}
|
||
*/
|
||
$.timepicker.datetimeRange = function (startTime, endTime, options) {
|
||
$.timepicker.handleRange('datetimepicker', startTime, endTime, options);
|
||
};
|
||
|
||
/**
|
||
* Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
|
||
* enforce date range limits.
|
||
* @param {Element} startTime
|
||
* @param {Element} endTime
|
||
* @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
|
||
* a boolean value that can be used to reformat the input values to the `dateFormat`.
|
||
* @return {jQuery}
|
||
*/
|
||
$.timepicker.dateRange = function (startTime, endTime, options) {
|
||
$.timepicker.handleRange('datepicker', startTime, endTime, options);
|
||
};
|
||
|
||
/**
|
||
* Calls `method` on the `startTime` and `endTime` elements, and configures them to
|
||
* enforce date range limits.
|
||
* @param {string} method Can be used to specify the type of picker to be added
|
||
* @param {Element} startTime
|
||
* @param {Element} endTime
|
||
* @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
|
||
* a boolean value that can be used to reformat the input values to the `dateFormat`.
|
||
* @return {jQuery}
|
||
*/
|
||
$.timepicker.handleRange = function (method, startTime, endTime, options) {
|
||
options = $.extend({}, {
|
||
minInterval: 0, // min allowed interval in milliseconds
|
||
maxInterval: 0, // max allowed interval in milliseconds
|
||
start: {}, // options for start picker
|
||
end: {} // options for end picker
|
||
}, options);
|
||
|
||
// for the mean time this fixes an issue with calling getDate with timepicker()
|
||
var timeOnly = false;
|
||
if(method === 'timepicker'){
|
||
timeOnly = true;
|
||
method = 'datetimepicker';
|
||
}
|
||
|
||
function checkDates(changed, other) {
|
||
var startdt = startTime[method]('getDate'),
|
||
enddt = endTime[method]('getDate'),
|
||
changeddt = changed[method]('getDate');
|
||
|
||
if (startdt !== null) {
|
||
var minDate = new Date(startdt.getTime()),
|
||
maxDate = new Date(startdt.getTime());
|
||
|
||
minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
|
||
maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
|
||
|
||
if (options.minInterval > 0 && minDate > enddt) { // minInterval check
|
||
endTime[method]('setDate', minDate);
|
||
}
|
||
else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
|
||
endTime[method]('setDate', maxDate);
|
||
}
|
||
else if (startdt > enddt) {
|
||
other[method]('setDate', changeddt);
|
||
}
|
||
}
|
||
}
|
||
|
||
function selected(changed, other, option) {
|
||
if (!changed.val()) {
|
||
return;
|
||
}
|
||
var date = changed[method].call(changed, 'getDate');
|
||
if (date !== null && options.minInterval > 0) {
|
||
if (option === 'minDate') {
|
||
date.setMilliseconds(date.getMilliseconds() + options.minInterval);
|
||
}
|
||
if (option === 'maxDate') {
|
||
date.setMilliseconds(date.getMilliseconds() - options.minInterval);
|
||
}
|
||
}
|
||
|
||
if (date.getTime) {
|
||
other[method].call(other, 'option', option, date);
|
||
}
|
||
}
|
||
|
||
$.fn[method].call(startTime, $.extend({
|
||
timeOnly: timeOnly,
|
||
onClose: function (dateText, inst) {
|
||
checkDates($(this), endTime);
|
||
},
|
||
onSelect: function (selectedDateTime) {
|
||
selected($(this), endTime, 'minDate');
|
||
}
|
||
}, options, options.start));
|
||
$.fn[method].call(endTime, $.extend({
|
||
timeOnly: timeOnly,
|
||
onClose: function (dateText, inst) {
|
||
checkDates($(this), startTime);
|
||
},
|
||
onSelect: function (selectedDateTime) {
|
||
selected($(this), startTime, 'maxDate');
|
||
}
|
||
}, options, options.end));
|
||
|
||
checkDates(startTime, endTime);
|
||
|
||
selected(startTime, endTime, 'minDate');
|
||
selected(endTime, startTime, 'maxDate');
|
||
|
||
return $([startTime.get(0), endTime.get(0)]);
|
||
};
|
||
|
||
/**
|
||
* Log error or data to the console during error or debugging
|
||
* @param {Object} err pass any type object to log to the console during error or debugging
|
||
* @return {void}
|
||
*/
|
||
$.timepicker.log = function () {
|
||
if (window.console) {
|
||
window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Add util object to allow access to private methods for testability.
|
||
*/
|
||
$.timepicker._util = {
|
||
_extendRemove: extendRemove,
|
||
_isEmptyObject: isEmptyObject,
|
||
_convert24to12: convert24to12,
|
||
_detectSupport: detectSupport,
|
||
_selectLocalTimezone: selectLocalTimezone,
|
||
_computeEffectiveSetting: computeEffectiveSetting,
|
||
_splitDateTime: splitDateTime,
|
||
_parseDateTimeInternal: parseDateTimeInternal
|
||
};
|
||
|
||
/*
|
||
* Microsecond support
|
||
*/
|
||
if (!Date.prototype.getMicroseconds) {
|
||
Date.prototype.microseconds = 0;
|
||
Date.prototype.getMicroseconds = function () { return this.microseconds; };
|
||
Date.prototype.setMicroseconds = function (m) {
|
||
this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
|
||
this.microseconds = m % 1000;
|
||
return this;
|
||
};
|
||
}
|
||
|
||
/*
|
||
* Keep up with the version
|
||
*/
|
||
$.timepicker.version = "1.5.3";
|
||
|
||
}));
|
||
;/**
|
||
* Ajax Queue Plugin
|
||
*
|
||
* Homepage: http://jquery.com/plugins/project/ajaxqueue
|
||
* Documentation: http://docs.jquery.com/AjaxQueue
|
||
*/
|
||
|
||
/**
|
||
|
||
<script>
|
||
$(function(){
|
||
jQuery.ajaxQueue({
|
||
url: "test.php",
|
||
success: function(html){ jQuery("ul").append(html); }
|
||
});
|
||
jQuery.ajaxQueue({
|
||
url: "test.php",
|
||
success: function(html){ jQuery("ul").append(html); }
|
||
});
|
||
jQuery.ajaxSync({
|
||
url: "test.php",
|
||
success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
|
||
});
|
||
jQuery.ajaxSync({
|
||
url: "test.php",
|
||
success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
|
||
});
|
||
});
|
||
</script>
|
||
<ul style="position: absolute; top: 5px; right: 5px;"></ul>
|
||
|
||
*/
|
||
/*
|
||
* Queued Ajax requests.
|
||
* A new Ajax request won't be started until the previous queued
|
||
* request has finished.
|
||
*/
|
||
|
||
/*
|
||
* Synced Ajax requests.
|
||
* The Ajax request will happen as soon as you call this method, but
|
||
* the callbacks (success/error/complete) won't fire until all previous
|
||
* synced requests have been completed.
|
||
*/
|
||
|
||
|
||
(function($) {
|
||
|
||
var ajax = $.ajax;
|
||
|
||
var pendingRequests = {};
|
||
|
||
var synced = [];
|
||
var syncedData = [];
|
||
|
||
$.ajax = function(settings) {
|
||
// create settings for compatibility with ajaxSetup
|
||
settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));
|
||
|
||
var port = settings.port;
|
||
|
||
switch(settings.mode) {
|
||
case "abort":
|
||
if ( pendingRequests[port] ) {
|
||
pendingRequests[port].abort();
|
||
}
|
||
return pendingRequests[port] = ajax.apply(this, arguments);
|
||
case "queue":
|
||
var _old = settings.complete;
|
||
settings.complete = function(){
|
||
if ( _old )
|
||
_old.apply( this, arguments );
|
||
jQuery([ajax]).dequeue("ajax" + port );;
|
||
};
|
||
|
||
jQuery([ ajax ]).queue("ajax" + port, function(){
|
||
ajax( settings );
|
||
});
|
||
return;
|
||
case "sync":
|
||
var pos = synced.length;
|
||
|
||
synced[ pos ] = {
|
||
error: settings.error,
|
||
success: settings.success,
|
||
complete: settings.complete,
|
||
done: false
|
||
};
|
||
|
||
syncedData[ pos ] = {
|
||
error: [],
|
||
success: [],
|
||
complete: []
|
||
};
|
||
|
||
settings.error = function(){ syncedData[ pos ].error = arguments; };
|
||
settings.success = function(){ syncedData[ pos ].success = arguments; };
|
||
settings.complete = function(){
|
||
syncedData[ pos ].complete = arguments;
|
||
synced[ pos ].done = true;
|
||
|
||
if ( pos == 0 || !synced[ pos-1 ] )
|
||
for ( var i = pos; i < synced.length && synced[i].done; i++ ) {
|
||
if ( synced[i].error ) synced[i].error.apply( jQuery, syncedData[i].error );
|
||
if ( synced[i].success ) synced[i].success.apply( jQuery, syncedData[i].success );
|
||
if ( synced[i].complete ) synced[i].complete.apply( jQuery, syncedData[i].complete );
|
||
|
||
synced[i] = null;
|
||
syncedData[i] = null;
|
||
}
|
||
};
|
||
}
|
||
return ajax.apply(this, arguments);
|
||
};
|
||
|
||
})(jQuery);;/*
|
||
* Autocomplete - jQuery plugin 1.0.2
|
||
*
|
||
* Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, 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
|
||
*
|
||
* Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
|
||
*
|
||
*/
|
||
|
||
;(function($) {
|
||
|
||
$.fn.extend({
|
||
autocomplete: function(urlOrData, options) {
|
||
var isUrl = typeof urlOrData == "string";
|
||
options = $.extend({}, $.Autocompleter.defaults, {
|
||
url: isUrl ? urlOrData : null,
|
||
data: isUrl ? null : urlOrData,
|
||
delay: isUrl ? $.Autocompleter.defaults.delay : 10,
|
||
max: options && !options.scroll ? 10 : 150
|
||
}, options);
|
||
|
||
// if highlight is set to false, replace it with a do-nothing function
|
||
options.highlight = options.highlight || function(value) { return value; };
|
||
|
||
// if the formatMatch option is not specified, then use formatItem for backwards compatibility
|
||
options.formatMatch = options.formatMatch || options.formatItem;
|
||
|
||
return this.each(function() {
|
||
new $.Autocompleter(this, options);
|
||
});
|
||
},
|
||
result: function(handler) {
|
||
return this.bind("result", handler);
|
||
},
|
||
search: function(handler) {
|
||
return this.trigger("search", [handler]);
|
||
},
|
||
flushCache: function() {
|
||
return this.trigger("flushCache");
|
||
},
|
||
setOptions: function(options){
|
||
return this.trigger("setOptions", [options]);
|
||
},
|
||
unautocomplete: function() {
|
||
return this.trigger("unautocomplete");
|
||
}
|
||
});
|
||
|
||
$.Autocompleter = function(input, options) {
|
||
|
||
var KEY = {
|
||
UP: 38,
|
||
DOWN: 40,
|
||
DEL: 46,
|
||
TAB: 9,
|
||
RETURN: 13,
|
||
ESC: 27,
|
||
COMMA: 188,
|
||
PAGEUP: 33,
|
||
PAGEDOWN: 34,
|
||
BACKSPACE: 8
|
||
};
|
||
|
||
// Create $ object for input element
|
||
var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
|
||
|
||
var timeout;
|
||
var previousValue = "";
|
||
var cache = $.Autocompleter.Cache(options);
|
||
var hasFocus = 0;
|
||
var lastKeyPressCode;
|
||
var config = {
|
||
mouseDownOnSelect: false
|
||
};
|
||
var select = $.Autocompleter.Select(options, input, selectCurrent, config);
|
||
|
||
var blockSubmit;
|
||
|
||
// prevent form submit in opera when selecting with return key
|
||
$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
|
||
if (blockSubmit) {
|
||
blockSubmit = false;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
|
||
$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
|
||
// track last key pressed
|
||
lastKeyPressCode = event.keyCode;
|
||
switch(event.keyCode) {
|
||
|
||
case KEY.UP:
|
||
event.preventDefault();
|
||
if ( select.visible() ) {
|
||
select.prev();
|
||
} else {
|
||
onChange(0, true);
|
||
}
|
||
break;
|
||
|
||
case KEY.DOWN:
|
||
event.preventDefault();
|
||
if ( select.visible() ) {
|
||
select.next();
|
||
} else {
|
||
onChange(0, true);
|
||
}
|
||
break;
|
||
|
||
case KEY.PAGEUP:
|
||
event.preventDefault();
|
||
if ( select.visible() ) {
|
||
select.pageUp();
|
||
} else {
|
||
onChange(0, true);
|
||
}
|
||
break;
|
||
|
||
case KEY.PAGEDOWN:
|
||
event.preventDefault();
|
||
if ( select.visible() ) {
|
||
select.pageDown();
|
||
} else {
|
||
onChange(0, true);
|
||
}
|
||
break;
|
||
|
||
// matches also semicolon
|
||
case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
|
||
case KEY.TAB:
|
||
case KEY.RETURN:
|
||
if( selectCurrent() ) {
|
||
// stop default to prevent a form submit, Opera needs special handling
|
||
event.preventDefault();
|
||
blockSubmit = true;
|
||
return false;
|
||
}
|
||
break;
|
||
|
||
case KEY.ESC:
|
||
select.hide();
|
||
break;
|
||
|
||
default:
|
||
clearTimeout(timeout);
|
||
timeout = setTimeout(onChange, options.delay);
|
||
break;
|
||
}
|
||
}).focus(function(){
|
||
// track whether the field has focus, we shouldn't process any
|
||
// results if the field no longer has focus
|
||
hasFocus++;
|
||
}).blur(function() {
|
||
hasFocus = 0;
|
||
if (!config.mouseDownOnSelect) {
|
||
hideResults();
|
||
}
|
||
}).click(function() {
|
||
// show select when clicking in a focused field
|
||
if ( hasFocus++ > 1 && !select.visible() ) {
|
||
onChange(0, true);
|
||
}
|
||
}).bind("search", function() {
|
||
// TODO why not just specifying both arguments?
|
||
var fn = (arguments.length > 1) ? arguments[1] : null;
|
||
function findValueCallback(q, data) {
|
||
var result;
|
||
if( data && data.length ) {
|
||
for (var i=0; i < data.length; i++) {
|
||
if( data[i].result.toLowerCase() == q.toLowerCase() ) {
|
||
result = data[i];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if( typeof fn == "function" ) fn(result);
|
||
else $input.trigger("result", result && [result.data, result.value]);
|
||
}
|
||
$.each(trimWords($input.val()), function(i, value) {
|
||
request(value, findValueCallback, findValueCallback);
|
||
});
|
||
}).bind("flushCache", function() {
|
||
cache.flush();
|
||
}).bind("setOptions", function() {
|
||
$.extend(options, arguments[1]);
|
||
// if we've updated the data, repopulate
|
||
if ( "data" in arguments[1] )
|
||
cache.populate();
|
||
}).bind("unautocomplete", function() {
|
||
select.unbind();
|
||
$input.unbind();
|
||
$(input.form).unbind(".autocomplete");
|
||
});
|
||
|
||
|
||
function selectCurrent() {
|
||
var selected = select.selected();
|
||
if( !selected )
|
||
return false;
|
||
|
||
var v = selected.result;
|
||
previousValue = v;
|
||
|
||
if ( options.multiple ) {
|
||
var words = trimWords($input.val());
|
||
if ( words.length > 1 ) {
|
||
v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
|
||
}
|
||
v += options.multipleSeparator;
|
||
}
|
||
|
||
$input.val(v);
|
||
hideResultsNow();
|
||
$input.trigger("result", [selected.data, selected.value]);
|
||
return true;
|
||
}
|
||
|
||
function onChange(crap, skipPrevCheck) {
|
||
if( lastKeyPressCode == KEY.DEL ) {
|
||
select.hide();
|
||
return;
|
||
}
|
||
|
||
var currentValue = $input.val();
|
||
|
||
if ( !skipPrevCheck && currentValue == previousValue )
|
||
return;
|
||
|
||
previousValue = currentValue;
|
||
|
||
currentValue = lastWord(currentValue);
|
||
if ( currentValue.length >= options.minChars) {
|
||
$input.addClass(options.loadingClass);
|
||
if (!options.matchCase)
|
||
currentValue = currentValue.toLowerCase();
|
||
request(currentValue, receiveData, hideResultsNow);
|
||
} else {
|
||
stopLoading();
|
||
select.hide();
|
||
}
|
||
};
|
||
|
||
function trimWords(value) {
|
||
if ( !value ) {
|
||
return [""];
|
||
}
|
||
var words = value.split( options.multipleSeparator );
|
||
var result = [];
|
||
$.each(words, function(i, value) {
|
||
if ( $.trim(value) )
|
||
result[i] = $.trim(value);
|
||
});
|
||
return result;
|
||
}
|
||
|
||
function lastWord(value) {
|
||
if ( !options.multiple )
|
||
return value;
|
||
var words = trimWords(value);
|
||
return words[words.length - 1];
|
||
}
|
||
|
||
// fills in the input box w/the first match (assumed to be the best match)
|
||
// q: the term entered
|
||
// sValue: the first matching result
|
||
function autoFill(q, sValue){
|
||
// autofill in the complete box w/the first match as long as the user hasn't entered in more data
|
||
// if the last user key pressed was backspace, don't autofill
|
||
if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
|
||
// fill in the value (keep the case the user has typed)
|
||
$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
|
||
// select the portion of the value not typed by the user (so the next character will erase)
|
||
$.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
|
||
}
|
||
};
|
||
|
||
function hideResults() {
|
||
clearTimeout(timeout);
|
||
timeout = setTimeout(hideResultsNow, 200);
|
||
};
|
||
|
||
function hideResultsNow() {
|
||
var wasVisible = select.visible();
|
||
select.hide();
|
||
clearTimeout(timeout);
|
||
stopLoading();
|
||
if (options.mustMatch) {
|
||
// call search and run callback
|
||
$input.search(
|
||
function (result){
|
||
// if no value found, clear the input box
|
||
if( !result ) {
|
||
if (options.multiple) {
|
||
var words = trimWords($input.val()).slice(0, -1);
|
||
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
|
||
}
|
||
else
|
||
$input.val( "" );
|
||
}
|
||
}
|
||
);
|
||
}
|
||
if (wasVisible)
|
||
// position cursor at end of input field
|
||
$.Autocompleter.Selection(input, input.value.length, input.value.length);
|
||
};
|
||
|
||
function receiveData(q, data) {
|
||
if ( data && data.length && hasFocus ) {
|
||
stopLoading();
|
||
select.display(data, q);
|
||
autoFill(q, data[0].value);
|
||
select.show();
|
||
} else {
|
||
hideResultsNow();
|
||
}
|
||
};
|
||
|
||
function request(term, success, failure) {
|
||
if (!options.matchCase)
|
||
term = term.toLowerCase();
|
||
var data = cache.load(term);
|
||
// recieve the cached data
|
||
if (data && data.length) {
|
||
success(term, data);
|
||
// if an AJAX url has been supplied, try loading the data now
|
||
} else if( (typeof options.url == "string") && (options.url.length > 0) ){
|
||
|
||
var extraParams = {
|
||
timestamp: +new Date()
|
||
};
|
||
$.each(options.extraParams, function(key, param) {
|
||
extraParams[key] = typeof param == "function" ? param() : param;
|
||
});
|
||
|
||
// don't add q parameter (won't work for nomantim)
|
||
var data = typeof options.extraParams == "function" ?
|
||
$.extend({}, options.extraParams()) : $.extend({
|
||
q: lastWord(term),
|
||
limit: options.max
|
||
}, extraParams);
|
||
|
||
$.ajax({
|
||
// try to leverage ajaxQueue plugin to abort previous requests
|
||
mode: "abort",
|
||
// limit abortion to this input
|
||
port: "autocomplete" + input.name,
|
||
dataType: options.dataType,
|
||
url: options.url,
|
||
type: options.type || "POST",
|
||
data: data,
|
||
success: function(data) {
|
||
var parsed = options.parse && options.parse(data) || parse(data);
|
||
cache.add(term, parsed);
|
||
success(term, parsed);
|
||
}
|
||
});
|
||
} else {
|
||
// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
|
||
select.emptyList();
|
||
failure(term);
|
||
}
|
||
};
|
||
|
||
function parse(data) {
|
||
var parsed = [];
|
||
var rows = data.split("\n");
|
||
for (var i=0; i < rows.length; i++) {
|
||
var row = $.trim(rows[i]);
|
||
if (row) {
|
||
row = row.split("|");
|
||
parsed[parsed.length] = {
|
||
data: row,
|
||
value: row[0],
|
||
result: options.formatResult && options.formatResult(row, row[0]) || row[0]
|
||
};
|
||
}
|
||
}
|
||
return parsed;
|
||
};
|
||
|
||
function stopLoading() {
|
||
$input.removeClass(options.loadingClass);
|
||
};
|
||
|
||
};
|
||
|
||
$.Autocompleter.defaults = {
|
||
inputClass: "ac_input",
|
||
resultsClass: "ac_results",
|
||
loadingClass: "ac_loading",
|
||
minChars: 1,
|
||
delay: 400,
|
||
matchCase: false,
|
||
matchSubset: true,
|
||
matchContains: false,
|
||
cacheLength: 10,
|
||
max: 100,
|
||
mustMatch: false,
|
||
extraParams: {},
|
||
selectFirst: true,
|
||
formatItem: function(row) { return row[0]; },
|
||
formatMatch: null,
|
||
autoFill: false,
|
||
width: 0,
|
||
multiple: false,
|
||
multipleSeparator: ", ",
|
||
highlight: function(value, term) {
|
||
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
|
||
},
|
||
scroll: true,
|
||
scrollHeight: 180
|
||
};
|
||
|
||
$.Autocompleter.Cache = function(options) {
|
||
|
||
var data = {};
|
||
var length = 0;
|
||
|
||
function matchSubset(s, sub) {
|
||
if (!options.matchCase)
|
||
s = s.toLowerCase();
|
||
var i = s.indexOf(sub);
|
||
if (i == -1) return false;
|
||
return i == 0 || options.matchContains;
|
||
};
|
||
|
||
function add(q, value) {
|
||
if (length > options.cacheLength){
|
||
flush();
|
||
}
|
||
if (!data[q]){
|
||
length++;
|
||
}
|
||
data[q] = value;
|
||
}
|
||
|
||
function populate(){
|
||
if( !options.data ) return false;
|
||
// track the matches
|
||
var stMatchSets = {},
|
||
nullData = 0;
|
||
|
||
// no url was specified, we need to adjust the cache length to make sure it fits the local data store
|
||
if( !options.url ) options.cacheLength = 1;
|
||
|
||
// track all options for minChars = 0
|
||
stMatchSets[""] = [];
|
||
|
||
// loop through the array and create a lookup structure
|
||
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
|
||
var rawValue = options.data[i];
|
||
// if rawValue is a string, make an array otherwise just reference the array
|
||
rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
|
||
|
||
var value = options.formatMatch(rawValue, i+1, options.data.length);
|
||
if ( value === false )
|
||
continue;
|
||
|
||
var firstChar = value.charAt(0).toLowerCase();
|
||
// if no lookup array for this character exists, look it up now
|
||
if( !stMatchSets[firstChar] )
|
||
stMatchSets[firstChar] = [];
|
||
|
||
// if the match is a string
|
||
var row = {
|
||
value: value,
|
||
data: rawValue,
|
||
result: options.formatResult && options.formatResult(rawValue) || value
|
||
};
|
||
|
||
// push the current match into the set list
|
||
stMatchSets[firstChar].push(row);
|
||
|
||
// keep track of minChars zero items
|
||
if ( nullData++ < options.max ) {
|
||
stMatchSets[""].push(row);
|
||
}
|
||
};
|
||
|
||
// add the data items to the cache
|
||
$.each(stMatchSets, function(i, value) {
|
||
// increase the cache size
|
||
options.cacheLength++;
|
||
// add to the cache
|
||
add(i, value);
|
||
});
|
||
}
|
||
|
||
// populate any existing data
|
||
setTimeout(populate, 25);
|
||
|
||
function flush(){
|
||
data = {};
|
||
length = 0;
|
||
}
|
||
|
||
return {
|
||
flush: flush,
|
||
add: add,
|
||
populate: populate,
|
||
load: function(q) {
|
||
if (!options.cacheLength || !length)
|
||
return null;
|
||
/*
|
||
* if dealing w/local data and matchContains than we must make sure
|
||
* to loop through all the data collections looking for matches
|
||
*/
|
||
if( !options.url && options.matchContains ){
|
||
// track all matches
|
||
var csub = [];
|
||
// loop through all the data grids for matches
|
||
for( var k in data ){
|
||
// don't search through the stMatchSets[""] (minChars: 0) cache
|
||
// this prevents duplicates
|
||
if( k.length > 0 ){
|
||
var c = data[k];
|
||
$.each(c, function(i, x) {
|
||
// if we've got a match, add it to the array
|
||
if (matchSubset(x.value, q)) {
|
||
csub.push(x);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
return csub;
|
||
} else
|
||
// if the exact item exists, use it
|
||
if (data[q]){
|
||
return data[q];
|
||
} else
|
||
if (options.matchSubset) {
|
||
for (var i = q.length - 1; i >= options.minChars; i--) {
|
||
var c = data[q.substr(0, i)];
|
||
if (c) {
|
||
var csub = [];
|
||
$.each(c, function(i, x) {
|
||
if (matchSubset(x.value, q)) {
|
||
csub[csub.length] = x;
|
||
}
|
||
});
|
||
return csub;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
};
|
||
};
|
||
|
||
$.Autocompleter.Select = function (options, input, select, config) {
|
||
var CLASSES = {
|
||
ACTIVE: "ac_over"
|
||
};
|
||
|
||
var listItems,
|
||
active = -1,
|
||
data,
|
||
term = "",
|
||
needsInit = true,
|
||
element,
|
||
list;
|
||
|
||
// Create results
|
||
function init() {
|
||
if (!needsInit)
|
||
return;
|
||
element = $("<div/>")
|
||
.hide()
|
||
.addClass(options.resultsClass)
|
||
.css("position", "absolute")
|
||
.appendTo(document.body);
|
||
|
||
list = $("<ul/>").appendTo(element).mouseover( function(event) {
|
||
if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
|
||
active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
|
||
$(target(event)).addClass(CLASSES.ACTIVE);
|
||
}
|
||
}).click(function(event) {
|
||
$(target(event)).addClass(CLASSES.ACTIVE);
|
||
select();
|
||
// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
|
||
input.focus();
|
||
return false;
|
||
}).mousedown(function() {
|
||
config.mouseDownOnSelect = true;
|
||
}).mouseup(function() {
|
||
config.mouseDownOnSelect = false;
|
||
});
|
||
|
||
if( options.width > 0 )
|
||
element.css("width", options.width);
|
||
|
||
needsInit = false;
|
||
}
|
||
|
||
function target(event) {
|
||
var element = event.target;
|
||
while(element && element.tagName != "LI")
|
||
element = element.parentNode;
|
||
// more fun with IE, sometimes event.target is empty, just ignore it then
|
||
if(!element)
|
||
return [];
|
||
return element;
|
||
}
|
||
|
||
function moveSelect(step) {
|
||
listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
|
||
movePosition(step);
|
||
var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
|
||
if(options.scroll) {
|
||
var offset = 0;
|
||
listItems.slice(0, active).each(function() {
|
||
offset += this.offsetHeight;
|
||
});
|
||
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
|
||
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
|
||
} else if(offset < list.scrollTop()) {
|
||
list.scrollTop(offset);
|
||
}
|
||
}
|
||
};
|
||
|
||
function movePosition(step) {
|
||
active += step;
|
||
if (active < 0) {
|
||
active = listItems.size() - 1;
|
||
} else if (active >= listItems.size()) {
|
||
active = 0;
|
||
}
|
||
}
|
||
|
||
function limitNumberOfItems(available) {
|
||
return options.max && options.max < available
|
||
? options.max
|
||
: available;
|
||
}
|
||
|
||
function fillList() {
|
||
list.empty();
|
||
var max = limitNumberOfItems(data.length);
|
||
for (var i=0; i < max; i++) {
|
||
if (!data[i])
|
||
continue;
|
||
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
|
||
if ( formatted === false )
|
||
continue;
|
||
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
|
||
$.data(li, "ac_data", data[i]);
|
||
}
|
||
listItems = list.find("li");
|
||
if ( options.selectFirst ) {
|
||
listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
|
||
active = 0;
|
||
}
|
||
// apply bgiframe if available
|
||
if ( $.fn.bgiframe )
|
||
list.bgiframe();
|
||
}
|
||
|
||
return {
|
||
display: function(d, q) {
|
||
init();
|
||
data = d;
|
||
term = q;
|
||
fillList();
|
||
},
|
||
next: function() {
|
||
moveSelect(1);
|
||
},
|
||
prev: function() {
|
||
moveSelect(-1);
|
||
},
|
||
pageUp: function() {
|
||
if (active != 0 && active - 8 < 0) {
|
||
moveSelect( -active );
|
||
} else {
|
||
moveSelect(-8);
|
||
}
|
||
},
|
||
pageDown: function() {
|
||
if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
|
||
moveSelect( listItems.size() - 1 - active );
|
||
} else {
|
||
moveSelect(8);
|
||
}
|
||
},
|
||
hide: function() {
|
||
element && element.hide();
|
||
listItems && listItems.removeClass(CLASSES.ACTIVE);
|
||
active = -1;
|
||
},
|
||
visible : function() {
|
||
return element && element.is(":visible");
|
||
},
|
||
current: function() {
|
||
return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
|
||
},
|
||
show: function() {
|
||
var offset = $(input).offset();
|
||
element.css({
|
||
width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
|
||
top: offset.top + input.offsetHeight,
|
||
left: offset.left
|
||
}).show();
|
||
if(options.scroll) {
|
||
list.scrollTop(0);
|
||
list.css({
|
||
maxHeight: options.scrollHeight,
|
||
overflow: 'auto'
|
||
});
|
||
|
||
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
|
||
var listHeight = 0;
|
||
listItems.each(function() {
|
||
listHeight += this.offsetHeight;
|
||
});
|
||
var scrollbarsVisible = listHeight > options.scrollHeight;
|
||
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
|
||
if (!scrollbarsVisible) {
|
||
// IE doesn't recalculate width when scrollbar disappears
|
||
listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
|
||
}
|
||
}
|
||
|
||
}
|
||
},
|
||
selected: function() {
|
||
var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
|
||
return selected && selected.length && $.data(selected[0], "ac_data");
|
||
},
|
||
emptyList: function (){
|
||
list && list.empty();
|
||
},
|
||
unbind: function() {
|
||
element && element.remove();
|
||
}
|
||
};
|
||
};
|
||
|
||
$.Autocompleter.Selection = function(field, start, end) {
|
||
if( field.createTextRange ){
|
||
var selRange = field.createTextRange();
|
||
selRange.collapse(true);
|
||
selRange.moveStart("character", start);
|
||
selRange.moveEnd("character", end);
|
||
selRange.select();
|
||
} else if( field.setSelectionRange ){
|
||
field.setSelectionRange(start, end);
|
||
} else {
|
||
if( field.selectionStart ){
|
||
field.selectionStart = start;
|
||
field.selectionEnd = end;
|
||
}
|
||
}
|
||
field.focus();
|
||
};
|
||
|
||
})(jQuery);;/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
|
||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||
*
|
||
* $LastChangedDate: 2007-07-22 01:45:56 +0200 (Son, 22 Jul 2007) $
|
||
* $Rev: 2447 $
|
||
*
|
||
* Version 2.1.1
|
||
*/
|
||
(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery);;/*!
|
||
* jQuery Color Animations v@VERSION
|
||
* https://github.com/jquery/jquery-color
|
||
*
|
||
* Copyright jQuery Foundation and other contributors
|
||
* Released under the MIT license.
|
||
* http://jquery.org/license
|
||
*
|
||
* Date: @DATE
|
||
*/
|
||
(function( jQuery, undefined ) {
|
||
|
||
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
|
||
|
||
// plusequals test for += 100 -= 100
|
||
rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
|
||
// a set of RE's that can match strings and generate color tuples.
|
||
stringParsers = [{
|
||
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
|
||
parse: function( execResult ) {
|
||
return [
|
||
execResult[ 1 ],
|
||
execResult[ 2 ],
|
||
execResult[ 3 ],
|
||
execResult[ 4 ]
|
||
];
|
||
}
|
||
}, {
|
||
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
|
||
parse: function( execResult ) {
|
||
return [
|
||
execResult[ 1 ] * 2.55,
|
||
execResult[ 2 ] * 2.55,
|
||
execResult[ 3 ] * 2.55,
|
||
execResult[ 4 ]
|
||
];
|
||
}
|
||
}, {
|
||
// this regex ignores A-F because it's compared against an already lowercased string
|
||
re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
|
||
parse: function( execResult ) {
|
||
return [
|
||
parseInt( execResult[ 1 ], 16 ),
|
||
parseInt( execResult[ 2 ], 16 ),
|
||
parseInt( execResult[ 3 ], 16 )
|
||
];
|
||
}
|
||
}, {
|
||
// this regex ignores A-F because it's compared against an already lowercased string
|
||
re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
|
||
parse: function( execResult ) {
|
||
return [
|
||
parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
|
||
parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
|
||
parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
|
||
];
|
||
}
|
||
}, {
|
||
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
|
||
space: "hsla",
|
||
parse: function( execResult ) {
|
||
return [
|
||
execResult[ 1 ],
|
||
execResult[ 2 ] / 100,
|
||
execResult[ 3 ] / 100,
|
||
execResult[ 4 ]
|
||
];
|
||
}
|
||
}],
|
||
|
||
// jQuery.Color( )
|
||
color = jQuery.Color = function( color, green, blue, alpha ) {
|
||
return new jQuery.Color.fn.parse( color, green, blue, alpha );
|
||
},
|
||
spaces = {
|
||
rgba: {
|
||
props: {
|
||
red: {
|
||
idx: 0,
|
||
type: "byte"
|
||
},
|
||
green: {
|
||
idx: 1,
|
||
type: "byte"
|
||
},
|
||
blue: {
|
||
idx: 2,
|
||
type: "byte"
|
||
}
|
||
}
|
||
},
|
||
|
||
hsla: {
|
||
props: {
|
||
hue: {
|
||
idx: 0,
|
||
type: "degrees"
|
||
},
|
||
saturation: {
|
||
idx: 1,
|
||
type: "percent"
|
||
},
|
||
lightness: {
|
||
idx: 2,
|
||
type: "percent"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
propTypes = {
|
||
"byte": {
|
||
floor: true,
|
||
max: 255
|
||
},
|
||
"percent": {
|
||
max: 1
|
||
},
|
||
"degrees": {
|
||
mod: 360,
|
||
floor: true
|
||
}
|
||
},
|
||
support = color.support = {},
|
||
|
||
// element for support tests
|
||
supportElem = jQuery( "<p>" )[ 0 ],
|
||
|
||
// colors = jQuery.Color.names
|
||
colors,
|
||
|
||
// local aliases of functions called often
|
||
each = jQuery.each;
|
||
|
||
// determine rgba support immediately
|
||
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
|
||
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
|
||
|
||
// define cache name and alpha properties
|
||
// for rgba and hsla spaces
|
||
each( spaces, function( spaceName, space ) {
|
||
space.cache = "_" + spaceName;
|
||
space.props.alpha = {
|
||
idx: 3,
|
||
type: "percent",
|
||
def: 1
|
||
};
|
||
});
|
||
|
||
function clamp( value, prop, allowEmpty ) {
|
||
var type = propTypes[ prop.type ] || {};
|
||
|
||
if ( value == null ) {
|
||
return (allowEmpty || !prop.def) ? null : prop.def;
|
||
}
|
||
|
||
// ~~ is an short way of doing floor for positive numbers
|
||
value = type.floor ? ~~value : parseFloat( value );
|
||
|
||
// IE will pass in empty strings as value for alpha,
|
||
// which will hit this case
|
||
if ( isNaN( value ) ) {
|
||
return prop.def;
|
||
}
|
||
|
||
if ( type.mod ) {
|
||
// we add mod before modding to make sure that negatives values
|
||
// get converted properly: -10 -> 350
|
||
return (value + type.mod) % type.mod;
|
||
}
|
||
|
||
// for now all property types without mod have min and max
|
||
return 0 > value ? 0 : type.max < value ? type.max : value;
|
||
}
|
||
|
||
function stringParse( string ) {
|
||
var inst = color(),
|
||
rgba = inst._rgba = [];
|
||
|
||
string = string.toLowerCase();
|
||
|
||
each( stringParsers, function( i, parser ) {
|
||
var parsed,
|
||
match = parser.re.exec( string ),
|
||
values = match && parser.parse( match ),
|
||
spaceName = parser.space || "rgba";
|
||
|
||
if ( values ) {
|
||
parsed = inst[ spaceName ]( values );
|
||
|
||
// if this was an rgba parse the assignment might happen twice
|
||
// oh well....
|
||
inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
|
||
rgba = inst._rgba = parsed._rgba;
|
||
|
||
// exit each( stringParsers ) here because we matched
|
||
return false;
|
||
}
|
||
});
|
||
|
||
// Found a stringParser that handled it
|
||
if ( rgba.length ) {
|
||
|
||
// if this came from a parsed string, force "transparent" when alpha is 0
|
||
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
|
||
if ( rgba.join() === "0,0,0,0" ) {
|
||
jQuery.extend( rgba, colors.transparent );
|
||
}
|
||
return inst;
|
||
}
|
||
|
||
// named colors
|
||
return colors[ string ];
|
||
}
|
||
|
||
color.fn = jQuery.extend( color.prototype, {
|
||
parse: function( red, green, blue, alpha ) {
|
||
if ( red === undefined ) {
|
||
this._rgba = [ null, null, null, null ];
|
||
return this;
|
||
}
|
||
if ( red.jquery || red.nodeType ) {
|
||
red = jQuery( red ).css( green );
|
||
green = undefined;
|
||
}
|
||
|
||
var inst = this,
|
||
type = jQuery.type( red ),
|
||
rgba = this._rgba = [];
|
||
|
||
// more than 1 argument specified - assume ( red, green, blue, alpha )
|
||
if ( green !== undefined ) {
|
||
red = [ red, green, blue, alpha ];
|
||
type = "array";
|
||
}
|
||
|
||
if ( type === "string" ) {
|
||
return this.parse( stringParse( red ) || colors._default );
|
||
}
|
||
|
||
if ( type === "array" ) {
|
||
each( spaces.rgba.props, function( key, prop ) {
|
||
rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
|
||
});
|
||
return this;
|
||
}
|
||
|
||
if ( type === "object" ) {
|
||
if ( red instanceof color ) {
|
||
each( spaces, function( spaceName, space ) {
|
||
if ( red[ space.cache ] ) {
|
||
inst[ space.cache ] = red[ space.cache ].slice();
|
||
}
|
||
});
|
||
} else {
|
||
each( spaces, function( spaceName, space ) {
|
||
var cache = space.cache;
|
||
each( space.props, function( key, prop ) {
|
||
|
||
// if the cache doesn't exist, and we know how to convert
|
||
if ( !inst[ cache ] && space.to ) {
|
||
|
||
// if the value was null, we don't need to copy it
|
||
// if the key was alpha, we don't need to copy it either
|
||
if ( key === "alpha" || red[ key ] == null ) {
|
||
return;
|
||
}
|
||
inst[ cache ] = space.to( inst._rgba );
|
||
}
|
||
|
||
// this is the only case where we allow nulls for ALL properties.
|
||
// call clamp with alwaysAllowEmpty
|
||
inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
|
||
});
|
||
|
||
// everything defined but alpha?
|
||
if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
|
||
// use the default of 1
|
||
inst[ cache ][ 3 ] = 1;
|
||
if ( space.from ) {
|
||
inst._rgba = space.from( inst[ cache ] );
|
||
}
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
}
|
||
},
|
||
is: function( compare ) {
|
||
var is = color( compare ),
|
||
same = true,
|
||
inst = this;
|
||
|
||
each( spaces, function( _, space ) {
|
||
var localCache,
|
||
isCache = is[ space.cache ];
|
||
if (isCache) {
|
||
localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
|
||
each( space.props, function( _, prop ) {
|
||
if ( isCache[ prop.idx ] != null ) {
|
||
same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
|
||
return same;
|
||
}
|
||
});
|
||
}
|
||
return same;
|
||
});
|
||
return same;
|
||
},
|
||
_space: function() {
|
||
var used = [],
|
||
inst = this;
|
||
each( spaces, function( spaceName, space ) {
|
||
if ( inst[ space.cache ] ) {
|
||
used.push( spaceName );
|
||
}
|
||
});
|
||
return used.pop();
|
||
},
|
||
transition: function( other, distance ) {
|
||
var end = color( other ),
|
||
spaceName = end._space(),
|
||
space = spaces[ spaceName ],
|
||
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
|
||
start = startColor[ space.cache ] || space.to( startColor._rgba ),
|
||
result = start.slice();
|
||
|
||
end = end[ space.cache ];
|
||
each( space.props, function( key, prop ) {
|
||
var index = prop.idx,
|
||
startValue = start[ index ],
|
||
endValue = end[ index ],
|
||
type = propTypes[ prop.type ] || {};
|
||
|
||
// if null, don't override start value
|
||
if ( endValue === null ) {
|
||
return;
|
||
}
|
||
// if null - use end
|
||
if ( startValue === null ) {
|
||
result[ index ] = endValue;
|
||
} else {
|
||
if ( type.mod ) {
|
||
if ( endValue - startValue > type.mod / 2 ) {
|
||
startValue += type.mod;
|
||
} else if ( startValue - endValue > type.mod / 2 ) {
|
||
startValue -= type.mod;
|
||
}
|
||
}
|
||
result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
|
||
}
|
||
});
|
||
return this[ spaceName ]( result );
|
||
},
|
||
blend: function( opaque ) {
|
||
// if we are already opaque - return ourself
|
||
if ( this._rgba[ 3 ] === 1 ) {
|
||
return this;
|
||
}
|
||
|
||
var rgb = this._rgba.slice(),
|
||
a = rgb.pop(),
|
||
blend = color( opaque )._rgba;
|
||
|
||
return color( jQuery.map( rgb, function( v, i ) {
|
||
return ( 1 - a ) * blend[ i ] + a * v;
|
||
}));
|
||
},
|
||
toRgbaString: function() {
|
||
var prefix = "rgba(",
|
||
rgba = jQuery.map( this._rgba, function( v, i ) {
|
||
return v == null ? ( i > 2 ? 1 : 0 ) : v;
|
||
});
|
||
|
||
if ( rgba[ 3 ] === 1 ) {
|
||
rgba.pop();
|
||
prefix = "rgb(";
|
||
}
|
||
|
||
return prefix + rgba.join() + ")";
|
||
},
|
||
toHslaString: function() {
|
||
var prefix = "hsla(",
|
||
hsla = jQuery.map( this.hsla(), function( v, i ) {
|
||
if ( v == null ) {
|
||
v = i > 2 ? 1 : 0;
|
||
}
|
||
|
||
// catch 1 and 2
|
||
if ( i && i < 3 ) {
|
||
v = Math.round( v * 100 ) + "%";
|
||
}
|
||
return v;
|
||
});
|
||
|
||
if ( hsla[ 3 ] === 1 ) {
|
||
hsla.pop();
|
||
prefix = "hsl(";
|
||
}
|
||
return prefix + hsla.join() + ")";
|
||
},
|
||
toHexString: function( includeAlpha ) {
|
||
var rgba = this._rgba.slice(),
|
||
alpha = rgba.pop();
|
||
|
||
if ( includeAlpha ) {
|
||
rgba.push( ~~( alpha * 255 ) );
|
||
}
|
||
|
||
return "#" + jQuery.map( rgba, function( v ) {
|
||
|
||
// default to 0 when nulls exist
|
||
v = ( v || 0 ).toString( 16 );
|
||
return v.length === 1 ? "0" + v : v;
|
||
}).join("");
|
||
},
|
||
toString: function() {
|
||
return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
|
||
}
|
||
});
|
||
color.fn.parse.prototype = color.fn;
|
||
|
||
// hsla conversions adapted from:
|
||
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
|
||
|
||
function hue2rgb( p, q, h ) {
|
||
h = ( h + 1 ) % 1;
|
||
if ( h * 6 < 1 ) {
|
||
return p + (q - p) * h * 6;
|
||
}
|
||
if ( h * 2 < 1) {
|
||
return q;
|
||
}
|
||
if ( h * 3 < 2 ) {
|
||
return p + (q - p) * ((2/3) - h) * 6;
|
||
}
|
||
return p;
|
||
}
|
||
|
||
spaces.hsla.to = function ( rgba ) {
|
||
if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
|
||
return [ null, null, null, rgba[ 3 ] ];
|
||
}
|
||
var r = rgba[ 0 ] / 255,
|
||
g = rgba[ 1 ] / 255,
|
||
b = rgba[ 2 ] / 255,
|
||
a = rgba[ 3 ],
|
||
max = Math.max( r, g, b ),
|
||
min = Math.min( r, g, b ),
|
||
diff = max - min,
|
||
add = max + min,
|
||
l = add * 0.5,
|
||
h, s;
|
||
|
||
if ( min === max ) {
|
||
h = 0;
|
||
} else if ( r === max ) {
|
||
h = ( 60 * ( g - b ) / diff ) + 360;
|
||
} else if ( g === max ) {
|
||
h = ( 60 * ( b - r ) / diff ) + 120;
|
||
} else {
|
||
h = ( 60 * ( r - g ) / diff ) + 240;
|
||
}
|
||
|
||
// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
|
||
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
|
||
if ( diff === 0 ) {
|
||
s = 0;
|
||
} else if ( l <= 0.5 ) {
|
||
s = diff / add;
|
||
} else {
|
||
s = diff / ( 2 - add );
|
||
}
|
||
return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
|
||
};
|
||
|
||
spaces.hsla.from = function ( hsla ) {
|
||
if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
|
||
return [ null, null, null, hsla[ 3 ] ];
|
||
}
|
||
var h = hsla[ 0 ] / 360,
|
||
s = hsla[ 1 ],
|
||
l = hsla[ 2 ],
|
||
a = hsla[ 3 ],
|
||
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
|
||
p = 2 * l - q;
|
||
|
||
return [
|
||
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
|
||
Math.round( hue2rgb( p, q, h ) * 255 ),
|
||
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
|
||
a
|
||
];
|
||
};
|
||
|
||
|
||
each( spaces, function( spaceName, space ) {
|
||
var props = space.props,
|
||
cache = space.cache,
|
||
to = space.to,
|
||
from = space.from;
|
||
|
||
// makes rgba() and hsla()
|
||
color.fn[ spaceName ] = function( value ) {
|
||
|
||
// generate a cache for this space if it doesn't exist
|
||
if ( to && !this[ cache ] ) {
|
||
this[ cache ] = to( this._rgba );
|
||
}
|
||
if ( value === undefined ) {
|
||
return this[ cache ].slice();
|
||
}
|
||
|
||
var ret,
|
||
type = jQuery.type( value ),
|
||
arr = ( type === "array" || type === "object" ) ? value : arguments,
|
||
local = this[ cache ].slice();
|
||
|
||
each( props, function( key, prop ) {
|
||
var val = arr[ type === "object" ? key : prop.idx ];
|
||
if ( val == null ) {
|
||
val = local[ prop.idx ];
|
||
}
|
||
local[ prop.idx ] = clamp( val, prop );
|
||
});
|
||
|
||
if ( from ) {
|
||
ret = color( from( local ) );
|
||
ret[ cache ] = local;
|
||
return ret;
|
||
} else {
|
||
return color( local );
|
||
}
|
||
};
|
||
|
||
// makes red() green() blue() alpha() hue() saturation() lightness()
|
||
each( props, function( key, prop ) {
|
||
// alpha is included in more than one space
|
||
if ( color.fn[ key ] ) {
|
||
return;
|
||
}
|
||
color.fn[ key ] = function( value ) {
|
||
var vtype = jQuery.type( value ),
|
||
fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
|
||
local = this[ fn ](),
|
||
cur = local[ prop.idx ],
|
||
match;
|
||
|
||
if ( vtype === "undefined" ) {
|
||
return cur;
|
||
}
|
||
|
||
if ( vtype === "function" ) {
|
||
value = value.call( this, cur );
|
||
vtype = jQuery.type( value );
|
||
}
|
||
if ( value == null && prop.empty ) {
|
||
return this;
|
||
}
|
||
if ( vtype === "string" ) {
|
||
match = rplusequals.exec( value );
|
||
if ( match ) {
|
||
value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
|
||
}
|
||
}
|
||
local[ prop.idx ] = value;
|
||
return this[ fn ]( local );
|
||
};
|
||
});
|
||
});
|
||
|
||
// add cssHook and .fx.step function for each named hook.
|
||
// accept a space separated string of properties
|
||
color.hook = function( hook ) {
|
||
var hooks = hook.split( " " );
|
||
each( hooks, function( i, hook ) {
|
||
jQuery.cssHooks[ hook ] = {
|
||
set: function( elem, value ) {
|
||
var parsed, curElem,
|
||
backgroundColor = "";
|
||
|
||
if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
|
||
value = color( parsed || value );
|
||
if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
|
||
curElem = hook === "backgroundColor" ? elem.parentNode : elem;
|
||
while (
|
||
(backgroundColor === "" || backgroundColor === "transparent") &&
|
||
curElem && curElem.style
|
||
) {
|
||
try {
|
||
backgroundColor = jQuery.css( curElem, "backgroundColor" );
|
||
curElem = curElem.parentNode;
|
||
} catch ( e ) {
|
||
}
|
||
}
|
||
|
||
value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
|
||
backgroundColor :
|
||
"_default" );
|
||
}
|
||
|
||
value = value.toRgbaString();
|
||
}
|
||
try {
|
||
elem.style[ hook ] = value;
|
||
} catch( e ) {
|
||
// wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
|
||
}
|
||
}
|
||
};
|
||
jQuery.fx.step[ hook ] = function( fx ) {
|
||
if ( !fx.colorInit ) {
|
||
fx.start = color( fx.elem, hook );
|
||
fx.end = color( fx.end );
|
||
fx.colorInit = true;
|
||
}
|
||
jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
|
||
};
|
||
});
|
||
|
||
};
|
||
|
||
color.hook( stepHooks );
|
||
|
||
jQuery.cssHooks.borderColor = {
|
||
expand: function( value ) {
|
||
var expanded = {};
|
||
|
||
each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
|
||
expanded[ "border" + part + "Color" ] = value;
|
||
});
|
||
return expanded;
|
||
}
|
||
};
|
||
|
||
// Basic color names only.
|
||
// Usage of any of the other color names requires adding yourself or including
|
||
// jquery.color.svg-names.js.
|
||
colors = jQuery.Color.names = {
|
||
// 4.1. Basic color keywords
|
||
aqua: "#00ffff",
|
||
black: "#000000",
|
||
blue: "#0000ff",
|
||
fuchsia: "#ff00ff",
|
||
gray: "#808080",
|
||
green: "#008000",
|
||
lime: "#00ff00",
|
||
maroon: "#800000",
|
||
navy: "#000080",
|
||
olive: "#808000",
|
||
purple: "#800080",
|
||
red: "#ff0000",
|
||
silver: "#c0c0c0",
|
||
teal: "#008080",
|
||
white: "#ffffff",
|
||
yellow: "#ffff00",
|
||
|
||
// 4.2.3. "transparent" color keyword
|
||
transparent: [ null, null, null, 0 ],
|
||
|
||
_default: "#ffffff"
|
||
};
|
||
|
||
}( jQuery ));
|
||
;/*!
|
||
* jQuery Form Plugin
|
||
* version: 3.51.0-2014.06.20
|
||
* Requires jQuery v1.5 or later
|
||
* Copyright (c) 2014 M. Alsup
|
||
* Examples and documentation at: http://malsup.com/jquery/form/
|
||
* Project repository: https://github.com/malsup/form
|
||
* Dual licensed under the MIT and GPL licenses.
|
||
* https://github.com/malsup/form#copyright-and-license
|
||
*/
|
||
/*global ActiveXObject */
|
||
|
||
// AMD support
|
||
(function (factory) {
|
||
"use strict";
|
||
if (typeof define === 'function' && define.amd) {
|
||
// using AMD; register as anon module
|
||
define(['jquery'], factory);
|
||
} else {
|
||
// no AMD; invoke directly
|
||
factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
|
||
}
|
||
}
|
||
|
||
(function($) {
|
||
"use strict";
|
||
|
||
/*
|
||
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 = $("<input type='file'/>").get(0).files !== undefined;
|
||
feature.formdata = window.FormData !== undefined;
|
||
|
||
var hasProp = !!$.fn.prop;
|
||
|
||
// attr2 uses prop when it can but checks the return type for
|
||
// an expected string. this accounts for the case where a form
|
||
// contains inputs with names like "action" or "method"; in those
|
||
// cases "prop" returns the element
|
||
$.fn.attr2 = function() {
|
||
if ( ! hasProp ) {
|
||
return this.attr.apply(this, arguments);
|
||
}
|
||
var val = this.prop.apply(this, arguments);
|
||
if ( ( val && val.jquery ) || typeof val === 'string' ) {
|
||
return val;
|
||
}
|
||
return this.attr.apply(this, arguments);
|
||
};
|
||
|
||
/**
|
||
* ajaxSubmit() provides a mechanism for immediately submitting
|
||
* an HTML form using AJAX.
|
||
*/
|
||
$.fn.ajaxSubmit = function(options) {
|
||
/*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 };
|
||
}
|
||
else if ( options === undefined ) {
|
||
options = {};
|
||
}
|
||
|
||
method = options.type || this.attr2('method');
|
||
action = options.url || this.attr2('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 || $.ajaxSettings.type,
|
||
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]);
|
||
}
|
||
};
|
||
|
||
if (options.error) {
|
||
var oldError = options.error;
|
||
options.error = function(xhr, status, error) {
|
||
var context = options.context || this;
|
||
oldError.apply(context, [xhr, status, error, $form]);
|
||
};
|
||
}
|
||
|
||
if (options.complete) {
|
||
var oldComplete = options.complete;
|
||
options.complete = function(xhr, status) {
|
||
var context = options.context || this;
|
||
oldComplete.apply(context, [xhr, status, $form]);
|
||
};
|
||
}
|
||
|
||
// are there files to upload?
|
||
|
||
// [value] (issue #113), also see comment:
|
||
// https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
|
||
var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
|
||
|
||
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;
|
||
|
||
var jqxhr;
|
||
|
||
// 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() {
|
||
jqxhr = fileUploadIframe(a);
|
||
});
|
||
}
|
||
else {
|
||
jqxhr = fileUploadIframe(a);
|
||
}
|
||
}
|
||
else if ((hasFileInputs || multipart) && fileAPI) {
|
||
jqxhr = fileUploadXhr(a);
|
||
}
|
||
else {
|
||
jqxhr = $.ajax(options);
|
||
}
|
||
|
||
$form.removeData('jqxhr').data('jqxhr', jqxhr);
|
||
|
||
// 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;
|
||
|
||
// utility fn for deep serialization
|
||
function deepSerialize(extraData){
|
||
var serialized = $.param(extraData, options.traditional).split('&');
|
||
var len = serialized.length;
|
||
var result = [];
|
||
var i, part;
|
||
for (i=0; i < len; i++) {
|
||
// #252; undo param space replacement
|
||
serialized[i] = serialized[i].replace(/\+/g,' ');
|
||
part = serialized[i].split('=');
|
||
// #278; use array instead of object storage, favoring array serializations
|
||
result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// 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) {
|
||
var serializedData = deepSerialize(options.extraData);
|
||
for (i=0; i < serializedData.length; i++) {
|
||
if (serializedData[i]) {
|
||
formdata.append(serializedData[i][0], serializedData[i][1]);
|
||
}
|
||
}
|
||
}
|
||
|
||
options.data = null;
|
||
|
||
var s = $.extend(true, {}, $.ajaxSettings, options, {
|
||
contentType: false,
|
||
processData: false,
|
||
cache: false,
|
||
type: method || 'POST'
|
||
});
|
||
|
||
if (options.uploadProgress) {
|
||
// workaround because jqXHR does not expose upload property
|
||
s.xhr = function() {
|
||
var xhr = $.ajaxSettings.xhr();
|
||
if (xhr.upload) {
|
||
xhr.upload.addEventListener('progress', 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);
|
||
}, false);
|
||
}
|
||
return xhr;
|
||
};
|
||
}
|
||
|
||
s.data = null;
|
||
var beforeSend = s.beforeSend;
|
||
s.beforeSend = function(xhr, o) {
|
||
//Send FormData() provided by user
|
||
if (options.formData) {
|
||
o.data = options.formData;
|
||
}
|
||
else {
|
||
o.data = formdata;
|
||
}
|
||
if(beforeSend) {
|
||
beforeSend.call(this, xhr, o);
|
||
}
|
||
};
|
||
return $.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 deferred = $.Deferred();
|
||
|
||
// #341
|
||
deferred.abort = function(status) {
|
||
xhr.abort(status);
|
||
};
|
||
|
||
if (a) {
|
||
// ensure that every serialized input is still enabled
|
||
for (i=0; i < elements.length; i++) {
|
||
el = $(elements[i]);
|
||
if ( hasProp ) {
|
||
el.prop('disabled', false);
|
||
}
|
||
else {
|
||
el.removeAttr('disabled');
|
||
}
|
||
}
|
||
}
|
||
|
||
s = $.extend(true, {}, $.ajaxSettings, options);
|
||
s.context = s.context || s;
|
||
id = 'jqFormIO' + (new Date().getTime());
|
||
if (s.iframeTarget) {
|
||
$io = $(s.iframeTarget);
|
||
n = $io.attr2('name');
|
||
if (!n) {
|
||
$io.attr2('name', id);
|
||
}
|
||
else {
|
||
id = n;
|
||
}
|
||
}
|
||
else {
|
||
$io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
|
||
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
||
}
|
||
io = $io[0];
|
||
|
||
|
||
xhr = { // mock object
|
||
aborted: 0,
|
||
responseText: null,
|
||
responseXML: null,
|
||
status: 0,
|
||
statusText: 'n/a',
|
||
getAllResponseHeaders: function() {},
|
||
getResponseHeader: function() {},
|
||
setRequestHeader: function() {},
|
||
abort: function(status) {
|
||
var e = (status === 'timeout' ? 'timeout' : 'aborted');
|
||
log('aborting upload... ' + e);
|
||
this.aborted = 1;
|
||
|
||
try { // #214, #257
|
||
if (io.contentWindow.document.execCommand) {
|
||
io.contentWindow.document.execCommand('Stop');
|
||
}
|
||
}
|
||
catch(ignore) {}
|
||
|
||
$io.attr('src', s.iframeSrc); // abort op in progress
|
||
xhr.error = e;
|
||
if (s.error) {
|
||
s.error.call(s.context, xhr, e, status);
|
||
}
|
||
if (g) {
|
||
$.event.trigger("ajaxError", [xhr, s, e]);
|
||
}
|
||
if (s.complete) {
|
||
s.complete.call(s.context, xhr, e);
|
||
}
|
||
}
|
||
};
|
||
|
||
g = s.global;
|
||
// trigger ajax global events so that activity/block indicators work like normal
|
||
if (g && 0 === $.active++) {
|
||
$.event.trigger("ajaxStart");
|
||
}
|
||
if (g) {
|
||
$.event.trigger("ajaxSend", [xhr, s]);
|
||
}
|
||
|
||
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
|
||
if (s.global) {
|
||
$.active--;
|
||
}
|
||
deferred.reject();
|
||
return deferred;
|
||
}
|
||
if (xhr.aborted) {
|
||
deferred.reject();
|
||
return deferred;
|
||
}
|
||
|
||
// add submitting element to data if we know it
|
||
sub = form.clk;
|
||
if (sub) {
|
||
n = sub.name;
|
||
if (n && !sub.disabled) {
|
||
s.extraData = s.extraData || {};
|
||
s.extraData[n] = sub.value;
|
||
if (sub.type == "image") {
|
||
s.extraData[n+'.x'] = form.clk_x;
|
||
s.extraData[n+'.y'] = form.clk_y;
|
||
}
|
||
}
|
||
}
|
||
|
||
var CLIENT_TIMEOUT_ABORT = 1;
|
||
var SERVER_ABORT = 2;
|
||
|
||
function getDoc(frame) {
|
||
/* it looks like contentWindow or contentDocument do not
|
||
* carry the protocol property in ie8, when running under ssl
|
||
* frame.document is the only valid response document, since
|
||
* the protocol is know but not on the other two objects. strange?
|
||
* "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
|
||
*/
|
||
|
||
var doc = null;
|
||
|
||
// IE8 cascading access check
|
||
try {
|
||
if (frame.contentWindow) {
|
||
doc = frame.contentWindow.document;
|
||
}
|
||
} catch(err) {
|
||
// IE8 access denied under ssl & missing protocol
|
||
log('cannot get iframe.contentWindow document: ' + err);
|
||
}
|
||
|
||
if (doc) { // successful getting content
|
||
return doc;
|
||
}
|
||
|
||
try { // simply checking may throw in ie8 under ssl or mismatched protocol
|
||
doc = frame.contentDocument ? frame.contentDocument : frame.document;
|
||
} catch(err) {
|
||
// last attempt
|
||
log('cannot get iframe.contentDocument: ' + err);
|
||
doc = frame.document;
|
||
}
|
||
return doc;
|
||
}
|
||
|
||
// Rails CSRF hack (thanks to Yvan Barthelemy)
|
||
var csrf_token = $('meta[name=csrf-token]').attr('content');
|
||
var csrf_param = $('meta[name=csrf-param]').attr('content');
|
||
if (csrf_param && csrf_token) {
|
||
s.extraData = s.extraData || {};
|
||
s.extraData[csrf_param] = csrf_token;
|
||
}
|
||
|
||
// take a breath so that pending repaints get some cpu time before the upload starts
|
||
function doSubmit() {
|
||
// make sure form attrs are set
|
||
var t = $form.attr2('target'),
|
||
a = $form.attr2('action'),
|
||
mp = 'multipart/form-data',
|
||
et = $form.attr('enctype') || $form.attr('encoding') || mp;
|
||
|
||
// update form attrs in IE friendly way
|
||
form.setAttribute('target',id);
|
||
if (!method || /post/i.test(method) ) {
|
||
form.setAttribute('method', 'POST');
|
||
}
|
||
if (a != s.url) {
|
||
form.setAttribute('action', s.url);
|
||
}
|
||
|
||
// ie borks in some cases when setting encoding
|
||
if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
|
||
$form.attr({
|
||
encoding: 'multipart/form-data',
|
||
enctype: 'multipart/form-data'
|
||
});
|
||
}
|
||
|
||
// support timout
|
||
if (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 && state.toLowerCase() == 'uninitialized') {
|
||
setTimeout(checkState,50);
|
||
}
|
||
}
|
||
catch(e) {
|
||
log('Server abort: ' , e, ' (', e.name, ')');
|
||
cb(SERVER_ABORT);
|
||
if (timeoutHandle) {
|
||
clearTimeout(timeoutHandle);
|
||
}
|
||
timeoutHandle = undefined;
|
||
}
|
||
}
|
||
|
||
// add "extra" data to form if provided in options
|
||
var extraInputs = [];
|
||
try {
|
||
if (s.extraData) {
|
||
for (var n in s.extraData) {
|
||
if (s.extraData.hasOwnProperty(n)) {
|
||
// if using the $.param format that allows for multiple values with the same name
|
||
if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
|
||
extraInputs.push(
|
||
$('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
|
||
.appendTo(form)[0]);
|
||
} else {
|
||
extraInputs.push(
|
||
$('<input type="hidden" name="'+n+'">').val(s.extraData[n])
|
||
.appendTo(form)[0]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!s.iframeTarget) {
|
||
// add iframe to doc and submit the form
|
||
$io.appendTo('body');
|
||
}
|
||
if (io.attachEvent) {
|
||
io.attachEvent('onload', cb);
|
||
}
|
||
else {
|
||
io.addEventListener('load', cb, false);
|
||
}
|
||
setTimeout(checkState,15);
|
||
|
||
try {
|
||
form.submit();
|
||
} catch(err) {
|
||
// just in case form has element with name/id of 'submit'
|
||
var submitFn = document.createElement('form').submit;
|
||
submitFn.apply(form);
|
||
}
|
||
}
|
||
finally {
|
||
// reset attrs and remove "extra" input elements
|
||
form.setAttribute('action',a);
|
||
form.setAttribute('enctype', et); // #380
|
||
if(t) {
|
||
form.setAttribute('target', t);
|
||
} else {
|
||
$form.removeAttr('target');
|
||
}
|
||
$(extraInputs).remove();
|
||
}
|
||
}
|
||
|
||
if (s.forceSync) {
|
||
doSubmit();
|
||
}
|
||
else {
|
||
setTimeout(doSubmit, 10); // this lets dom updates render
|
||
}
|
||
|
||
var data, doc, domCheckCount = 50, callbackProcessed;
|
||
|
||
function cb(e) {
|
||
if (xhr.aborted || callbackProcessed) {
|
||
return;
|
||
}
|
||
|
||
doc = getDoc(io);
|
||
if(!doc) {
|
||
log('cannot access response document');
|
||
e = SERVER_ABORT;
|
||
}
|
||
if (e === CLIENT_TIMEOUT_ABORT && xhr) {
|
||
xhr.abort('timeout');
|
||
deferred.reject(xhr, 'timeout');
|
||
return;
|
||
}
|
||
else if (e == SERVER_ABORT && xhr) {
|
||
xhr.abort('server abort');
|
||
deferred.reject(xhr, 'error', 'server abort');
|
||
return;
|
||
}
|
||
|
||
if (!doc || doc.location.href == s.iframeSrc) {
|
||
// response not received yet
|
||
if (!timedOut) {
|
||
return;
|
||
}
|
||
}
|
||
if (io.detachEvent) {
|
||
io.detachEvent('onload', cb);
|
||
}
|
||
else {
|
||
io.removeEventListener('load', cb, false);
|
||
}
|
||
|
||
var status = 'success', errMsg;
|
||
try {
|
||
if (timedOut) {
|
||
throw 'timeout';
|
||
}
|
||
|
||
var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
|
||
log('isXml='+isXml);
|
||
if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
|
||
if (--domCheckCount) {
|
||
// in some browsers (Opera) the iframe DOM is not always traversable when
|
||
// the onload callback fires, so we loop a bit to accommodate
|
||
log('requeing onLoad callback, DOM not available');
|
||
setTimeout(cb, 250);
|
||
return;
|
||
}
|
||
// let this fall through because server response could be an empty document
|
||
//log('Could not access iframe DOM after mutiple tries.');
|
||
//throw 'DOMException: not available';
|
||
}
|
||
|
||
//log('response detected');
|
||
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.toLowerCase()];
|
||
};
|
||
// 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 || '').toLowerCase();
|
||
var scr = /(json|script|text)/.test(dt);
|
||
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 ? pre.textContent : pre.innerText;
|
||
}
|
||
else if (b) {
|
||
xhr.responseText = b.textContent ? b.textContent : b.innerText;
|
||
}
|
||
}
|
||
}
|
||
else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
|
||
xhr.responseXML = toXml(xhr.responseText);
|
||
}
|
||
|
||
try {
|
||
data = httpData(xhr, dt, s);
|
||
}
|
||
catch (err) {
|
||
status = 'parsererror';
|
||
xhr.error = errMsg = (err || status);
|
||
}
|
||
}
|
||
catch (err) {
|
||
log('error caught: ',err);
|
||
status = 'error';
|
||
xhr.error = errMsg = (err || status);
|
||
}
|
||
|
||
if (xhr.aborted) {
|
||
log('upload aborted');
|
||
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 (status === 'success') {
|
||
if (s.success) {
|
||
s.success.call(s.context, data, 'success', xhr);
|
||
}
|
||
deferred.resolve(xhr.responseText, 'success', xhr);
|
||
if (g) {
|
||
$.event.trigger("ajaxSuccess", [xhr, s]);
|
||
}
|
||
}
|
||
else if (status) {
|
||
if (errMsg === undefined) {
|
||
errMsg = xhr.statusText;
|
||
}
|
||
if (s.error) {
|
||
s.error.call(s.context, xhr, status, errMsg);
|
||
}
|
||
deferred.reject(xhr, 'error', errMsg);
|
||
if (g) {
|
||
$.event.trigger("ajaxError", [xhr, s, errMsg]);
|
||
}
|
||
}
|
||
|
||
if (g) {
|
||
$.event.trigger("ajaxComplete", [xhr, s]);
|
||
}
|
||
|
||
if (g && ! --$.active) {
|
||
$.event.trigger("ajaxStop");
|
||
}
|
||
|
||
if (s.complete) {
|
||
s.complete.call(s.context, xhr, status);
|
||
}
|
||
|
||
callbackProcessed = true;
|
||
if (s.timeout) {
|
||
clearTimeout(timeoutHandle);
|
||
}
|
||
|
||
// clean up
|
||
setTimeout(function() {
|
||
if (!s.iframeTarget) {
|
||
$io.remove();
|
||
}
|
||
else { //adding else to clean up existing iframe response.
|
||
$io.attr('src', s.iframeSrc);
|
||
}
|
||
xhr.responseXML = null;
|
||
}, 100);
|
||
}
|
||
|
||
var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
|
||
if (window.ActiveXObject) {
|
||
doc = new ActiveXObject('Microsoft.XMLDOM');
|
||
doc.async = 'false';
|
||
doc.loadXML(s);
|
||
}
|
||
else {
|
||
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
||
}
|
||
return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
|
||
};
|
||
var parseJSON = $.parseJSON || function(s) {
|
||
/*jslint evil:true */
|
||
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') {
|
||
if ($.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;
|
||
};
|
||
|
||
return deferred;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* ajaxForm() provides a mechanism for fully automating form submission.
|
||
*
|
||
* The advantages of using this method instead of ajaxSubmit() are:
|
||
*
|
||
* 1: This method will include coordinates for <input type="image" /> elements (if the element
|
||
* is used to submit the form).
|
||
* 2. This method will include the submit element's name/value data (for the element that was
|
||
* used to submit the form).
|
||
* 3. This method binds the submit() method to the form for you.
|
||
*
|
||
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
|
||
* passes the options argument along after properly binding events for submit elements and
|
||
* the form itself.
|
||
*/
|
||
$.fn.ajaxForm = function(options) {
|
||
options = options || {};
|
||
options.delegation = options.delegation && $.isFunction($.fn.on);
|
||
|
||
// in jQuery 1.3+ we can fix mistakes with the ready state
|
||
if (!options.delegation && this.length === 0) {
|
||
var o = { s: this.selector, c: this.context };
|
||
if (!$.isReady && o.s) {
|
||
log('DOM not ready, queuing ajaxForm');
|
||
$(function() {
|
||
$(o.s,o.c).ajaxForm(options);
|
||
});
|
||
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;
|
||
}
|
||
|
||
if ( options.delegation ) {
|
||
$(document)
|
||
.off('submit.form-plugin', this.selector, doAjaxSubmit)
|
||
.off('click.form-plugin', this.selector, captureSubmittingElement)
|
||
.on('submit.form-plugin', this.selector, options, doAjaxSubmit)
|
||
.on('click.form-plugin', this.selector, options, captureSubmittingElement);
|
||
return this;
|
||
}
|
||
|
||
return this.ajaxFormUnbind()
|
||
.bind('submit.form-plugin', options, doAjaxSubmit)
|
||
.bind('click.form-plugin', options, captureSubmittingElement);
|
||
};
|
||
|
||
// private event handlers
|
||
function doAjaxSubmit(e) {
|
||
/*jshint validthis:true */
|
||
var options = e.data;
|
||
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
|
||
e.preventDefault();
|
||
$(e.target).ajaxSubmit(options); // #365
|
||
}
|
||
}
|
||
|
||
function captureSubmittingElement(e) {
|
||
/*jshint validthis:true */
|
||
var target = e.target;
|
||
var $el = $(target);
|
||
if (!($el.is("[type=submit],[type=image]"))) {
|
||
// is this a child element of the submit el? (ex: a span within a button)
|
||
var t = $el.closest('[type=submit]');
|
||
if (t.length === 0) {
|
||
return;
|
||
}
|
||
target = t[0];
|
||
}
|
||
var form = this;
|
||
form.clk = target;
|
||
if (target.type == 'image') {
|
||
if (e.offsetX !== undefined) {
|
||
form.clk_x = e.offsetX;
|
||
form.clk_y = e.offsetY;
|
||
} else if (typeof $.fn.offset == 'function') {
|
||
var offset = $el.offset();
|
||
form.clk_x = e.pageX - offset.left;
|
||
form.clk_y = e.pageY - offset.top;
|
||
} else {
|
||
form.clk_x = e.pageX - target.offsetLeft;
|
||
form.clk_y = e.pageY - target.offsetTop;
|
||
}
|
||
}
|
||
// clear form vars
|
||
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
|
||
}
|
||
|
||
|
||
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
||
$.fn.ajaxFormUnbind = function() {
|
||
return this.unbind('submit.form-plugin click.form-plugin');
|
||
};
|
||
|
||
/**
|
||
* formToArray() gathers form element data into an array of objects that can
|
||
* be passed to any of the following ajax functions: $.get, $.post, or load.
|
||
* Each object in the array has both a 'name' and 'value' property. An example of
|
||
* an array for a simple login form might be:
|
||
*
|
||
* [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
|
||
*
|
||
* It is this array that is passed to pre-submit callback functions provided to the
|
||
* ajaxSubmit() and ajaxForm() methods.
|
||
*/
|
||
$.fn.formToArray = function(semantic, elements) {
|
||
var a = [];
|
||
if (this.length === 0) {
|
||
return a;
|
||
}
|
||
|
||
var form = this[0];
|
||
var formId = this.attr('id');
|
||
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
||
var els2;
|
||
|
||
if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
|
||
els = $(els).get(); // convert to standard array
|
||
}
|
||
|
||
// #386; account for inputs outside the form which use the 'form' attribute
|
||
if ( formId ) {
|
||
els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
|
||
if ( els2.length ) {
|
||
els = (els || []).concat(els2);
|
||
}
|
||
}
|
||
|
||
if (!els || !els.length) {
|
||
return a;
|
||
}
|
||
|
||
var i,j,n,v,el,max,jmax;
|
||
for(i=0, max=els.length; i < max; i++) {
|
||
el = els[i];
|
||
n = el.name;
|
||
if (!n || el.disabled) {
|
||
continue;
|
||
}
|
||
|
||
if (semantic && form.clk && el.type == "image") {
|
||
// handle image inputs on the fly when semantic == true
|
||
if(form.clk == el) {
|
||
a.push({name: n, value: $(el).val(), type: el.type });
|
||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||
}
|
||
continue;
|
||
}
|
||
|
||
v = $.fieldValue(el, true);
|
||
if (v && v.constructor == Array) {
|
||
if (elements) {
|
||
elements.push(el);
|
||
}
|
||
for(j=0, jmax=v.length; j < jmax; j++) {
|
||
a.push({name: n, value: v[j]});
|
||
}
|
||
}
|
||
else if (feature.fileapi && el.type == 'file') {
|
||
if (elements) {
|
||
elements.push(el);
|
||
}
|
||
var files = el.files;
|
||
if (files.length) {
|
||
for (j=0; j < files.length; j++) {
|
||
a.push({name: n, value: files[j], type: el.type});
|
||
}
|
||
}
|
||
else {
|
||
// #180
|
||
a.push({ name: n, value: '', type: el.type });
|
||
}
|
||
}
|
||
else if (v !== null && typeof v != 'undefined') {
|
||
if (elements) {
|
||
elements.push(el);
|
||
}
|
||
a.push({name: n, value: v, type: el.type, required: el.required});
|
||
}
|
||
}
|
||
|
||
if (!semantic && form.clk) {
|
||
// input type=='image' are not found in elements array! handle it here
|
||
var $input = $(form.clk), input = $input[0];
|
||
n = input.name;
|
||
if (n && !input.disabled && input.type == 'image') {
|
||
a.push({name: n, value: $input.val()});
|
||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||
}
|
||
}
|
||
return a;
|
||
};
|
||
|
||
/**
|
||
* Serializes form data into a 'submittable' string. This method will return a string
|
||
* in the format: name1=value1&name2=value2
|
||
*/
|
||
$.fn.formSerialize = function(semantic) {
|
||
//hand off to jQuery.param for proper encoding
|
||
return $.param(this.formToArray(semantic));
|
||
};
|
||
|
||
/**
|
||
* Serializes all field elements in the jQuery object into a query string.
|
||
* This method will return a string in the format: name1=value1&name2=value2
|
||
*/
|
||
$.fn.fieldSerialize = function(successful) {
|
||
var a = [];
|
||
this.each(function() {
|
||
var n = this.name;
|
||
if (!n) {
|
||
return;
|
||
}
|
||
var v = $.fieldValue(this, successful);
|
||
if (v && v.constructor == Array) {
|
||
for (var i=0,max=v.length; i < max; i++) {
|
||
a.push({name: n, value: v[i]});
|
||
}
|
||
}
|
||
else if (v !== null && typeof v != 'undefined') {
|
||
a.push({name: this.name, value: v});
|
||
}
|
||
});
|
||
//hand off to jQuery.param for proper encoding
|
||
return $.param(a);
|
||
};
|
||
|
||
/**
|
||
* Returns the value(s) of the element in the matched set. For example, consider the following form:
|
||
*
|
||
* <form><fieldset>
|
||
* <input name="A" type="text" />
|
||
* <input name="A" type="text" />
|
||
* <input name="B" type="checkbox" value="B1" />
|
||
* <input name="B" type="checkbox" value="B2"/>
|
||
* <input name="C" type="radio" value="C1" />
|
||
* <input name="C" type="radio" value="C2" />
|
||
* </fieldset></form>
|
||
*
|
||
* var v = $('input[type=text]').fieldValue();
|
||
* // if no values are entered into the text inputs
|
||
* v == ['','']
|
||
* // if values entered into the text inputs are 'foo' and 'bar'
|
||
* v == ['foo','bar']
|
||
*
|
||
* var v = $('input[type=checkbox]').fieldValue();
|
||
* // if neither checkbox is checked
|
||
* v === undefined
|
||
* // if both checkboxes are checked
|
||
* v == ['B1', 'B2']
|
||
*
|
||
* var v = $('input[type=radio]').fieldValue();
|
||
* // if neither radio is checked
|
||
* v === undefined
|
||
* // if first radio is checked
|
||
* v == ['C1']
|
||
*
|
||
* The successful argument controls whether or not the field element must be 'successful'
|
||
* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
|
||
* The default value of the successful argument is true. If this value is false the value(s)
|
||
* for each element is returned.
|
||
*
|
||
* Note: This method *always* returns an array. If no valid value can be determined the
|
||
* array will be empty, otherwise it will contain one or more values.
|
||
*/
|
||
$.fn.fieldValue = function(successful) {
|
||
for (var val=[], i=0, max=this.length; i < max; i++) {
|
||
var el = this[i];
|
||
var v = $.fieldValue(el, successful);
|
||
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
|
||
continue;
|
||
}
|
||
if (v.constructor == Array) {
|
||
$.merge(val, v);
|
||
}
|
||
else {
|
||
val.push(v);
|
||
}
|
||
}
|
||
return val;
|
||
};
|
||
|
||
/**
|
||
* Returns the value of the field element.
|
||
*/
|
||
$.fieldValue = function(el, successful) {
|
||
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
||
if (successful === undefined) {
|
||
successful = true;
|
||
}
|
||
|
||
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
||
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
||
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
||
tag == 'select' && el.selectedIndex == -1)) {
|
||
return null;
|
||
}
|
||
|
||
if (tag == 'select') {
|
||
var index = el.selectedIndex;
|
||
if (index < 0) {
|
||
return null;
|
||
}
|
||
var a = [], ops = el.options;
|
||
var one = (t == 'select-one');
|
||
var max = (one ? index+1 : ops.length);
|
||
for(var i=(one ? index : 0); i < max; i++) {
|
||
var op = ops[i];
|
||
if (op.selected) {
|
||
var v = op.value;
|
||
if (!v) { // extra pain for IE...
|
||
v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
|
||
}
|
||
if (one) {
|
||
return v;
|
||
}
|
||
a.push(v);
|
||
}
|
||
}
|
||
return a;
|
||
}
|
||
return $(el).val();
|
||
};
|
||
|
||
/**
|
||
* Clears the form data. Takes the following actions on the form's input fields:
|
||
* - input text fields will have their 'value' property set to the empty string
|
||
* - select elements will have their 'selectedIndex' property set to -1
|
||
* - checkbox and radio inputs will have their 'checked' property set to false
|
||
* - inputs of type submit, button, reset, and hidden will *not* be effected
|
||
* - button elements will *not* be effected
|
||
*/
|
||
$.fn.clearForm = function(includeHidden) {
|
||
return this.each(function() {
|
||
$('input,select,textarea', this).clearFields(includeHidden);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Clears the selected form elements.
|
||
*/
|
||
$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
|
||
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 (re.test(t) || tag == 'textarea') {
|
||
this.value = '';
|
||
}
|
||
else if (t == 'checkbox' || t == 'radio') {
|
||
this.checked = false;
|
||
}
|
||
else if (tag == 'select') {
|
||
this.selectedIndex = -1;
|
||
}
|
||
else if (t == "file") {
|
||
if (/MSIE/.test(navigator.userAgent)) {
|
||
$(this).replaceWith($(this).clone(true));
|
||
} else {
|
||
$(this).val('');
|
||
}
|
||
}
|
||
else if (includeHidden) {
|
||
// includeHidden can be the value true, or it can be a selector string
|
||
// indicating a special test; for example:
|
||
// $('#myForm').clearForm('.special:hidden')
|
||
// the above would clean hidden inputs that have the class of 'special'
|
||
if ( (includeHidden === true && /hidden/.test(t)) ||
|
||
(typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
|
||
this.value = '';
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Resets the form data. Causes all form elements to be reset to their original value.
|
||
*/
|
||
$.fn.resetForm = function() {
|
||
return this.each(function() {
|
||
// guard against an input with the name of 'reset'
|
||
// note that IE reports the reset function as an 'object'
|
||
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
|
||
this.reset();
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Enables or disables any matching elements.
|
||
*/
|
||
$.fn.enable = function(b) {
|
||
if (b === undefined) {
|
||
b = true;
|
||
}
|
||
return this.each(function() {
|
||
this.disabled = !b;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Checks/unchecks any matching checkboxes or radio buttons and
|
||
* selects/deselects and matching option elements.
|
||
*/
|
||
$.fn.selected = function(select) {
|
||
if (select === undefined) {
|
||
select = true;
|
||
}
|
||
return this.each(function() {
|
||
var t = this.type;
|
||
if (t == 'checkbox' || t == 'radio') {
|
||
this.checked = select;
|
||
}
|
||
else if (this.tagName.toLowerCase() == 'option') {
|
||
var $sel = $(this).parent('select');
|
||
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
||
// deselect all other options
|
||
$sel.find('option').selected(false);
|
||
}
|
||
this.selected = select;
|
||
}
|
||
});
|
||
};
|
||
|
||
// expose debug var
|
||
$.fn.ajaxSubmit.debug = false;
|
||
|
||
// helper fn for console logging
|
||
function log() {
|
||
if (!$.fn.ajaxSubmit.debug) {
|
||
return;
|
||
}
|
||
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);
|
||
}
|
||
}
|
||
|
||
}));
|
||
;/*
|
||
Copyright (c) 2011 Oscar Godson ( http://oscargodson.com ) and Sebastian Nitu ( http://sebnitu.com )
|
||
|
||
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.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
THE SOFTWARE.
|
||
|
||
More infomation on http://oscargodson.com/labs/jkey
|
||
or fork it at https://github.com/OscarGodson/jKey
|
||
|
||
Special thanks to Macy Abbey
|
||
*/
|
||
(function($) {
|
||
$.fn.jkey = function(keyCombo,options,callback) {
|
||
// Save the key codes to JSON object
|
||
var keyCodes = {
|
||
/* start the a-z keys */
|
||
'a' : 65,
|
||
'b' : 66,
|
||
'c' : 67,
|
||
'd' : 68,
|
||
'e' : 69,
|
||
'f' : 70,
|
||
'g' : 71,
|
||
'h' : 72,
|
||
'i' : 73,
|
||
'j' : 74,
|
||
'k' : 75,
|
||
'l' : 76,
|
||
'm' : 77,
|
||
'n' : 78,
|
||
'o' : 79,
|
||
'p' : 80,
|
||
'q' : 81,
|
||
'r' : 82,
|
||
's' : 83,
|
||
't' : 84,
|
||
'u' : 85,
|
||
'v' : 86,
|
||
'w' : 87,
|
||
'x' : 88,
|
||
'y' : 89,
|
||
'z' : 90,
|
||
/* start number keys */
|
||
'0' : 48,
|
||
'1' : 49,
|
||
'2' : 50,
|
||
'3' : 51,
|
||
'4' : 52,
|
||
'5' : 53,
|
||
'6' : 54,
|
||
'7' : 55,
|
||
'8' : 56,
|
||
'9' : 57,
|
||
/* start the f keys */
|
||
'f1' : 112,
|
||
'f2' : 113,
|
||
'f3' : 114,
|
||
'f4' : 115,
|
||
'f5' : 116,
|
||
'f6' : 117,
|
||
'f7' : 118,
|
||
'f8' : 119,
|
||
'f9' : 120,
|
||
'f10': 121,
|
||
'f11': 122,
|
||
'f12': 123,
|
||
/* start the modifier keys */
|
||
'shift' : 16,
|
||
'ctrl' : 17,
|
||
'control' : 17,
|
||
'alt' : 18,
|
||
'option' : 18, //Mac OS key
|
||
'opt' : 18, //Mac OS key
|
||
'cmd' : 224, //Mac OS key
|
||
'command' : 224, //Mac OS key
|
||
'fn' : 255, //tested on Lenovo ThinkPad
|
||
'function' : 255, //tested on Lenovo ThinkPad
|
||
/* Misc. Keys */
|
||
'backspace' : 8,
|
||
'osxdelete' : 8, //Mac OS version of backspace
|
||
'enter' : 13,
|
||
'return' : 13, //Mac OS version of "enter"
|
||
'space':32,
|
||
'spacebar':32,
|
||
'esc':27,
|
||
'escape':27,
|
||
'tab':9,
|
||
'capslock':20,
|
||
'capslk':20,
|
||
'super':91,
|
||
'windows':91,
|
||
'insert':45,
|
||
'delete':46, //NOT THE OS X DELETE KEY!
|
||
'home':36,
|
||
'end':35,
|
||
'pgup':33,
|
||
'pageup':33,
|
||
'pgdn':34,
|
||
'pagedown':34,
|
||
/* Arrow keys */
|
||
'left' : 37,
|
||
'up' : 38,
|
||
'right': 39,
|
||
'down' : 40,
|
||
/* Special char keys */
|
||
'`':96,
|
||
'~':96,
|
||
'-':45,
|
||
'_':45,
|
||
'=':187,
|
||
'+':187,
|
||
'[':219,
|
||
'{':219,
|
||
']':221,
|
||
'}':221,
|
||
'\\':220, //it's actually a \ but there's two to escape the original
|
||
'|':220,
|
||
';':59,
|
||
':':59,
|
||
"'":222,
|
||
'"':222,
|
||
',':188,
|
||
'<':188,
|
||
'.':190,
|
||
'>':190,
|
||
'/':191,
|
||
'?':191
|
||
};
|
||
|
||
var x = '';
|
||
var y = '';
|
||
if(typeof options == 'function' && typeof callback == 'undefined'){
|
||
callback = options;
|
||
options = false;
|
||
}
|
||
|
||
//IE has issues here... so, we "convert" toString() :(
|
||
if(keyCombo.toString().indexOf(',') > -1){ //If multiple keys are selected
|
||
var keySplit = keyCombo.match(/[a-zA-Z0-9]+/gi);
|
||
}
|
||
else { //Else just store this single key
|
||
var keySplit = [keyCombo];
|
||
}
|
||
for(x in keySplit){ //For each key in the array...
|
||
if(!keySplit.hasOwnProperty(x)) { continue; }
|
||
//Same as above for the toString() and IE
|
||
if(keySplit[x].toString().indexOf('+') > -1){
|
||
//Key selection by user is a key combo
|
||
// Create a combo array and split the key combo
|
||
var combo = [];
|
||
var comboSplit = keySplit[x].split('+');
|
||
// Save the key codes for each element in the key combo
|
||
for(y in comboSplit){
|
||
combo[y] = keyCodes[ comboSplit[y] ];
|
||
}
|
||
keySplit[x] = combo;
|
||
}
|
||
else {
|
||
//Otherwise, it's just a normal, single key command
|
||
keySplit[x] = keyCodes[ keySplit[x] ];
|
||
}
|
||
}
|
||
|
||
function swapJsonKeyValues(input) {
|
||
var one, output = {};
|
||
for (one in input) {
|
||
if (input.hasOwnProperty(one)) {
|
||
output[input[one]] = one;
|
||
}
|
||
}
|
||
return output;
|
||
}
|
||
|
||
var keyCodesSwitch = swapJsonKeyValues(keyCodes);
|
||
|
||
return this.each(function() {
|
||
$this = $(this);
|
||
|
||
// Create active keys array
|
||
// This array will store all the keys that are currently being pressed
|
||
var activeKeys = [];
|
||
$this.bind('keydown',function(e){
|
||
// Save the current key press
|
||
activeKeys[ e.keyCode ] = e.keyCode;
|
||
|
||
if($.inArray(e.keyCode, keySplit) > -1){ // If the key the user pressed is matched with any key the developer set a key code with...
|
||
if(typeof callback == 'function'){ //and they provided a callback function
|
||
callback.call(this, keyCodesSwitch[e.keyCode] ); //trigger call back and...
|
||
if(options === false){
|
||
e.preventDefault(); //cancel the normal
|
||
}
|
||
}
|
||
}
|
||
else { // Else, the key did not match which means it's either a key combo or just dosn't exist
|
||
// Check if the individual items in the key combo match what was pressed
|
||
for(x in keySplit){
|
||
if($.inArray(e.keyCode, keySplit[x]) > -1){
|
||
// Initiate the active variable
|
||
var active = 'unchecked';
|
||
|
||
// All the individual keys in the combo with the keys that are currently being pressed
|
||
for(y in keySplit[x]) {
|
||
if(active != false) {
|
||
if($.inArray(keySplit[x][y], activeKeys) > -1){
|
||
active = true;
|
||
}
|
||
else {
|
||
active = false;
|
||
}
|
||
}
|
||
}
|
||
// If all the keys in the combo are being pressed, active will equal true
|
||
if(active === true){
|
||
if(typeof callback == 'function'){ //and they provided a callback function
|
||
|
||
var activeString = '';
|
||
|
||
for(var z in activeKeys) {
|
||
if (activeKeys[z] != '') {
|
||
activeString += keyCodesSwitch[ activeKeys[z] ] + '+';
|
||
}
|
||
}
|
||
activeString = activeString.substring(0, activeString.length - 1);
|
||
callback.call(this, activeString ); //trigger call back and...
|
||
if(options === false){
|
||
e.preventDefault(); //cancel the normal
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} // end of if in array
|
||
}).bind('keyup',function(e) {
|
||
// Remove the current key press
|
||
activeKeys[ e.keyCode ] = '';
|
||
});
|
||
});
|
||
}
|
||
})(jQuery);;/*
|
||
* Metadata - jQuery plugin for parsing metadata from elements
|
||
*
|
||
* Copyright (c) 2006 John Resig, Yehuda Katz, J<>örn Zaefferer, Paul McLanahan
|
||
*
|
||
* Dual licensed under the MIT and GPL licenses:
|
||
* http://www.opensource.org/licenses/mit-license.php
|
||
* http://www.gnu.org/licenses/gpl.html
|
||
*
|
||
* Revision: $Id: jquery.metadata.js 4187 2007-12-16 17:15:27Z joern.zaefferer $
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
|
||
* in the JSON will become a property of the element itself.
|
||
*
|
||
* There are three supported types of metadata storage:
|
||
*
|
||
* attr: Inside an attribute. The name parameter indicates *which* attribute.
|
||
*
|
||
* class: Inside the class attribute, wrapped in curly braces: { }
|
||
*
|
||
* elem: Inside a child element (e.g. a script tag). The
|
||
* name parameter indicates *which* element.
|
||
*
|
||
* The metadata for an element is loaded the first time the element is accessed via jQuery.
|
||
*
|
||
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
|
||
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
|
||
*
|
||
* @name $.metadata.setType
|
||
*
|
||
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
|
||
* @before $.metadata.setType("class")
|
||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||
* @desc Reads metadata from the class attribute
|
||
*
|
||
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
|
||
* @before $.metadata.setType("attr", "data")
|
||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||
* @desc Reads metadata from a "data" attribute
|
||
*
|
||
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
|
||
* @before $.metadata.setType("elem", "script")
|
||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||
* @desc Reads metadata from a nested script element
|
||
*
|
||
* @param String type The encoding type
|
||
* @param String name The name of the attribute to be used to get metadata (optional)
|
||
* @cat Plugins/Metadata
|
||
* @descr Sets the type of encoding to be used when loading metadata for the first time
|
||
* @type undefined
|
||
* @see metadata()
|
||
*/
|
||
|
||
(function($) {
|
||
|
||
$.extend({
|
||
metadata : {
|
||
defaults : {
|
||
type: 'class',
|
||
name: 'metadata',
|
||
cre: /({.*})/,
|
||
single: 'metadata'
|
||
},
|
||
setType: function( type, name ){
|
||
this.defaults.type = type;
|
||
this.defaults.name = name;
|
||
},
|
||
get: function( elem, opts ){
|
||
var settings = $.extend({},this.defaults,opts);
|
||
// check for empty string in single property
|
||
if ( !settings.single.length ) settings.single = 'metadata';
|
||
|
||
var data = $.data(elem, settings.single);
|
||
// returned cached data if it already exists
|
||
if ( data ) return data;
|
||
|
||
data = "{}";
|
||
|
||
if ( settings.type == "class" ) {
|
||
var m = settings.cre.exec( elem.className );
|
||
if ( m )
|
||
data = m[1];
|
||
} else if ( settings.type == "elem" ) {
|
||
if( !elem.getElementsByTagName )
|
||
return undefined;
|
||
var e = elem.getElementsByTagName(settings.name);
|
||
if ( e.length )
|
||
data = $.trim(e[0].innerHTML);
|
||
} else if ( elem.getAttribute != undefined ) {
|
||
var attr = elem.getAttribute( settings.name );
|
||
if ( attr )
|
||
data = attr;
|
||
}
|
||
|
||
if ( data.indexOf( '{' ) <0 )
|
||
data = "{" + data + "}";
|
||
|
||
data = eval("(" + data + ")");
|
||
|
||
$.data( elem, settings.single, data );
|
||
return data;
|
||
}
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Returns the metadata object for the first member of the jQuery object.
|
||
*
|
||
* @name metadata
|
||
* @descr Returns element's metadata object
|
||
* @param Object opts An object contianing settings to override the defaults
|
||
* @type jQuery
|
||
* @cat Plugins/Metadata
|
||
*/
|
||
$.fn.metadata = function( opts ){
|
||
return $.metadata.get( this[0], opts );
|
||
};
|
||
|
||
})(jQuery);;/*! TableSorter (FORK) v{{version}} *//*
|
||
* Client-side table sorting with ease!
|
||
* @requires jQuery v1.2.6+
|
||
*
|
||
* Copyright (c) 2007 Christian Bach
|
||
* fork maintained by Rob Garrison
|
||
*
|
||
* Examples and docs at: http://tablesorter.com
|
||
* Dual licensed under the MIT and GPL licenses:
|
||
* http://www.opensource.org/licenses/mit-license.php
|
||
* http://www.gnu.org/licenses/gpl.html
|
||
*
|
||
* @type jQuery
|
||
* @name tablesorter (FORK)
|
||
* @cat Plugins/Tablesorter
|
||
* @author Christian Bach - christian.bach@polyester.se
|
||
* @contributor Rob Garrison - https://github.com/Mottie/tablesorter
|
||
*/
|
||
/*jshint browser:true, jquery:true, unused:false, expr: true */
|
||
/*global console:false, alert:false, require:false, define:false, module:false */
|
||
(function(factory) {
|
||
if (typeof define === 'function' && define.amd) {
|
||
define(['jquery'], factory);
|
||
} else if (typeof module === 'object' && typeof module.exports === 'object') {
|
||
module.exports = factory(require('jquery'));
|
||
} else {
|
||
factory(jQuery);
|
||
}
|
||
}(function($) {
|
||
'use strict';
|
||
$.extend({
|
||
/*jshint supernew:true */
|
||
tablesorter: new function() {
|
||
|
||
var ts = this;
|
||
|
||
ts.version = '{{version}}';
|
||
|
||
ts.parsers = [];
|
||
ts.widgets = [];
|
||
ts.defaults = {
|
||
|
||
// *** appearance
|
||
theme : 'default', // adds tablesorter-{theme} to the table for styling
|
||
widthFixed : false, // adds colgroup to fix widths of columns
|
||
showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered.
|
||
|
||
headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> (class from cssIcon)
|
||
onRenderTemplate : null, // function(index, template){ return template; }, (template is a string)
|
||
onRenderHeader : null, // function(index){}, (nothing to return)
|
||
|
||
// *** functionality
|
||
cancelSelection : true, // prevent text selection in the header
|
||
tabIndex : true, // add tabindex to header for keyboard accessibility
|
||
dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd'
|
||
sortMultiSortKey : 'shiftKey', // key used to select additional columns
|
||
sortResetKey : 'ctrlKey', // key used to remove sorting on a column
|
||
usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89'
|
||
delayInit : false, // if false, the parsed table contents will not update until the first sort
|
||
serverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
|
||
resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
|
||
|
||
// *** sort options
|
||
headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
|
||
ignoreCase : true, // ignore case while sorting
|
||
sortForce : null, // column(s) first sorted; always applied
|
||
sortList : [], // Initial sort order; applied initially; updated when manually sorted
|
||
sortAppend : null, // column(s) sorted last; always applied
|
||
sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained
|
||
|
||
sortInitialOrder : 'asc', // sort direction on first click
|
||
sortLocaleCompare: false, // replace equivalent character (accented characters)
|
||
sortReset : false, // third click on the header will reset column to default - unsorted
|
||
sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
|
||
|
||
emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
|
||
stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero
|
||
textExtraction : 'basic', // text extraction method/function - function(node, table, cellIndex){}
|
||
textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function)
|
||
textSorter : null, // choose overall or specific column sorter function(a, b, direction, table, columnIndex) [alt: ts.sortText]
|
||
numberSorter : null, // choose overall numeric sorter function(a, b, direction, maxColumnValue)
|
||
|
||
// *** widget options
|
||
widgets: [], // method to add widgets, e.g. widgets: ['zebra']
|
||
widgetOptions : {
|
||
zebra : [ 'even', 'odd' ] // zebra widget alternating row class names
|
||
},
|
||
initWidgets : true, // apply widgets on tablesorter initialization
|
||
widgetClass : 'widget-{name}', // table class name template to match to include a widget
|
||
|
||
// *** callbacks
|
||
initialized : null, // function(table){},
|
||
|
||
// *** extra css class names
|
||
tableClass : '',
|
||
cssAsc : '',
|
||
cssDesc : '',
|
||
cssNone : '',
|
||
cssHeader : '',
|
||
cssHeaderRow : '',
|
||
cssProcessing : '', // processing icon applied to header during sort/filter
|
||
|
||
cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent
|
||
cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate
|
||
cssIconNone : '', // class name added to the icon when there is no column sort
|
||
cssIconAsc : '', // class name added to the icon when the column has an ascending sort
|
||
cssIconDesc : '', // class name added to the icon when the column has a descending sort
|
||
cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!)
|
||
cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort
|
||
cssIgnoreRow : 'tablesorter-ignoreRow', // header row to ignore; cells within this row will not be added to c.$headers
|
||
|
||
// *** selectors
|
||
selectorHeaders : '> thead th, > thead td',
|
||
selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
|
||
selectorRemove : '.remove-me',
|
||
|
||
// *** advanced
|
||
debug : false,
|
||
|
||
// *** Internal variables
|
||
headerList: [],
|
||
empties: {},
|
||
strings: {},
|
||
parsers: []
|
||
|
||
// removed: widgetZebra: { css: ['even', 'odd'] }
|
||
|
||
};
|
||
|
||
// internal css classes - these will ALWAYS be added to
|
||
// the table and MUST only contain one class name - fixes #381
|
||
ts.css = {
|
||
table : 'tablesorter',
|
||
cssHasChild: 'tablesorter-hasChildRow',
|
||
childRow : 'tablesorter-childRow',
|
||
colgroup : 'tablesorter-colgroup',
|
||
header : 'tablesorter-header',
|
||
headerRow : 'tablesorter-headerRow',
|
||
headerIn : 'tablesorter-header-inner',
|
||
icon : 'tablesorter-icon',
|
||
processing : 'tablesorter-processing',
|
||
sortAsc : 'tablesorter-headerAsc',
|
||
sortDesc : 'tablesorter-headerDesc',
|
||
sortNone : 'tablesorter-headerUnSorted'
|
||
};
|
||
|
||
// labels applied to sortable headers for accessibility (aria) support
|
||
ts.language = {
|
||
sortAsc : 'Ascending sort applied, ',
|
||
sortDesc : 'Descending sort applied, ',
|
||
sortNone : 'No sort applied, ',
|
||
nextAsc : 'activate to apply an ascending sort',
|
||
nextDesc : 'activate to apply a descending sort',
|
||
nextNone : 'activate to remove the sort'
|
||
};
|
||
|
||
/* debuging utils */
|
||
function log() {
|
||
var a = arguments[0],
|
||
s = arguments.length > 1 ? Array.prototype.slice.call(arguments) : a;
|
||
if (typeof console !== 'undefined' && typeof console.log !== 'undefined') {
|
||
console[ /error/i.test(a) ? 'error' : /warn/i.test(a) ? 'warn' : 'log' ](s);
|
||
} else {
|
||
alert(s);
|
||
}
|
||
}
|
||
|
||
function benchmark(s, d) {
|
||
log(s + ' (' + (new Date().getTime() - d.getTime()) + 'ms)');
|
||
}
|
||
|
||
ts.log = log;
|
||
ts.benchmark = benchmark;
|
||
|
||
// $.isEmptyObject from jQuery v1.4
|
||
function isEmptyObject(obj) {
|
||
/*jshint forin: false */
|
||
for (var name in obj) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
ts.getElementText = function(c, node, cellIndex) {
|
||
if (!node) { return ''; }
|
||
var te,
|
||
t = c.textExtraction || '',
|
||
// node could be a jquery object
|
||
// http://jsperf.com/jquery-vs-instanceof-jquery/2
|
||
$node = node.jquery ? node : $(node);
|
||
if (typeof(t) === 'string') {
|
||
// check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
|
||
return $.trim( ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) || $node.text() || '' );
|
||
} else {
|
||
if (typeof(t) === 'function') {
|
||
return $.trim( t($node[0], c.table, cellIndex) );
|
||
} else if (typeof (te = ts.getColumnData( c.table, t, cellIndex )) === 'function') {
|
||
return $.trim( te($node[0], c.table, cellIndex) );
|
||
}
|
||
}
|
||
// fallback
|
||
return $.trim( $node[0].textContent || $node.text() || '' );
|
||
};
|
||
|
||
function detectParserForColumn(table, rows, rowIndex, cellIndex) {
|
||
var cur, $node,
|
||
c = table.config,
|
||
i = ts.parsers.length,
|
||
node = false,
|
||
nodeValue = '',
|
||
keepLooking = true;
|
||
while (nodeValue === '' && keepLooking) {
|
||
rowIndex++;
|
||
if (rows[rowIndex]) {
|
||
node = rows[rowIndex].cells[cellIndex];
|
||
nodeValue = ts.getElementText(c, node, cellIndex);
|
||
$node = $(node);
|
||
if (table.config.debug) {
|
||
log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"');
|
||
}
|
||
} else {
|
||
keepLooking = false;
|
||
}
|
||
}
|
||
while (--i >= 0) {
|
||
cur = ts.parsers[i];
|
||
// ignore the default text parser because it will always be true
|
||
if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, table, node, $node)) {
|
||
return cur;
|
||
}
|
||
}
|
||
// nothing found, return the generic parser (text)
|
||
return ts.getParserById('text');
|
||
}
|
||
|
||
function buildParserCache(table) {
|
||
var c = table.config,
|
||
// update table bodies in case we start with an empty table
|
||
tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'),
|
||
rows, list, l, i, h, ch, np, p, e, time,
|
||
j = 0,
|
||
parsersDebug = '',
|
||
len = tb.length;
|
||
if ( len === 0) {
|
||
return c.debug ? log('Warning: *Empty table!* Not building a parser cache') : '';
|
||
} else if (c.debug) {
|
||
time = new Date();
|
||
log('Detecting parsers for each column');
|
||
}
|
||
list = {
|
||
extractors: [],
|
||
parsers: []
|
||
};
|
||
while (j < len) {
|
||
rows = tb[j].rows;
|
||
if (rows.length) {
|
||
l = c.columns; // rows[j].cells.length;
|
||
for (i = 0; i < l; i++) {
|
||
h = c.$headers.filter('[data-column="' + i + '"]:last');
|
||
// get column indexed table cell
|
||
ch = ts.getColumnData( table, c.headers, i );
|
||
// get column parser/extractor
|
||
e = ts.getParserById( ts.getData(h, ch, 'extractor') );
|
||
p = ts.getParserById( ts.getData(h, ch, 'sorter') );
|
||
np = ts.getData(h, ch, 'parser') === 'false';
|
||
// empty cells behaviour - keeping emptyToBottom for backwards compatibility
|
||
c.empties[i] = ( ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase();
|
||
// text strings behaviour in numerical sorts
|
||
c.strings[i] = ( ts.getData(h, ch, 'string') || c.stringTo || 'max' ).toLowerCase();
|
||
if (np) {
|
||
p = ts.getParserById('no-parser');
|
||
}
|
||
if (!e) {
|
||
// For now, maybe detect someday
|
||
e = false;
|
||
}
|
||
if (!p) {
|
||
p = detectParserForColumn(table, rows, -1, i);
|
||
}
|
||
if (c.debug) {
|
||
parsersDebug += 'column:' + i + '; extractor:' + e.id + '; parser:' + p.id + '; string:' + c.strings[i] + '; empty: ' + c.empties[i] + '\n';
|
||
}
|
||
list.parsers[i] = p;
|
||
list.extractors[i] = e;
|
||
}
|
||
}
|
||
j += (list.parsers.length) ? len : 1;
|
||
}
|
||
if (c.debug) {
|
||
log(parsersDebug ? parsersDebug : 'No parsers detected');
|
||
benchmark('Completed detecting parsers', time);
|
||
}
|
||
c.parsers = list.parsers;
|
||
c.extractors = list.extractors;
|
||
}
|
||
|
||
/* utils */
|
||
function buildCache(table) {
|
||
var cc, t, tx, v, i, j, k, $row, cols, cacheTime,
|
||
totalRows, rowData, colMax,
|
||
c = table.config,
|
||
$tb = c.$tbodies,
|
||
extractors = c.extractors,
|
||
parsers = c.parsers;
|
||
c.cache = {};
|
||
c.totalRows = 0;
|
||
// if no parsers found, return - it's an empty table.
|
||
if (!parsers) {
|
||
return c.debug ? log('Warning: *Empty table!* Not building a cache') : '';
|
||
}
|
||
if (c.debug) {
|
||
cacheTime = new Date();
|
||
}
|
||
// processing icon
|
||
if (c.showProcessing) {
|
||
ts.isProcessing(table, true);
|
||
}
|
||
for (k = 0; k < $tb.length; k++) {
|
||
colMax = []; // column max value per tbody
|
||
cc = c.cache[k] = {
|
||
normalized: [] // array of normalized row data; last entry contains 'rowData' above
|
||
// colMax: # // added at the end
|
||
};
|
||
|
||
totalRows = ($tb[k] && $tb[k].rows.length) || 0;
|
||
for (i = 0; i < totalRows; ++i) {
|
||
rowData = {
|
||
// order: original row order #
|
||
// $row : jQuery Object[]
|
||
child: [], // child row text (filter widget)
|
||
raw: [] // original row text
|
||
};
|
||
/** Add the table data to main data array */
|
||
$row = $($tb[k].rows[i]);
|
||
cols = [];
|
||
// if this is a child row, add it to the last row's children and continue to the next row
|
||
// ignore child row class, if it is the first row
|
||
if ($row.hasClass(c.cssChildRow) && i !== 0) {
|
||
t = cc.normalized.length - 1;
|
||
cc.normalized[t][c.columns].$row = cc.normalized[t][c.columns].$row.add($row);
|
||
// add 'hasChild' class name to parent row
|
||
if (!$row.prev().hasClass(c.cssChildRow)) {
|
||
$row.prev().addClass(ts.css.cssHasChild);
|
||
}
|
||
// save child row content (un-parsed!)
|
||
rowData.child[t] = $.trim( $row[0].textContent || $row.text() || '' );
|
||
// go to the next for loop
|
||
continue;
|
||
}
|
||
rowData.$row = $row;
|
||
rowData.order = i; // add original row position to rowCache
|
||
for (j = 0; j < c.columns; ++j) {
|
||
if (typeof parsers[j] === 'undefined') {
|
||
if (c.debug) {
|
||
log('No parser found for cell:', $row[0].cells[j], 'does it have a header?');
|
||
}
|
||
continue;
|
||
}
|
||
t = ts.getElementText(c, $row[0].cells[j], j);
|
||
rowData.raw.push(t); // save original row text
|
||
// do extract before parsing if there is one
|
||
if (typeof extractors[j].id === 'undefined') {
|
||
tx = t;
|
||
} else {
|
||
tx = extractors[j].format(t, table, $row[0].cells[j], j);
|
||
}
|
||
// allow parsing if the string is empty, previously parsing would change it to zero,
|
||
// in case the parser needs to extract data from the table cell attributes
|
||
v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(tx, table, $row[0].cells[j], j);
|
||
cols.push( c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v );
|
||
if ((parsers[j].type || '').toLowerCase() === 'numeric') {
|
||
// determine column max value (ignore sign)
|
||
colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0);
|
||
}
|
||
}
|
||
// ensure rowData is always in the same location (after the last column)
|
||
cols[c.columns] = rowData;
|
||
cc.normalized.push(cols);
|
||
}
|
||
cc.colMax = colMax;
|
||
// total up rows, not including child rows
|
||
c.totalRows += cc.normalized.length;
|
||
|
||
}
|
||
if (c.showProcessing) {
|
||
ts.isProcessing(table); // remove processing icon
|
||
}
|
||
if (c.debug) {
|
||
benchmark('Building cache for ' + totalRows + ' rows', cacheTime);
|
||
}
|
||
}
|
||
|
||
// init flag (true) used by pager plugin to prevent widget application
|
||
function appendToTable(table, init) {
|
||
var c = table.config,
|
||
wo = c.widgetOptions,
|
||
$tbodies = c.$tbodies,
|
||
rows = [],
|
||
cc = c.cache,
|
||
n, totalRows, $bk, $tb,
|
||
i, k, appendTime;
|
||
// empty table - fixes #206/#346
|
||
if (isEmptyObject(cc)) {
|
||
// run pager appender in case the table was just emptied
|
||
return c.appender ? c.appender(table, rows) :
|
||
table.isUpdating ? c.$table.trigger('updateComplete', table) : ''; // Fixes #532
|
||
}
|
||
if (c.debug) {
|
||
appendTime = new Date();
|
||
}
|
||
for (k = 0; k < $tbodies.length; k++) {
|
||
$bk = $tbodies.eq(k);
|
||
if ($bk.length) {
|
||
// get tbody
|
||
$tb = ts.processTbody(table, $bk, true);
|
||
n = cc[k].normalized;
|
||
totalRows = n.length;
|
||
for (i = 0; i < totalRows; i++) {
|
||
rows.push(n[i][c.columns].$row);
|
||
// removeRows used by the pager plugin; don't render if using ajax - fixes #411
|
||
if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) {
|
||
$tb.append(n[i][c.columns].$row);
|
||
}
|
||
}
|
||
// restore tbody
|
||
ts.processTbody(table, $tb, false);
|
||
}
|
||
}
|
||
if (c.appender) {
|
||
c.appender(table, rows);
|
||
}
|
||
if (c.debug) {
|
||
benchmark('Rebuilt table', appendTime);
|
||
}
|
||
// apply table widgets; but not before ajax completes
|
||
if (!init && !c.appender) { ts.applyWidget(table); }
|
||
if (table.isUpdating) {
|
||
c.$table.trigger('updateComplete', table);
|
||
}
|
||
}
|
||
|
||
function formatSortingOrder(v) {
|
||
// look for 'd' in 'desc' order; return true
|
||
return (/^d/i.test(v) || v === 1);
|
||
}
|
||
|
||
function buildHeaders(table) {
|
||
var ch, $t,
|
||
h, i, t, lock, time,
|
||
c = table.config;
|
||
c.headerList = [];
|
||
c.headerContent = [];
|
||
if (c.debug) {
|
||
time = new Date();
|
||
}
|
||
// children tr in tfoot - see issue #196 & #547
|
||
c.columns = ts.computeColumnIndex( c.$table.children('thead, tfoot').children('tr') );
|
||
// add icon if cssIcon option exists
|
||
i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : '';
|
||
// redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
|
||
c.$headers = $( $.map( $(table).find(c.selectorHeaders), function(elem, index) {
|
||
$t = $(elem);
|
||
// ignore cell (don't add it to c.$headers) if row has ignoreRow class
|
||
if ($t.parent().hasClass(c.cssIgnoreRow)) { return; }
|
||
// make sure to get header cell & not column indexed cell
|
||
ch = ts.getColumnData( table, c.headers, index, true );
|
||
// save original header content
|
||
c.headerContent[index] = $t.html();
|
||
// if headerTemplate is empty, don't reformat the header cell
|
||
if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) {
|
||
// set up header template
|
||
t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i);
|
||
if (c.onRenderTemplate) {
|
||
h = c.onRenderTemplate.apply($t, [index, t]);
|
||
if (h && typeof h === 'string') { t = h; } // only change t if something is returned
|
||
}
|
||
$t.html('<div class="' + ts.css.headerIn + '">' + t + '</div>'); // faster than wrapInner
|
||
}
|
||
if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index, c, c.$table]); }
|
||
// *** remove this.column value if no conflicts found
|
||
elem.column = parseInt( $t.attr('data-column'), 10);
|
||
elem.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2];
|
||
elem.count = -1; // set to -1 because clicking on the header automatically adds one
|
||
elem.lockedOrder = false;
|
||
lock = ts.getData($t, ch, 'lockedOrder') || false;
|
||
if (typeof lock !== 'undefined' && lock !== false) {
|
||
elem.order = elem.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0];
|
||
}
|
||
$t.addClass(ts.css.header + ' ' + c.cssHeader);
|
||
// add cell to headerList
|
||
c.headerList[index] = elem;
|
||
// add to parent in case there are multiple rows
|
||
$t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow).attr('role', 'row');
|
||
// allow keyboard cursor to focus on element
|
||
if (c.tabIndex) { $t.attr('tabindex', 0); }
|
||
return elem;
|
||
}));
|
||
$(table).find(c.selectorHeaders).attr({
|
||
scope: 'col',
|
||
role : 'columnheader'
|
||
});
|
||
// enable/disable sorting
|
||
updateHeader(table);
|
||
if (c.debug) {
|
||
benchmark('Built headers:', time);
|
||
log(c.$headers);
|
||
}
|
||
}
|
||
|
||
function commonUpdate(table, resort, callback) {
|
||
var c = table.config;
|
||
// remove rows/elements before update
|
||
c.$table.find(c.selectorRemove).remove();
|
||
// rebuild parsers
|
||
buildParserCache(table);
|
||
// rebuild the cache map
|
||
buildCache(table);
|
||
checkResort(c, resort, callback);
|
||
}
|
||
|
||
function updateHeader(table) {
|
||
var s, $th, col,
|
||
c = table.config;
|
||
c.$headers.each(function(index, th){
|
||
$th = $(th);
|
||
col = ts.getColumnData( table, c.headers, index, true );
|
||
// add 'sorter-false' class if 'parser-false' is set
|
||
s = ts.getData( th, col, 'sorter' ) === 'false' || ts.getData( th, col, 'parser' ) === 'false';
|
||
th.sortDisabled = s;
|
||
$th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s);
|
||
// aria-controls - requires table ID
|
||
if (table.id) {
|
||
if (s) {
|
||
$th.removeAttr('aria-controls');
|
||
} else {
|
||
$th.attr('aria-controls', table.id);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function setHeadersCss(table) {
|
||
var f, i, j,
|
||
c = table.config,
|
||
list = c.sortList,
|
||
len = list.length,
|
||
none = ts.css.sortNone + ' ' + c.cssNone,
|
||
css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc],
|
||
cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],
|
||
aria = ['ascending', 'descending'],
|
||
// find the footer
|
||
$t = $(table).find('tfoot tr').children().add(c.$extraHeaders).removeClass(css.join(' '));
|
||
// remove all header information
|
||
c.$headers
|
||
.removeClass(css.join(' '))
|
||
.addClass(none).attr('aria-sort', 'none')
|
||
.find('.' + c.cssIcon)
|
||
.removeClass(cssIcon.join(' '))
|
||
.addClass(cssIcon[2]);
|
||
for (i = 0; i < len; i++) {
|
||
// direction = 2 means reset!
|
||
if (list[i][1] !== 2) {
|
||
// multicolumn sorting updating - choose the :last in case there are nested columns
|
||
f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (len === 1 ? ':last' : '') );
|
||
if (f.length) {
|
||
for (j = 0; j < f.length; j++) {
|
||
if (!f[j].sortDisabled) {
|
||
f.eq(j)
|
||
.removeClass(none)
|
||
.addClass(css[list[i][1]])
|
||
.attr('aria-sort', aria[list[i][1]])
|
||
.find('.' + c.cssIcon)
|
||
.removeClass(cssIcon[2])
|
||
.addClass(cssIcon[list[i][1]]);
|
||
}
|
||
}
|
||
// add sorted class to footer & extra headers, if they exist
|
||
if ($t.length) {
|
||
$t.filter('[data-column="' + list[i][0] + '"]').removeClass(none).addClass(css[list[i][1]]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// add verbose aria labels
|
||
c.$headers.not('.sorter-false').each(function(){
|
||
var $this = $(this),
|
||
nextSort = this.order[(this.count + 1) % (c.sortReset ? 3 : 2)],
|
||
txt = $.trim( $this.text() ) + ': ' +
|
||
ts.language[ $this.hasClass(ts.css.sortAsc) ? 'sortAsc' : $this.hasClass(ts.css.sortDesc) ? 'sortDesc' : 'sortNone' ] +
|
||
ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
|
||
$this.attr('aria-label', txt );
|
||
});
|
||
}
|
||
|
||
function updateHeaderSortCount(table, list) {
|
||
var s, t, o, col, primary,
|
||
c = table.config,
|
||
sl = list || c.sortList;
|
||
c.sortList = [];
|
||
$.each(sl, function(i,v){
|
||
// ensure all sortList values are numeric - fixes #127
|
||
col = parseInt(v[0], 10);
|
||
// make sure header exists
|
||
o = c.$headers.filter('[data-column="' + col + '"]:last')[0];
|
||
if (o) { // prevents error if sorton array is wrong
|
||
// o.count = o.count + 1;
|
||
t = ('' + v[1]).match(/^(1|d|s|o|n)/);
|
||
t = t ? t[0] : '';
|
||
// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
|
||
switch(t) {
|
||
case '1': case 'd': // descending
|
||
t = 1;
|
||
break;
|
||
case 's': // same direction (as primary column)
|
||
// if primary sort is set to 's', make it ascending
|
||
t = primary || 0;
|
||
break;
|
||
case 'o':
|
||
s = o.order[(primary || 0) % (c.sortReset ? 3 : 2)];
|
||
// opposite of primary column; but resets if primary resets
|
||
t = s === 0 ? 1 : s === 1 ? 0 : 2;
|
||
break;
|
||
case 'n':
|
||
o.count = o.count + 1;
|
||
t = o.order[(o.count) % (c.sortReset ? 3 : 2)];
|
||
break;
|
||
default: // ascending
|
||
t = 0;
|
||
break;
|
||
}
|
||
primary = i === 0 ? t : primary;
|
||
s = [ col, parseInt(t, 10) || 0 ];
|
||
c.sortList.push(s);
|
||
t = $.inArray(s[1], o.order); // fixes issue #167
|
||
o.count = t >= 0 ? t : s[1] % (c.sortReset ? 3 : 2);
|
||
}
|
||
});
|
||
}
|
||
|
||
function getCachedSortType(parsers, i) {
|
||
return (parsers && parsers[i]) ? parsers[i].type || '' : '';
|
||
}
|
||
|
||
function initSort(table, cell, event){
|
||
if (table.isUpdating) {
|
||
// let any updates complete before initializing a sort
|
||
return setTimeout(function(){ initSort(table, cell, event); }, 50);
|
||
}
|
||
var arry, indx, col, order, s,
|
||
c = table.config,
|
||
key = !event[c.sortMultiSortKey],
|
||
$table = c.$table;
|
||
// Only call sortStart if sorting is enabled
|
||
$table.trigger('sortStart', table);
|
||
// get current column sort order
|
||
cell.count = event[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2);
|
||
// reset all sorts on non-current column - issue #30
|
||
if (c.sortRestart) {
|
||
indx = cell;
|
||
c.$headers.each(function() {
|
||
// only reset counts on columns that weren't just clicked on and if not included in a multisort
|
||
if (this !== indx && (key || !$(this).is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc))) {
|
||
this.count = -1;
|
||
}
|
||
});
|
||
}
|
||
// get current column index
|
||
indx = parseInt( $(cell).attr('data-column'), 10 );
|
||
// user only wants to sort on one column
|
||
if (key) {
|
||
// flush the sort list
|
||
c.sortList = [];
|
||
if (c.sortForce !== null) {
|
||
arry = c.sortForce;
|
||
for (col = 0; col < arry.length; col++) {
|
||
if (arry[col][0] !== indx) {
|
||
c.sortList.push(arry[col]);
|
||
}
|
||
}
|
||
}
|
||
// add column to sort list
|
||
order = cell.order[cell.count];
|
||
if (order < 2) {
|
||
c.sortList.push([indx, order]);
|
||
// add other columns if header spans across multiple
|
||
if (cell.colSpan > 1) {
|
||
for (col = 1; col < cell.colSpan; col++) {
|
||
c.sortList.push([indx + col, order]);
|
||
}
|
||
}
|
||
}
|
||
// multi column sorting
|
||
} else {
|
||
// get rid of the sortAppend before adding more - fixes issue #115 & #523
|
||
if (c.sortAppend && c.sortList.length > 1) {
|
||
for (col = 0; col < c.sortAppend.length; col++) {
|
||
s = ts.isValueInArray(c.sortAppend[col][0], c.sortList);
|
||
if (s >= 0) {
|
||
c.sortList.splice(s,1);
|
||
}
|
||
}
|
||
}
|
||
// the user has clicked on an already sorted column
|
||
if (ts.isValueInArray(indx, c.sortList) >= 0) {
|
||
// reverse the sorting direction
|
||
for (col = 0; col < c.sortList.length; col++) {
|
||
s = c.sortList[col];
|
||
order = c.$headers.filter('[data-column="' + s[0] + '"]:last')[0];
|
||
if (s[0] === indx) {
|
||
// order.count seems to be incorrect when compared to cell.count
|
||
s[1] = order.order[cell.count];
|
||
if (s[1] === 2) {
|
||
c.sortList.splice(col,1);
|
||
order.count = -1;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// add column to sort list array
|
||
order = cell.order[cell.count];
|
||
if (order < 2) {
|
||
c.sortList.push([indx, order]);
|
||
// add other columns if header spans across multiple
|
||
if (cell.colSpan > 1) {
|
||
for (col = 1; col < cell.colSpan; col++) {
|
||
c.sortList.push([indx + col, order]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (c.sortAppend !== null) {
|
||
arry = c.sortAppend;
|
||
for (col = 0; col < arry.length; col++) {
|
||
if (arry[col][0] !== indx) {
|
||
c.sortList.push(arry[col]);
|
||
}
|
||
}
|
||
}
|
||
// sortBegin event triggered immediately before the sort
|
||
$table.trigger('sortBegin', table);
|
||
// setTimeout needed so the processing icon shows up
|
||
setTimeout(function(){
|
||
// set css for headers
|
||
setHeadersCss(table);
|
||
multisort(table);
|
||
appendToTable(table);
|
||
$table.trigger('sortEnd', table);
|
||
}, 1);
|
||
}
|
||
|
||
// sort multiple columns
|
||
function multisort(table) { /*jshint loopfunc:true */
|
||
var i, k, num, col, sortTime, colMax,
|
||
rows, order, sort, x, y,
|
||
dir = 0,
|
||
c = table.config,
|
||
cts = c.textSorter || '',
|
||
sortList = c.sortList,
|
||
l = sortList.length,
|
||
bl = c.$tbodies.length;
|
||
if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346
|
||
return;
|
||
}
|
||
if (c.debug) { sortTime = new Date(); }
|
||
for (k = 0; k < bl; k++) {
|
||
colMax = c.cache[k].colMax;
|
||
rows = c.cache[k].normalized;
|
||
|
||
rows.sort(function(a, b) {
|
||
// rows is undefined here in IE, so don't use it!
|
||
for (i = 0; i < l; i++) {
|
||
col = sortList[i][0];
|
||
order = sortList[i][1];
|
||
// sort direction, true = asc, false = desc
|
||
dir = order === 0;
|
||
|
||
if (c.sortStable && a[col] === b[col] && l === 1) {
|
||
return a[c.columns].order - b[c.columns].order;
|
||
}
|
||
|
||
// fallback to natural sort since it is more robust
|
||
num = /n/i.test(getCachedSortType(c.parsers, col));
|
||
if (num && c.strings[col]) {
|
||
// sort strings in numerical columns
|
||
if (typeof (c.string[c.strings[col]]) === 'boolean') {
|
||
num = (dir ? 1 : -1) * (c.string[c.strings[col]] ? -1 : 1);
|
||
} else {
|
||
num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0;
|
||
}
|
||
// fall back to built-in numeric sort
|
||
// var sort = $.tablesorter['sort' + s](table, a[c], b[c], c, colMax[c], dir);
|
||
sort = c.numberSorter ? c.numberSorter(a[col], b[col], dir, colMax[col], table) :
|
||
ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table);
|
||
} else {
|
||
// set a & b depending on sort direction
|
||
x = dir ? a : b;
|
||
y = dir ? b : a;
|
||
// text sort function
|
||
if (typeof(cts) === 'function') {
|
||
// custom OVERALL text sorter
|
||
sort = cts(x[col], y[col], dir, col, table);
|
||
} else if (typeof(cts) === 'object' && cts.hasOwnProperty(col)) {
|
||
// custom text sorter for a SPECIFIC COLUMN
|
||
sort = cts[col](x[col], y[col], dir, col, table);
|
||
} else {
|
||
// fall back to natural sort
|
||
sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c);
|
||
}
|
||
}
|
||
if (sort) { return sort; }
|
||
}
|
||
return a[c.columns].order - b[c.columns].order;
|
||
});
|
||
}
|
||
if (c.debug) { benchmark('Sorting on ' + sortList.toString() + ' and dir ' + order + ' time', sortTime); }
|
||
}
|
||
|
||
function resortComplete(c, callback){
|
||
if (c.table.isUpdating) {
|
||
c.$table.trigger('updateComplete', c.table);
|
||
}
|
||
if ($.isFunction(callback)) {
|
||
callback(c.table);
|
||
}
|
||
}
|
||
|
||
function checkResort(c, resort, callback) {
|
||
var sl = $.isArray(resort) ? resort : c.sortList,
|
||
// if no resort parameter is passed, fallback to config.resort (true by default)
|
||
resrt = typeof resort === 'undefined' ? c.resort : resort;
|
||
// don't try to resort if the table is still processing
|
||
// this will catch spamming of the updateCell method
|
||
if (resrt !== false && !c.serverSideSorting && !c.table.isProcessing) {
|
||
if (sl.length) {
|
||
c.$table.trigger('sorton', [sl, function(){
|
||
resortComplete(c, callback);
|
||
}, true]);
|
||
} else {
|
||
c.$table.trigger('sortReset', [function(){
|
||
resortComplete(c, callback);
|
||
ts.applyWidget(c.table, false);
|
||
}]);
|
||
}
|
||
} else {
|
||
resortComplete(c, callback);
|
||
ts.applyWidget(c.table, false);
|
||
}
|
||
}
|
||
|
||
function bindMethods(table){
|
||
var c = table.config,
|
||
$table = c.$table,
|
||
events = ('sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' +
|
||
'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ').split(' ')
|
||
.join(c.namespace + ' ');
|
||
// apply easy methods that trigger bound events
|
||
$table
|
||
.unbind( events.replace(/\s+/g, ' ') )
|
||
.bind('sortReset' + c.namespace, function(e, callback){
|
||
e.stopPropagation();
|
||
c.sortList = [];
|
||
setHeadersCss(table);
|
||
multisort(table);
|
||
appendToTable(table);
|
||
if ($.isFunction(callback)) {
|
||
callback(table);
|
||
}
|
||
})
|
||
.bind('updateAll' + c.namespace, function(e, resort, callback){
|
||
e.stopPropagation();
|
||
table.isUpdating = true;
|
||
ts.refreshWidgets(table, true, true);
|
||
buildHeaders(table);
|
||
ts.bindEvents(table, c.$headers, true);
|
||
bindMethods(table);
|
||
commonUpdate(table, resort, callback);
|
||
})
|
||
.bind('update' + c.namespace + ' updateRows' + c.namespace, function(e, resort, callback) {
|
||
e.stopPropagation();
|
||
table.isUpdating = true;
|
||
// update sorting (if enabled/disabled)
|
||
updateHeader(table);
|
||
commonUpdate(table, resort, callback);
|
||
})
|
||
.bind('updateCell' + c.namespace, function(e, cell, resort, callback) {
|
||
e.stopPropagation();
|
||
table.isUpdating = true;
|
||
$table.find(c.selectorRemove).remove();
|
||
// get position from the dom
|
||
var v, t, row, icell,
|
||
$tb = c.$tbodies,
|
||
$cell = $(cell),
|
||
// update cache - format: function(s, table, cell, cellIndex)
|
||
// no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
|
||
tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
|
||
$row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
|
||
cell = $cell[0]; // in case cell is a jQuery object
|
||
// tbody may not exist if update is initialized while tbody is removed for processing
|
||
if ($tb.length && tbdy >= 0) {
|
||
row = $tb.eq(tbdy).find('tr').index( $row );
|
||
icell = $cell.index();
|
||
c.cache[tbdy].normalized[row][c.columns].$row = $row;
|
||
if (typeof c.extractors[icell].id === 'undefined') {
|
||
t = ts.getElementText(c, cell, icell);
|
||
} else {
|
||
t = c.extractors[icell].format( ts.getElementText(c, cell, icell), table, cell, icell );
|
||
}
|
||
v = c.parsers[icell].id === 'no-parser' ? '' :
|
||
c.parsers[icell].format( t, table, cell, icell );
|
||
c.cache[tbdy].normalized[row][icell] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
|
||
if ((c.parsers[icell].type || '').toLowerCase() === 'numeric') {
|
||
// update column max value (ignore sign)
|
||
c.cache[tbdy].colMax[icell] = Math.max(Math.abs(v) || 0, c.cache[tbdy].colMax[icell] || 0);
|
||
}
|
||
v = resort !== 'undefined' ? resort : c.resort;
|
||
if (v !== false) {
|
||
// widgets will be reapplied
|
||
checkResort(c, v, callback);
|
||
} else {
|
||
// don't reapply widgets is resort is false, just in case it causes
|
||
// problems with element focus
|
||
if ($.isFunction(callback)) {
|
||
callback(table);
|
||
}
|
||
c.$table.trigger('updateComplete', c.table);
|
||
}
|
||
}
|
||
})
|
||
.bind('addRows' + c.namespace, function(e, $row, resort, callback) {
|
||
e.stopPropagation();
|
||
table.isUpdating = true;
|
||
if (isEmptyObject(c.cache)) {
|
||
// empty table, do an update instead - fixes #450
|
||
updateHeader(table);
|
||
commonUpdate(table, resort, callback);
|
||
} else {
|
||
$row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
|
||
var i, j, l, t, v, rowData, cells,
|
||
rows = $row.filter('tr').length,
|
||
tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
|
||
// fixes adding rows to an empty table - see issue #179
|
||
if (!(c.parsers && c.parsers.length)) {
|
||
buildParserCache(table);
|
||
}
|
||
// add each row
|
||
for (i = 0; i < rows; i++) {
|
||
l = $row[i].cells.length;
|
||
cells = [];
|
||
rowData = {
|
||
child: [],
|
||
$row : $row.eq(i),
|
||
order: c.cache[tbdy].normalized.length
|
||
};
|
||
// add each cell
|
||
for (j = 0; j < l; j++) {
|
||
if (typeof c.extractors[j].id === 'undefined') {
|
||
t = ts.getElementText(c, $row[i].cells[j], j);
|
||
} else {
|
||
t = c.extractors[j].format( ts.getElementText(c, $row[i].cells[j], j), table, $row[i].cells[j], j );
|
||
}
|
||
v = c.parsers[j].id === 'no-parser' ? '' :
|
||
c.parsers[j].format( t, table, $row[i].cells[j], j );
|
||
cells[j] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
|
||
if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
|
||
// update column max value (ignore sign)
|
||
c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
|
||
}
|
||
}
|
||
// add the row data to the end
|
||
cells.push(rowData);
|
||
// update cache
|
||
c.cache[tbdy].normalized.push(cells);
|
||
}
|
||
// resort using current settings
|
||
checkResort(c, resort, callback);
|
||
}
|
||
})
|
||
.bind('updateComplete' + c.namespace, function(){
|
||
table.isUpdating = false;
|
||
})
|
||
.bind('sorton' + c.namespace, function(e, list, callback, init) {
|
||
var c = table.config;
|
||
e.stopPropagation();
|
||
$table.trigger('sortStart', this);
|
||
// update header count index
|
||
updateHeaderSortCount(table, list);
|
||
// set css for headers
|
||
setHeadersCss(table);
|
||
// fixes #346
|
||
if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
|
||
$table.trigger('sortBegin', this);
|
||
// sort the table and append it to the dom
|
||
multisort(table);
|
||
appendToTable(table, init);
|
||
$table.trigger('sortEnd', this);
|
||
ts.applyWidget(table);
|
||
if ($.isFunction(callback)) {
|
||
callback(table);
|
||
}
|
||
})
|
||
.bind('appendCache' + c.namespace, function(e, callback, init) {
|
||
e.stopPropagation();
|
||
appendToTable(table, init);
|
||
if ($.isFunction(callback)) {
|
||
callback(table);
|
||
}
|
||
})
|
||
.bind('updateCache' + c.namespace, function(e, callback){
|
||
// rebuild parsers
|
||
if (!(c.parsers && c.parsers.length)) {
|
||
buildParserCache(table);
|
||
}
|
||
// rebuild the cache map
|
||
buildCache(table);
|
||
if ($.isFunction(callback)) {
|
||
callback(table);
|
||
}
|
||
})
|
||
.bind('applyWidgetId' + c.namespace, function(e, id) {
|
||
e.stopPropagation();
|
||
ts.getWidgetById(id).format(table, c, c.widgetOptions);
|
||
})
|
||
.bind('applyWidgets' + c.namespace, function(e, init) {
|
||
e.stopPropagation();
|
||
// apply widgets
|
||
ts.applyWidget(table, init);
|
||
})
|
||
.bind('refreshWidgets' + c.namespace, function(e, all, dontapply){
|
||
e.stopPropagation();
|
||
ts.refreshWidgets(table, all, dontapply);
|
||
})
|
||
.bind('destroy' + c.namespace, function(e, c, cb){
|
||
e.stopPropagation();
|
||
ts.destroy(table, c, cb);
|
||
})
|
||
.bind('resetToLoadState' + c.namespace, function(){
|
||
// remove all widgets
|
||
ts.removeWidget(table, true, false);
|
||
// restore original settings; this clears out current settings, but does not clear
|
||
// values saved to storage.
|
||
c = $.extend(true, ts.defaults, c.originalSettings);
|
||
table.hasInitialized = false;
|
||
// setup the entire table again
|
||
ts.setup( table, c );
|
||
});
|
||
}
|
||
|
||
/* public methods */
|
||
ts.construct = function(settings) {
|
||
return this.each(function() {
|
||
var table = this,
|
||
// merge & extend config options
|
||
c = $.extend(true, {}, ts.defaults, settings);
|
||
// save initial settings
|
||
c.originalSettings = settings;
|
||
// create a table from data (build table widget)
|
||
if (!table.hasInitialized && ts.buildTable && this.tagName !== 'TABLE') {
|
||
// return the table (in case the original target is the table's container)
|
||
ts.buildTable(table, c);
|
||
} else {
|
||
ts.setup(table, c);
|
||
}
|
||
});
|
||
};
|
||
|
||
ts.setup = function(table, c) {
|
||
// if no thead or tbody, or tablesorter is already present, quit
|
||
if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) {
|
||
return c.debug ? log('ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : '';
|
||
}
|
||
|
||
var k = '',
|
||
$table = $(table),
|
||
m = $.metadata;
|
||
// initialization flag
|
||
table.hasInitialized = false;
|
||
// table is being processed flag
|
||
table.isProcessing = true;
|
||
// make sure to store the config object
|
||
table.config = c;
|
||
// save the settings where they read
|
||
$.data(table, 'tablesorter', c);
|
||
if (c.debug) { $.data( table, 'startoveralltimer', new Date()); }
|
||
|
||
// removing this in version 3 (only supports jQuery 1.7+)
|
||
c.supportsDataObject = (function(version) {
|
||
version[0] = parseInt(version[0], 10);
|
||
return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4);
|
||
})($.fn.jquery.split('.'));
|
||
// digit sort text location; keeping max+/- for backwards compatibility
|
||
c.string = { 'max': 1, 'min': -1, 'emptymin': 1, 'emptymax': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false };
|
||
// ensure case insensitivity
|
||
c.emptyTo = c.emptyTo.toLowerCase();
|
||
c.stringTo = c.stringTo.toLowerCase();
|
||
// add table theme class only if there isn't already one there
|
||
if (!/tablesorter\-/.test($table.attr('class'))) {
|
||
k = (c.theme !== '' ? ' tablesorter-' + c.theme : '');
|
||
}
|
||
c.table = table;
|
||
c.$table = $table
|
||
.addClass(ts.css.table + ' ' + c.tableClass + k)
|
||
.attr('role', 'grid');
|
||
c.$headers = $table.find(c.selectorHeaders);
|
||
|
||
// give the table a unique id, which will be used in namespace binding
|
||
if (!c.namespace) {
|
||
c.namespace = '.tablesorter' + Math.random().toString(16).slice(2);
|
||
} else {
|
||
// make sure namespace starts with a period & doesn't have weird characters
|
||
c.namespace = '.' + c.namespace.replace(/\W/g,'');
|
||
}
|
||
|
||
c.$table.children().children('tr').attr('role', 'row');
|
||
c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')').attr({
|
||
'aria-live' : 'polite',
|
||
'aria-relevant' : 'all'
|
||
});
|
||
if (c.$table.children('caption').length) {
|
||
k = c.$table.children('caption')[0];
|
||
if (!k.id) { k.id = c.namespace.slice(1) + 'caption'; }
|
||
c.$table.attr('aria-labelledby', k.id);
|
||
}
|
||
c.widgetInit = {}; // keep a list of initialized widgets
|
||
// change textExtraction via data-attribute
|
||
c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic';
|
||
// build headers
|
||
buildHeaders(table);
|
||
// fixate columns if the users supplies the fixedWidth option
|
||
// do this after theme has been applied
|
||
ts.fixColumnWidth(table);
|
||
// try to auto detect column type, and store in tables config
|
||
buildParserCache(table);
|
||
// start total row count at zero
|
||
c.totalRows = 0;
|
||
// build the cache for the tbody cells
|
||
// delayInit will delay building the cache until the user starts a sort
|
||
if (!c.delayInit) { buildCache(table); }
|
||
// bind all header events and methods
|
||
ts.bindEvents(table, c.$headers, true);
|
||
bindMethods(table);
|
||
// get sort list from jQuery data or metadata
|
||
// in jQuery < 1.4, an error occurs when calling $table.data()
|
||
if (c.supportsDataObject && typeof $table.data().sortlist !== 'undefined') {
|
||
c.sortList = $table.data().sortlist;
|
||
} else if (m && ($table.metadata() && $table.metadata().sortlist)) {
|
||
c.sortList = $table.metadata().sortlist;
|
||
}
|
||
// apply widget init code
|
||
ts.applyWidget(table, true);
|
||
// if user has supplied a sort list to constructor
|
||
if (c.sortList.length > 0) {
|
||
$table.trigger('sorton', [c.sortList, {}, !c.initWidgets, true]);
|
||
} else {
|
||
setHeadersCss(table);
|
||
if (c.initWidgets) {
|
||
// apply widget format
|
||
ts.applyWidget(table, false);
|
||
}
|
||
}
|
||
|
||
// show processesing icon
|
||
if (c.showProcessing) {
|
||
$table
|
||
.unbind('sortBegin' + c.namespace + ' sortEnd' + c.namespace)
|
||
.bind('sortBegin' + c.namespace + ' sortEnd' + c.namespace, function(e) {
|
||
clearTimeout(c.processTimer);
|
||
ts.isProcessing(table);
|
||
if (e.type === 'sortBegin') {
|
||
c.processTimer = setTimeout(function(){
|
||
ts.isProcessing(table, true);
|
||
}, 500);
|
||
}
|
||
});
|
||
}
|
||
|
||
// initialized
|
||
table.hasInitialized = true;
|
||
table.isProcessing = false;
|
||
if (c.debug) {
|
||
ts.benchmark('Overall initialization time', $.data( table, 'startoveralltimer'));
|
||
}
|
||
$table.trigger('tablesorter-initialized', table);
|
||
if (typeof c.initialized === 'function') { c.initialized(table); }
|
||
};
|
||
|
||
// automatically add a colgroup with col elements set to a percentage width
|
||
ts.fixColumnWidth = function(table) {
|
||
table = $(table)[0];
|
||
var overallWidth, percent,
|
||
c = table.config,
|
||
colgroup = c.$table.children('colgroup');
|
||
// remove plugin-added colgroup, in case we need to refresh the widths
|
||
if (colgroup.length && colgroup.hasClass(ts.css.colgroup)) {
|
||
colgroup.remove();
|
||
}
|
||
if (c.widthFixed && c.$table.children('colgroup').length === 0) {
|
||
colgroup = $('<colgroup class="' + ts.css.colgroup + '">');
|
||
overallWidth = c.$table.width();
|
||
// only add col for visible columns - fixes #371
|
||
c.$tbodies.find('tr:first').children(':visible').each(function() {
|
||
percent = parseInt( ( $(this).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
|
||
colgroup.append( $('<col>').css('width', percent) );
|
||
});
|
||
c.$table.prepend(colgroup);
|
||
}
|
||
};
|
||
|
||
ts.getColumnData = function(table, obj, indx, getCell, $headers){
|
||
if (typeof obj === 'undefined' || obj === null) { return; }
|
||
table = $(table)[0];
|
||
var $h, k,
|
||
c = table.config,
|
||
$cell = ( $headers || c.$headers );
|
||
if (obj[indx]) {
|
||
return getCell ? obj[indx] : obj[$cell.index( $cell.filter('[data-column="' + indx + '"]:last') )];
|
||
}
|
||
for (k in obj) {
|
||
if (typeof k === 'string') {
|
||
$h = $cell.filter('[data-column="' + indx + '"]:last')
|
||
// header cell with class/id
|
||
.filter(k)
|
||
// find elements within the header cell with cell/id
|
||
.add( $cell.filter('[data-column="' + indx + '"]:last').find(k) );
|
||
if ($h.length) {
|
||
return obj[k];
|
||
}
|
||
}
|
||
}
|
||
return;
|
||
};
|
||
|
||
// computeTableHeaderCellIndexes from:
|
||
// http://www.javascripttoolbox.com/lib/table/examples.php
|
||
// http://www.javascripttoolbox.com/temp/table_cellindex.html
|
||
ts.computeColumnIndex = function(trs) {
|
||
var matrix = [],
|
||
lookup = {},
|
||
cols = 0, // determine the number of columns
|
||
i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, matrixrow;
|
||
for (i = 0; i < trs.length; i++) {
|
||
cells = trs[i].cells;
|
||
for (j = 0; j < cells.length; j++) {
|
||
cell = cells[j];
|
||
$cell = $(cell);
|
||
rowIndex = cell.parentNode.rowIndex;
|
||
cellId = rowIndex + '-' + $cell.index();
|
||
rowSpan = cell.rowSpan || 1;
|
||
colSpan = cell.colSpan || 1;
|
||
if (typeof(matrix[rowIndex]) === 'undefined') {
|
||
matrix[rowIndex] = [];
|
||
}
|
||
// Find first available column in the first row
|
||
for (k = 0; k < matrix[rowIndex].length + 1; k++) {
|
||
if (typeof(matrix[rowIndex][k]) === 'undefined') {
|
||
firstAvailCol = k;
|
||
break;
|
||
}
|
||
}
|
||
lookup[cellId] = firstAvailCol;
|
||
cols = Math.max(firstAvailCol, cols);
|
||
// add data-column
|
||
$cell.attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex
|
||
for (k = rowIndex; k < rowIndex + rowSpan; k++) {
|
||
if (typeof(matrix[k]) === 'undefined') {
|
||
matrix[k] = [];
|
||
}
|
||
matrixrow = matrix[k];
|
||
for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
|
||
matrixrow[l] = 'x';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// may not be accurate if # header columns !== # tbody columns
|
||
return cols + 1; // add one because it's a zero-based index
|
||
};
|
||
|
||
// *** Process table ***
|
||
// add processing indicator
|
||
ts.isProcessing = function(table, toggle, $ths) {
|
||
table = $(table);
|
||
var c = table[0].config,
|
||
// default to all headers
|
||
$h = $ths || table.find('.' + ts.css.header);
|
||
if (toggle) {
|
||
// don't use sortList if custom $ths used
|
||
if (typeof $ths !== 'undefined' && c.sortList.length > 0) {
|
||
// get headers from the sortList
|
||
$h = $h.filter(function(){
|
||
// get data-column from attr to keep compatibility with jQuery 1.2.6
|
||
return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList) >= 0;
|
||
});
|
||
}
|
||
table.add($h).addClass(ts.css.processing + ' ' + c.cssProcessing);
|
||
} else {
|
||
table.add($h).removeClass(ts.css.processing + ' ' + c.cssProcessing);
|
||
}
|
||
};
|
||
|
||
// detach tbody but save the position
|
||
// don't use tbody because there are portions that look for a tbody index (updateCell)
|
||
ts.processTbody = function(table, $tb, getIt){
|
||
table = $(table)[0];
|
||
var holdr;
|
||
if (getIt) {
|
||
table.isProcessing = true;
|
||
$tb.before('<span class="tablesorter-savemyplace"/>');
|
||
holdr = ($.fn.detach) ? $tb.detach() : $tb.remove();
|
||
return holdr;
|
||
}
|
||
holdr = $(table).find('span.tablesorter-savemyplace');
|
||
$tb.insertAfter( holdr );
|
||
holdr.remove();
|
||
table.isProcessing = false;
|
||
};
|
||
|
||
ts.clearTableBody = function(table) {
|
||
$(table)[0].config.$tbodies.children().detach();
|
||
};
|
||
|
||
ts.bindEvents = function(table, $headers, core){
|
||
table = $(table)[0];
|
||
var downTime,
|
||
c = table.config;
|
||
if (core !== true) {
|
||
c.$extraHeaders = c.$extraHeaders ? c.$extraHeaders.add($headers) : $headers;
|
||
}
|
||
// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
|
||
$headers
|
||
// http://stackoverflow.com/questions/5312849/jquery-find-self;
|
||
.find(c.selectorSort).add( $headers.filter(c.selectorSort) )
|
||
.unbind( ('mousedown mouseup sort keyup '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') )
|
||
.bind( 'mousedown mouseup sort keyup '.split(' ').join(c.namespace + ' '), function(e, external) {
|
||
var cell,
|
||
$target = $(e.target),
|
||
type = e.type;
|
||
// only recognize left clicks or enter
|
||
if ( ((e.which || e.button) !== 1 && !/sort|keyup/.test(type)) || (type === 'keyup' && e.which !== 13) ) {
|
||
return;
|
||
}
|
||
// ignore long clicks (prevents resizable widget from initializing a sort)
|
||
if (type === 'mouseup' && external !== true && (new Date().getTime() - downTime > 250)) { return; }
|
||
// set timer on mousedown
|
||
if (type === 'mousedown') {
|
||
downTime = new Date().getTime();
|
||
return;
|
||
}
|
||
cell = $.fn.closest ? $target.closest('td,th') : $target.parents('td,th').filter(':first');
|
||
// prevent sort being triggered on form elements
|
||
if ( /(input|select|button|textarea)/i.test(e.target.tagName) ||
|
||
// nosort class name, or elements within a nosort container
|
||
$target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 ||
|
||
// elements within a button
|
||
$target.parents('button').length > 0 ) {
|
||
return !c.cancelSelection;
|
||
}
|
||
if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
|
||
// jQuery v1.2.6 doesn't have closest()
|
||
cell = $.fn.closest ? $(this).closest('th, td')[0] : /TH|TD/.test(this.tagName) ? this : $(this).parents('th, td')[0];
|
||
// reference original table headers and find the same cell
|
||
cell = c.$headers[ $headers.index( cell ) ];
|
||
if (!cell.sortDisabled) {
|
||
initSort(table, cell, e);
|
||
}
|
||
});
|
||
if (c.cancelSelection) {
|
||
// cancel selection
|
||
$headers
|
||
.attr('unselectable', 'on')
|
||
.bind('selectstart', false)
|
||
.css({
|
||
'user-select': 'none',
|
||
'MozUserSelect': 'none' // not needed for jQuery 1.8+
|
||
});
|
||
}
|
||
};
|
||
|
||
// restore headers
|
||
ts.restoreHeaders = function(table){
|
||
var $cell,
|
||
c = $(table)[0].config;
|
||
// don't use c.$headers here in case header cells were swapped
|
||
c.$table.find(c.selectorHeaders).each(function(i){
|
||
$cell = $(this);
|
||
// only restore header cells if it is wrapped
|
||
// because this is also used by the updateAll method
|
||
if ($cell.find('.' + ts.css.headerIn).length){
|
||
$cell.html( c.headerContent[i] );
|
||
}
|
||
});
|
||
};
|
||
|
||
ts.destroy = function(table, removeClasses, callback){
|
||
table = $(table)[0];
|
||
if (!table.hasInitialized) { return; }
|
||
// remove all widgets
|
||
ts.removeWidget(table, true, false);
|
||
var events,
|
||
$t = $(table),
|
||
c = table.config,
|
||
$h = $t.find('thead:first'),
|
||
$r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow),
|
||
$f = $t.find('tfoot:first > tr').children('th, td');
|
||
if (removeClasses === false && $.inArray('uitheme', c.widgets) >= 0) {
|
||
// reapply uitheme classes, in case we want to maintain appearance
|
||
$t.trigger('applyWidgetId', ['uitheme']);
|
||
$t.trigger('applyWidgetId', ['zebra']);
|
||
}
|
||
// remove widget added rows, just in case
|
||
$h.find('tr').not($r).remove();
|
||
// disable tablesorter
|
||
events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' +
|
||
'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ')
|
||
.join(c.namespace + ' ');
|
||
$t
|
||
.removeData('tablesorter')
|
||
.unbind( events.replace(/\s+/g, ' ') );
|
||
c.$headers.add($f)
|
||
.removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone].join(' ') )
|
||
.removeAttr('data-column')
|
||
.removeAttr('aria-label')
|
||
.attr('aria-disabled', 'true');
|
||
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') );
|
||
ts.restoreHeaders(table);
|
||
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
|
||
// clear flag in case the plugin is initialized again
|
||
table.hasInitialized = false;
|
||
delete table.config.cache;
|
||
if (typeof callback === 'function') {
|
||
callback(table);
|
||
}
|
||
};
|
||
|
||
// *** sort functions ***
|
||
// regex used in natural sort
|
||
ts.regex = {
|
||
chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters
|
||
chunks: /(^\\0|\\0$)/, // replace chunks @ ends
|
||
hex: /^0x[0-9a-f]+$/i // hex
|
||
};
|
||
|
||
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
|
||
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
|
||
// I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall
|
||
ts.sortNatural = function(a, b) {
|
||
if (a === b) { return 0; }
|
||
var xN, xD, yN, yD, xF, yF, i, mx,
|
||
r = ts.regex;
|
||
// first try and sort Hex codes
|
||
if (r.hex.test(b)) {
|
||
xD = parseInt(a.match(r.hex), 16);
|
||
yD = parseInt(b.match(r.hex), 16);
|
||
if ( xD < yD ) { return -1; }
|
||
if ( xD > yD ) { return 1; }
|
||
}
|
||
// chunk/tokenize
|
||
xN = a.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0');
|
||
yN = b.replace(r.chunk, '\\0$1\\0').replace(r.chunks, '').split('\\0');
|
||
mx = Math.max(xN.length, yN.length);
|
||
// natural sorting through split numeric strings and default strings
|
||
for (i = 0; i < mx; i++) {
|
||
// find floats not starting with '0', string or 0 if not defined
|
||
xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0;
|
||
yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0;
|
||
// handle numeric vs string comparison - number < string - (Kyle Adams)
|
||
if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; }
|
||
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
|
||
if (typeof xF !== typeof yF) {
|
||
xF += '';
|
||
yF += '';
|
||
}
|
||
if (xF < yF) { return -1; }
|
||
if (xF > yF) { return 1; }
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
ts.sortNaturalAsc = function(a, b, col, table, c) {
|
||
if (a === b) { return 0; }
|
||
var e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
||
if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; }
|
||
if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; }
|
||
return ts.sortNatural(a, b);
|
||
};
|
||
|
||
ts.sortNaturalDesc = function(a, b, col, table, c) {
|
||
if (a === b) { return 0; }
|
||
var e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
||
if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; }
|
||
if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; }
|
||
return ts.sortNatural(b, a);
|
||
};
|
||
|
||
// basic alphabetical sort
|
||
ts.sortText = function(a, b) {
|
||
return a > b ? 1 : (a < b ? -1 : 0);
|
||
};
|
||
|
||
// return text string value by adding up ascii value
|
||
// so the text is somewhat sorted when using a digital sort
|
||
// this is NOT an alphanumeric sort
|
||
ts.getTextValue = function(a, num, mx) {
|
||
if (mx) {
|
||
// make sure the text value is greater than the max numerical value (mx)
|
||
var i, l = a ? a.length : 0, n = mx + num;
|
||
for (i = 0; i < l; i++) {
|
||
n += a.charCodeAt(i);
|
||
}
|
||
return num * n;
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
ts.sortNumericAsc = function(a, b, num, mx, col, table) {
|
||
if (a === b) { return 0; }
|
||
var c = table.config,
|
||
e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
||
if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; }
|
||
if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; }
|
||
if (isNaN(a)) { a = ts.getTextValue(a, num, mx); }
|
||
if (isNaN(b)) { b = ts.getTextValue(b, num, mx); }
|
||
return a - b;
|
||
};
|
||
|
||
ts.sortNumericDesc = function(a, b, num, mx, col, table) {
|
||
if (a === b) { return 0; }
|
||
var c = table.config,
|
||
e = c.string[ (c.empties[col] || c.emptyTo ) ];
|
||
if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; }
|
||
if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; }
|
||
if (isNaN(a)) { a = ts.getTextValue(a, num, mx); }
|
||
if (isNaN(b)) { b = ts.getTextValue(b, num, mx); }
|
||
return b - a;
|
||
};
|
||
|
||
ts.sortNumeric = function(a, b) {
|
||
return a - b;
|
||
};
|
||
|
||
// used when replacing accented characters during sorting
|
||
ts.characterEquivalents = {
|
||
'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå
|
||
'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ
|
||
'c' : '\u00e7\u0107\u010d', // çćč
|
||
'C' : '\u00c7\u0106\u010c', // ÇĆČ
|
||
'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
|
||
'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
|
||
'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
|
||
'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
|
||
'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6', // óòôõö
|
||
'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6', // ÓÒÔÕÖ
|
||
'ss': '\u00df', // ß (s sharp)
|
||
'SS': '\u1e9e', // ẞ (Capital sharp s)
|
||
'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
|
||
'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
|
||
};
|
||
ts.replaceAccents = function(s) {
|
||
var a, acc = '[', eq = ts.characterEquivalents;
|
||
if (!ts.characterRegex) {
|
||
ts.characterRegexArray = {};
|
||
for (a in eq) {
|
||
if (typeof a === 'string') {
|
||
acc += eq[a];
|
||
ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g');
|
||
}
|
||
}
|
||
ts.characterRegex = new RegExp(acc + ']');
|
||
}
|
||
if (ts.characterRegex.test(s)) {
|
||
for (a in eq) {
|
||
if (typeof a === 'string') {
|
||
s = s.replace( ts.characterRegexArray[a], a );
|
||
}
|
||
}
|
||
}
|
||
return s;
|
||
};
|
||
|
||
// *** utilities ***
|
||
ts.isValueInArray = function(column, arry) {
|
||
var indx, len = arry.length;
|
||
for (indx = 0; indx < len; indx++) {
|
||
if (arry[indx][0] === column) {
|
||
return indx;
|
||
}
|
||
}
|
||
return -1;
|
||
};
|
||
|
||
ts.addParser = function(parser) {
|
||
var i, l = ts.parsers.length, a = true;
|
||
for (i = 0; i < l; i++) {
|
||
if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) {
|
||
a = false;
|
||
}
|
||
}
|
||
if (a) {
|
||
ts.parsers.push(parser);
|
||
}
|
||
};
|
||
|
||
ts.getParserById = function(name) {
|
||
/*jshint eqeqeq:false */
|
||
if (name == 'false') { return false; }
|
||
var i, l = ts.parsers.length;
|
||
for (i = 0; i < l; i++) {
|
||
if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) {
|
||
return ts.parsers[i];
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
ts.addWidget = function(widget) {
|
||
ts.widgets.push(widget);
|
||
};
|
||
|
||
ts.hasWidget = function(table, name){
|
||
table = $(table);
|
||
return table.length && table[0].config && table[0].config.widgetInit[name] || false;
|
||
};
|
||
|
||
ts.getWidgetById = function(name) {
|
||
var i, w, l = ts.widgets.length;
|
||
for (i = 0; i < l; i++) {
|
||
w = ts.widgets[i];
|
||
if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) {
|
||
return w;
|
||
}
|
||
}
|
||
};
|
||
|
||
ts.applyWidget = function(table, init, callback) {
|
||
table = $(table)[0]; // in case this is called externally
|
||
var c = table.config,
|
||
wo = c.widgetOptions,
|
||
tableClass = ' ' + c.table.className + ' ',
|
||
widgets = [],
|
||
time, time2, w, wd;
|
||
// prevent numerous consecutive widget applications
|
||
if (init !== false && table.hasInitialized && (table.isApplyingWidgets || table.isUpdating)) { return; }
|
||
if (c.debug) { time = new Date(); }
|
||
// look for widgets to apply from in table class
|
||
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
|
||
wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' )+ '\\s', 'g' );
|
||
if ( tableClass.match( wd ) ) {
|
||
// extract out the widget id from the table class (widget id's can include dashes)
|
||
w = tableClass.match( wd );
|
||
if ( w ) {
|
||
$.each( w, function( i,n ){
|
||
c.widgets.push( n.replace( wd, '$1' ) );
|
||
});
|
||
}
|
||
}
|
||
if (c.widgets.length) {
|
||
table.isApplyingWidgets = true;
|
||
// ensure unique widget ids
|
||
c.widgets = $.grep(c.widgets, function(v, k){
|
||
return $.inArray(v, c.widgets) === k;
|
||
});
|
||
// build widget array & add priority as needed
|
||
$.each(c.widgets || [], function(i,n){
|
||
wd = ts.getWidgetById(n);
|
||
if (wd && wd.id) {
|
||
// set priority to 10 if not defined
|
||
if (!wd.priority) { wd.priority = 10; }
|
||
widgets[i] = wd;
|
||
}
|
||
});
|
||
// sort widgets by priority
|
||
widgets.sort(function(a, b){
|
||
return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
|
||
});
|
||
// add/update selected widgets
|
||
$.each(widgets, function(i,w){
|
||
if (w) {
|
||
if (init || !(c.widgetInit[w.id])) {
|
||
// set init flag first to prevent calling init more than once (e.g. pager)
|
||
c.widgetInit[w.id] = true;
|
||
if (w.hasOwnProperty('options')) {
|
||
wo = table.config.widgetOptions = $.extend( true, {}, w.options, wo );
|
||
}
|
||
if (w.hasOwnProperty('init')) {
|
||
if (c.debug) { time2 = new Date(); }
|
||
w.init(table, w, c, wo);
|
||
if (c.debug) { ts.benchmark('Initializing ' + w.id + ' widget', time2); }
|
||
}
|
||
}
|
||
if (!init && w.hasOwnProperty('format')) {
|
||
if (c.debug) { time2 = new Date(); }
|
||
w.format(table, c, wo, false);
|
||
if (c.debug) { ts.benchmark( ( init ? 'Initializing ' : 'Applying ' ) + w.id + ' widget', time2); }
|
||
}
|
||
}
|
||
});
|
||
// callback executed on init only
|
||
if (!init && typeof callback === 'function') {
|
||
callback(table);
|
||
}
|
||
}
|
||
setTimeout(function(){
|
||
table.isApplyingWidgets = false;
|
||
$.data(table, 'lastWidgetApplication', new Date());
|
||
}, 0);
|
||
if (c.debug) {
|
||
w = c.widgets.length;
|
||
benchmark('Completed ' + (init === true ? 'initializing ' : 'applying ') + w + ' widget' + (w !== 1 ? 's' : ''), time);
|
||
}
|
||
};
|
||
|
||
ts.removeWidget = function(table, name, refreshing){
|
||
table = $(table)[0];
|
||
// if name === true, add all widgets from $.tablesorter.widgets
|
||
if (name === true) {
|
||
name = [];
|
||
$.each( ts.widgets, function(i, w){
|
||
if (w && w.id) {
|
||
name.push( w.id );
|
||
}
|
||
});
|
||
} else {
|
||
// name can be either an array of widgets names,
|
||
// or a space/comma separated list of widget names
|
||
name = ( $.isArray(name) ? name.join(',') : name || '' ).toLowerCase().split( /[\s,]+/ );
|
||
}
|
||
var i, widget, indx,
|
||
c = table.config,
|
||
len = name.length;
|
||
for (i = 0; i < len; i++) {
|
||
widget = ts.getWidgetById(name[i]);
|
||
indx = $.inArray( name[i], c.widgets );
|
||
if ( widget && 'remove' in widget ) {
|
||
if (c.debug && indx >= 0) { log( 'Removing "' + name[i] + '" widget' ); }
|
||
widget.remove(table, c, c.widgetOptions, refreshing);
|
||
c.widgetInit[name[i]] = false;
|
||
}
|
||
// don't remove the widget from config.widget if refreshing
|
||
if (indx >= 0 && refreshing !== true) {
|
||
c.widgets.splice( indx, 1 );
|
||
}
|
||
}
|
||
};
|
||
|
||
ts.refreshWidgets = function(table, doAll, dontapply) {
|
||
table = $(table)[0]; // see issue #243
|
||
var c = table.config,
|
||
cw = c.widgets,
|
||
list = [],
|
||
callback = function(table){
|
||
$(table).trigger('refreshComplete');
|
||
};
|
||
// remove widgets not defined in config.widgets, unless doAll is true
|
||
$.each( ts.widgets, function(i, w){
|
||
if (w && w.id && (doAll || $.inArray( w.id, cw ) < 0)) {
|
||
list.push( w.id );
|
||
}
|
||
});
|
||
ts.removeWidget( table, list.join(','), true );
|
||
if (dontapply !== true) {
|
||
// call widget init if
|
||
ts.applyWidget(table, doAll || false, callback );
|
||
if (doAll) {
|
||
// apply widget format
|
||
ts.applyWidget(table, false, callback);
|
||
}
|
||
} else {
|
||
callback(table);
|
||
}
|
||
};
|
||
|
||
// get sorter, string, empty, etc options for each column from
|
||
// jQuery data, metadata, header option or header class name ('sorter-false')
|
||
// priority = jQuery data > meta > headers option > header class name
|
||
ts.getData = function(h, ch, key) {
|
||
var val = '', $h = $(h), m, cl;
|
||
if (!$h.length) { return ''; }
|
||
m = $.metadata ? $h.metadata() : false;
|
||
cl = ' ' + ($h.attr('class') || '');
|
||
if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){
|
||
// 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
|
||
// 'data-sort-initial-order' is assigned to 'sortInitialOrder'
|
||
val += $h.data(key) || $h.data(key.toLowerCase());
|
||
} else if (m && typeof m[key] !== 'undefined') {
|
||
val += m[key];
|
||
} else if (ch && typeof ch[key] !== 'undefined') {
|
||
val += ch[key];
|
||
} else if (cl !== ' ' && cl.match(' ' + key + '-')) {
|
||
// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
|
||
val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || '';
|
||
}
|
||
return $.trim(val);
|
||
};
|
||
|
||
ts.formatFloat = function(s, table) {
|
||
if (typeof s !== 'string' || s === '') { return s; }
|
||
// allow using formatFloat without a table; defaults to US number format
|
||
var i,
|
||
t = table && table.config ? table.config.usNumberFormat !== false :
|
||
typeof table !== 'undefined' ? table : true;
|
||
if (t) {
|
||
// US Format - 1,234,567.89 -> 1234567.89
|
||
s = s.replace(/,/g,'');
|
||
} else {
|
||
// German Format = 1.234.567,89 -> 1234567.89
|
||
// French Format = 1 234 567,89 -> 1234567.89
|
||
s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.');
|
||
}
|
||
if(/^\s*\([.\d]+\)/.test(s)) {
|
||
// make (#) into a negative number -> (10) = -10
|
||
s = s.replace(/^\s*\(([.\d]+)\)/, '-$1');
|
||
}
|
||
i = parseFloat(s);
|
||
// return the text instead of zero
|
||
return isNaN(i) ? $.trim(s) : i;
|
||
};
|
||
|
||
ts.isDigit = function(s) {
|
||
// replace all unwanted chars and match
|
||
return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : true;
|
||
};
|
||
|
||
}()
|
||
});
|
||
|
||
// make shortcut
|
||
var ts = $.tablesorter;
|
||
|
||
// extend plugin scope
|
||
$.fn.extend({
|
||
tablesorter: ts.construct
|
||
});
|
||
|
||
// add default parsers
|
||
ts.addParser({
|
||
id: 'no-parser',
|
||
is: function() {
|
||
return false;
|
||
},
|
||
format: function() {
|
||
return '';
|
||
},
|
||
type: 'text'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'text',
|
||
is: function() {
|
||
return true;
|
||
},
|
||
format: function(s, table) {
|
||
var c = table.config;
|
||
if (s) {
|
||
s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s );
|
||
s = c.sortLocaleCompare ? ts.replaceAccents(s) : s;
|
||
}
|
||
return s;
|
||
},
|
||
type: 'text'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'digit',
|
||
is: function(s) {
|
||
return ts.isDigit(s);
|
||
},
|
||
format: function(s, table) {
|
||
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
|
||
return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'currency',
|
||
is: function(s) {
|
||
return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[+\-,. ]/g,'')); // £$€¤¥¢
|
||
},
|
||
format: function(s, table) {
|
||
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
|
||
return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'url',
|
||
is: function(s) {
|
||
return (/^(https?|ftp|file):\/\//).test(s);
|
||
},
|
||
format: function(s) {
|
||
return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s;
|
||
},
|
||
parsed : true, // filter widget flag
|
||
type: 'text'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'isoDate',
|
||
is: function(s) {
|
||
return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s);
|
||
},
|
||
format: function(s, table) {
|
||
var date = s ? new Date( s.replace(/-/g, '/') ) : s;
|
||
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'percent',
|
||
is: function(s) {
|
||
return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15;
|
||
},
|
||
format: function(s, table) {
|
||
return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
// added image parser to core v2.17.9
|
||
ts.addParser({
|
||
id: 'image',
|
||
is: function(s, table, node, $node){
|
||
return $node.find('img').length > 0;
|
||
},
|
||
format: function(s, table, cell) {
|
||
return $(cell).find('img').attr(table.config.imgAttr || 'alt') || s;
|
||
},
|
||
parsed : true, // filter widget flag
|
||
type: 'text'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'usLongDate',
|
||
is: function(s) {
|
||
// two digit years are not allowed cross-browser
|
||
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
|
||
return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
|
||
},
|
||
format: function(s, table) {
|
||
var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
|
||
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
|
||
is: function(s) {
|
||
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
|
||
return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g,' ').replace(/[\-.,]/g, '/'));
|
||
},
|
||
format: function(s, table, cell, cellIndex) {
|
||
if (s) {
|
||
var date, d,
|
||
c = table.config,
|
||
ci = c.$headers.filter('[data-column="' + cellIndex + '"]:last'),
|
||
format = ci.length && ci[0].dateFormat || ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') || c.dateFormat;
|
||
d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'); // escaped - because JSHint in Firefox was showing it as an error
|
||
if (format === 'mmddyyyy') {
|
||
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2');
|
||
} else if (format === 'ddmmyyyy') {
|
||
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1');
|
||
} else if (format === 'yyyymmdd') {
|
||
d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3');
|
||
}
|
||
date = new Date(d);
|
||
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
||
}
|
||
return s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'time',
|
||
is: function(s) {
|
||
return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s);
|
||
},
|
||
format: function(s, table) {
|
||
var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
|
||
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
ts.addParser({
|
||
id: 'metadata',
|
||
is: function() {
|
||
return false;
|
||
},
|
||
format: function(s, table, cell) {
|
||
var c = table.config,
|
||
p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
|
||
return $(cell).metadata()[p];
|
||
},
|
||
type: 'numeric'
|
||
});
|
||
|
||
// add default widgets
|
||
ts.addWidget({
|
||
id: 'zebra',
|
||
priority: 90,
|
||
format: function(table, c, wo) {
|
||
var $tb, $tv, $tr, row, even, time, k,
|
||
child = new RegExp(c.cssChildRow, 'i'),
|
||
b = c.$tbodies;
|
||
if (c.debug) {
|
||
time = new Date();
|
||
}
|
||
for (k = 0; k < b.length; k++ ) {
|
||
// loop through the visible rows
|
||
row = 0;
|
||
$tb = b.eq(k);
|
||
$tv = $tb.children('tr:visible').not(c.selectorRemove);
|
||
// revered back to using jQuery each - strangely it's the fastest method
|
||
/*jshint loopfunc:true */
|
||
$tv.each(function(){
|
||
$tr = $(this);
|
||
// style child rows the same way the parent row was styled
|
||
if (!child.test(this.className)) { row++; }
|
||
even = (row % 2 === 0);
|
||
$tr.removeClass(wo.zebra[even ? 1 : 0]).addClass(wo.zebra[even ? 0 : 1]);
|
||
});
|
||
}
|
||
},
|
||
remove: function(table, c, wo, refreshing){
|
||
if (refreshing) { return; }
|
||
var k, $tb,
|
||
b = c.$tbodies,
|
||
rmv = (wo.zebra || [ 'even', 'odd' ]).join(' ');
|
||
for (k = 0; k < b.length; k++ ){
|
||
$tb = ts.processTbody(table, b.eq(k), true); // remove tbody
|
||
$tb.children().removeClass(rmv);
|
||
ts.processTbody(table, $tb, false); // restore tbody
|
||
}
|
||
}
|
||
});
|
||
|
||
return ts;
|
||
}));;/*
|
||
*
|
||
* StaticRow widget for jQuery TableSorter 2.0
|
||
* Version 1.0
|
||
*
|
||
* Copyright (c) 2011 Nils Luxton
|
||
* Licensed under the MIT license:
|
||
* http://www.opensource.org/licenses/mit-license.php
|
||
*
|
||
*/
|
||
|
||
$.tablesorter.addWidget({
|
||
|
||
// Give the new Widget an ID to be used in the tablesorter() call, as follows:
|
||
// $('#myElement').tablesorter({ widgets: ['zebra','staticRow'] });
|
||
id: 'staticRow',
|
||
|
||
// "Format" is run on all widgets once when the tablesorter has finished initialising,
|
||
// and then again every time a sort has finished.
|
||
format: function(table) {
|
||
|
||
// Use a property of the function to determine
|
||
// whether this is the first run of "Format"
|
||
// (i.e. is this the table's default starting position,
|
||
// or has it been sorted?)
|
||
if (typeof $(table).data('hasSorted') == 'undefined')
|
||
{
|
||
$(table).data('hasSorted', true); // This will force us into the "else" block the next time "Format" is run
|
||
|
||
// "Index" the static rows, saving their current (starting)
|
||
// position in the table inside a data() param on the
|
||
// <tr> element itself for later use.
|
||
$('tbody .static', table).each(function() {
|
||
$(this).data('tableindex', $(this).index());
|
||
});
|
||
}
|
||
else
|
||
{
|
||
// Loop the static rows, moving them to their
|
||
// original "indexed" position, and keep doing
|
||
// this until no more re-shuffling needs doing
|
||
var hasShuffled = true;
|
||
|
||
while (hasShuffled)
|
||
{
|
||
hasShuffled = false;
|
||
$('tbody .static', table).each(function() {
|
||
var targetIndex = $(this).data('tableindex');
|
||
if (targetIndex != $(this).index())
|
||
{
|
||
hasShuffled = true;
|
||
var thisRow = $(this).detach();
|
||
var numRows = $('tbody tr', table).length;
|
||
|
||
// Are we trying to be the last row?
|
||
if (targetIndex >= numRows)
|
||
{
|
||
thisRow.appendTo($('tbody', table));
|
||
}
|
||
// Are we trying to be the first row?
|
||
else if (targetIndex == 0)
|
||
{
|
||
thisRow.prependTo($('tbody', table));
|
||
}
|
||
// No, we want to be somewhere in the middle!
|
||
else
|
||
{
|
||
thisRow.insertBefore($('tbody tr:eq(' + targetIndex + ')', table));
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
$('tbody .static-last', table).each(function() {
|
||
var row = $(this).detach();
|
||
row.appendTo($('tbody', table));
|
||
});
|
||
|
||
}
|
||
});
|
||
;/*! jQuery Validation Plugin - v1.13.1 - 10/14/2014
|
||
* http://jqueryvalidation.org/
|
||
* Copyright (c) 2014 Jörn Zaefferer; Licensed MIT */
|
||
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.validateDelegate(":submit","click",function(b){c.settings.submitHandler&&(c.submitButton=b.target),a(b.target).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(b.target).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.submit(function(b){function d(){var d,e;return c.settings.submitHandler?(c.submitButton&&(d=a("<input type='hidden'/>").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),e=c.settings.submitHandler.call(c,c.currentForm,b),c.submitButton&&d.remove(),void 0!==e?e:!1):!0}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c;return a(this[0]).is("form")?b=this.validate().form():(b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b})),b},removeAttrs:function(b){var c={},d=this;return a.each(b.split(/\s/),function(a,b){c[b]=d.attr(b),d.removeAttr(b)}),c},rules:function(b,c){var d,e,f,g,h,i,j=this[0];if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(b,c){i[c]=f[c],delete f[c],"required"===c&&a(j).removeAttr("aria-required")}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g),a(j).attr("aria-required","true")),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}),a.extend(a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){return!!a.trim(""+a(b).val())},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(a,b){(9!==b.which||""!==this.elementValue(a))&&(a.name in this.submitted||a===this.lastElement)&&this.element(a)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},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.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=a.data(this[0].form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!this.is(e.ignore)&&e[d].call(c,this[0],b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox']","focusin focusout keyup",b).validateDelegate("select, option, [type='radio'], [type='checkbox']","click",b),this.settings.invalidHandler&&a(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler),a(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required","true")},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c=this.clean(b),d=this.validationTargetFor(c),e=!0;return this.lastElement=d,void 0===d?delete this.invalid[c.name]:(this.prepareElement(d),this.currentElements=a(d),e=this.check(d)!==!1,e?delete this.invalid[d.name]:this.invalid[d.name]=!0),a(b).attr("aria-invalid",!e),this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),e},showErrors:function(b){if(b){a.extend(this.errorMap,b),this.errorList=[];for(var c in b)this.errorList.push({message:b[c],element:this.findByName(c)[0]});this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue").removeAttr("aria-invalid")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled], [readonly]").not(this.settings.ignore).filter(function(){return!this.name&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in c||!b.objectLength(a(this).rules())?!1:(c[this.name]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([]),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d=a(b),e=b.type;return"radio"===e||"checkbox"===e?a("input[name='"+b.name+"']:checked").val():"number"===e&&"undefined"!=typeof b.validity?b.validity.badInput?!1:d.val():(c=d.val(),"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f=a(b).rules(),g=a.map(f,function(a,b){return b}).length,h=!1,i=this.elementValue(b);for(d in f){e={method:d,parameters:f[d]};try{if(c=a.validator.methods[d].call(this,i,b,e.parameters),"dependency-mismatch"===c&&1===g){h=!0;continue}if(h=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(j){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",j),j}}if(!h)return this.objectLength(f)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a];return void 0},defaultMessage:function(b,c){return this.findDefined(this.customMessage(b.name,c),this.customDataMessage(b,c),!this.settings.ignoreTitle&&b.title||void 0,a.validator.messages[c],"<strong>Warning: No message defined for "+b.name+"</strong>")},formatAndAdd:function(b,c){var d=this.defaultMessage(b,c.method),e=/\$?\{(\d+)\}/g;"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),this.errorList.push({message:d,element:b,method:c.method}),this.errorMap[b.name]=d,this.submitted[b.name]=d},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],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 a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g=this.errorsFor(b),h=this.idOrName(b),i=a(b).attr("aria-describedby");g.length?(g.removeClass(this.settings.validClass).addClass(this.settings.errorClass),g.html(c)):(g=a("<"+this.settings.errorElement+">").attr("id",h+"-error").addClass(this.settings.errorClass).html(c||""),d=g,this.settings.wrapper&&(d=g.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement(d,a(b)):d.insertAfter(b),g.is("label")?g.attr("for",h):0===g.parents("label[for='"+h+"']").length&&(f=g.attr("id").replace(/(:|\.|\[|\])/g,"\\$1"),i?i.match(new RegExp("\\b"+f+"\\b"))||(i+=" "+f):i=f,a(b).attr("aria-describedby",i),e=this.groups[b.name],e&&a.each(this.groups,function(b,c){c===e&&a("[name='"+b+"']",this.currentForm).attr("aria-describedby",g.attr("id"))}))),!c&&this.settings.success&&(g.text(""),"string"==typeof this.settings.success?g.addClass(this.settings.success):this.settings.success(g,b)),this.toShow=this.toShow.add(g)},errorsFor:function(b){var c=this.idOrName(b),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+d.replace(/\s+/g,", #")),this.errors().filter(e)},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+b+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):!0},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(a){this.pending[a.name]||(this.pendingRequest++,this.pending[a.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b){return a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),/min|max/.test(c)&&(null===g||/number|range|text/.test(g))&&(d=Number(d)),d||0===d?e[c]=d:g===c&&"range"!==g&&(e[c]=!0);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b);for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),void 0!==d&&(e[c]=d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0!==e.param?e.param:!0:delete b[d]}}),a.each(b,function(d,e){b[d]=a.isFunction(e)?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:a.trim(b).length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(https?|s?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(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 \-]+/.test(a))return!1;var c,d,e=0,f=0,g=!1;if(a=a.replace(/\D/g,""),a.length<13||a.length>19)return!1;for(c=a.length-1;c>=0;c--)d=a.charAt(c),f=parseInt(d,10),g&&(f*=2)>9&&(f-=9),e+=f,g=!g;return e%10===0},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||d>=e},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||c>=a},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d){if(this.optional(c))return"dependency-mismatch";var e,f,g=this.previousValue(c);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),g.originalMessage=this.settings.messages[c.name].remote,this.settings.messages[c.name].remote=g.message,d="string"==typeof d&&{url:d}||d,g.old===b?g.valid:(g.old=b,e=this,this.startRequest(c),f={},f[c.name]=b,a.ajax(a.extend(!0,{url:d,mode:"abort",port:"validate"+c.name,dataType:"json",data:f,context:e.currentForm,success:function(d){var f,h,i,j=d===!0||"true"===d;e.settings.messages[c.name].remote=g.originalMessage,j?(i=e.formSubmitted,e.prepareElement(c),e.formSubmitted=i,e.successList.push(c),delete e.invalid[c.name],e.showErrors()):(f={},h=d||e.defaultMessage(c,"remote"),f[c.name]=g.message=a.isFunction(h)?h(b):h,e.invalid[c.name]=!0,e.showErrors(f)),g.valid=j,e.stopRequest(c,j)}},d)),"pending")}}}),a.format=function(){throw"$.format has been deprecated. Please use $.validator.format instead."};var b,c={};a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)}),a.extend(a.fn,{validateDelegate:function(b,c,d){return this.bind(c,function(c){var e=a(c.target);return e.is(b)?d.apply(e,arguments):void 0})}})});;function get_dimensions()
|
||
{
|
||
var dims = {width:0,height:0};
|
||
|
||
if( typeof( window.innerWidth ) == 'number' ) {
|
||
//Non-IE
|
||
dims.width = window.innerWidth;
|
||
dims.height = window.innerHeight;
|
||
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
|
||
//IE 6+ in 'standards compliant mode'
|
||
dims.width = document.documentElement.clientWidth;
|
||
dims.height = document.documentElement.clientHeight;
|
||
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
|
||
//IE 4 compatible
|
||
dims.width = document.body.clientWidth;
|
||
dims.height = document.body.clientHeight;
|
||
}
|
||
|
||
return dims;
|
||
}
|
||
|
||
function set_feedback(text, classname, keep_displayed)
|
||
{
|
||
if(text)
|
||
{
|
||
$('#feedback_bar').removeClass().addClass(classname).html(text).css('opacity','1');
|
||
|
||
if(!keep_displayed)
|
||
{
|
||
$('#feedback_bar').fadeTo(5000, 1).fadeTo("fast",0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
$('#feedback_bar').css('opacity','0');
|
||
}
|
||
}
|
||
|
||
;(function($){
|
||
//keylisteners
|
||
$.each(['customers', 'items', 'reports', 'receivings', 'sales'], function(key, value) {
|
||
$(window).jkey('f' + (key+1), function(){
|
||
window.location = BASE_URL + '/' + value + '/index';
|
||
});
|
||
});
|
||
})(jQuery);
|
||
;/*
|
||
* Date prototype extensions. Doesn't depend on any
|
||
* other code. Doens't overwrite existing methods.
|
||
*
|
||
* Adds dayNames, abbrDayNames, monthNames and abbrMonthNames static properties and isLeapYear,
|
||
* isWeekend, isWeekDay, getDaysInMonth, getDayName, getMonthName, getDayOfYear, getWeekOfYear,
|
||
* setDayOfYear, addYears, addMonths, addDays, addHours, addMinutes, addSeconds methods
|
||
*
|
||
* Copyright (c) 2006 Jörn Zaefferer and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
|
||
*
|
||
* Additional methods and properties added by Kelvin Luck: firstDayOfWeek, dateFormat, zeroTime, asString, fromString -
|
||
* I've added my name to these methods so you know who to blame if they are broken!
|
||
*
|
||
* Dual licensed under the MIT and GPL licenses:
|
||
* http://www.opensource.org/licenses/mit-license.php
|
||
* http://www.gnu.org/licenses/gpl.html
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* An Array of day names starting with Sunday.
|
||
*
|
||
* @example dayNames[0]
|
||
* @result 'Sunday'
|
||
*
|
||
* @name dayNames
|
||
* @type Array
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
Date.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||
|
||
/**
|
||
* An Array of abbreviated day names starting with Sun.
|
||
*
|
||
* @example abbrDayNames[0]
|
||
* @result 'Sun'
|
||
*
|
||
* @name abbrDayNames
|
||
* @type Array
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
Date.abbrDayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||
|
||
/**
|
||
* An Array of month names starting with Janurary.
|
||
*
|
||
* @example monthNames[0]
|
||
* @result 'January'
|
||
*
|
||
* @name monthNames
|
||
* @type Array
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
Date.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||
|
||
/**
|
||
* An Array of abbreviated month names starting with Jan.
|
||
*
|
||
* @example abbrMonthNames[0]
|
||
* @result 'Jan'
|
||
*
|
||
* @name monthNames
|
||
* @type Array
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
Date.abbrMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||
|
||
/**
|
||
* The first day of the week for this locale.
|
||
*
|
||
* @name firstDayOfWeek
|
||
* @type Number
|
||
* @cat Plugins/Methods/Date
|
||
* @author Kelvin Luck
|
||
*/
|
||
Date.firstDayOfWeek = 1;
|
||
|
||
/**
|
||
* The format that string dates should be represented as (e.g. 'dd/mm/yyyy' for UK, 'mm/dd/yyyy' for US, 'yyyy-mm-dd' for Unicode etc).
|
||
*
|
||
* @name format
|
||
* @type String
|
||
* @cat Plugins/Methods/Date
|
||
* @author Kelvin Luck
|
||
*/
|
||
Date.format = 'mm/dd/yyyy';
|
||
//Date.format = 'mm/dd/yyyy';
|
||
//Date.format = 'yyyy-mm-dd';
|
||
//Date.format = 'dd mmm yy';
|
||
|
||
/**
|
||
* The first two numbers in the century to be used when decoding a two digit year. Since a two digit year is ambiguous (and date.setYear
|
||
* only works with numbers < 99 and so doesn't allow you to set years after 2000) we need to use this to disambiguate the two digit year codes.
|
||
*
|
||
* @name format
|
||
* @type String
|
||
* @cat Plugins/Methods/Date
|
||
* @author Kelvin Luck
|
||
*/
|
||
Date.fullYearStart = '20';
|
||
|
||
(function() {
|
||
|
||
/**
|
||
* Adds a given method under the given name
|
||
* to the Date prototype if it doesn't
|
||
* currently exist.
|
||
*
|
||
* @private
|
||
*/
|
||
function add(name, method) {
|
||
if( !Date.prototype[name] ) {
|
||
Date.prototype[name] = method;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Checks if the year is a leap year.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.isLeapYear();
|
||
* @result true
|
||
*
|
||
* @name isLeapYear
|
||
* @type Boolean
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("isLeapYear", function() {
|
||
var y = this.getFullYear();
|
||
return (y%4==0 && y%100!=0) || y%400==0;
|
||
});
|
||
|
||
/**
|
||
* Checks if the day is a weekend day (Sat or Sun).
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.isWeekend();
|
||
* @result false
|
||
*
|
||
* @name isWeekend
|
||
* @type Boolean
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("isWeekend", function() {
|
||
return this.getDay()==0 || this.getDay()==6;
|
||
});
|
||
|
||
/**
|
||
* Check if the day is a day of the week (Mon-Fri)
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.isWeekDay();
|
||
* @result false
|
||
*
|
||
* @name isWeekDay
|
||
* @type Boolean
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("isWeekDay", function() {
|
||
return !this.isWeekend();
|
||
});
|
||
|
||
/**
|
||
* Gets the number of days in the month.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getDaysInMonth();
|
||
* @result 31
|
||
*
|
||
* @name getDaysInMonth
|
||
* @type Number
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("getDaysInMonth", function() {
|
||
return [31,(this.isLeapYear() ? 29:28),31,30,31,30,31,31,30,31,30,31][this.getMonth()];
|
||
});
|
||
|
||
/**
|
||
* Gets the name of the day.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getDayName();
|
||
* @result 'Saturday'
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getDayName(true);
|
||
* @result 'Sat'
|
||
*
|
||
* @param abbreviated Boolean When set to true the name will be abbreviated.
|
||
* @name getDayName
|
||
* @type String
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("getDayName", function(abbreviated) {
|
||
return abbreviated ? Date.abbrDayNames[this.getDay()] : Date.dayNames[this.getDay()];
|
||
});
|
||
|
||
/**
|
||
* Gets the name of the month.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getMonthName();
|
||
* @result 'Janurary'
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getMonthName(true);
|
||
* @result 'Jan'
|
||
*
|
||
* @param abbreviated Boolean When set to true the name will be abbreviated.
|
||
* @name getDayName
|
||
* @type String
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("getMonthName", function(abbreviated) {
|
||
return abbreviated ? Date.abbrMonthNames[this.getMonth()] : Date.monthNames[this.getMonth()];
|
||
});
|
||
|
||
/**
|
||
* Get the number of the day of the year.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getDayOfYear();
|
||
* @result 11
|
||
*
|
||
* @name getDayOfYear
|
||
* @type Number
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("getDayOfYear", function() {
|
||
var tmpdtm = new Date("1/1/" + this.getFullYear());
|
||
return Math.floor((this.getTime() - tmpdtm.getTime()) / 86400000);
|
||
});
|
||
|
||
/**
|
||
* Get the number of the week of the year.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.getWeekOfYear();
|
||
* @result 2
|
||
*
|
||
* @name getWeekOfYear
|
||
* @type Number
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("getWeekOfYear", function() {
|
||
return Math.ceil(this.getDayOfYear() / 7);
|
||
});
|
||
|
||
/**
|
||
* Set the day of the year.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.setDayOfYear(1);
|
||
* dtm.toString();
|
||
* @result 'Tue Jan 01 2008 00:00:00'
|
||
*
|
||
* @name setDayOfYear
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("setDayOfYear", function(day) {
|
||
this.setMonth(0);
|
||
this.setDate(day);
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Add a number of years to the date object.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.addYears(1);
|
||
* dtm.toString();
|
||
* @result 'Mon Jan 12 2009 00:00:00'
|
||
*
|
||
* @name addYears
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("addYears", function(num) {
|
||
this.setFullYear(this.getFullYear() + num);
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Add a number of months to the date object.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.addMonths(1);
|
||
* dtm.toString();
|
||
* @result 'Tue Feb 12 2008 00:00:00'
|
||
*
|
||
* @name addMonths
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("addMonths", function(num) {
|
||
var tmpdtm = this.getDate();
|
||
|
||
this.setMonth(this.getMonth() + num);
|
||
|
||
if (tmpdtm > this.getDate())
|
||
this.addDays(-this.getDate());
|
||
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Add a number of days to the date object.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.addDays(1);
|
||
* dtm.toString();
|
||
* @result 'Sun Jan 13 2008 00:00:00'
|
||
*
|
||
* @name addDays
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("addDays", function(num) {
|
||
//this.setDate(this.getDate() + num);
|
||
this.setTime(this.getTime() + (num*86400000) );
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Add a number of hours to the date object.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.addHours(24);
|
||
* dtm.toString();
|
||
* @result 'Sun Jan 13 2008 00:00:00'
|
||
*
|
||
* @name addHours
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("addHours", function(num) {
|
||
this.setHours(this.getHours() + num);
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Add a number of minutes to the date object.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.addMinutes(60);
|
||
* dtm.toString();
|
||
* @result 'Sat Jan 12 2008 01:00:00'
|
||
*
|
||
* @name addMinutes
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("addMinutes", function(num) {
|
||
this.setMinutes(this.getMinutes() + num);
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Add a number of seconds to the date object.
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.addSeconds(60);
|
||
* dtm.toString();
|
||
* @result 'Sat Jan 12 2008 00:01:00'
|
||
*
|
||
* @name addSeconds
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
*/
|
||
add("addSeconds", function(num) {
|
||
this.setSeconds(this.getSeconds() + num);
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Sets the time component of this Date to zero for cleaner, easier comparison of dates where time is not relevant.
|
||
*
|
||
* @example var dtm = new Date();
|
||
* dtm.zeroTime();
|
||
* dtm.toString();
|
||
* @result 'Sat Jan 12 2008 00:01:00'
|
||
*
|
||
* @name zeroTime
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
* @author Kelvin Luck
|
||
*/
|
||
add("zeroTime", function() {
|
||
this.setMilliseconds(0);
|
||
this.setSeconds(0);
|
||
this.setMinutes(0);
|
||
this.setHours(0);
|
||
return this;
|
||
});
|
||
|
||
/**
|
||
* Returns a string representation of the date object according to Date.format.
|
||
* (Date.toString may be used in other places so I purposefully didn't overwrite it)
|
||
*
|
||
* @example var dtm = new Date("01/12/2008");
|
||
* dtm.asString();
|
||
* @result '12/01/2008' // (where Date.format == 'dd/mm/yyyy'
|
||
*
|
||
* @name asString
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
* @author Kelvin Luck
|
||
*/
|
||
add("asString", function(format) {
|
||
var r = format || Date.format;
|
||
return r
|
||
.split('yyyy').join(this.getFullYear())
|
||
.split('yy').join((this.getFullYear() + '').substring(2))
|
||
.split('mmmm').join(this.getMonthName(false))
|
||
.split('mmm').join(this.getMonthName(true))
|
||
.split('mm').join(_zeroPad(this.getMonth()+1))
|
||
.split('dd').join(_zeroPad(this.getDate()))
|
||
.split('hh').join(_zeroPad(this.getHours()))
|
||
.split('min').join(_zeroPad(this.getMinutes()))
|
||
.split('ss').join(_zeroPad(this.getSeconds()));
|
||
});
|
||
|
||
/**
|
||
* Returns a new date object created from the passed String according to Date.format or false if the attempt to do this results in an invalid date object
|
||
* (We can't simple use Date.parse as it's not aware of locale and I chose not to overwrite it incase it's functionality is being relied on elsewhere)
|
||
*
|
||
* @example var dtm = Date.fromString("12/01/2008");
|
||
* dtm.toString();
|
||
* @result 'Sat Jan 12 2008 00:00:00' // (where Date.format == 'dd/mm/yyyy'
|
||
*
|
||
* @name fromString
|
||
* @type Date
|
||
* @cat Plugins/Methods/Date
|
||
* @author Kelvin Luck
|
||
*/
|
||
Date.fromString = function(s, format)
|
||
{
|
||
var f = format || Date.format;
|
||
var d = new Date('01/01/1977');
|
||
|
||
var mLength = 0;
|
||
|
||
var iM = f.indexOf('mmmm');
|
||
if (iM > -1) {
|
||
for (var i=0; i<Date.monthNames.length; i++) {
|
||
var mStr = s.substr(iM, Date.monthNames[i].length);
|
||
if (Date.monthNames[i] == mStr) {
|
||
mLength = Date.monthNames[i].length - 4;
|
||
break;
|
||
}
|
||
}
|
||
d.setMonth(i);
|
||
} else {
|
||
iM = f.indexOf('mmm');
|
||
if (iM > -1) {
|
||
var mStr = s.substr(iM, 3);
|
||
for (var i=0; i<Date.abbrMonthNames.length; i++) {
|
||
if (Date.abbrMonthNames[i] == mStr) break;
|
||
}
|
||
d.setMonth(i);
|
||
} else {
|
||
d.setMonth(Number(s.substr(f.indexOf('mm'), 2)) - 1);
|
||
}
|
||
}
|
||
|
||
var iY = f.indexOf('yyyy');
|
||
|
||
if (iY > -1) {
|
||
if (iM < iY)
|
||
{
|
||
iY += mLength;
|
||
}
|
||
d.setFullYear(Number(s.substr(iY, 4)));
|
||
} else {
|
||
if (iM < iY)
|
||
{
|
||
iY += mLength;
|
||
}
|
||
// TODO - this doesn't work very well - are there any rules for what is meant by a two digit year?
|
||
d.setFullYear(Number(Date.fullYearStart + s.substr(f.indexOf('yy'), 2)));
|
||
}
|
||
var iD = f.indexOf('dd');
|
||
if (iM < iD)
|
||
{
|
||
iD += mLength;
|
||
}
|
||
d.setDate(Number(s.substr(iD, 2)));
|
||
if (isNaN(d.getTime())) {
|
||
return false;
|
||
}
|
||
return d;
|
||
};
|
||
|
||
// utility method
|
||
var _zeroPad = function(num) {
|
||
var s = '0'+num;
|
||
return s.substring(s.length-2)
|
||
//return ('0'+num).substring(-2); // doesn't work on IE :(
|
||
};
|
||
|
||
})();;/*
|
||
* imgPreview jQuery plugin
|
||
* Copyright (c) 2009 James Padolsey
|
||
* j@qd9.co.uk | http://james.padolsey.com
|
||
* Dual licensed under MIT and GPL.
|
||
* Updated: 09/02/09
|
||
* @author James Padolsey
|
||
* @version 0.22
|
||
*/
|
||
(function($){
|
||
|
||
$.expr[':'].linkingToImage = function(elem, index, match){
|
||
// This will return true if the specified attribute contains a valid link to an image:
|
||
return !! ($(elem).attr(match[3]) && $(elem).attr(match[3]).match(/\.(gif|jpe?g|png|bmp)$/i));
|
||
};
|
||
|
||
$.fn.imgPreview = function(userDefinedSettings){
|
||
|
||
var s = $.extend({
|
||
|
||
/* DEFAULTS */
|
||
|
||
// CSS to be applied to image:
|
||
imgCSS: {},
|
||
// Distance between cursor and preview:
|
||
distanceFromCursor: {top:10, left:10},
|
||
// Boolean, whether or not to preload images:
|
||
preloadImages: true,
|
||
// Callback: run when link is hovered: container is shown:
|
||
onShow: function(){},
|
||
// Callback: container is hidden:
|
||
onHide: function(){},
|
||
// Callback: Run when image within container has loaded:
|
||
onLoad: function(){},
|
||
// ID to give to container (for CSS styling):
|
||
containerID: 'imgPreviewContainer',
|
||
// Class to be given to container while image is loading:
|
||
containerLoadingClass: 'loading',
|
||
// Prefix (if using thumbnails), e.g. 'thumb_'
|
||
thumbPrefix: '',
|
||
// Where to retrieve the image from:
|
||
srcAttr: 'href'
|
||
|
||
}, userDefinedSettings),
|
||
|
||
$container = $('<div/>').attr('id', s.containerID)
|
||
.append('<img/>').hide()
|
||
.css('position','absolute')
|
||
.appendTo('body'),
|
||
|
||
$img = $('img', $container).css(s.imgCSS),
|
||
|
||
// Get all valid elements (linking to images / ATTR with image link):
|
||
$collection = this.filter(':linkingToImage(' + s.srcAttr + ')');
|
||
|
||
// Re-usable means to add prefix (from setting):
|
||
function addPrefix(src) {
|
||
return src && src.replace(/(\/?)([^\/]+)$/,'$1' + s.thumbPrefix + '$2');
|
||
}
|
||
|
||
if (s.preloadImages) {
|
||
(function(i){
|
||
var tempIMG = new Image(),
|
||
callee = arguments.callee;
|
||
var src = $($collection[i]).attr(s.srcAttr)
|
||
if (src)
|
||
{
|
||
tempIMG.src = addPrefix(src);
|
||
tempIMG.onload = function(){
|
||
$collection[i + 1] && callee(i + 1);
|
||
};
|
||
}
|
||
})(0);
|
||
}
|
||
|
||
$collection
|
||
.mousemove(function(e){
|
||
|
||
$container.css({
|
||
top: e.pageY + s.distanceFromCursor.top + 'px',
|
||
left: e.pageX + s.distanceFromCursor.left + 'px'
|
||
});
|
||
|
||
})
|
||
.hover(function(){
|
||
|
||
var link = this;
|
||
$container
|
||
.addClass(s.containerLoadingClass)
|
||
.show();
|
||
$img
|
||
.load(function(){
|
||
$container.removeClass(s.containerLoadingClass);
|
||
$img.show();
|
||
s.onLoad.call($img[0], link);
|
||
})
|
||
.attr( 'src' , addPrefix($(link).attr(s.srcAttr)) );
|
||
s.onShow.call($container[0], link);
|
||
|
||
}, function(){
|
||
|
||
$container.hide();
|
||
$img.unbind('load').attr('src','').hide();
|
||
s.onHide.call($container[0], this);
|
||
|
||
});
|
||
|
||
// Return full selection, not $collection!
|
||
return this;
|
||
|
||
};
|
||
|
||
})(jQuery);;function checkbox_click(event)
|
||
{
|
||
event.stopPropagation();
|
||
do_email(enable_email.url);
|
||
if($(event.target).attr('checked'))
|
||
{
|
||
$(event.target).parent().parent().find("td").addClass('selected').css("backgroundColor","");
|
||
}
|
||
else
|
||
{
|
||
$(event.target).parent().parent().find("td").removeClass();
|
||
}
|
||
}
|
||
|
||
function enable_search(options)
|
||
{
|
||
if (!options.format_item) {
|
||
format_item = function(results) {
|
||
return results[0];
|
||
};
|
||
}
|
||
//Keep track of enable_email has been called
|
||
if(!enable_search.enabled)
|
||
enable_search.enabled=true;
|
||
|
||
$('#search').click(function()
|
||
{
|
||
$(this).attr('value','');
|
||
});
|
||
|
||
var widget = $("#search").autocomplete(options.suggest_url,{max:100,delay:10, selectFirst: false,
|
||
formatItem : options.format_item, extraParams: options.extra_params});
|
||
$("#search").result(function(event, data, formatted)
|
||
{
|
||
do_search(true, options.on_complete);
|
||
});
|
||
|
||
attach_search_listener();
|
||
|
||
$('#search_form').submit(function(event)
|
||
{
|
||
event.preventDefault();
|
||
// reset page number when selecting a specific page number
|
||
$('#limit_from').val(0);
|
||
if(get_selected_values().length >0)
|
||
{
|
||
if(!confirm(options.confirm_search_message))
|
||
return;
|
||
}
|
||
do_search(true, options.on_complete);
|
||
});
|
||
|
||
return widget;
|
||
}
|
||
enable_search.enabled=false;
|
||
|
||
function attach_search_listener()
|
||
{
|
||
// prevent redirecting to link when search enabled
|
||
$("#pagination a").click(function(event) {
|
||
if ($("#search").val() || $("#search_form input:checked")) {
|
||
event.preventDefault();
|
||
// set limit_from to value included in the link
|
||
var uri_segments = event.currentTarget.href.split('/');
|
||
var limit_from = uri_segments.pop();
|
||
$('#limit_from').val(limit_from);
|
||
do_search(true);
|
||
}
|
||
});
|
||
}
|
||
|
||
function do_search(show_feedback,on_complete)
|
||
{
|
||
//If search is not enabled, don't do anything
|
||
if(!enable_search.enabled)
|
||
return;
|
||
|
||
if(show_feedback)
|
||
$('#search').addClass("ac_loading");
|
||
|
||
$.post(
|
||
$('#search_form').attr('action'),
|
||
// serialize all the input fields in the form
|
||
$('#search_form').serialize(),
|
||
function(response) {
|
||
$('#sortable_table tbody').html(response.rows);
|
||
if(typeof on_complete=='function')
|
||
on_complete(response);
|
||
$('#search').removeClass("ac_loading");
|
||
//$('#spinner').hide();
|
||
//re-init elements in new table, as table tbody children were replaced
|
||
tb_init('#sortable_table a.thickbox');
|
||
$('#pagination').html(response.pagination);
|
||
$('#sortable_table tbody :checkbox').click(checkbox_click);
|
||
$("#select_all").attr('checked',false);
|
||
if (response.total_rows > 0)
|
||
{
|
||
update_sortable_table();
|
||
enable_row_selection();
|
||
}
|
||
attach_search_listener();
|
||
}, "json"
|
||
);
|
||
}
|
||
|
||
function enable_email(email_url)
|
||
{
|
||
//Keep track of enable_email has been called
|
||
if(!enable_email.enabled)
|
||
enable_email.enabled=true;
|
||
|
||
//store url in function cache
|
||
if(!enable_email.url)
|
||
{
|
||
enable_email.url=email_url;
|
||
}
|
||
|
||
$('#select_all, #sortable_table tbody :checkbox').click(checkbox_click);
|
||
}
|
||
enable_email.enabled=false;
|
||
enable_email.url=false;
|
||
|
||
function do_email(url)
|
||
{
|
||
//If email is not enabled, don't do anything
|
||
if(!enable_email.enabled)
|
||
return;
|
||
|
||
$.post(url, { 'ids[]': get_selected_values() },function(response)
|
||
{
|
||
$('#email').attr('href',response);
|
||
});
|
||
|
||
}
|
||
|
||
function enable_checkboxes()
|
||
{
|
||
$('#sortable_table tbody :checkbox').click(checkbox_click);
|
||
}
|
||
|
||
function enable_delete(confirm_message,none_selected_message)
|
||
{
|
||
//Keep track of enable_delete has been called
|
||
if(!enable_delete.enabled)
|
||
enable_delete.enabled=true;
|
||
|
||
$("#delete").click(function(event)
|
||
{
|
||
event.preventDefault();
|
||
if($("#sortable_table tbody :checkbox:checked").length >0)
|
||
{
|
||
if(confirm(confirm_message))
|
||
{
|
||
do_delete($(this).attr('href'));
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
alert(none_selected_message);
|
||
}
|
||
});
|
||
}
|
||
enable_delete.enabled=false;
|
||
|
||
function do_delete(url)
|
||
{
|
||
//If delete is not enabled, don't do anything
|
||
if(!enable_delete.enabled)
|
||
return;
|
||
|
||
var row_ids = get_selected_values();
|
||
var selected_rows = get_selected_rows();
|
||
$.post(url, { 'ids[]': row_ids },function(response)
|
||
{
|
||
//delete was successful, remove checkbox rows
|
||
if(response.success)
|
||
{
|
||
$(selected_rows).each(function(index, dom)
|
||
{
|
||
$(this).find("td").animate({backgroundColor:"green"},1200,"linear")
|
||
.end().animate({opacity:0},1200,"linear",function()
|
||
{
|
||
$(this).remove();
|
||
//Re-init sortable table as we removed a row
|
||
$("#sortable_table tbody tr").length > 0 && update_sortable_table();
|
||
|
||
});
|
||
});
|
||
|
||
set_feedback(response.message,'success_message',false);
|
||
}
|
||
else
|
||
{
|
||
set_feedback(response.message,'error_message',true);
|
||
}
|
||
|
||
|
||
},"json");
|
||
}
|
||
|
||
function enable_bulk_edit(none_selected_message)
|
||
{
|
||
//Keep track of enable_bulk_edit has been called
|
||
if(!enable_bulk_edit.enabled)
|
||
enable_bulk_edit.enabled=true;
|
||
|
||
$('#bulk_edit').click(function(event)
|
||
{
|
||
event.preventDefault();
|
||
if($("#sortable_table tbody :checkbox:checked").length >0)
|
||
{
|
||
tb_show($(this).attr('title'),$(this).attr('href'),false);
|
||
$(this).blur();
|
||
}
|
||
else
|
||
{
|
||
alert(none_selected_message);
|
||
}
|
||
});
|
||
}
|
||
enable_bulk_edit.enabled=false;
|
||
|
||
function enable_select_all()
|
||
{
|
||
//Keep track of enable_select_all has been called
|
||
if(!enable_select_all.enabled)
|
||
enable_select_all.enabled=true;
|
||
|
||
$('#select_all').click(function()
|
||
{
|
||
if($(this).attr('checked'))
|
||
{
|
||
$("#sortable_table tbody :checkbox").each(function()
|
||
{
|
||
$(this).attr('checked',true);
|
||
$(this).parent().parent().find("td").addClass('selected').css("backgroundColor","");
|
||
|
||
});
|
||
}
|
||
else
|
||
{
|
||
$("#sortable_table tbody :checkbox").each(function()
|
||
{
|
||
$(this).attr('checked',false);
|
||
$(this).parent().parent().find("td").removeClass();
|
||
});
|
||
}
|
||
});
|
||
}
|
||
enable_select_all.enabled=false;
|
||
|
||
function enable_row_selection(rows)
|
||
{
|
||
//Keep track of enable_row_selection has been called
|
||
if(!enable_row_selection.enabled)
|
||
enable_row_selection.enabled=true;
|
||
|
||
if(typeof rows =="undefined")
|
||
rows=$("#sortable_table tbody tr");
|
||
|
||
rows.hover(
|
||
function row_over()
|
||
{
|
||
$(this).find("td").addClass('over').css("backgroundColor","");
|
||
$(this).css("cursor","pointer");
|
||
},
|
||
|
||
function row_out()
|
||
{
|
||
if(!$(this).find("td").hasClass("selected"))
|
||
{
|
||
$(this).find("td").removeClass();
|
||
}
|
||
}
|
||
);
|
||
|
||
rows.click(function row_click(event)
|
||
{
|
||
|
||
var checkbox = $(this).find(":checkbox");
|
||
checkbox.attr('checked',!checkbox.attr('checked'));
|
||
do_email(enable_email.url);
|
||
|
||
if(checkbox.attr('checked'))
|
||
{
|
||
$(this).find("td").addClass('selected').css("backgroundColor","");
|
||
}
|
||
else
|
||
{
|
||
$(this).find("td").removeClass();
|
||
}
|
||
});
|
||
}
|
||
enable_row_selection.enabled=false;
|
||
|
||
function update_sortable_table()
|
||
{
|
||
//let tablesorter know we changed <tbody> and then triger a resort
|
||
$("#sortable_table").trigger("update");
|
||
if(typeof $("#sortable_table")[0].config!="undefined")
|
||
{
|
||
var sorting = $("#sortable_table")[0].config.sortList;
|
||
$("#sortable_table").trigger("sorton",[sorting]);
|
||
}
|
||
else
|
||
{
|
||
window['init_table_sorting'] && init_table_sorting();
|
||
}
|
||
}
|
||
|
||
function get_table_row(id) {
|
||
id = id || $("input[name='sale_id']").val();
|
||
var $element = $("#sortable_table tbody :checkbox[value='" + id + "']");
|
||
if ($element.length === 0) {
|
||
$element = $("#sortable_table tbody a[href*='/" + id + "/']");
|
||
}
|
||
return $element;
|
||
}
|
||
|
||
function update_row(row_id,url,callback)
|
||
{
|
||
$.post(url, { 'row_id': row_id },function(response)
|
||
{
|
||
//Replace previous row
|
||
var row_to_update = get_table_row(row_id).parent().parent();
|
||
row_to_update.replaceWith(response);
|
||
reinit_row(row_id);
|
||
hightlight_row(row_id);
|
||
callback && typeof(callback) == "function" && callback();
|
||
}, 'html');
|
||
}
|
||
|
||
function reinit_row(checkbox_id)
|
||
{
|
||
var new_checkbox = $("#sortable_table tbody tr :checkbox[value="+checkbox_id+"]");
|
||
var new_row = new_checkbox.parent().parent();
|
||
enable_row_selection(new_row);
|
||
//Re-init some stuff as we replaced row
|
||
update_sortable_table();
|
||
tb_init(new_row.find("a.thickbox"));
|
||
//re-enable e-mail
|
||
new_checkbox.click(checkbox_click);
|
||
}
|
||
|
||
function animate_row(row,color)
|
||
{
|
||
color = color || "#e1ffdd";
|
||
row.find("td").css("backgroundColor", "#ffffff").animate({backgroundColor:color},"slow","linear")
|
||
.animate({backgroundColor:color},5000)
|
||
.animate({backgroundColor:"#ffffff"},"slow","linear");
|
||
}
|
||
|
||
function hightlight_row(checkbox_id)
|
||
{
|
||
var new_checkbox = $("#sortable_table tbody tr :checkbox[value="+checkbox_id+"]");
|
||
var new_row = new_checkbox.parent().parent();
|
||
|
||
animate_row(new_row);
|
||
}
|
||
|
||
function get_selected_values()
|
||
{
|
||
var selected_values = new Array();
|
||
$("#sortable_table tbody :checkbox:checked").each(function()
|
||
{
|
||
selected_values.push($(this).val());
|
||
});
|
||
return selected_values;
|
||
}
|
||
|
||
function get_selected_rows()
|
||
{
|
||
var selected_rows = new Array();
|
||
$("#sortable_table tbody :checkbox:checked").each(function()
|
||
{
|
||
selected_rows.push($(this).parent().parent());
|
||
});
|
||
return selected_rows;
|
||
}
|
||
|
||
function get_visible_checkbox_ids()
|
||
{
|
||
var row_ids = new Array();
|
||
$("#sortable_table tbody :checkbox").each(function()
|
||
{
|
||
row_ids.push($(this).val());
|
||
});
|
||
return row_ids;
|
||
};(function($) {
|
||
|
||
function http_s(url)
|
||
{
|
||
return document.location.protocol + '//' + url;
|
||
}
|
||
|
||
if (window.sessionStorage && !sessionStorage['country'])
|
||
{
|
||
$.ajax({
|
||
type: "GET",
|
||
url: http_s('ipinfo.io/json'),
|
||
success: function(response) {
|
||
sessionStorage['country'] = response.country;
|
||
}, dataType: 'jsonp'
|
||
});
|
||
}
|
||
|
||
var url = http_s('nominatim.openstreetmap.org/search');
|
||
|
||
var handle_auto_completion = function(fields) {
|
||
return function(event, results, formatted) {
|
||
if (results != null && results.length > 0) {
|
||
// handle auto completion
|
||
for(var i in fields) {
|
||
$("#" + fields[i]).val(results[i]);
|
||
}
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
};
|
||
|
||
var set_field_values = function(results) {
|
||
return results[0] + ' - ' + results[1];
|
||
};
|
||
|
||
var create_parser = function(field_name, parse_format)
|
||
{
|
||
var parse_field = function(format, address)
|
||
{
|
||
var fields = [];
|
||
$.each(format.split("|"), function(key, value)
|
||
{
|
||
if (address[value] && fields.length < 2 && $.inArray(address[value], fields) === -1)
|
||
{
|
||
fields.push(address[value]);
|
||
}
|
||
});
|
||
return fields[0] + (fields[1] ? ' (' + fields[1] + ')' : '');
|
||
};
|
||
|
||
return function(data)
|
||
{
|
||
var parsed = [];
|
||
$.each(data, function(index, value)
|
||
{
|
||
var address = value.address;
|
||
var row = [];
|
||
$.each(parse_format, function(key, format)
|
||
{
|
||
row.push(parse_field(format, address));
|
||
});
|
||
parsed[index] = {
|
||
data: row,
|
||
value: address[field_name],
|
||
result: address[field_name]
|
||
};
|
||
});
|
||
return parsed;
|
||
};
|
||
};
|
||
|
||
var request_params = function(id, key, language)
|
||
{
|
||
return function() {
|
||
var result = {
|
||
format: 'json',
|
||
limit: 5,
|
||
addressdetails: 1,
|
||
country: window['sessionStorage'] ? sessionStorage['country'] : 'be',
|
||
'accept-language' : language || navigator.language
|
||
};
|
||
result[key || id] = $("#"+id).val();
|
||
return result;
|
||
}
|
||
|
||
};
|
||
|
||
var nominatim = {
|
||
|
||
init : function(options) {
|
||
|
||
$.each(options.fields, function(key, value)
|
||
{
|
||
var handle_field_completion = handle_auto_completion(value.dependencies);
|
||
$("#" + key).autocomplete(url,{
|
||
max:100,
|
||
minChars:3,
|
||
delay:500,
|
||
formatItem: set_field_values,
|
||
type: 'GET',
|
||
dataType:'json',
|
||
extraParams: request_params(key, value.response && value.response.field, options.language),
|
||
parse: create_parser(key, (value.response && value.response.format) || value.dependencies)
|
||
});
|
||
$("#" + key).result(handle_field_completion);
|
||
});
|
||
}
|
||
|
||
};
|
||
|
||
window['nominatim'] = nominatim;
|
||
|
||
})(jQuery);;/* SWFObject v2.1 <http://code.google.com/p/swfobject/>
|
||
Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
|
||
This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
|
||
*/
|
||
var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("<script id=__ie_ondomload defer=true src=//:><\/script>");J=C("__ie_ondomload");if(J){I(J,"onreadystatechange",S)}}catch(q){}}if(h.webkit&&typeof K.readyState!=b){Z=setInterval(function(){if(/loaded|complete/.test(K.readyState)){E()}},10)}if(typeof K.addEventListener!=b){K.addEventListener("DOMContentLoaded",E,null)}R(E)}();function S(){if(J.readyState=="complete"){J.parentNode.removeChild(J);E()}}function E(){if(e){return }if(h.ie&&h.win){var v=a("span");try{var u=K.getElementsByTagName("body")[0].appendChild(v);u.parentNode.removeChild(u)}catch(w){return }}e=true;if(Z){clearInterval(Z);Z=null}var q=o.length;for(var r=0;r<q;r++){o[r]()}}function f(q){if(e){q()}else{o[o.length]=q}}function R(r){if(typeof j.addEventListener!=b){j.addEventListener("load",r,false)}else{if(typeof K.addEventListener!=b){K.addEventListener("load",r,false)}else{if(typeof j.attachEvent!=b){I(j,"onload",r)}else{if(typeof j.onload=="function"){var q=j.onload;j.onload=function(){q();r()}}else{j.onload=r}}}}}function H(){var t=N.length;for(var q=0;q<t;q++){var u=N[q].id;if(h.pv[0]>0){var r=C(u);if(r){N[q].width=r.getAttribute("width")?r.getAttribute("width"):"0";N[q].height=r.getAttribute("height")?r.getAttribute("height"):"0";if(c(N[q].swfVersion)){if(h.webkit&&h.webkit<312){Y(r)}W(u,true)}else{if(N[q].expressInstall&&!A&&c("6.0.65")&&(h.win||h.mac)){k(N[q])}else{O(r)}}}}else{W(u,true)}}}function Y(t){var q=t.getElementsByTagName(Q)[0];if(q){var w=a("embed"),y=q.attributes;if(y){var v=y.length;for(var u=0;u<v;u++){if(y[u].nodeName=="DATA"){w.setAttribute("src",y[u].nodeValue)}else{w.setAttribute(y[u].nodeName,y[u].nodeValue)}}}var x=q.childNodes;if(x){var z=x.length;for(var r=0;r<z;r++){if(x[r].nodeType==1&&x[r].nodeName=="PARAM"){w.setAttribute(x[r].getAttribute("name"),x[r].getAttribute("value"))}}}t.parentNode.replaceChild(w,t)}}function k(w){A=true;var u=C(w.id);if(u){if(w.altContentId){var y=C(w.altContentId);if(y){M=y;l=w.altContentId}}else{M=G(u)}if(!(/%$/.test(w.width))&&parseInt(w.width,10)<310){w.width="310"}if(!(/%$/.test(w.height))&&parseInt(w.height,10)<137){w.height="137"}K.title=K.title.slice(0,47)+" - Flash Player Installation";var z=h.ie&&h.win?"ActiveX":"PlugIn",q=K.title,r="MMredirectURL="+j.location+"&MMplayerType="+z+"&MMdoctitle="+q,x=w.id;if(h.ie&&h.win&&u.readyState!=4){var t=a("div");x+="SWFObjectNew";t.setAttribute("id",x);u.parentNode.insertBefore(t,u);u.style.display="none";var v=function(){u.parentNode.removeChild(u)};I(j,"onload",v)}U({data:w.expressInstall,id:m,width:w.width,height:w.height},{flashvars:r},x)}}function O(t){if(h.ie&&h.win&&t.readyState!=4){var r=a("div");t.parentNode.insertBefore(r,t);r.parentNode.replaceChild(G(t),r);t.style.display="none";var q=function(){t.parentNode.removeChild(t)};I(j,"onload",q)}else{t.parentNode.replaceChild(G(t),t)}}function G(v){var u=a("div");if(h.win&&h.ie){u.innerHTML=v.innerHTML}else{var r=v.getElementsByTagName(Q)[0];if(r){var w=r.childNodes;if(w){var q=w.length;for(var t=0;t<q;t++){if(!(w[t].nodeType==1&&w[t].nodeName=="PARAM")&&!(w[t].nodeType==8)){u.appendChild(w[t].cloneNode(true))}}}}}return u}function U(AG,AE,t){var q,v=C(t);if(v){if(typeof AG.id==b){AG.id=t}if(h.ie&&h.win){var AF="";for(var AB in AG){if(AG[AB]!=Object.prototype[AB]){if(AB.toLowerCase()=="data"){AE.movie=AG[AB]}else{if(AB.toLowerCase()=="styleclass"){AF+=' class="'+AG[AB]+'"'}else{if(AB.toLowerCase()!="classid"){AF+=" "+AB+'="'+AG[AB]+'"'}}}}}var AD="";for(var AA in AE){if(AE[AA]!=Object.prototype[AA]){AD+='<param name="'+AA+'" value="'+AE[AA]+'" />'}}v.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AF+">"+AD+"</object>";i[i.length]=AG.id;q=C(AG.id)}else{if(h.webkit&&h.webkit<312){var AC=a("embed");AC.setAttribute("type",P);for(var z in AG){if(AG[z]!=Object.prototype[z]){if(z.toLowerCase()=="data"){AC.setAttribute("src",AG[z])}else{if(z.toLowerCase()=="styleclass"){AC.setAttribute("class",AG[z])}else{if(z.toLowerCase()!="classid"){AC.setAttribute(z,AG[z])}}}}}for(var y in AE){if(AE[y]!=Object.prototype[y]){if(y.toLowerCase()!="movie"){AC.setAttribute(y,AE[y])}}}v.parentNode.replaceChild(AC,v);q=AC}else{var u=a(Q);u.setAttribute("type",P);for(var x in AG){if(AG[x]!=Object.prototype[x]){if(x.toLowerCase()=="styleclass"){u.setAttribute("class",AG[x])}else{if(x.toLowerCase()!="classid"){u.setAttribute(x,AG[x])}}}}for(var w in AE){if(AE[w]!=Object.prototype[w]&&w.toLowerCase()!="movie"){F(u,w,AE[w])}}v.parentNode.replaceChild(u,v);q=u}}}return q}function F(t,q,r){var u=a("param");u.setAttribute("name",q);u.setAttribute("value",r);t.appendChild(u)}function X(r){var q=C(r);if(q&&(q.nodeName=="OBJECT"||q.nodeName=="EMBED")){if(h.ie&&h.win){if(q.readyState==4){B(r)}else{j.attachEvent("onload",function(){B(r)})}}else{q.parentNode.removeChild(q)}}}function B(t){var r=C(t);if(r){for(var q in r){if(typeof r[q]=="function"){r[q]=null}}r.parentNode.removeChild(r)}}function C(t){var q=null;try{q=K.getElementById(t)}catch(r){}return q}function a(q){return K.createElement(q)}function I(t,q,r){t.attachEvent(q,r);d[d.length]=[t,q,r]}function c(t){var r=h.pv,q=t.split(".");q[0]=parseInt(q[0],10);q[1]=parseInt(q[1],10)||0;q[2]=parseInt(q[2],10)||0;return(r[0]>q[0]||(r[0]==q[0]&&r[1]>q[1])||(r[0]==q[0]&&r[1]==q[1]&&r[2]>=q[2]))?true:false}function V(v,r){if(h.ie&&h.mac){return }var u=K.getElementsByTagName("head")[0],t=a("style");t.setAttribute("type","text/css");t.setAttribute("media","screen");if(!(h.ie&&h.win)&&typeof K.createTextNode!=b){t.appendChild(K.createTextNode(v+" {"+r+"}"))}u.appendChild(t);if(h.ie&&h.win&&typeof K.styleSheets!=b&&K.styleSheets.length>0){var q=K.styleSheets[K.styleSheets.length-1];if(typeof q.addRule==Q){q.addRule(v,r)}}}function W(t,q){var r=q?"visible":"hidden";if(e&&C(t)){C(t).style.visibility=r}else{V("#"+t,"visibility:"+r)}}function g(s){var r=/[\\\"<>\.;]/;var q=r.exec(s)!=null;return q?encodeURIComponent(s):s}var D=function(){if(h.ie&&h.win){window.attachEvent("onunload",function(){var w=d.length;for(var v=0;v<w;v++){d[v][0].detachEvent(d[v][1],d[v][2])}var t=i.length;for(var u=0;u<t;u++){X(i[u])}for(var r in h){h[r]=null}h=null;for(var q in swfobject){swfobject[q]=null}swfobject=null})}}();return{registerObject:function(u,q,t){if(!h.w3cdom||!u||!q){return }var r={};r.id=u;r.swfVersion=q;r.expressInstall=t?t:false;N[N.length]=r;W(u,false)},getObjectById:function(v){var q=null;if(h.w3cdom){var t=C(v);if(t){var u=t.getElementsByTagName(Q)[0];if(!u||(u&&typeof t.SetVariable!=b)){q=t}else{if(typeof u.SetVariable!=b){q=u}}}}return q},embedSWF:function(x,AE,AB,AD,q,w,r,z,AC){if(!h.w3cdom||!x||!AE||!AB||!AD||!q){return }AB+="";AD+="";if(c(q)){W(AE,false);var AA={};if(AC&&typeof AC===Q){for(var v in AC){if(AC[v]!=Object.prototype[v]){AA[v]=AC[v]}}}AA.data=x;AA.width=AB;AA.height=AD;var y={};if(z&&typeof z===Q){for(var u in z){if(z[u]!=Object.prototype[u]){y[u]=z[u]}}}if(r&&typeof r===Q){for(var t in r){if(r[t]!=Object.prototype[t]){if(typeof y.flashvars!=b){y.flashvars+="&"+t+"="+r[t]}else{y.flashvars=t+"="+r[t]}}}}f(function(){U(AA,y,AE);if(AA.id==AE){W(AE,true)}})}else{if(w&&!A&&c("6.0.65")&&(h.win||h.mac)){A=true;W(AE,false);f(function(){var AF={};AF.id=AF.altContentId=AE;AF.width=AB;AF.height=AD;AF.expressInstall=w;k(AF)})}}},getFlashPlayerVersion:function(){return{major:h.pv[0],minor:h.pv[1],release:h.pv[2]}},hasFlashPlayerVersion:c,createSWF:function(t,r,q){if(h.w3cdom){return U(t,r,q)}else{return undefined}},removeSWF:function(q){if(h.w3cdom){X(q)}},createCSS:function(r,q){if(h.w3cdom){V(r,q)}},addDomLoadEvent:f,addLoadEvent:R,getQueryParamValue:function(v){var u=K.location.search||K.location.hash;if(v==null){return g(u)}if(u){var t=u.substring(1).split("&");for(var r=0;r<t.length;r++){if(t[r].substring(0,t[r].indexOf("="))==v){return g(t[r].substring((t[r].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(A&&M){var q=C(m);if(q){q.parentNode.replaceChild(M,q);if(l){W(l,true);if(h.ie&&h.win){M.style.display="block"}}M=null;l=null;A=false}}}}}();;
|
||
/* http://www.menucool.com/tabbed-content Free to use. Version 2013.7.6 */
|
||
(function(){var g=function(a){if(a&&a.stopPropagation)a.stopPropagation();else window.event.cancelBubble=true;var b=a?a:window.event;b.preventDefault&&b.preventDefault()},d=function(a,c,b){if(a.addEventListener)a.addEventListener(c,b,false);else a.attachEvent&&a.attachEvent("on"+c,b)},a=function(c,a){var b=new RegExp("(^| )"+a+"( |$)");return b.test(c.className)?true:false},j=function(b,c,d){if(!a(b,c))if(b.className=="")b.className=c;else if(d)b.className=c+" "+b.className;else b.className+=" "+c},h=function(a,b){var c=new RegExp("(^| )"+b+"( |$)");a.className=a.className.replace(c,"$1");a.className=a.className.replace(/ $/,"")},e=function(){var b=window.location.pathname;if(b.indexOf("/")!=-1)b=b.split("/");var a=b[b.length-1]||"root";if(a.indexOf(".")!=-1)a=a.substring(0,a.indexOf("."));if(a>20)a=a.substring(a.length-19);return a},c="mi"+e(),b=function(b,a){this.g(b,a)};b.prototype={h:function(){var b=new RegExp(c+this.a+"=(\\d+)"),a=document.cookie.match(b);return a?a[1]:this.i()},i:function(){for(var b=0,c=this.b.length;b<c;b++)if(a(this.b[b].parentNode,"selected"))return b;return 0},j:function(b,d){var c=document.getElementById(b.TargetId);if(!c)return;this.l(c);for(var a=0;a<this.b.length;a++)if(this.b[a]==b){j(b.parentNode,"selected");d&&this.d&&this.k(this.a,a)}else h(this.b[a].parentNode,"selected")},k:function(a,b){document.cookie=c+a+"="+b+"; path=/"},l:function(b){for(var a=0;a<this.c.length;a++)this.c[a].style.display=this.c[a].id==b.id?"block":"none"},m:function(){this.c=[];for(var c=this,a=0;a<this.b.length;a++){var b=document.getElementById(this.b[a].TargetId);if(b){this.c.push(b);d(this.b[a],"click",function(b){var a=this;if(a===window)a=window.event.srcElement;c.j(a,1);g(b);return false})}}},g:function(f,h){this.a=h;this.b=[];for(var e=f.getElementsByTagName("a"),i=/#([^?]+)/,a,b,c=0;c<e.length;c++){b=e[c];a=b.getAttribute("href");if(a.indexOf("#")==-1)continue;else{var d=a.match(i);if(d){a=d[1];b.TargetId=a;this.b.push(b)}else continue}}var g=f.getAttribute("data-persist")||"";this.d=g.toLowerCase()=="true"?1:0;this.m();this.n()},n:function(){var a=this.d?parseInt(this.h()):this.i();if(a>=this.b.length)a=0;this.j(this.b[a],0)}};var k=[],i=function(e){var b=false;function a(){if(b)return;b=true;setTimeout(e,4)}if(document.addEventListener)document.addEventListener("DOMContentLoaded",a,false);else if(document.attachEvent){try{var f=window.frameElement!=null}catch(g){}if(document.documentElement.doScroll&&!f){function c(){if(b)return;try{document.documentElement.doScroll("left");a()}catch(d){setTimeout(c,10)}}c()}document.attachEvent("onreadystatechange",function(){document.readyState==="complete"&&a()})}d(window,"load",a)},f=function(){for(var d=document.getElementsByTagName("ul"),c=0,e=d.length;c<e;c++)a(d[c],"tabs")&&k.push(new b(d[c],c))};i(f);return{}})();/*
|
||
* Thickbox 3.1 - One Box To Rule Them All.
|
||
* By Cody Lindley (http://www.codylindley.com)
|
||
* Copyright (c) 2007 cody lindley
|
||
* Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||
*/
|
||
|
||
var tb_pathToImage = "images/loading_animation.gif";
|
||
|
||
/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/
|
||
|
||
//on page load call tb_init
|
||
$(document).ready(function(){
|
||
tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
|
||
imgLoader = new Image();// preload image
|
||
imgLoader.src = tb_pathToImage;
|
||
});
|
||
|
||
//add thickbox to href & area elements that have a class of .thickbox
|
||
function tb_init(domChunk){
|
||
$(domChunk).click(function(){
|
||
var t = this.title || this.name || null;
|
||
var a = this.href || this.alt;
|
||
var g = this.rel || false;
|
||
tb_show(t,a,g);
|
||
this.blur();
|
||
return false;
|
||
});
|
||
}
|
||
|
||
function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link
|
||
|
||
try {
|
||
if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
|
||
$("body","html").css({height: "100%", width: "100%"});
|
||
$("html").css("overflow","hidden");
|
||
if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
|
||
$("body").append("<iframe id='TB_HideSelect'></iframe><div id='TB_overlay'></div><div id='TB_window'></div>");
|
||
$("#TB_overlay").click(tb_remove);
|
||
}
|
||
}else{//all others
|
||
if(document.getElementById("TB_overlay") === null){
|
||
$("body").append("<div id='TB_overlay'></div><div id='TB_window'></div>");
|
||
$("#TB_overlay").click(tb_remove);
|
||
}
|
||
}
|
||
|
||
if(tb_detectMacXFF()){
|
||
$("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
|
||
}else{
|
||
$("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
|
||
}
|
||
|
||
if(caption===null){caption="";}
|
||
$("body").append("<div id='TB_load'><img src='"+imgLoader.src+"' /></div>");//add loader to the page
|
||
$('#TB_load').show();//show loader
|
||
|
||
var baseURL;
|
||
if(url.indexOf("?")!==-1){ //ff there is a query string involved
|
||
baseURL = url.substr(0, url.indexOf("?"));
|
||
}else{
|
||
baseURL = url;
|
||
}
|
||
|
||
var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
|
||
var urlType = baseURL.toLowerCase().match(urlString);
|
||
|
||
if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
|
||
|
||
TB_PrevCaption = "";
|
||
TB_PrevURL = "";
|
||
TB_PrevHTML = "";
|
||
TB_NextCaption = "";
|
||
TB_NextURL = "";
|
||
TB_NextHTML = "";
|
||
TB_imageCount = "";
|
||
TB_FoundURL = false;
|
||
if(imageGroup){
|
||
TB_TempArray = $("a[@rel="+imageGroup+"]").get();
|
||
for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
|
||
var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
|
||
if (!(TB_TempArray[TB_Counter].href == url)) {
|
||
if (TB_FoundURL) {
|
||
TB_NextCaption = TB_TempArray[TB_Counter].title;
|
||
TB_NextURL = TB_TempArray[TB_Counter].href;
|
||
TB_NextHTML = "<span id='TB_next'> <a href='#'>Next ></a></span>";
|
||
} else {
|
||
TB_PrevCaption = TB_TempArray[TB_Counter].title;
|
||
TB_PrevURL = TB_TempArray[TB_Counter].href;
|
||
TB_PrevHTML = "<span id='TB_prev'> <a href='#'>< Prev</a></span>";
|
||
}
|
||
} else {
|
||
TB_FoundURL = true;
|
||
TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length);
|
||
}
|
||
}
|
||
}
|
||
|
||
imgPreloader = new Image();
|
||
imgPreloader.onload = function(){
|
||
imgPreloader.onload = null;
|
||
|
||
// Resizing large images - orginal by Christian Montoya edited by me.
|
||
var pagesize = tb_getPageSize();
|
||
var x = pagesize[0] - 150;
|
||
var y = pagesize[1] - 150;
|
||
var imageWidth = imgPreloader.width;
|
||
var imageHeight = imgPreloader.height;
|
||
if (imageWidth > x) {
|
||
imageHeight = imageHeight * (x / imageWidth);
|
||
imageWidth = x;
|
||
if (imageHeight > y) {
|
||
imageWidth = imageWidth * (y / imageHeight);
|
||
imageHeight = y;
|
||
}
|
||
} else if (imageHeight > y) {
|
||
imageWidth = imageWidth * (y / imageHeight);
|
||
imageHeight = y;
|
||
if (imageWidth > x) {
|
||
imageHeight = imageHeight * (x / imageWidth);
|
||
imageWidth = x;
|
||
}
|
||
}
|
||
// End Resizing
|
||
|
||
TB_WIDTH = imageWidth + 30;
|
||
TB_HEIGHT = imageHeight + 60;
|
||
$("#TB_window").append("<a href='' id='TB_ImageOff' title='Close'><img id='TB_Image' src='"+url+"' width='"+imageWidth+"' height='"+imageHeight+"' alt='"+caption+"'/></a>" + "<div id='TB_caption'>"+caption+"<div id='TB_secondLine'>" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='Close'>X</a></div>");
|
||
|
||
$("#TB_closeWindowButton").click(tb_remove);
|
||
|
||
if (!(TB_PrevHTML === "")) {
|
||
function goPrev(){
|
||
if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);}
|
||
$("#TB_window").remove();
|
||
$("body").append("<div id='TB_window'></div>");
|
||
tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
|
||
return false;
|
||
}
|
||
$("#TB_prev").click(goPrev);
|
||
}
|
||
|
||
if (!(TB_NextHTML === "")) {
|
||
function goNext(){
|
||
$("#TB_window").remove();
|
||
$("body").append("<div id='TB_window'></div>");
|
||
tb_show(TB_NextCaption, TB_NextURL, imageGroup);
|
||
return false;
|
||
}
|
||
$("#TB_next").click(goNext);
|
||
|
||
}
|
||
|
||
document.onkeydown = function(e){
|
||
if (e == null) { // ie
|
||
keycode = event.keyCode;
|
||
} else { // mozilla
|
||
keycode = e.which;
|
||
}
|
||
if(keycode == 27){ // close
|
||
tb_remove();
|
||
} else if(keycode == 190){ // display previous image
|
||
if(!(TB_NextHTML == "")){
|
||
document.onkeydown = "";
|
||
goNext();
|
||
}
|
||
} else if(keycode == 188){ // display next image
|
||
if(!(TB_PrevHTML == "")){
|
||
document.onkeydown = "";
|
||
goPrev();
|
||
}
|
||
}
|
||
};
|
||
|
||
tb_position();
|
||
$("#TB_load").remove();
|
||
$("#TB_ImageOff").click(tb_remove);
|
||
$("#TB_window").css({display:"block"}); //for safari using css instead of show
|
||
};
|
||
|
||
imgPreloader.src = url;
|
||
}else{//code to show html
|
||
var params = tb_parseUrl(url);
|
||
var dims = get_dimensions();
|
||
TB_WIDTH = (params['width']*1) + 30 || dims.width*.6;//default to 60% of window width
|
||
TB_HEIGHT = (params['height']*1) + 40 || dims.height*.85;//default to 85% of window height
|
||
ajaxContentW = TB_WIDTH - 30;
|
||
ajaxContentH = TB_HEIGHT - 45;
|
||
|
||
if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window
|
||
urlNoQuery = url.split('TB_');
|
||
$("#TB_iframeContent").remove();
|
||
if(params['modal'] != "true"){//iframe no modal
|
||
$("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='Close'>X</a></div></div><iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;' > </iframe>");
|
||
}else{//iframe modal
|
||
$("#TB_overlay").unbind();
|
||
$("#TB_window").append("<iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;'> </iframe>");
|
||
}
|
||
}else{// not an iframe, ajax
|
||
if($("#TB_window").css("display") != "block"){
|
||
if(params['modal'] != "true"){//ajax no modal
|
||
$("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'>X</a></div></div><div id='TB_ajaxContent' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px'></div>");
|
||
}else{//ajax modal
|
||
$("#TB_overlay").unbind();
|
||
$("#TB_window").append("<div id='TB_ajaxContent' class='TB_modal' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px;'></div>");
|
||
}
|
||
}else{//this means the window is already up, we are just loading new content via ajax
|
||
$("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
|
||
$("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
|
||
$("#TB_ajaxContent")[0].scrollTop = 0;
|
||
$("#TB_ajaxWindowTitle").html(caption);
|
||
}
|
||
}
|
||
|
||
$("#TB_closeWindowButton").click(tb_remove);
|
||
|
||
if(url.indexOf('TB_inline') != -1){
|
||
$("#TB_ajaxContent").append($('#' + params['inlineId']).children());
|
||
$("#TB_window").unload(function () {
|
||
$('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished
|
||
});
|
||
tb_position();
|
||
$("#TB_load").remove();
|
||
$("#TB_window").css({display:"block"});
|
||
}else if(url.indexOf('TB_iframe') != -1){
|
||
tb_position();
|
||
if($.browser.safari){//safari needs help because it will not fire iframe onload
|
||
$("#TB_load").remove();
|
||
$("#TB_window").css({display:"block"});
|
||
}
|
||
}else{
|
||
$("#TB_ajaxContent").load(url += "/random:" + (new Date().getTime()),function(){//to do a post change this load method
|
||
tb_position();
|
||
$("#TB_load").remove();
|
||
tb_init("#TB_ajaxContent a.thickbox");
|
||
$("#TB_window").css({display:"block"});
|
||
});
|
||
}
|
||
|
||
}
|
||
|
||
if(!params['modal']){
|
||
document.onkeyup = function(e){
|
||
if (e == null) { // ie
|
||
keycode = event.keyCode;
|
||
} else { // mozilla
|
||
keycode = e.which;
|
||
}
|
||
if(keycode == 27){ // close
|
||
tb_remove();
|
||
}
|
||
};
|
||
}
|
||
|
||
} catch(e) {
|
||
//nothing here
|
||
}
|
||
}
|
||
|
||
//helper functions below
|
||
function tb_showIframe(){
|
||
$("#TB_load").remove();
|
||
$("#TB_window").css({display:"block"});
|
||
}
|
||
|
||
function tb_remove() {
|
||
$("#TB_imageOff").unbind("click");
|
||
$("#TB_closeWindowButton").unbind("click");
|
||
$("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();});
|
||
$("#TB_load").remove();
|
||
if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
|
||
$("body","html").css({height: "auto", width: "auto"});
|
||
$("html").css("overflow","");
|
||
}
|
||
document.onkeydown = "";
|
||
document.onkeyup = "";
|
||
return false;
|
||
}
|
||
|
||
function tb_position() {
|
||
$("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});
|
||
if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6
|
||
$("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});
|
||
}
|
||
}
|
||
|
||
function tb_parseQuery ( query ) {
|
||
var Params = {};
|
||
if ( ! query ) {return Params;}// return empty object
|
||
var Pairs = query.split(/[;&]/);
|
||
for ( var i = 0; i < Pairs.length; i++ ) {
|
||
var KeyVal = Pairs[i].split('=');
|
||
if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
|
||
var key = unescape( KeyVal[0] );
|
||
var val = unescape( KeyVal[1] );
|
||
val = val.replace(/\+/g, ' ');
|
||
Params[key] = val;
|
||
}
|
||
return Params;
|
||
}
|
||
|
||
function tb_parseUrl( url ) {
|
||
var Params = {}
|
||
if( !url) {return Params;}
|
||
var Pairs = url.match(/[a-z 0-9~%.:_\-]+:[a-z 0-9~%.:_\-]+/ig);
|
||
if(Pairs==null){return Params;}
|
||
for ( var i = 0; i < Pairs.length; i++ ) {
|
||
var KeyVal = Pairs[i].split(':');
|
||
if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
|
||
var key = unescape( KeyVal[0] );
|
||
var val = unescape( KeyVal[1] );
|
||
val = val.replace(/\+/g, ' ');
|
||
Params[key] = val;
|
||
}
|
||
return Params;
|
||
|
||
}
|
||
|
||
function tb_getPageSize(){
|
||
var de = document.documentElement;
|
||
var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
|
||
var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
|
||
arrayPageSize = [w,h];
|
||
return arrayPageSize;
|
||
}
|
||
|
||
function tb_detectMacXFF() {
|
||
var userAgent = navigator.userAgent.toLowerCase();
|
||
if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
|