28877 lines
790 KiB
JavaScript
28877 lines
790 KiB
JavaScript
/*!
|
|
* jQuery JavaScript Library v3.2.0
|
|
* https://jquery.com/
|
|
*
|
|
* Includes Sizzle.js
|
|
* https://sizzlejs.com/
|
|
*
|
|
* Copyright JS Foundation and other contributors
|
|
* Released under the MIT license
|
|
* https://jquery.org/license
|
|
*
|
|
* Date: 2017-03-16T21:26Z
|
|
*/
|
|
( function( global, factory ) {
|
|
|
|
"use strict";
|
|
|
|
if ( typeof module === "object" && typeof module.exports === "object" ) {
|
|
|
|
// For CommonJS and CommonJS-like environments where a proper `window`
|
|
// is present, execute the factory and get jQuery.
|
|
// For environments that do not have a `window` with a `document`
|
|
// (such as Node.js), expose a factory as module.exports.
|
|
// This accentuates the need for the creation of a real `window`.
|
|
// e.g. var jQuery = require("jquery")(window);
|
|
// See ticket #14549 for more info.
|
|
module.exports = global.document ?
|
|
factory( global, true ) :
|
|
function( w ) {
|
|
if ( !w.document ) {
|
|
throw new Error( "jQuery requires a window with a document" );
|
|
}
|
|
return factory( w );
|
|
};
|
|
} else {
|
|
factory( global );
|
|
}
|
|
|
|
// Pass this if window is not defined yet
|
|
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
|
|
|
|
// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
|
|
// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
|
|
// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
|
|
// enough that all such attempts are guarded in a try block.
|
|
"use strict";
|
|
|
|
var arr = [];
|
|
|
|
var document = window.document;
|
|
|
|
var getProto = Object.getPrototypeOf;
|
|
|
|
var slice = arr.slice;
|
|
|
|
var concat = arr.concat;
|
|
|
|
var push = arr.push;
|
|
|
|
var indexOf = arr.indexOf;
|
|
|
|
var class2type = {};
|
|
|
|
var toString = class2type.toString;
|
|
|
|
var hasOwn = class2type.hasOwnProperty;
|
|
|
|
var fnToString = hasOwn.toString;
|
|
|
|
var ObjectFunctionString = fnToString.call( Object );
|
|
|
|
var support = {};
|
|
|
|
|
|
|
|
function DOMEval( code, doc ) {
|
|
doc = doc || document;
|
|
|
|
var script = doc.createElement( "script" );
|
|
|
|
script.text = code;
|
|
doc.head.appendChild( script ).parentNode.removeChild( script );
|
|
}
|
|
/* global Symbol */
|
|
// Defining this global in .eslintrc.json would create a danger of using the global
|
|
// unguarded in another place, it seems safer to define global only for this module
|
|
|
|
|
|
|
|
var
|
|
version = "3.2.0",
|
|
|
|
// Define a local copy of jQuery
|
|
jQuery = function( selector, context ) {
|
|
|
|
// The jQuery object is actually just the init constructor 'enhanced'
|
|
// Need init if jQuery is called (just allow error to be thrown if not included)
|
|
return new jQuery.fn.init( selector, context );
|
|
},
|
|
|
|
// Support: Android <=4.0 only
|
|
// Make sure we trim BOM and NBSP
|
|
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
|
|
|
|
// Matches dashed string for camelizing
|
|
rmsPrefix = /^-ms-/,
|
|
rdashAlpha = /-([a-z])/g,
|
|
|
|
// Used by jQuery.camelCase as callback to replace()
|
|
fcamelCase = function( all, letter ) {
|
|
return letter.toUpperCase();
|
|
};
|
|
|
|
jQuery.fn = jQuery.prototype = {
|
|
|
|
// The current version of jQuery being used
|
|
jquery: version,
|
|
|
|
constructor: jQuery,
|
|
|
|
// The default length of a jQuery object is 0
|
|
length: 0,
|
|
|
|
toArray: function() {
|
|
return 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 all the elements in a clean array
|
|
if ( num == null ) {
|
|
return slice.call( this );
|
|
}
|
|
|
|
// Return just the one element from the set
|
|
return num < 0 ? this[ num + this.length ] : this[ num ];
|
|
},
|
|
|
|
// Take an array of elements and push it onto the stack
|
|
// (returning the new matched element set)
|
|
pushStack: function( elems ) {
|
|
|
|
// 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;
|
|
|
|
// Return the newly-formed element set
|
|
return ret;
|
|
},
|
|
|
|
// Execute a callback for every element in the matched set.
|
|
each: function( callback ) {
|
|
return jQuery.each( this, callback );
|
|
},
|
|
|
|
map: function( callback ) {
|
|
return this.pushStack( jQuery.map( this, function( elem, i ) {
|
|
return callback.call( elem, i, elem );
|
|
} ) );
|
|
},
|
|
|
|
slice: function() {
|
|
return this.pushStack( slice.apply( this, arguments ) );
|
|
},
|
|
|
|
first: function() {
|
|
return this.eq( 0 );
|
|
},
|
|
|
|
last: function() {
|
|
return this.eq( -1 );
|
|
},
|
|
|
|
eq: function( i ) {
|
|
var len = this.length,
|
|
j = +i + ( i < 0 ? len : 0 );
|
|
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
|
|
},
|
|
|
|
end: function() {
|
|
return this.prevObject || this.constructor();
|
|
},
|
|
|
|
// For internal use only.
|
|
// Behaves like an Array's method, not like a jQuery method.
|
|
push: push,
|
|
sort: arr.sort,
|
|
splice: arr.splice
|
|
};
|
|
|
|
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;
|
|
|
|
// Skip the boolean and the target
|
|
target = arguments[ i ] || {};
|
|
i++;
|
|
}
|
|
|
|
// 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 ( i === length ) {
|
|
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 = Array.isArray( copy ) ) ) ) {
|
|
|
|
if ( copyIsArray ) {
|
|
copyIsArray = false;
|
|
clone = src && Array.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( {
|
|
|
|
// Unique for each copy of jQuery on the page
|
|
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
|
|
|
|
// Assume jQuery is ready without the ready module
|
|
isReady: true,
|
|
|
|
error: function( msg ) {
|
|
throw new Error( msg );
|
|
},
|
|
|
|
noop: function() {},
|
|
|
|
isFunction: function( obj ) {
|
|
return jQuery.type( obj ) === "function";
|
|
},
|
|
|
|
isWindow: function( obj ) {
|
|
return obj != null && obj === obj.window;
|
|
},
|
|
|
|
isNumeric: function( obj ) {
|
|
|
|
// As of jQuery 3.0, isNumeric is limited to
|
|
// strings and numbers (primitives or objects)
|
|
// that can be coerced to finite numbers (gh-2662)
|
|
var type = jQuery.type( obj );
|
|
return ( type === "number" || type === "string" ) &&
|
|
|
|
// parseFloat NaNs numeric-cast false positives ("")
|
|
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
|
|
// subtraction forces infinities to NaN
|
|
!isNaN( obj - parseFloat( obj ) );
|
|
},
|
|
|
|
isPlainObject: function( obj ) {
|
|
var proto, Ctor;
|
|
|
|
// Detect obvious negatives
|
|
// Use toString instead of jQuery.type to catch host objects
|
|
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
|
|
return false;
|
|
}
|
|
|
|
proto = getProto( obj );
|
|
|
|
// Objects with no prototype (e.g., `Object.create( null )`) are plain
|
|
if ( !proto ) {
|
|
return true;
|
|
}
|
|
|
|
// Objects with prototype are plain iff they were constructed by a global Object function
|
|
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
|
|
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
|
|
},
|
|
|
|
isEmptyObject: function( obj ) {
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
// See https://github.com/eslint/eslint/issues/6125
|
|
var name;
|
|
|
|
for ( name in obj ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
type: function( obj ) {
|
|
if ( obj == null ) {
|
|
return obj + "";
|
|
}
|
|
|
|
// Support: Android <=2.3 only (functionish RegExp)
|
|
return typeof obj === "object" || typeof obj === "function" ?
|
|
class2type[ toString.call( obj ) ] || "object" :
|
|
typeof obj;
|
|
},
|
|
|
|
// Evaluates a script in a global context
|
|
globalEval: function( code ) {
|
|
DOMEval( code );
|
|
},
|
|
|
|
// Convert dashed to camelCase; used by the css and data modules
|
|
// Support: IE <=9 - 11, Edge 12 - 13
|
|
// Microsoft forgot to hump their vendor prefix (#9572)
|
|
camelCase: function( string ) {
|
|
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
|
},
|
|
|
|
each: function( obj, callback ) {
|
|
var length, i = 0;
|
|
|
|
if ( isArrayLike( obj ) ) {
|
|
length = obj.length;
|
|
for ( ; i < length; i++ ) {
|
|
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for ( i in obj ) {
|
|
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
},
|
|
|
|
// Support: Android <=4.0 only
|
|
trim: function( text ) {
|
|
return text == null ?
|
|
"" :
|
|
( text + "" ).replace( rtrim, "" );
|
|
},
|
|
|
|
// results is for internal usage only
|
|
makeArray: function( arr, results ) {
|
|
var ret = results || [];
|
|
|
|
if ( arr != null ) {
|
|
if ( isArrayLike( Object( arr ) ) ) {
|
|
jQuery.merge( ret,
|
|
typeof arr === "string" ?
|
|
[ arr ] : arr
|
|
);
|
|
} else {
|
|
push.call( ret, arr );
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
|
|
inArray: function( elem, arr, i ) {
|
|
return arr == null ? -1 : indexOf.call( arr, elem, i );
|
|
},
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
merge: function( first, second ) {
|
|
var len = +second.length,
|
|
j = 0,
|
|
i = first.length;
|
|
|
|
for ( ; j < len; j++ ) {
|
|
first[ i++ ] = second[ j ];
|
|
}
|
|
|
|
first.length = i;
|
|
|
|
return first;
|
|
},
|
|
|
|
grep: function( elems, callback, invert ) {
|
|
var callbackInverse,
|
|
matches = [],
|
|
i = 0,
|
|
length = elems.length,
|
|
callbackExpect = !invert;
|
|
|
|
// Go through the array, only saving the items
|
|
// that pass the validator function
|
|
for ( ; i < length; i++ ) {
|
|
callbackInverse = !callback( elems[ i ], i );
|
|
if ( callbackInverse !== callbackExpect ) {
|
|
matches.push( elems[ i ] );
|
|
}
|
|
}
|
|
|
|
return matches;
|
|
},
|
|
|
|
// arg is for internal usage only
|
|
map: function( elems, callback, arg ) {
|
|
var length, value,
|
|
i = 0,
|
|
ret = [];
|
|
|
|
// Go through the array, translating each of the items to their new values
|
|
if ( isArrayLike( elems ) ) {
|
|
length = elems.length;
|
|
for ( ; i < length; i++ ) {
|
|
value = callback( elems[ i ], i, arg );
|
|
|
|
if ( value != null ) {
|
|
ret.push( value );
|
|
}
|
|
}
|
|
|
|
// Go through every key on the object,
|
|
} else {
|
|
for ( i in elems ) {
|
|
value = callback( elems[ i ], i, arg );
|
|
|
|
if ( value != null ) {
|
|
ret.push( value );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Flatten any nested arrays
|
|
return 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 = slice.call( arguments, 2 );
|
|
proxy = function() {
|
|
return fn.apply( context || this, args.concat( 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;
|
|
},
|
|
|
|
now: Date.now,
|
|
|
|
// jQuery.support is not used in Core but other projects attach their
|
|
// properties to it so it needs to exist.
|
|
support: support
|
|
} );
|
|
|
|
if ( typeof Symbol === "function" ) {
|
|
jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
|
|
}
|
|
|
|
// Populate the class2type map
|
|
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
|
|
function( i, name ) {
|
|
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
|
} );
|
|
|
|
function isArrayLike( obj ) {
|
|
|
|
// Support: real iOS 8.2 only (not reproducible in simulator)
|
|
// `in` check used to prevent JIT error (gh-2145)
|
|
// hasOwn isn't used here due to false negatives
|
|
// regarding Nodelist length in IE
|
|
var length = !!obj && "length" in obj && obj.length,
|
|
type = jQuery.type( obj );
|
|
|
|
if ( type === "function" || jQuery.isWindow( obj ) ) {
|
|
return false;
|
|
}
|
|
|
|
return type === "array" || length === 0 ||
|
|
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
|
|
}
|
|
var Sizzle =
|
|
/*!
|
|
* Sizzle CSS Selector Engine v2.3.3
|
|
* https://sizzlejs.com/
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license
|
|
* http://jquery.org/license
|
|
*
|
|
* Date: 2016-08-08
|
|
*/
|
|
(function( window ) {
|
|
|
|
var i,
|
|
support,
|
|
Expr,
|
|
getText,
|
|
isXML,
|
|
tokenize,
|
|
compile,
|
|
select,
|
|
outermostContext,
|
|
sortInput,
|
|
hasDuplicate,
|
|
|
|
// Local document vars
|
|
setDocument,
|
|
document,
|
|
docElem,
|
|
documentIsHTML,
|
|
rbuggyQSA,
|
|
rbuggyMatches,
|
|
matches,
|
|
contains,
|
|
|
|
// Instance-specific data
|
|
expando = "sizzle" + 1 * new Date(),
|
|
preferredDoc = window.document,
|
|
dirruns = 0,
|
|
done = 0,
|
|
classCache = createCache(),
|
|
tokenCache = createCache(),
|
|
compilerCache = createCache(),
|
|
sortOrder = function( a, b ) {
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
}
|
|
return 0;
|
|
},
|
|
|
|
// Instance methods
|
|
hasOwn = ({}).hasOwnProperty,
|
|
arr = [],
|
|
pop = arr.pop,
|
|
push_native = arr.push,
|
|
push = arr.push,
|
|
slice = arr.slice,
|
|
// Use a stripped-down indexOf as it's faster than native
|
|
// https://jsperf.com/thor-indexof-vs-for/5
|
|
indexOf = function( list, elem ) {
|
|
var i = 0,
|
|
len = list.length;
|
|
for ( ; i < len; i++ ) {
|
|
if ( list[i] === elem ) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
|
|
|
|
// Regular expressions
|
|
|
|
// http://www.w3.org/TR/css3-selectors/#whitespace
|
|
whitespace = "[\\x20\\t\\r\\n\\f]",
|
|
|
|
// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
|
|
identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
|
|
|
|
// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
|
|
attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
|
|
// Operator (capture 2)
|
|
"*([*^$|!~]?=)" + whitespace +
|
|
// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
|
|
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
|
|
"*\\]",
|
|
|
|
pseudos = ":(" + identifier + ")(?:\\((" +
|
|
// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
|
|
// 1. quoted (capture 3; capture 4 or capture 5)
|
|
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
|
|
// 2. simple (capture 6)
|
|
"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
|
|
// 3. anything else (capture 2)
|
|
".*" +
|
|
")\\)|)",
|
|
|
|
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
|
|
rwhitespace = new RegExp( whitespace + "+", "g" ),
|
|
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
|
|
|
|
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
|
|
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
|
|
|
|
rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
|
|
|
|
rpseudo = new RegExp( pseudos ),
|
|
ridentifier = new RegExp( "^" + identifier + "$" ),
|
|
|
|
matchExpr = {
|
|
"ID": new RegExp( "^#(" + identifier + ")" ),
|
|
"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
|
|
"TAG": new RegExp( "^(" + identifier + "|[*])" ),
|
|
"ATTR": new RegExp( "^" + attributes ),
|
|
"PSEUDO": new RegExp( "^" + pseudos ),
|
|
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
|
|
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
|
|
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
|
|
"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
|
|
// For use in libraries implementing .is()
|
|
// We use this for POS matching in `select`
|
|
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
|
|
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
|
|
},
|
|
|
|
rinputs = /^(?:input|select|textarea|button)$/i,
|
|
rheader = /^h\d$/i,
|
|
|
|
rnative = /^[^{]+\{\s*\[native \w/,
|
|
|
|
// Easily-parseable/retrievable ID or TAG or CLASS selectors
|
|
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
|
|
|
|
rsibling = /[+~]/,
|
|
|
|
// CSS escapes
|
|
// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
|
|
runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
|
|
funescape = function( _, escaped, escapedWhitespace ) {
|
|
var high = "0x" + escaped - 0x10000;
|
|
// NaN means non-codepoint
|
|
// Support: Firefox<24
|
|
// Workaround erroneous numeric interpretation of +"0x"
|
|
return high !== high || escapedWhitespace ?
|
|
escaped :
|
|
high < 0 ?
|
|
// BMP codepoint
|
|
String.fromCharCode( high + 0x10000 ) :
|
|
// Supplemental Plane codepoint (surrogate pair)
|
|
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
|
|
},
|
|
|
|
// CSS string/identifier serialization
|
|
// https://drafts.csswg.org/cssom/#common-serializing-idioms
|
|
rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
|
|
fcssescape = function( ch, asCodePoint ) {
|
|
if ( asCodePoint ) {
|
|
|
|
// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
|
|
if ( ch === "\0" ) {
|
|
return "\uFFFD";
|
|
}
|
|
|
|
// Control characters and (dependent upon position) numbers get escaped as code points
|
|
return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
|
|
}
|
|
|
|
// Other potentially-special ASCII characters get backslash-escaped
|
|
return "\\" + ch;
|
|
},
|
|
|
|
// Used for iframes
|
|
// See setDocument()
|
|
// Removing the function wrapper causes a "Permission Denied"
|
|
// error in IE
|
|
unloadHandler = function() {
|
|
setDocument();
|
|
},
|
|
|
|
disabledAncestor = addCombinator(
|
|
function( elem ) {
|
|
return elem.disabled === true && ("form" in elem || "label" in elem);
|
|
},
|
|
{ dir: "parentNode", next: "legend" }
|
|
);
|
|
|
|
// Optimize for push.apply( _, NodeList )
|
|
try {
|
|
push.apply(
|
|
(arr = slice.call( preferredDoc.childNodes )),
|
|
preferredDoc.childNodes
|
|
);
|
|
// Support: Android<4.0
|
|
// Detect silently failing push.apply
|
|
arr[ preferredDoc.childNodes.length ].nodeType;
|
|
} catch ( e ) {
|
|
push = { apply: arr.length ?
|
|
|
|
// Leverage slice if possible
|
|
function( target, els ) {
|
|
push_native.apply( target, slice.call(els) );
|
|
} :
|
|
|
|
// Support: IE<9
|
|
// Otherwise append directly
|
|
function( target, els ) {
|
|
var j = target.length,
|
|
i = 0;
|
|
// Can't trust NodeList.length
|
|
while ( (target[j++] = els[i++]) ) {}
|
|
target.length = j - 1;
|
|
}
|
|
};
|
|
}
|
|
|
|
function Sizzle( selector, context, results, seed ) {
|
|
var m, i, elem, nid, match, groups, newSelector,
|
|
newContext = context && context.ownerDocument,
|
|
|
|
// nodeType defaults to 9, since context defaults to document
|
|
nodeType = context ? context.nodeType : 9;
|
|
|
|
results = results || [];
|
|
|
|
// Return early from calls with invalid selector or context
|
|
if ( typeof selector !== "string" || !selector ||
|
|
nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
|
|
|
|
return results;
|
|
}
|
|
|
|
// Try to shortcut find operations (as opposed to filters) in HTML documents
|
|
if ( !seed ) {
|
|
|
|
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
|
|
setDocument( context );
|
|
}
|
|
context = context || document;
|
|
|
|
if ( documentIsHTML ) {
|
|
|
|
// If the selector is sufficiently simple, try using a "get*By*" DOM method
|
|
// (excepting DocumentFragment context, where the methods don't exist)
|
|
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
|
|
|
|
// ID selector
|
|
if ( (m = match[1]) ) {
|
|
|
|
// Document context
|
|
if ( nodeType === 9 ) {
|
|
if ( (elem = context.getElementById( m )) ) {
|
|
|
|
// Support: IE, Opera, Webkit
|
|
// TODO: identify versions
|
|
// getElementById can match elements by name instead of ID
|
|
if ( elem.id === m ) {
|
|
results.push( elem );
|
|
return results;
|
|
}
|
|
} else {
|
|
return results;
|
|
}
|
|
|
|
// Element context
|
|
} else {
|
|
|
|
// Support: IE, Opera, Webkit
|
|
// TODO: identify versions
|
|
// getElementById can match elements by name instead of ID
|
|
if ( newContext && (elem = newContext.getElementById( m )) &&
|
|
contains( context, elem ) &&
|
|
elem.id === m ) {
|
|
|
|
results.push( elem );
|
|
return results;
|
|
}
|
|
}
|
|
|
|
// Type selector
|
|
} else if ( match[2] ) {
|
|
push.apply( results, context.getElementsByTagName( selector ) );
|
|
return results;
|
|
|
|
// Class selector
|
|
} else if ( (m = match[3]) && support.getElementsByClassName &&
|
|
context.getElementsByClassName ) {
|
|
|
|
push.apply( results, context.getElementsByClassName( m ) );
|
|
return results;
|
|
}
|
|
}
|
|
|
|
// Take advantage of querySelectorAll
|
|
if ( support.qsa &&
|
|
!compilerCache[ selector + " " ] &&
|
|
(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
|
|
|
|
if ( nodeType !== 1 ) {
|
|
newContext = context;
|
|
newSelector = selector;
|
|
|
|
// qSA looks outside Element context, which is not what we want
|
|
// Thanks to Andrew Dupont for this workaround technique
|
|
// Support: IE <=8
|
|
// Exclude object elements
|
|
} else if ( context.nodeName.toLowerCase() !== "object" ) {
|
|
|
|
// Capture the context ID, setting it first if necessary
|
|
if ( (nid = context.getAttribute( "id" )) ) {
|
|
nid = nid.replace( rcssescape, fcssescape );
|
|
} else {
|
|
context.setAttribute( "id", (nid = expando) );
|
|
}
|
|
|
|
// Prefix every selector in the list
|
|
groups = tokenize( selector );
|
|
i = groups.length;
|
|
while ( i-- ) {
|
|
groups[i] = "#" + nid + " " + toSelector( groups[i] );
|
|
}
|
|
newSelector = groups.join( "," );
|
|
|
|
// Expand context for sibling selectors
|
|
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
|
|
context;
|
|
}
|
|
|
|
if ( newSelector ) {
|
|
try {
|
|
push.apply( results,
|
|
newContext.querySelectorAll( newSelector )
|
|
);
|
|
return results;
|
|
} catch ( qsaError ) {
|
|
} finally {
|
|
if ( nid === expando ) {
|
|
context.removeAttribute( "id" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// All others
|
|
return select( selector.replace( rtrim, "$1" ), context, results, seed );
|
|
}
|
|
|
|
/**
|
|
* Create key-value caches of limited size
|
|
* @returns {function(string, object)} Returns the Object data after storing it on itself with
|
|
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
|
|
* deleting the oldest entry
|
|
*/
|
|
function createCache() {
|
|
var keys = [];
|
|
|
|
function cache( key, value ) {
|
|
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
|
|
if ( keys.push( key + " " ) > Expr.cacheLength ) {
|
|
// Only keep the most recent entries
|
|
delete cache[ keys.shift() ];
|
|
}
|
|
return (cache[ key + " " ] = value);
|
|
}
|
|
return cache;
|
|
}
|
|
|
|
/**
|
|
* Mark a function for special use by Sizzle
|
|
* @param {Function} fn The function to mark
|
|
*/
|
|
function markFunction( fn ) {
|
|
fn[ expando ] = true;
|
|
return fn;
|
|
}
|
|
|
|
/**
|
|
* Support testing using an element
|
|
* @param {Function} fn Passed the created element and returns a boolean result
|
|
*/
|
|
function assert( fn ) {
|
|
var el = document.createElement("fieldset");
|
|
|
|
try {
|
|
return !!fn( el );
|
|
} catch (e) {
|
|
return false;
|
|
} finally {
|
|
// Remove from its parent by default
|
|
if ( el.parentNode ) {
|
|
el.parentNode.removeChild( el );
|
|
}
|
|
// release memory in IE
|
|
el = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds the same handler for all of the specified attrs
|
|
* @param {String} attrs Pipe-separated list of attributes
|
|
* @param {Function} handler The method that will be applied
|
|
*/
|
|
function addHandle( attrs, handler ) {
|
|
var arr = attrs.split("|"),
|
|
i = arr.length;
|
|
|
|
while ( i-- ) {
|
|
Expr.attrHandle[ arr[i] ] = handler;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks document order of two siblings
|
|
* @param {Element} a
|
|
* @param {Element} b
|
|
* @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
|
|
*/
|
|
function siblingCheck( a, b ) {
|
|
var cur = b && a,
|
|
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
|
|
a.sourceIndex - b.sourceIndex;
|
|
|
|
// Use IE sourceIndex if available on both nodes
|
|
if ( diff ) {
|
|
return diff;
|
|
}
|
|
|
|
// Check if b follows a
|
|
if ( cur ) {
|
|
while ( (cur = cur.nextSibling) ) {
|
|
if ( cur === b ) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return a ? 1 : -1;
|
|
}
|
|
|
|
/**
|
|
* Returns a function to use in pseudos for input types
|
|
* @param {String} type
|
|
*/
|
|
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
|
|
* @param {String} type
|
|
*/
|
|
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 :enabled/:disabled
|
|
* @param {Boolean} disabled true for :disabled; false for :enabled
|
|
*/
|
|
function createDisabledPseudo( disabled ) {
|
|
|
|
// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
|
|
return function( elem ) {
|
|
|
|
// Only certain elements can match :enabled or :disabled
|
|
// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
|
|
// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
|
|
if ( "form" in elem ) {
|
|
|
|
// Check for inherited disabledness on relevant non-disabled elements:
|
|
// * listed form-associated elements in a disabled fieldset
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
|
// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
|
|
// * option elements in a disabled optgroup
|
|
// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
|
|
// All such elements have a "form" property.
|
|
if ( elem.parentNode && elem.disabled === false ) {
|
|
|
|
// Option elements defer to a parent optgroup if present
|
|
if ( "label" in elem ) {
|
|
if ( "label" in elem.parentNode ) {
|
|
return elem.parentNode.disabled === disabled;
|
|
} else {
|
|
return elem.disabled === disabled;
|
|
}
|
|
}
|
|
|
|
// Support: IE 6 - 11
|
|
// Use the isDisabled shortcut property to check for disabled fieldset ancestors
|
|
return elem.isDisabled === disabled ||
|
|
|
|
// Where there is no isDisabled, check manually
|
|
/* jshint -W018 */
|
|
elem.isDisabled !== !disabled &&
|
|
disabledAncestor( elem ) === disabled;
|
|
}
|
|
|
|
return elem.disabled === disabled;
|
|
|
|
// Try to winnow out elements that can't be disabled before trusting the disabled property.
|
|
// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
|
|
// even exist on them, let alone have a boolean value.
|
|
} else if ( "label" in elem ) {
|
|
return elem.disabled === disabled;
|
|
}
|
|
|
|
// Remaining elements are neither :enabled nor :disabled
|
|
return false;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns a function to use in pseudos for positionals
|
|
* @param {Function} fn
|
|
*/
|
|
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]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Checks a node for validity as a Sizzle context
|
|
* @param {Element|Object=} context
|
|
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
|
|
*/
|
|
function testContext( context ) {
|
|
return context && typeof context.getElementsByTagName !== "undefined" && context;
|
|
}
|
|
|
|
// Expose support vars for convenience
|
|
support = Sizzle.support = {};
|
|
|
|
/**
|
|
* Detects XML nodes
|
|
* @param {Element|Object} elem An element or a document
|
|
* @returns {Boolean} True iff elem is a non-HTML XML node
|
|
*/
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* Sets document-related variables once based on the current document
|
|
* @param {Element|Object} [doc] An element or document object to use to set the document
|
|
* @returns {Object} Returns the current document
|
|
*/
|
|
setDocument = Sizzle.setDocument = function( node ) {
|
|
var hasCompare, subWindow,
|
|
doc = node ? node.ownerDocument || node : preferredDoc;
|
|
|
|
// Return early if doc is invalid or already selected
|
|
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
|
|
return document;
|
|
}
|
|
|
|
// Update global variables
|
|
document = doc;
|
|
docElem = document.documentElement;
|
|
documentIsHTML = !isXML( document );
|
|
|
|
// Support: IE 9-11, Edge
|
|
// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
|
|
if ( preferredDoc !== document &&
|
|
(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
|
|
|
|
// Support: IE 11, Edge
|
|
if ( subWindow.addEventListener ) {
|
|
subWindow.addEventListener( "unload", unloadHandler, false );
|
|
|
|
// Support: IE 9 - 10 only
|
|
} else if ( subWindow.attachEvent ) {
|
|
subWindow.attachEvent( "onunload", unloadHandler );
|
|
}
|
|
}
|
|
|
|
/* Attributes
|
|
---------------------------------------------------------------------- */
|
|
|
|
// Support: IE<8
|
|
// Verify that getAttribute really returns attributes and not properties
|
|
// (excepting IE8 booleans)
|
|
support.attributes = assert(function( el ) {
|
|
el.className = "i";
|
|
return !el.getAttribute("className");
|
|
});
|
|
|
|
/* getElement(s)By*
|
|
---------------------------------------------------------------------- */
|
|
|
|
// Check if getElementsByTagName("*") returns only elements
|
|
support.getElementsByTagName = assert(function( el ) {
|
|
el.appendChild( document.createComment("") );
|
|
return !el.getElementsByTagName("*").length;
|
|
});
|
|
|
|
// Support: IE<9
|
|
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
|
|
|
|
// Support: IE<10
|
|
// Check if getElementById returns elements by name
|
|
// The broken getElementById methods don't pick up programmatically-set names,
|
|
// so use a roundabout getElementsByName test
|
|
support.getById = assert(function( el ) {
|
|
docElem.appendChild( el ).id = expando;
|
|
return !document.getElementsByName || !document.getElementsByName( expando ).length;
|
|
});
|
|
|
|
// ID filter and find
|
|
if ( support.getById ) {
|
|
Expr.filter["ID"] = function( id ) {
|
|
var attrId = id.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
return elem.getAttribute("id") === attrId;
|
|
};
|
|
};
|
|
Expr.find["ID"] = function( id, context ) {
|
|
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
|
|
var elem = context.getElementById( id );
|
|
return elem ? [ elem ] : [];
|
|
}
|
|
};
|
|
} else {
|
|
Expr.filter["ID"] = function( id ) {
|
|
var attrId = id.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
var node = typeof elem.getAttributeNode !== "undefined" &&
|
|
elem.getAttributeNode("id");
|
|
return node && node.value === attrId;
|
|
};
|
|
};
|
|
|
|
// Support: IE 6 - 7 only
|
|
// getElementById is not reliable as a find shortcut
|
|
Expr.find["ID"] = function( id, context ) {
|
|
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
|
|
var node, i, elems,
|
|
elem = context.getElementById( id );
|
|
|
|
if ( elem ) {
|
|
|
|
// Verify the id attribute
|
|
node = elem.getAttributeNode("id");
|
|
if ( node && node.value === id ) {
|
|
return [ elem ];
|
|
}
|
|
|
|
// Fall back on getElementsByName
|
|
elems = context.getElementsByName( id );
|
|
i = 0;
|
|
while ( (elem = elems[i++]) ) {
|
|
node = elem.getAttributeNode("id");
|
|
if ( node && node.value === id ) {
|
|
return [ elem ];
|
|
}
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
};
|
|
}
|
|
|
|
// Tag
|
|
Expr.find["TAG"] = support.getElementsByTagName ?
|
|
function( tag, context ) {
|
|
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
|
return context.getElementsByTagName( tag );
|
|
|
|
// DocumentFragment nodes don't have gEBTN
|
|
} else if ( support.qsa ) {
|
|
return context.querySelectorAll( tag );
|
|
}
|
|
} :
|
|
|
|
function( tag, context ) {
|
|
var elem,
|
|
tmp = [],
|
|
i = 0,
|
|
// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
|
|
results = context.getElementsByTagName( tag );
|
|
|
|
// Filter out possible comments
|
|
if ( tag === "*" ) {
|
|
while ( (elem = results[i++]) ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
tmp.push( elem );
|
|
}
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
return results;
|
|
};
|
|
|
|
// Class
|
|
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
|
|
if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
|
|
return context.getElementsByClassName( className );
|
|
}
|
|
};
|
|
|
|
/* QSA/matchesSelector
|
|
---------------------------------------------------------------------- */
|
|
|
|
// QSA and matchesSelector support
|
|
|
|
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
|
|
rbuggyMatches = [];
|
|
|
|
// qSa(:focus) reports false when true (Chrome 21)
|
|
// We allow this because of a bug in IE8/9 that throws an error
|
|
// whenever `document.activeElement` is accessed on an iframe
|
|
// So, we allow :focus to pass through QSA all the time to avoid the IE error
|
|
// See https://bugs.jquery.com/ticket/13378
|
|
rbuggyQSA = [];
|
|
|
|
if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
|
|
// Build QSA regex
|
|
// Regex strategy adopted from Diego Perini
|
|
assert(function( el ) {
|
|
// Select is set to empty string on purpose
|
|
// This is to test IE's treatment of not explicitly
|
|
// setting a boolean content attribute,
|
|
// since its presence should be enough
|
|
// https://bugs.jquery.com/ticket/12359
|
|
docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
|
|
"<select id='" + expando + "-\r\\' msallowcapture=''>" +
|
|
"<option selected=''></option></select>";
|
|
|
|
// Support: IE8, Opera 11-12.16
|
|
// Nothing should be selected when empty strings follow ^= or $= or *=
|
|
// The test attribute must be unknown in Opera but "safe" for WinRT
|
|
// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
|
|
if ( el.querySelectorAll("[msallowcapture^='']").length ) {
|
|
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
|
|
}
|
|
|
|
// Support: IE8
|
|
// Boolean attributes and "value" are not treated correctly
|
|
if ( !el.querySelectorAll("[selected]").length ) {
|
|
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
|
|
}
|
|
|
|
// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
|
|
if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
|
|
rbuggyQSA.push("~=");
|
|
}
|
|
|
|
// Webkit/Opera - :checked should return selected option elements
|
|
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
|
// IE8 throws error here and will not see later tests
|
|
if ( !el.querySelectorAll(":checked").length ) {
|
|
rbuggyQSA.push(":checked");
|
|
}
|
|
|
|
// Support: Safari 8+, iOS 8+
|
|
// https://bugs.webkit.org/show_bug.cgi?id=136851
|
|
// In-page `selector#id sibling-combinator selector` fails
|
|
if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
|
|
rbuggyQSA.push(".#.+[+~]");
|
|
}
|
|
});
|
|
|
|
assert(function( el ) {
|
|
el.innerHTML = "<a href='' disabled='disabled'></a>" +
|
|
"<select disabled='disabled'><option/></select>";
|
|
|
|
// Support: Windows 8 Native Apps
|
|
// The type and name attributes are restricted during .innerHTML assignment
|
|
var input = document.createElement("input");
|
|
input.setAttribute( "type", "hidden" );
|
|
el.appendChild( input ).setAttribute( "name", "D" );
|
|
|
|
// Support: IE8
|
|
// Enforce case-sensitivity of name attribute
|
|
if ( el.querySelectorAll("[name=d]").length ) {
|
|
rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
|
|
}
|
|
|
|
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
|
|
// IE8 throws error here and will not see later tests
|
|
if ( el.querySelectorAll(":enabled").length !== 2 ) {
|
|
rbuggyQSA.push( ":enabled", ":disabled" );
|
|
}
|
|
|
|
// Support: IE9-11+
|
|
// IE's :disabled selector does not pick up the children of disabled fieldsets
|
|
docElem.appendChild( el ).disabled = true;
|
|
if ( el.querySelectorAll(":disabled").length !== 2 ) {
|
|
rbuggyQSA.push( ":enabled", ":disabled" );
|
|
}
|
|
|
|
// Opera 10-11 does not throw on post-comma invalid pseudos
|
|
el.querySelectorAll("*,:x");
|
|
rbuggyQSA.push(",.*:");
|
|
});
|
|
}
|
|
|
|
if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
|
|
docElem.webkitMatchesSelector ||
|
|
docElem.mozMatchesSelector ||
|
|
docElem.oMatchesSelector ||
|
|
docElem.msMatchesSelector) )) ) {
|
|
|
|
assert(function( el ) {
|
|
// Check to see if it's possible to do matchesSelector
|
|
// on a disconnected node (IE 9)
|
|
support.disconnectedMatch = matches.call( el, "*" );
|
|
|
|
// This should fail with an exception
|
|
// Gecko does not error, returns false instead
|
|
matches.call( el, "[s!='']:x" );
|
|
rbuggyMatches.push( "!=", pseudos );
|
|
});
|
|
}
|
|
|
|
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
|
|
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
|
|
|
|
/* Contains
|
|
---------------------------------------------------------------------- */
|
|
hasCompare = rnative.test( docElem.compareDocumentPosition );
|
|
|
|
// Element contains another
|
|
// Purposefully self-exclusive
|
|
// As in, an element does not contain itself
|
|
contains = hasCompare || rnative.test( 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 ) :
|
|
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
|
));
|
|
} :
|
|
function( a, b ) {
|
|
if ( b ) {
|
|
while ( (b = b.parentNode) ) {
|
|
if ( b === a ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/* Sorting
|
|
---------------------------------------------------------------------- */
|
|
|
|
// Document order sorting
|
|
sortOrder = hasCompare ?
|
|
function( a, b ) {
|
|
|
|
// Flag for duplicate removal
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
|
|
// Sort on method existence if only one input has compareDocumentPosition
|
|
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
|
|
if ( compare ) {
|
|
return compare;
|
|
}
|
|
|
|
// Calculate position if both inputs belong to the same document
|
|
compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
|
|
a.compareDocumentPosition( b ) :
|
|
|
|
// Otherwise we know they are disconnected
|
|
1;
|
|
|
|
// Disconnected nodes
|
|
if ( compare & 1 ||
|
|
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
|
|
|
|
// Choose the first element that is related to our preferred document
|
|
if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
|
|
return -1;
|
|
}
|
|
if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
|
|
return 1;
|
|
}
|
|
|
|
// Maintain original order
|
|
return sortInput ?
|
|
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
|
|
0;
|
|
}
|
|
|
|
return compare & 4 ? -1 : 1;
|
|
} :
|
|
function( a, b ) {
|
|
// Exit early if the nodes are identical
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
|
|
var cur,
|
|
i = 0,
|
|
aup = a.parentNode,
|
|
bup = b.parentNode,
|
|
ap = [ a ],
|
|
bp = [ b ];
|
|
|
|
// Parentless nodes are either documents or disconnected
|
|
if ( !aup || !bup ) {
|
|
return a === document ? -1 :
|
|
b === document ? 1 :
|
|
aup ? -1 :
|
|
bup ? 1 :
|
|
sortInput ?
|
|
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
|
|
0;
|
|
|
|
// If the nodes are siblings, we can do a quick check
|
|
} else if ( aup === bup ) {
|
|
return siblingCheck( a, b );
|
|
}
|
|
|
|
// Otherwise we need full lists of their ancestors for comparison
|
|
cur = a;
|
|
while ( (cur = cur.parentNode) ) {
|
|
ap.unshift( cur );
|
|
}
|
|
cur = b;
|
|
while ( (cur = cur.parentNode) ) {
|
|
bp.unshift( cur );
|
|
}
|
|
|
|
// Walk down the tree looking for a discrepancy
|
|
while ( ap[i] === bp[i] ) {
|
|
i++;
|
|
}
|
|
|
|
return i ?
|
|
// Do a sibling check if the nodes have a common ancestor
|
|
siblingCheck( ap[i], bp[i] ) :
|
|
|
|
// Otherwise nodes in our document sort first
|
|
ap[i] === preferredDoc ? -1 :
|
|
bp[i] === preferredDoc ? 1 :
|
|
0;
|
|
};
|
|
|
|
return document;
|
|
};
|
|
|
|
Sizzle.matches = function( expr, elements ) {
|
|
return Sizzle( expr, null, null, elements );
|
|
};
|
|
|
|
Sizzle.matchesSelector = function( elem, expr ) {
|
|
// Set document vars if needed
|
|
if ( ( elem.ownerDocument || elem ) !== document ) {
|
|
setDocument( elem );
|
|
}
|
|
|
|
// Make sure that attribute selectors are quoted
|
|
expr = expr.replace( rattributeQuotes, "='$1']" );
|
|
|
|
if ( support.matchesSelector && documentIsHTML &&
|
|
!compilerCache[ expr + " " ] &&
|
|
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
|
|
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
|
|
|
|
try {
|
|
var ret = matches.call( elem, expr );
|
|
|
|
// IE 9's matchesSelector returns false on disconnected nodes
|
|
if ( ret || support.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, document, null, [ elem ] ).length > 0;
|
|
};
|
|
|
|
Sizzle.contains = function( context, elem ) {
|
|
// Set document vars if needed
|
|
if ( ( context.ownerDocument || context ) !== document ) {
|
|
setDocument( context );
|
|
}
|
|
return contains( context, elem );
|
|
};
|
|
|
|
Sizzle.attr = function( elem, name ) {
|
|
// Set document vars if needed
|
|
if ( ( elem.ownerDocument || elem ) !== document ) {
|
|
setDocument( elem );
|
|
}
|
|
|
|
var fn = Expr.attrHandle[ name.toLowerCase() ],
|
|
// Don't get fooled by Object.prototype properties (jQuery #13807)
|
|
val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
|
|
fn( elem, name, !documentIsHTML ) :
|
|
undefined;
|
|
|
|
return val !== undefined ?
|
|
val :
|
|
support.attributes || !documentIsHTML ?
|
|
elem.getAttribute( name ) :
|
|
(val = elem.getAttributeNode(name)) && val.specified ?
|
|
val.value :
|
|
null;
|
|
};
|
|
|
|
Sizzle.escape = function( sel ) {
|
|
return (sel + "").replace( rcssescape, fcssescape );
|
|
};
|
|
|
|
Sizzle.error = function( msg ) {
|
|
throw new Error( "Syntax error, unrecognized expression: " + msg );
|
|
};
|
|
|
|
/**
|
|
* Document sorting and removing duplicates
|
|
* @param {ArrayLike} results
|
|
*/
|
|
Sizzle.uniqueSort = function( results ) {
|
|
var elem,
|
|
duplicates = [],
|
|
j = 0,
|
|
i = 0;
|
|
|
|
// Unless we *know* we can detect duplicates, assume their presence
|
|
hasDuplicate = !support.detectDuplicates;
|
|
sortInput = !support.sortStable && results.slice( 0 );
|
|
results.sort( sortOrder );
|
|
|
|
if ( hasDuplicate ) {
|
|
while ( (elem = results[i++]) ) {
|
|
if ( elem === results[ i ] ) {
|
|
j = duplicates.push( i );
|
|
}
|
|
}
|
|
while ( j-- ) {
|
|
results.splice( duplicates[ j ], 1 );
|
|
}
|
|
}
|
|
|
|
// Clear input after sorting to release objects
|
|
// See https://github.com/jquery/sizzle/pull/225
|
|
sortInput = null;
|
|
|
|
return results;
|
|
};
|
|
|
|
/**
|
|
* 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 no nodeType, this is expected to be an array
|
|
while ( (node = elem[i++]) ) {
|
|
// Do not traverse comment nodes
|
|
ret += getText( node );
|
|
}
|
|
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
|
|
// Use textContent for elements
|
|
// innerText usage removed for consistency of new lines (jQuery #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
|
|
|
|
return ret;
|
|
};
|
|
|
|
Expr = Sizzle.selectors = {
|
|
|
|
// Can be adjusted by the user
|
|
cacheLength: 50,
|
|
|
|
createPseudo: markFunction,
|
|
|
|
match: matchExpr,
|
|
|
|
attrHandle: {},
|
|
|
|
find: {},
|
|
|
|
relative: {
|
|
">": { dir: "parentNode", first: true },
|
|
" ": { dir: "parentNode" },
|
|
"+": { dir: "previousSibling", first: true },
|
|
"~": { dir: "previousSibling" }
|
|
},
|
|
|
|
preFilter: {
|
|
"ATTR": function( match ) {
|
|
match[1] = match[1].replace( runescape, funescape );
|
|
|
|
// Move the given value to match[3] whether quoted or unquoted
|
|
match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
|
|
|
|
if ( match[2] === "~=" ) {
|
|
match[3] = " " + match[3] + " ";
|
|
}
|
|
|
|
return match.slice( 0, 4 );
|
|
},
|
|
|
|
"CHILD": function( match ) {
|
|
/* matches from matchExpr["CHILD"]
|
|
1 type (only|nth|...)
|
|
2 what (child|of-type)
|
|
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
|
|
4 xn-component of xn+y argument ([+-]?\d*n|)
|
|
5 sign of xn-component
|
|
6 x of xn-component
|
|
7 sign of y-component
|
|
8 y of y-component
|
|
*/
|
|
match[1] = match[1].toLowerCase();
|
|
|
|
if ( match[1].slice( 0, 3 ) === "nth" ) {
|
|
// nth-* requires argument
|
|
if ( !match[3] ) {
|
|
Sizzle.error( match[0] );
|
|
}
|
|
|
|
// numeric x and y parameters for Expr.filter.CHILD
|
|
// remember that false/true cast respectively to 0/1
|
|
match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
|
|
match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
|
|
|
|
// other types prohibit arguments
|
|
} else if ( match[3] ) {
|
|
Sizzle.error( match[0] );
|
|
}
|
|
|
|
return match;
|
|
},
|
|
|
|
"PSEUDO": function( match ) {
|
|
var excess,
|
|
unquoted = !match[6] && match[2];
|
|
|
|
if ( matchExpr["CHILD"].test( match[0] ) ) {
|
|
return null;
|
|
}
|
|
|
|
// Accept quoted arguments as-is
|
|
if ( match[3] ) {
|
|
match[2] = match[4] || match[5] || "";
|
|
|
|
// Strip excess characters from unquoted arguments
|
|
} else if ( unquoted && 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
|
|
match[0] = match[0].slice( 0, excess );
|
|
match[2] = unquoted.slice( 0, excess );
|
|
}
|
|
|
|
// Return only captures needed by the pseudo filter method (type and argument)
|
|
return match.slice( 0, 3 );
|
|
}
|
|
},
|
|
|
|
filter: {
|
|
|
|
"TAG": function( nodeNameSelector ) {
|
|
var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
|
|
return nodeNameSelector === "*" ?
|
|
function() { return true; } :
|
|
function( elem ) {
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
|
|
};
|
|
},
|
|
|
|
"CLASS": function( className ) {
|
|
var pattern = classCache[ className + " " ];
|
|
|
|
return pattern ||
|
|
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
|
|
classCache( className, function( elem ) {
|
|
return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
|
|
});
|
|
},
|
|
|
|
"ATTR": function( name, operator, check ) {
|
|
return function( elem ) {
|
|
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.slice( -check.length ) === check :
|
|
operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
|
|
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
|
|
false;
|
|
};
|
|
},
|
|
|
|
"CHILD": function( type, what, argument, first, last ) {
|
|
var simple = type.slice( 0, 3 ) !== "nth",
|
|
forward = type.slice( -4 ) !== "last",
|
|
ofType = what === "of-type";
|
|
|
|
return first === 1 && last === 0 ?
|
|
|
|
// Shortcut for :nth-*(n)
|
|
function( elem ) {
|
|
return !!elem.parentNode;
|
|
} :
|
|
|
|
function( elem, context, xml ) {
|
|
var cache, uniqueCache, outerCache, node, nodeIndex, start,
|
|
dir = simple !== forward ? "nextSibling" : "previousSibling",
|
|
parent = elem.parentNode,
|
|
name = ofType && elem.nodeName.toLowerCase(),
|
|
useCache = !xml && !ofType,
|
|
diff = false;
|
|
|
|
if ( parent ) {
|
|
|
|
// :(first|last|only)-(child|of-type)
|
|
if ( simple ) {
|
|
while ( dir ) {
|
|
node = elem;
|
|
while ( (node = node[ dir ]) ) {
|
|
if ( ofType ?
|
|
node.nodeName.toLowerCase() === name :
|
|
node.nodeType === 1 ) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
// Reverse direction for :only-* (if we haven't yet done so)
|
|
start = dir = type === "only" && !start && "nextSibling";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
start = [ forward ? parent.firstChild : parent.lastChild ];
|
|
|
|
// non-xml :nth-child(...) stores cache data on `parent`
|
|
if ( forward && useCache ) {
|
|
|
|
// Seek `elem` from a previously-cached index
|
|
|
|
// ...in a gzip-friendly way
|
|
node = parent;
|
|
outerCache = node[ expando ] || (node[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ node.uniqueID ] ||
|
|
(outerCache[ node.uniqueID ] = {});
|
|
|
|
cache = uniqueCache[ type ] || [];
|
|
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
|
|
diff = nodeIndex && cache[ 2 ];
|
|
node = nodeIndex && parent.childNodes[ nodeIndex ];
|
|
|
|
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
|
|
|
// Fallback to seeking `elem` from the start
|
|
(diff = nodeIndex = 0) || start.pop()) ) {
|
|
|
|
// When found, cache indexes on `parent` and break
|
|
if ( node.nodeType === 1 && ++diff && node === elem ) {
|
|
uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// Use previously-cached element index if available
|
|
if ( useCache ) {
|
|
// ...in a gzip-friendly way
|
|
node = elem;
|
|
outerCache = node[ expando ] || (node[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ node.uniqueID ] ||
|
|
(outerCache[ node.uniqueID ] = {});
|
|
|
|
cache = uniqueCache[ type ] || [];
|
|
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
|
|
diff = nodeIndex;
|
|
}
|
|
|
|
// xml :nth-child(...)
|
|
// or :nth-last-child(...) or :nth(-last)?-of-type(...)
|
|
if ( diff === false ) {
|
|
// Use the same loop as above to seek `elem` from the start
|
|
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
|
(diff = nodeIndex = 0) || start.pop()) ) {
|
|
|
|
if ( ( ofType ?
|
|
node.nodeName.toLowerCase() === name :
|
|
node.nodeType === 1 ) &&
|
|
++diff ) {
|
|
|
|
// Cache the index of each encountered element
|
|
if ( useCache ) {
|
|
outerCache = node[ expando ] || (node[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ node.uniqueID ] ||
|
|
(outerCache[ node.uniqueID ] = {});
|
|
|
|
uniqueCache[ type ] = [ dirruns, diff ];
|
|
}
|
|
|
|
if ( node === elem ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Incorporate the offset, then check against cycle size
|
|
diff -= last;
|
|
return diff === first || ( diff % first === 0 && diff / first >= 0 );
|
|
}
|
|
};
|
|
},
|
|
|
|
"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( seed, matched[i] );
|
|
seed[ idx ] = !( matches[ idx ] = matched[i] );
|
|
}
|
|
}) :
|
|
function( elem ) {
|
|
return fn( elem, 0, args );
|
|
};
|
|
}
|
|
|
|
return fn;
|
|
}
|
|
},
|
|
|
|
pseudos: {
|
|
// Potentially complex 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 );
|
|
// Don't keep the element (issue #299)
|
|
input[0] = null;
|
|
return !results.pop();
|
|
};
|
|
}),
|
|
|
|
"has": markFunction(function( selector ) {
|
|
return function( elem ) {
|
|
return Sizzle( selector, elem ).length > 0;
|
|
};
|
|
}),
|
|
|
|
"contains": markFunction(function( text ) {
|
|
text = text.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
|
|
};
|
|
}),
|
|
|
|
// "Whether an element is represented by a :lang() selector
|
|
// is based solely on the element's language value
|
|
// being equal to the identifier C,
|
|
// or beginning with the identifier C immediately followed by "-".
|
|
// The matching of C against the element's language value is performed case-insensitively.
|
|
// The identifier C does not have to be a valid language name."
|
|
// http://www.w3.org/TR/selectors/#lang-pseudo
|
|
"lang": markFunction( function( lang ) {
|
|
// lang value must be a valid identifier
|
|
if ( !ridentifier.test(lang || "") ) {
|
|
Sizzle.error( "unsupported lang: " + lang );
|
|
}
|
|
lang = lang.replace( runescape, funescape ).toLowerCase();
|
|
return function( elem ) {
|
|
var elemLang;
|
|
do {
|
|
if ( (elemLang = documentIsHTML ?
|
|
elem.lang :
|
|
elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
|
|
|
|
elemLang = elemLang.toLowerCase();
|
|
return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
|
|
}
|
|
} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
|
|
return false;
|
|
};
|
|
}),
|
|
|
|
// Miscellaneous
|
|
"target": function( elem ) {
|
|
var hash = window.location && window.location.hash;
|
|
return hash && hash.slice( 1 ) === elem.id;
|
|
},
|
|
|
|
"root": function( elem ) {
|
|
return elem === docElem;
|
|
},
|
|
|
|
"focus": function( elem ) {
|
|
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
|
|
},
|
|
|
|
// Boolean properties
|
|
"enabled": createDisabledPseudo( false ),
|
|
"disabled": createDisabledPseudo( 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;
|
|
},
|
|
|
|
// Contents
|
|
"empty": function( elem ) {
|
|
// http://www.w3.org/TR/selectors/#empty-pseudo
|
|
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
|
|
// but not by others (comment: 8; processing instruction: 7; etc.)
|
|
// nodeType < 6 works because attributes (2) do not appear as children
|
|
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
|
if ( elem.nodeType < 6 ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
"parent": function( elem ) {
|
|
return !Expr.pseudos["empty"]( elem );
|
|
},
|
|
|
|
// Element/input types
|
|
"header": function( elem ) {
|
|
return rheader.test( elem.nodeName );
|
|
},
|
|
|
|
"input": function( elem ) {
|
|
return rinputs.test( elem.nodeName );
|
|
},
|
|
|
|
"button": function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === "input" && elem.type === "button" || name === "button";
|
|
},
|
|
|
|
"text": function( elem ) {
|
|
var attr;
|
|
return elem.nodeName.toLowerCase() === "input" &&
|
|
elem.type === "text" &&
|
|
|
|
// Support: IE<8
|
|
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
|
|
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
|
|
},
|
|
|
|
// Position-in-collection
|
|
"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 ) {
|
|
var i = 0;
|
|
for ( ; i < length; i += 2 ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"odd": createPositionalPseudo(function( matchIndexes, length ) {
|
|
var i = 1;
|
|
for ( ; i < length; i += 2 ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for ( ; --i >= 0; ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for ( ; ++i < length; ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
})
|
|
}
|
|
};
|
|
|
|
Expr.pseudos["nth"] = Expr.pseudos["eq"];
|
|
|
|
// Add button/input type pseudos
|
|
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
|
|
Expr.pseudos[ i ] = createInputPseudo( i );
|
|
}
|
|
for ( i in { submit: true, reset: true } ) {
|
|
Expr.pseudos[ i ] = createButtonPseudo( i );
|
|
}
|
|
|
|
// Easy API for creating new setFilters
|
|
function setFilters() {}
|
|
setFilters.prototype = Expr.filters = Expr.pseudos;
|
|
Expr.setFilters = new setFilters();
|
|
|
|
tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
|
|
var matched, match, tokens, type,
|
|
soFar, groups, preFilters,
|
|
cached = tokenCache[ 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 )) ) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
// Cast descendant combinators to space
|
|
type: match[0].replace( rtrim, " " )
|
|
});
|
|
soFar = soFar.slice( matched.length );
|
|
}
|
|
|
|
// Filters
|
|
for ( type in Expr.filter ) {
|
|
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
|
|
(match = preFilters[ type ]( match ))) ) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
type: type,
|
|
matches: match
|
|
});
|
|
soFar = soFar.slice( matched.length );
|
|
}
|
|
}
|
|
|
|
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 toSelector( tokens ) {
|
|
var i = 0,
|
|
len = tokens.length,
|
|
selector = "";
|
|
for ( ; i < len; i++ ) {
|
|
selector += tokens[i].value;
|
|
}
|
|
return selector;
|
|
}
|
|
|
|
function addCombinator( matcher, combinator, base ) {
|
|
var dir = combinator.dir,
|
|
skip = combinator.next,
|
|
key = skip || dir,
|
|
checkNonElements = base && key === "parentNode",
|
|
doneName = done++;
|
|
|
|
return combinator.first ?
|
|
// Check against closest ancestor/preceding element
|
|
function( elem, context, xml ) {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
return matcher( elem, context, xml );
|
|
}
|
|
}
|
|
return false;
|
|
} :
|
|
|
|
// Check against all ancestor/preceding elements
|
|
function( elem, context, xml ) {
|
|
var oldCache, uniqueCache, outerCache,
|
|
newCache = [ dirruns, doneName ];
|
|
|
|
// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
|
|
if ( xml ) {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
if ( matcher( elem, context, xml ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
outerCache = elem[ expando ] || (elem[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
|
|
|
|
if ( skip && skip === elem.nodeName.toLowerCase() ) {
|
|
elem = elem[ dir ] || elem;
|
|
} else if ( (oldCache = uniqueCache[ key ]) &&
|
|
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
|
|
|
|
// Assign to newCache so results back-propagate to previous elements
|
|
return (newCache[ 2 ] = oldCache[ 2 ]);
|
|
} else {
|
|
// Reuse newcache so results back-propagate to previous elements
|
|
uniqueCache[ key ] = newCache;
|
|
|
|
// A match means we're done; a fail means we have to keep checking
|
|
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
|
|
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 multipleContexts( selector, contexts, results ) {
|
|
var i = 0,
|
|
len = contexts.length;
|
|
for ( ; i < len; i++ ) {
|
|
Sizzle( selector, contexts[i], results );
|
|
}
|
|
return results;
|
|
}
|
|
|
|
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( 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( checkContext, elem ) > -1;
|
|
}, implicitRelative, true ),
|
|
matchers = [ function( elem, context, xml ) {
|
|
var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
|
|
(checkContext = context).nodeType ?
|
|
matchContext( elem, context, xml ) :
|
|
matchAnyContext( elem, context, xml ) );
|
|
// Avoid hanging onto element (issue #299)
|
|
checkContext = null;
|
|
return ret;
|
|
} ];
|
|
|
|
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 && toSelector(
|
|
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
|
|
tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
|
|
).replace( rtrim, "$1" ),
|
|
matcher,
|
|
i < j && matcherFromTokens( tokens.slice( i, j ) ),
|
|
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
|
|
j < len && toSelector( tokens )
|
|
);
|
|
}
|
|
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, outermost ) {
|
|
var elem, j, matcher,
|
|
matchedCount = 0,
|
|
i = "0",
|
|
unmatched = seed && [],
|
|
setMatched = [],
|
|
contextBackup = outermostContext,
|
|
// We must always have either seed elements or outermost context
|
|
elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
|
|
// Use integer dirruns iff this is the outermost matcher
|
|
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
|
|
len = elems.length;
|
|
|
|
if ( outermost ) {
|
|
outermostContext = context === document || context || outermost;
|
|
}
|
|
|
|
// Add elements passing elementMatchers directly to results
|
|
// Support: IE<9, Safari
|
|
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
|
|
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
|
|
if ( byElement && elem ) {
|
|
j = 0;
|
|
if ( !context && elem.ownerDocument !== document ) {
|
|
setDocument( elem );
|
|
xml = !documentIsHTML;
|
|
}
|
|
while ( (matcher = elementMatchers[j++]) ) {
|
|
if ( matcher( elem, context || document, xml) ) {
|
|
results.push( elem );
|
|
break;
|
|
}
|
|
}
|
|
if ( outermost ) {
|
|
dirruns = dirrunsUnique;
|
|
}
|
|
}
|
|
|
|
// 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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
// `i` is now the count of elements visited above, and adding it to `matchedCount`
|
|
// makes the latter nonnegative.
|
|
matchedCount += i;
|
|
|
|
// Apply set filters to unmatched elements
|
|
// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
|
|
// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
|
|
// no element matchers and no seed.
|
|
// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
|
|
// case, which will result in a "00" `matchedCount` that differs from `i` but is also
|
|
// numerically zero.
|
|
if ( bySet && i !== matchedCount ) {
|
|
j = 0;
|
|
while ( (matcher = setMatchers[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;
|
|
};
|
|
|
|
return bySet ?
|
|
markFunction( superMatcher ) :
|
|
superMatcher;
|
|
}
|
|
|
|
compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
|
|
var i,
|
|
setMatchers = [],
|
|
elementMatchers = [],
|
|
cached = compilerCache[ selector + " " ];
|
|
|
|
if ( !cached ) {
|
|
// Generate a function of recursive functions that can be used to check each element
|
|
if ( !match ) {
|
|
match = tokenize( selector );
|
|
}
|
|
i = match.length;
|
|
while ( i-- ) {
|
|
cached = matcherFromTokens( match[i] );
|
|
if ( cached[ expando ] ) {
|
|
setMatchers.push( cached );
|
|
} else {
|
|
elementMatchers.push( cached );
|
|
}
|
|
}
|
|
|
|
// Cache the compiled function
|
|
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
|
|
|
|
// Save selector and tokenization
|
|
cached.selector = selector;
|
|
}
|
|
return cached;
|
|
};
|
|
|
|
/**
|
|
* A low-level selection function that works with Sizzle's compiled
|
|
* selector functions
|
|
* @param {String|Function} selector A selector or a pre-compiled
|
|
* selector function built with Sizzle.compile
|
|
* @param {Element} context
|
|
* @param {Array} [results]
|
|
* @param {Array} [seed] A set of elements to match against
|
|
*/
|
|
select = Sizzle.select = function( selector, context, results, seed ) {
|
|
var i, tokens, token, type, find,
|
|
compiled = typeof selector === "function" && selector,
|
|
match = !seed && tokenize( (selector = compiled.selector || selector) );
|
|
|
|
results = results || [];
|
|
|
|
// Try to minimize operations if there is only one selector in the list and no seed
|
|
// (the latter of which guarantees us context)
|
|
if ( match.length === 1 ) {
|
|
|
|
// Reduce context if the leading compound selector is an ID
|
|
tokens = match[0] = match[0].slice( 0 );
|
|
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
|
|
context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
|
|
|
|
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
|
|
if ( !context ) {
|
|
return results;
|
|
|
|
// Precompiled matchers will still verify ancestry, so step up a level
|
|
} else if ( compiled ) {
|
|
context = context.parentNode;
|
|
}
|
|
|
|
selector = selector.slice( tokens.shift().value.length );
|
|
}
|
|
|
|
// Fetch a seed set for right-to-left matching
|
|
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
|
|
while ( 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( runescape, funescape ),
|
|
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
|
|
)) ) {
|
|
|
|
// If seed is empty or no tokens remain, we can return early
|
|
tokens.splice( i, 1 );
|
|
selector = seed.length && toSelector( tokens );
|
|
if ( !selector ) {
|
|
push.apply( results, seed );
|
|
return results;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compile and execute a filtering function if one is not provided
|
|
// Provide `match` to avoid retokenization if we modified the selector above
|
|
( compiled || compile( selector, match ) )(
|
|
seed,
|
|
context,
|
|
!documentIsHTML,
|
|
results,
|
|
!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
|
|
);
|
|
return results;
|
|
};
|
|
|
|
// One-time assignments
|
|
|
|
// Sort stability
|
|
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
|
|
|
|
// Support: Chrome 14-35+
|
|
// Always assume duplicates if they aren't passed to the comparison function
|
|
support.detectDuplicates = !!hasDuplicate;
|
|
|
|
// Initialize against the default document
|
|
setDocument();
|
|
|
|
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
|
|
// Detached nodes confoundingly follow *each other*
|
|
support.sortDetached = assert(function( el ) {
|
|
// Should return 1, but returns 4 (following)
|
|
return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
|
|
});
|
|
|
|
// Support: IE<8
|
|
// Prevent attribute/property "interpolation"
|
|
// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
|
|
if ( !assert(function( el ) {
|
|
el.innerHTML = "<a href='#'></a>";
|
|
return el.firstChild.getAttribute("href") === "#" ;
|
|
}) ) {
|
|
addHandle( "type|href|height|width", function( elem, name, isXML ) {
|
|
if ( !isXML ) {
|
|
return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
|
|
}
|
|
});
|
|
}
|
|
|
|
// Support: IE<9
|
|
// Use defaultValue in place of getAttribute("value")
|
|
if ( !support.attributes || !assert(function( el ) {
|
|
el.innerHTML = "<input/>";
|
|
el.firstChild.setAttribute( "value", "" );
|
|
return el.firstChild.getAttribute( "value" ) === "";
|
|
}) ) {
|
|
addHandle( "value", function( elem, name, isXML ) {
|
|
if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
|
|
return elem.defaultValue;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Support: IE<9
|
|
// Use getAttributeNode to fetch booleans when getAttribute lies
|
|
if ( !assert(function( el ) {
|
|
return el.getAttribute("disabled") == null;
|
|
}) ) {
|
|
addHandle( booleans, function( elem, name, isXML ) {
|
|
var val;
|
|
if ( !isXML ) {
|
|
return elem[ name ] === true ? name.toLowerCase() :
|
|
(val = elem.getAttributeNode( name )) && val.specified ?
|
|
val.value :
|
|
null;
|
|
}
|
|
});
|
|
}
|
|
|
|
return Sizzle;
|
|
|
|
})( window );
|
|
|
|
|
|
|
|
jQuery.find = Sizzle;
|
|
jQuery.expr = Sizzle.selectors;
|
|
|
|
// Deprecated
|
|
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
|
|
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
|
|
jQuery.text = Sizzle.getText;
|
|
jQuery.isXMLDoc = Sizzle.isXML;
|
|
jQuery.contains = Sizzle.contains;
|
|
jQuery.escapeSelector = Sizzle.escape;
|
|
|
|
|
|
|
|
|
|
var dir = function( elem, dir, until ) {
|
|
var matched = [],
|
|
truncate = until !== undefined;
|
|
|
|
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
if ( truncate && jQuery( elem ).is( until ) ) {
|
|
break;
|
|
}
|
|
matched.push( elem );
|
|
}
|
|
}
|
|
return matched;
|
|
};
|
|
|
|
|
|
var siblings = function( n, elem ) {
|
|
var matched = [];
|
|
|
|
for ( ; n; n = n.nextSibling ) {
|
|
if ( n.nodeType === 1 && n !== elem ) {
|
|
matched.push( n );
|
|
}
|
|
}
|
|
|
|
return matched;
|
|
};
|
|
|
|
|
|
var rneedsContext = jQuery.expr.match.needsContext;
|
|
|
|
|
|
|
|
function nodeName( elem, name ) {
|
|
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
|
|
|
|
};
|
|
var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
|
|
|
|
|
|
|
|
var risSimple = /^.[^:#\[\.,]*$/;
|
|
|
|
// Implement the identical functionality for filter and not
|
|
function winnow( elements, qualifier, not ) {
|
|
if ( jQuery.isFunction( qualifier ) ) {
|
|
return jQuery.grep( elements, function( elem, i ) {
|
|
return !!qualifier.call( elem, i, elem ) !== not;
|
|
} );
|
|
}
|
|
|
|
// Single element
|
|
if ( qualifier.nodeType ) {
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( elem === qualifier ) !== not;
|
|
} );
|
|
}
|
|
|
|
// Arraylike of elements (jQuery, arguments, Array)
|
|
if ( typeof qualifier !== "string" ) {
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
|
|
} );
|
|
}
|
|
|
|
// Simple selector that can be filtered directly, removing non-Elements
|
|
if ( risSimple.test( qualifier ) ) {
|
|
return jQuery.filter( qualifier, elements, not );
|
|
}
|
|
|
|
// Complex selector, compare the two sets, removing non-Elements
|
|
qualifier = jQuery.filter( qualifier, elements );
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;
|
|
} );
|
|
}
|
|
|
|
jQuery.filter = function( expr, elems, not ) {
|
|
var elem = elems[ 0 ];
|
|
|
|
if ( not ) {
|
|
expr = ":not(" + expr + ")";
|
|
}
|
|
|
|
if ( elems.length === 1 && elem.nodeType === 1 ) {
|
|
return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
|
|
}
|
|
|
|
return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
|
|
return elem.nodeType === 1;
|
|
} ) );
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
find: function( selector ) {
|
|
var i, ret,
|
|
len = this.length,
|
|
self = this;
|
|
|
|
if ( typeof selector !== "string" ) {
|
|
return this.pushStack( jQuery( selector ).filter( function() {
|
|
for ( i = 0; i < len; i++ ) {
|
|
if ( jQuery.contains( self[ i ], this ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
} ) );
|
|
}
|
|
|
|
ret = this.pushStack( [] );
|
|
|
|
for ( i = 0; i < len; i++ ) {
|
|
jQuery.find( selector, self[ i ], ret );
|
|
}
|
|
|
|
return len > 1 ? jQuery.uniqueSort( ret ) : ret;
|
|
},
|
|
filter: function( selector ) {
|
|
return this.pushStack( winnow( this, selector || [], false ) );
|
|
},
|
|
not: function( selector ) {
|
|
return this.pushStack( winnow( this, selector || [], true ) );
|
|
},
|
|
is: function( selector ) {
|
|
return !!winnow(
|
|
this,
|
|
|
|
// 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".
|
|
typeof selector === "string" && rneedsContext.test( selector ) ?
|
|
jQuery( selector ) :
|
|
selector || [],
|
|
false
|
|
).length;
|
|
}
|
|
} );
|
|
|
|
|
|
// Initialize a jQuery object
|
|
|
|
|
|
// A central reference to the root jQuery(document)
|
|
var rootjQuery,
|
|
|
|
// A simple way to check for HTML strings
|
|
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
|
|
// Strict HTML recognition (#11290: must start with <)
|
|
// Shortcut simple #id case for speed
|
|
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
|
|
|
|
init = jQuery.fn.init = function( selector, context, root ) {
|
|
var match, elem;
|
|
|
|
// HANDLE: $(""), $(null), $(undefined), $(false)
|
|
if ( !selector ) {
|
|
return this;
|
|
}
|
|
|
|
// Method init() accepts an alternate rootjQuery
|
|
// so migrate can support jQuery.sub (gh-2101)
|
|
root = root || rootjQuery;
|
|
|
|
// Handle HTML strings
|
|
if ( typeof selector === "string" ) {
|
|
if ( selector[ 0 ] === "<" &&
|
|
selector[ 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;
|
|
|
|
// Option to run scripts is true for back-compat
|
|
// Intentionally let the error be thrown if parseHTML is not present
|
|
jQuery.merge( this, jQuery.parseHTML(
|
|
match[ 1 ],
|
|
context && context.nodeType ? context.ownerDocument || context : document,
|
|
true
|
|
) );
|
|
|
|
// HANDLE: $(html, props)
|
|
if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
|
|
for ( match in context ) {
|
|
|
|
// Properties of context are called as methods if possible
|
|
if ( jQuery.isFunction( this[ match ] ) ) {
|
|
this[ match ]( context[ match ] );
|
|
|
|
// ...and otherwise set as attributes
|
|
} else {
|
|
this.attr( match, context[ match ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
|
|
// HANDLE: $(#id)
|
|
} else {
|
|
elem = document.getElementById( match[ 2 ] );
|
|
|
|
if ( elem ) {
|
|
|
|
// Inject the element directly into the jQuery object
|
|
this[ 0 ] = elem;
|
|
this.length = 1;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
// HANDLE: $(expr, $(...))
|
|
} else if ( !context || context.jquery ) {
|
|
return ( context || root ).find( selector );
|
|
|
|
// HANDLE: $(expr, context)
|
|
// (which is just equivalent to: $(context).find(expr)
|
|
} else {
|
|
return this.constructor( context ).find( selector );
|
|
}
|
|
|
|
// HANDLE: $(DOMElement)
|
|
} else if ( selector.nodeType ) {
|
|
this[ 0 ] = selector;
|
|
this.length = 1;
|
|
return this;
|
|
|
|
// HANDLE: $(function)
|
|
// Shortcut for document ready
|
|
} else if ( jQuery.isFunction( selector ) ) {
|
|
return root.ready !== undefined ?
|
|
root.ready( selector ) :
|
|
|
|
// Execute immediately if ready is not present
|
|
selector( jQuery );
|
|
}
|
|
|
|
return jQuery.makeArray( selector, this );
|
|
};
|
|
|
|
// Give the init function the jQuery prototype for later instantiation
|
|
init.prototype = jQuery.fn;
|
|
|
|
// Initialize central reference
|
|
rootjQuery = jQuery( document );
|
|
|
|
|
|
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
|
|
|
|
// 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( {
|
|
has: function( target ) {
|
|
var targets = jQuery( target, this ),
|
|
l = targets.length;
|
|
|
|
return this.filter( function() {
|
|
var i = 0;
|
|
for ( ; i < l; i++ ) {
|
|
if ( jQuery.contains( this, targets[ i ] ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
} );
|
|
},
|
|
|
|
closest: function( selectors, context ) {
|
|
var cur,
|
|
i = 0,
|
|
l = this.length,
|
|
matched = [],
|
|
targets = typeof selectors !== "string" && jQuery( selectors );
|
|
|
|
// Positional selectors never match, since there's no _selection_ context
|
|
if ( !rneedsContext.test( selectors ) ) {
|
|
for ( ; i < l; i++ ) {
|
|
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
|
|
|
|
// Always skip document fragments
|
|
if ( cur.nodeType < 11 && ( targets ?
|
|
targets.index( cur ) > -1 :
|
|
|
|
// Don't pass non-elements to Sizzle
|
|
cur.nodeType === 1 &&
|
|
jQuery.find.matchesSelector( cur, selectors ) ) ) {
|
|
|
|
matched.push( cur );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
|
|
},
|
|
|
|
// Determine the position of an element within the set
|
|
index: function( elem ) {
|
|
|
|
// No argument, return index in parent
|
|
if ( !elem ) {
|
|
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
|
|
}
|
|
|
|
// Index in selector
|
|
if ( typeof elem === "string" ) {
|
|
return indexOf.call( jQuery( elem ), this[ 0 ] );
|
|
}
|
|
|
|
// Locate the position of the desired element
|
|
return indexOf.call( this,
|
|
|
|
// If it receives a jQuery object, the first element is used
|
|
elem.jquery ? elem[ 0 ] : elem
|
|
);
|
|
},
|
|
|
|
add: function( selector, context ) {
|
|
return this.pushStack(
|
|
jQuery.uniqueSort(
|
|
jQuery.merge( this.get(), jQuery( selector, context ) )
|
|
)
|
|
);
|
|
},
|
|
|
|
addBack: function( selector ) {
|
|
return this.add( selector == null ?
|
|
this.prevObject : this.prevObject.filter( selector )
|
|
);
|
|
}
|
|
} );
|
|
|
|
function sibling( cur, dir ) {
|
|
while ( ( cur = cur[ dir ] ) && 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 dir( elem, "parentNode" );
|
|
},
|
|
parentsUntil: function( elem, i, until ) {
|
|
return dir( elem, "parentNode", until );
|
|
},
|
|
next: function( elem ) {
|
|
return sibling( elem, "nextSibling" );
|
|
},
|
|
prev: function( elem ) {
|
|
return sibling( elem, "previousSibling" );
|
|
},
|
|
nextAll: function( elem ) {
|
|
return dir( elem, "nextSibling" );
|
|
},
|
|
prevAll: function( elem ) {
|
|
return dir( elem, "previousSibling" );
|
|
},
|
|
nextUntil: function( elem, i, until ) {
|
|
return dir( elem, "nextSibling", until );
|
|
},
|
|
prevUntil: function( elem, i, until ) {
|
|
return dir( elem, "previousSibling", until );
|
|
},
|
|
siblings: function( elem ) {
|
|
return siblings( ( elem.parentNode || {} ).firstChild, elem );
|
|
},
|
|
children: function( elem ) {
|
|
return siblings( elem.firstChild );
|
|
},
|
|
contents: function( elem ) {
|
|
if ( nodeName( elem, "iframe" ) ) {
|
|
return elem.contentDocument;
|
|
}
|
|
|
|
// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
|
|
// Treat the template element as a regular one in browsers that
|
|
// don't support it.
|
|
if ( nodeName( elem, "template" ) ) {
|
|
elem = elem.content || elem;
|
|
}
|
|
|
|
return jQuery.merge( [], elem.childNodes );
|
|
}
|
|
}, function( name, fn ) {
|
|
jQuery.fn[ name ] = function( until, selector ) {
|
|
var matched = jQuery.map( this, fn, until );
|
|
|
|
if ( name.slice( -5 ) !== "Until" ) {
|
|
selector = until;
|
|
}
|
|
|
|
if ( selector && typeof selector === "string" ) {
|
|
matched = jQuery.filter( selector, matched );
|
|
}
|
|
|
|
if ( this.length > 1 ) {
|
|
|
|
// Remove duplicates
|
|
if ( !guaranteedUnique[ name ] ) {
|
|
jQuery.uniqueSort( matched );
|
|
}
|
|
|
|
// Reverse order for parents* and prev-derivatives
|
|
if ( rparentsprev.test( name ) ) {
|
|
matched.reverse();
|
|
}
|
|
}
|
|
|
|
return this.pushStack( matched );
|
|
};
|
|
} );
|
|
var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
|
|
|
|
|
|
|
|
// Convert String-formatted options into Object-formatted ones
|
|
function createOptions( options ) {
|
|
var object = {};
|
|
jQuery.each( options.match( rnothtmlwhite ) || [], 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" ?
|
|
createOptions( options ) :
|
|
jQuery.extend( {}, options );
|
|
|
|
var // Flag to know if list is currently firing
|
|
firing,
|
|
|
|
// Last fire value for non-forgettable lists
|
|
memory,
|
|
|
|
// Flag to know if list was already fired
|
|
fired,
|
|
|
|
// Flag to prevent firing
|
|
locked,
|
|
|
|
// Actual callback list
|
|
list = [],
|
|
|
|
// Queue of execution data for repeatable lists
|
|
queue = [],
|
|
|
|
// Index of currently firing callback (modified by add/remove as needed)
|
|
firingIndex = -1,
|
|
|
|
// Fire callbacks
|
|
fire = function() {
|
|
|
|
// Enforce single-firing
|
|
locked = locked || options.once;
|
|
|
|
// Execute callbacks for all pending executions,
|
|
// respecting firingIndex overrides and runtime changes
|
|
fired = firing = true;
|
|
for ( ; queue.length; firingIndex = -1 ) {
|
|
memory = queue.shift();
|
|
while ( ++firingIndex < list.length ) {
|
|
|
|
// Run callback and check for early termination
|
|
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
|
|
options.stopOnFalse ) {
|
|
|
|
// Jump to end and forget the data so .add doesn't re-fire
|
|
firingIndex = list.length;
|
|
memory = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Forget the data if we're done with it
|
|
if ( !options.memory ) {
|
|
memory = false;
|
|
}
|
|
|
|
firing = false;
|
|
|
|
// Clean up if we're done firing for good
|
|
if ( locked ) {
|
|
|
|
// Keep an empty list if we have data for future add calls
|
|
if ( memory ) {
|
|
list = [];
|
|
|
|
// Otherwise, this object is spent
|
|
} else {
|
|
list = "";
|
|
}
|
|
}
|
|
},
|
|
|
|
// Actual Callbacks object
|
|
self = {
|
|
|
|
// Add a callback or a collection of callbacks to the list
|
|
add: function() {
|
|
if ( list ) {
|
|
|
|
// If we have memory from a past run, we should fire after adding
|
|
if ( memory && !firing ) {
|
|
firingIndex = list.length - 1;
|
|
queue.push( memory );
|
|
}
|
|
|
|
( function add( args ) {
|
|
jQuery.each( args, function( _, arg ) {
|
|
if ( jQuery.isFunction( arg ) ) {
|
|
if ( !options.unique || !self.has( arg ) ) {
|
|
list.push( arg );
|
|
}
|
|
} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
|
|
|
|
// Inspect recursively
|
|
add( arg );
|
|
}
|
|
} );
|
|
} )( arguments );
|
|
|
|
if ( memory && !firing ) {
|
|
fire();
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Remove a callback from the list
|
|
remove: function() {
|
|
jQuery.each( arguments, function( _, arg ) {
|
|
var index;
|
|
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
|
|
list.splice( index, 1 );
|
|
|
|
// Handle firing indexes
|
|
if ( index <= firingIndex ) {
|
|
firingIndex--;
|
|
}
|
|
}
|
|
} );
|
|
return this;
|
|
},
|
|
|
|
// Check if a given callback is in the list.
|
|
// If no argument is given, return whether or not list has callbacks attached.
|
|
has: function( fn ) {
|
|
return fn ?
|
|
jQuery.inArray( fn, list ) > -1 :
|
|
list.length > 0;
|
|
},
|
|
|
|
// Remove all callbacks from the list
|
|
empty: function() {
|
|
if ( list ) {
|
|
list = [];
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Disable .fire and .add
|
|
// Abort any current/pending executions
|
|
// Clear all callbacks and values
|
|
disable: function() {
|
|
locked = queue = [];
|
|
list = memory = "";
|
|
return this;
|
|
},
|
|
disabled: function() {
|
|
return !list;
|
|
},
|
|
|
|
// Disable .fire
|
|
// Also disable .add unless we have memory (since it would have no effect)
|
|
// Abort any pending executions
|
|
lock: function() {
|
|
locked = queue = [];
|
|
if ( !memory && !firing ) {
|
|
list = memory = "";
|
|
}
|
|
return this;
|
|
},
|
|
locked: function() {
|
|
return !!locked;
|
|
},
|
|
|
|
// Call all callbacks with the given context and arguments
|
|
fireWith: function( context, args ) {
|
|
if ( !locked ) {
|
|
args = args || [];
|
|
args = [ context, args.slice ? args.slice() : args ];
|
|
queue.push( args );
|
|
if ( !firing ) {
|
|
fire();
|
|
}
|
|
}
|
|
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;
|
|
};
|
|
|
|
|
|
function Identity( v ) {
|
|
return v;
|
|
}
|
|
function Thrower( ex ) {
|
|
throw ex;
|
|
}
|
|
|
|
function adoptValue( value, resolve, reject, noValue ) {
|
|
var method;
|
|
|
|
try {
|
|
|
|
// Check for promise aspect first to privilege synchronous behavior
|
|
if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
|
|
method.call( value ).done( resolve ).fail( reject );
|
|
|
|
// Other thenables
|
|
} else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
|
|
method.call( value, resolve, reject );
|
|
|
|
// Other non-thenables
|
|
} else {
|
|
|
|
// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
|
|
// * false: [ value ].slice( 0 ) => resolve( value )
|
|
// * true: [ value ].slice( 1 ) => resolve()
|
|
resolve.apply( undefined, [ value ].slice( noValue ) );
|
|
}
|
|
|
|
// For Promises/A+, convert exceptions into rejections
|
|
// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
|
|
// Deferred#then to conditionally suppress rejection.
|
|
} catch ( value ) {
|
|
|
|
// Support: Android 4.0 only
|
|
// Strict mode functions invoked without .call/.apply get global-object context
|
|
reject.apply( undefined, [ value ] );
|
|
}
|
|
}
|
|
|
|
jQuery.extend( {
|
|
|
|
Deferred: function( func ) {
|
|
var tuples = [
|
|
|
|
// action, add listener, callbacks,
|
|
// ... .then handlers, argument index, [final state]
|
|
[ "notify", "progress", jQuery.Callbacks( "memory" ),
|
|
jQuery.Callbacks( "memory" ), 2 ],
|
|
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
|
|
jQuery.Callbacks( "once memory" ), 0, "resolved" ],
|
|
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
|
|
jQuery.Callbacks( "once memory" ), 1, "rejected" ]
|
|
],
|
|
state = "pending",
|
|
promise = {
|
|
state: function() {
|
|
return state;
|
|
},
|
|
always: function() {
|
|
deferred.done( arguments ).fail( arguments );
|
|
return this;
|
|
},
|
|
"catch": function( fn ) {
|
|
return promise.then( null, fn );
|
|
},
|
|
|
|
// Keep pipe for back-compat
|
|
pipe: function( /* fnDone, fnFail, fnProgress */ ) {
|
|
var fns = arguments;
|
|
|
|
return jQuery.Deferred( function( newDefer ) {
|
|
jQuery.each( tuples, function( i, tuple ) {
|
|
|
|
// Map tuples (progress, done, fail) to arguments (done, fail, progress)
|
|
var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
|
|
|
|
// deferred.progress(function() { bind to newDefer or newDefer.notify })
|
|
// deferred.done(function() { bind to newDefer or newDefer.resolve })
|
|
// deferred.fail(function() { bind to newDefer or newDefer.reject })
|
|
deferred[ tuple[ 1 ] ]( function() {
|
|
var returned = fn && fn.apply( this, arguments );
|
|
if ( returned && jQuery.isFunction( returned.promise ) ) {
|
|
returned.promise()
|
|
.progress( newDefer.notify )
|
|
.done( newDefer.resolve )
|
|
.fail( newDefer.reject );
|
|
} else {
|
|
newDefer[ tuple[ 0 ] + "With" ](
|
|
this,
|
|
fn ? [ returned ] : arguments
|
|
);
|
|
}
|
|
} );
|
|
} );
|
|
fns = null;
|
|
} ).promise();
|
|
},
|
|
then: function( onFulfilled, onRejected, onProgress ) {
|
|
var maxDepth = 0;
|
|
function resolve( depth, deferred, handler, special ) {
|
|
return function() {
|
|
var that = this,
|
|
args = arguments,
|
|
mightThrow = function() {
|
|
var returned, then;
|
|
|
|
// Support: Promises/A+ section 2.3.3.3.3
|
|
// https://promisesaplus.com/#point-59
|
|
// Ignore double-resolution attempts
|
|
if ( depth < maxDepth ) {
|
|
return;
|
|
}
|
|
|
|
returned = handler.apply( that, args );
|
|
|
|
// Support: Promises/A+ section 2.3.1
|
|
// https://promisesaplus.com/#point-48
|
|
if ( returned === deferred.promise() ) {
|
|
throw new TypeError( "Thenable self-resolution" );
|
|
}
|
|
|
|
// Support: Promises/A+ sections 2.3.3.1, 3.5
|
|
// https://promisesaplus.com/#point-54
|
|
// https://promisesaplus.com/#point-75
|
|
// Retrieve `then` only once
|
|
then = returned &&
|
|
|
|
// Support: Promises/A+ section 2.3.4
|
|
// https://promisesaplus.com/#point-64
|
|
// Only check objects and functions for thenability
|
|
( typeof returned === "object" ||
|
|
typeof returned === "function" ) &&
|
|
returned.then;
|
|
|
|
// Handle a returned thenable
|
|
if ( jQuery.isFunction( then ) ) {
|
|
|
|
// Special processors (notify) just wait for resolution
|
|
if ( special ) {
|
|
then.call(
|
|
returned,
|
|
resolve( maxDepth, deferred, Identity, special ),
|
|
resolve( maxDepth, deferred, Thrower, special )
|
|
);
|
|
|
|
// Normal processors (resolve) also hook into progress
|
|
} else {
|
|
|
|
// ...and disregard older resolution values
|
|
maxDepth++;
|
|
|
|
then.call(
|
|
returned,
|
|
resolve( maxDepth, deferred, Identity, special ),
|
|
resolve( maxDepth, deferred, Thrower, special ),
|
|
resolve( maxDepth, deferred, Identity,
|
|
deferred.notifyWith )
|
|
);
|
|
}
|
|
|
|
// Handle all other returned values
|
|
} else {
|
|
|
|
// Only substitute handlers pass on context
|
|
// and multiple values (non-spec behavior)
|
|
if ( handler !== Identity ) {
|
|
that = undefined;
|
|
args = [ returned ];
|
|
}
|
|
|
|
// Process the value(s)
|
|
// Default process is resolve
|
|
( special || deferred.resolveWith )( that, args );
|
|
}
|
|
},
|
|
|
|
// Only normal processors (resolve) catch and reject exceptions
|
|
process = special ?
|
|
mightThrow :
|
|
function() {
|
|
try {
|
|
mightThrow();
|
|
} catch ( e ) {
|
|
|
|
if ( jQuery.Deferred.exceptionHook ) {
|
|
jQuery.Deferred.exceptionHook( e,
|
|
process.stackTrace );
|
|
}
|
|
|
|
// Support: Promises/A+ section 2.3.3.3.4.1
|
|
// https://promisesaplus.com/#point-61
|
|
// Ignore post-resolution exceptions
|
|
if ( depth + 1 >= maxDepth ) {
|
|
|
|
// Only substitute handlers pass on context
|
|
// and multiple values (non-spec behavior)
|
|
if ( handler !== Thrower ) {
|
|
that = undefined;
|
|
args = [ e ];
|
|
}
|
|
|
|
deferred.rejectWith( that, args );
|
|
}
|
|
}
|
|
};
|
|
|
|
// Support: Promises/A+ section 2.3.3.3.1
|
|
// https://promisesaplus.com/#point-57
|
|
// Re-resolve promises immediately to dodge false rejection from
|
|
// subsequent errors
|
|
if ( depth ) {
|
|
process();
|
|
} else {
|
|
|
|
// Call an optional hook to record the stack, in case of exception
|
|
// since it's otherwise lost when execution goes async
|
|
if ( jQuery.Deferred.getStackHook ) {
|
|
process.stackTrace = jQuery.Deferred.getStackHook();
|
|
}
|
|
window.setTimeout( process );
|
|
}
|
|
};
|
|
}
|
|
|
|
return jQuery.Deferred( function( newDefer ) {
|
|
|
|
// progress_handlers.add( ... )
|
|
tuples[ 0 ][ 3 ].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
jQuery.isFunction( onProgress ) ?
|
|
onProgress :
|
|
Identity,
|
|
newDefer.notifyWith
|
|
)
|
|
);
|
|
|
|
// fulfilled_handlers.add( ... )
|
|
tuples[ 1 ][ 3 ].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
jQuery.isFunction( onFulfilled ) ?
|
|
onFulfilled :
|
|
Identity
|
|
)
|
|
);
|
|
|
|
// rejected_handlers.add( ... )
|
|
tuples[ 2 ][ 3 ].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
jQuery.isFunction( onRejected ) ?
|
|
onRejected :
|
|
Thrower
|
|
)
|
|
);
|
|
} ).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 = {};
|
|
|
|
// Add list-specific methods
|
|
jQuery.each( tuples, function( i, tuple ) {
|
|
var list = tuple[ 2 ],
|
|
stateString = tuple[ 5 ];
|
|
|
|
// promise.progress = list.add
|
|
// promise.done = list.add
|
|
// promise.fail = list.add
|
|
promise[ tuple[ 1 ] ] = list.add;
|
|
|
|
// Handle state
|
|
if ( stateString ) {
|
|
list.add(
|
|
function() {
|
|
|
|
// state = "resolved" (i.e., fulfilled)
|
|
// state = "rejected"
|
|
state = stateString;
|
|
},
|
|
|
|
// rejected_callbacks.disable
|
|
// fulfilled_callbacks.disable
|
|
tuples[ 3 - i ][ 2 ].disable,
|
|
|
|
// progress_callbacks.lock
|
|
tuples[ 0 ][ 2 ].lock
|
|
);
|
|
}
|
|
|
|
// progress_handlers.fire
|
|
// fulfilled_handlers.fire
|
|
// rejected_handlers.fire
|
|
list.add( tuple[ 3 ].fire );
|
|
|
|
// deferred.notify = function() { deferred.notifyWith(...) }
|
|
// deferred.resolve = function() { deferred.resolveWith(...) }
|
|
// deferred.reject = function() { deferred.rejectWith(...) }
|
|
deferred[ tuple[ 0 ] ] = function() {
|
|
deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
|
|
return this;
|
|
};
|
|
|
|
// deferred.notifyWith = list.fireWith
|
|
// deferred.resolveWith = list.fireWith
|
|
// deferred.rejectWith = list.fireWith
|
|
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( singleValue ) {
|
|
var
|
|
|
|
// count of uncompleted subordinates
|
|
remaining = arguments.length,
|
|
|
|
// count of unprocessed arguments
|
|
i = remaining,
|
|
|
|
// subordinate fulfillment data
|
|
resolveContexts = Array( i ),
|
|
resolveValues = slice.call( arguments ),
|
|
|
|
// the master Deferred
|
|
master = jQuery.Deferred(),
|
|
|
|
// subordinate callback factory
|
|
updateFunc = function( i ) {
|
|
return function( value ) {
|
|
resolveContexts[ i ] = this;
|
|
resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
|
|
if ( !( --remaining ) ) {
|
|
master.resolveWith( resolveContexts, resolveValues );
|
|
}
|
|
};
|
|
};
|
|
|
|
// Single- and empty arguments are adopted like Promise.resolve
|
|
if ( remaining <= 1 ) {
|
|
adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
|
|
!remaining );
|
|
|
|
// Use .then() to unwrap secondary thenables (cf. gh-3000)
|
|
if ( master.state() === "pending" ||
|
|
jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
|
|
|
|
return master.then();
|
|
}
|
|
}
|
|
|
|
// Multiple arguments are aggregated like Promise.all array elements
|
|
while ( i-- ) {
|
|
adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
|
|
}
|
|
|
|
return master.promise();
|
|
}
|
|
} );
|
|
|
|
|
|
// These usually indicate a programmer mistake during development,
|
|
// warn about them ASAP rather than swallowing them by default.
|
|
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
|
|
|
|
jQuery.Deferred.exceptionHook = function( error, stack ) {
|
|
|
|
// Support: IE 8 - 9 only
|
|
// Console exists when dev tools are open, which can happen at any time
|
|
if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
|
|
window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
jQuery.readyException = function( error ) {
|
|
window.setTimeout( function() {
|
|
throw error;
|
|
} );
|
|
};
|
|
|
|
|
|
|
|
|
|
// The deferred used on DOM ready
|
|
var readyList = jQuery.Deferred();
|
|
|
|
jQuery.fn.ready = function( fn ) {
|
|
|
|
readyList
|
|
.then( fn )
|
|
|
|
// Wrap jQuery.readyException in a function so that the lookup
|
|
// happens at the time of error handling instead of callback
|
|
// registration.
|
|
.catch( function( error ) {
|
|
jQuery.readyException( error );
|
|
} );
|
|
|
|
return this;
|
|
};
|
|
|
|
jQuery.extend( {
|
|
|
|
// 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,
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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 ] );
|
|
}
|
|
} );
|
|
|
|
jQuery.ready.then = readyList.then;
|
|
|
|
// The ready event handler and self cleanup method
|
|
function completed() {
|
|
document.removeEventListener( "DOMContentLoaded", completed );
|
|
window.removeEventListener( "load", completed );
|
|
jQuery.ready();
|
|
}
|
|
|
|
// Catch cases where $(document).ready() is called
|
|
// after the browser event has already occurred.
|
|
// Support: IE <=9 - 10 only
|
|
// Older IE sometimes signals "interactive" too soon
|
|
if ( document.readyState === "complete" ||
|
|
( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
|
|
|
|
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
|
window.setTimeout( jQuery.ready );
|
|
|
|
} else {
|
|
|
|
// Use the handy event callback
|
|
document.addEventListener( "DOMContentLoaded", completed );
|
|
|
|
// A fallback to window.onload, that will always work
|
|
window.addEventListener( "load", completed );
|
|
}
|
|
|
|
|
|
|
|
|
|
// Multifunctional method to get and set values of a collection
|
|
// The value/s can optionally be executed if it's a function
|
|
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
|
|
var i = 0,
|
|
len = elems.length,
|
|
bulk = key == null;
|
|
|
|
// Sets many values
|
|
if ( jQuery.type( key ) === "object" ) {
|
|
chainable = true;
|
|
for ( i in key ) {
|
|
access( elems, fn, i, key[ i ], true, emptyGet, raw );
|
|
}
|
|
|
|
// Sets one value
|
|
} else if ( value !== undefined ) {
|
|
chainable = true;
|
|
|
|
if ( !jQuery.isFunction( value ) ) {
|
|
raw = true;
|
|
}
|
|
|
|
if ( bulk ) {
|
|
|
|
// Bulk operations run against the entire set
|
|
if ( raw ) {
|
|
fn.call( elems, value );
|
|
fn = null;
|
|
|
|
// ...except when executing function values
|
|
} else {
|
|
bulk = fn;
|
|
fn = function( elem, key, value ) {
|
|
return bulk.call( jQuery( elem ), value );
|
|
};
|
|
}
|
|
}
|
|
|
|
if ( fn ) {
|
|
for ( ; i < len; i++ ) {
|
|
fn(
|
|
elems[ i ], key, raw ?
|
|
value :
|
|
value.call( elems[ i ], i, fn( elems[ i ], key ) )
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( chainable ) {
|
|
return elems;
|
|
}
|
|
|
|
// Gets
|
|
if ( bulk ) {
|
|
return fn.call( elems );
|
|
}
|
|
|
|
return len ? fn( elems[ 0 ], key ) : emptyGet;
|
|
};
|
|
var acceptData = function( owner ) {
|
|
|
|
// Accepts only:
|
|
// - Node
|
|
// - Node.ELEMENT_NODE
|
|
// - Node.DOCUMENT_NODE
|
|
// - Object
|
|
// - Any
|
|
return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
|
|
};
|
|
|
|
|
|
|
|
|
|
function Data() {
|
|
this.expando = jQuery.expando + Data.uid++;
|
|
}
|
|
|
|
Data.uid = 1;
|
|
|
|
Data.prototype = {
|
|
|
|
cache: function( owner ) {
|
|
|
|
// Check if the owner object already has a cache
|
|
var value = owner[ this.expando ];
|
|
|
|
// If not, create one
|
|
if ( !value ) {
|
|
value = {};
|
|
|
|
// We can accept data for non-element nodes in modern browsers,
|
|
// but we should not, see #8335.
|
|
// Always return an empty object.
|
|
if ( acceptData( owner ) ) {
|
|
|
|
// If it is a node unlikely to be stringify-ed or looped over
|
|
// use plain assignment
|
|
if ( owner.nodeType ) {
|
|
owner[ this.expando ] = value;
|
|
|
|
// Otherwise secure it in a non-enumerable property
|
|
// configurable must be true to allow the property to be
|
|
// deleted when data is removed
|
|
} else {
|
|
Object.defineProperty( owner, this.expando, {
|
|
value: value,
|
|
configurable: true
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
|
|
return value;
|
|
},
|
|
set: function( owner, data, value ) {
|
|
var prop,
|
|
cache = this.cache( owner );
|
|
|
|
// Handle: [ owner, key, value ] args
|
|
// Always use camelCase key (gh-2257)
|
|
if ( typeof data === "string" ) {
|
|
cache[ jQuery.camelCase( data ) ] = value;
|
|
|
|
// Handle: [ owner, { properties } ] args
|
|
} else {
|
|
|
|
// Copy the properties one-by-one to the cache object
|
|
for ( prop in data ) {
|
|
cache[ jQuery.camelCase( prop ) ] = data[ prop ];
|
|
}
|
|
}
|
|
return cache;
|
|
},
|
|
get: function( owner, key ) {
|
|
return key === undefined ?
|
|
this.cache( owner ) :
|
|
|
|
// Always use camelCase key (gh-2257)
|
|
owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
|
|
},
|
|
access: function( owner, key, value ) {
|
|
|
|
// In cases where either:
|
|
//
|
|
// 1. No key was specified
|
|
// 2. A string key was specified, but no value provided
|
|
//
|
|
// Take the "read" path and allow the get method to determine
|
|
// which value to return, respectively either:
|
|
//
|
|
// 1. The entire cache object
|
|
// 2. The data stored at the key
|
|
//
|
|
if ( key === undefined ||
|
|
( ( key && typeof key === "string" ) && value === undefined ) ) {
|
|
|
|
return this.get( owner, key );
|
|
}
|
|
|
|
// When the key is not a string, or both a key and value
|
|
// are specified, set or extend (existing objects) with either:
|
|
//
|
|
// 1. An object of properties
|
|
// 2. A key and value
|
|
//
|
|
this.set( owner, key, value );
|
|
|
|
// Since the "set" path can have two possible entry points
|
|
// return the expected data based on which path was taken[*]
|
|
return value !== undefined ? value : key;
|
|
},
|
|
remove: function( owner, key ) {
|
|
var i,
|
|
cache = owner[ this.expando ];
|
|
|
|
if ( cache === undefined ) {
|
|
return;
|
|
}
|
|
|
|
if ( key !== undefined ) {
|
|
|
|
// Support array or space separated string of keys
|
|
if ( Array.isArray( key ) ) {
|
|
|
|
// If key is an array of keys...
|
|
// We always set camelCase keys, so remove that.
|
|
key = key.map( jQuery.camelCase );
|
|
} else {
|
|
key = jQuery.camelCase( key );
|
|
|
|
// If a key with the spaces exists, use it.
|
|
// Otherwise, create an array by matching non-whitespace
|
|
key = key in cache ?
|
|
[ key ] :
|
|
( key.match( rnothtmlwhite ) || [] );
|
|
}
|
|
|
|
i = key.length;
|
|
|
|
while ( i-- ) {
|
|
delete cache[ key[ i ] ];
|
|
}
|
|
}
|
|
|
|
// Remove the expando if there's no more data
|
|
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
|
|
|
|
// Support: Chrome <=35 - 45
|
|
// Webkit & Blink performance suffers when deleting properties
|
|
// from DOM nodes, so set to undefined instead
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
|
|
if ( owner.nodeType ) {
|
|
owner[ this.expando ] = undefined;
|
|
} else {
|
|
delete owner[ this.expando ];
|
|
}
|
|
}
|
|
},
|
|
hasData: function( owner ) {
|
|
var cache = owner[ this.expando ];
|
|
return cache !== undefined && !jQuery.isEmptyObject( cache );
|
|
}
|
|
};
|
|
var dataPriv = new Data();
|
|
|
|
var dataUser = new Data();
|
|
|
|
|
|
|
|
// Implementation Summary
|
|
//
|
|
// 1. Enforce API surface and semantic compatibility with 1.9.x branch
|
|
// 2. Improve the module's maintainability by reducing the storage
|
|
// paths to a single mechanism.
|
|
// 3. Use the same single mechanism to support "private" and "user" data.
|
|
// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
|
|
// 5. Avoid exposing implementation details on user objects (eg. expando properties)
|
|
// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
|
|
|
|
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
|
|
rmultiDash = /[A-Z]/g;
|
|
|
|
function getData( data ) {
|
|
if ( data === "true" ) {
|
|
return true;
|
|
}
|
|
|
|
if ( data === "false" ) {
|
|
return false;
|
|
}
|
|
|
|
if ( data === "null" ) {
|
|
return null;
|
|
}
|
|
|
|
// Only convert to a number if it doesn't change the string
|
|
if ( data === +data + "" ) {
|
|
return +data;
|
|
}
|
|
|
|
if ( rbrace.test( data ) ) {
|
|
return JSON.parse( data );
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
function dataAttr( elem, key, data ) {
|
|
var name;
|
|
|
|
// If nothing was found internally, try to fetch any
|
|
// data from the HTML5 data-* attribute
|
|
if ( data === undefined && elem.nodeType === 1 ) {
|
|
name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
|
|
data = elem.getAttribute( name );
|
|
|
|
if ( typeof data === "string" ) {
|
|
try {
|
|
data = getData( data );
|
|
} catch ( e ) {}
|
|
|
|
// Make sure we set the data so it isn't changed later
|
|
dataUser.set( elem, key, data );
|
|
} else {
|
|
data = undefined;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
jQuery.extend( {
|
|
hasData: function( elem ) {
|
|
return dataUser.hasData( elem ) || dataPriv.hasData( elem );
|
|
},
|
|
|
|
data: function( elem, name, data ) {
|
|
return dataUser.access( elem, name, data );
|
|
},
|
|
|
|
removeData: function( elem, name ) {
|
|
dataUser.remove( elem, name );
|
|
},
|
|
|
|
// TODO: Now that all calls to _data and _removeData have been replaced
|
|
// with direct calls to dataPriv methods, these can be deprecated.
|
|
_data: function( elem, name, data ) {
|
|
return dataPriv.access( elem, name, data );
|
|
},
|
|
|
|
_removeData: function( elem, name ) {
|
|
dataPriv.remove( elem, name );
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
data: function( key, value ) {
|
|
var i, name, data,
|
|
elem = this[ 0 ],
|
|
attrs = elem && elem.attributes;
|
|
|
|
// Gets all values
|
|
if ( key === undefined ) {
|
|
if ( this.length ) {
|
|
data = dataUser.get( elem );
|
|
|
|
if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
|
|
i = attrs.length;
|
|
while ( i-- ) {
|
|
|
|
// Support: IE 11 only
|
|
// The attrs elements can be null (#14894)
|
|
if ( attrs[ i ] ) {
|
|
name = attrs[ i ].name;
|
|
if ( name.indexOf( "data-" ) === 0 ) {
|
|
name = jQuery.camelCase( name.slice( 5 ) );
|
|
dataAttr( elem, name, data[ name ] );
|
|
}
|
|
}
|
|
}
|
|
dataPriv.set( elem, "hasDataAttrs", true );
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// Sets multiple values
|
|
if ( typeof key === "object" ) {
|
|
return this.each( function() {
|
|
dataUser.set( this, key );
|
|
} );
|
|
}
|
|
|
|
return access( this, function( value ) {
|
|
var data;
|
|
|
|
// The calling jQuery object (element matches) is not empty
|
|
// (and therefore has an element appears at this[ 0 ]) and the
|
|
// `value` parameter was not undefined. An empty jQuery object
|
|
// will result in `undefined` for elem = this[ 0 ] which will
|
|
// throw an exception if an attempt to read a data cache is made.
|
|
if ( elem && value === undefined ) {
|
|
|
|
// Attempt to get data from the cache
|
|
// The key will always be camelCased in Data
|
|
data = dataUser.get( elem, key );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// Attempt to "discover" the data in
|
|
// HTML5 custom data-* attrs
|
|
data = dataAttr( elem, key );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// We tried really hard, but the data doesn't exist.
|
|
return;
|
|
}
|
|
|
|
// Set the data...
|
|
this.each( function() {
|
|
|
|
// We always store the camelCased key
|
|
dataUser.set( this, key, value );
|
|
} );
|
|
}, null, value, arguments.length > 1, null, true );
|
|
},
|
|
|
|
removeData: function( key ) {
|
|
return this.each( function() {
|
|
dataUser.remove( this, key );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
|
|
jQuery.extend( {
|
|
queue: function( elem, type, data ) {
|
|
var queue;
|
|
|
|
if ( elem ) {
|
|
type = ( type || "fx" ) + "queue";
|
|
queue = dataPriv.get( elem, type );
|
|
|
|
// Speed up dequeue by getting out quickly if this is just a lookup
|
|
if ( data ) {
|
|
if ( !queue || Array.isArray( data ) ) {
|
|
queue = dataPriv.access( 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 public - generate a queueHooks object, or return the current one
|
|
_queueHooks: function( elem, type ) {
|
|
var key = type + "queueHooks";
|
|
return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
|
|
empty: jQuery.Callbacks( "once memory" ).add( function() {
|
|
dataPriv.remove( elem, [ type + "queue", key ] );
|
|
} )
|
|
} );
|
|
}
|
|
} );
|
|
|
|
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 );
|
|
} );
|
|
},
|
|
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 = dataPriv.get( elements[ i ], type + "queueHooks" );
|
|
if ( tmp && tmp.empty ) {
|
|
count++;
|
|
tmp.empty.add( resolve );
|
|
}
|
|
}
|
|
resolve();
|
|
return defer.promise( obj );
|
|
}
|
|
} );
|
|
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
|
|
|
|
var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
|
|
|
|
|
|
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
|
|
|
|
var isHiddenWithinTree = function( elem, el ) {
|
|
|
|
// isHiddenWithinTree might be called from jQuery#filter function;
|
|
// in that case, element will be second argument
|
|
elem = el || elem;
|
|
|
|
// Inline style trumps all
|
|
return elem.style.display === "none" ||
|
|
elem.style.display === "" &&
|
|
|
|
// Otherwise, check computed style
|
|
// Support: Firefox <=43 - 45
|
|
// Disconnected elements can have computed display: none, so first confirm that elem is
|
|
// in the document.
|
|
jQuery.contains( elem.ownerDocument, elem ) &&
|
|
|
|
jQuery.css( elem, "display" ) === "none";
|
|
};
|
|
|
|
var swap = function( elem, options, callback, args ) {
|
|
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.apply( elem, args || [] );
|
|
|
|
// Revert the old values
|
|
for ( name in options ) {
|
|
elem.style[ name ] = old[ name ];
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
|
|
|
|
|
|
function adjustCSS( elem, prop, valueParts, tween ) {
|
|
var adjusted,
|
|
scale = 1,
|
|
maxIterations = 20,
|
|
currentValue = tween ?
|
|
function() {
|
|
return tween.cur();
|
|
} :
|
|
function() {
|
|
return jQuery.css( elem, prop, "" );
|
|
},
|
|
initial = currentValue(),
|
|
unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
|
|
|
|
// Starting value computation is required for potential unit mismatches
|
|
initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
|
|
rcssNum.exec( jQuery.css( elem, prop ) );
|
|
|
|
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
|
|
|
|
// Trust units reported by jQuery.css
|
|
unit = unit || initialInUnit[ 3 ];
|
|
|
|
// Make sure we update the tween properties later on
|
|
valueParts = valueParts || [];
|
|
|
|
// Iteratively approximate from a nonzero starting point
|
|
initialInUnit = +initial || 1;
|
|
|
|
do {
|
|
|
|
// If previous iteration zeroed out, double until we get *something*.
|
|
// Use string for doubling so we don't accidentally see scale as unchanged below
|
|
scale = scale || ".5";
|
|
|
|
// Adjust and apply
|
|
initialInUnit = initialInUnit / scale;
|
|
jQuery.style( elem, prop, initialInUnit + unit );
|
|
|
|
// Update scale, tolerating zero or NaN from tween.cur()
|
|
// Break the loop if scale is unchanged or perfect, or if we've just had enough.
|
|
} while (
|
|
scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
|
|
);
|
|
}
|
|
|
|
if ( valueParts ) {
|
|
initialInUnit = +initialInUnit || +initial || 0;
|
|
|
|
// Apply relative offset (+=/-=) if specified
|
|
adjusted = valueParts[ 1 ] ?
|
|
initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
|
|
+valueParts[ 2 ];
|
|
if ( tween ) {
|
|
tween.unit = unit;
|
|
tween.start = initialInUnit;
|
|
tween.end = adjusted;
|
|
}
|
|
}
|
|
return adjusted;
|
|
}
|
|
|
|
|
|
var defaultDisplayMap = {};
|
|
|
|
function getDefaultDisplay( elem ) {
|
|
var temp,
|
|
doc = elem.ownerDocument,
|
|
nodeName = elem.nodeName,
|
|
display = defaultDisplayMap[ nodeName ];
|
|
|
|
if ( display ) {
|
|
return display;
|
|
}
|
|
|
|
temp = doc.body.appendChild( doc.createElement( nodeName ) );
|
|
display = jQuery.css( temp, "display" );
|
|
|
|
temp.parentNode.removeChild( temp );
|
|
|
|
if ( display === "none" ) {
|
|
display = "block";
|
|
}
|
|
defaultDisplayMap[ nodeName ] = display;
|
|
|
|
return display;
|
|
}
|
|
|
|
function showHide( elements, show ) {
|
|
var display, elem,
|
|
values = [],
|
|
index = 0,
|
|
length = elements.length;
|
|
|
|
// Determine new display value for elements that need to change
|
|
for ( ; index < length; index++ ) {
|
|
elem = elements[ index ];
|
|
if ( !elem.style ) {
|
|
continue;
|
|
}
|
|
|
|
display = elem.style.display;
|
|
if ( show ) {
|
|
|
|
// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
|
|
// check is required in this first loop unless we have a nonempty display value (either
|
|
// inline or about-to-be-restored)
|
|
if ( display === "none" ) {
|
|
values[ index ] = dataPriv.get( elem, "display" ) || null;
|
|
if ( !values[ index ] ) {
|
|
elem.style.display = "";
|
|
}
|
|
}
|
|
if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
|
|
values[ index ] = getDefaultDisplay( elem );
|
|
}
|
|
} else {
|
|
if ( display !== "none" ) {
|
|
values[ index ] = "none";
|
|
|
|
// Remember what we're overwriting
|
|
dataPriv.set( elem, "display", display );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the display of the elements in a second loop to avoid constant reflow
|
|
for ( index = 0; index < length; index++ ) {
|
|
if ( values[ index ] != null ) {
|
|
elements[ index ].style.display = values[ index ];
|
|
}
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
jQuery.fn.extend( {
|
|
show: function() {
|
|
return showHide( this, true );
|
|
},
|
|
hide: function() {
|
|
return showHide( this );
|
|
},
|
|
toggle: function( state ) {
|
|
if ( typeof state === "boolean" ) {
|
|
return state ? this.show() : this.hide();
|
|
}
|
|
|
|
return this.each( function() {
|
|
if ( isHiddenWithinTree( this ) ) {
|
|
jQuery( this ).show();
|
|
} else {
|
|
jQuery( this ).hide();
|
|
}
|
|
} );
|
|
}
|
|
} );
|
|
var rcheckableType = ( /^(?:checkbox|radio)$/i );
|
|
|
|
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
|
|
|
|
var rscriptType = ( /^$|\/(?:java|ecma)script/i );
|
|
|
|
|
|
|
|
// We have to close these tags to support XHTML (#13200)
|
|
var wrapMap = {
|
|
|
|
// Support: IE <=9 only
|
|
option: [ 1, "<select multiple='multiple'>", "</select>" ],
|
|
|
|
// XHTML parsers do not magically insert elements in the
|
|
// same way that tag soup parsers do. So we cannot shorten
|
|
// this by omitting <tbody> or other required elements.
|
|
thead: [ 1, "<table>", "</table>" ],
|
|
col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
|
|
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
|
|
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
|
|
|
|
_default: [ 0, "", "" ]
|
|
};
|
|
|
|
// Support: IE <=9 only
|
|
wrapMap.optgroup = wrapMap.option;
|
|
|
|
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
|
|
wrapMap.th = wrapMap.td;
|
|
|
|
|
|
function getAll( context, tag ) {
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
|
|
var ret;
|
|
|
|
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
|
ret = context.getElementsByTagName( tag || "*" );
|
|
|
|
} else if ( typeof context.querySelectorAll !== "undefined" ) {
|
|
ret = context.querySelectorAll( tag || "*" );
|
|
|
|
} else {
|
|
ret = [];
|
|
}
|
|
|
|
if ( tag === undefined || tag && nodeName( context, tag ) ) {
|
|
return jQuery.merge( [ context ], ret );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
// Mark scripts as having already been evaluated
|
|
function setGlobalEval( elems, refElements ) {
|
|
var i = 0,
|
|
l = elems.length;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
dataPriv.set(
|
|
elems[ i ],
|
|
"globalEval",
|
|
!refElements || dataPriv.get( refElements[ i ], "globalEval" )
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
var rhtml = /<|&#?\w+;/;
|
|
|
|
function buildFragment( elems, context, scripts, selection, ignored ) {
|
|
var elem, tmp, tag, wrap, contains, j,
|
|
fragment = context.createDocumentFragment(),
|
|
nodes = [],
|
|
i = 0,
|
|
l = elems.length;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
elem = elems[ i ];
|
|
|
|
if ( elem || elem === 0 ) {
|
|
|
|
// Add nodes directly
|
|
if ( jQuery.type( elem ) === "object" ) {
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
|
|
|
|
// Convert non-html into a text node
|
|
} else if ( !rhtml.test( elem ) ) {
|
|
nodes.push( context.createTextNode( elem ) );
|
|
|
|
// Convert html into DOM nodes
|
|
} else {
|
|
tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
|
|
|
|
// Deserialize a standard representation
|
|
tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
|
|
wrap = wrapMap[ tag ] || wrapMap._default;
|
|
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
|
|
|
|
// Descend through wrappers to the right content
|
|
j = wrap[ 0 ];
|
|
while ( j-- ) {
|
|
tmp = tmp.lastChild;
|
|
}
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
jQuery.merge( nodes, tmp.childNodes );
|
|
|
|
// Remember the top-level container
|
|
tmp = fragment.firstChild;
|
|
|
|
// Ensure the created nodes are orphaned (#12392)
|
|
tmp.textContent = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove wrapper from fragment
|
|
fragment.textContent = "";
|
|
|
|
i = 0;
|
|
while ( ( elem = nodes[ i++ ] ) ) {
|
|
|
|
// Skip elements already in the context collection (trac-4087)
|
|
if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
|
|
if ( ignored ) {
|
|
ignored.push( elem );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
contains = jQuery.contains( elem.ownerDocument, elem );
|
|
|
|
// Append to fragment
|
|
tmp = getAll( fragment.appendChild( elem ), "script" );
|
|
|
|
// Preserve script evaluation history
|
|
if ( contains ) {
|
|
setGlobalEval( tmp );
|
|
}
|
|
|
|
// Capture executables
|
|
if ( scripts ) {
|
|
j = 0;
|
|
while ( ( elem = tmp[ j++ ] ) ) {
|
|
if ( rscriptType.test( elem.type || "" ) ) {
|
|
scripts.push( elem );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fragment;
|
|
}
|
|
|
|
|
|
( function() {
|
|
var fragment = document.createDocumentFragment(),
|
|
div = fragment.appendChild( document.createElement( "div" ) ),
|
|
input = document.createElement( "input" );
|
|
|
|
// Support: Android 4.0 - 4.3 only
|
|
// Check state lost if the name is set (#11217)
|
|
// Support: Windows Web Apps (WWA)
|
|
// `name` and `type` must use .setAttribute for WWA (#14901)
|
|
input.setAttribute( "type", "radio" );
|
|
input.setAttribute( "checked", "checked" );
|
|
input.setAttribute( "name", "t" );
|
|
|
|
div.appendChild( input );
|
|
|
|
// Support: Android <=4.1 only
|
|
// Older WebKit doesn't clone checked state correctly in fragments
|
|
support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
|
|
|
// Support: IE <=11 only
|
|
// Make sure textarea (and checkbox) defaultValue is properly cloned
|
|
div.innerHTML = "<textarea>x</textarea>";
|
|
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
|
|
} )();
|
|
var documentElement = document.documentElement;
|
|
|
|
|
|
|
|
var
|
|
rkeyEvent = /^key/,
|
|
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
|
|
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
|
|
|
|
function returnTrue() {
|
|
return true;
|
|
}
|
|
|
|
function returnFalse() {
|
|
return false;
|
|
}
|
|
|
|
// Support: IE <=9 only
|
|
// See #13393 for more info
|
|
function safeActiveElement() {
|
|
try {
|
|
return document.activeElement;
|
|
} catch ( err ) { }
|
|
}
|
|
|
|
function on( elem, types, selector, data, fn, one ) {
|
|
var origFn, type;
|
|
|
|
// Types can be a map of types/handlers
|
|
if ( typeof types === "object" ) {
|
|
|
|
// ( types-Object, selector, data )
|
|
if ( typeof selector !== "string" ) {
|
|
|
|
// ( types-Object, data )
|
|
data = data || selector;
|
|
selector = undefined;
|
|
}
|
|
for ( type in types ) {
|
|
on( elem, type, selector, data, types[ type ], one );
|
|
}
|
|
return elem;
|
|
}
|
|
|
|
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 elem;
|
|
}
|
|
|
|
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 elem.each( function() {
|
|
jQuery.event.add( this, types, fn, data, selector );
|
|
} );
|
|
}
|
|
|
|
/*
|
|
* Helper functions for managing events -- not part of the public interface.
|
|
* Props to Dean Edwards' addEvent library for many of the ideas.
|
|
*/
|
|
jQuery.event = {
|
|
|
|
global: {},
|
|
|
|
add: function( elem, types, handler, data, selector ) {
|
|
|
|
var handleObjIn, eventHandle, tmp,
|
|
events, t, handleObj,
|
|
special, handlers, type, namespaces, origType,
|
|
elemData = dataPriv.get( elem );
|
|
|
|
// Don't attach events to noData or text/comment nodes (but allow plain objects)
|
|
if ( !elemData ) {
|
|
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;
|
|
}
|
|
|
|
// Ensure that invalid selectors throw exceptions at attach time
|
|
// Evaluate against documentElement in case elem is a non-element node (e.g., document)
|
|
if ( selector ) {
|
|
jQuery.find.matchesSelector( documentElement, 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
|
|
if ( !( events = elemData.events ) ) {
|
|
events = elemData.events = {};
|
|
}
|
|
if ( !( eventHandle = elemData.handle ) ) {
|
|
eventHandle = elemData.handle = 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" && jQuery.event.triggered !== e.type ?
|
|
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
|
|
};
|
|
}
|
|
|
|
// Handle multiple events separated by a space
|
|
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
|
|
t = types.length;
|
|
while ( t-- ) {
|
|
tmp = rtypenamespace.exec( types[ t ] ) || [];
|
|
type = origType = tmp[ 1 ];
|
|
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
|
|
|
|
// There *must* be a type, no attaching namespace-only handlers
|
|
if ( !type ) {
|
|
continue;
|
|
}
|
|
|
|
// 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: origType,
|
|
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
|
|
if ( !( handlers = events[ type ] ) ) {
|
|
handlers = events[ type ] = [];
|
|
handlers.delegateCount = 0;
|
|
|
|
// Only use addEventListener if the special events handler returns false
|
|
if ( !special.setup ||
|
|
special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
|
|
|
|
if ( elem.addEventListener ) {
|
|
elem.addEventListener( 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;
|
|
}
|
|
|
|
},
|
|
|
|
// Detach an event or set of events from an element
|
|
remove: function( elem, types, handler, selector, mappedTypes ) {
|
|
|
|
var j, origCount, tmp,
|
|
events, t, handleObj,
|
|
special, handlers, type, namespaces, origType,
|
|
elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
|
|
|
|
if ( !elemData || !( events = elemData.events ) ) {
|
|
return;
|
|
}
|
|
|
|
// Once for each type.namespace in types; type may be omitted
|
|
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
|
|
t = types.length;
|
|
while ( t-- ) {
|
|
tmp = rtypenamespace.exec( types[ t ] ) || [];
|
|
type = origType = tmp[ 1 ];
|
|
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
|
|
|
|
// 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;
|
|
handlers = events[ type ] || [];
|
|
tmp = tmp[ 2 ] &&
|
|
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
|
|
|
|
// Remove matching events
|
|
origCount = j = handlers.length;
|
|
while ( j-- ) {
|
|
handleObj = handlers[ j ];
|
|
|
|
if ( ( mappedTypes || origType === handleObj.origType ) &&
|
|
( !handler || handler.guid === handleObj.guid ) &&
|
|
( !tmp || tmp.test( handleObj.namespace ) ) &&
|
|
( !selector || selector === handleObj.selector ||
|
|
selector === "**" && handleObj.selector ) ) {
|
|
handlers.splice( j, 1 );
|
|
|
|
if ( handleObj.selector ) {
|
|
handlers.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 ( origCount && !handlers.length ) {
|
|
if ( !special.teardown ||
|
|
special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
|
|
|
|
jQuery.removeEvent( elem, type, elemData.handle );
|
|
}
|
|
|
|
delete events[ type ];
|
|
}
|
|
}
|
|
|
|
// Remove data and the expando if it's no longer used
|
|
if ( jQuery.isEmptyObject( events ) ) {
|
|
dataPriv.remove( elem, "handle events" );
|
|
}
|
|
},
|
|
|
|
dispatch: function( nativeEvent ) {
|
|
|
|
// Make a writable jQuery.Event from the native event object
|
|
var event = jQuery.event.fix( nativeEvent );
|
|
|
|
var i, j, ret, matched, handleObj, handlerQueue,
|
|
args = new Array( arguments.length ),
|
|
handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
|
|
special = jQuery.event.special[ event.type ] || {};
|
|
|
|
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
|
args[ 0 ] = event;
|
|
|
|
for ( i = 1; i < arguments.length; i++ ) {
|
|
args[ i ] = arguments[ i ];
|
|
}
|
|
|
|
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
|
|
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
|
|
|
|
// Run delegates first; they may want to stop propagation beneath us
|
|
i = 0;
|
|
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
|
|
event.currentTarget = matched.elem;
|
|
|
|
j = 0;
|
|
while ( ( handleObj = matched.handlers[ j++ ] ) &&
|
|
!event.isImmediatePropagationStopped() ) {
|
|
|
|
// Triggered event must either 1) have no namespace, or 2) have namespace(s)
|
|
// a subset or equal to those in the bound event (both can have no namespace).
|
|
if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
|
|
|
|
event.handleObj = handleObj;
|
|
event.data = handleObj.data;
|
|
|
|
ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
|
|
handleObj.handler ).apply( matched.elem, args );
|
|
|
|
if ( ret !== undefined ) {
|
|
if ( ( event.result = 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;
|
|
},
|
|
|
|
handlers: function( event, handlers ) {
|
|
var i, handleObj, sel, matchedHandlers, matchedSelectors,
|
|
handlerQueue = [],
|
|
delegateCount = handlers.delegateCount,
|
|
cur = event.target;
|
|
|
|
// Find delegate handlers
|
|
if ( delegateCount &&
|
|
|
|
// Support: IE <=9
|
|
// Black-hole SVG <use> instance trees (trac-13180)
|
|
cur.nodeType &&
|
|
|
|
// Support: Firefox <=42
|
|
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
|
|
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
|
|
// Support: IE 11 only
|
|
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
|
|
!( event.type === "click" && event.button >= 1 ) ) {
|
|
|
|
for ( ; cur !== this; cur = cur.parentNode || this ) {
|
|
|
|
// Don't check non-elements (#13208)
|
|
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
|
|
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
|
|
matchedHandlers = [];
|
|
matchedSelectors = {};
|
|
for ( i = 0; i < delegateCount; i++ ) {
|
|
handleObj = handlers[ i ];
|
|
|
|
// Don't conflict with Object.prototype properties (#13203)
|
|
sel = handleObj.selector + " ";
|
|
|
|
if ( matchedSelectors[ sel ] === undefined ) {
|
|
matchedSelectors[ sel ] = handleObj.needsContext ?
|
|
jQuery( sel, this ).index( cur ) > -1 :
|
|
jQuery.find( sel, this, null, [ cur ] ).length;
|
|
}
|
|
if ( matchedSelectors[ sel ] ) {
|
|
matchedHandlers.push( handleObj );
|
|
}
|
|
}
|
|
if ( matchedHandlers.length ) {
|
|
handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the remaining (directly-bound) handlers
|
|
cur = this;
|
|
if ( delegateCount < handlers.length ) {
|
|
handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
|
|
}
|
|
|
|
return handlerQueue;
|
|
},
|
|
|
|
addProp: function( name, hook ) {
|
|
Object.defineProperty( jQuery.Event.prototype, name, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
|
|
get: jQuery.isFunction( hook ) ?
|
|
function() {
|
|
if ( this.originalEvent ) {
|
|
return hook( this.originalEvent );
|
|
}
|
|
} :
|
|
function() {
|
|
if ( this.originalEvent ) {
|
|
return this.originalEvent[ name ];
|
|
}
|
|
},
|
|
|
|
set: function( value ) {
|
|
Object.defineProperty( this, name, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: value
|
|
} );
|
|
}
|
|
} );
|
|
},
|
|
|
|
fix: function( originalEvent ) {
|
|
return originalEvent[ jQuery.expando ] ?
|
|
originalEvent :
|
|
new jQuery.Event( originalEvent );
|
|
},
|
|
|
|
special: {
|
|
load: {
|
|
|
|
// Prevent triggered image.load events from bubbling to window.load
|
|
noBubble: true
|
|
},
|
|
focus: {
|
|
|
|
// Fire native event if possible so blur/focus sequence is correct
|
|
trigger: function() {
|
|
if ( this !== safeActiveElement() && this.focus ) {
|
|
this.focus();
|
|
return false;
|
|
}
|
|
},
|
|
delegateType: "focusin"
|
|
},
|
|
blur: {
|
|
trigger: function() {
|
|
if ( this === safeActiveElement() && this.blur ) {
|
|
this.blur();
|
|
return false;
|
|
}
|
|
},
|
|
delegateType: "focusout"
|
|
},
|
|
click: {
|
|
|
|
// For checkable types, fire native event so checked state will be right
|
|
trigger: function() {
|
|
if ( rcheckableType.test( this.type ) &&
|
|
this.click && nodeName( this, "input" ) ) {
|
|
|
|
this.click();
|
|
return false;
|
|
}
|
|
},
|
|
|
|
// For cross-browser consistency, don't fire native .click() on links
|
|
_default: function( event ) {
|
|
return nodeName( event.target, "a" );
|
|
}
|
|
},
|
|
|
|
beforeunload: {
|
|
postDispatch: function( event ) {
|
|
|
|
// Support: Firefox 20+
|
|
// Firefox doesn't alert if the returnValue field is not set.
|
|
if ( event.result !== undefined && event.originalEvent ) {
|
|
event.originalEvent.returnValue = event.result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
jQuery.removeEvent = function( elem, type, handle ) {
|
|
|
|
// This "if" is needed for plain objects
|
|
if ( elem.removeEventListener ) {
|
|
elem.removeEventListener( type, 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.defaultPrevented === undefined &&
|
|
|
|
// Support: Android <=2.3 only
|
|
src.returnValue === false ?
|
|
returnTrue :
|
|
returnFalse;
|
|
|
|
// Create target properties
|
|
// Support: Safari <=6 - 7 only
|
|
// Target should not be a text node (#504, #13143)
|
|
this.target = ( src.target && src.target.nodeType === 3 ) ?
|
|
src.target.parentNode :
|
|
src.target;
|
|
|
|
this.currentTarget = src.currentTarget;
|
|
this.relatedTarget = src.relatedTarget;
|
|
|
|
// 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;
|
|
};
|
|
|
|
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
|
|
// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
|
jQuery.Event.prototype = {
|
|
constructor: jQuery.Event,
|
|
isDefaultPrevented: returnFalse,
|
|
isPropagationStopped: returnFalse,
|
|
isImmediatePropagationStopped: returnFalse,
|
|
isSimulated: false,
|
|
|
|
preventDefault: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isDefaultPrevented = returnTrue;
|
|
|
|
if ( e && !this.isSimulated ) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
stopPropagation: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isPropagationStopped = returnTrue;
|
|
|
|
if ( e && !this.isSimulated ) {
|
|
e.stopPropagation();
|
|
}
|
|
},
|
|
stopImmediatePropagation: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isImmediatePropagationStopped = returnTrue;
|
|
|
|
if ( e && !this.isSimulated ) {
|
|
e.stopImmediatePropagation();
|
|
}
|
|
|
|
this.stopPropagation();
|
|
}
|
|
};
|
|
|
|
// Includes all common event props including KeyEvent and MouseEvent specific props
|
|
jQuery.each( {
|
|
altKey: true,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
changedTouches: true,
|
|
ctrlKey: true,
|
|
detail: true,
|
|
eventPhase: true,
|
|
metaKey: true,
|
|
pageX: true,
|
|
pageY: true,
|
|
shiftKey: true,
|
|
view: true,
|
|
"char": true,
|
|
charCode: true,
|
|
key: true,
|
|
keyCode: true,
|
|
button: true,
|
|
buttons: true,
|
|
clientX: true,
|
|
clientY: true,
|
|
offsetX: true,
|
|
offsetY: true,
|
|
pointerId: true,
|
|
pointerType: true,
|
|
screenX: true,
|
|
screenY: true,
|
|
targetTouches: true,
|
|
toElement: true,
|
|
touches: true,
|
|
|
|
which: function( event ) {
|
|
var button = event.button;
|
|
|
|
// Add which for key events
|
|
if ( event.which == null && rkeyEvent.test( event.type ) ) {
|
|
return event.charCode != null ? event.charCode : event.keyCode;
|
|
}
|
|
|
|
// Add which for click: 1 === left; 2 === middle; 3 === right
|
|
if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
|
|
if ( button & 1 ) {
|
|
return 1;
|
|
}
|
|
|
|
if ( button & 2 ) {
|
|
return 3;
|
|
}
|
|
|
|
if ( button & 4 ) {
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return event.which;
|
|
}
|
|
}, jQuery.event.addProp );
|
|
|
|
// Create mouseenter/leave events using mouseover/out and event-time checks
|
|
// so that event delegation works in jQuery.
|
|
// Do the same for pointerenter/pointerleave and pointerover/pointerout
|
|
//
|
|
// Support: Safari 7 only
|
|
// Safari sends mouseenter too often; see:
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
|
|
// for the description of the bug (it existed in older Chrome versions as well).
|
|
jQuery.each( {
|
|
mouseenter: "mouseover",
|
|
mouseleave: "mouseout",
|
|
pointerenter: "pointerover",
|
|
pointerleave: "pointerout"
|
|
}, function( orig, fix ) {
|
|
jQuery.event.special[ orig ] = {
|
|
delegateType: fix,
|
|
bindType: fix,
|
|
|
|
handle: function( event ) {
|
|
var ret,
|
|
target = this,
|
|
related = event.relatedTarget,
|
|
handleObj = event.handleObj;
|
|
|
|
// For mouseenter/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;
|
|
}
|
|
};
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
on: function( types, selector, data, fn ) {
|
|
return on( this, types, selector, data, fn );
|
|
},
|
|
one: function( types, selector, data, fn ) {
|
|
return on( this, 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 );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
|
|
var
|
|
|
|
/* eslint-disable max-len */
|
|
|
|
// See https://github.com/eslint/eslint/issues/3229
|
|
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
|
|
|
|
/* eslint-enable */
|
|
|
|
// Support: IE <=10 - 11, Edge 12 - 13
|
|
// In IE/Edge using regex groups here causes severe slowdowns.
|
|
// See https://connect.microsoft.com/IE/feedback/details/1736512/
|
|
rnoInnerhtml = /<script|<style|<link/i,
|
|
|
|
// checked="checked" or checked
|
|
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
|
rscriptTypeMasked = /^true\/(.*)/,
|
|
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
|
|
|
|
// Prefer a tbody over its parent table for containing new rows
|
|
function manipulationTarget( elem, content ) {
|
|
if ( nodeName( elem, "table" ) &&
|
|
nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
|
|
|
|
return jQuery( ">tbody", elem )[ 0 ] || elem;
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
// Replace/restore the type attribute of script elements for safe DOM manipulation
|
|
function disableScript( elem ) {
|
|
elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
|
|
return elem;
|
|
}
|
|
function restoreScript( elem ) {
|
|
var match = rscriptTypeMasked.exec( elem.type );
|
|
|
|
if ( match ) {
|
|
elem.type = match[ 1 ];
|
|
} else {
|
|
elem.removeAttribute( "type" );
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
function cloneCopyEvent( src, dest ) {
|
|
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
|
|
|
|
if ( dest.nodeType !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
// 1. Copy private data: events, handlers, etc.
|
|
if ( dataPriv.hasData( src ) ) {
|
|
pdataOld = dataPriv.access( src );
|
|
pdataCur = dataPriv.set( dest, pdataOld );
|
|
events = pdataOld.events;
|
|
|
|
if ( events ) {
|
|
delete pdataCur.handle;
|
|
pdataCur.events = {};
|
|
|
|
for ( type in events ) {
|
|
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
|
jQuery.event.add( dest, type, events[ type ][ i ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Copy user data
|
|
if ( dataUser.hasData( src ) ) {
|
|
udataOld = dataUser.access( src );
|
|
udataCur = jQuery.extend( {}, udataOld );
|
|
|
|
dataUser.set( dest, udataCur );
|
|
}
|
|
}
|
|
|
|
// Fix IE bugs, see support tests
|
|
function fixInput( src, dest ) {
|
|
var nodeName = dest.nodeName.toLowerCase();
|
|
|
|
// Fails to persist the checked state of a cloned checkbox or radio button.
|
|
if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
|
|
dest.checked = src.checked;
|
|
|
|
// Fails to return the selected option to the default selected state when cloning options
|
|
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
|
dest.defaultValue = src.defaultValue;
|
|
}
|
|
}
|
|
|
|
function domManip( collection, args, callback, ignored ) {
|
|
|
|
// Flatten any nested arrays
|
|
args = concat.apply( [], args );
|
|
|
|
var fragment, first, scripts, hasScripts, node, doc,
|
|
i = 0,
|
|
l = collection.length,
|
|
iNoClone = l - 1,
|
|
value = args[ 0 ],
|
|
isFunction = jQuery.isFunction( value );
|
|
|
|
// We can't cloneNode fragments that contain checked, in WebKit
|
|
if ( isFunction ||
|
|
( l > 1 && typeof value === "string" &&
|
|
!support.checkClone && rchecked.test( value ) ) ) {
|
|
return collection.each( function( index ) {
|
|
var self = collection.eq( index );
|
|
if ( isFunction ) {
|
|
args[ 0 ] = value.call( this, index, self.html() );
|
|
}
|
|
domManip( self, args, callback, ignored );
|
|
} );
|
|
}
|
|
|
|
if ( l ) {
|
|
fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
|
|
first = fragment.firstChild;
|
|
|
|
if ( fragment.childNodes.length === 1 ) {
|
|
fragment = first;
|
|
}
|
|
|
|
// Require either new content or an interest in ignored elements to invoke the callback
|
|
if ( first || ignored ) {
|
|
scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
|
|
hasScripts = scripts.length;
|
|
|
|
// Use the original fragment for the last item
|
|
// instead of the first because it can end up
|
|
// being emptied incorrectly in certain situations (#8070).
|
|
for ( ; i < l; i++ ) {
|
|
node = fragment;
|
|
|
|
if ( i !== iNoClone ) {
|
|
node = jQuery.clone( node, true, true );
|
|
|
|
// Keep references to cloned scripts for later restoration
|
|
if ( hasScripts ) {
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
jQuery.merge( scripts, getAll( node, "script" ) );
|
|
}
|
|
}
|
|
|
|
callback.call( collection[ i ], node, i );
|
|
}
|
|
|
|
if ( hasScripts ) {
|
|
doc = scripts[ scripts.length - 1 ].ownerDocument;
|
|
|
|
// Reenable scripts
|
|
jQuery.map( scripts, restoreScript );
|
|
|
|
// Evaluate executable scripts on first document insertion
|
|
for ( i = 0; i < hasScripts; i++ ) {
|
|
node = scripts[ i ];
|
|
if ( rscriptType.test( node.type || "" ) &&
|
|
!dataPriv.access( node, "globalEval" ) &&
|
|
jQuery.contains( doc, node ) ) {
|
|
|
|
if ( node.src ) {
|
|
|
|
// Optional AJAX dependency, but won't run scripts if not present
|
|
if ( jQuery._evalUrl ) {
|
|
jQuery._evalUrl( node.src );
|
|
}
|
|
} else {
|
|
DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return collection;
|
|
}
|
|
|
|
function remove( elem, selector, keepData ) {
|
|
var node,
|
|
nodes = selector ? jQuery.filter( selector, elem ) : elem,
|
|
i = 0;
|
|
|
|
for ( ; ( node = nodes[ i ] ) != null; i++ ) {
|
|
if ( !keepData && node.nodeType === 1 ) {
|
|
jQuery.cleanData( getAll( node ) );
|
|
}
|
|
|
|
if ( node.parentNode ) {
|
|
if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
|
|
setGlobalEval( getAll( node, "script" ) );
|
|
}
|
|
node.parentNode.removeChild( node );
|
|
}
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
jQuery.extend( {
|
|
htmlPrefilter: function( html ) {
|
|
return html.replace( rxhtmlTag, "<$1></$2>" );
|
|
},
|
|
|
|
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
|
|
var i, l, srcElements, destElements,
|
|
clone = elem.cloneNode( true ),
|
|
inPage = jQuery.contains( elem.ownerDocument, elem );
|
|
|
|
// Fix IE cloning issues
|
|
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
|
|
!jQuery.isXMLDoc( elem ) ) {
|
|
|
|
// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
|
|
destElements = getAll( clone );
|
|
srcElements = getAll( elem );
|
|
|
|
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
|
fixInput( srcElements[ i ], destElements[ i ] );
|
|
}
|
|
}
|
|
|
|
// Copy the events from the original to the clone
|
|
if ( dataAndEvents ) {
|
|
if ( deepDataAndEvents ) {
|
|
srcElements = srcElements || getAll( elem );
|
|
destElements = destElements || getAll( clone );
|
|
|
|
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
|
cloneCopyEvent( srcElements[ i ], destElements[ i ] );
|
|
}
|
|
} else {
|
|
cloneCopyEvent( elem, clone );
|
|
}
|
|
}
|
|
|
|
// Preserve script evaluation history
|
|
destElements = getAll( clone, "script" );
|
|
if ( destElements.length > 0 ) {
|
|
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
|
|
}
|
|
|
|
// Return the cloned set
|
|
return clone;
|
|
},
|
|
|
|
cleanData: function( elems ) {
|
|
var data, elem, type,
|
|
special = jQuery.event.special,
|
|
i = 0;
|
|
|
|
for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
|
|
if ( acceptData( elem ) ) {
|
|
if ( ( data = elem[ dataPriv.expando ] ) ) {
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Support: Chrome <=35 - 45+
|
|
// Assign undefined instead of using delete, see Data#remove
|
|
elem[ dataPriv.expando ] = undefined;
|
|
}
|
|
if ( elem[ dataUser.expando ] ) {
|
|
|
|
// Support: Chrome <=35 - 45+
|
|
// Assign undefined instead of using delete, see Data#remove
|
|
elem[ dataUser.expando ] = undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
detach: function( selector ) {
|
|
return remove( this, selector, true );
|
|
},
|
|
|
|
remove: function( selector ) {
|
|
return remove( this, selector );
|
|
},
|
|
|
|
text: function( value ) {
|
|
return access( this, function( value ) {
|
|
return value === undefined ?
|
|
jQuery.text( this ) :
|
|
this.empty().each( function() {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
this.textContent = value;
|
|
}
|
|
} );
|
|
}, null, value, arguments.length );
|
|
},
|
|
|
|
append: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
var target = manipulationTarget( this, elem );
|
|
target.appendChild( elem );
|
|
}
|
|
} );
|
|
},
|
|
|
|
prepend: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
var target = manipulationTarget( this, elem );
|
|
target.insertBefore( elem, target.firstChild );
|
|
}
|
|
} );
|
|
},
|
|
|
|
before: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.parentNode ) {
|
|
this.parentNode.insertBefore( elem, this );
|
|
}
|
|
} );
|
|
},
|
|
|
|
after: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.parentNode ) {
|
|
this.parentNode.insertBefore( elem, this.nextSibling );
|
|
}
|
|
} );
|
|
},
|
|
|
|
empty: function() {
|
|
var elem,
|
|
i = 0;
|
|
|
|
for ( ; ( elem = this[ i ] ) != null; i++ ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
|
|
// Prevent memory leaks
|
|
jQuery.cleanData( getAll( elem, false ) );
|
|
|
|
// Remove any remaining nodes
|
|
elem.textContent = "";
|
|
}
|
|
}
|
|
|
|
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 access( this, function( value ) {
|
|
var elem = this[ 0 ] || {},
|
|
i = 0,
|
|
l = this.length;
|
|
|
|
if ( value === undefined && elem.nodeType === 1 ) {
|
|
return elem.innerHTML;
|
|
}
|
|
|
|
// See if we can take a shortcut and just use innerHTML
|
|
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
|
|
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
|
|
|
|
value = jQuery.htmlPrefilter( value );
|
|
|
|
try {
|
|
for ( ; i < l; i++ ) {
|
|
elem = this[ i ] || {};
|
|
|
|
// Remove element nodes and prevent memory leaks
|
|
if ( elem.nodeType === 1 ) {
|
|
jQuery.cleanData( getAll( elem, false ) );
|
|
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() {
|
|
var ignored = [];
|
|
|
|
// Make the changes, replacing each non-ignored context element with the new content
|
|
return domManip( this, arguments, function( elem ) {
|
|
var parent = this.parentNode;
|
|
|
|
if ( jQuery.inArray( this, ignored ) < 0 ) {
|
|
jQuery.cleanData( getAll( this ) );
|
|
if ( parent ) {
|
|
parent.replaceChild( elem, this );
|
|
}
|
|
}
|
|
|
|
// Force callback invocation
|
|
}, ignored );
|
|
}
|
|
} );
|
|
|
|
jQuery.each( {
|
|
appendTo: "append",
|
|
prependTo: "prepend",
|
|
insertBefore: "before",
|
|
insertAfter: "after",
|
|
replaceAll: "replaceWith"
|
|
}, function( name, original ) {
|
|
jQuery.fn[ name ] = function( selector ) {
|
|
var elems,
|
|
ret = [],
|
|
insert = jQuery( selector ),
|
|
last = insert.length - 1,
|
|
i = 0;
|
|
|
|
for ( ; i <= last; i++ ) {
|
|
elems = i === last ? this : this.clone( true );
|
|
jQuery( insert[ i ] )[ original ]( elems );
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// .get() because push.apply(_, arraylike) throws on ancient WebKit
|
|
push.apply( ret, elems.get() );
|
|
}
|
|
|
|
return this.pushStack( ret );
|
|
};
|
|
} );
|
|
var rmargin = ( /^margin/ );
|
|
|
|
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
|
|
|
|
var getStyles = function( elem ) {
|
|
|
|
// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
|
|
// IE throws on elements created in popups
|
|
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
|
|
var view = elem.ownerDocument.defaultView;
|
|
|
|
if ( !view || !view.opener ) {
|
|
view = window;
|
|
}
|
|
|
|
return view.getComputedStyle( elem );
|
|
};
|
|
|
|
|
|
|
|
( function() {
|
|
|
|
// Executing both pixelPosition & boxSizingReliable tests require only one layout
|
|
// so they're executed at the same time to save the second computation.
|
|
function computeStyleTests() {
|
|
|
|
// This is a singleton, we need to execute it only once
|
|
if ( !div ) {
|
|
return;
|
|
}
|
|
|
|
div.style.cssText =
|
|
"box-sizing:border-box;" +
|
|
"position:relative;display:block;" +
|
|
"margin:auto;border:1px;padding:1px;" +
|
|
"top:1%;width:50%";
|
|
div.innerHTML = "";
|
|
documentElement.appendChild( container );
|
|
|
|
var divStyle = window.getComputedStyle( div );
|
|
pixelPositionVal = divStyle.top !== "1%";
|
|
|
|
// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
|
|
reliableMarginLeftVal = divStyle.marginLeft === "2px";
|
|
boxSizingReliableVal = divStyle.width === "4px";
|
|
|
|
// Support: Android 4.0 - 4.3 only
|
|
// Some styles come back with percentage values, even though they shouldn't
|
|
div.style.marginRight = "50%";
|
|
pixelMarginRightVal = divStyle.marginRight === "4px";
|
|
|
|
documentElement.removeChild( container );
|
|
|
|
// Nullify the div so it wouldn't be stored in the memory and
|
|
// it will also be a sign that checks already performed
|
|
div = null;
|
|
}
|
|
|
|
var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
|
|
container = document.createElement( "div" ),
|
|
div = document.createElement( "div" );
|
|
|
|
// Finish early in limited (non-browser) environments
|
|
if ( !div.style ) {
|
|
return;
|
|
}
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// Style of cloned element affects source element cloned (#8908)
|
|
div.style.backgroundClip = "content-box";
|
|
div.cloneNode( true ).style.backgroundClip = "";
|
|
support.clearCloneStyle = div.style.backgroundClip === "content-box";
|
|
|
|
container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
|
|
"padding:0;margin-top:1px;position:absolute";
|
|
container.appendChild( div );
|
|
|
|
jQuery.extend( support, {
|
|
pixelPosition: function() {
|
|
computeStyleTests();
|
|
return pixelPositionVal;
|
|
},
|
|
boxSizingReliable: function() {
|
|
computeStyleTests();
|
|
return boxSizingReliableVal;
|
|
},
|
|
pixelMarginRight: function() {
|
|
computeStyleTests();
|
|
return pixelMarginRightVal;
|
|
},
|
|
reliableMarginLeft: function() {
|
|
computeStyleTests();
|
|
return reliableMarginLeftVal;
|
|
}
|
|
} );
|
|
} )();
|
|
|
|
|
|
function curCSS( elem, name, computed ) {
|
|
var width, minWidth, maxWidth, ret,
|
|
style = elem.style;
|
|
|
|
computed = computed || getStyles( elem );
|
|
|
|
// getPropertyValue is needed for:
|
|
// .css('filter') (IE 9 only, #12537)
|
|
// .css('--customProperty) (#3144)
|
|
if ( computed ) {
|
|
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"
|
|
// Android Browser returns percentage for some values,
|
|
// but width seems to be reliably pixels.
|
|
// This is against the CSSOM draft spec:
|
|
// https://drafts.csswg.org/cssom/#resolved-values
|
|
if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {
|
|
|
|
// Remember the original values
|
|
width = style.width;
|
|
minWidth = style.minWidth;
|
|
maxWidth = style.maxWidth;
|
|
|
|
// Put in the new values to get a computed value out
|
|
style.minWidth = style.maxWidth = style.width = ret;
|
|
ret = computed.width;
|
|
|
|
// Revert the changed values
|
|
style.width = width;
|
|
style.minWidth = minWidth;
|
|
style.maxWidth = maxWidth;
|
|
}
|
|
}
|
|
|
|
return ret !== undefined ?
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// IE returns zIndex value as an integer.
|
|
ret + "" :
|
|
ret;
|
|
}
|
|
|
|
|
|
function addGetHookIf( conditionFn, hookFn ) {
|
|
|
|
// Define the hook, we'll check on the first run if it's really needed.
|
|
return {
|
|
get: function() {
|
|
if ( conditionFn() ) {
|
|
|
|
// Hook not needed (or it's not possible to use it due
|
|
// to missing dependency), remove it.
|
|
delete this.get;
|
|
return;
|
|
}
|
|
|
|
// Hook needed; redefine it so that the support test is not executed again.
|
|
return ( this.get = hookFn ).apply( this, arguments );
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
var
|
|
|
|
// 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]).+)/,
|
|
rcustomProp = /^--/,
|
|
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
|
cssNormalTransform = {
|
|
letterSpacing: "0",
|
|
fontWeight: "400"
|
|
},
|
|
|
|
cssPrefixes = [ "Webkit", "Moz", "ms" ],
|
|
emptyStyle = document.createElement( "div" ).style;
|
|
|
|
// Return a css property mapped to a potentially vendor prefixed property
|
|
function vendorPropName( name ) {
|
|
|
|
// Shortcut for names that are not vendor prefixed
|
|
if ( name in emptyStyle ) {
|
|
return name;
|
|
}
|
|
|
|
// Check for vendor prefixed names
|
|
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
|
|
i = cssPrefixes.length;
|
|
|
|
while ( i-- ) {
|
|
name = cssPrefixes[ i ] + capName;
|
|
if ( name in emptyStyle ) {
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return a property mapped along what jQuery.cssProps suggests or to
|
|
// a vendor prefixed property.
|
|
function finalPropName( name ) {
|
|
var ret = jQuery.cssProps[ name ];
|
|
if ( !ret ) {
|
|
ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
function setPositiveNumber( elem, value, subtract ) {
|
|
|
|
// Any relative (+/-) values have already been
|
|
// normalized at this point
|
|
var matches = rcssNum.exec( value );
|
|
return matches ?
|
|
|
|
// Guard against undefined "subtract", e.g., when used as in cssHooks
|
|
Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
|
|
value;
|
|
}
|
|
|
|
function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
|
|
var i,
|
|
val = 0;
|
|
|
|
// If we already have the right measurement, avoid augmentation
|
|
if ( extra === ( isBorderBox ? "border" : "content" ) ) {
|
|
i = 4;
|
|
|
|
// Otherwise initialize for horizontal or vertical properties
|
|
} else {
|
|
i = name === "width" ? 1 : 0;
|
|
}
|
|
|
|
for ( ; i < 4; i += 2 ) {
|
|
|
|
// Both box models exclude margin, so add it if we want it
|
|
if ( extra === "margin" ) {
|
|
val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
|
|
}
|
|
|
|
if ( isBorderBox ) {
|
|
|
|
// border-box includes padding, so remove it if we want content
|
|
if ( extra === "content" ) {
|
|
val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
|
}
|
|
|
|
// At this point, extra isn't border nor margin, so remove border
|
|
if ( extra !== "margin" ) {
|
|
val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
}
|
|
} else {
|
|
|
|
// At this point, extra isn't content, so add padding
|
|
val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
|
|
|
// At this point, extra isn't content nor padding, so add border
|
|
if ( extra !== "padding" ) {
|
|
val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
}
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
function getWidthOrHeight( elem, name, extra ) {
|
|
|
|
// Start with computed style
|
|
var valueIsBorderBox,
|
|
styles = getStyles( elem ),
|
|
val = curCSS( elem, name, styles ),
|
|
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
|
|
|
|
// Computed unit is not pixels. Stop here and return.
|
|
if ( rnumnonpx.test( val ) ) {
|
|
return val;
|
|
}
|
|
|
|
// Check for style in case a browser which returns unreliable values
|
|
// for getComputedStyle silently falls back to the reliable elem.style
|
|
valueIsBorderBox = isBorderBox &&
|
|
( 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,
|
|
styles
|
|
)
|
|
) + "px";
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// Don't automatically add "px" to these possibly-unitless properties
|
|
cssNumber: {
|
|
"animationIterationCount": true,
|
|
"columnCount": true,
|
|
"fillOpacity": true,
|
|
"flexGrow": true,
|
|
"flexShrink": true,
|
|
"fontWeight": true,
|
|
"lineHeight": true,
|
|
"opacity": true,
|
|
"order": 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: {
|
|
"float": "cssFloat"
|
|
},
|
|
|
|
// 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 ),
|
|
isCustomProp = rcustomProp.test( name ),
|
|
style = elem.style;
|
|
|
|
// Make sure that we're working with the right name. We don't
|
|
// want to query the value if it is a CSS custom property
|
|
// since they are user-defined.
|
|
if ( !isCustomProp ) {
|
|
name = finalPropName( origName );
|
|
}
|
|
|
|
// Gets hook for the prefixed version, then unprefixed version
|
|
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
|
|
|
// Check if we're setting a value
|
|
if ( value !== undefined ) {
|
|
type = typeof value;
|
|
|
|
// Convert "+=" or "-=" to relative numbers (#7345)
|
|
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
|
|
value = adjustCSS( elem, name, ret );
|
|
|
|
// Fixes bug #9237
|
|
type = "number";
|
|
}
|
|
|
|
// Make sure that null and NaN values aren't set (#7116)
|
|
if ( value == null || value !== value ) {
|
|
return;
|
|
}
|
|
|
|
// If a number was passed in, add the unit (except for certain CSS properties)
|
|
if ( type === "number" ) {
|
|
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
|
|
}
|
|
|
|
// background-* props affect original clone's values
|
|
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
|
|
style[ name ] = "inherit";
|
|
}
|
|
|
|
// 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 ) {
|
|
|
|
if ( isCustomProp ) {
|
|
style.setProperty( name, value );
|
|
} else {
|
|
style[ name ] = value;
|
|
}
|
|
}
|
|
|
|
} 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, extra, styles ) {
|
|
var val, num, hooks,
|
|
origName = jQuery.camelCase( name ),
|
|
isCustomProp = rcustomProp.test( name );
|
|
|
|
// Make sure that we're working with the right name. We don't
|
|
// want to modify the value if it is a CSS custom property
|
|
// since they are user-defined.
|
|
if ( !isCustomProp ) {
|
|
name = finalPropName( origName );
|
|
}
|
|
|
|
// Try prefixed name followed by the unprefixed name
|
|
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, styles );
|
|
}
|
|
|
|
// Convert "normal" to computed value
|
|
if ( val === "normal" && name in cssNormalTransform ) {
|
|
val = cssNormalTransform[ name ];
|
|
}
|
|
|
|
// Make numeric if forced or a qualifier was provided and val looks numeric
|
|
if ( extra === "" || extra ) {
|
|
num = parseFloat( val );
|
|
return extra === true || isFinite( num ) ? num || 0 : val;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
} );
|
|
|
|
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
|
|
// but it must have a current display style that would benefit
|
|
return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
|
|
|
|
// Support: Safari 8+
|
|
// Table columns in Safari have non-zero offsetWidth & zero
|
|
// getBoundingClientRect().width unless display is changed.
|
|
// Support: IE <=11 only
|
|
// Running getBoundingClientRect on a disconnected node
|
|
// in IE throws an error.
|
|
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
|
|
swap( elem, cssShow, function() {
|
|
return getWidthOrHeight( elem, name, extra );
|
|
} ) :
|
|
getWidthOrHeight( elem, name, extra );
|
|
}
|
|
},
|
|
|
|
set: function( elem, value, extra ) {
|
|
var matches,
|
|
styles = extra && getStyles( elem ),
|
|
subtract = extra && augmentWidthOrHeight(
|
|
elem,
|
|
name,
|
|
extra,
|
|
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
|
|
styles
|
|
);
|
|
|
|
// Convert to pixels if value adjustment is needed
|
|
if ( subtract && ( matches = rcssNum.exec( value ) ) &&
|
|
( matches[ 3 ] || "px" ) !== "px" ) {
|
|
|
|
elem.style[ name ] = value;
|
|
value = jQuery.css( elem, name );
|
|
}
|
|
|
|
return setPositiveNumber( elem, value, subtract );
|
|
}
|
|
};
|
|
} );
|
|
|
|
jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
|
|
function( elem, computed ) {
|
|
if ( computed ) {
|
|
return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
|
|
elem.getBoundingClientRect().left -
|
|
swap( elem, { marginLeft: 0 }, function() {
|
|
return elem.getBoundingClientRect().left;
|
|
} )
|
|
) + "px";
|
|
}
|
|
}
|
|
);
|
|
|
|
// 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 = 0,
|
|
expanded = {},
|
|
|
|
// Assumes a single number if not a string
|
|
parts = typeof value === "string" ? value.split( " " ) : [ value ];
|
|
|
|
for ( ; 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;
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
css: function( name, value ) {
|
|
return access( this, function( elem, name, value ) {
|
|
var styles, len,
|
|
map = {},
|
|
i = 0;
|
|
|
|
if ( Array.isArray( name ) ) {
|
|
styles = getStyles( elem );
|
|
len = name.length;
|
|
|
|
for ( ; i < len; i++ ) {
|
|
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
return value !== undefined ?
|
|
jQuery.style( elem, name, value ) :
|
|
jQuery.css( elem, name );
|
|
}, name, value, arguments.length > 1 );
|
|
}
|
|
} );
|
|
|
|
|
|
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 || jQuery.easing._default;
|
|
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;
|
|
|
|
// Use a property on the element directly when it is not a DOM element,
|
|
// or when there is no matching style property that exists.
|
|
if ( tween.elem.nodeType !== 1 ||
|
|
tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
|
|
return tween.elem[ tween.prop ];
|
|
}
|
|
|
|
// Passing an empty string as a 3rd parameter to .css will automatically
|
|
// attempt a parseFloat and fallback to a string if the parse fails.
|
|
// 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, "" );
|
|
|
|
// 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 available and use plain properties where available.
|
|
if ( jQuery.fx.step[ tween.prop ] ) {
|
|
jQuery.fx.step[ tween.prop ]( tween );
|
|
} else if ( tween.elem.nodeType === 1 &&
|
|
( 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;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Support: IE <=9 only
|
|
// 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.easing = {
|
|
linear: function( p ) {
|
|
return p;
|
|
},
|
|
swing: function( p ) {
|
|
return 0.5 - Math.cos( p * Math.PI ) / 2;
|
|
},
|
|
_default: "swing"
|
|
};
|
|
|
|
jQuery.fx = Tween.prototype.init;
|
|
|
|
// Back compat <1.8 extension point
|
|
jQuery.fx.step = {};
|
|
|
|
|
|
|
|
|
|
var
|
|
fxNow, inProgress,
|
|
rfxtypes = /^(?:toggle|show|hide)$/,
|
|
rrun = /queueHooks$/;
|
|
|
|
function schedule() {
|
|
if ( inProgress ) {
|
|
if ( document.hidden === false && window.requestAnimationFrame ) {
|
|
window.requestAnimationFrame( schedule );
|
|
} else {
|
|
window.setTimeout( schedule, jQuery.fx.interval );
|
|
}
|
|
|
|
jQuery.fx.tick();
|
|
}
|
|
}
|
|
|
|
// Animations created synchronously will run synchronously
|
|
function createFxNow() {
|
|
window.setTimeout( function() {
|
|
fxNow = undefined;
|
|
} );
|
|
return ( fxNow = jQuery.now() );
|
|
}
|
|
|
|
// Generate parameters to create a standard animation
|
|
function genFx( type, includeWidth ) {
|
|
var which,
|
|
i = 0,
|
|
attrs = { height: type };
|
|
|
|
// If we include width, step value is 1 to do all cssExpand values,
|
|
// otherwise 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;
|
|
}
|
|
|
|
function createTween( value, prop, animation ) {
|
|
var tween,
|
|
collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
|
|
index = 0,
|
|
length = collection.length;
|
|
for ( ; index < length; index++ ) {
|
|
if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
|
|
|
|
// We're done with this property
|
|
return tween;
|
|
}
|
|
}
|
|
}
|
|
|
|
function defaultPrefilter( elem, props, opts ) {
|
|
var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
|
|
isBox = "width" in props || "height" in props,
|
|
anim = this,
|
|
orig = {},
|
|
style = elem.style,
|
|
hidden = elem.nodeType && isHiddenWithinTree( elem ),
|
|
dataShow = dataPriv.get( elem, "fxshow" );
|
|
|
|
// Queue-skipping animations hijack the fx hooks
|
|
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() {
|
|
|
|
// Ensure the complete handler is called before this completes
|
|
anim.always( function() {
|
|
hooks.unqueued--;
|
|
if ( !jQuery.queue( elem, "fx" ).length ) {
|
|
hooks.empty.fire();
|
|
}
|
|
} );
|
|
} );
|
|
}
|
|
|
|
// Detect show/hide animations
|
|
for ( prop in props ) {
|
|
value = props[ prop ];
|
|
if ( rfxtypes.test( value ) ) {
|
|
delete props[ prop ];
|
|
toggle = toggle || value === "toggle";
|
|
if ( value === ( hidden ? "hide" : "show" ) ) {
|
|
|
|
// Pretend to be hidden if this is a "show" and
|
|
// there is still data from a stopped show/hide
|
|
if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
|
|
hidden = true;
|
|
|
|
// Ignore all other no-op show/hide data
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
|
|
}
|
|
}
|
|
|
|
// Bail out if this is a no-op like .hide().hide()
|
|
propTween = !jQuery.isEmptyObject( props );
|
|
if ( !propTween && jQuery.isEmptyObject( orig ) ) {
|
|
return;
|
|
}
|
|
|
|
// Restrict "overflow" and "display" styles during box animations
|
|
if ( isBox && elem.nodeType === 1 ) {
|
|
|
|
// Support: IE <=9 - 11, Edge 12 - 13
|
|
// Record all 3 overflow attributes because IE does not infer the shorthand
|
|
// from identically-valued overflowX and overflowY
|
|
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
|
|
|
|
// Identify a display type, preferring old show/hide data over the CSS cascade
|
|
restoreDisplay = dataShow && dataShow.display;
|
|
if ( restoreDisplay == null ) {
|
|
restoreDisplay = dataPriv.get( elem, "display" );
|
|
}
|
|
display = jQuery.css( elem, "display" );
|
|
if ( display === "none" ) {
|
|
if ( restoreDisplay ) {
|
|
display = restoreDisplay;
|
|
} else {
|
|
|
|
// Get nonempty value(s) by temporarily forcing visibility
|
|
showHide( [ elem ], true );
|
|
restoreDisplay = elem.style.display || restoreDisplay;
|
|
display = jQuery.css( elem, "display" );
|
|
showHide( [ elem ] );
|
|
}
|
|
}
|
|
|
|
// Animate inline elements as inline-block
|
|
if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
|
|
if ( jQuery.css( elem, "float" ) === "none" ) {
|
|
|
|
// Restore the original display value at the end of pure show/hide animations
|
|
if ( !propTween ) {
|
|
anim.done( function() {
|
|
style.display = restoreDisplay;
|
|
} );
|
|
if ( restoreDisplay == null ) {
|
|
display = style.display;
|
|
restoreDisplay = display === "none" ? "" : display;
|
|
}
|
|
}
|
|
style.display = "inline-block";
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( opts.overflow ) {
|
|
style.overflow = "hidden";
|
|
anim.always( function() {
|
|
style.overflow = opts.overflow[ 0 ];
|
|
style.overflowX = opts.overflow[ 1 ];
|
|
style.overflowY = opts.overflow[ 2 ];
|
|
} );
|
|
}
|
|
|
|
// Implement show/hide animations
|
|
propTween = false;
|
|
for ( prop in orig ) {
|
|
|
|
// General show/hide setup for this element animation
|
|
if ( !propTween ) {
|
|
if ( dataShow ) {
|
|
if ( "hidden" in dataShow ) {
|
|
hidden = dataShow.hidden;
|
|
}
|
|
} else {
|
|
dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
|
|
}
|
|
|
|
// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
|
|
if ( toggle ) {
|
|
dataShow.hidden = !hidden;
|
|
}
|
|
|
|
// Show elements before animating them
|
|
if ( hidden ) {
|
|
showHide( [ elem ], true );
|
|
}
|
|
|
|
/* eslint-disable no-loop-func */
|
|
|
|
anim.done( function() {
|
|
|
|
/* eslint-enable no-loop-func */
|
|
|
|
// The final step of a "hide" animation is actually hiding the element
|
|
if ( !hidden ) {
|
|
showHide( [ elem ] );
|
|
}
|
|
dataPriv.remove( elem, "fxshow" );
|
|
for ( prop in orig ) {
|
|
jQuery.style( elem, prop, orig[ prop ] );
|
|
}
|
|
} );
|
|
}
|
|
|
|
// Per-property setup
|
|
propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
|
|
if ( !( prop in dataShow ) ) {
|
|
dataShow[ prop ] = propTween.start;
|
|
if ( hidden ) {
|
|
propTween.end = propTween.start;
|
|
propTween.start = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 ( Array.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 won't overwrite existing keys.
|
|
// Reusing 'index' 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Animation( elem, properties, options ) {
|
|
var result,
|
|
stopped,
|
|
index = 0,
|
|
length = Animation.prefilters.length,
|
|
deferred = jQuery.Deferred().always( function() {
|
|
|
|
// Don't match elem in the :animated selector
|
|
delete tick.elem;
|
|
} ),
|
|
tick = function() {
|
|
if ( stopped ) {
|
|
return false;
|
|
}
|
|
var currentTime = fxNow || createFxNow(),
|
|
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
|
|
|
|
// Support: Android 2.3 only
|
|
// 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 there's more to do, yield
|
|
if ( percent < 1 && length ) {
|
|
return remaining;
|
|
}
|
|
|
|
// If this was an empty animation, synthesize a final progress notification
|
|
if ( !length ) {
|
|
deferred.notifyWith( elem, [ animation, 1, 0 ] );
|
|
}
|
|
|
|
// Resolve the animation and report its conclusion
|
|
deferred.resolveWith( elem, [ animation ] );
|
|
return false;
|
|
},
|
|
animation = deferred.promise( {
|
|
elem: elem,
|
|
props: jQuery.extend( {}, properties ),
|
|
opts: jQuery.extend( true, {
|
|
specialEasing: {},
|
|
easing: jQuery.easing._default
|
|
}, options ),
|
|
originalProperties: properties,
|
|
originalOptions: options,
|
|
startTime: fxNow || createFxNow(),
|
|
duration: options.duration,
|
|
tweens: [],
|
|
createTween: function( prop, end ) {
|
|
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;
|
|
if ( stopped ) {
|
|
return this;
|
|
}
|
|
stopped = true;
|
|
for ( ; index < length; index++ ) {
|
|
animation.tweens[ index ].run( 1 );
|
|
}
|
|
|
|
// Resolve when we played the last frame; otherwise, reject
|
|
if ( gotoEnd ) {
|
|
deferred.notifyWith( elem, [ animation, 1, 0 ] );
|
|
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 = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
|
|
if ( result ) {
|
|
if ( jQuery.isFunction( result.stop ) ) {
|
|
jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
|
|
jQuery.proxy( result.stop, result );
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
jQuery.map( props, createTween, animation );
|
|
|
|
if ( jQuery.isFunction( animation.opts.start ) ) {
|
|
animation.opts.start.call( elem, animation );
|
|
}
|
|
|
|
// Attach callbacks from options
|
|
animation
|
|
.progress( animation.opts.progress )
|
|
.done( animation.opts.done, animation.opts.complete )
|
|
.fail( animation.opts.fail )
|
|
.always( animation.opts.always );
|
|
|
|
jQuery.fx.timer(
|
|
jQuery.extend( tick, {
|
|
elem: elem,
|
|
anim: animation,
|
|
queue: animation.opts.queue
|
|
} )
|
|
);
|
|
|
|
return animation;
|
|
}
|
|
|
|
jQuery.Animation = jQuery.extend( Animation, {
|
|
|
|
tweeners: {
|
|
"*": [ function( prop, value ) {
|
|
var tween = this.createTween( prop, value );
|
|
adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
|
|
return tween;
|
|
} ]
|
|
},
|
|
|
|
tweener: function( props, callback ) {
|
|
if ( jQuery.isFunction( props ) ) {
|
|
callback = props;
|
|
props = [ "*" ];
|
|
} else {
|
|
props = props.match( rnothtmlwhite );
|
|
}
|
|
|
|
var prop,
|
|
index = 0,
|
|
length = props.length;
|
|
|
|
for ( ; index < length; index++ ) {
|
|
prop = props[ index ];
|
|
Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
|
|
Animation.tweeners[ prop ].unshift( callback );
|
|
}
|
|
},
|
|
|
|
prefilters: [ defaultPrefilter ],
|
|
|
|
prefilter: function( callback, prepend ) {
|
|
if ( prepend ) {
|
|
Animation.prefilters.unshift( callback );
|
|
} else {
|
|
Animation.prefilters.push( 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
|
|
};
|
|
|
|
// Go to the end state if fx are off
|
|
if ( jQuery.fx.off ) {
|
|
opt.duration = 0;
|
|
|
|
} else {
|
|
if ( typeof opt.duration !== "number" ) {
|
|
if ( opt.duration in jQuery.fx.speeds ) {
|
|
opt.duration = jQuery.fx.speeds[ opt.duration ];
|
|
|
|
} else {
|
|
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.fn.extend( {
|
|
fadeTo: function( speed, to, easing, callback ) {
|
|
|
|
// Show any hidden elements after setting opacity to 0
|
|
return this.filter( isHiddenWithinTree ).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, or finishing resolves immediately
|
|
if ( empty || dataPriv.get( this, "finish" ) ) {
|
|
anim.stop( true );
|
|
}
|
|
};
|
|
doAnimation.finish = doAnimation;
|
|
|
|
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 = dataPriv.get( 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 );
|
|
}
|
|
} );
|
|
},
|
|
finish: function( type ) {
|
|
if ( type !== false ) {
|
|
type = type || "fx";
|
|
}
|
|
return this.each( function() {
|
|
var index,
|
|
data = dataPriv.get( this ),
|
|
queue = data[ type + "queue" ],
|
|
hooks = data[ type + "queueHooks" ],
|
|
timers = jQuery.timers,
|
|
length = queue ? queue.length : 0;
|
|
|
|
// Enable finishing flag on private data
|
|
data.finish = true;
|
|
|
|
// Empty the queue first
|
|
jQuery.queue( this, type, [] );
|
|
|
|
if ( hooks && hooks.stop ) {
|
|
hooks.stop.call( this, true );
|
|
}
|
|
|
|
// Look for any active animations, and finish them
|
|
for ( index = timers.length; index--; ) {
|
|
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
|
|
timers[ index ].anim.stop( true );
|
|
timers.splice( index, 1 );
|
|
}
|
|
}
|
|
|
|
// Look for any animations in the old queue and finish them
|
|
for ( index = 0; index < length; index++ ) {
|
|
if ( queue[ index ] && queue[ index ].finish ) {
|
|
queue[ index ].finish.call( this );
|
|
}
|
|
}
|
|
|
|
// Turn off finishing flag
|
|
delete data.finish;
|
|
} );
|
|
}
|
|
} );
|
|
|
|
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" ?
|
|
cssFn.apply( this, arguments ) :
|
|
this.animate( genFx( name, true ), speed, easing, callback );
|
|
};
|
|
} );
|
|
|
|
// 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.timers = [];
|
|
jQuery.fx.tick = function() {
|
|
var timer,
|
|
i = 0,
|
|
timers = jQuery.timers;
|
|
|
|
fxNow = jQuery.now();
|
|
|
|
for ( ; i < timers.length; i++ ) {
|
|
timer = timers[ i ];
|
|
|
|
// Run the timer and safely remove it when done (allowing for external removal)
|
|
if ( !timer() && timers[ i ] === timer ) {
|
|
timers.splice( i--, 1 );
|
|
}
|
|
}
|
|
|
|
if ( !timers.length ) {
|
|
jQuery.fx.stop();
|
|
}
|
|
fxNow = undefined;
|
|
};
|
|
|
|
jQuery.fx.timer = function( timer ) {
|
|
jQuery.timers.push( timer );
|
|
jQuery.fx.start();
|
|
};
|
|
|
|
jQuery.fx.interval = 13;
|
|
jQuery.fx.start = function() {
|
|
if ( inProgress ) {
|
|
return;
|
|
}
|
|
|
|
inProgress = true;
|
|
schedule();
|
|
};
|
|
|
|
jQuery.fx.stop = function() {
|
|
inProgress = null;
|
|
};
|
|
|
|
jQuery.fx.speeds = {
|
|
slow: 600,
|
|
fast: 200,
|
|
|
|
// Default speed
|
|
_default: 400
|
|
};
|
|
|
|
|
|
// Based off of the plugin by Clint Helfers, with permission.
|
|
// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
|
|
jQuery.fn.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 = window.setTimeout( next, time );
|
|
hooks.stop = function() {
|
|
window.clearTimeout( timeout );
|
|
};
|
|
} );
|
|
};
|
|
|
|
|
|
( function() {
|
|
var input = document.createElement( "input" ),
|
|
select = document.createElement( "select" ),
|
|
opt = select.appendChild( document.createElement( "option" ) );
|
|
|
|
input.type = "checkbox";
|
|
|
|
// Support: Android <=4.3 only
|
|
// Default value for a checkbox should be "on"
|
|
support.checkOn = input.value !== "";
|
|
|
|
// Support: IE <=11 only
|
|
// Must access selectedIndex to make default options select
|
|
support.optSelected = opt.selected;
|
|
|
|
// Support: IE <=11 only
|
|
// An input loses its value after becoming a radio
|
|
input = document.createElement( "input" );
|
|
input.value = "t";
|
|
input.type = "radio";
|
|
support.radioValue = input.value === "t";
|
|
} )();
|
|
|
|
|
|
var boolHook,
|
|
attrHandle = jQuery.expr.attrHandle;
|
|
|
|
jQuery.fn.extend( {
|
|
attr: function( name, value ) {
|
|
return access( this, jQuery.attr, name, value, arguments.length > 1 );
|
|
},
|
|
|
|
removeAttr: function( name ) {
|
|
return this.each( function() {
|
|
jQuery.removeAttr( this, name );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.extend( {
|
|
attr: function( elem, name, value ) {
|
|
var ret, hooks,
|
|
nType = elem.nodeType;
|
|
|
|
// Don't get/set attributes on text, comment and attribute nodes
|
|
if ( nType === 3 || nType === 8 || nType === 2 ) {
|
|
return;
|
|
}
|
|
|
|
// Fallback to prop when attributes are not supported
|
|
if ( typeof elem.getAttribute === "undefined" ) {
|
|
return jQuery.prop( elem, name, value );
|
|
}
|
|
|
|
// Attribute hooks are determined by the lowercase version
|
|
// Grab necessary hook if one is defined
|
|
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
|
hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
|
|
( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
|
|
}
|
|
|
|
if ( value !== undefined ) {
|
|
if ( value === null ) {
|
|
jQuery.removeAttr( elem, name );
|
|
return;
|
|
}
|
|
|
|
if ( hooks && "set" in hooks &&
|
|
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
|
|
return ret;
|
|
}
|
|
|
|
elem.setAttribute( name, value + "" );
|
|
return value;
|
|
}
|
|
|
|
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
|
|
return ret;
|
|
}
|
|
|
|
ret = jQuery.find.attr( elem, name );
|
|
|
|
// Non-existent attributes return null, we normalize to undefined
|
|
return ret == null ? undefined : ret;
|
|
},
|
|
|
|
attrHooks: {
|
|
type: {
|
|
set: function( elem, value ) {
|
|
if ( !support.radioValue && value === "radio" &&
|
|
nodeName( elem, "input" ) ) {
|
|
var val = elem.value;
|
|
elem.setAttribute( "type", value );
|
|
if ( val ) {
|
|
elem.value = val;
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
removeAttr: function( elem, value ) {
|
|
var name,
|
|
i = 0,
|
|
|
|
// Attribute names can contain non-HTML whitespace characters
|
|
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
attrNames = value && value.match( rnothtmlwhite );
|
|
|
|
if ( attrNames && elem.nodeType === 1 ) {
|
|
while ( ( name = attrNames[ i++ ] ) ) {
|
|
elem.removeAttribute( name );
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
|
|
// Hooks for boolean attributes
|
|
boolHook = {
|
|
set: function( elem, value, name ) {
|
|
if ( value === false ) {
|
|
|
|
// Remove boolean attributes when set to false
|
|
jQuery.removeAttr( elem, name );
|
|
} else {
|
|
elem.setAttribute( name, name );
|
|
}
|
|
return name;
|
|
}
|
|
};
|
|
|
|
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
|
|
var getter = attrHandle[ name ] || jQuery.find.attr;
|
|
|
|
attrHandle[ name ] = function( elem, name, isXML ) {
|
|
var ret, handle,
|
|
lowercaseName = name.toLowerCase();
|
|
|
|
if ( !isXML ) {
|
|
|
|
// Avoid an infinite loop by temporarily removing this function from the getter
|
|
handle = attrHandle[ lowercaseName ];
|
|
attrHandle[ lowercaseName ] = ret;
|
|
ret = getter( elem, name, isXML ) != null ?
|
|
lowercaseName :
|
|
null;
|
|
attrHandle[ lowercaseName ] = handle;
|
|
}
|
|
return ret;
|
|
};
|
|
} );
|
|
|
|
|
|
|
|
|
|
var rfocusable = /^(?:input|select|textarea|button)$/i,
|
|
rclickable = /^(?:a|area)$/i;
|
|
|
|
jQuery.fn.extend( {
|
|
prop: function( name, value ) {
|
|
return access( this, jQuery.prop, name, value, arguments.length > 1 );
|
|
},
|
|
|
|
removeProp: function( name ) {
|
|
return this.each( function() {
|
|
delete this[ jQuery.propFix[ name ] || name ];
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.extend( {
|
|
prop: function( elem, name, value ) {
|
|
var ret, hooks,
|
|
nType = elem.nodeType;
|
|
|
|
// Don't get/set properties on text, comment and attribute nodes
|
|
if ( nType === 3 || nType === 8 || nType === 2 ) {
|
|
return;
|
|
}
|
|
|
|
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
|
|
|
// 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;
|
|
}
|
|
|
|
return ( elem[ name ] = value );
|
|
}
|
|
|
|
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
|
|
return ret;
|
|
}
|
|
|
|
return elem[ name ];
|
|
},
|
|
|
|
propHooks: {
|
|
tabIndex: {
|
|
get: function( elem ) {
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// elem.tabIndex doesn't always return the
|
|
// correct value when it hasn't been explicitly set
|
|
// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
|
|
// Use proper attribute retrieval(#12072)
|
|
var tabindex = jQuery.find.attr( elem, "tabindex" );
|
|
|
|
if ( tabindex ) {
|
|
return parseInt( tabindex, 10 );
|
|
}
|
|
|
|
if (
|
|
rfocusable.test( elem.nodeName ) ||
|
|
rclickable.test( elem.nodeName ) &&
|
|
elem.href
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
},
|
|
|
|
propFix: {
|
|
"for": "htmlFor",
|
|
"class": "className"
|
|
}
|
|
} );
|
|
|
|
// Support: IE <=11 only
|
|
// Accessing the selectedIndex property
|
|
// forces the browser to respect setting selected
|
|
// on the option
|
|
// The getter ensures a default option is selected
|
|
// when in an optgroup
|
|
// eslint rule "no-unused-expressions" is disabled for this code
|
|
// since it considers such accessions noop
|
|
if ( !support.optSelected ) {
|
|
jQuery.propHooks.selected = {
|
|
get: function( elem ) {
|
|
|
|
/* eslint no-unused-expressions: "off" */
|
|
|
|
var parent = elem.parentNode;
|
|
if ( parent && parent.parentNode ) {
|
|
parent.parentNode.selectedIndex;
|
|
}
|
|
return null;
|
|
},
|
|
set: function( elem ) {
|
|
|
|
/* eslint no-unused-expressions: "off" */
|
|
|
|
var parent = elem.parentNode;
|
|
if ( parent ) {
|
|
parent.selectedIndex;
|
|
|
|
if ( parent.parentNode ) {
|
|
parent.parentNode.selectedIndex;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
jQuery.each( [
|
|
"tabIndex",
|
|
"readOnly",
|
|
"maxLength",
|
|
"cellSpacing",
|
|
"cellPadding",
|
|
"rowSpan",
|
|
"colSpan",
|
|
"useMap",
|
|
"frameBorder",
|
|
"contentEditable"
|
|
], function() {
|
|
jQuery.propFix[ this.toLowerCase() ] = this;
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Strip and collapse whitespace according to HTML spec
|
|
// https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace
|
|
function stripAndCollapse( value ) {
|
|
var tokens = value.match( rnothtmlwhite ) || [];
|
|
return tokens.join( " " );
|
|
}
|
|
|
|
|
|
function getClass( elem ) {
|
|
return elem.getAttribute && elem.getAttribute( "class" ) || "";
|
|
}
|
|
|
|
jQuery.fn.extend( {
|
|
addClass: function( value ) {
|
|
var classes, elem, cur, curValue, clazz, j, finalValue,
|
|
i = 0;
|
|
|
|
if ( jQuery.isFunction( value ) ) {
|
|
return this.each( function( j ) {
|
|
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
|
|
} );
|
|
}
|
|
|
|
if ( typeof value === "string" && value ) {
|
|
classes = value.match( rnothtmlwhite ) || [];
|
|
|
|
while ( ( elem = this[ i++ ] ) ) {
|
|
curValue = getClass( elem );
|
|
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
|
|
|
if ( cur ) {
|
|
j = 0;
|
|
while ( ( clazz = classes[ j++ ] ) ) {
|
|
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
|
|
cur += clazz + " ";
|
|
}
|
|
}
|
|
|
|
// Only assign if different to avoid unneeded rendering.
|
|
finalValue = stripAndCollapse( cur );
|
|
if ( curValue !== finalValue ) {
|
|
elem.setAttribute( "class", finalValue );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
removeClass: function( value ) {
|
|
var classes, elem, cur, curValue, clazz, j, finalValue,
|
|
i = 0;
|
|
|
|
if ( jQuery.isFunction( value ) ) {
|
|
return this.each( function( j ) {
|
|
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
|
|
} );
|
|
}
|
|
|
|
if ( !arguments.length ) {
|
|
return this.attr( "class", "" );
|
|
}
|
|
|
|
if ( typeof value === "string" && value ) {
|
|
classes = value.match( rnothtmlwhite ) || [];
|
|
|
|
while ( ( elem = this[ i++ ] ) ) {
|
|
curValue = getClass( elem );
|
|
|
|
// This expression is here for better compressibility (see addClass)
|
|
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
|
|
|
if ( cur ) {
|
|
j = 0;
|
|
while ( ( clazz = classes[ j++ ] ) ) {
|
|
|
|
// Remove *all* instances
|
|
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
|
|
cur = cur.replace( " " + clazz + " ", " " );
|
|
}
|
|
}
|
|
|
|
// Only assign if different to avoid unneeded rendering.
|
|
finalValue = stripAndCollapse( cur );
|
|
if ( curValue !== finalValue ) {
|
|
elem.setAttribute( "class", finalValue );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
toggleClass: function( value, stateVal ) {
|
|
var type = typeof value;
|
|
|
|
if ( typeof stateVal === "boolean" && type === "string" ) {
|
|
return stateVal ? this.addClass( value ) : this.removeClass( value );
|
|
}
|
|
|
|
if ( jQuery.isFunction( value ) ) {
|
|
return this.each( function( i ) {
|
|
jQuery( this ).toggleClass(
|
|
value.call( this, i, getClass( this ), stateVal ),
|
|
stateVal
|
|
);
|
|
} );
|
|
}
|
|
|
|
return this.each( function() {
|
|
var className, i, self, classNames;
|
|
|
|
if ( type === "string" ) {
|
|
|
|
// Toggle individual class names
|
|
i = 0;
|
|
self = jQuery( this );
|
|
classNames = value.match( rnothtmlwhite ) || [];
|
|
|
|
while ( ( className = classNames[ i++ ] ) ) {
|
|
|
|
// Check each className given, space separated list
|
|
if ( self.hasClass( className ) ) {
|
|
self.removeClass( className );
|
|
} else {
|
|
self.addClass( className );
|
|
}
|
|
}
|
|
|
|
// Toggle whole class name
|
|
} else if ( value === undefined || type === "boolean" ) {
|
|
className = getClass( this );
|
|
if ( className ) {
|
|
|
|
// Store className if set
|
|
dataPriv.set( this, "__className__", className );
|
|
}
|
|
|
|
// If the element has a class name or if we're passed `false`,
|
|
// then remove the whole classname (if there was one, the above saved it).
|
|
// Otherwise bring back whatever was previously saved (if anything),
|
|
// falling back to the empty string if nothing was stored.
|
|
if ( this.setAttribute ) {
|
|
this.setAttribute( "class",
|
|
className || value === false ?
|
|
"" :
|
|
dataPriv.get( this, "__className__" ) || ""
|
|
);
|
|
}
|
|
}
|
|
} );
|
|
},
|
|
|
|
hasClass: function( selector ) {
|
|
var className, elem,
|
|
i = 0;
|
|
|
|
className = " " + selector + " ";
|
|
while ( ( elem = this[ i++ ] ) ) {
|
|
if ( elem.nodeType === 1 &&
|
|
( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
var rreturn = /\r/g;
|
|
|
|
jQuery.fn.extend( {
|
|
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;
|
|
|
|
// Handle most common string cases
|
|
if ( typeof ret === "string" ) {
|
|
return ret.replace( rreturn, "" );
|
|
}
|
|
|
|
// Handle cases where value is null/undef or number
|
|
return ret == null ? "" : ret;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
isFunction = jQuery.isFunction( value );
|
|
|
|
return this.each( function( i ) {
|
|
var val;
|
|
|
|
if ( this.nodeType !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
if ( isFunction ) {
|
|
val = value.call( this, i, jQuery( this ).val() );
|
|
} else {
|
|
val = value;
|
|
}
|
|
|
|
// Treat null/undefined as ""; convert numbers to string
|
|
if ( val == null ) {
|
|
val = "";
|
|
|
|
} else if ( typeof val === "number" ) {
|
|
val += "";
|
|
|
|
} else if ( Array.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 ) {
|
|
|
|
var val = jQuery.find.attr( elem, "value" );
|
|
return val != null ?
|
|
val :
|
|
|
|
// Support: IE <=10 - 11 only
|
|
// option.text throws exceptions (#14686, #14858)
|
|
// Strip and collapse whitespace
|
|
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
|
|
stripAndCollapse( jQuery.text( elem ) );
|
|
}
|
|
},
|
|
select: {
|
|
get: function( elem ) {
|
|
var value, option, i,
|
|
options = elem.options,
|
|
index = elem.selectedIndex,
|
|
one = elem.type === "select-one",
|
|
values = one ? null : [],
|
|
max = one ? index + 1 : options.length;
|
|
|
|
if ( index < 0 ) {
|
|
i = max;
|
|
|
|
} else {
|
|
i = one ? index : 0;
|
|
}
|
|
|
|
// Loop through all the selected options
|
|
for ( ; i < max; i++ ) {
|
|
option = options[ i ];
|
|
|
|
// Support: IE <=9 only
|
|
// IE8-9 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
|
|
!option.disabled &&
|
|
( !option.parentNode.disabled ||
|
|
!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 optionSet, option,
|
|
options = elem.options,
|
|
values = jQuery.makeArray( value ),
|
|
i = options.length;
|
|
|
|
while ( i-- ) {
|
|
option = options[ i ];
|
|
|
|
/* eslint-disable no-cond-assign */
|
|
|
|
if ( option.selected =
|
|
jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
|
|
) {
|
|
optionSet = true;
|
|
}
|
|
|
|
/* eslint-enable no-cond-assign */
|
|
}
|
|
|
|
// Force browsers to behave consistently when non-matching value is set
|
|
if ( !optionSet ) {
|
|
elem.selectedIndex = -1;
|
|
}
|
|
return values;
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
|
|
// Radios and checkboxes getter/setter
|
|
jQuery.each( [ "radio", "checkbox" ], function() {
|
|
jQuery.valHooks[ this ] = {
|
|
set: function( elem, value ) {
|
|
if ( Array.isArray( value ) ) {
|
|
return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
|
|
}
|
|
}
|
|
};
|
|
if ( !support.checkOn ) {
|
|
jQuery.valHooks[ this ].get = function( elem ) {
|
|
return elem.getAttribute( "value" ) === null ? "on" : elem.value;
|
|
};
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Return jQuery for attributes-only inclusion
|
|
|
|
|
|
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
|
|
|
|
jQuery.extend( jQuery.event, {
|
|
|
|
trigger: function( event, data, elem, onlyHandlers ) {
|
|
|
|
var i, cur, tmp, bubbleType, ontype, handle, special,
|
|
eventPath = [ elem || document ],
|
|
type = hasOwn.call( event, "type" ) ? event.type : event,
|
|
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
|
|
|
|
cur = tmp = elem = elem || document;
|
|
|
|
// Don't do events on text and comment nodes
|
|
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
|
|
return;
|
|
}
|
|
|
|
// 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( "." ) > -1 ) {
|
|
|
|
// Namespaced trigger; create a regexp to match event type in handle()
|
|
namespaces = type.split( "." );
|
|
type = namespaces.shift();
|
|
namespaces.sort();
|
|
}
|
|
ontype = type.indexOf( ":" ) < 0 && "on" + type;
|
|
|
|
// Caller can pass in a jQuery.Event object, Object, or just an event type string
|
|
event = event[ jQuery.expando ] ?
|
|
event :
|
|
new jQuery.Event( type, typeof event === "object" && event );
|
|
|
|
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
|
|
event.isTrigger = onlyHandlers ? 2 : 3;
|
|
event.namespace = namespaces.join( "." );
|
|
event.rnamespace = event.namespace ?
|
|
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
|
|
null;
|
|
|
|
// 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 ?
|
|
[ event ] :
|
|
jQuery.makeArray( data, [ event ] );
|
|
|
|
// Allow special events to draw outside the lines
|
|
special = jQuery.event.special[ type ] || {};
|
|
if ( !onlyHandlers && 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)
|
|
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
|
|
|
|
bubbleType = special.delegateType || type;
|
|
if ( !rfocusMorph.test( bubbleType + type ) ) {
|
|
cur = cur.parentNode;
|
|
}
|
|
for ( ; cur; cur = cur.parentNode ) {
|
|
eventPath.push( cur );
|
|
tmp = cur;
|
|
}
|
|
|
|
// Only add window if we got to document (e.g., not plain obj or detached DOM)
|
|
if ( tmp === ( elem.ownerDocument || document ) ) {
|
|
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
|
|
}
|
|
}
|
|
|
|
// Fire handlers on the event path
|
|
i = 0;
|
|
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
|
|
|
|
event.type = i > 1 ?
|
|
bubbleType :
|
|
special.bindType || type;
|
|
|
|
// jQuery handler
|
|
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
|
|
dataPriv.get( cur, "handle" );
|
|
if ( handle ) {
|
|
handle.apply( cur, data );
|
|
}
|
|
|
|
// Native handler
|
|
handle = ontype && cur[ ontype ];
|
|
if ( handle && handle.apply && acceptData( cur ) ) {
|
|
event.result = handle.apply( cur, data );
|
|
if ( event.result === 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( eventPath.pop(), data ) === false ) &&
|
|
acceptData( elem ) ) {
|
|
|
|
// Call a native DOM method on the target with the same name as the event.
|
|
// Don't do default actions on window, that's where global variables be (#6170)
|
|
if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
|
|
|
|
// Don't re-trigger an onFOO event when we call its FOO() method
|
|
tmp = elem[ ontype ];
|
|
|
|
if ( tmp ) {
|
|
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 ( tmp ) {
|
|
elem[ ontype ] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return event.result;
|
|
},
|
|
|
|
// Piggyback on a donor event to simulate a different one
|
|
// Used only for `focus(in | out)` events
|
|
simulate: function( type, elem, event ) {
|
|
var e = jQuery.extend(
|
|
new jQuery.Event(),
|
|
event,
|
|
{
|
|
type: type,
|
|
isSimulated: true
|
|
}
|
|
);
|
|
|
|
jQuery.event.trigger( e, null, elem );
|
|
}
|
|
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
trigger: function( type, data ) {
|
|
return this.each( function() {
|
|
jQuery.event.trigger( type, data, this );
|
|
} );
|
|
},
|
|
triggerHandler: function( type, data ) {
|
|
var elem = this[ 0 ];
|
|
if ( elem ) {
|
|
return jQuery.event.trigger( type, data, elem, true );
|
|
}
|
|
}
|
|
} );
|
|
|
|
|
|
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
|
|
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
|
|
"change select submit keydown keypress keyup contextmenu" ).split( " " ),
|
|
function( i, name ) {
|
|
|
|
// Handle event binding
|
|
jQuery.fn[ name ] = function( data, fn ) {
|
|
return arguments.length > 0 ?
|
|
this.on( name, null, data, fn ) :
|
|
this.trigger( name );
|
|
};
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
hover: function( fnOver, fnOut ) {
|
|
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
support.focusin = "onfocusin" in window;
|
|
|
|
|
|
// Support: Firefox <=44
|
|
// Firefox doesn't have focus(in | out) events
|
|
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
|
|
//
|
|
// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
|
|
// focus(in | out) events fire after focus & blur events,
|
|
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
|
|
// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
|
|
if ( !support.focusin ) {
|
|
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
|
|
|
|
// Attach a single capturing handler on the document while someone wants focusin/focusout
|
|
var handler = function( event ) {
|
|
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
|
|
};
|
|
|
|
jQuery.event.special[ fix ] = {
|
|
setup: function() {
|
|
var doc = this.ownerDocument || this,
|
|
attaches = dataPriv.access( doc, fix );
|
|
|
|
if ( !attaches ) {
|
|
doc.addEventListener( orig, handler, true );
|
|
}
|
|
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
|
|
},
|
|
teardown: function() {
|
|
var doc = this.ownerDocument || this,
|
|
attaches = dataPriv.access( doc, fix ) - 1;
|
|
|
|
if ( !attaches ) {
|
|
doc.removeEventListener( orig, handler, true );
|
|
dataPriv.remove( doc, fix );
|
|
|
|
} else {
|
|
dataPriv.access( doc, fix, attaches );
|
|
}
|
|
}
|
|
};
|
|
} );
|
|
}
|
|
var location = window.location;
|
|
|
|
var nonce = jQuery.now();
|
|
|
|
var rquery = ( /\?/ );
|
|
|
|
|
|
|
|
// Cross-browser xml parsing
|
|
jQuery.parseXML = function( data ) {
|
|
var xml;
|
|
if ( !data || typeof data !== "string" ) {
|
|
return null;
|
|
}
|
|
|
|
// Support: IE 9 - 11 only
|
|
// IE throws on parseFromString with invalid input.
|
|
try {
|
|
xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
|
|
} catch ( e ) {
|
|
xml = undefined;
|
|
}
|
|
|
|
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
|
|
jQuery.error( "Invalid XML: " + data );
|
|
}
|
|
return xml;
|
|
};
|
|
|
|
|
|
var
|
|
rbracket = /\[\]$/,
|
|
rCRLF = /\r?\n/g,
|
|
rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
|
|
rsubmittable = /^(?:input|select|textarea|keygen)/i;
|
|
|
|
function buildParams( prefix, obj, traditional, add ) {
|
|
var name;
|
|
|
|
if ( Array.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 {
|
|
|
|
// Item is non-scalar (array or object), encode its numeric index.
|
|
buildParams(
|
|
prefix + "[" + ( typeof v === "object" && v != null ? 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 );
|
|
}
|
|
}
|
|
|
|
// 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, valueOrFunction ) {
|
|
|
|
// If value is a function, invoke it and use its return value
|
|
var value = jQuery.isFunction( valueOrFunction ) ?
|
|
valueOrFunction() :
|
|
valueOrFunction;
|
|
|
|
s[ s.length ] = encodeURIComponent( key ) + "=" +
|
|
encodeURIComponent( value == null ? "" : value );
|
|
};
|
|
|
|
// If an array was passed in, assume that it is an array of form elements.
|
|
if ( Array.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( "&" );
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
serialize: function() {
|
|
return jQuery.param( this.serializeArray() );
|
|
},
|
|
serializeArray: function() {
|
|
return this.map( function() {
|
|
|
|
// Can add propHook for "elements" to filter or add form elements
|
|
var elements = jQuery.prop( this, "elements" );
|
|
return elements ? jQuery.makeArray( elements ) : this;
|
|
} )
|
|
.filter( function() {
|
|
var type = this.type;
|
|
|
|
// Use .is( ":disabled" ) so that fieldset[disabled] works
|
|
return this.name && !jQuery( this ).is( ":disabled" ) &&
|
|
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
|
|
( this.checked || !rcheckableType.test( type ) );
|
|
} )
|
|
.map( function( i, elem ) {
|
|
var val = jQuery( this ).val();
|
|
|
|
if ( val == null ) {
|
|
return null;
|
|
}
|
|
|
|
if ( Array.isArray( val ) ) {
|
|
return jQuery.map( val, function( val ) {
|
|
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
|
} );
|
|
}
|
|
|
|
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
|
} ).get();
|
|
}
|
|
} );
|
|
|
|
|
|
var
|
|
r20 = /%20/g,
|
|
rhash = /#.*$/,
|
|
rantiCache = /([?&])_=[^&]*/,
|
|
rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
|
|
|
|
// #7653, #8125, #8152: local protocol detection
|
|
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
|
|
rnoContent = /^(?:GET|HEAD)$/,
|
|
rprotocol = /^\/\//,
|
|
|
|
/* 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 = "*/".concat( "*" ),
|
|
|
|
// Anchor tag for parsing the document origin
|
|
originAnchor = document.createElement( "a" );
|
|
originAnchor.href = location.href;
|
|
|
|
// 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,
|
|
i = 0,
|
|
dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
|
|
|
|
if ( jQuery.isFunction( func ) ) {
|
|
|
|
// For each dataType in the dataTypeExpression
|
|
while ( ( dataType = dataTypes[ i++ ] ) ) {
|
|
|
|
// Prepend if requested
|
|
if ( dataType[ 0 ] === "+" ) {
|
|
dataType = dataType.slice( 1 ) || "*";
|
|
( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
|
|
|
|
// Otherwise append
|
|
} else {
|
|
( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Base inspection function for prefilters and transports
|
|
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
|
|
|
|
var inspected = {},
|
|
seekingTransport = ( structure === transports );
|
|
|
|
function inspect( dataType ) {
|
|
var selected;
|
|
inspected[ dataType ] = true;
|
|
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
|
|
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
|
|
if ( typeof dataTypeOrTransport === "string" &&
|
|
!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
|
|
|
|
options.dataTypes.unshift( dataTypeOrTransport );
|
|
inspect( dataTypeOrTransport );
|
|
return false;
|
|
} else if ( seekingTransport ) {
|
|
return !( selected = dataTypeOrTransport );
|
|
}
|
|
} );
|
|
return selected;
|
|
}
|
|
|
|
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
|
|
}
|
|
|
|
// 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 );
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
/* Handles responses to an ajax request:
|
|
* - 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;
|
|
|
|
// 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
|
|
* Also sets the responseXXX fields on the jqXHR instance
|
|
*/
|
|
function ajaxConvert( s, response, jqXHR, isSuccess ) {
|
|
var conv2, current, conv, tmp, prev,
|
|
converters = {},
|
|
|
|
// Work with a copy of dataTypes in case we need to modify it for conversion
|
|
dataTypes = s.dataTypes.slice();
|
|
|
|
// Create converters map with lowercased keys
|
|
if ( dataTypes[ 1 ] ) {
|
|
for ( conv in s.converters ) {
|
|
converters[ conv.toLowerCase() ] = s.converters[ conv ];
|
|
}
|
|
}
|
|
|
|
current = dataTypes.shift();
|
|
|
|
// Convert to each sequential dataType
|
|
while ( current ) {
|
|
|
|
if ( s.responseFields[ current ] ) {
|
|
jqXHR[ s.responseFields[ current ] ] = response;
|
|
}
|
|
|
|
// Apply the dataFilter if provided
|
|
if ( !prev && isSuccess && s.dataFilter ) {
|
|
response = s.dataFilter( response, s.dataType );
|
|
}
|
|
|
|
prev = current;
|
|
current = dataTypes.shift();
|
|
|
|
if ( current ) {
|
|
|
|
// There's only work to do if current dataType is non-auto
|
|
if ( current === "*" ) {
|
|
|
|
current = prev;
|
|
|
|
// Convert response if prev dataType is non-auto and differs from current
|
|
} else 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.unshift( tmp[ 1 ] );
|
|
}
|
|
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
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return { state: "success", data: response };
|
|
}
|
|
|
|
jQuery.extend( {
|
|
|
|
// Counter for holding the number of active queries
|
|
active: 0,
|
|
|
|
// Last-Modified header cache for next request
|
|
lastModified: {},
|
|
etag: {},
|
|
|
|
ajaxSettings: {
|
|
url: location.href,
|
|
type: "GET",
|
|
isLocal: rlocalProtocol.test( location.protocol ),
|
|
global: true,
|
|
processData: true,
|
|
async: true,
|
|
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
|
|
|
/*
|
|
timeout: 0,
|
|
data: null,
|
|
dataType: null,
|
|
username: null,
|
|
password: null,
|
|
cache: null,
|
|
throws: false,
|
|
traditional: false,
|
|
headers: {},
|
|
*/
|
|
|
|
accepts: {
|
|
"*": allTypes,
|
|
text: "text/plain",
|
|
html: "text/html",
|
|
xml: "application/xml, text/xml",
|
|
json: "application/json, text/javascript"
|
|
},
|
|
|
|
contents: {
|
|
xml: /\bxml\b/,
|
|
html: /\bhtml/,
|
|
json: /\bjson\b/
|
|
},
|
|
|
|
responseFields: {
|
|
xml: "responseXML",
|
|
text: "responseText",
|
|
json: "responseJSON"
|
|
},
|
|
|
|
// Data converters
|
|
// Keys separate source (or catchall "*") and destination types with a single space
|
|
converters: {
|
|
|
|
// Convert anything to text
|
|
"* text": String,
|
|
|
|
// Text to html (true = no transformation)
|
|
"text html": true,
|
|
|
|
// Evaluate text as a json expression
|
|
"text json": JSON.parse,
|
|
|
|
// 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: {
|
|
url: true,
|
|
context: true
|
|
}
|
|
},
|
|
|
|
// 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 ) {
|
|
return settings ?
|
|
|
|
// Building a settings object
|
|
ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
|
|
|
|
// Extending ajaxSettings
|
|
ajaxExtend( jQuery.ajaxSettings, target );
|
|
},
|
|
|
|
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 transport,
|
|
|
|
// URL without anti-cache param
|
|
cacheURL,
|
|
|
|
// Response headers
|
|
responseHeadersString,
|
|
responseHeaders,
|
|
|
|
// timeout handle
|
|
timeoutTimer,
|
|
|
|
// Url cleanup var
|
|
urlAnchor,
|
|
|
|
// Request state (becomes false upon send and true upon completion)
|
|
completed,
|
|
|
|
// To know if global events are to be dispatched
|
|
fireGlobals,
|
|
|
|
// Loop variable
|
|
i,
|
|
|
|
// uncached part of the url
|
|
uncached,
|
|
|
|
// Create the final options object
|
|
s = jQuery.ajaxSetup( {}, options ),
|
|
|
|
// Callbacks context
|
|
callbackContext = s.context || s,
|
|
|
|
// Context for global events is callbackContext if it is a DOM node or jQuery collection
|
|
globalEventContext = s.context &&
|
|
( callbackContext.nodeType || callbackContext.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 = {},
|
|
|
|
// Default abort message
|
|
strAbort = "canceled",
|
|
|
|
// Fake xhr
|
|
jqXHR = {
|
|
readyState: 0,
|
|
|
|
// Builds headers hashtable if needed
|
|
getResponseHeader: function( key ) {
|
|
var match;
|
|
if ( completed ) {
|
|
if ( !responseHeaders ) {
|
|
responseHeaders = {};
|
|
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
|
|
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
|
|
}
|
|
}
|
|
match = responseHeaders[ key.toLowerCase() ];
|
|
}
|
|
return match == null ? null : match;
|
|
},
|
|
|
|
// Raw string
|
|
getAllResponseHeaders: function() {
|
|
return completed ? responseHeadersString : null;
|
|
},
|
|
|
|
// Caches the header
|
|
setRequestHeader: function( name, value ) {
|
|
if ( completed == null ) {
|
|
name = requestHeadersNames[ name.toLowerCase() ] =
|
|
requestHeadersNames[ name.toLowerCase() ] || name;
|
|
requestHeaders[ name ] = value;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Overrides response content-type header
|
|
overrideMimeType: function( type ) {
|
|
if ( completed == null ) {
|
|
s.mimeType = type;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Status-dependent callbacks
|
|
statusCode: function( map ) {
|
|
var code;
|
|
if ( map ) {
|
|
if ( completed ) {
|
|
|
|
// Execute the appropriate callbacks
|
|
jqXHR.always( map[ jqXHR.status ] );
|
|
} else {
|
|
|
|
// Lazy-add the new callbacks in a way that preserves old ones
|
|
for ( code in map ) {
|
|
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Cancel the request
|
|
abort: function( statusText ) {
|
|
var finalText = statusText || strAbort;
|
|
if ( transport ) {
|
|
transport.abort( finalText );
|
|
}
|
|
done( 0, finalText );
|
|
return this;
|
|
}
|
|
};
|
|
|
|
// Attach deferreds
|
|
deferred.promise( jqXHR );
|
|
|
|
// Add protocol if not provided (prefilters might expect it)
|
|
// Handle falsy url in the settings object (#10093: consistency with old signature)
|
|
// We also use the url parameter if available
|
|
s.url = ( ( url || s.url || location.href ) + "" )
|
|
.replace( rprotocol, location.protocol + "//" );
|
|
|
|
// Alias method option to type as per ticket #12004
|
|
s.type = options.method || options.type || s.method || s.type;
|
|
|
|
// Extract dataTypes list
|
|
s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
|
|
|
|
// A cross-domain request is in order when the origin doesn't match the current origin.
|
|
if ( s.crossDomain == null ) {
|
|
urlAnchor = document.createElement( "a" );
|
|
|
|
// Support: IE <=8 - 11, Edge 12 - 13
|
|
// IE throws exception on accessing the href property if url is malformed,
|
|
// e.g. http://example.com:80x/
|
|
try {
|
|
urlAnchor.href = s.url;
|
|
|
|
// Support: IE <=8 - 11 only
|
|
// Anchor's host property isn't correctly set when s.url is relative
|
|
urlAnchor.href = urlAnchor.href;
|
|
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
|
|
urlAnchor.protocol + "//" + urlAnchor.host;
|
|
} catch ( e ) {
|
|
|
|
// If there is an error parsing the URL, assume it is crossDomain,
|
|
// it can be rejected by the transport if it is invalid
|
|
s.crossDomain = true;
|
|
}
|
|
}
|
|
|
|
// 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 ( completed ) {
|
|
return jqXHR;
|
|
}
|
|
|
|
// We can fire global events as of now if asked to
|
|
// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
|
|
fireGlobals = jQuery.event && s.global;
|
|
|
|
// Watch for a new set of requests
|
|
if ( fireGlobals && jQuery.active++ === 0 ) {
|
|
jQuery.event.trigger( "ajaxStart" );
|
|
}
|
|
|
|
// Uppercase the type
|
|
s.type = s.type.toUpperCase();
|
|
|
|
// Determine if request has content
|
|
s.hasContent = !rnoContent.test( s.type );
|
|
|
|
// Save the URL in case we're toying with the If-Modified-Since
|
|
// and/or If-None-Match header later on
|
|
// Remove hash to simplify url manipulation
|
|
cacheURL = s.url.replace( rhash, "" );
|
|
|
|
// More options handling for requests with no content
|
|
if ( !s.hasContent ) {
|
|
|
|
// Remember the hash so we can put it back
|
|
uncached = s.url.slice( cacheURL.length );
|
|
|
|
// If data is available, append data to url
|
|
if ( s.data ) {
|
|
cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
|
|
|
|
// #9682: remove data so that it's not used in an eventual retry
|
|
delete s.data;
|
|
}
|
|
|
|
// Add or update anti-cache param if needed
|
|
if ( s.cache === false ) {
|
|
cacheURL = cacheURL.replace( rantiCache, "$1" );
|
|
uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
|
|
}
|
|
|
|
// Put hash and anti-cache on the URL that will be requested (gh-1732)
|
|
s.url = cacheURL + uncached;
|
|
|
|
// Change '%20' to '+' if this is encoded form body content (gh-2658)
|
|
} else if ( s.data && s.processData &&
|
|
( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
|
|
s.data = s.data.replace( r20, "+" );
|
|
}
|
|
|
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
|
if ( s.ifModified ) {
|
|
if ( jQuery.lastModified[ cacheURL ] ) {
|
|
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
|
|
}
|
|
if ( jQuery.etag[ cacheURL ] ) {
|
|
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
|
|
}
|
|
}
|
|
|
|
// 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 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 || completed ) ) {
|
|
|
|
// Abort if not done already and return
|
|
return jqXHR.abort();
|
|
}
|
|
|
|
// Aborting is no longer a cancellation
|
|
strAbort = "abort";
|
|
|
|
// Install callbacks on deferreds
|
|
completeDeferred.add( s.complete );
|
|
jqXHR.done( s.success );
|
|
jqXHR.fail( s.error );
|
|
|
|
// 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 ] );
|
|
}
|
|
|
|
// If request was aborted inside ajaxSend, stop there
|
|
if ( completed ) {
|
|
return jqXHR;
|
|
}
|
|
|
|
// Timeout
|
|
if ( s.async && s.timeout > 0 ) {
|
|
timeoutTimer = window.setTimeout( function() {
|
|
jqXHR.abort( "timeout" );
|
|
}, s.timeout );
|
|
}
|
|
|
|
try {
|
|
completed = false;
|
|
transport.send( requestHeaders, done );
|
|
} catch ( e ) {
|
|
|
|
// Rethrow post-completion exceptions
|
|
if ( completed ) {
|
|
throw e;
|
|
}
|
|
|
|
// Propagate others as results
|
|
done( -1, e );
|
|
}
|
|
}
|
|
|
|
// Callback for when everything is done
|
|
function done( status, nativeStatusText, responses, headers ) {
|
|
var isSuccess, success, error, response, modified,
|
|
statusText = nativeStatusText;
|
|
|
|
// Ignore repeat invocations
|
|
if ( completed ) {
|
|
return;
|
|
}
|
|
|
|
completed = true;
|
|
|
|
// Clear timeout if it exists
|
|
if ( timeoutTimer ) {
|
|
window.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;
|
|
|
|
// Determine if successful
|
|
isSuccess = status >= 200 && status < 300 || status === 304;
|
|
|
|
// Get response data
|
|
if ( responses ) {
|
|
response = ajaxHandleResponses( s, jqXHR, responses );
|
|
}
|
|
|
|
// Convert no matter what (that way responseXXX fields are always set)
|
|
response = ajaxConvert( s, response, jqXHR, isSuccess );
|
|
|
|
// If successful, handle type chaining
|
|
if ( isSuccess ) {
|
|
|
|
// 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[ cacheURL ] = modified;
|
|
}
|
|
modified = jqXHR.getResponseHeader( "etag" );
|
|
if ( modified ) {
|
|
jQuery.etag[ cacheURL ] = modified;
|
|
}
|
|
}
|
|
|
|
// if no content
|
|
if ( status === 204 || s.type === "HEAD" ) {
|
|
statusText = "nocontent";
|
|
|
|
// if not modified
|
|
} else if ( status === 304 ) {
|
|
statusText = "notmodified";
|
|
|
|
// If we have data, let's convert it
|
|
} else {
|
|
statusText = response.state;
|
|
success = response.data;
|
|
error = response.error;
|
|
isSuccess = !error;
|
|
}
|
|
} else {
|
|
|
|
// Extract error from statusText and normalize for non-aborts
|
|
error = statusText;
|
|
if ( status || !statusText ) {
|
|
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( isSuccess ? "ajaxSuccess" : "ajaxError",
|
|
[ 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" );
|
|
}
|
|
}
|
|
}
|
|
|
|
return jqXHR;
|
|
},
|
|
|
|
getJSON: function( url, data, callback ) {
|
|
return jQuery.get( url, data, callback, "json" );
|
|
},
|
|
|
|
getScript: function( url, callback ) {
|
|
return jQuery.get( url, undefined, callback, "script" );
|
|
}
|
|
} );
|
|
|
|
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;
|
|
}
|
|
|
|
// The url can be an options object (which then must have .url)
|
|
return jQuery.ajax( jQuery.extend( {
|
|
url: url,
|
|
type: method,
|
|
dataType: type,
|
|
data: data,
|
|
success: callback
|
|
}, jQuery.isPlainObject( url ) && url ) );
|
|
};
|
|
} );
|
|
|
|
|
|
jQuery._evalUrl = function( url ) {
|
|
return jQuery.ajax( {
|
|
url: url,
|
|
|
|
// Make this explicit, since user can override this through ajaxSetup (#11264)
|
|
type: "GET",
|
|
dataType: "script",
|
|
cache: true,
|
|
async: false,
|
|
global: false,
|
|
"throws": true
|
|
} );
|
|
};
|
|
|
|
|
|
jQuery.fn.extend( {
|
|
wrapAll: function( html ) {
|
|
var wrap;
|
|
|
|
if ( this[ 0 ] ) {
|
|
if ( jQuery.isFunction( html ) ) {
|
|
html = html.call( this[ 0 ] );
|
|
}
|
|
|
|
// The elements to wrap the target around
|
|
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.firstElementChild ) {
|
|
elem = elem.firstElementChild;
|
|
}
|
|
|
|
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( selector ) {
|
|
this.parent( selector ).not( "body" ).each( function() {
|
|
jQuery( this ).replaceWith( this.childNodes );
|
|
} );
|
|
return this;
|
|
}
|
|
} );
|
|
|
|
|
|
jQuery.expr.pseudos.hidden = function( elem ) {
|
|
return !jQuery.expr.pseudos.visible( elem );
|
|
};
|
|
jQuery.expr.pseudos.visible = function( elem ) {
|
|
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
|
|
};
|
|
|
|
|
|
|
|
|
|
jQuery.ajaxSettings.xhr = function() {
|
|
try {
|
|
return new window.XMLHttpRequest();
|
|
} catch ( e ) {}
|
|
};
|
|
|
|
var xhrSuccessStatus = {
|
|
|
|
// File protocol always yields status code 0, assume 200
|
|
0: 200,
|
|
|
|
// Support: IE <=9 only
|
|
// #1450: sometimes IE returns 1223 when it should be 204
|
|
1223: 204
|
|
},
|
|
xhrSupported = jQuery.ajaxSettings.xhr();
|
|
|
|
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
|
|
support.ajax = xhrSupported = !!xhrSupported;
|
|
|
|
jQuery.ajaxTransport( function( options ) {
|
|
var callback, errorCallback;
|
|
|
|
// Cross domain only allowed if supported through XMLHttpRequest
|
|
if ( support.cors || xhrSupported && !options.crossDomain ) {
|
|
return {
|
|
send: function( headers, complete ) {
|
|
var i,
|
|
xhr = options.xhr();
|
|
|
|
xhr.open(
|
|
options.type,
|
|
options.url,
|
|
options.async,
|
|
options.username,
|
|
options.password
|
|
);
|
|
|
|
// Apply custom fields if provided
|
|
if ( options.xhrFields ) {
|
|
for ( i in options.xhrFields ) {
|
|
xhr[ i ] = options.xhrFields[ i ];
|
|
}
|
|
}
|
|
|
|
// Override mime type if needed
|
|
if ( options.mimeType && xhr.overrideMimeType ) {
|
|
xhr.overrideMimeType( options.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 ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
|
|
headers[ "X-Requested-With" ] = "XMLHttpRequest";
|
|
}
|
|
|
|
// Set headers
|
|
for ( i in headers ) {
|
|
xhr.setRequestHeader( i, headers[ i ] );
|
|
}
|
|
|
|
// Callback
|
|
callback = function( type ) {
|
|
return function() {
|
|
if ( callback ) {
|
|
callback = errorCallback = xhr.onload =
|
|
xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
|
|
|
|
if ( type === "abort" ) {
|
|
xhr.abort();
|
|
} else if ( type === "error" ) {
|
|
|
|
// Support: IE <=9 only
|
|
// On a manual native abort, IE9 throws
|
|
// errors on any property access that is not readyState
|
|
if ( typeof xhr.status !== "number" ) {
|
|
complete( 0, "error" );
|
|
} else {
|
|
complete(
|
|
|
|
// File: protocol always yields status 0; see #8605, #14207
|
|
xhr.status,
|
|
xhr.statusText
|
|
);
|
|
}
|
|
} else {
|
|
complete(
|
|
xhrSuccessStatus[ xhr.status ] || xhr.status,
|
|
xhr.statusText,
|
|
|
|
// Support: IE <=9 only
|
|
// IE9 has no XHR2 but throws on binary (trac-11426)
|
|
// For XHR2 non-text, let the caller handle it (gh-2498)
|
|
( xhr.responseType || "text" ) !== "text" ||
|
|
typeof xhr.responseText !== "string" ?
|
|
{ binary: xhr.response } :
|
|
{ text: xhr.responseText },
|
|
xhr.getAllResponseHeaders()
|
|
);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
// Listen to events
|
|
xhr.onload = callback();
|
|
errorCallback = xhr.onerror = callback( "error" );
|
|
|
|
// Support: IE 9 only
|
|
// Use onreadystatechange to replace onabort
|
|
// to handle uncaught aborts
|
|
if ( xhr.onabort !== undefined ) {
|
|
xhr.onabort = errorCallback;
|
|
} else {
|
|
xhr.onreadystatechange = function() {
|
|
|
|
// Check readyState before timeout as it changes
|
|
if ( xhr.readyState === 4 ) {
|
|
|
|
// Allow onerror to be called first,
|
|
// but that will not handle a native abort
|
|
// Also, save errorCallback to a variable
|
|
// as xhr.onerror cannot be accessed
|
|
window.setTimeout( function() {
|
|
if ( callback ) {
|
|
errorCallback();
|
|
}
|
|
} );
|
|
}
|
|
};
|
|
}
|
|
|
|
// Create the abort callback
|
|
callback = callback( "abort" );
|
|
|
|
try {
|
|
|
|
// Do send the request (this may raise an exception)
|
|
xhr.send( options.hasContent && options.data || null );
|
|
} catch ( e ) {
|
|
|
|
// #14683: Only rethrow if this hasn't been notified as an error yet
|
|
if ( callback ) {
|
|
throw e;
|
|
}
|
|
}
|
|
},
|
|
|
|
abort: function() {
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
|
|
jQuery.ajaxPrefilter( function( s ) {
|
|
if ( s.crossDomain ) {
|
|
s.contents.script = false;
|
|
}
|
|
} );
|
|
|
|
// Install script dataType
|
|
jQuery.ajaxSetup( {
|
|
accepts: {
|
|
script: "text/javascript, application/javascript, " +
|
|
"application/ecmascript, application/x-ecmascript"
|
|
},
|
|
contents: {
|
|
script: /\b(?:java|ecma)script\b/
|
|
},
|
|
converters: {
|
|
"text script": function( text ) {
|
|
jQuery.globalEval( text );
|
|
return text;
|
|
}
|
|
}
|
|
} );
|
|
|
|
// Handle cache's special case and crossDomain
|
|
jQuery.ajaxPrefilter( "script", function( s ) {
|
|
if ( s.cache === undefined ) {
|
|
s.cache = false;
|
|
}
|
|
if ( s.crossDomain ) {
|
|
s.type = "GET";
|
|
}
|
|
} );
|
|
|
|
// Bind script tag hack transport
|
|
jQuery.ajaxTransport( "script", function( s ) {
|
|
|
|
// This transport only deals with cross domain requests
|
|
if ( s.crossDomain ) {
|
|
var script, callback;
|
|
return {
|
|
send: function( _, complete ) {
|
|
script = jQuery( "<script>" ).prop( {
|
|
charset: s.scriptCharset,
|
|
src: s.url
|
|
} ).on(
|
|
"load error",
|
|
callback = function( evt ) {
|
|
script.remove();
|
|
callback = null;
|
|
if ( evt ) {
|
|
complete( evt.type === "error" ? 404 : 200, evt.type );
|
|
}
|
|
}
|
|
);
|
|
|
|
// Use native DOM manipulation to avoid our domManip AJAX trickery
|
|
document.head.appendChild( script[ 0 ] );
|
|
},
|
|
abort: function() {
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
var oldCallbacks = [],
|
|
rjsonp = /(=)\?(?=&|$)|\?\?/;
|
|
|
|
// 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,
|
|
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
|
|
"url" :
|
|
typeof s.data === "string" &&
|
|
( s.contentType || "" )
|
|
.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
|
|
rjsonp.test( s.data ) && "data"
|
|
);
|
|
|
|
// Handle iff the expected data type is "jsonp" or we have a parameter to set
|
|
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
|
|
|
|
// Get callback name, remembering preexisting value associated with it
|
|
callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
|
|
s.jsonpCallback() :
|
|
s.jsonpCallback;
|
|
|
|
// Insert callback into url or form data
|
|
if ( jsonProp ) {
|
|
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
|
|
} else if ( s.jsonp !== false ) {
|
|
s.url += ( rquery.test( s.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
|
|
overwritten = window[ callbackName ];
|
|
window[ callbackName ] = function() {
|
|
responseContainer = arguments;
|
|
};
|
|
|
|
// Clean-up function (fires after converters)
|
|
jqXHR.always( function() {
|
|
|
|
// If previous value didn't exist - remove it
|
|
if ( overwritten === undefined ) {
|
|
jQuery( window ).removeProp( callbackName );
|
|
|
|
// Otherwise restore preexisting value
|
|
} else {
|
|
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";
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Support: Safari 8 only
|
|
// In Safari 8 documents created via document.implementation.createHTMLDocument
|
|
// collapse sibling forms: the second one becomes a child of the first one.
|
|
// Because of that, this security measure has to be disabled in Safari 8.
|
|
// https://bugs.webkit.org/show_bug.cgi?id=137337
|
|
support.createHTMLDocument = ( function() {
|
|
var body = document.implementation.createHTMLDocument( "" ).body;
|
|
body.innerHTML = "<form></form><form></form>";
|
|
return body.childNodes.length === 2;
|
|
} )();
|
|
|
|
|
|
// Argument "data" should be string of html
|
|
// context (optional): If specified, the fragment will be created in this context,
|
|
// defaults to document
|
|
// keepScripts (optional): If true, will include scripts passed in the html string
|
|
jQuery.parseHTML = function( data, context, keepScripts ) {
|
|
if ( typeof data !== "string" ) {
|
|
return [];
|
|
}
|
|
if ( typeof context === "boolean" ) {
|
|
keepScripts = context;
|
|
context = false;
|
|
}
|
|
|
|
var base, parsed, scripts;
|
|
|
|
if ( !context ) {
|
|
|
|
// Stop scripts or inline event handlers from being executed immediately
|
|
// by using document.implementation
|
|
if ( support.createHTMLDocument ) {
|
|
context = document.implementation.createHTMLDocument( "" );
|
|
|
|
// Set the base href for the created document
|
|
// so any parsed elements with URLs
|
|
// are based on the document's URL (gh-2965)
|
|
base = context.createElement( "base" );
|
|
base.href = document.location.href;
|
|
context.head.appendChild( base );
|
|
} else {
|
|
context = document;
|
|
}
|
|
}
|
|
|
|
parsed = rsingleTag.exec( data );
|
|
scripts = !keepScripts && [];
|
|
|
|
// Single tag
|
|
if ( parsed ) {
|
|
return [ context.createElement( parsed[ 1 ] ) ];
|
|
}
|
|
|
|
parsed = buildFragment( [ data ], context, scripts );
|
|
|
|
if ( scripts && scripts.length ) {
|
|
jQuery( scripts ).remove();
|
|
}
|
|
|
|
return jQuery.merge( [], parsed.childNodes );
|
|
};
|
|
|
|
|
|
/**
|
|
* Load a url into a page
|
|
*/
|
|
jQuery.fn.load = function( url, params, callback ) {
|
|
var selector, type, response,
|
|
self = this,
|
|
off = url.indexOf( " " );
|
|
|
|
if ( off > -1 ) {
|
|
selector = stripAndCollapse( url.slice( off ) );
|
|
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";
|
|
}
|
|
|
|
// If we have elements to modify, make the request
|
|
if ( self.length > 0 ) {
|
|
jQuery.ajax( {
|
|
url: url,
|
|
|
|
// If "type" variable is undefined, then "GET" method will be used.
|
|
// Make value of this field explicit since
|
|
// user can override it through ajaxSetup method
|
|
type: type || "GET",
|
|
dataType: "html",
|
|
data: params
|
|
} ).done( function( responseText ) {
|
|
|
|
// Save response for use in complete callback
|
|
response = arguments;
|
|
|
|
self.html( selector ?
|
|
|
|
// If a selector was specified, locate the right elements in a dummy div
|
|
// Exclude scripts to avoid IE 'Permission Denied' errors
|
|
jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
|
|
|
|
// Otherwise use the full result
|
|
responseText );
|
|
|
|
// If the request succeeds, this function gets "data", "status", "jqXHR"
|
|
// but they are ignored because response was set above.
|
|
// If it fails, this function gets "jqXHR", "status", "error"
|
|
} ).always( callback && function( jqXHR, status ) {
|
|
self.each( function() {
|
|
callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
|
|
} );
|
|
} );
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
|
|
|
|
|
|
// Attach a bunch of functions for handling common AJAX events
|
|
jQuery.each( [
|
|
"ajaxStart",
|
|
"ajaxStop",
|
|
"ajaxComplete",
|
|
"ajaxError",
|
|
"ajaxSuccess",
|
|
"ajaxSend"
|
|
], function( i, type ) {
|
|
jQuery.fn[ type ] = function( fn ) {
|
|
return this.on( type, fn );
|
|
};
|
|
} );
|
|
|
|
|
|
|
|
|
|
jQuery.expr.pseudos.animated = function( elem ) {
|
|
return jQuery.grep( jQuery.timers, function( fn ) {
|
|
return elem === fn.elem;
|
|
} ).length;
|
|
};
|
|
|
|
|
|
|
|
|
|
jQuery.offset = {
|
|
setOffset: function( elem, options, i ) {
|
|
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
|
|
position = jQuery.css( elem, "position" ),
|
|
curElem = jQuery( elem ),
|
|
props = {};
|
|
|
|
// Set position first, in-case top/left are set even on static elem
|
|
if ( position === "static" ) {
|
|
elem.style.position = "relative";
|
|
}
|
|
|
|
curOffset = curElem.offset();
|
|
curCSSTop = jQuery.css( elem, "top" );
|
|
curCSSLeft = jQuery.css( elem, "left" );
|
|
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
|
|
( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
|
|
|
|
// 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 ) ) {
|
|
|
|
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
|
|
options = options.call( elem, i, jQuery.extend( {}, 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( {
|
|
offset: function( options ) {
|
|
|
|
// Preserve chaining for setter
|
|
if ( arguments.length ) {
|
|
return options === undefined ?
|
|
this :
|
|
this.each( function( i ) {
|
|
jQuery.offset.setOffset( this, options, i );
|
|
} );
|
|
}
|
|
|
|
var doc, docElem, rect, win,
|
|
elem = this[ 0 ];
|
|
|
|
if ( !elem ) {
|
|
return;
|
|
}
|
|
|
|
// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
|
|
// Support: IE <=11 only
|
|
// Running getBoundingClientRect on a
|
|
// disconnected node in IE throws an error
|
|
if ( !elem.getClientRects().length ) {
|
|
return { top: 0, left: 0 };
|
|
}
|
|
|
|
rect = elem.getBoundingClientRect();
|
|
|
|
doc = elem.ownerDocument;
|
|
docElem = doc.documentElement;
|
|
win = doc.defaultView;
|
|
|
|
return {
|
|
top: rect.top + win.pageYOffset - docElem.clientTop,
|
|
left: rect.left + win.pageXOffset - docElem.clientLeft
|
|
};
|
|
},
|
|
|
|
position: function() {
|
|
if ( !this[ 0 ] ) {
|
|
return;
|
|
}
|
|
|
|
var offsetParent, offset,
|
|
elem = this[ 0 ],
|
|
parentOffset = { top: 0, left: 0 };
|
|
|
|
// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
|
|
// because it is its only offset parent
|
|
if ( jQuery.css( elem, "position" ) === "fixed" ) {
|
|
|
|
// Assume getBoundingClientRect is there when computed position is fixed
|
|
offset = elem.getBoundingClientRect();
|
|
|
|
} else {
|
|
|
|
// Get *real* offsetParent
|
|
offsetParent = this.offsetParent();
|
|
|
|
// Get correct offsets
|
|
offset = this.offset();
|
|
if ( !nodeName( offsetParent[ 0 ], "html" ) ) {
|
|
parentOffset = offsetParent.offset();
|
|
}
|
|
|
|
// Add offsetParent borders
|
|
parentOffset = {
|
|
top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ),
|
|
left: parentOffset.left + jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true )
|
|
};
|
|
}
|
|
|
|
// Subtract parent offsets and element margins
|
|
return {
|
|
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
|
|
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
|
|
};
|
|
},
|
|
|
|
// This method will return documentElement in the following cases:
|
|
// 1) For the element inside the iframe without offsetParent, this method will return
|
|
// documentElement of the parent window
|
|
// 2) For the hidden or detached element
|
|
// 3) For body or html element, i.e. in case of the html node - it will return itself
|
|
//
|
|
// but those exceptions were never presented as a real life use-cases
|
|
// and might be considered as more preferable results.
|
|
//
|
|
// This logic, however, is not guaranteed and can change at any point in the future
|
|
offsetParent: function() {
|
|
return this.map( function() {
|
|
var offsetParent = this.offsetParent;
|
|
|
|
while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
|
|
offsetParent = offsetParent.offsetParent;
|
|
}
|
|
|
|
return offsetParent || documentElement;
|
|
} );
|
|
}
|
|
} );
|
|
|
|
// Create scrollLeft and scrollTop methods
|
|
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
|
|
var top = "pageYOffset" === prop;
|
|
|
|
jQuery.fn[ method ] = function( val ) {
|
|
return access( this, function( elem, method, val ) {
|
|
|
|
// Coalesce documents and windows
|
|
var win;
|
|
if ( jQuery.isWindow( elem ) ) {
|
|
win = elem;
|
|
} else if ( elem.nodeType === 9 ) {
|
|
win = elem.defaultView;
|
|
}
|
|
|
|
if ( val === undefined ) {
|
|
return win ? win[ prop ] : elem[ method ];
|
|
}
|
|
|
|
if ( win ) {
|
|
win.scrollTo(
|
|
!top ? val : win.pageXOffset,
|
|
top ? val : win.pageYOffset
|
|
);
|
|
|
|
} else {
|
|
elem[ method ] = val;
|
|
}
|
|
}, method, val, arguments.length );
|
|
};
|
|
} );
|
|
|
|
// Support: Safari <=7 - 9.1, Chrome <=37 - 49
|
|
// Add the top/left cssHooks using jQuery.fn.position
|
|
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
|
|
// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
|
|
// getComputedStyle returns percent when specified for top/left/bottom/right;
|
|
// rather than make the css module depend on the offset module, just check for it here
|
|
jQuery.each( [ "top", "left" ], function( i, prop ) {
|
|
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
|
|
function( elem, computed ) {
|
|
if ( computed ) {
|
|
computed = curCSS( elem, prop );
|
|
|
|
// If curCSS returns percentage, fallback to offset
|
|
return rnumnonpx.test( computed ) ?
|
|
jQuery( elem ).position()[ prop ] + "px" :
|
|
computed;
|
|
}
|
|
}
|
|
);
|
|
} );
|
|
|
|
|
|
// 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 access( this, function( elem, type, value ) {
|
|
var doc;
|
|
|
|
if ( jQuery.isWindow( elem ) ) {
|
|
|
|
// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
|
|
return funcName.indexOf( "outer" ) === 0 ?
|
|
elem[ "inner" + name ] :
|
|
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
|
|
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, extra ) :
|
|
|
|
// Set width or height on the element
|
|
jQuery.style( elem, type, value, extra );
|
|
}, type, chainable ? margin : undefined, chainable );
|
|
};
|
|
} );
|
|
} );
|
|
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
bind: function( types, data, fn ) {
|
|
return this.on( types, null, data, fn );
|
|
},
|
|
unbind: function( types, fn ) {
|
|
return this.off( types, null, fn );
|
|
},
|
|
|
|
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 );
|
|
},
|
|
holdReady: function( hold ) {
|
|
if ( hold ) {
|
|
jQuery.readyWait++;
|
|
} else {
|
|
jQuery.ready( true );
|
|
}
|
|
}
|
|
} );
|
|
|
|
jQuery.isArray = Array.isArray;
|
|
jQuery.parseJSON = JSON.parse;
|
|
jQuery.nodeName = nodeName;
|
|
|
|
|
|
|
|
|
|
// Register as a named AMD module, since jQuery can be concatenated with other
|
|
// files that may use define, but not via 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.
|
|
|
|
// Note that for maximum portability, libraries that are not jQuery should
|
|
// declare themselves as anonymous modules, and avoid setting a global if an
|
|
// AMD loader is present. jQuery is a special case. For more information, see
|
|
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
|
|
|
|
if ( typeof define === "function" && define.amd ) {
|
|
define( "jquery", [], function() {
|
|
return jQuery;
|
|
} );
|
|
}
|
|
|
|
|
|
|
|
|
|
var
|
|
|
|
// Map over jQuery in case of overwrite
|
|
_jQuery = window.jQuery,
|
|
|
|
// Map over the $ in case of overwrite
|
|
_$ = window.$;
|
|
|
|
jQuery.noConflict = function( deep ) {
|
|
if ( window.$ === jQuery ) {
|
|
window.$ = _$;
|
|
}
|
|
|
|
if ( deep && window.jQuery === jQuery ) {
|
|
window.jQuery = _jQuery;
|
|
}
|
|
|
|
return jQuery;
|
|
};
|
|
|
|
// Expose jQuery and $ identifiers, even in AMD
|
|
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
|
|
// and CommonJS for browser emulators (#13566)
|
|
if ( !noGlobal ) {
|
|
window.jQuery = window.$ = jQuery;
|
|
}
|
|
|
|
|
|
|
|
|
|
return jQuery;
|
|
} );
|
|
|
|
/**
|
|
* bootbox.js [v4.4.0]
|
|
*
|
|
* http://bootboxjs.com/license.txt
|
|
*/
|
|
|
|
// @see https://github.com/makeusabrew/bootbox/issues/180
|
|
// @see https://github.com/makeusabrew/bootbox/issues/186
|
|
(function (root, factory) {
|
|
|
|
"use strict";
|
|
if (typeof define === "function" && define.amd) {
|
|
// AMD. Register as an anonymous module.
|
|
define(["resources/assets/js/001-jquery"], factory);
|
|
} else if (typeof exports === "object") {
|
|
// Node. Does not work with strict CommonJS, but
|
|
// only CommonJS-like environments that support module.exports,
|
|
// like Node.
|
|
module.exports = factory(require("resources/assets/js/001-jquery"));
|
|
} else {
|
|
// Browser globals (root is window)
|
|
root.bootbox = factory(root.jQuery);
|
|
}
|
|
|
|
}(this, function init($, undefined) {
|
|
|
|
"use strict";
|
|
|
|
// the base DOM structure needed to create a modal
|
|
var templates = {
|
|
dialog:
|
|
"<div class='bootbox modal' tabindex='-1' role='dialog'>" +
|
|
"<div class='modal-dialog'>" +
|
|
"<div class='modal-content'>" +
|
|
"<div class='modal-body'><div class='bootbox-body'></div></div>" +
|
|
"</div>" +
|
|
"</div>" +
|
|
"</div>",
|
|
header:
|
|
"<div class='modal-header'>" +
|
|
"<h4 class='modal-title'></h4>" +
|
|
"</div>",
|
|
footer:
|
|
"<div class='modal-footer'></div>",
|
|
closeButton:
|
|
"<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>×</button>",
|
|
form:
|
|
"<form class='bootbox-form'></form>",
|
|
inputs: {
|
|
text:
|
|
"<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",
|
|
textarea:
|
|
"<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",
|
|
email:
|
|
"<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",
|
|
select:
|
|
"<select class='bootbox-input bootbox-input-select form-control'></select>",
|
|
checkbox:
|
|
"<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",
|
|
date:
|
|
"<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",
|
|
time:
|
|
"<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",
|
|
number:
|
|
"<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",
|
|
password:
|
|
"<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"
|
|
}
|
|
};
|
|
|
|
var defaults = {
|
|
// default language
|
|
locale: "en",
|
|
// show backdrop or not. Default to static so user has to interact with dialog
|
|
backdrop: "static",
|
|
// animate the modal in/out
|
|
animate: true,
|
|
// additional class string applied to the top level dialog
|
|
className: null,
|
|
// whether or not to include a close button
|
|
closeButton: true,
|
|
// show the dialog immediately by default
|
|
show: true,
|
|
// dialog container
|
|
container: "body"
|
|
};
|
|
|
|
// our public object; augmented after our private API
|
|
var exports = {};
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
function _t(key) {
|
|
var locale = locales[defaults.locale];
|
|
return locale ? locale[key] : locales.en[key];
|
|
}
|
|
|
|
function processCallback(e, dialog, callback) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
// by default we assume a callback will get rid of the dialog,
|
|
// although it is given the opportunity to override this
|
|
|
|
// so, if the callback can be invoked and it *explicitly returns false*
|
|
// then we'll set a flag to keep the dialog active...
|
|
var preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false;
|
|
|
|
// ... otherwise we'll bin it
|
|
if (!preserveDialog) {
|
|
dialog.modal("hide");
|
|
}
|
|
}
|
|
|
|
function getKeyLength(obj) {
|
|
// @TODO defer to Object.keys(x).length if available?
|
|
var k, t = 0;
|
|
for (k in obj) {
|
|
t ++;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
function each(collection, iterator) {
|
|
var index = 0;
|
|
$.each(collection, function(key, value) {
|
|
iterator(key, value, index++);
|
|
});
|
|
}
|
|
|
|
function sanitize(options) {
|
|
var buttons;
|
|
var total;
|
|
|
|
if (typeof options !== "object") {
|
|
throw new Error("Please supply an object of options");
|
|
}
|
|
|
|
if (!options.message) {
|
|
throw new Error("Please specify a message");
|
|
}
|
|
|
|
// make sure any supplied options take precedence over defaults
|
|
options = $.extend({}, defaults, options);
|
|
|
|
if (!options.buttons) {
|
|
options.buttons = {};
|
|
}
|
|
|
|
buttons = options.buttons;
|
|
|
|
total = getKeyLength(buttons);
|
|
|
|
each(buttons, function(key, button, index) {
|
|
|
|
if ($.isFunction(button)) {
|
|
// short form, assume value is our callback. Since button
|
|
// isn't an object it isn't a reference either so re-assign it
|
|
button = buttons[key] = {
|
|
callback: button
|
|
};
|
|
}
|
|
|
|
// before any further checks make sure by now button is the correct type
|
|
if ($.type(button) !== "object") {
|
|
throw new Error("button with key " + key + " must be an object");
|
|
}
|
|
|
|
if (!button.label) {
|
|
// the lack of an explicit label means we'll assume the key is good enough
|
|
button.label = key;
|
|
}
|
|
|
|
if (!button.className) {
|
|
if (total <= 2 && index === total-1) {
|
|
// always add a primary to the main option in a two-button dialog
|
|
button.className = "btn-primary";
|
|
} else {
|
|
button.className = "btn-secondary";
|
|
}
|
|
}
|
|
});
|
|
|
|
return options;
|
|
}
|
|
|
|
/**
|
|
* map a flexible set of arguments into a single returned object
|
|
* if args.length is already one just return it, otherwise
|
|
* use the properties argument to map the unnamed args to
|
|
* object properties
|
|
* so in the latter case:
|
|
* mapArguments(["foo", $.noop], ["message", "callback"])
|
|
* -> { message: "foo", callback: $.noop }
|
|
*/
|
|
function mapArguments(args, properties) {
|
|
var argn = args.length;
|
|
var options = {};
|
|
|
|
if (argn < 1 || argn > 2) {
|
|
throw new Error("Invalid argument length");
|
|
}
|
|
|
|
if (argn === 2 || typeof args[0] === "string") {
|
|
options[properties[0]] = args[0];
|
|
options[properties[1]] = args[1];
|
|
} else {
|
|
options = args[0];
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
/**
|
|
* merge a set of default dialog options with user supplied arguments
|
|
*/
|
|
function mergeArguments(defaults, args, properties) {
|
|
return $.extend(
|
|
// deep merge
|
|
true,
|
|
// ensure the target is an empty, unreferenced object
|
|
{},
|
|
// the base options object for this type of dialog (often just buttons)
|
|
defaults,
|
|
// args could be an object or array; if it's an array properties will
|
|
// map it to a proper options object
|
|
mapArguments(
|
|
args,
|
|
properties
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* this entry-level method makes heavy use of composition to take a simple
|
|
* range of inputs and return valid options suitable for passing to bootbox.dialog
|
|
*/
|
|
function mergeDialogOptions(className, labels, properties, args) {
|
|
// build up a base set of dialog properties
|
|
var baseOptions = {
|
|
className: "bootbox-" + className,
|
|
buttons: createLabels.apply(null, labels)
|
|
};
|
|
|
|
// ensure the buttons properties generated, *after* merging
|
|
// with user args are still valid against the supplied labels
|
|
return validateButtons(
|
|
// merge the generated base properties with user supplied arguments
|
|
mergeArguments(
|
|
baseOptions,
|
|
args,
|
|
// if args.length > 1, properties specify how each arg maps to an object key
|
|
properties
|
|
),
|
|
labels
|
|
);
|
|
}
|
|
|
|
/**
|
|
* from a given list of arguments return a suitable object of button labels
|
|
* all this does is normalise the given labels and translate them where possible
|
|
* e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" }
|
|
*/
|
|
function createLabels() {
|
|
var buttons = {};
|
|
|
|
for (var i = 0, j = arguments.length; i < j; i++) {
|
|
var argument = arguments[i];
|
|
var key = argument.toLowerCase();
|
|
var value = argument.toUpperCase();
|
|
|
|
buttons[key] = {
|
|
label: _t(value)
|
|
};
|
|
}
|
|
|
|
return buttons;
|
|
}
|
|
|
|
function validateButtons(options, buttons) {
|
|
var allowedButtons = {};
|
|
each(buttons, function(key, value) {
|
|
allowedButtons[value] = true;
|
|
});
|
|
|
|
each(options.buttons, function(key) {
|
|
if (allowedButtons[key] === undefined) {
|
|
throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")");
|
|
}
|
|
});
|
|
|
|
return options;
|
|
}
|
|
|
|
exports.alert = function() {
|
|
var options;
|
|
|
|
options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments);
|
|
|
|
if (options.callback && !$.isFunction(options.callback)) {
|
|
throw new Error("alert requires callback property to be a function when provided");
|
|
}
|
|
|
|
/**
|
|
* overrides
|
|
*/
|
|
options.buttons.ok.callback = options.onEscape = function() {
|
|
if ($.isFunction(options.callback)) {
|
|
return options.callback.call(this);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
return exports.dialog(options);
|
|
};
|
|
|
|
exports.confirm = function() {
|
|
var options;
|
|
|
|
options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments);
|
|
|
|
/**
|
|
* overrides; undo anything the user tried to set they shouldn't have
|
|
*/
|
|
options.buttons.cancel.callback = options.onEscape = function() {
|
|
return options.callback.call(this, false);
|
|
};
|
|
|
|
options.buttons.confirm.callback = function() {
|
|
return options.callback.call(this, true);
|
|
};
|
|
|
|
// confirm specific validation
|
|
if (!$.isFunction(options.callback)) {
|
|
throw new Error("confirm requires a callback");
|
|
}
|
|
|
|
return exports.dialog(options);
|
|
};
|
|
|
|
exports.prompt = function() {
|
|
var options;
|
|
var defaults;
|
|
var dialog;
|
|
var form;
|
|
var input;
|
|
var shouldShow;
|
|
var inputOptions;
|
|
|
|
// we have to create our form first otherwise
|
|
// its value is undefined when gearing up our options
|
|
// @TODO this could be solved by allowing message to
|
|
// be a function instead...
|
|
form = $(templates.form);
|
|
|
|
// prompt defaults are more complex than others in that
|
|
// users can override more defaults
|
|
// @TODO I don't like that prompt has to do a lot of heavy
|
|
// lifting which mergeDialogOptions can *almost* support already
|
|
// just because of 'value' and 'inputType' - can we refactor?
|
|
defaults = {
|
|
className: "bootbox-prompt",
|
|
buttons: createLabels("cancel", "confirm"),
|
|
value: "",
|
|
inputType: "text"
|
|
};
|
|
|
|
options = validateButtons(
|
|
mergeArguments(defaults, arguments, ["title", "callback"]),
|
|
["cancel", "confirm"]
|
|
);
|
|
|
|
// capture the user's show value; we always set this to false before
|
|
// spawning the dialog to give us a chance to attach some handlers to
|
|
// it, but we need to make sure we respect a preference not to show it
|
|
shouldShow = (options.show === undefined) ? true : options.show;
|
|
|
|
/**
|
|
* overrides; undo anything the user tried to set they shouldn't have
|
|
*/
|
|
options.message = form;
|
|
|
|
options.buttons.cancel.callback = options.onEscape = function() {
|
|
return options.callback.call(this, null);
|
|
};
|
|
|
|
options.buttons.confirm.callback = function() {
|
|
var value;
|
|
|
|
switch (options.inputType) {
|
|
case "text":
|
|
case "textarea":
|
|
case "email":
|
|
case "select":
|
|
case "date":
|
|
case "time":
|
|
case "number":
|
|
case "password":
|
|
value = input.val();
|
|
break;
|
|
|
|
case "checkbox":
|
|
var checkedItems = input.find("input:checked");
|
|
|
|
// we assume that checkboxes are always multiple,
|
|
// hence we default to an empty array
|
|
value = [];
|
|
|
|
each(checkedItems, function(_, item) {
|
|
value.push($(item).val());
|
|
});
|
|
break;
|
|
}
|
|
|
|
return options.callback.call(this, value);
|
|
};
|
|
|
|
options.show = false;
|
|
|
|
// prompt specific validation
|
|
if (!options.title) {
|
|
throw new Error("prompt requires a title");
|
|
}
|
|
|
|
if (!$.isFunction(options.callback)) {
|
|
throw new Error("prompt requires a callback");
|
|
}
|
|
|
|
if (!templates.inputs[options.inputType]) {
|
|
throw new Error("invalid prompt type");
|
|
}
|
|
|
|
// create the input based on the supplied type
|
|
input = $(templates.inputs[options.inputType]);
|
|
|
|
switch (options.inputType) {
|
|
case "text":
|
|
case "textarea":
|
|
case "email":
|
|
case "date":
|
|
case "time":
|
|
case "number":
|
|
case "password":
|
|
input.val(options.value);
|
|
break;
|
|
|
|
case "select":
|
|
var groups = {};
|
|
inputOptions = options.inputOptions || [];
|
|
|
|
if (!$.isArray(inputOptions)) {
|
|
throw new Error("Please pass an array of input options");
|
|
}
|
|
|
|
if (!inputOptions.length) {
|
|
throw new Error("prompt with select requires options");
|
|
}
|
|
|
|
each(inputOptions, function(_, option) {
|
|
|
|
// assume the element to attach to is the input...
|
|
var elem = input;
|
|
|
|
if (option.value === undefined || option.text === undefined) {
|
|
throw new Error("given options in wrong format");
|
|
}
|
|
|
|
// ... but override that element if this option sits in a group
|
|
|
|
if (option.group) {
|
|
// initialise group if necessary
|
|
if (!groups[option.group]) {
|
|
groups[option.group] = $("<optgroup/>").attr("label", option.group);
|
|
}
|
|
|
|
elem = groups[option.group];
|
|
}
|
|
|
|
elem.append("<option value='" + option.value + "'>" + option.text + "</option>");
|
|
});
|
|
|
|
each(groups, function(_, group) {
|
|
input.append(group);
|
|
});
|
|
|
|
// safe to set a select's value as per a normal input
|
|
input.val(options.value);
|
|
break;
|
|
|
|
case "checkbox":
|
|
var values = $.isArray(options.value) ? options.value : [options.value];
|
|
inputOptions = options.inputOptions || [];
|
|
|
|
if (!inputOptions.length) {
|
|
throw new Error("prompt with checkbox requires options");
|
|
}
|
|
|
|
if (!inputOptions[0].value || !inputOptions[0].text) {
|
|
throw new Error("given options in wrong format");
|
|
}
|
|
|
|
// checkboxes have to nest within a containing element, so
|
|
// they break the rules a bit and we end up re-assigning
|
|
// our 'input' element to this container instead
|
|
input = $("<div/>");
|
|
|
|
each(inputOptions, function(_, option) {
|
|
var checkbox = $(templates.inputs[options.inputType]);
|
|
|
|
checkbox.find("input").attr("value", option.value);
|
|
checkbox.find("label").append(option.text);
|
|
|
|
// we've ensured values is an array so we can always iterate over it
|
|
each(values, function(_, value) {
|
|
if (value === option.value) {
|
|
checkbox.find("input").prop("checked", true);
|
|
}
|
|
});
|
|
|
|
input.append(checkbox);
|
|
});
|
|
break;
|
|
}
|
|
|
|
// @TODO provide an attributes option instead
|
|
// and simply map that as keys: vals
|
|
if (options.placeholder) {
|
|
input.attr("placeholder", options.placeholder);
|
|
}
|
|
|
|
if (options.pattern) {
|
|
input.attr("pattern", options.pattern);
|
|
}
|
|
|
|
if (options.maxlength) {
|
|
input.attr("maxlength", options.maxlength);
|
|
}
|
|
|
|
// now place it in our form
|
|
form.append(input);
|
|
|
|
form.on("submit", function(e) {
|
|
e.preventDefault();
|
|
// Fix for SammyJS (or similar JS routing library) hijacking the form post.
|
|
e.stopPropagation();
|
|
// @TODO can we actually click *the* button object instead?
|
|
// e.g. buttons.confirm.click() or similar
|
|
dialog.find(".btn-primary").click();
|
|
});
|
|
|
|
dialog = exports.dialog(options);
|
|
|
|
// clear the existing handler focusing the submit button...
|
|
dialog.off("shown.bs.modal");
|
|
|
|
// ...and replace it with one focusing our input, if possible
|
|
dialog.on("shown.bs.modal", function() {
|
|
// need the closure here since input isn't
|
|
// an object otherwise
|
|
input.focus();
|
|
});
|
|
|
|
if (shouldShow === true) {
|
|
dialog.modal("show");
|
|
}
|
|
|
|
return dialog;
|
|
};
|
|
|
|
exports.dialog = function(options) {
|
|
options = sanitize(options);
|
|
|
|
var dialog = $(templates.dialog);
|
|
var innerDialog = dialog.find(".modal-dialog");
|
|
var body = dialog.find(".modal-body");
|
|
var buttons = options.buttons;
|
|
var buttonStr = "";
|
|
var callbacks = {
|
|
onEscape: options.onEscape
|
|
};
|
|
|
|
if ($.fn.modal === undefined) {
|
|
throw new Error(
|
|
"$.fn.modal is not defined; please double check you have included " +
|
|
"the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ " +
|
|
"for more details."
|
|
);
|
|
}
|
|
|
|
each(buttons, function(key, button) {
|
|
|
|
// @TODO I don't like this string appending to itself; bit dirty. Needs reworking
|
|
// can we just build up button elements instead? slower but neater. Then button
|
|
// can just become a template too
|
|
buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
|
|
callbacks[key] = button.callback;
|
|
});
|
|
|
|
body.find(".bootbox-body").html(options.message);
|
|
|
|
if (options.animate === true) {
|
|
dialog.addClass("fade");
|
|
}
|
|
|
|
if (options.className) {
|
|
dialog.addClass(options.className);
|
|
}
|
|
|
|
if (options.size === "large") {
|
|
innerDialog.addClass("modal-lg");
|
|
} else if (options.size === "small") {
|
|
innerDialog.addClass("modal-sm");
|
|
}
|
|
|
|
if (options.title) {
|
|
body.before(templates.header);
|
|
}
|
|
|
|
if (options.closeButton) {
|
|
var closeButton = $(templates.closeButton);
|
|
|
|
if (options.title) {
|
|
dialog.find(".modal-header").prepend(closeButton);
|
|
} else {
|
|
closeButton.css("margin-top", "-10px").prependTo(body);
|
|
}
|
|
}
|
|
|
|
if (options.title) {
|
|
dialog.find(".modal-title").html(options.title);
|
|
}
|
|
|
|
if (buttonStr.length) {
|
|
body.after(templates.footer);
|
|
dialog.find(".modal-footer").html(buttonStr);
|
|
}
|
|
|
|
|
|
/**
|
|
* Bootstrap event listeners; used handle extra
|
|
* setup & teardown required after the underlying
|
|
* modal has performed certain actions
|
|
*/
|
|
|
|
dialog.on("hidden.bs.modal", function(e) {
|
|
// ensure we don't accidentally intercept hidden events triggered
|
|
// by children of the current dialog. We shouldn't anymore now BS
|
|
// namespaces its events; but still worth doing
|
|
if (e.target === this) {
|
|
dialog.remove();
|
|
}
|
|
});
|
|
|
|
/*
|
|
dialog.on("show.bs.modal", function() {
|
|
// sadly this doesn't work; show is called *just* before
|
|
// the backdrop is added so we'd need a setTimeout hack or
|
|
// otherwise... leaving in as would be nice
|
|
if (options.backdrop) {
|
|
dialog.next(".modal-backdrop").addClass("bootbox-backdrop");
|
|
}
|
|
});
|
|
*/
|
|
|
|
dialog.on("shown.bs.modal", function() {
|
|
dialog.find(".btn-primary:first").focus();
|
|
});
|
|
|
|
/**
|
|
* Bootbox event listeners; experimental and may not last
|
|
* just an attempt to decouple some behaviours from their
|
|
* respective triggers
|
|
*/
|
|
|
|
if (options.backdrop !== "static") {
|
|
// A boolean true/false according to the Bootstrap docs
|
|
// should show a dialog the user can dismiss by clicking on
|
|
// the background.
|
|
// We always only ever pass static/false to the actual
|
|
// $.modal function because with `true` we can't trap
|
|
// this event (the .modal-backdrop swallows it)
|
|
// However, we still want to sort of respect true
|
|
// and invoke the escape mechanism instead
|
|
dialog.on("click.dismiss.bs.modal", function(e) {
|
|
// @NOTE: the target varies in >= 3.3.x releases since the modal backdrop
|
|
// moved *inside* the outer dialog rather than *alongside* it
|
|
if (dialog.children(".modal-backdrop").length) {
|
|
e.currentTarget = dialog.children(".modal-backdrop").get(0);
|
|
}
|
|
|
|
if (e.target !== e.currentTarget) {
|
|
return;
|
|
}
|
|
|
|
dialog.trigger("escape.close.bb");
|
|
});
|
|
}
|
|
|
|
dialog.on("escape.close.bb", function(e) {
|
|
if (callbacks.onEscape) {
|
|
processCallback(e, dialog, callbacks.onEscape);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Standard jQuery event listeners; used to handle user
|
|
* interaction with our dialog
|
|
*/
|
|
|
|
dialog.on("click", ".modal-footer button", function(e) {
|
|
var callbackKey = $(this).data("bb-handler");
|
|
|
|
processCallback(e, dialog, callbacks[callbackKey]);
|
|
});
|
|
|
|
dialog.on("click", ".bootbox-close-button", function(e) {
|
|
// onEscape might be falsy but that's fine; the fact is
|
|
// if the user has managed to click the close button we
|
|
// have to close the dialog, callback or not
|
|
processCallback(e, dialog, callbacks.onEscape);
|
|
});
|
|
|
|
dialog.on("keyup", function(e) {
|
|
if (e.which === 27) {
|
|
dialog.trigger("escape.close.bb");
|
|
}
|
|
});
|
|
|
|
// the remainder of this method simply deals with adding our
|
|
// dialogent to the DOM, augmenting it with Bootstrap's modal
|
|
// functionality and then giving the resulting object back
|
|
// to our caller
|
|
|
|
$(options.container).append(dialog);
|
|
|
|
dialog.modal({
|
|
backdrop: options.backdrop ? "static": false,
|
|
keyboard: false,
|
|
show: false
|
|
});
|
|
|
|
if (options.show) {
|
|
dialog.modal("show");
|
|
}
|
|
|
|
// @TODO should we return the raw element here or should
|
|
// we wrap it in an object on which we can expose some neater
|
|
// methods, e.g. var d = bootbox.alert(); d.hide(); instead
|
|
// of d.modal("hide");
|
|
|
|
/*
|
|
function BBDialog(elem) {
|
|
this.elem = elem;
|
|
}
|
|
|
|
BBDialog.prototype = {
|
|
hide: function() {
|
|
return this.elem.modal("hide");
|
|
},
|
|
show: function() {
|
|
return this.elem.modal("show");
|
|
}
|
|
};
|
|
*/
|
|
|
|
return dialog;
|
|
|
|
};
|
|
|
|
exports.setDefaults = function() {
|
|
var values = {};
|
|
|
|
if (arguments.length === 2) {
|
|
// allow passing of single key/value...
|
|
values[arguments[0]] = arguments[1];
|
|
} else {
|
|
// ... and as an object too
|
|
values = arguments[0];
|
|
}
|
|
|
|
$.extend(defaults, values);
|
|
};
|
|
|
|
exports.hideAll = function() {
|
|
$(".bootbox").modal("hide");
|
|
|
|
return exports;
|
|
};
|
|
|
|
|
|
/**
|
|
* standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
|
|
* unlikely to be required. If this gets too large it can be split out into separate JS files.
|
|
*/
|
|
var locales = {
|
|
bg_BG : {
|
|
OK : "Ок",
|
|
CANCEL : "Отказ",
|
|
CONFIRM : "Потвърждавам"
|
|
},
|
|
br : {
|
|
OK : "OK",
|
|
CANCEL : "Cancelar",
|
|
CONFIRM : "Sim"
|
|
},
|
|
cs : {
|
|
OK : "OK",
|
|
CANCEL : "Zrušit",
|
|
CONFIRM : "Potvrdit"
|
|
},
|
|
da : {
|
|
OK : "OK",
|
|
CANCEL : "Annuller",
|
|
CONFIRM : "Accepter"
|
|
},
|
|
de : {
|
|
OK : "OK",
|
|
CANCEL : "Abbrechen",
|
|
CONFIRM : "Akzeptieren"
|
|
},
|
|
el : {
|
|
OK : "Εντάξει",
|
|
CANCEL : "Ακύρωση",
|
|
CONFIRM : "Επιβεβαίωση"
|
|
},
|
|
en : {
|
|
OK : "OK",
|
|
CANCEL : "Cancel",
|
|
CONFIRM : "OK"
|
|
},
|
|
es : {
|
|
OK : "OK",
|
|
CANCEL : "Cancelar",
|
|
CONFIRM : "Aceptar"
|
|
},
|
|
et : {
|
|
OK : "OK",
|
|
CANCEL : "Katkesta",
|
|
CONFIRM : "OK"
|
|
},
|
|
fa : {
|
|
OK : "قبول",
|
|
CANCEL : "لغو",
|
|
CONFIRM : "تایید"
|
|
},
|
|
fi : {
|
|
OK : "OK",
|
|
CANCEL : "Peruuta",
|
|
CONFIRM : "OK"
|
|
},
|
|
fr : {
|
|
OK : "OK",
|
|
CANCEL : "Annuler",
|
|
CONFIRM : "D'accord"
|
|
},
|
|
he : {
|
|
OK : "אישור",
|
|
CANCEL : "ביטול",
|
|
CONFIRM : "אישור"
|
|
},
|
|
hu : {
|
|
OK : "OK",
|
|
CANCEL : "Mégsem",
|
|
CONFIRM : "Megerősít"
|
|
},
|
|
hr : {
|
|
OK : "OK",
|
|
CANCEL : "Odustani",
|
|
CONFIRM : "Potvrdi"
|
|
},
|
|
id : {
|
|
OK : "OK",
|
|
CANCEL : "Batal",
|
|
CONFIRM : "OK"
|
|
},
|
|
it : {
|
|
OK : "OK",
|
|
CANCEL : "Annulla",
|
|
CONFIRM : "Conferma"
|
|
},
|
|
ja : {
|
|
OK : "OK",
|
|
CANCEL : "キャンセル",
|
|
CONFIRM : "確認"
|
|
},
|
|
lt : {
|
|
OK : "Gerai",
|
|
CANCEL : "Atšaukti",
|
|
CONFIRM : "Patvirtinti"
|
|
},
|
|
lv : {
|
|
OK : "Labi",
|
|
CANCEL : "Atcelt",
|
|
CONFIRM : "Apstiprināt"
|
|
},
|
|
nl : {
|
|
OK : "OK",
|
|
CANCEL : "Annuleren",
|
|
CONFIRM : "Accepteren"
|
|
},
|
|
no : {
|
|
OK : "OK",
|
|
CANCEL : "Avbryt",
|
|
CONFIRM : "OK"
|
|
},
|
|
pl : {
|
|
OK : "OK",
|
|
CANCEL : "Anuluj",
|
|
CONFIRM : "Potwierdź"
|
|
},
|
|
pt : {
|
|
OK : "OK",
|
|
CANCEL : "Cancelar",
|
|
CONFIRM : "Confirmar"
|
|
},
|
|
ru : {
|
|
OK : "OK",
|
|
CANCEL : "Отмена",
|
|
CONFIRM : "Применить"
|
|
},
|
|
sq : {
|
|
OK : "OK",
|
|
CANCEL : "Anulo",
|
|
CONFIRM : "Prano"
|
|
},
|
|
sv : {
|
|
OK : "OK",
|
|
CANCEL : "Avbryt",
|
|
CONFIRM : "OK"
|
|
},
|
|
th : {
|
|
OK : "ตกลง",
|
|
CANCEL : "ยกเลิก",
|
|
CONFIRM : "ยืนยัน"
|
|
},
|
|
tr : {
|
|
OK : "Tamam",
|
|
CANCEL : "İptal",
|
|
CONFIRM : "Onayla"
|
|
},
|
|
zh_CN : {
|
|
OK : "OK",
|
|
CANCEL : "取消",
|
|
CONFIRM : "确认"
|
|
},
|
|
zh_TW : {
|
|
OK : "OK",
|
|
CANCEL : "取消",
|
|
CONFIRM : "確認"
|
|
}
|
|
};
|
|
|
|
exports.addLocale = function(name, values) {
|
|
$.each(["OK", "CANCEL", "CONFIRM"], function(_, v) {
|
|
if (!values[v]) {
|
|
throw new Error("Please supply a translation for '" + v + "'");
|
|
}
|
|
});
|
|
|
|
locales[name] = {
|
|
OK: values.OK,
|
|
CANCEL: values.CANCEL,
|
|
CONFIRM: values.CONFIRM
|
|
};
|
|
|
|
return exports;
|
|
};
|
|
|
|
exports.removeLocale = function(name) {
|
|
delete locales[name];
|
|
|
|
return exports;
|
|
};
|
|
|
|
exports.setLocale = function(name) {
|
|
return exports.setDefaults("locale", name);
|
|
};
|
|
|
|
exports.init = function(_$) {
|
|
return init(_$ || $);
|
|
};
|
|
|
|
return exports;
|
|
}));
|
|
|
|
/*!
|
|
* Vue.js v2.2.0
|
|
* (c) 2014-2017 Evan You
|
|
* Released under the MIT License.
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
(global.Vue = factory());
|
|
}(this, (function () { 'use strict';
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Convert a value to a string that is actually rendered.
|
|
*/
|
|
function _toString (val) {
|
|
return val == null
|
|
? ''
|
|
: typeof val === 'object'
|
|
? JSON.stringify(val, null, 2)
|
|
: String(val)
|
|
}
|
|
|
|
/**
|
|
* Convert a input value to a number for persistence.
|
|
* If the conversion fails, return original string.
|
|
*/
|
|
function toNumber (val) {
|
|
var n = parseFloat(val);
|
|
return isNaN(n) ? val : n
|
|
}
|
|
|
|
/**
|
|
* Make a map and return a function for checking if a key
|
|
* is in that map.
|
|
*/
|
|
function makeMap (
|
|
str,
|
|
expectsLowerCase
|
|
) {
|
|
var map = Object.create(null);
|
|
var list = str.split(',');
|
|
for (var i = 0; i < list.length; i++) {
|
|
map[list[i]] = true;
|
|
}
|
|
return expectsLowerCase
|
|
? function (val) { return map[val.toLowerCase()]; }
|
|
: function (val) { return map[val]; }
|
|
}
|
|
|
|
/**
|
|
* Check if a tag is a built-in tag.
|
|
*/
|
|
var isBuiltInTag = makeMap('slot,component', true);
|
|
|
|
/**
|
|
* Remove an item from an array
|
|
*/
|
|
function remove (arr, item) {
|
|
if (arr.length) {
|
|
var index = arr.indexOf(item);
|
|
if (index > -1) {
|
|
return arr.splice(index, 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check whether the object has the property.
|
|
*/
|
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
function hasOwn (obj, key) {
|
|
return hasOwnProperty.call(obj, key)
|
|
}
|
|
|
|
/**
|
|
* Check if value is primitive
|
|
*/
|
|
function isPrimitive (value) {
|
|
return typeof value === 'string' || typeof value === 'number'
|
|
}
|
|
|
|
/**
|
|
* Create a cached version of a pure function.
|
|
*/
|
|
function cached (fn) {
|
|
var cache = Object.create(null);
|
|
return (function cachedFn (str) {
|
|
var hit = cache[str];
|
|
return hit || (cache[str] = fn(str))
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Camelize a hyphen-delimited string.
|
|
*/
|
|
var camelizeRE = /-(\w)/g;
|
|
var camelize = cached(function (str) {
|
|
return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })
|
|
});
|
|
|
|
/**
|
|
* Capitalize a string.
|
|
*/
|
|
var capitalize = cached(function (str) {
|
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
});
|
|
|
|
/**
|
|
* Hyphenate a camelCase string.
|
|
*/
|
|
var hyphenateRE = /([^-])([A-Z])/g;
|
|
var hyphenate = cached(function (str) {
|
|
return str
|
|
.replace(hyphenateRE, '$1-$2')
|
|
.replace(hyphenateRE, '$1-$2')
|
|
.toLowerCase()
|
|
});
|
|
|
|
/**
|
|
* Simple bind, faster than native
|
|
*/
|
|
function bind (fn, ctx) {
|
|
function boundFn (a) {
|
|
var l = arguments.length;
|
|
return l
|
|
? l > 1
|
|
? fn.apply(ctx, arguments)
|
|
: fn.call(ctx, a)
|
|
: fn.call(ctx)
|
|
}
|
|
// record original fn length
|
|
boundFn._length = fn.length;
|
|
return boundFn
|
|
}
|
|
|
|
/**
|
|
* Convert an Array-like object to a real Array.
|
|
*/
|
|
function toArray (list, start) {
|
|
start = start || 0;
|
|
var i = list.length - start;
|
|
var ret = new Array(i);
|
|
while (i--) {
|
|
ret[i] = list[i + start];
|
|
}
|
|
return ret
|
|
}
|
|
|
|
/**
|
|
* Mix properties into target object.
|
|
*/
|
|
function extend (to, _from) {
|
|
for (var key in _from) {
|
|
to[key] = _from[key];
|
|
}
|
|
return to
|
|
}
|
|
|
|
/**
|
|
* Quick object check - this is primarily used to tell
|
|
* Objects from primitive values when we know the value
|
|
* is a JSON-compliant type.
|
|
*/
|
|
function isObject (obj) {
|
|
return obj !== null && typeof obj === 'object'
|
|
}
|
|
|
|
/**
|
|
* Strict object type check. Only returns true
|
|
* for plain JavaScript objects.
|
|
*/
|
|
var toString = Object.prototype.toString;
|
|
var OBJECT_STRING = '[object Object]';
|
|
function isPlainObject (obj) {
|
|
return toString.call(obj) === OBJECT_STRING
|
|
}
|
|
|
|
/**
|
|
* Merge an Array of Objects into a single Object.
|
|
*/
|
|
function toObject (arr) {
|
|
var res = {};
|
|
for (var i = 0; i < arr.length; i++) {
|
|
if (arr[i]) {
|
|
extend(res, arr[i]);
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
/**
|
|
* Perform no operation.
|
|
*/
|
|
function noop () {}
|
|
|
|
/**
|
|
* Always return false.
|
|
*/
|
|
var no = function () { return false; };
|
|
|
|
/**
|
|
* Return same value
|
|
*/
|
|
var identity = function (_) { return _; };
|
|
|
|
/**
|
|
* Generate a static keys string from compiler modules.
|
|
*/
|
|
function genStaticKeys (modules) {
|
|
return modules.reduce(function (keys, m) {
|
|
return keys.concat(m.staticKeys || [])
|
|
}, []).join(',')
|
|
}
|
|
|
|
/**
|
|
* Check if two values are loosely equal - that is,
|
|
* if they are plain objects, do they have the same shape?
|
|
*/
|
|
function looseEqual (a, b) {
|
|
var isObjectA = isObject(a);
|
|
var isObjectB = isObject(b);
|
|
if (isObjectA && isObjectB) {
|
|
return JSON.stringify(a) === JSON.stringify(b)
|
|
} else if (!isObjectA && !isObjectB) {
|
|
return String(a) === String(b)
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
function looseIndexOf (arr, val) {
|
|
for (var i = 0; i < arr.length; i++) {
|
|
if (looseEqual(arr[i], val)) { return i }
|
|
}
|
|
return -1
|
|
}
|
|
|
|
/**
|
|
* Ensure a function is called only once.
|
|
*/
|
|
function once (fn) {
|
|
var called = false;
|
|
return function () {
|
|
if (!called) {
|
|
called = true;
|
|
fn();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var config = {
|
|
/**
|
|
* Option merge strategies (used in core/util/options)
|
|
*/
|
|
optionMergeStrategies: Object.create(null),
|
|
|
|
/**
|
|
* Whether to suppress warnings.
|
|
*/
|
|
silent: false,
|
|
|
|
/**
|
|
* Show production mode tip message on boot?
|
|
*/
|
|
productionTip: "development" !== 'production',
|
|
|
|
/**
|
|
* Whether to enable devtools
|
|
*/
|
|
devtools: "development" !== 'production',
|
|
|
|
/**
|
|
* Whether to record perf
|
|
*/
|
|
performance: "development" !== 'production',
|
|
|
|
/**
|
|
* Error handler for watcher errors
|
|
*/
|
|
errorHandler: null,
|
|
|
|
/**
|
|
* Ignore certain custom elements
|
|
*/
|
|
ignoredElements: [],
|
|
|
|
/**
|
|
* Custom user key aliases for v-on
|
|
*/
|
|
keyCodes: Object.create(null),
|
|
|
|
/**
|
|
* Check if a tag is reserved so that it cannot be registered as a
|
|
* component. This is platform-dependent and may be overwritten.
|
|
*/
|
|
isReservedTag: no,
|
|
|
|
/**
|
|
* Check if a tag is an unknown element.
|
|
* Platform-dependent.
|
|
*/
|
|
isUnknownElement: no,
|
|
|
|
/**
|
|
* Get the namespace of an element
|
|
*/
|
|
getTagNamespace: noop,
|
|
|
|
/**
|
|
* Parse the real tag name for the specific platform.
|
|
*/
|
|
parsePlatformTagName: identity,
|
|
|
|
/**
|
|
* Check if an attribute must be bound using property, e.g. value
|
|
* Platform-dependent.
|
|
*/
|
|
mustUseProp: no,
|
|
|
|
/**
|
|
* List of asset types that a component can own.
|
|
*/
|
|
_assetTypes: [
|
|
'component',
|
|
'directive',
|
|
'filter'
|
|
],
|
|
|
|
/**
|
|
* List of lifecycle hooks.
|
|
*/
|
|
_lifecycleHooks: [
|
|
'beforeCreate',
|
|
'created',
|
|
'beforeMount',
|
|
'mounted',
|
|
'beforeUpdate',
|
|
'updated',
|
|
'beforeDestroy',
|
|
'destroyed',
|
|
'activated',
|
|
'deactivated'
|
|
],
|
|
|
|
/**
|
|
* Max circular updates allowed in a scheduler flush cycle.
|
|
*/
|
|
_maxUpdateCount: 100
|
|
};
|
|
|
|
/* */
|
|
/* globals MutationObserver */
|
|
|
|
// can we use __proto__?
|
|
var hasProto = '__proto__' in {};
|
|
|
|
// Browser environment sniffing
|
|
var inBrowser = typeof window !== 'undefined';
|
|
var UA = inBrowser && window.navigator.userAgent.toLowerCase();
|
|
var isIE = UA && /msie|trident/.test(UA);
|
|
var isIE9 = UA && UA.indexOf('msie 9.0') > 0;
|
|
var isEdge = UA && UA.indexOf('edge/') > 0;
|
|
var isAndroid = UA && UA.indexOf('android') > 0;
|
|
var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA);
|
|
var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
|
|
|
|
// this needs to be lazy-evaled because vue may be required before
|
|
// vue-server-renderer can set VUE_ENV
|
|
var _isServer;
|
|
var isServerRendering = function () {
|
|
if (_isServer === undefined) {
|
|
/* istanbul ignore if */
|
|
if (!inBrowser && typeof global !== 'undefined') {
|
|
// detect presence of vue-server-renderer and avoid
|
|
// Webpack shimming the process
|
|
_isServer = global['process'].env.VUE_ENV === 'server';
|
|
} else {
|
|
_isServer = false;
|
|
}
|
|
}
|
|
return _isServer
|
|
};
|
|
|
|
// detect devtools
|
|
var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
|
|
|
|
/* istanbul ignore next */
|
|
function isNative (Ctor) {
|
|
return /native code/.test(Ctor.toString())
|
|
}
|
|
|
|
var hasSymbol =
|
|
typeof Symbol !== 'undefined' && isNative(Symbol) &&
|
|
typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);
|
|
|
|
/**
|
|
* Defer a task to execute it asynchronously.
|
|
*/
|
|
var nextTick = (function () {
|
|
var callbacks = [];
|
|
var pending = false;
|
|
var timerFunc;
|
|
|
|
function nextTickHandler () {
|
|
pending = false;
|
|
var copies = callbacks.slice(0);
|
|
callbacks.length = 0;
|
|
for (var i = 0; i < copies.length; i++) {
|
|
copies[i]();
|
|
}
|
|
}
|
|
|
|
// the nextTick behavior leverages the microtask queue, which can be accessed
|
|
// via either native Promise.then or MutationObserver.
|
|
// MutationObserver has wider support, however it is seriously bugged in
|
|
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
|
|
// completely stops working after triggering a few times... so, if native
|
|
// Promise is available, we will use it:
|
|
/* istanbul ignore if */
|
|
if (typeof Promise !== 'undefined' && isNative(Promise)) {
|
|
var p = Promise.resolve();
|
|
var logError = function (err) { console.error(err); };
|
|
timerFunc = function () {
|
|
p.then(nextTickHandler).catch(logError);
|
|
// in problematic UIWebViews, Promise.then doesn't completely break, but
|
|
// it can get stuck in a weird state where callbacks are pushed into the
|
|
// microtask queue but the queue isn't being flushed, until the browser
|
|
// needs to do some other work, e.g. handle a timer. Therefore we can
|
|
// "force" the microtask queue to be flushed by adding an empty timer.
|
|
if (isIOS) { setTimeout(noop); }
|
|
};
|
|
} else if (typeof MutationObserver !== 'undefined' && (
|
|
isNative(MutationObserver) ||
|
|
// PhantomJS and iOS 7.x
|
|
MutationObserver.toString() === '[object MutationObserverConstructor]'
|
|
)) {
|
|
// use MutationObserver where native Promise is not available,
|
|
// e.g. PhantomJS IE11, iOS7, Android 4.4
|
|
var counter = 1;
|
|
var observer = new MutationObserver(nextTickHandler);
|
|
var textNode = document.createTextNode(String(counter));
|
|
observer.observe(textNode, {
|
|
characterData: true
|
|
});
|
|
timerFunc = function () {
|
|
counter = (counter + 1) % 2;
|
|
textNode.data = String(counter);
|
|
};
|
|
} else {
|
|
// fallback to setTimeout
|
|
/* istanbul ignore next */
|
|
timerFunc = function () {
|
|
setTimeout(nextTickHandler, 0);
|
|
};
|
|
}
|
|
|
|
return function queueNextTick (cb, ctx) {
|
|
var _resolve;
|
|
callbacks.push(function () {
|
|
if (cb) { cb.call(ctx); }
|
|
if (_resolve) { _resolve(ctx); }
|
|
});
|
|
if (!pending) {
|
|
pending = true;
|
|
timerFunc();
|
|
}
|
|
if (!cb && typeof Promise !== 'undefined') {
|
|
return new Promise(function (resolve) {
|
|
_resolve = resolve;
|
|
})
|
|
}
|
|
}
|
|
})();
|
|
|
|
var _Set;
|
|
/* istanbul ignore if */
|
|
if (typeof Set !== 'undefined' && isNative(Set)) {
|
|
// use native Set when available.
|
|
_Set = Set;
|
|
} else {
|
|
// a non-standard Set polyfill that only works with primitive keys.
|
|
_Set = (function () {
|
|
function Set () {
|
|
this.set = Object.create(null);
|
|
}
|
|
Set.prototype.has = function has (key) {
|
|
return this.set[key] === true
|
|
};
|
|
Set.prototype.add = function add (key) {
|
|
this.set[key] = true;
|
|
};
|
|
Set.prototype.clear = function clear () {
|
|
this.set = Object.create(null);
|
|
};
|
|
|
|
return Set;
|
|
}());
|
|
}
|
|
|
|
var perf;
|
|
|
|
{
|
|
perf = inBrowser && window.performance;
|
|
if (perf && (!perf.mark || !perf.measure)) {
|
|
perf = undefined;
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var emptyObject = Object.freeze({});
|
|
|
|
/**
|
|
* Check if a string starts with $ or _
|
|
*/
|
|
function isReserved (str) {
|
|
var c = (str + '').charCodeAt(0);
|
|
return c === 0x24 || c === 0x5F
|
|
}
|
|
|
|
/**
|
|
* Define a property.
|
|
*/
|
|
function def (obj, key, val, enumerable) {
|
|
Object.defineProperty(obj, key, {
|
|
value: val,
|
|
enumerable: !!enumerable,
|
|
writable: true,
|
|
configurable: true
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Parse simple path.
|
|
*/
|
|
var bailRE = /[^\w.$]/;
|
|
function parsePath (path) {
|
|
if (bailRE.test(path)) {
|
|
return
|
|
} else {
|
|
var segments = path.split('.');
|
|
return function (obj) {
|
|
for (var i = 0; i < segments.length; i++) {
|
|
if (!obj) { return }
|
|
obj = obj[segments[i]];
|
|
}
|
|
return obj
|
|
}
|
|
}
|
|
}
|
|
|
|
var warn = noop;
|
|
var tip = noop;
|
|
var formatComponentName;
|
|
|
|
{
|
|
var hasConsole = typeof console !== 'undefined';
|
|
var classifyRE = /(?:^|[-_])(\w)/g;
|
|
var classify = function (str) { return str
|
|
.replace(classifyRE, function (c) { return c.toUpperCase(); })
|
|
.replace(/[-_]/g, ''); };
|
|
|
|
warn = function (msg, vm) {
|
|
if (hasConsole && (!config.silent)) {
|
|
console.error("[Vue warn]: " + msg + " " + (
|
|
vm ? formatLocation(formatComponentName(vm)) : ''
|
|
));
|
|
}
|
|
};
|
|
|
|
tip = function (msg, vm) {
|
|
if (hasConsole && (!config.silent)) {
|
|
console.warn("[Vue tip]: " + msg + " " + (
|
|
vm ? formatLocation(formatComponentName(vm)) : ''
|
|
));
|
|
}
|
|
};
|
|
|
|
formatComponentName = function (vm, includeFile) {
|
|
if (vm.$root === vm) {
|
|
return '<Root>'
|
|
}
|
|
var name = vm._isVue
|
|
? vm.$options.name || vm.$options._componentTag
|
|
: vm.name;
|
|
|
|
var file = vm._isVue && vm.$options.__file;
|
|
if (!name && file) {
|
|
var match = file.match(/([^/\\]+)\.vue$/);
|
|
name = match && match[1];
|
|
}
|
|
|
|
return (
|
|
(name ? ("<" + (classify(name)) + ">") : "<Anonymous>") +
|
|
(file && includeFile !== false ? (" at " + file) : '')
|
|
)
|
|
};
|
|
|
|
var formatLocation = function (str) {
|
|
if (str === "<Anonymous>") {
|
|
str += " - use the \"name\" option for better debugging messages.";
|
|
}
|
|
return ("\n(found in " + str + ")")
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
|
|
var uid$1 = 0;
|
|
|
|
/**
|
|
* A dep is an observable that can have multiple
|
|
* directives subscribing to it.
|
|
*/
|
|
var Dep = function Dep () {
|
|
this.id = uid$1++;
|
|
this.subs = [];
|
|
};
|
|
|
|
Dep.prototype.addSub = function addSub (sub) {
|
|
this.subs.push(sub);
|
|
};
|
|
|
|
Dep.prototype.removeSub = function removeSub (sub) {
|
|
remove(this.subs, sub);
|
|
};
|
|
|
|
Dep.prototype.depend = function depend () {
|
|
if (Dep.target) {
|
|
Dep.target.addDep(this);
|
|
}
|
|
};
|
|
|
|
Dep.prototype.notify = function notify () {
|
|
// stablize the subscriber list first
|
|
var subs = this.subs.slice();
|
|
for (var i = 0, l = subs.length; i < l; i++) {
|
|
subs[i].update();
|
|
}
|
|
};
|
|
|
|
// the current target watcher being evaluated.
|
|
// this is globally unique because there could be only one
|
|
// watcher being evaluated at any time.
|
|
Dep.target = null;
|
|
var targetStack = [];
|
|
|
|
function pushTarget (_target) {
|
|
if (Dep.target) { targetStack.push(Dep.target); }
|
|
Dep.target = _target;
|
|
}
|
|
|
|
function popTarget () {
|
|
Dep.target = targetStack.pop();
|
|
}
|
|
|
|
/*
|
|
* not type checking this file because flow doesn't play well with
|
|
* dynamically accessing methods on Array prototype
|
|
*/
|
|
|
|
var arrayProto = Array.prototype;
|
|
var arrayMethods = Object.create(arrayProto);[
|
|
'push',
|
|
'pop',
|
|
'shift',
|
|
'unshift',
|
|
'splice',
|
|
'sort',
|
|
'reverse'
|
|
]
|
|
.forEach(function (method) {
|
|
// cache original method
|
|
var original = arrayProto[method];
|
|
def(arrayMethods, method, function mutator () {
|
|
var arguments$1 = arguments;
|
|
|
|
// avoid leaking arguments:
|
|
// http://jsperf.com/closure-with-arguments
|
|
var i = arguments.length;
|
|
var args = new Array(i);
|
|
while (i--) {
|
|
args[i] = arguments$1[i];
|
|
}
|
|
var result = original.apply(this, args);
|
|
var ob = this.__ob__;
|
|
var inserted;
|
|
switch (method) {
|
|
case 'push':
|
|
inserted = args;
|
|
break
|
|
case 'unshift':
|
|
inserted = args;
|
|
break
|
|
case 'splice':
|
|
inserted = args.slice(2);
|
|
break
|
|
}
|
|
if (inserted) { ob.observeArray(inserted); }
|
|
// notify change
|
|
ob.dep.notify();
|
|
return result
|
|
});
|
|
});
|
|
|
|
/* */
|
|
|
|
var arrayKeys = Object.getOwnPropertyNames(arrayMethods);
|
|
|
|
/**
|
|
* By default, when a reactive property is set, the new value is
|
|
* also converted to become reactive. However when passing down props,
|
|
* we don't want to force conversion because the value may be a nested value
|
|
* under a frozen data structure. Converting it would defeat the optimization.
|
|
*/
|
|
var observerState = {
|
|
shouldConvert: true,
|
|
isSettingProps: false
|
|
};
|
|
|
|
/**
|
|
* Observer class that are attached to each observed
|
|
* object. Once attached, the observer converts target
|
|
* object's property keys into getter/setters that
|
|
* collect dependencies and dispatches updates.
|
|
*/
|
|
var Observer = function Observer (value) {
|
|
this.value = value;
|
|
this.dep = new Dep();
|
|
this.vmCount = 0;
|
|
def(value, '__ob__', this);
|
|
if (Array.isArray(value)) {
|
|
var augment = hasProto
|
|
? protoAugment
|
|
: copyAugment;
|
|
augment(value, arrayMethods, arrayKeys);
|
|
this.observeArray(value);
|
|
} else {
|
|
this.walk(value);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Walk through each property and convert them into
|
|
* getter/setters. This method should only be called when
|
|
* value type is Object.
|
|
*/
|
|
Observer.prototype.walk = function walk (obj) {
|
|
var keys = Object.keys(obj);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
defineReactive$$1(obj, keys[i], obj[keys[i]]);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Observe a list of Array items.
|
|
*/
|
|
Observer.prototype.observeArray = function observeArray (items) {
|
|
for (var i = 0, l = items.length; i < l; i++) {
|
|
observe(items[i]);
|
|
}
|
|
};
|
|
|
|
// helpers
|
|
|
|
/**
|
|
* Augment an target Object or Array by intercepting
|
|
* the prototype chain using __proto__
|
|
*/
|
|
function protoAugment (target, src) {
|
|
/* eslint-disable no-proto */
|
|
target.__proto__ = src;
|
|
/* eslint-enable no-proto */
|
|
}
|
|
|
|
/**
|
|
* Augment an target Object or Array by defining
|
|
* hidden properties.
|
|
*/
|
|
/* istanbul ignore next */
|
|
function copyAugment (target, src, keys) {
|
|
for (var i = 0, l = keys.length; i < l; i++) {
|
|
var key = keys[i];
|
|
def(target, key, src[key]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempt to create an observer instance for a value,
|
|
* returns the new observer if successfully observed,
|
|
* or the existing observer if the value already has one.
|
|
*/
|
|
function observe (value, asRootData) {
|
|
if (!isObject(value)) {
|
|
return
|
|
}
|
|
var ob;
|
|
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
|
|
ob = value.__ob__;
|
|
} else if (
|
|
observerState.shouldConvert &&
|
|
!isServerRendering() &&
|
|
(Array.isArray(value) || isPlainObject(value)) &&
|
|
Object.isExtensible(value) &&
|
|
!value._isVue
|
|
) {
|
|
ob = new Observer(value);
|
|
}
|
|
if (asRootData && ob) {
|
|
ob.vmCount++;
|
|
}
|
|
return ob
|
|
}
|
|
|
|
/**
|
|
* Define a reactive property on an Object.
|
|
*/
|
|
function defineReactive$$1 (
|
|
obj,
|
|
key,
|
|
val,
|
|
customSetter
|
|
) {
|
|
var dep = new Dep();
|
|
|
|
var property = Object.getOwnPropertyDescriptor(obj, key);
|
|
if (property && property.configurable === false) {
|
|
return
|
|
}
|
|
|
|
// cater for pre-defined getter/setters
|
|
var getter = property && property.get;
|
|
var setter = property && property.set;
|
|
|
|
var childOb = observe(val);
|
|
Object.defineProperty(obj, key, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
get: function reactiveGetter () {
|
|
var value = getter ? getter.call(obj) : val;
|
|
if (Dep.target) {
|
|
dep.depend();
|
|
if (childOb) {
|
|
childOb.dep.depend();
|
|
}
|
|
if (Array.isArray(value)) {
|
|
dependArray(value);
|
|
}
|
|
}
|
|
return value
|
|
},
|
|
set: function reactiveSetter (newVal) {
|
|
var value = getter ? getter.call(obj) : val;
|
|
/* eslint-disable no-self-compare */
|
|
if (newVal === value || (newVal !== newVal && value !== value)) {
|
|
return
|
|
}
|
|
/* eslint-enable no-self-compare */
|
|
if ("development" !== 'production' && customSetter) {
|
|
customSetter();
|
|
}
|
|
if (setter) {
|
|
setter.call(obj, newVal);
|
|
} else {
|
|
val = newVal;
|
|
}
|
|
childOb = observe(newVal);
|
|
dep.notify();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set a property on an object. Adds the new property and
|
|
* triggers change notification if the property doesn't
|
|
* already exist.
|
|
*/
|
|
function set (obj, key, val) {
|
|
if (Array.isArray(obj)) {
|
|
obj.length = Math.max(obj.length, key);
|
|
obj.splice(key, 1, val);
|
|
return val
|
|
}
|
|
if (hasOwn(obj, key)) {
|
|
obj[key] = val;
|
|
return
|
|
}
|
|
var ob = obj.__ob__;
|
|
if (obj._isVue || (ob && ob.vmCount)) {
|
|
"development" !== 'production' && warn(
|
|
'Avoid adding reactive properties to a Vue instance or its root $data ' +
|
|
'at runtime - declare it upfront in the data option.'
|
|
);
|
|
return
|
|
}
|
|
if (!ob) {
|
|
obj[key] = val;
|
|
return
|
|
}
|
|
defineReactive$$1(ob.value, key, val);
|
|
ob.dep.notify();
|
|
return val
|
|
}
|
|
|
|
/**
|
|
* Delete a property and trigger change if necessary.
|
|
*/
|
|
function del (obj, key) {
|
|
if (Array.isArray(obj)) {
|
|
obj.splice(key, 1);
|
|
return
|
|
}
|
|
var ob = obj.__ob__;
|
|
if (obj._isVue || (ob && ob.vmCount)) {
|
|
"development" !== 'production' && warn(
|
|
'Avoid deleting properties on a Vue instance or its root $data ' +
|
|
'- just set it to null.'
|
|
);
|
|
return
|
|
}
|
|
if (!hasOwn(obj, key)) {
|
|
return
|
|
}
|
|
delete obj[key];
|
|
if (!ob) {
|
|
return
|
|
}
|
|
ob.dep.notify();
|
|
}
|
|
|
|
/**
|
|
* Collect dependencies on array elements when the array is touched, since
|
|
* we cannot intercept array element access like property getters.
|
|
*/
|
|
function dependArray (value) {
|
|
for (var e = (void 0), i = 0, l = value.length; i < l; i++) {
|
|
e = value[i];
|
|
e && e.__ob__ && e.__ob__.dep.depend();
|
|
if (Array.isArray(e)) {
|
|
dependArray(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Option overwriting strategies are functions that handle
|
|
* how to merge a parent option value and a child option
|
|
* value into the final value.
|
|
*/
|
|
var strats = config.optionMergeStrategies;
|
|
|
|
/**
|
|
* Options with restrictions
|
|
*/
|
|
{
|
|
strats.el = strats.propsData = function (parent, child, vm, key) {
|
|
if (!vm) {
|
|
warn(
|
|
"option \"" + key + "\" can only be used during instance " +
|
|
'creation with the `new` keyword.'
|
|
);
|
|
}
|
|
return defaultStrat(parent, child)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Helper that recursively merges two data objects together.
|
|
*/
|
|
function mergeData (to, from) {
|
|
if (!from) { return to }
|
|
var key, toVal, fromVal;
|
|
var keys = Object.keys(from);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
toVal = to[key];
|
|
fromVal = from[key];
|
|
if (!hasOwn(to, key)) {
|
|
set(to, key, fromVal);
|
|
} else if (isPlainObject(toVal) && isPlainObject(fromVal)) {
|
|
mergeData(toVal, fromVal);
|
|
}
|
|
}
|
|
return to
|
|
}
|
|
|
|
/**
|
|
* Data
|
|
*/
|
|
strats.data = function (
|
|
parentVal,
|
|
childVal,
|
|
vm
|
|
) {
|
|
if (!vm) {
|
|
// in a Vue.extend merge, both should be functions
|
|
if (!childVal) {
|
|
return parentVal
|
|
}
|
|
if (typeof childVal !== 'function') {
|
|
"development" !== 'production' && warn(
|
|
'The "data" option should be a function ' +
|
|
'that returns a per-instance value in component ' +
|
|
'definitions.',
|
|
vm
|
|
);
|
|
return parentVal
|
|
}
|
|
if (!parentVal) {
|
|
return childVal
|
|
}
|
|
// when parentVal & childVal are both present,
|
|
// we need to return a function that returns the
|
|
// merged result of both functions... no need to
|
|
// check if parentVal is a function here because
|
|
// it has to be a function to pass previous merges.
|
|
return function mergedDataFn () {
|
|
return mergeData(
|
|
childVal.call(this),
|
|
parentVal.call(this)
|
|
)
|
|
}
|
|
} else if (parentVal || childVal) {
|
|
return function mergedInstanceDataFn () {
|
|
// instance merge
|
|
var instanceData = typeof childVal === 'function'
|
|
? childVal.call(vm)
|
|
: childVal;
|
|
var defaultData = typeof parentVal === 'function'
|
|
? parentVal.call(vm)
|
|
: undefined;
|
|
if (instanceData) {
|
|
return mergeData(instanceData, defaultData)
|
|
} else {
|
|
return defaultData
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Hooks and props are merged as arrays.
|
|
*/
|
|
function mergeHook (
|
|
parentVal,
|
|
childVal
|
|
) {
|
|
return childVal
|
|
? parentVal
|
|
? parentVal.concat(childVal)
|
|
: Array.isArray(childVal)
|
|
? childVal
|
|
: [childVal]
|
|
: parentVal
|
|
}
|
|
|
|
config._lifecycleHooks.forEach(function (hook) {
|
|
strats[hook] = mergeHook;
|
|
});
|
|
|
|
/**
|
|
* Assets
|
|
*
|
|
* When a vm is present (instance creation), we need to do
|
|
* a three-way merge between constructor options, instance
|
|
* options and parent options.
|
|
*/
|
|
function mergeAssets (parentVal, childVal) {
|
|
var res = Object.create(parentVal || null);
|
|
return childVal
|
|
? extend(res, childVal)
|
|
: res
|
|
}
|
|
|
|
config._assetTypes.forEach(function (type) {
|
|
strats[type + 's'] = mergeAssets;
|
|
});
|
|
|
|
/**
|
|
* Watchers.
|
|
*
|
|
* Watchers hashes should not overwrite one
|
|
* another, so we merge them as arrays.
|
|
*/
|
|
strats.watch = function (parentVal, childVal) {
|
|
/* istanbul ignore if */
|
|
if (!childVal) { return Object.create(parentVal || null) }
|
|
if (!parentVal) { return childVal }
|
|
var ret = {};
|
|
extend(ret, parentVal);
|
|
for (var key in childVal) {
|
|
var parent = ret[key];
|
|
var child = childVal[key];
|
|
if (parent && !Array.isArray(parent)) {
|
|
parent = [parent];
|
|
}
|
|
ret[key] = parent
|
|
? parent.concat(child)
|
|
: [child];
|
|
}
|
|
return ret
|
|
};
|
|
|
|
/**
|
|
* Other object hashes.
|
|
*/
|
|
strats.props =
|
|
strats.methods =
|
|
strats.computed = function (parentVal, childVal) {
|
|
if (!childVal) { return Object.create(parentVal || null) }
|
|
if (!parentVal) { return childVal }
|
|
var ret = Object.create(null);
|
|
extend(ret, parentVal);
|
|
extend(ret, childVal);
|
|
return ret
|
|
};
|
|
|
|
/**
|
|
* Default strategy.
|
|
*/
|
|
var defaultStrat = function (parentVal, childVal) {
|
|
return childVal === undefined
|
|
? parentVal
|
|
: childVal
|
|
};
|
|
|
|
/**
|
|
* Validate component names
|
|
*/
|
|
function checkComponents (options) {
|
|
for (var key in options.components) {
|
|
var lower = key.toLowerCase();
|
|
if (isBuiltInTag(lower) || config.isReservedTag(lower)) {
|
|
warn(
|
|
'Do not use built-in or reserved HTML elements as component ' +
|
|
'id: ' + key
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ensure all props option syntax are normalized into the
|
|
* Object-based format.
|
|
*/
|
|
function normalizeProps (options) {
|
|
var props = options.props;
|
|
if (!props) { return }
|
|
var res = {};
|
|
var i, val, name;
|
|
if (Array.isArray(props)) {
|
|
i = props.length;
|
|
while (i--) {
|
|
val = props[i];
|
|
if (typeof val === 'string') {
|
|
name = camelize(val);
|
|
res[name] = { type: null };
|
|
} else {
|
|
warn('props must be strings when using array syntax.');
|
|
}
|
|
}
|
|
} else if (isPlainObject(props)) {
|
|
for (var key in props) {
|
|
val = props[key];
|
|
name = camelize(key);
|
|
res[name] = isPlainObject(val)
|
|
? val
|
|
: { type: val };
|
|
}
|
|
}
|
|
options.props = res;
|
|
}
|
|
|
|
/**
|
|
* Normalize raw function directives into object format.
|
|
*/
|
|
function normalizeDirectives (options) {
|
|
var dirs = options.directives;
|
|
if (dirs) {
|
|
for (var key in dirs) {
|
|
var def = dirs[key];
|
|
if (typeof def === 'function') {
|
|
dirs[key] = { bind: def, update: def };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merge two option objects into a new one.
|
|
* Core utility used in both instantiation and inheritance.
|
|
*/
|
|
function mergeOptions (
|
|
parent,
|
|
child,
|
|
vm
|
|
) {
|
|
{
|
|
checkComponents(child);
|
|
}
|
|
normalizeProps(child);
|
|
normalizeDirectives(child);
|
|
var extendsFrom = child.extends;
|
|
if (extendsFrom) {
|
|
parent = typeof extendsFrom === 'function'
|
|
? mergeOptions(parent, extendsFrom.options, vm)
|
|
: mergeOptions(parent, extendsFrom, vm);
|
|
}
|
|
if (child.mixins) {
|
|
for (var i = 0, l = child.mixins.length; i < l; i++) {
|
|
var mixin = child.mixins[i];
|
|
if (mixin.prototype instanceof Vue$3) {
|
|
mixin = mixin.options;
|
|
}
|
|
parent = mergeOptions(parent, mixin, vm);
|
|
}
|
|
}
|
|
var options = {};
|
|
var key;
|
|
for (key in parent) {
|
|
mergeField(key);
|
|
}
|
|
for (key in child) {
|
|
if (!hasOwn(parent, key)) {
|
|
mergeField(key);
|
|
}
|
|
}
|
|
function mergeField (key) {
|
|
var strat = strats[key] || defaultStrat;
|
|
options[key] = strat(parent[key], child[key], vm, key);
|
|
}
|
|
return options
|
|
}
|
|
|
|
/**
|
|
* Resolve an asset.
|
|
* This function is used because child instances need access
|
|
* to assets defined in its ancestor chain.
|
|
*/
|
|
function resolveAsset (
|
|
options,
|
|
type,
|
|
id,
|
|
warnMissing
|
|
) {
|
|
/* istanbul ignore if */
|
|
if (typeof id !== 'string') {
|
|
return
|
|
}
|
|
var assets = options[type];
|
|
// check local registration variations first
|
|
if (hasOwn(assets, id)) { return assets[id] }
|
|
var camelizedId = camelize(id);
|
|
if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }
|
|
var PascalCaseId = capitalize(camelizedId);
|
|
if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }
|
|
// fallback to prototype chain
|
|
var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
|
|
if ("development" !== 'production' && warnMissing && !res) {
|
|
warn(
|
|
'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
|
|
options
|
|
);
|
|
}
|
|
return res
|
|
}
|
|
|
|
/* */
|
|
|
|
function validateProp (
|
|
key,
|
|
propOptions,
|
|
propsData,
|
|
vm
|
|
) {
|
|
var prop = propOptions[key];
|
|
var absent = !hasOwn(propsData, key);
|
|
var value = propsData[key];
|
|
// handle boolean props
|
|
if (isType(Boolean, prop.type)) {
|
|
if (absent && !hasOwn(prop, 'default')) {
|
|
value = false;
|
|
} else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) {
|
|
value = true;
|
|
}
|
|
}
|
|
// check default value
|
|
if (value === undefined) {
|
|
value = getPropDefaultValue(vm, prop, key);
|
|
// since the default value is a fresh copy,
|
|
// make sure to observe it.
|
|
var prevShouldConvert = observerState.shouldConvert;
|
|
observerState.shouldConvert = true;
|
|
observe(value);
|
|
observerState.shouldConvert = prevShouldConvert;
|
|
}
|
|
{
|
|
assertProp(prop, key, value, vm, absent);
|
|
}
|
|
return value
|
|
}
|
|
|
|
/**
|
|
* Get the default value of a prop.
|
|
*/
|
|
function getPropDefaultValue (vm, prop, key) {
|
|
// no default, return undefined
|
|
if (!hasOwn(prop, 'default')) {
|
|
return undefined
|
|
}
|
|
var def = prop.default;
|
|
// warn against non-factory defaults for Object & Array
|
|
if ("development" !== 'production' && isObject(def)) {
|
|
warn(
|
|
'Invalid default value for prop "' + key + '": ' +
|
|
'Props with type Object/Array must use a factory function ' +
|
|
'to return the default value.',
|
|
vm
|
|
);
|
|
}
|
|
// the raw prop value was also undefined from previous render,
|
|
// return previous default value to avoid unnecessary watcher trigger
|
|
if (vm && vm.$options.propsData &&
|
|
vm.$options.propsData[key] === undefined &&
|
|
vm._props[key] !== undefined) {
|
|
return vm._props[key]
|
|
}
|
|
// call factory function for non-Function types
|
|
// a value is Function if its prototype is function even across different execution context
|
|
return typeof def === 'function' && getType(prop.type) !== 'Function'
|
|
? def.call(vm)
|
|
: def
|
|
}
|
|
|
|
/**
|
|
* Assert whether a prop is valid.
|
|
*/
|
|
function assertProp (
|
|
prop,
|
|
name,
|
|
value,
|
|
vm,
|
|
absent
|
|
) {
|
|
if (prop.required && absent) {
|
|
warn(
|
|
'Missing required prop: "' + name + '"',
|
|
vm
|
|
);
|
|
return
|
|
}
|
|
if (value == null && !prop.required) {
|
|
return
|
|
}
|
|
var type = prop.type;
|
|
var valid = !type || type === true;
|
|
var expectedTypes = [];
|
|
if (type) {
|
|
if (!Array.isArray(type)) {
|
|
type = [type];
|
|
}
|
|
for (var i = 0; i < type.length && !valid; i++) {
|
|
var assertedType = assertType(value, type[i]);
|
|
expectedTypes.push(assertedType.expectedType || '');
|
|
valid = assertedType.valid;
|
|
}
|
|
}
|
|
if (!valid) {
|
|
warn(
|
|
'Invalid prop: type check failed for prop "' + name + '".' +
|
|
' Expected ' + expectedTypes.map(capitalize).join(', ') +
|
|
', got ' + Object.prototype.toString.call(value).slice(8, -1) + '.',
|
|
vm
|
|
);
|
|
return
|
|
}
|
|
var validator = prop.validator;
|
|
if (validator) {
|
|
if (!validator(value)) {
|
|
warn(
|
|
'Invalid prop: custom validator check failed for prop "' + name + '".',
|
|
vm
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assert the type of a value
|
|
*/
|
|
function assertType (value, type) {
|
|
var valid;
|
|
var expectedType = getType(type);
|
|
if (expectedType === 'String') {
|
|
valid = typeof value === (expectedType = 'string');
|
|
} else if (expectedType === 'Number') {
|
|
valid = typeof value === (expectedType = 'number');
|
|
} else if (expectedType === 'Boolean') {
|
|
valid = typeof value === (expectedType = 'boolean');
|
|
} else if (expectedType === 'Function') {
|
|
valid = typeof value === (expectedType = 'function');
|
|
} else if (expectedType === 'Object') {
|
|
valid = isPlainObject(value);
|
|
} else if (expectedType === 'Array') {
|
|
valid = Array.isArray(value);
|
|
} else {
|
|
valid = value instanceof type;
|
|
}
|
|
return {
|
|
valid: valid,
|
|
expectedType: expectedType
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Use function string name to check built-in types,
|
|
* because a simple equality check will fail when running
|
|
* across different vms / iframes.
|
|
*/
|
|
function getType (fn) {
|
|
var match = fn && fn.toString().match(/^\s*function (\w+)/);
|
|
return match && match[1]
|
|
}
|
|
|
|
function isType (type, fn) {
|
|
if (!Array.isArray(fn)) {
|
|
return getType(fn) === getType(type)
|
|
}
|
|
for (var i = 0, len = fn.length; i < len; i++) {
|
|
if (getType(fn[i]) === getType(type)) {
|
|
return true
|
|
}
|
|
}
|
|
/* istanbul ignore next */
|
|
return false
|
|
}
|
|
|
|
function handleError (err, vm, type) {
|
|
if (config.errorHandler) {
|
|
config.errorHandler.call(null, err, vm, type);
|
|
} else {
|
|
{
|
|
warn(("Error in " + type + ":"), vm);
|
|
}
|
|
/* istanbul ignore else */
|
|
if (inBrowser && typeof console !== 'undefined') {
|
|
console.error(err);
|
|
} else {
|
|
throw err
|
|
}
|
|
}
|
|
}
|
|
|
|
/* not type checking this file because flow doesn't play well with Proxy */
|
|
|
|
var initProxy;
|
|
|
|
{
|
|
var allowedGlobals = makeMap(
|
|
'Infinity,undefined,NaN,isFinite,isNaN,' +
|
|
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
|
|
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
|
|
'require' // for Webpack/Browserify
|
|
);
|
|
|
|
var warnNonPresent = function (target, key) {
|
|
warn(
|
|
"Property or method \"" + key + "\" is not defined on the instance but " +
|
|
"referenced during render. Make sure to declare reactive data " +
|
|
"properties in the data option.",
|
|
target
|
|
);
|
|
};
|
|
|
|
var hasProxy =
|
|
typeof Proxy !== 'undefined' &&
|
|
Proxy.toString().match(/native code/);
|
|
|
|
if (hasProxy) {
|
|
var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta');
|
|
config.keyCodes = new Proxy(config.keyCodes, {
|
|
set: function set (target, key, value) {
|
|
if (isBuiltInModifier(key)) {
|
|
warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key));
|
|
return false
|
|
} else {
|
|
target[key] = value;
|
|
return true
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
var hasHandler = {
|
|
has: function has (target, key) {
|
|
var has = key in target;
|
|
var isAllowed = allowedGlobals(key) || key.charAt(0) === '_';
|
|
if (!has && !isAllowed) {
|
|
warnNonPresent(target, key);
|
|
}
|
|
return has || !isAllowed
|
|
}
|
|
};
|
|
|
|
var getHandler = {
|
|
get: function get (target, key) {
|
|
if (typeof key === 'string' && !(key in target)) {
|
|
warnNonPresent(target, key);
|
|
}
|
|
return target[key]
|
|
}
|
|
};
|
|
|
|
initProxy = function initProxy (vm) {
|
|
if (hasProxy) {
|
|
// determine which proxy handler to use
|
|
var options = vm.$options;
|
|
var handlers = options.render && options.render._withStripped
|
|
? getHandler
|
|
: hasHandler;
|
|
vm._renderProxy = new Proxy(vm, handlers);
|
|
} else {
|
|
vm._renderProxy = vm;
|
|
}
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
var VNode = function VNode (
|
|
tag,
|
|
data,
|
|
children,
|
|
text,
|
|
elm,
|
|
context,
|
|
componentOptions
|
|
) {
|
|
this.tag = tag;
|
|
this.data = data;
|
|
this.children = children;
|
|
this.text = text;
|
|
this.elm = elm;
|
|
this.ns = undefined;
|
|
this.context = context;
|
|
this.functionalContext = undefined;
|
|
this.key = data && data.key;
|
|
this.componentOptions = componentOptions;
|
|
this.componentInstance = undefined;
|
|
this.parent = undefined;
|
|
this.raw = false;
|
|
this.isStatic = false;
|
|
this.isRootInsert = true;
|
|
this.isComment = false;
|
|
this.isCloned = false;
|
|
this.isOnce = false;
|
|
};
|
|
|
|
var prototypeAccessors = { child: {} };
|
|
|
|
// DEPRECATED: alias for componentInstance for backwards compat.
|
|
/* istanbul ignore next */
|
|
prototypeAccessors.child.get = function () {
|
|
return this.componentInstance
|
|
};
|
|
|
|
Object.defineProperties( VNode.prototype, prototypeAccessors );
|
|
|
|
var createEmptyVNode = function () {
|
|
var node = new VNode();
|
|
node.text = '';
|
|
node.isComment = true;
|
|
return node
|
|
};
|
|
|
|
function createTextVNode (val) {
|
|
return new VNode(undefined, undefined, undefined, String(val))
|
|
}
|
|
|
|
// optimized shallow clone
|
|
// used for static nodes and slot nodes because they may be reused across
|
|
// multiple renders, cloning them avoids errors when DOM manipulations rely
|
|
// on their elm reference.
|
|
function cloneVNode (vnode) {
|
|
var cloned = new VNode(
|
|
vnode.tag,
|
|
vnode.data,
|
|
vnode.children,
|
|
vnode.text,
|
|
vnode.elm,
|
|
vnode.context,
|
|
vnode.componentOptions
|
|
);
|
|
cloned.ns = vnode.ns;
|
|
cloned.isStatic = vnode.isStatic;
|
|
cloned.key = vnode.key;
|
|
cloned.isCloned = true;
|
|
return cloned
|
|
}
|
|
|
|
function cloneVNodes (vnodes) {
|
|
var res = new Array(vnodes.length);
|
|
for (var i = 0; i < vnodes.length; i++) {
|
|
res[i] = cloneVNode(vnodes[i]);
|
|
}
|
|
return res
|
|
}
|
|
|
|
/* */
|
|
|
|
var normalizeEvent = cached(function (name) {
|
|
var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first
|
|
name = once$$1 ? name.slice(1) : name;
|
|
var capture = name.charAt(0) === '!';
|
|
name = capture ? name.slice(1) : name;
|
|
return {
|
|
name: name,
|
|
once: once$$1,
|
|
capture: capture
|
|
}
|
|
});
|
|
|
|
function createFnInvoker (fns) {
|
|
function invoker () {
|
|
var arguments$1 = arguments;
|
|
|
|
var fns = invoker.fns;
|
|
if (Array.isArray(fns)) {
|
|
for (var i = 0; i < fns.length; i++) {
|
|
fns[i].apply(null, arguments$1);
|
|
}
|
|
} else {
|
|
// return handler return value for single handlers
|
|
return fns.apply(null, arguments)
|
|
}
|
|
}
|
|
invoker.fns = fns;
|
|
return invoker
|
|
}
|
|
|
|
function updateListeners (
|
|
on,
|
|
oldOn,
|
|
add,
|
|
remove$$1,
|
|
vm
|
|
) {
|
|
var name, cur, old, event;
|
|
for (name in on) {
|
|
cur = on[name];
|
|
old = oldOn[name];
|
|
event = normalizeEvent(name);
|
|
if (!cur) {
|
|
"development" !== 'production' && warn(
|
|
"Invalid handler for event \"" + (event.name) + "\": got " + String(cur),
|
|
vm
|
|
);
|
|
} else if (!old) {
|
|
if (!cur.fns) {
|
|
cur = on[name] = createFnInvoker(cur);
|
|
}
|
|
add(event.name, cur, event.once, event.capture);
|
|
} else if (cur !== old) {
|
|
old.fns = cur;
|
|
on[name] = old;
|
|
}
|
|
}
|
|
for (name in oldOn) {
|
|
if (!on[name]) {
|
|
event = normalizeEvent(name);
|
|
remove$$1(event.name, oldOn[name], event.capture);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function mergeVNodeHook (def, hookKey, hook) {
|
|
var invoker;
|
|
var oldHook = def[hookKey];
|
|
|
|
function wrappedHook () {
|
|
hook.apply(this, arguments);
|
|
// important: remove merged hook to ensure it's called only once
|
|
// and prevent memory leak
|
|
remove(invoker.fns, wrappedHook);
|
|
}
|
|
|
|
if (!oldHook) {
|
|
// no existing hook
|
|
invoker = createFnInvoker([wrappedHook]);
|
|
} else {
|
|
/* istanbul ignore if */
|
|
if (oldHook.fns && oldHook.merged) {
|
|
// already a merged invoker
|
|
invoker = oldHook;
|
|
invoker.fns.push(wrappedHook);
|
|
} else {
|
|
// existing plain hook
|
|
invoker = createFnInvoker([oldHook, wrappedHook]);
|
|
}
|
|
}
|
|
|
|
invoker.merged = true;
|
|
def[hookKey] = invoker;
|
|
}
|
|
|
|
/* */
|
|
|
|
// The template compiler attempts to minimize the need for normalization by
|
|
// statically analyzing the template at compile time.
|
|
//
|
|
// For plain HTML markup, normalization can be completely skipped because the
|
|
// generated render function is guaranteed to return Array<VNode>. There are
|
|
// two cases where extra normalization is needed:
|
|
|
|
// 1. When the children contains components - because a functional component
|
|
// may return an Array instead of a single root. In this case, just a simple
|
|
// normalization is needed - if any child is an Array, we flatten the whole
|
|
// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
|
|
// because functional components already normalize their own children.
|
|
function simpleNormalizeChildren (children) {
|
|
for (var i = 0; i < children.length; i++) {
|
|
if (Array.isArray(children[i])) {
|
|
return Array.prototype.concat.apply([], children)
|
|
}
|
|
}
|
|
return children
|
|
}
|
|
|
|
// 2. When the children contains constrcuts that always generated nested Arrays,
|
|
// e.g. <template>, <slot>, v-for, or when the children is provided by user
|
|
// with hand-written render functions / JSX. In such cases a full normalization
|
|
// is needed to cater to all possible types of children values.
|
|
function normalizeChildren (children) {
|
|
return isPrimitive(children)
|
|
? [createTextVNode(children)]
|
|
: Array.isArray(children)
|
|
? normalizeArrayChildren(children)
|
|
: undefined
|
|
}
|
|
|
|
function normalizeArrayChildren (children, nestedIndex) {
|
|
var res = [];
|
|
var i, c, last;
|
|
for (i = 0; i < children.length; i++) {
|
|
c = children[i];
|
|
if (c == null || typeof c === 'boolean') { continue }
|
|
last = res[res.length - 1];
|
|
// nested
|
|
if (Array.isArray(c)) {
|
|
res.push.apply(res, normalizeArrayChildren(c, ((nestedIndex || '') + "_" + i)));
|
|
} else if (isPrimitive(c)) {
|
|
if (last && last.text) {
|
|
last.text += String(c);
|
|
} else if (c !== '') {
|
|
// convert primitive to vnode
|
|
res.push(createTextVNode(c));
|
|
}
|
|
} else {
|
|
if (c.text && last && last.text) {
|
|
res[res.length - 1] = createTextVNode(last.text + c.text);
|
|
} else {
|
|
// default key for nested array children (likely generated by v-for)
|
|
if (c.tag && c.key == null && nestedIndex != null) {
|
|
c.key = "__vlist" + nestedIndex + "_" + i + "__";
|
|
}
|
|
res.push(c);
|
|
}
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
/* */
|
|
|
|
function getFirstComponentChild (children) {
|
|
return children && children.filter(function (c) { return c && c.componentOptions; })[0]
|
|
}
|
|
|
|
/* */
|
|
|
|
function initEvents (vm) {
|
|
vm._events = Object.create(null);
|
|
vm._hasHookEvent = false;
|
|
// init parent attached events
|
|
var listeners = vm.$options._parentListeners;
|
|
if (listeners) {
|
|
updateComponentListeners(vm, listeners);
|
|
}
|
|
}
|
|
|
|
var target;
|
|
|
|
function add (event, fn, once$$1) {
|
|
if (once$$1) {
|
|
target.$once(event, fn);
|
|
} else {
|
|
target.$on(event, fn);
|
|
}
|
|
}
|
|
|
|
function remove$1 (event, fn) {
|
|
target.$off(event, fn);
|
|
}
|
|
|
|
function updateComponentListeners (
|
|
vm,
|
|
listeners,
|
|
oldListeners
|
|
) {
|
|
target = vm;
|
|
updateListeners(listeners, oldListeners || {}, add, remove$1, vm);
|
|
}
|
|
|
|
function eventsMixin (Vue) {
|
|
var hookRE = /^hook:/;
|
|
Vue.prototype.$on = function (event, fn) {
|
|
var this$1 = this;
|
|
|
|
var vm = this;
|
|
if (Array.isArray(event)) {
|
|
for (var i = 0, l = event.length; i < l; i++) {
|
|
this$1.$on(event[i], fn);
|
|
}
|
|
} else {
|
|
(vm._events[event] || (vm._events[event] = [])).push(fn);
|
|
// optimize hook:event cost by using a boolean flag marked at registration
|
|
// instead of a hash lookup
|
|
if (hookRE.test(event)) {
|
|
vm._hasHookEvent = true;
|
|
}
|
|
}
|
|
return vm
|
|
};
|
|
|
|
Vue.prototype.$once = function (event, fn) {
|
|
var vm = this;
|
|
function on () {
|
|
vm.$off(event, on);
|
|
fn.apply(vm, arguments);
|
|
}
|
|
on.fn = fn;
|
|
vm.$on(event, on);
|
|
return vm
|
|
};
|
|
|
|
Vue.prototype.$off = function (event, fn) {
|
|
var vm = this;
|
|
// all
|
|
if (!arguments.length) {
|
|
vm._events = Object.create(null);
|
|
return vm
|
|
}
|
|
// specific event
|
|
var cbs = vm._events[event];
|
|
if (!cbs) {
|
|
return vm
|
|
}
|
|
if (arguments.length === 1) {
|
|
vm._events[event] = null;
|
|
return vm
|
|
}
|
|
// specific handler
|
|
var cb;
|
|
var i = cbs.length;
|
|
while (i--) {
|
|
cb = cbs[i];
|
|
if (cb === fn || cb.fn === fn) {
|
|
cbs.splice(i, 1);
|
|
break
|
|
}
|
|
}
|
|
return vm
|
|
};
|
|
|
|
Vue.prototype.$emit = function (event) {
|
|
var vm = this;
|
|
var cbs = vm._events[event];
|
|
if (cbs) {
|
|
cbs = cbs.length > 1 ? toArray(cbs) : cbs;
|
|
var args = toArray(arguments, 1);
|
|
for (var i = 0, l = cbs.length; i < l; i++) {
|
|
cbs[i].apply(vm, args);
|
|
}
|
|
}
|
|
return vm
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for resolving raw children VNodes into a slot object.
|
|
*/
|
|
function resolveSlots (
|
|
children,
|
|
context
|
|
) {
|
|
var slots = {};
|
|
if (!children) {
|
|
return slots
|
|
}
|
|
var defaultSlot = [];
|
|
var name, child;
|
|
for (var i = 0, l = children.length; i < l; i++) {
|
|
child = children[i];
|
|
// named slots should only be respected if the vnode was rendered in the
|
|
// same context.
|
|
if ((child.context === context || child.functionalContext === context) &&
|
|
child.data && (name = child.data.slot)) {
|
|
var slot = (slots[name] || (slots[name] = []));
|
|
if (child.tag === 'template') {
|
|
slot.push.apply(slot, child.children);
|
|
} else {
|
|
slot.push(child);
|
|
}
|
|
} else {
|
|
defaultSlot.push(child);
|
|
}
|
|
}
|
|
// ignore single whitespace
|
|
if (defaultSlot.length && !(
|
|
defaultSlot.length === 1 &&
|
|
(defaultSlot[0].text === ' ' || defaultSlot[0].isComment)
|
|
)) {
|
|
slots.default = defaultSlot;
|
|
}
|
|
return slots
|
|
}
|
|
|
|
function resolveScopedSlots (
|
|
fns
|
|
) {
|
|
var res = {};
|
|
for (var i = 0; i < fns.length; i++) {
|
|
res[fns[i][0]] = fns[i][1];
|
|
}
|
|
return res
|
|
}
|
|
|
|
/* */
|
|
|
|
var activeInstance = null;
|
|
|
|
function initLifecycle (vm) {
|
|
var options = vm.$options;
|
|
|
|
// locate first non-abstract parent
|
|
var parent = options.parent;
|
|
if (parent && !options.abstract) {
|
|
while (parent.$options.abstract && parent.$parent) {
|
|
parent = parent.$parent;
|
|
}
|
|
parent.$children.push(vm);
|
|
}
|
|
|
|
vm.$parent = parent;
|
|
vm.$root = parent ? parent.$root : vm;
|
|
|
|
vm.$children = [];
|
|
vm.$refs = {};
|
|
|
|
vm._watcher = null;
|
|
vm._inactive = null;
|
|
vm._directInactive = false;
|
|
vm._isMounted = false;
|
|
vm._isDestroyed = false;
|
|
vm._isBeingDestroyed = false;
|
|
}
|
|
|
|
function lifecycleMixin (Vue) {
|
|
Vue.prototype._update = function (vnode, hydrating) {
|
|
var vm = this;
|
|
if (vm._isMounted) {
|
|
callHook(vm, 'beforeUpdate');
|
|
}
|
|
var prevEl = vm.$el;
|
|
var prevVnode = vm._vnode;
|
|
var prevActiveInstance = activeInstance;
|
|
activeInstance = vm;
|
|
vm._vnode = vnode;
|
|
// Vue.prototype.__patch__ is injected in entry points
|
|
// based on the rendering backend used.
|
|
if (!prevVnode) {
|
|
// initial render
|
|
vm.$el = vm.__patch__(
|
|
vm.$el, vnode, hydrating, false /* removeOnly */,
|
|
vm.$options._parentElm,
|
|
vm.$options._refElm
|
|
);
|
|
} else {
|
|
// updates
|
|
vm.$el = vm.__patch__(prevVnode, vnode);
|
|
}
|
|
activeInstance = prevActiveInstance;
|
|
// update __vue__ reference
|
|
if (prevEl) {
|
|
prevEl.__vue__ = null;
|
|
}
|
|
if (vm.$el) {
|
|
vm.$el.__vue__ = vm;
|
|
}
|
|
// if parent is an HOC, update its $el as well
|
|
if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
|
|
vm.$parent.$el = vm.$el;
|
|
}
|
|
// updated hook is called by the scheduler to ensure that children are
|
|
// updated in a parent's updated hook.
|
|
};
|
|
|
|
Vue.prototype.$forceUpdate = function () {
|
|
var vm = this;
|
|
if (vm._watcher) {
|
|
vm._watcher.update();
|
|
}
|
|
};
|
|
|
|
Vue.prototype.$destroy = function () {
|
|
var vm = this;
|
|
if (vm._isBeingDestroyed) {
|
|
return
|
|
}
|
|
callHook(vm, 'beforeDestroy');
|
|
vm._isBeingDestroyed = true;
|
|
// remove self from parent
|
|
var parent = vm.$parent;
|
|
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
|
|
remove(parent.$children, vm);
|
|
}
|
|
// teardown watchers
|
|
if (vm._watcher) {
|
|
vm._watcher.teardown();
|
|
}
|
|
var i = vm._watchers.length;
|
|
while (i--) {
|
|
vm._watchers[i].teardown();
|
|
}
|
|
// remove reference from data ob
|
|
// frozen object may not have observer.
|
|
if (vm._data.__ob__) {
|
|
vm._data.__ob__.vmCount--;
|
|
}
|
|
// call the last hook...
|
|
vm._isDestroyed = true;
|
|
callHook(vm, 'destroyed');
|
|
// turn off all instance listeners.
|
|
vm.$off();
|
|
// remove __vue__ reference
|
|
if (vm.$el) {
|
|
vm.$el.__vue__ = null;
|
|
}
|
|
// invoke destroy hooks on current rendered tree
|
|
vm.__patch__(vm._vnode, null);
|
|
};
|
|
}
|
|
|
|
function mountComponent (
|
|
vm,
|
|
el,
|
|
hydrating
|
|
) {
|
|
vm.$el = el;
|
|
if (!vm.$options.render) {
|
|
vm.$options.render = createEmptyVNode;
|
|
{
|
|
/* istanbul ignore if */
|
|
if (vm.$options.template && vm.$options.template.charAt(0) !== '#') {
|
|
warn(
|
|
'You are using the runtime-only build of Vue where the template ' +
|
|
'option is not available. Either pre-compile the templates into ' +
|
|
'render functions, or use the compiler-included build.',
|
|
vm
|
|
);
|
|
} else {
|
|
warn(
|
|
'Failed to mount component: template or render function not defined.',
|
|
vm
|
|
);
|
|
}
|
|
}
|
|
}
|
|
callHook(vm, 'beforeMount');
|
|
|
|
var updateComponent;
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && config.performance && perf) {
|
|
updateComponent = function () {
|
|
var name = vm._name;
|
|
var startTag = "start " + name;
|
|
var endTag = "end " + name;
|
|
perf.mark(startTag);
|
|
var vnode = vm._render();
|
|
perf.mark(endTag);
|
|
perf.measure((name + " render"), startTag, endTag);
|
|
perf.mark(startTag);
|
|
vm._update(vnode, hydrating);
|
|
perf.mark(endTag);
|
|
perf.measure((name + " patch"), startTag, endTag);
|
|
};
|
|
} else {
|
|
updateComponent = function () {
|
|
vm._update(vm._render(), hydrating);
|
|
};
|
|
}
|
|
|
|
vm._watcher = new Watcher(vm, updateComponent, noop);
|
|
hydrating = false;
|
|
|
|
// manually mounted instance, call mounted on self
|
|
// mounted is called for render-created child components in its inserted hook
|
|
if (vm.$vnode == null) {
|
|
vm._isMounted = true;
|
|
callHook(vm, 'mounted');
|
|
}
|
|
return vm
|
|
}
|
|
|
|
function updateChildComponent (
|
|
vm,
|
|
propsData,
|
|
listeners,
|
|
parentVnode,
|
|
renderChildren
|
|
) {
|
|
// determine whether component has slot children
|
|
// we need to do this before overwriting $options._renderChildren
|
|
var hasChildren = !!(
|
|
renderChildren || // has new static slots
|
|
vm.$options._renderChildren || // has old static slots
|
|
parentVnode.data.scopedSlots || // has new scoped slots
|
|
vm.$scopedSlots !== emptyObject // has old scoped slots
|
|
);
|
|
|
|
vm.$options._parentVnode = parentVnode;
|
|
vm.$vnode = parentVnode; // update vm's placeholder node without re-render
|
|
if (vm._vnode) { // update child tree's parent
|
|
vm._vnode.parent = parentVnode;
|
|
}
|
|
vm.$options._renderChildren = renderChildren;
|
|
|
|
// update props
|
|
if (propsData && vm.$options.props) {
|
|
observerState.shouldConvert = false;
|
|
{
|
|
observerState.isSettingProps = true;
|
|
}
|
|
var props = vm._props;
|
|
var propKeys = vm.$options._propKeys || [];
|
|
for (var i = 0; i < propKeys.length; i++) {
|
|
var key = propKeys[i];
|
|
props[key] = validateProp(key, vm.$options.props, propsData, vm);
|
|
}
|
|
observerState.shouldConvert = true;
|
|
{
|
|
observerState.isSettingProps = false;
|
|
}
|
|
// keep a copy of raw propsData
|
|
vm.$options.propsData = propsData;
|
|
}
|
|
// update listeners
|
|
if (listeners) {
|
|
var oldListeners = vm.$options._parentListeners;
|
|
vm.$options._parentListeners = listeners;
|
|
updateComponentListeners(vm, listeners, oldListeners);
|
|
}
|
|
// resolve slots + force update if has children
|
|
if (hasChildren) {
|
|
vm.$slots = resolveSlots(renderChildren, parentVnode.context);
|
|
vm.$forceUpdate();
|
|
}
|
|
}
|
|
|
|
function isInInactiveTree (vm) {
|
|
while (vm && (vm = vm.$parent)) {
|
|
if (vm._inactive) { return true }
|
|
}
|
|
return false
|
|
}
|
|
|
|
function activateChildComponent (vm, direct) {
|
|
if (direct) {
|
|
vm._directInactive = false;
|
|
if (isInInactiveTree(vm)) {
|
|
return
|
|
}
|
|
} else if (vm._directInactive) {
|
|
return
|
|
}
|
|
if (vm._inactive || vm._inactive == null) {
|
|
vm._inactive = false;
|
|
for (var i = 0; i < vm.$children.length; i++) {
|
|
activateChildComponent(vm.$children[i]);
|
|
}
|
|
callHook(vm, 'activated');
|
|
}
|
|
}
|
|
|
|
function deactivateChildComponent (vm, direct) {
|
|
if (direct) {
|
|
vm._directInactive = true;
|
|
if (isInInactiveTree(vm)) {
|
|
return
|
|
}
|
|
}
|
|
if (!vm._inactive) {
|
|
vm._inactive = true;
|
|
for (var i = 0; i < vm.$children.length; i++) {
|
|
deactivateChildComponent(vm.$children[i]);
|
|
}
|
|
callHook(vm, 'deactivated');
|
|
}
|
|
}
|
|
|
|
function callHook (vm, hook) {
|
|
var handlers = vm.$options[hook];
|
|
if (handlers) {
|
|
for (var i = 0, j = handlers.length; i < j; i++) {
|
|
try {
|
|
handlers[i].call(vm);
|
|
} catch (e) {
|
|
handleError(e, vm, (hook + " hook"));
|
|
}
|
|
}
|
|
}
|
|
if (vm._hasHookEvent) {
|
|
vm.$emit('hook:' + hook);
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
|
|
var queue = [];
|
|
var has = {};
|
|
var circular = {};
|
|
var waiting = false;
|
|
var flushing = false;
|
|
var index = 0;
|
|
|
|
/**
|
|
* Reset the scheduler's state.
|
|
*/
|
|
function resetSchedulerState () {
|
|
queue.length = 0;
|
|
has = {};
|
|
{
|
|
circular = {};
|
|
}
|
|
waiting = flushing = false;
|
|
}
|
|
|
|
/**
|
|
* Flush both queues and run the watchers.
|
|
*/
|
|
function flushSchedulerQueue () {
|
|
flushing = true;
|
|
var watcher, id, vm;
|
|
|
|
// Sort queue before flush.
|
|
// This ensures that:
|
|
// 1. Components are updated from parent to child. (because parent is always
|
|
// created before the child)
|
|
// 2. A component's user watchers are run before its render watcher (because
|
|
// user watchers are created before the render watcher)
|
|
// 3. If a component is destroyed during a parent component's watcher run,
|
|
// its watchers can be skipped.
|
|
queue.sort(function (a, b) { return a.id - b.id; });
|
|
|
|
// do not cache length because more watchers might be pushed
|
|
// as we run existing watchers
|
|
for (index = 0; index < queue.length; index++) {
|
|
watcher = queue[index];
|
|
id = watcher.id;
|
|
has[id] = null;
|
|
watcher.run();
|
|
// in dev build, check and stop circular updates.
|
|
if ("development" !== 'production' && has[id] != null) {
|
|
circular[id] = (circular[id] || 0) + 1;
|
|
if (circular[id] > config._maxUpdateCount) {
|
|
warn(
|
|
'You may have an infinite update loop ' + (
|
|
watcher.user
|
|
? ("in watcher with expression \"" + (watcher.expression) + "\"")
|
|
: "in a component render function."
|
|
),
|
|
watcher.vm
|
|
);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// call updated hooks
|
|
index = queue.length;
|
|
while (index--) {
|
|
watcher = queue[index];
|
|
vm = watcher.vm;
|
|
if (vm._watcher === watcher && vm._isMounted) {
|
|
callHook(vm, 'updated');
|
|
}
|
|
}
|
|
|
|
// devtool hook
|
|
/* istanbul ignore if */
|
|
if (devtools && config.devtools) {
|
|
devtools.emit('flush');
|
|
}
|
|
|
|
resetSchedulerState();
|
|
}
|
|
|
|
/**
|
|
* Push a watcher into the watcher queue.
|
|
* Jobs with duplicate IDs will be skipped unless it's
|
|
* pushed when the queue is being flushed.
|
|
*/
|
|
function queueWatcher (watcher) {
|
|
var id = watcher.id;
|
|
if (has[id] == null) {
|
|
has[id] = true;
|
|
if (!flushing) {
|
|
queue.push(watcher);
|
|
} else {
|
|
// if already flushing, splice the watcher based on its id
|
|
// if already past its id, it will be run next immediately.
|
|
var i = queue.length - 1;
|
|
while (i >= 0 && queue[i].id > watcher.id) {
|
|
i--;
|
|
}
|
|
queue.splice(Math.max(i, index) + 1, 0, watcher);
|
|
}
|
|
// queue the flush
|
|
if (!waiting) {
|
|
waiting = true;
|
|
nextTick(flushSchedulerQueue);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var uid$2 = 0;
|
|
|
|
/**
|
|
* A watcher parses an expression, collects dependencies,
|
|
* and fires callback when the expression value changes.
|
|
* This is used for both the $watch() api and directives.
|
|
*/
|
|
var Watcher = function Watcher (
|
|
vm,
|
|
expOrFn,
|
|
cb,
|
|
options
|
|
) {
|
|
this.vm = vm;
|
|
vm._watchers.push(this);
|
|
// options
|
|
if (options) {
|
|
this.deep = !!options.deep;
|
|
this.user = !!options.user;
|
|
this.lazy = !!options.lazy;
|
|
this.sync = !!options.sync;
|
|
} else {
|
|
this.deep = this.user = this.lazy = this.sync = false;
|
|
}
|
|
this.cb = cb;
|
|
this.id = ++uid$2; // uid for batching
|
|
this.active = true;
|
|
this.dirty = this.lazy; // for lazy watchers
|
|
this.deps = [];
|
|
this.newDeps = [];
|
|
this.depIds = new _Set();
|
|
this.newDepIds = new _Set();
|
|
this.expression = expOrFn.toString();
|
|
// parse expression for getter
|
|
if (typeof expOrFn === 'function') {
|
|
this.getter = expOrFn;
|
|
} else {
|
|
this.getter = parsePath(expOrFn);
|
|
if (!this.getter) {
|
|
this.getter = function () {};
|
|
"development" !== 'production' && warn(
|
|
"Failed watching path: \"" + expOrFn + "\" " +
|
|
'Watcher only accepts simple dot-delimited paths. ' +
|
|
'For full control, use a function instead.',
|
|
vm
|
|
);
|
|
}
|
|
}
|
|
this.value = this.lazy
|
|
? undefined
|
|
: this.get();
|
|
};
|
|
|
|
/**
|
|
* Evaluate the getter, and re-collect dependencies.
|
|
*/
|
|
Watcher.prototype.get = function get () {
|
|
pushTarget(this);
|
|
var value;
|
|
var vm = this.vm;
|
|
if (this.user) {
|
|
try {
|
|
value = this.getter.call(vm, vm);
|
|
} catch (e) {
|
|
handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
|
|
}
|
|
} else {
|
|
value = this.getter.call(vm, vm);
|
|
}
|
|
// "touch" every property so they are all tracked as
|
|
// dependencies for deep watching
|
|
if (this.deep) {
|
|
traverse(value);
|
|
}
|
|
popTarget();
|
|
this.cleanupDeps();
|
|
return value
|
|
};
|
|
|
|
/**
|
|
* Add a dependency to this directive.
|
|
*/
|
|
Watcher.prototype.addDep = function addDep (dep) {
|
|
var id = dep.id;
|
|
if (!this.newDepIds.has(id)) {
|
|
this.newDepIds.add(id);
|
|
this.newDeps.push(dep);
|
|
if (!this.depIds.has(id)) {
|
|
dep.addSub(this);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clean up for dependency collection.
|
|
*/
|
|
Watcher.prototype.cleanupDeps = function cleanupDeps () {
|
|
var this$1 = this;
|
|
|
|
var i = this.deps.length;
|
|
while (i--) {
|
|
var dep = this$1.deps[i];
|
|
if (!this$1.newDepIds.has(dep.id)) {
|
|
dep.removeSub(this$1);
|
|
}
|
|
}
|
|
var tmp = this.depIds;
|
|
this.depIds = this.newDepIds;
|
|
this.newDepIds = tmp;
|
|
this.newDepIds.clear();
|
|
tmp = this.deps;
|
|
this.deps = this.newDeps;
|
|
this.newDeps = tmp;
|
|
this.newDeps.length = 0;
|
|
};
|
|
|
|
/**
|
|
* Subscriber interface.
|
|
* Will be called when a dependency changes.
|
|
*/
|
|
Watcher.prototype.update = function update () {
|
|
/* istanbul ignore else */
|
|
if (this.lazy) {
|
|
this.dirty = true;
|
|
} else if (this.sync) {
|
|
this.run();
|
|
} else {
|
|
queueWatcher(this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Scheduler job interface.
|
|
* Will be called by the scheduler.
|
|
*/
|
|
Watcher.prototype.run = function run () {
|
|
if (this.active) {
|
|
var value = this.get();
|
|
if (
|
|
value !== this.value ||
|
|
// Deep watchers and watchers on Object/Arrays should fire even
|
|
// when the value is the same, because the value may
|
|
// have mutated.
|
|
isObject(value) ||
|
|
this.deep
|
|
) {
|
|
// set new value
|
|
var oldValue = this.value;
|
|
this.value = value;
|
|
if (this.user) {
|
|
try {
|
|
this.cb.call(this.vm, value, oldValue);
|
|
} catch (e) {
|
|
handleError(e, this.vm, ("callback for watcher \"" + (this.expression) + "\""));
|
|
}
|
|
} else {
|
|
this.cb.call(this.vm, value, oldValue);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Evaluate the value of the watcher.
|
|
* This only gets called for lazy watchers.
|
|
*/
|
|
Watcher.prototype.evaluate = function evaluate () {
|
|
this.value = this.get();
|
|
this.dirty = false;
|
|
};
|
|
|
|
/**
|
|
* Depend on all deps collected by this watcher.
|
|
*/
|
|
Watcher.prototype.depend = function depend () {
|
|
var this$1 = this;
|
|
|
|
var i = this.deps.length;
|
|
while (i--) {
|
|
this$1.deps[i].depend();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Remove self from all dependencies' subscriber list.
|
|
*/
|
|
Watcher.prototype.teardown = function teardown () {
|
|
var this$1 = this;
|
|
|
|
if (this.active) {
|
|
// remove self from vm's watcher list
|
|
// this is a somewhat expensive operation so we skip it
|
|
// if the vm is being destroyed.
|
|
if (!this.vm._isBeingDestroyed) {
|
|
remove(this.vm._watchers, this);
|
|
}
|
|
var i = this.deps.length;
|
|
while (i--) {
|
|
this$1.deps[i].removeSub(this$1);
|
|
}
|
|
this.active = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Recursively traverse an object to evoke all converted
|
|
* getters, so that every nested property inside the object
|
|
* is collected as a "deep" dependency.
|
|
*/
|
|
var seenObjects = new _Set();
|
|
function traverse (val) {
|
|
seenObjects.clear();
|
|
_traverse(val, seenObjects);
|
|
}
|
|
|
|
function _traverse (val, seen) {
|
|
var i, keys;
|
|
var isA = Array.isArray(val);
|
|
if ((!isA && !isObject(val)) || !Object.isExtensible(val)) {
|
|
return
|
|
}
|
|
if (val.__ob__) {
|
|
var depId = val.__ob__.dep.id;
|
|
if (seen.has(depId)) {
|
|
return
|
|
}
|
|
seen.add(depId);
|
|
}
|
|
if (isA) {
|
|
i = val.length;
|
|
while (i--) { _traverse(val[i], seen); }
|
|
} else {
|
|
keys = Object.keys(val);
|
|
i = keys.length;
|
|
while (i--) { _traverse(val[keys[i]], seen); }
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var sharedPropertyDefinition = {
|
|
enumerable: true,
|
|
configurable: true,
|
|
get: noop,
|
|
set: noop
|
|
};
|
|
|
|
function proxy (target, sourceKey, key) {
|
|
sharedPropertyDefinition.get = function proxyGetter () {
|
|
return this[sourceKey][key]
|
|
};
|
|
sharedPropertyDefinition.set = function proxySetter (val) {
|
|
this[sourceKey][key] = val;
|
|
};
|
|
Object.defineProperty(target, key, sharedPropertyDefinition);
|
|
}
|
|
|
|
function initState (vm) {
|
|
vm._watchers = [];
|
|
var opts = vm.$options;
|
|
if (opts.props) { initProps(vm, opts.props); }
|
|
if (opts.methods) { initMethods(vm, opts.methods); }
|
|
if (opts.data) {
|
|
initData(vm);
|
|
} else {
|
|
observe(vm._data = {}, true /* asRootData */);
|
|
}
|
|
if (opts.computed) { initComputed(vm, opts.computed); }
|
|
if (opts.watch) { initWatch(vm, opts.watch); }
|
|
}
|
|
|
|
var isReservedProp = { key: 1, ref: 1, slot: 1 };
|
|
|
|
function initProps (vm, propsOptions) {
|
|
var propsData = vm.$options.propsData || {};
|
|
var props = vm._props = {};
|
|
// cache prop keys so that future props updates can iterate using Array
|
|
// instead of dynamic object key enumeration.
|
|
var keys = vm.$options._propKeys = [];
|
|
var isRoot = !vm.$parent;
|
|
// root instance props should be converted
|
|
observerState.shouldConvert = isRoot;
|
|
var loop = function ( key ) {
|
|
keys.push(key);
|
|
var value = validateProp(key, propsOptions, propsData, vm);
|
|
/* istanbul ignore else */
|
|
{
|
|
if (isReservedProp[key]) {
|
|
warn(
|
|
("\"" + key + "\" is a reserved attribute and cannot be used as component prop."),
|
|
vm
|
|
);
|
|
}
|
|
defineReactive$$1(props, key, value, function () {
|
|
if (vm.$parent && !observerState.isSettingProps) {
|
|
warn(
|
|
"Avoid mutating a prop directly since the value will be " +
|
|
"overwritten whenever the parent component re-renders. " +
|
|
"Instead, use a data or computed property based on the prop's " +
|
|
"value. Prop being mutated: \"" + key + "\"",
|
|
vm
|
|
);
|
|
}
|
|
});
|
|
}
|
|
// static props are already proxied on the component's prototype
|
|
// during Vue.extend(). We only need to proxy props defined at
|
|
// instantiation here.
|
|
if (!(key in vm)) {
|
|
proxy(vm, "_props", key);
|
|
}
|
|
};
|
|
|
|
for (var key in propsOptions) loop( key );
|
|
observerState.shouldConvert = true;
|
|
}
|
|
|
|
function initData (vm) {
|
|
var data = vm.$options.data;
|
|
data = vm._data = typeof data === 'function'
|
|
? data.call(vm)
|
|
: data || {};
|
|
if (!isPlainObject(data)) {
|
|
data = {};
|
|
"development" !== 'production' && warn(
|
|
'data functions should return an object:\n' +
|
|
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
|
|
vm
|
|
);
|
|
}
|
|
// proxy data on instance
|
|
var keys = Object.keys(data);
|
|
var props = vm.$options.props;
|
|
var i = keys.length;
|
|
while (i--) {
|
|
if (props && hasOwn(props, keys[i])) {
|
|
"development" !== 'production' && warn(
|
|
"The data property \"" + (keys[i]) + "\" is already declared as a prop. " +
|
|
"Use prop default value instead.",
|
|
vm
|
|
);
|
|
} else if (!isReserved(keys[i])) {
|
|
proxy(vm, "_data", keys[i]);
|
|
}
|
|
}
|
|
// observe data
|
|
observe(data, true /* asRootData */);
|
|
}
|
|
|
|
var computedWatcherOptions = { lazy: true };
|
|
|
|
function initComputed (vm, computed) {
|
|
var watchers = vm._computedWatchers = Object.create(null);
|
|
|
|
for (var key in computed) {
|
|
var userDef = computed[key];
|
|
var getter = typeof userDef === 'function' ? userDef : userDef.get;
|
|
// create internal watcher for the computed property.
|
|
watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions);
|
|
|
|
// component-defined computed properties are already defined on the
|
|
// component prototype. We only need to define computed properties defined
|
|
// at instantiation here.
|
|
if (!(key in vm)) {
|
|
defineComputed(vm, key, userDef);
|
|
}
|
|
}
|
|
}
|
|
|
|
function defineComputed (target, key, userDef) {
|
|
if (typeof userDef === 'function') {
|
|
sharedPropertyDefinition.get = createComputedGetter(key);
|
|
sharedPropertyDefinition.set = noop;
|
|
} else {
|
|
sharedPropertyDefinition.get = userDef.get
|
|
? userDef.cache !== false
|
|
? createComputedGetter(key)
|
|
: userDef.get
|
|
: noop;
|
|
sharedPropertyDefinition.set = userDef.set
|
|
? userDef.set
|
|
: noop;
|
|
}
|
|
Object.defineProperty(target, key, sharedPropertyDefinition);
|
|
}
|
|
|
|
function createComputedGetter (key) {
|
|
return function computedGetter () {
|
|
var watcher = this._computedWatchers && this._computedWatchers[key];
|
|
if (watcher) {
|
|
if (watcher.dirty) {
|
|
watcher.evaluate();
|
|
}
|
|
if (Dep.target) {
|
|
watcher.depend();
|
|
}
|
|
return watcher.value
|
|
}
|
|
}
|
|
}
|
|
|
|
function initMethods (vm, methods) {
|
|
var props = vm.$options.props;
|
|
for (var key in methods) {
|
|
vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
|
|
{
|
|
if (methods[key] == null) {
|
|
warn(
|
|
"method \"" + key + "\" has an undefined value in the component definition. " +
|
|
"Did you reference the function correctly?",
|
|
vm
|
|
);
|
|
}
|
|
if (props && hasOwn(props, key)) {
|
|
warn(
|
|
("method \"" + key + "\" has already been defined as a prop."),
|
|
vm
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function initWatch (vm, watch) {
|
|
for (var key in watch) {
|
|
var handler = watch[key];
|
|
if (Array.isArray(handler)) {
|
|
for (var i = 0; i < handler.length; i++) {
|
|
createWatcher(vm, key, handler[i]);
|
|
}
|
|
} else {
|
|
createWatcher(vm, key, handler);
|
|
}
|
|
}
|
|
}
|
|
|
|
function createWatcher (vm, key, handler) {
|
|
var options;
|
|
if (isPlainObject(handler)) {
|
|
options = handler;
|
|
handler = handler.handler;
|
|
}
|
|
if (typeof handler === 'string') {
|
|
handler = vm[handler];
|
|
}
|
|
vm.$watch(key, handler, options);
|
|
}
|
|
|
|
function stateMixin (Vue) {
|
|
// flow somehow has problems with directly declared definition object
|
|
// when using Object.defineProperty, so we have to procedurally build up
|
|
// the object here.
|
|
var dataDef = {};
|
|
dataDef.get = function () { return this._data };
|
|
var propsDef = {};
|
|
propsDef.get = function () { return this._props };
|
|
{
|
|
dataDef.set = function (newData) {
|
|
warn(
|
|
'Avoid replacing instance root $data. ' +
|
|
'Use nested data properties instead.',
|
|
this
|
|
);
|
|
};
|
|
propsDef.set = function () {
|
|
warn("$props is readonly.", this);
|
|
};
|
|
}
|
|
Object.defineProperty(Vue.prototype, '$data', dataDef);
|
|
Object.defineProperty(Vue.prototype, '$props', propsDef);
|
|
|
|
Vue.prototype.$set = set;
|
|
Vue.prototype.$delete = del;
|
|
|
|
Vue.prototype.$watch = function (
|
|
expOrFn,
|
|
cb,
|
|
options
|
|
) {
|
|
var vm = this;
|
|
options = options || {};
|
|
options.user = true;
|
|
var watcher = new Watcher(vm, expOrFn, cb, options);
|
|
if (options.immediate) {
|
|
cb.call(vm, watcher.value);
|
|
}
|
|
return function unwatchFn () {
|
|
watcher.teardown();
|
|
}
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
var hooks = { init: init, prepatch: prepatch, insert: insert, destroy: destroy };
|
|
var hooksToMerge = Object.keys(hooks);
|
|
|
|
function createComponent (
|
|
Ctor,
|
|
data,
|
|
context,
|
|
children,
|
|
tag
|
|
) {
|
|
if (!Ctor) {
|
|
return
|
|
}
|
|
|
|
var baseCtor = context.$options._base;
|
|
if (isObject(Ctor)) {
|
|
Ctor = baseCtor.extend(Ctor);
|
|
}
|
|
|
|
if (typeof Ctor !== 'function') {
|
|
{
|
|
warn(("Invalid Component definition: " + (String(Ctor))), context);
|
|
}
|
|
return
|
|
}
|
|
|
|
// async component
|
|
if (!Ctor.cid) {
|
|
if (Ctor.resolved) {
|
|
Ctor = Ctor.resolved;
|
|
} else {
|
|
Ctor = resolveAsyncComponent(Ctor, baseCtor, function () {
|
|
// it's ok to queue this on every render because
|
|
// $forceUpdate is buffered by the scheduler.
|
|
context.$forceUpdate();
|
|
});
|
|
if (!Ctor) {
|
|
// return nothing if this is indeed an async component
|
|
// wait for the callback to trigger parent update.
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// resolve constructor options in case global mixins are applied after
|
|
// component constructor creation
|
|
resolveConstructorOptions(Ctor);
|
|
|
|
data = data || {};
|
|
|
|
// transform component v-model data into props & events
|
|
if (data.model) {
|
|
transformModel(Ctor.options, data);
|
|
}
|
|
|
|
// extract props
|
|
var propsData = extractProps(data, Ctor);
|
|
|
|
// functional component
|
|
if (Ctor.options.functional) {
|
|
return createFunctionalComponent(Ctor, propsData, data, context, children)
|
|
}
|
|
|
|
// extract listeners, since these needs to be treated as
|
|
// child component listeners instead of DOM listeners
|
|
var listeners = data.on;
|
|
// replace with listeners with .native modifier
|
|
data.on = data.nativeOn;
|
|
|
|
if (Ctor.options.abstract) {
|
|
// abstract components do not keep anything
|
|
// other than props & listeners
|
|
data = {};
|
|
}
|
|
|
|
// merge component management hooks onto the placeholder node
|
|
mergeHooks(data);
|
|
|
|
// return a placeholder vnode
|
|
var name = Ctor.options.name || tag;
|
|
var vnode = new VNode(
|
|
("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
|
|
data, undefined, undefined, undefined, context,
|
|
{ Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }
|
|
);
|
|
return vnode
|
|
}
|
|
|
|
function createFunctionalComponent (
|
|
Ctor,
|
|
propsData,
|
|
data,
|
|
context,
|
|
children
|
|
) {
|
|
var props = {};
|
|
var propOptions = Ctor.options.props;
|
|
if (propOptions) {
|
|
for (var key in propOptions) {
|
|
props[key] = validateProp(key, propOptions, propsData);
|
|
}
|
|
}
|
|
// ensure the createElement function in functional components
|
|
// gets a unique context - this is necessary for correct named slot check
|
|
var _context = Object.create(context);
|
|
var h = function (a, b, c, d) { return createElement(_context, a, b, c, d, true); };
|
|
var vnode = Ctor.options.render.call(null, h, {
|
|
props: props,
|
|
data: data,
|
|
parent: context,
|
|
children: children,
|
|
slots: function () { return resolveSlots(children, context); }
|
|
});
|
|
if (vnode instanceof VNode) {
|
|
vnode.functionalContext = context;
|
|
if (data.slot) {
|
|
(vnode.data || (vnode.data = {})).slot = data.slot;
|
|
}
|
|
}
|
|
return vnode
|
|
}
|
|
|
|
function createComponentInstanceForVnode (
|
|
vnode, // we know it's MountedComponentVNode but flow doesn't
|
|
parent, // activeInstance in lifecycle state
|
|
parentElm,
|
|
refElm
|
|
) {
|
|
var vnodeComponentOptions = vnode.componentOptions;
|
|
var options = {
|
|
_isComponent: true,
|
|
parent: parent,
|
|
propsData: vnodeComponentOptions.propsData,
|
|
_componentTag: vnodeComponentOptions.tag,
|
|
_parentVnode: vnode,
|
|
_parentListeners: vnodeComponentOptions.listeners,
|
|
_renderChildren: vnodeComponentOptions.children,
|
|
_parentElm: parentElm || null,
|
|
_refElm: refElm || null
|
|
};
|
|
// check inline-template render functions
|
|
var inlineTemplate = vnode.data.inlineTemplate;
|
|
if (inlineTemplate) {
|
|
options.render = inlineTemplate.render;
|
|
options.staticRenderFns = inlineTemplate.staticRenderFns;
|
|
}
|
|
return new vnodeComponentOptions.Ctor(options)
|
|
}
|
|
|
|
function init (
|
|
vnode,
|
|
hydrating,
|
|
parentElm,
|
|
refElm
|
|
) {
|
|
if (!vnode.componentInstance || vnode.componentInstance._isDestroyed) {
|
|
var child = vnode.componentInstance = createComponentInstanceForVnode(
|
|
vnode,
|
|
activeInstance,
|
|
parentElm,
|
|
refElm
|
|
);
|
|
child.$mount(hydrating ? vnode.elm : undefined, hydrating);
|
|
} else if (vnode.data.keepAlive) {
|
|
// kept-alive components, treat as a patch
|
|
var mountedNode = vnode; // work around flow
|
|
prepatch(mountedNode, mountedNode);
|
|
}
|
|
}
|
|
|
|
function prepatch (
|
|
oldVnode,
|
|
vnode
|
|
) {
|
|
var options = vnode.componentOptions;
|
|
var child = vnode.componentInstance = oldVnode.componentInstance;
|
|
updateChildComponent(
|
|
child,
|
|
options.propsData, // updated props
|
|
options.listeners, // updated listeners
|
|
vnode, // new parent vnode
|
|
options.children // new children
|
|
);
|
|
}
|
|
|
|
function insert (vnode) {
|
|
if (!vnode.componentInstance._isMounted) {
|
|
vnode.componentInstance._isMounted = true;
|
|
callHook(vnode.componentInstance, 'mounted');
|
|
}
|
|
if (vnode.data.keepAlive) {
|
|
activateChildComponent(vnode.componentInstance, true /* direct */);
|
|
}
|
|
}
|
|
|
|
function destroy (vnode) {
|
|
if (!vnode.componentInstance._isDestroyed) {
|
|
if (!vnode.data.keepAlive) {
|
|
vnode.componentInstance.$destroy();
|
|
} else {
|
|
deactivateChildComponent(vnode.componentInstance, true /* direct */);
|
|
}
|
|
}
|
|
}
|
|
|
|
function resolveAsyncComponent (
|
|
factory,
|
|
baseCtor,
|
|
cb
|
|
) {
|
|
if (factory.requested) {
|
|
// pool callbacks
|
|
factory.pendingCallbacks.push(cb);
|
|
} else {
|
|
factory.requested = true;
|
|
var cbs = factory.pendingCallbacks = [cb];
|
|
var sync = true;
|
|
|
|
var resolve = function (res) {
|
|
if (isObject(res)) {
|
|
res = baseCtor.extend(res);
|
|
}
|
|
// cache resolved
|
|
factory.resolved = res;
|
|
// invoke callbacks only if this is not a synchronous resolve
|
|
// (async resolves are shimmed as synchronous during SSR)
|
|
if (!sync) {
|
|
for (var i = 0, l = cbs.length; i < l; i++) {
|
|
cbs[i](res);
|
|
}
|
|
}
|
|
};
|
|
|
|
var reject = function (reason) {
|
|
"development" !== 'production' && warn(
|
|
"Failed to resolve async component: " + (String(factory)) +
|
|
(reason ? ("\nReason: " + reason) : '')
|
|
);
|
|
};
|
|
|
|
var res = factory(resolve, reject);
|
|
|
|
// handle promise
|
|
if (res && typeof res.then === 'function' && !factory.resolved) {
|
|
res.then(resolve, reject);
|
|
}
|
|
|
|
sync = false;
|
|
// return in case resolved synchronously
|
|
return factory.resolved
|
|
}
|
|
}
|
|
|
|
function extractProps (data, Ctor) {
|
|
// we are only extracting raw values here.
|
|
// validation and default values are handled in the child
|
|
// component itself.
|
|
var propOptions = Ctor.options.props;
|
|
if (!propOptions) {
|
|
return
|
|
}
|
|
var res = {};
|
|
var attrs = data.attrs;
|
|
var props = data.props;
|
|
var domProps = data.domProps;
|
|
if (attrs || props || domProps) {
|
|
for (var key in propOptions) {
|
|
var altKey = hyphenate(key);
|
|
checkProp(res, props, key, altKey, true) ||
|
|
checkProp(res, attrs, key, altKey) ||
|
|
checkProp(res, domProps, key, altKey);
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
function checkProp (
|
|
res,
|
|
hash,
|
|
key,
|
|
altKey,
|
|
preserve
|
|
) {
|
|
if (hash) {
|
|
if (hasOwn(hash, key)) {
|
|
res[key] = hash[key];
|
|
if (!preserve) {
|
|
delete hash[key];
|
|
}
|
|
return true
|
|
} else if (hasOwn(hash, altKey)) {
|
|
res[key] = hash[altKey];
|
|
if (!preserve) {
|
|
delete hash[altKey];
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
function mergeHooks (data) {
|
|
if (!data.hook) {
|
|
data.hook = {};
|
|
}
|
|
for (var i = 0; i < hooksToMerge.length; i++) {
|
|
var key = hooksToMerge[i];
|
|
var fromParent = data.hook[key];
|
|
var ours = hooks[key];
|
|
data.hook[key] = fromParent ? mergeHook$1(ours, fromParent) : ours;
|
|
}
|
|
}
|
|
|
|
function mergeHook$1 (one, two) {
|
|
return function (a, b, c, d) {
|
|
one(a, b, c, d);
|
|
two(a, b, c, d);
|
|
}
|
|
}
|
|
|
|
// transform component v-model info (value and callback) into
|
|
// prop and event handler respectively.
|
|
function transformModel (options, data) {
|
|
var prop = (options.model && options.model.prop) || 'value';
|
|
var event = (options.model && options.model.event) || 'input';(data.props || (data.props = {}))[prop] = data.model.value;
|
|
var on = data.on || (data.on = {});
|
|
if (on[event]) {
|
|
on[event] = [data.model.callback].concat(on[event]);
|
|
} else {
|
|
on[event] = data.model.callback;
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var SIMPLE_NORMALIZE = 1;
|
|
var ALWAYS_NORMALIZE = 2;
|
|
|
|
// wrapper function for providing a more flexible interface
|
|
// without getting yelled at by flow
|
|
function createElement (
|
|
context,
|
|
tag,
|
|
data,
|
|
children,
|
|
normalizationType,
|
|
alwaysNormalize
|
|
) {
|
|
if (Array.isArray(data) || isPrimitive(data)) {
|
|
normalizationType = children;
|
|
children = data;
|
|
data = undefined;
|
|
}
|
|
if (alwaysNormalize) { normalizationType = ALWAYS_NORMALIZE; }
|
|
return _createElement(context, tag, data, children, normalizationType)
|
|
}
|
|
|
|
function _createElement (
|
|
context,
|
|
tag,
|
|
data,
|
|
children,
|
|
normalizationType
|
|
) {
|
|
if (data && data.__ob__) {
|
|
"development" !== 'production' && warn(
|
|
"Avoid using observed data object as vnode data: " + (JSON.stringify(data)) + "\n" +
|
|
'Always create fresh vnode data objects in each render!',
|
|
context
|
|
);
|
|
return createEmptyVNode()
|
|
}
|
|
if (!tag) {
|
|
// in case of component :is set to falsy value
|
|
return createEmptyVNode()
|
|
}
|
|
// support single function children as default scoped slot
|
|
if (Array.isArray(children) &&
|
|
typeof children[0] === 'function') {
|
|
data = data || {};
|
|
data.scopedSlots = { default: children[0] };
|
|
children.length = 0;
|
|
}
|
|
if (normalizationType === ALWAYS_NORMALIZE) {
|
|
children = normalizeChildren(children);
|
|
} else if (normalizationType === SIMPLE_NORMALIZE) {
|
|
children = simpleNormalizeChildren(children);
|
|
}
|
|
var vnode, ns;
|
|
if (typeof tag === 'string') {
|
|
var Ctor;
|
|
ns = config.getTagNamespace(tag);
|
|
if (config.isReservedTag(tag)) {
|
|
// platform built-in elements
|
|
vnode = new VNode(
|
|
config.parsePlatformTagName(tag), data, children,
|
|
undefined, undefined, context
|
|
);
|
|
} else if ((Ctor = resolveAsset(context.$options, 'components', tag))) {
|
|
// component
|
|
vnode = createComponent(Ctor, data, context, children, tag);
|
|
} else {
|
|
// unknown or unlisted namespaced elements
|
|
// check at runtime because it may get assigned a namespace when its
|
|
// parent normalizes children
|
|
vnode = new VNode(
|
|
tag, data, children,
|
|
undefined, undefined, context
|
|
);
|
|
}
|
|
} else {
|
|
// direct component options / constructor
|
|
vnode = createComponent(tag, data, context, children);
|
|
}
|
|
if (vnode) {
|
|
if (ns) { applyNS(vnode, ns); }
|
|
return vnode
|
|
} else {
|
|
return createEmptyVNode()
|
|
}
|
|
}
|
|
|
|
function applyNS (vnode, ns) {
|
|
vnode.ns = ns;
|
|
if (vnode.tag === 'foreignObject') {
|
|
// use default namespace inside foreignObject
|
|
return
|
|
}
|
|
if (vnode.children) {
|
|
for (var i = 0, l = vnode.children.length; i < l; i++) {
|
|
var child = vnode.children[i];
|
|
if (child.tag && !child.ns) {
|
|
applyNS(child, ns);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for rendering v-for lists.
|
|
*/
|
|
function renderList (
|
|
val,
|
|
render
|
|
) {
|
|
var ret, i, l, keys, key;
|
|
if (Array.isArray(val) || typeof val === 'string') {
|
|
ret = new Array(val.length);
|
|
for (i = 0, l = val.length; i < l; i++) {
|
|
ret[i] = render(val[i], i);
|
|
}
|
|
} else if (typeof val === 'number') {
|
|
ret = new Array(val);
|
|
for (i = 0; i < val; i++) {
|
|
ret[i] = render(i + 1, i);
|
|
}
|
|
} else if (isObject(val)) {
|
|
keys = Object.keys(val);
|
|
ret = new Array(keys.length);
|
|
for (i = 0, l = keys.length; i < l; i++) {
|
|
key = keys[i];
|
|
ret[i] = render(val[key], key, i);
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for rendering <slot>
|
|
*/
|
|
function renderSlot (
|
|
name,
|
|
fallback,
|
|
props,
|
|
bindObject
|
|
) {
|
|
var scopedSlotFn = this.$scopedSlots[name];
|
|
if (scopedSlotFn) { // scoped slot
|
|
props = props || {};
|
|
if (bindObject) {
|
|
extend(props, bindObject);
|
|
}
|
|
return scopedSlotFn(props) || fallback
|
|
} else {
|
|
var slotNodes = this.$slots[name];
|
|
// warn duplicate slot usage
|
|
if (slotNodes && "development" !== 'production') {
|
|
slotNodes._rendered && warn(
|
|
"Duplicate presence of slot \"" + name + "\" found in the same render tree " +
|
|
"- this will likely cause render errors.",
|
|
this
|
|
);
|
|
slotNodes._rendered = true;
|
|
}
|
|
return slotNodes || fallback
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for resolving filters
|
|
*/
|
|
function resolveFilter (id) {
|
|
return resolveAsset(this.$options, 'filters', id, true) || identity
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for checking keyCodes from config.
|
|
*/
|
|
function checkKeyCodes (
|
|
eventKeyCode,
|
|
key,
|
|
builtInAlias
|
|
) {
|
|
var keyCodes = config.keyCodes[key] || builtInAlias;
|
|
if (Array.isArray(keyCodes)) {
|
|
return keyCodes.indexOf(eventKeyCode) === -1
|
|
} else {
|
|
return keyCodes !== eventKeyCode
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for merging v-bind="object" into a VNode's data.
|
|
*/
|
|
function bindObjectProps (
|
|
data,
|
|
tag,
|
|
value,
|
|
asProp
|
|
) {
|
|
if (value) {
|
|
if (!isObject(value)) {
|
|
"development" !== 'production' && warn(
|
|
'v-bind without argument expects an Object or Array value',
|
|
this
|
|
);
|
|
} else {
|
|
if (Array.isArray(value)) {
|
|
value = toObject(value);
|
|
}
|
|
for (var key in value) {
|
|
if (key === 'class' || key === 'style') {
|
|
data[key] = value[key];
|
|
} else {
|
|
var type = data.attrs && data.attrs.type;
|
|
var hash = asProp || config.mustUseProp(tag, type, key)
|
|
? data.domProps || (data.domProps = {})
|
|
: data.attrs || (data.attrs = {});
|
|
hash[key] = value[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return data
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Runtime helper for rendering static trees.
|
|
*/
|
|
function renderStatic (
|
|
index,
|
|
isInFor
|
|
) {
|
|
var tree = this._staticTrees[index];
|
|
// if has already-rendered static tree and not inside v-for,
|
|
// we can reuse the same tree by doing a shallow clone.
|
|
if (tree && !isInFor) {
|
|
return Array.isArray(tree)
|
|
? cloneVNodes(tree)
|
|
: cloneVNode(tree)
|
|
}
|
|
// otherwise, render a fresh tree.
|
|
tree = this._staticTrees[index] =
|
|
this.$options.staticRenderFns[index].call(this._renderProxy);
|
|
markStatic(tree, ("__static__" + index), false);
|
|
return tree
|
|
}
|
|
|
|
/**
|
|
* Runtime helper for v-once.
|
|
* Effectively it means marking the node as static with a unique key.
|
|
*/
|
|
function markOnce (
|
|
tree,
|
|
index,
|
|
key
|
|
) {
|
|
markStatic(tree, ("__once__" + index + (key ? ("_" + key) : "")), true);
|
|
return tree
|
|
}
|
|
|
|
function markStatic (
|
|
tree,
|
|
key,
|
|
isOnce
|
|
) {
|
|
if (Array.isArray(tree)) {
|
|
for (var i = 0; i < tree.length; i++) {
|
|
if (tree[i] && typeof tree[i] !== 'string') {
|
|
markStaticNode(tree[i], (key + "_" + i), isOnce);
|
|
}
|
|
}
|
|
} else {
|
|
markStaticNode(tree, key, isOnce);
|
|
}
|
|
}
|
|
|
|
function markStaticNode (node, key, isOnce) {
|
|
node.isStatic = true;
|
|
node.key = key;
|
|
node.isOnce = isOnce;
|
|
}
|
|
|
|
/* */
|
|
|
|
function initRender (vm) {
|
|
vm.$vnode = null; // the placeholder node in parent tree
|
|
vm._vnode = null; // the root of the child tree
|
|
vm._staticTrees = null;
|
|
var parentVnode = vm.$options._parentVnode;
|
|
var renderContext = parentVnode && parentVnode.context;
|
|
vm.$slots = resolveSlots(vm.$options._renderChildren, renderContext);
|
|
vm.$scopedSlots = emptyObject;
|
|
// bind the createElement fn to this instance
|
|
// so that we get proper render context inside it.
|
|
// args order: tag, data, children, normalizationType, alwaysNormalize
|
|
// internal version is used by render functions compiled from templates
|
|
vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };
|
|
// normalization is always applied for the public version, used in
|
|
// user-written render functions.
|
|
vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };
|
|
}
|
|
|
|
function renderMixin (Vue) {
|
|
Vue.prototype.$nextTick = function (fn) {
|
|
return nextTick(fn, this)
|
|
};
|
|
|
|
Vue.prototype._render = function () {
|
|
var vm = this;
|
|
var ref = vm.$options;
|
|
var render = ref.render;
|
|
var staticRenderFns = ref.staticRenderFns;
|
|
var _parentVnode = ref._parentVnode;
|
|
|
|
if (vm._isMounted) {
|
|
// clone slot nodes on re-renders
|
|
for (var key in vm.$slots) {
|
|
vm.$slots[key] = cloneVNodes(vm.$slots[key]);
|
|
}
|
|
}
|
|
|
|
vm.$scopedSlots = (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject;
|
|
|
|
if (staticRenderFns && !vm._staticTrees) {
|
|
vm._staticTrees = [];
|
|
}
|
|
// set parent vnode. this allows render functions to have access
|
|
// to the data on the placeholder node.
|
|
vm.$vnode = _parentVnode;
|
|
// render self
|
|
var vnode;
|
|
try {
|
|
vnode = render.call(vm._renderProxy, vm.$createElement);
|
|
} catch (e) {
|
|
handleError(e, vm, "render function");
|
|
// return error render result,
|
|
// or previous vnode to prevent render error causing blank component
|
|
/* istanbul ignore else */
|
|
{
|
|
vnode = vm.$options.renderError
|
|
? vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
|
|
: vm._vnode;
|
|
}
|
|
}
|
|
// return empty vnode in case the render function errored out
|
|
if (!(vnode instanceof VNode)) {
|
|
if ("development" !== 'production' && Array.isArray(vnode)) {
|
|
warn(
|
|
'Multiple root nodes returned from render function. Render function ' +
|
|
'should return a single root node.',
|
|
vm
|
|
);
|
|
}
|
|
vnode = createEmptyVNode();
|
|
}
|
|
// set parent
|
|
vnode.parent = _parentVnode;
|
|
return vnode
|
|
};
|
|
|
|
// internal render helpers.
|
|
// these are exposed on the instance prototype to reduce generated render
|
|
// code size.
|
|
Vue.prototype._o = markOnce;
|
|
Vue.prototype._n = toNumber;
|
|
Vue.prototype._s = _toString;
|
|
Vue.prototype._l = renderList;
|
|
Vue.prototype._t = renderSlot;
|
|
Vue.prototype._q = looseEqual;
|
|
Vue.prototype._i = looseIndexOf;
|
|
Vue.prototype._m = renderStatic;
|
|
Vue.prototype._f = resolveFilter;
|
|
Vue.prototype._k = checkKeyCodes;
|
|
Vue.prototype._b = bindObjectProps;
|
|
Vue.prototype._v = createTextVNode;
|
|
Vue.prototype._e = createEmptyVNode;
|
|
Vue.prototype._u = resolveScopedSlots;
|
|
}
|
|
|
|
/* */
|
|
|
|
function initInjections (vm) {
|
|
var provide = vm.$options.provide;
|
|
var inject = vm.$options.inject;
|
|
if (provide) {
|
|
vm._provided = typeof provide === 'function'
|
|
? provide.call(vm)
|
|
: provide;
|
|
}
|
|
if (inject) {
|
|
// inject is :any because flow is not smart enough to figure out cached
|
|
// isArray here
|
|
var isArray = Array.isArray(inject);
|
|
var keys = isArray
|
|
? inject
|
|
: hasSymbol
|
|
? Reflect.ownKeys(inject)
|
|
: Object.keys(inject);
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var provideKey = isArray ? key : inject[key];
|
|
var source = vm;
|
|
while (source) {
|
|
if (source._provided && source._provided[provideKey]) {
|
|
vm[key] = source._provided[provideKey];
|
|
break
|
|
}
|
|
source = source.$parent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var uid = 0;
|
|
|
|
function initMixin (Vue) {
|
|
Vue.prototype._init = function (options) {
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && config.performance && perf) {
|
|
perf.mark('init');
|
|
}
|
|
|
|
var vm = this;
|
|
// a uid
|
|
vm._uid = uid++;
|
|
// a flag to avoid this being observed
|
|
vm._isVue = true;
|
|
// merge options
|
|
if (options && options._isComponent) {
|
|
// optimize internal component instantiation
|
|
// since dynamic options merging is pretty slow, and none of the
|
|
// internal component options needs special treatment.
|
|
initInternalComponent(vm, options);
|
|
} else {
|
|
vm.$options = mergeOptions(
|
|
resolveConstructorOptions(vm.constructor),
|
|
options || {},
|
|
vm
|
|
);
|
|
}
|
|
/* istanbul ignore else */
|
|
{
|
|
initProxy(vm);
|
|
}
|
|
// expose real self
|
|
vm._self = vm;
|
|
initLifecycle(vm);
|
|
initEvents(vm);
|
|
initRender(vm);
|
|
callHook(vm, 'beforeCreate');
|
|
initState(vm);
|
|
initInjections(vm);
|
|
callHook(vm, 'created');
|
|
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && config.performance && perf) {
|
|
vm._name = formatComponentName(vm, false);
|
|
perf.mark('init end');
|
|
perf.measure(((vm._name) + " init"), 'init', 'init end');
|
|
}
|
|
|
|
if (vm.$options.el) {
|
|
vm.$mount(vm.$options.el);
|
|
}
|
|
};
|
|
}
|
|
|
|
function initInternalComponent (vm, options) {
|
|
var opts = vm.$options = Object.create(vm.constructor.options);
|
|
// doing this because it's faster than dynamic enumeration.
|
|
opts.parent = options.parent;
|
|
opts.propsData = options.propsData;
|
|
opts._parentVnode = options._parentVnode;
|
|
opts._parentListeners = options._parentListeners;
|
|
opts._renderChildren = options._renderChildren;
|
|
opts._componentTag = options._componentTag;
|
|
opts._parentElm = options._parentElm;
|
|
opts._refElm = options._refElm;
|
|
if (options.render) {
|
|
opts.render = options.render;
|
|
opts.staticRenderFns = options.staticRenderFns;
|
|
}
|
|
}
|
|
|
|
function resolveConstructorOptions (Ctor) {
|
|
var options = Ctor.options;
|
|
if (Ctor.super) {
|
|
var superOptions = resolveConstructorOptions(Ctor.super);
|
|
var cachedSuperOptions = Ctor.superOptions;
|
|
if (superOptions !== cachedSuperOptions) {
|
|
// super option changed,
|
|
// need to resolve new options.
|
|
Ctor.superOptions = superOptions;
|
|
// check if there are any late-modified/attached options (#4976)
|
|
var modifiedOptions = resolveModifiedOptions(Ctor);
|
|
// update base extend options
|
|
if (modifiedOptions) {
|
|
extend(Ctor.extendOptions, modifiedOptions);
|
|
}
|
|
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions);
|
|
if (options.name) {
|
|
options.components[options.name] = Ctor;
|
|
}
|
|
}
|
|
}
|
|
return options
|
|
}
|
|
|
|
function resolveModifiedOptions (Ctor) {
|
|
var modified;
|
|
var latest = Ctor.options;
|
|
var sealed = Ctor.sealedOptions;
|
|
for (var key in latest) {
|
|
if (latest[key] !== sealed[key]) {
|
|
if (!modified) { modified = {}; }
|
|
modified[key] = dedupe(latest[key], sealed[key]);
|
|
}
|
|
}
|
|
return modified
|
|
}
|
|
|
|
function dedupe (latest, sealed) {
|
|
// compare latest and sealed to ensure lifecycle hooks won't be duplicated
|
|
// between merges
|
|
if (Array.isArray(latest)) {
|
|
var res = [];
|
|
sealed = Array.isArray(sealed) ? sealed : [sealed];
|
|
for (var i = 0; i < latest.length; i++) {
|
|
if (sealed.indexOf(latest[i]) < 0) {
|
|
res.push(latest[i]);
|
|
}
|
|
}
|
|
return res
|
|
} else {
|
|
return latest
|
|
}
|
|
}
|
|
|
|
function Vue$3 (options) {
|
|
if ("development" !== 'production' &&
|
|
!(this instanceof Vue$3)) {
|
|
warn('Vue is a constructor and should be called with the `new` keyword');
|
|
}
|
|
this._init(options);
|
|
}
|
|
|
|
initMixin(Vue$3);
|
|
stateMixin(Vue$3);
|
|
eventsMixin(Vue$3);
|
|
lifecycleMixin(Vue$3);
|
|
renderMixin(Vue$3);
|
|
|
|
/* */
|
|
|
|
function initUse (Vue) {
|
|
Vue.use = function (plugin) {
|
|
/* istanbul ignore if */
|
|
if (plugin.installed) {
|
|
return
|
|
}
|
|
// additional parameters
|
|
var args = toArray(arguments, 1);
|
|
args.unshift(this);
|
|
if (typeof plugin.install === 'function') {
|
|
plugin.install.apply(plugin, args);
|
|
} else if (typeof plugin === 'function') {
|
|
plugin.apply(null, args);
|
|
}
|
|
plugin.installed = true;
|
|
return this
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
function initMixin$1 (Vue) {
|
|
Vue.mixin = function (mixin) {
|
|
this.options = mergeOptions(this.options, mixin);
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
function initExtend (Vue) {
|
|
/**
|
|
* Each instance constructor, including Vue, has a unique
|
|
* cid. This enables us to create wrapped "child
|
|
* constructors" for prototypal inheritance and cache them.
|
|
*/
|
|
Vue.cid = 0;
|
|
var cid = 1;
|
|
|
|
/**
|
|
* Class inheritance
|
|
*/
|
|
Vue.extend = function (extendOptions) {
|
|
extendOptions = extendOptions || {};
|
|
var Super = this;
|
|
var SuperId = Super.cid;
|
|
var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});
|
|
if (cachedCtors[SuperId]) {
|
|
return cachedCtors[SuperId]
|
|
}
|
|
|
|
var name = extendOptions.name || Super.options.name;
|
|
{
|
|
if (!/^[a-zA-Z][\w-]*$/.test(name)) {
|
|
warn(
|
|
'Invalid component name: "' + name + '". Component names ' +
|
|
'can only contain alphanumeric characters and the hyphen, ' +
|
|
'and must start with a letter.'
|
|
);
|
|
}
|
|
}
|
|
|
|
var Sub = function VueComponent (options) {
|
|
this._init(options);
|
|
};
|
|
Sub.prototype = Object.create(Super.prototype);
|
|
Sub.prototype.constructor = Sub;
|
|
Sub.cid = cid++;
|
|
Sub.options = mergeOptions(
|
|
Super.options,
|
|
extendOptions
|
|
);
|
|
Sub['super'] = Super;
|
|
|
|
// For props and computed properties, we define the proxy getters on
|
|
// the Vue instances at extension time, on the extended prototype. This
|
|
// avoids Object.defineProperty calls for each instance created.
|
|
if (Sub.options.props) {
|
|
initProps$1(Sub);
|
|
}
|
|
if (Sub.options.computed) {
|
|
initComputed$1(Sub);
|
|
}
|
|
|
|
// allow further extension/mixin/plugin usage
|
|
Sub.extend = Super.extend;
|
|
Sub.mixin = Super.mixin;
|
|
Sub.use = Super.use;
|
|
|
|
// create asset registers, so extended classes
|
|
// can have their private assets too.
|
|
config._assetTypes.forEach(function (type) {
|
|
Sub[type] = Super[type];
|
|
});
|
|
// enable recursive self-lookup
|
|
if (name) {
|
|
Sub.options.components[name] = Sub;
|
|
}
|
|
|
|
// keep a reference to the super options at extension time.
|
|
// later at instantiation we can check if Super's options have
|
|
// been updated.
|
|
Sub.superOptions = Super.options;
|
|
Sub.extendOptions = extendOptions;
|
|
Sub.sealedOptions = extend({}, Sub.options);
|
|
|
|
// cache constructor
|
|
cachedCtors[SuperId] = Sub;
|
|
return Sub
|
|
};
|
|
}
|
|
|
|
function initProps$1 (Comp) {
|
|
var props = Comp.options.props;
|
|
for (var key in props) {
|
|
proxy(Comp.prototype, "_props", key);
|
|
}
|
|
}
|
|
|
|
function initComputed$1 (Comp) {
|
|
var computed = Comp.options.computed;
|
|
for (var key in computed) {
|
|
defineComputed(Comp.prototype, key, computed[key]);
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function initAssetRegisters (Vue) {
|
|
/**
|
|
* Create asset registration methods.
|
|
*/
|
|
config._assetTypes.forEach(function (type) {
|
|
Vue[type] = function (
|
|
id,
|
|
definition
|
|
) {
|
|
if (!definition) {
|
|
return this.options[type + 's'][id]
|
|
} else {
|
|
/* istanbul ignore if */
|
|
{
|
|
if (type === 'component' && config.isReservedTag(id)) {
|
|
warn(
|
|
'Do not use built-in or reserved HTML elements as component ' +
|
|
'id: ' + id
|
|
);
|
|
}
|
|
}
|
|
if (type === 'component' && isPlainObject(definition)) {
|
|
definition.name = definition.name || id;
|
|
definition = this.options._base.extend(definition);
|
|
}
|
|
if (type === 'directive' && typeof definition === 'function') {
|
|
definition = { bind: definition, update: definition };
|
|
}
|
|
this.options[type + 's'][id] = definition;
|
|
return definition
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
/* */
|
|
|
|
var patternTypes = [String, RegExp];
|
|
|
|
function getComponentName (opts) {
|
|
return opts && (opts.Ctor.options.name || opts.tag)
|
|
}
|
|
|
|
function matches (pattern, name) {
|
|
if (typeof pattern === 'string') {
|
|
return pattern.split(',').indexOf(name) > -1
|
|
} else if (pattern instanceof RegExp) {
|
|
return pattern.test(name)
|
|
}
|
|
/* istanbul ignore next */
|
|
return false
|
|
}
|
|
|
|
function pruneCache (cache, filter) {
|
|
for (var key in cache) {
|
|
var cachedNode = cache[key];
|
|
if (cachedNode) {
|
|
var name = getComponentName(cachedNode.componentOptions);
|
|
if (name && !filter(name)) {
|
|
pruneCacheEntry(cachedNode);
|
|
cache[key] = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function pruneCacheEntry (vnode) {
|
|
if (vnode) {
|
|
if (!vnode.componentInstance._inactive) {
|
|
callHook(vnode.componentInstance, 'deactivated');
|
|
}
|
|
vnode.componentInstance.$destroy();
|
|
}
|
|
}
|
|
|
|
var KeepAlive = {
|
|
name: 'keep-alive',
|
|
abstract: true,
|
|
|
|
props: {
|
|
include: patternTypes,
|
|
exclude: patternTypes
|
|
},
|
|
|
|
created: function created () {
|
|
this.cache = Object.create(null);
|
|
},
|
|
|
|
destroyed: function destroyed () {
|
|
var this$1 = this;
|
|
|
|
for (var key in this$1.cache) {
|
|
pruneCacheEntry(this$1.cache[key]);
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
include: function include (val) {
|
|
pruneCache(this.cache, function (name) { return matches(val, name); });
|
|
},
|
|
exclude: function exclude (val) {
|
|
pruneCache(this.cache, function (name) { return !matches(val, name); });
|
|
}
|
|
},
|
|
|
|
render: function render () {
|
|
var vnode = getFirstComponentChild(this.$slots.default);
|
|
var componentOptions = vnode && vnode.componentOptions;
|
|
if (componentOptions) {
|
|
// check pattern
|
|
var name = getComponentName(componentOptions);
|
|
if (name && (
|
|
(this.include && !matches(this.include, name)) ||
|
|
(this.exclude && matches(this.exclude, name))
|
|
)) {
|
|
return vnode
|
|
}
|
|
var key = vnode.key == null
|
|
// same constructor may get registered as different local components
|
|
// so cid alone is not enough (#3269)
|
|
? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : '')
|
|
: vnode.key;
|
|
if (this.cache[key]) {
|
|
vnode.componentInstance = this.cache[key].componentInstance;
|
|
} else {
|
|
this.cache[key] = vnode;
|
|
}
|
|
vnode.data.keepAlive = true;
|
|
}
|
|
return vnode
|
|
}
|
|
};
|
|
|
|
var builtInComponents = {
|
|
KeepAlive: KeepAlive
|
|
};
|
|
|
|
/* */
|
|
|
|
function initGlobalAPI (Vue) {
|
|
// config
|
|
var configDef = {};
|
|
configDef.get = function () { return config; };
|
|
{
|
|
configDef.set = function () {
|
|
warn(
|
|
'Do not replace the Vue.config object, set individual fields instead.'
|
|
);
|
|
};
|
|
}
|
|
Object.defineProperty(Vue, 'config', configDef);
|
|
|
|
// exposed util methods.
|
|
// NOTE: these are not considered part of the public API - avoid relying on
|
|
// them unless you are aware of the risk.
|
|
Vue.util = {
|
|
warn: warn,
|
|
extend: extend,
|
|
mergeOptions: mergeOptions,
|
|
defineReactive: defineReactive$$1
|
|
};
|
|
|
|
Vue.set = set;
|
|
Vue.delete = del;
|
|
Vue.nextTick = nextTick;
|
|
|
|
Vue.options = Object.create(null);
|
|
config._assetTypes.forEach(function (type) {
|
|
Vue.options[type + 's'] = Object.create(null);
|
|
});
|
|
|
|
// this is used to identify the "base" constructor to extend all plain-object
|
|
// components with in Weex's multi-instance scenarios.
|
|
Vue.options._base = Vue;
|
|
|
|
extend(Vue.options.components, builtInComponents);
|
|
|
|
initUse(Vue);
|
|
initMixin$1(Vue);
|
|
initExtend(Vue);
|
|
initAssetRegisters(Vue);
|
|
}
|
|
|
|
initGlobalAPI(Vue$3);
|
|
|
|
Object.defineProperty(Vue$3.prototype, '$isServer', {
|
|
get: isServerRendering
|
|
});
|
|
|
|
Vue$3.version = '2.2.0';
|
|
|
|
/* */
|
|
|
|
// attributes that should be using props for binding
|
|
var acceptValue = makeMap('input,textarea,option,select');
|
|
var mustUseProp = function (tag, type, attr) {
|
|
return (
|
|
(attr === 'value' && acceptValue(tag)) && type !== 'button' ||
|
|
(attr === 'selected' && tag === 'option') ||
|
|
(attr === 'checked' && tag === 'input') ||
|
|
(attr === 'muted' && tag === 'video')
|
|
)
|
|
};
|
|
|
|
var isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck');
|
|
|
|
var isBooleanAttr = makeMap(
|
|
'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +
|
|
'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +
|
|
'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +
|
|
'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +
|
|
'required,reversed,scoped,seamless,selected,sortable,translate,' +
|
|
'truespeed,typemustmatch,visible'
|
|
);
|
|
|
|
var xlinkNS = 'http://www.w3.org/1999/xlink';
|
|
|
|
var isXlink = function (name) {
|
|
return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'
|
|
};
|
|
|
|
var getXlinkProp = function (name) {
|
|
return isXlink(name) ? name.slice(6, name.length) : ''
|
|
};
|
|
|
|
var isFalsyAttrValue = function (val) {
|
|
return val == null || val === false
|
|
};
|
|
|
|
/* */
|
|
|
|
function genClassForVnode (vnode) {
|
|
var data = vnode.data;
|
|
var parentNode = vnode;
|
|
var childNode = vnode;
|
|
while (childNode.componentInstance) {
|
|
childNode = childNode.componentInstance._vnode;
|
|
if (childNode.data) {
|
|
data = mergeClassData(childNode.data, data);
|
|
}
|
|
}
|
|
while ((parentNode = parentNode.parent)) {
|
|
if (parentNode.data) {
|
|
data = mergeClassData(data, parentNode.data);
|
|
}
|
|
}
|
|
return genClassFromData(data)
|
|
}
|
|
|
|
function mergeClassData (child, parent) {
|
|
return {
|
|
staticClass: concat(child.staticClass, parent.staticClass),
|
|
class: child.class
|
|
? [child.class, parent.class]
|
|
: parent.class
|
|
}
|
|
}
|
|
|
|
function genClassFromData (data) {
|
|
var dynamicClass = data.class;
|
|
var staticClass = data.staticClass;
|
|
if (staticClass || dynamicClass) {
|
|
return concat(staticClass, stringifyClass(dynamicClass))
|
|
}
|
|
/* istanbul ignore next */
|
|
return ''
|
|
}
|
|
|
|
function concat (a, b) {
|
|
return a ? b ? (a + ' ' + b) : a : (b || '')
|
|
}
|
|
|
|
function stringifyClass (value) {
|
|
var res = '';
|
|
if (!value) {
|
|
return res
|
|
}
|
|
if (typeof value === 'string') {
|
|
return value
|
|
}
|
|
if (Array.isArray(value)) {
|
|
var stringified;
|
|
for (var i = 0, l = value.length; i < l; i++) {
|
|
if (value[i]) {
|
|
if ((stringified = stringifyClass(value[i]))) {
|
|
res += stringified + ' ';
|
|
}
|
|
}
|
|
}
|
|
return res.slice(0, -1)
|
|
}
|
|
if (isObject(value)) {
|
|
for (var key in value) {
|
|
if (value[key]) { res += key + ' '; }
|
|
}
|
|
return res.slice(0, -1)
|
|
}
|
|
/* istanbul ignore next */
|
|
return res
|
|
}
|
|
|
|
/* */
|
|
|
|
var namespaceMap = {
|
|
svg: 'http://www.w3.org/2000/svg',
|
|
math: 'http://www.w3.org/1998/Math/MathML'
|
|
};
|
|
|
|
var isHTMLTag = makeMap(
|
|
'html,body,base,head,link,meta,style,title,' +
|
|
'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
|
|
'div,dd,dl,dt,figcaption,figure,hr,img,li,main,ol,p,pre,ul,' +
|
|
'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
|
|
's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
|
|
'embed,object,param,source,canvas,script,noscript,del,ins,' +
|
|
'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
|
|
'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
|
|
'output,progress,select,textarea,' +
|
|
'details,dialog,menu,menuitem,summary,' +
|
|
'content,element,shadow,template'
|
|
);
|
|
|
|
// this map is intentionally selective, only covering SVG elements that may
|
|
// contain child elements.
|
|
var isSVG = makeMap(
|
|
'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
|
|
'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
|
|
'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
|
|
true
|
|
);
|
|
|
|
var isPreTag = function (tag) { return tag === 'pre'; };
|
|
|
|
var isReservedTag = function (tag) {
|
|
return isHTMLTag(tag) || isSVG(tag)
|
|
};
|
|
|
|
function getTagNamespace (tag) {
|
|
if (isSVG(tag)) {
|
|
return 'svg'
|
|
}
|
|
// basic support for MathML
|
|
// note it doesn't support other MathML elements being component roots
|
|
if (tag === 'math') {
|
|
return 'math'
|
|
}
|
|
}
|
|
|
|
var unknownElementCache = Object.create(null);
|
|
function isUnknownElement (tag) {
|
|
/* istanbul ignore if */
|
|
if (!inBrowser) {
|
|
return true
|
|
}
|
|
if (isReservedTag(tag)) {
|
|
return false
|
|
}
|
|
tag = tag.toLowerCase();
|
|
/* istanbul ignore if */
|
|
if (unknownElementCache[tag] != null) {
|
|
return unknownElementCache[tag]
|
|
}
|
|
var el = document.createElement(tag);
|
|
if (tag.indexOf('-') > -1) {
|
|
// http://stackoverflow.com/a/28210364/1070244
|
|
return (unknownElementCache[tag] = (
|
|
el.constructor === window.HTMLUnknownElement ||
|
|
el.constructor === window.HTMLElement
|
|
))
|
|
} else {
|
|
return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Query an element selector if it's not an element already.
|
|
*/
|
|
function query (el) {
|
|
if (typeof el === 'string') {
|
|
var selected = document.querySelector(el);
|
|
if (!selected) {
|
|
"development" !== 'production' && warn(
|
|
'Cannot find element: ' + el
|
|
);
|
|
return document.createElement('div')
|
|
}
|
|
return selected
|
|
} else {
|
|
return el
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function createElement$1 (tagName, vnode) {
|
|
var elm = document.createElement(tagName);
|
|
if (tagName !== 'select') {
|
|
return elm
|
|
}
|
|
// false or null will remove the attribute but undefined will not
|
|
if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) {
|
|
elm.setAttribute('multiple', 'multiple');
|
|
}
|
|
return elm
|
|
}
|
|
|
|
function createElementNS (namespace, tagName) {
|
|
return document.createElementNS(namespaceMap[namespace], tagName)
|
|
}
|
|
|
|
function createTextNode (text) {
|
|
return document.createTextNode(text)
|
|
}
|
|
|
|
function createComment (text) {
|
|
return document.createComment(text)
|
|
}
|
|
|
|
function insertBefore (parentNode, newNode, referenceNode) {
|
|
parentNode.insertBefore(newNode, referenceNode);
|
|
}
|
|
|
|
function removeChild (node, child) {
|
|
node.removeChild(child);
|
|
}
|
|
|
|
function appendChild (node, child) {
|
|
node.appendChild(child);
|
|
}
|
|
|
|
function parentNode (node) {
|
|
return node.parentNode
|
|
}
|
|
|
|
function nextSibling (node) {
|
|
return node.nextSibling
|
|
}
|
|
|
|
function tagName (node) {
|
|
return node.tagName
|
|
}
|
|
|
|
function setTextContent (node, text) {
|
|
node.textContent = text;
|
|
}
|
|
|
|
function setAttribute (node, key, val) {
|
|
node.setAttribute(key, val);
|
|
}
|
|
|
|
|
|
var nodeOps = Object.freeze({
|
|
createElement: createElement$1,
|
|
createElementNS: createElementNS,
|
|
createTextNode: createTextNode,
|
|
createComment: createComment,
|
|
insertBefore: insertBefore,
|
|
removeChild: removeChild,
|
|
appendChild: appendChild,
|
|
parentNode: parentNode,
|
|
nextSibling: nextSibling,
|
|
tagName: tagName,
|
|
setTextContent: setTextContent,
|
|
setAttribute: setAttribute
|
|
});
|
|
|
|
/* */
|
|
|
|
var ref = {
|
|
create: function create (_, vnode) {
|
|
registerRef(vnode);
|
|
},
|
|
update: function update (oldVnode, vnode) {
|
|
if (oldVnode.data.ref !== vnode.data.ref) {
|
|
registerRef(oldVnode, true);
|
|
registerRef(vnode);
|
|
}
|
|
},
|
|
destroy: function destroy (vnode) {
|
|
registerRef(vnode, true);
|
|
}
|
|
};
|
|
|
|
function registerRef (vnode, isRemoval) {
|
|
var key = vnode.data.ref;
|
|
if (!key) { return }
|
|
|
|
var vm = vnode.context;
|
|
var ref = vnode.componentInstance || vnode.elm;
|
|
var refs = vm.$refs;
|
|
if (isRemoval) {
|
|
if (Array.isArray(refs[key])) {
|
|
remove(refs[key], ref);
|
|
} else if (refs[key] === ref) {
|
|
refs[key] = undefined;
|
|
}
|
|
} else {
|
|
if (vnode.data.refInFor) {
|
|
if (Array.isArray(refs[key]) && refs[key].indexOf(ref) < 0) {
|
|
refs[key].push(ref);
|
|
} else {
|
|
refs[key] = [ref];
|
|
}
|
|
} else {
|
|
refs[key] = ref;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Virtual DOM patching algorithm based on Snabbdom by
|
|
* Simon Friis Vindum (@paldepind)
|
|
* Licensed under the MIT License
|
|
* https://github.com/paldepind/snabbdom/blob/master/LICENSE
|
|
*
|
|
* modified by Evan You (@yyx990803)
|
|
*
|
|
|
|
/*
|
|
* Not type-checking this because this file is perf-critical and the cost
|
|
* of making flow understand it is not worth it.
|
|
*/
|
|
|
|
var emptyNode = new VNode('', {}, []);
|
|
|
|
var hooks$1 = ['create', 'activate', 'update', 'remove', 'destroy'];
|
|
|
|
function isUndef (s) {
|
|
return s == null
|
|
}
|
|
|
|
function isDef (s) {
|
|
return s != null
|
|
}
|
|
|
|
function sameVnode (vnode1, vnode2) {
|
|
return (
|
|
vnode1.key === vnode2.key &&
|
|
vnode1.tag === vnode2.tag &&
|
|
vnode1.isComment === vnode2.isComment &&
|
|
!vnode1.data === !vnode2.data
|
|
)
|
|
}
|
|
|
|
function createKeyToOldIdx (children, beginIdx, endIdx) {
|
|
var i, key;
|
|
var map = {};
|
|
for (i = beginIdx; i <= endIdx; ++i) {
|
|
key = children[i].key;
|
|
if (isDef(key)) { map[key] = i; }
|
|
}
|
|
return map
|
|
}
|
|
|
|
function createPatchFunction (backend) {
|
|
var i, j;
|
|
var cbs = {};
|
|
|
|
var modules = backend.modules;
|
|
var nodeOps = backend.nodeOps;
|
|
|
|
for (i = 0; i < hooks$1.length; ++i) {
|
|
cbs[hooks$1[i]] = [];
|
|
for (j = 0; j < modules.length; ++j) {
|
|
if (modules[j][hooks$1[i]] !== undefined) { cbs[hooks$1[i]].push(modules[j][hooks$1[i]]); }
|
|
}
|
|
}
|
|
|
|
function emptyNodeAt (elm) {
|
|
return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
|
|
}
|
|
|
|
function createRmCb (childElm, listeners) {
|
|
function remove$$1 () {
|
|
if (--remove$$1.listeners === 0) {
|
|
removeNode(childElm);
|
|
}
|
|
}
|
|
remove$$1.listeners = listeners;
|
|
return remove$$1
|
|
}
|
|
|
|
function removeNode (el) {
|
|
var parent = nodeOps.parentNode(el);
|
|
// element may have already been removed due to v-html / v-text
|
|
if (parent) {
|
|
nodeOps.removeChild(parent, el);
|
|
}
|
|
}
|
|
|
|
var inPre = 0;
|
|
function createElm (vnode, insertedVnodeQueue, parentElm, refElm, nested) {
|
|
vnode.isRootInsert = !nested; // for transition enter check
|
|
if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
|
|
return
|
|
}
|
|
|
|
var data = vnode.data;
|
|
var children = vnode.children;
|
|
var tag = vnode.tag;
|
|
if (isDef(tag)) {
|
|
{
|
|
if (data && data.pre) {
|
|
inPre++;
|
|
}
|
|
if (
|
|
!inPre &&
|
|
!vnode.ns &&
|
|
!(config.ignoredElements.length && config.ignoredElements.indexOf(tag) > -1) &&
|
|
config.isUnknownElement(tag)
|
|
) {
|
|
warn(
|
|
'Unknown custom element: <' + tag + '> - did you ' +
|
|
'register the component correctly? For recursive components, ' +
|
|
'make sure to provide the "name" option.',
|
|
vnode.context
|
|
);
|
|
}
|
|
}
|
|
vnode.elm = vnode.ns
|
|
? nodeOps.createElementNS(vnode.ns, tag)
|
|
: nodeOps.createElement(tag, vnode);
|
|
setScope(vnode);
|
|
|
|
/* istanbul ignore if */
|
|
{
|
|
createChildren(vnode, children, insertedVnodeQueue);
|
|
if (isDef(data)) {
|
|
invokeCreateHooks(vnode, insertedVnodeQueue);
|
|
}
|
|
insert(parentElm, vnode.elm, refElm);
|
|
}
|
|
|
|
if ("development" !== 'production' && data && data.pre) {
|
|
inPre--;
|
|
}
|
|
} else if (vnode.isComment) {
|
|
vnode.elm = nodeOps.createComment(vnode.text);
|
|
insert(parentElm, vnode.elm, refElm);
|
|
} else {
|
|
vnode.elm = nodeOps.createTextNode(vnode.text);
|
|
insert(parentElm, vnode.elm, refElm);
|
|
}
|
|
}
|
|
|
|
function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
|
|
var i = vnode.data;
|
|
if (isDef(i)) {
|
|
var isReactivated = isDef(vnode.componentInstance) && i.keepAlive;
|
|
if (isDef(i = i.hook) && isDef(i = i.init)) {
|
|
i(vnode, false /* hydrating */, parentElm, refElm);
|
|
}
|
|
// after calling the init hook, if the vnode is a child component
|
|
// it should've created a child instance and mounted it. the child
|
|
// component also has set the placeholder vnode's elm.
|
|
// in that case we can just return the element and be done.
|
|
if (isDef(vnode.componentInstance)) {
|
|
initComponent(vnode, insertedVnodeQueue);
|
|
if (isReactivated) {
|
|
reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm);
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
function initComponent (vnode, insertedVnodeQueue) {
|
|
if (vnode.data.pendingInsert) {
|
|
insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert);
|
|
}
|
|
vnode.elm = vnode.componentInstance.$el;
|
|
if (isPatchable(vnode)) {
|
|
invokeCreateHooks(vnode, insertedVnodeQueue);
|
|
setScope(vnode);
|
|
} else {
|
|
// empty component root.
|
|
// skip all element-related modules except for ref (#3455)
|
|
registerRef(vnode);
|
|
// make sure to invoke the insert hook
|
|
insertedVnodeQueue.push(vnode);
|
|
}
|
|
}
|
|
|
|
function reactivateComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
|
|
var i;
|
|
// hack for #4339: a reactivated component with inner transition
|
|
// does not trigger because the inner node's created hooks are not called
|
|
// again. It's not ideal to involve module-specific logic in here but
|
|
// there doesn't seem to be a better way to do it.
|
|
var innerNode = vnode;
|
|
while (innerNode.componentInstance) {
|
|
innerNode = innerNode.componentInstance._vnode;
|
|
if (isDef(i = innerNode.data) && isDef(i = i.transition)) {
|
|
for (i = 0; i < cbs.activate.length; ++i) {
|
|
cbs.activate[i](emptyNode, innerNode);
|
|
}
|
|
insertedVnodeQueue.push(innerNode);
|
|
break
|
|
}
|
|
}
|
|
// unlike a newly created component,
|
|
// a reactivated keep-alive component doesn't insert itself
|
|
insert(parentElm, vnode.elm, refElm);
|
|
}
|
|
|
|
function insert (parent, elm, ref) {
|
|
if (parent) {
|
|
if (ref) {
|
|
nodeOps.insertBefore(parent, elm, ref);
|
|
} else {
|
|
nodeOps.appendChild(parent, elm);
|
|
}
|
|
}
|
|
}
|
|
|
|
function createChildren (vnode, children, insertedVnodeQueue) {
|
|
if (Array.isArray(children)) {
|
|
for (var i = 0; i < children.length; ++i) {
|
|
createElm(children[i], insertedVnodeQueue, vnode.elm, null, true);
|
|
}
|
|
} else if (isPrimitive(vnode.text)) {
|
|
nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(vnode.text));
|
|
}
|
|
}
|
|
|
|
function isPatchable (vnode) {
|
|
while (vnode.componentInstance) {
|
|
vnode = vnode.componentInstance._vnode;
|
|
}
|
|
return isDef(vnode.tag)
|
|
}
|
|
|
|
function invokeCreateHooks (vnode, insertedVnodeQueue) {
|
|
for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
|
|
cbs.create[i$1](emptyNode, vnode);
|
|
}
|
|
i = vnode.data.hook; // Reuse variable
|
|
if (isDef(i)) {
|
|
if (i.create) { i.create(emptyNode, vnode); }
|
|
if (i.insert) { insertedVnodeQueue.push(vnode); }
|
|
}
|
|
}
|
|
|
|
// set scope id attribute for scoped CSS.
|
|
// this is implemented as a special case to avoid the overhead
|
|
// of going through the normal attribute patching process.
|
|
function setScope (vnode) {
|
|
var i;
|
|
var ancestor = vnode;
|
|
while (ancestor) {
|
|
if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) {
|
|
nodeOps.setAttribute(vnode.elm, i, '');
|
|
}
|
|
ancestor = ancestor.parent;
|
|
}
|
|
// for slot content they should also get the scopeId from the host instance.
|
|
if (isDef(i = activeInstance) &&
|
|
i !== vnode.context &&
|
|
isDef(i = i.$options._scopeId)) {
|
|
nodeOps.setAttribute(vnode.elm, i, '');
|
|
}
|
|
}
|
|
|
|
function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
|
|
for (; startIdx <= endIdx; ++startIdx) {
|
|
createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm);
|
|
}
|
|
}
|
|
|
|
function invokeDestroyHook (vnode) {
|
|
var i, j;
|
|
var data = vnode.data;
|
|
if (isDef(data)) {
|
|
if (isDef(i = data.hook) && isDef(i = i.destroy)) { i(vnode); }
|
|
for (i = 0; i < cbs.destroy.length; ++i) { cbs.destroy[i](vnode); }
|
|
}
|
|
if (isDef(i = vnode.children)) {
|
|
for (j = 0; j < vnode.children.length; ++j) {
|
|
invokeDestroyHook(vnode.children[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function removeVnodes (parentElm, vnodes, startIdx, endIdx) {
|
|
for (; startIdx <= endIdx; ++startIdx) {
|
|
var ch = vnodes[startIdx];
|
|
if (isDef(ch)) {
|
|
if (isDef(ch.tag)) {
|
|
removeAndInvokeRemoveHook(ch);
|
|
invokeDestroyHook(ch);
|
|
} else { // Text node
|
|
removeNode(ch.elm);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function removeAndInvokeRemoveHook (vnode, rm) {
|
|
if (rm || isDef(vnode.data)) {
|
|
var listeners = cbs.remove.length + 1;
|
|
if (!rm) {
|
|
// directly removing
|
|
rm = createRmCb(vnode.elm, listeners);
|
|
} else {
|
|
// we have a recursively passed down rm callback
|
|
// increase the listeners count
|
|
rm.listeners += listeners;
|
|
}
|
|
// recursively invoke hooks on child component root node
|
|
if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {
|
|
removeAndInvokeRemoveHook(i, rm);
|
|
}
|
|
for (i = 0; i < cbs.remove.length; ++i) {
|
|
cbs.remove[i](vnode, rm);
|
|
}
|
|
if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {
|
|
i(vnode, rm);
|
|
} else {
|
|
rm();
|
|
}
|
|
} else {
|
|
removeNode(vnode.elm);
|
|
}
|
|
}
|
|
|
|
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
|
|
var oldStartIdx = 0;
|
|
var newStartIdx = 0;
|
|
var oldEndIdx = oldCh.length - 1;
|
|
var oldStartVnode = oldCh[0];
|
|
var oldEndVnode = oldCh[oldEndIdx];
|
|
var newEndIdx = newCh.length - 1;
|
|
var newStartVnode = newCh[0];
|
|
var newEndVnode = newCh[newEndIdx];
|
|
var oldKeyToIdx, idxInOld, elmToMove, refElm;
|
|
|
|
// removeOnly is a special flag used only by <transition-group>
|
|
// to ensure removed elements stay in correct relative positions
|
|
// during leaving transitions
|
|
var canMove = !removeOnly;
|
|
|
|
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
|
|
if (isUndef(oldStartVnode)) {
|
|
oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
|
|
} else if (isUndef(oldEndVnode)) {
|
|
oldEndVnode = oldCh[--oldEndIdx];
|
|
} else if (sameVnode(oldStartVnode, newStartVnode)) {
|
|
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);
|
|
oldStartVnode = oldCh[++oldStartIdx];
|
|
newStartVnode = newCh[++newStartIdx];
|
|
} else if (sameVnode(oldEndVnode, newEndVnode)) {
|
|
patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
|
|
oldEndVnode = oldCh[--oldEndIdx];
|
|
newEndVnode = newCh[--newEndIdx];
|
|
} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
|
|
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
|
|
canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));
|
|
oldStartVnode = oldCh[++oldStartIdx];
|
|
newEndVnode = newCh[--newEndIdx];
|
|
} else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
|
|
patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
|
|
canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
|
|
oldEndVnode = oldCh[--oldEndIdx];
|
|
newStartVnode = newCh[++newStartIdx];
|
|
} else {
|
|
if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); }
|
|
idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : null;
|
|
if (isUndef(idxInOld)) { // New element
|
|
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm);
|
|
newStartVnode = newCh[++newStartIdx];
|
|
} else {
|
|
elmToMove = oldCh[idxInOld];
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && !elmToMove) {
|
|
warn(
|
|
'It seems there are duplicate keys that is causing an update error. ' +
|
|
'Make sure each v-for item has a unique key.'
|
|
);
|
|
}
|
|
if (sameVnode(elmToMove, newStartVnode)) {
|
|
patchVnode(elmToMove, newStartVnode, insertedVnodeQueue);
|
|
oldCh[idxInOld] = undefined;
|
|
canMove && nodeOps.insertBefore(parentElm, newStartVnode.elm, oldStartVnode.elm);
|
|
newStartVnode = newCh[++newStartIdx];
|
|
} else {
|
|
// same key but different element. treat as new element
|
|
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm);
|
|
newStartVnode = newCh[++newStartIdx];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (oldStartIdx > oldEndIdx) {
|
|
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
|
|
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
|
|
} else if (newStartIdx > newEndIdx) {
|
|
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
|
|
}
|
|
}
|
|
|
|
function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
|
|
if (oldVnode === vnode) {
|
|
return
|
|
}
|
|
// reuse element for static trees.
|
|
// note we only do this if the vnode is cloned -
|
|
// if the new node is not cloned it means the render functions have been
|
|
// reset by the hot-reload-api and we need to do a proper re-render.
|
|
if (vnode.isStatic &&
|
|
oldVnode.isStatic &&
|
|
vnode.key === oldVnode.key &&
|
|
(vnode.isCloned || vnode.isOnce)) {
|
|
vnode.elm = oldVnode.elm;
|
|
vnode.componentInstance = oldVnode.componentInstance;
|
|
return
|
|
}
|
|
var i;
|
|
var data = vnode.data;
|
|
var hasData = isDef(data);
|
|
if (hasData && isDef(i = data.hook) && isDef(i = i.prepatch)) {
|
|
i(oldVnode, vnode);
|
|
}
|
|
var elm = vnode.elm = oldVnode.elm;
|
|
var oldCh = oldVnode.children;
|
|
var ch = vnode.children;
|
|
if (hasData && isPatchable(vnode)) {
|
|
for (i = 0; i < cbs.update.length; ++i) { cbs.update[i](oldVnode, vnode); }
|
|
if (isDef(i = data.hook) && isDef(i = i.update)) { i(oldVnode, vnode); }
|
|
}
|
|
if (isUndef(vnode.text)) {
|
|
if (isDef(oldCh) && isDef(ch)) {
|
|
if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
|
|
} else if (isDef(ch)) {
|
|
if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
|
|
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
|
|
} else if (isDef(oldCh)) {
|
|
removeVnodes(elm, oldCh, 0, oldCh.length - 1);
|
|
} else if (isDef(oldVnode.text)) {
|
|
nodeOps.setTextContent(elm, '');
|
|
}
|
|
} else if (oldVnode.text !== vnode.text) {
|
|
nodeOps.setTextContent(elm, vnode.text);
|
|
}
|
|
if (hasData) {
|
|
if (isDef(i = data.hook) && isDef(i = i.postpatch)) { i(oldVnode, vnode); }
|
|
}
|
|
}
|
|
|
|
function invokeInsertHook (vnode, queue, initial) {
|
|
// delay insert hooks for component root nodes, invoke them after the
|
|
// element is really inserted
|
|
if (initial && vnode.parent) {
|
|
vnode.parent.data.pendingInsert = queue;
|
|
} else {
|
|
for (var i = 0; i < queue.length; ++i) {
|
|
queue[i].data.hook.insert(queue[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
var bailed = false;
|
|
// list of modules that can skip create hook during hydration because they
|
|
// are already rendered on the client or has no need for initialization
|
|
var isRenderedModule = makeMap('attrs,style,class,staticClass,staticStyle,key');
|
|
|
|
// Note: this is a browser-only function so we can assume elms are DOM nodes.
|
|
function hydrate (elm, vnode, insertedVnodeQueue) {
|
|
{
|
|
if (!assertNodeMatch(elm, vnode)) {
|
|
return false
|
|
}
|
|
}
|
|
vnode.elm = elm;
|
|
var tag = vnode.tag;
|
|
var data = vnode.data;
|
|
var children = vnode.children;
|
|
if (isDef(data)) {
|
|
if (isDef(i = data.hook) && isDef(i = i.init)) { i(vnode, true /* hydrating */); }
|
|
if (isDef(i = vnode.componentInstance)) {
|
|
// child component. it should have hydrated its own tree.
|
|
initComponent(vnode, insertedVnodeQueue);
|
|
return true
|
|
}
|
|
}
|
|
if (isDef(tag)) {
|
|
if (isDef(children)) {
|
|
// empty element, allow client to pick up and populate children
|
|
if (!elm.hasChildNodes()) {
|
|
createChildren(vnode, children, insertedVnodeQueue);
|
|
} else {
|
|
var childrenMatch = true;
|
|
var childNode = elm.firstChild;
|
|
for (var i$1 = 0; i$1 < children.length; i$1++) {
|
|
if (!childNode || !hydrate(childNode, children[i$1], insertedVnodeQueue)) {
|
|
childrenMatch = false;
|
|
break
|
|
}
|
|
childNode = childNode.nextSibling;
|
|
}
|
|
// if childNode is not null, it means the actual childNodes list is
|
|
// longer than the virtual children list.
|
|
if (!childrenMatch || childNode) {
|
|
if ("development" !== 'production' &&
|
|
typeof console !== 'undefined' &&
|
|
!bailed) {
|
|
bailed = true;
|
|
console.warn('Parent: ', elm);
|
|
console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children);
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
if (isDef(data)) {
|
|
for (var key in data) {
|
|
if (!isRenderedModule(key)) {
|
|
invokeCreateHooks(vnode, insertedVnodeQueue);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
} else if (elm.data !== vnode.text) {
|
|
elm.data = vnode.text;
|
|
}
|
|
return true
|
|
}
|
|
|
|
function assertNodeMatch (node, vnode) {
|
|
if (vnode.tag) {
|
|
return (
|
|
vnode.tag.indexOf('vue-component') === 0 ||
|
|
vnode.tag.toLowerCase() === (node.tagName && node.tagName.toLowerCase())
|
|
)
|
|
} else {
|
|
return node.nodeType === (vnode.isComment ? 8 : 3)
|
|
}
|
|
}
|
|
|
|
return function patch (oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
|
|
if (!vnode) {
|
|
if (oldVnode) { invokeDestroyHook(oldVnode); }
|
|
return
|
|
}
|
|
|
|
var isInitialPatch = false;
|
|
var insertedVnodeQueue = [];
|
|
|
|
if (!oldVnode) {
|
|
// empty mount (likely as component), create new root element
|
|
isInitialPatch = true;
|
|
createElm(vnode, insertedVnodeQueue, parentElm, refElm);
|
|
} else {
|
|
var isRealElement = isDef(oldVnode.nodeType);
|
|
if (!isRealElement && sameVnode(oldVnode, vnode)) {
|
|
// patch existing root node
|
|
patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly);
|
|
} else {
|
|
if (isRealElement) {
|
|
// mounting to a real element
|
|
// check if this is server-rendered content and if we can perform
|
|
// a successful hydration.
|
|
if (oldVnode.nodeType === 1 && oldVnode.hasAttribute('server-rendered')) {
|
|
oldVnode.removeAttribute('server-rendered');
|
|
hydrating = true;
|
|
}
|
|
if (hydrating) {
|
|
if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
|
|
invokeInsertHook(vnode, insertedVnodeQueue, true);
|
|
return oldVnode
|
|
} else {
|
|
warn(
|
|
'The client-side rendered virtual DOM tree is not matching ' +
|
|
'server-rendered content. This is likely caused by incorrect ' +
|
|
'HTML markup, for example nesting block-level elements inside ' +
|
|
'<p>, or missing <tbody>. Bailing hydration and performing ' +
|
|
'full client-side render.'
|
|
);
|
|
}
|
|
}
|
|
// either not server-rendered, or hydration failed.
|
|
// create an empty node and replace it
|
|
oldVnode = emptyNodeAt(oldVnode);
|
|
}
|
|
// replacing existing element
|
|
var oldElm = oldVnode.elm;
|
|
var parentElm$1 = nodeOps.parentNode(oldElm);
|
|
createElm(
|
|
vnode,
|
|
insertedVnodeQueue,
|
|
// extremely rare edge case: do not insert if old element is in a
|
|
// leaving transition. Only happens when combining transition +
|
|
// keep-alive + HOCs. (#4590)
|
|
oldElm._leaveCb ? null : parentElm$1,
|
|
nodeOps.nextSibling(oldElm)
|
|
);
|
|
|
|
if (vnode.parent) {
|
|
// component root element replaced.
|
|
// update parent placeholder node element, recursively
|
|
var ancestor = vnode.parent;
|
|
while (ancestor) {
|
|
ancestor.elm = vnode.elm;
|
|
ancestor = ancestor.parent;
|
|
}
|
|
if (isPatchable(vnode)) {
|
|
for (var i = 0; i < cbs.create.length; ++i) {
|
|
cbs.create[i](emptyNode, vnode.parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parentElm$1 !== null) {
|
|
removeVnodes(parentElm$1, [oldVnode], 0, 0);
|
|
} else if (isDef(oldVnode.tag)) {
|
|
invokeDestroyHook(oldVnode);
|
|
}
|
|
}
|
|
}
|
|
|
|
invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
|
|
return vnode.elm
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var directives = {
|
|
create: updateDirectives,
|
|
update: updateDirectives,
|
|
destroy: function unbindDirectives (vnode) {
|
|
updateDirectives(vnode, emptyNode);
|
|
}
|
|
};
|
|
|
|
function updateDirectives (oldVnode, vnode) {
|
|
if (oldVnode.data.directives || vnode.data.directives) {
|
|
_update(oldVnode, vnode);
|
|
}
|
|
}
|
|
|
|
function _update (oldVnode, vnode) {
|
|
var isCreate = oldVnode === emptyNode;
|
|
var isDestroy = vnode === emptyNode;
|
|
var oldDirs = normalizeDirectives$1(oldVnode.data.directives, oldVnode.context);
|
|
var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context);
|
|
|
|
var dirsWithInsert = [];
|
|
var dirsWithPostpatch = [];
|
|
|
|
var key, oldDir, dir;
|
|
for (key in newDirs) {
|
|
oldDir = oldDirs[key];
|
|
dir = newDirs[key];
|
|
if (!oldDir) {
|
|
// new directive, bind
|
|
callHook$1(dir, 'bind', vnode, oldVnode);
|
|
if (dir.def && dir.def.inserted) {
|
|
dirsWithInsert.push(dir);
|
|
}
|
|
} else {
|
|
// existing directive, update
|
|
dir.oldValue = oldDir.value;
|
|
callHook$1(dir, 'update', vnode, oldVnode);
|
|
if (dir.def && dir.def.componentUpdated) {
|
|
dirsWithPostpatch.push(dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dirsWithInsert.length) {
|
|
var callInsert = function () {
|
|
for (var i = 0; i < dirsWithInsert.length; i++) {
|
|
callHook$1(dirsWithInsert[i], 'inserted', vnode, oldVnode);
|
|
}
|
|
};
|
|
if (isCreate) {
|
|
mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', callInsert);
|
|
} else {
|
|
callInsert();
|
|
}
|
|
}
|
|
|
|
if (dirsWithPostpatch.length) {
|
|
mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'postpatch', function () {
|
|
for (var i = 0; i < dirsWithPostpatch.length; i++) {
|
|
callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!isCreate) {
|
|
for (key in oldDirs) {
|
|
if (!newDirs[key]) {
|
|
// no longer present, unbind
|
|
callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var emptyModifiers = Object.create(null);
|
|
|
|
function normalizeDirectives$1 (
|
|
dirs,
|
|
vm
|
|
) {
|
|
var res = Object.create(null);
|
|
if (!dirs) {
|
|
return res
|
|
}
|
|
var i, dir;
|
|
for (i = 0; i < dirs.length; i++) {
|
|
dir = dirs[i];
|
|
if (!dir.modifiers) {
|
|
dir.modifiers = emptyModifiers;
|
|
}
|
|
res[getRawDirName(dir)] = dir;
|
|
dir.def = resolveAsset(vm.$options, 'directives', dir.name, true);
|
|
}
|
|
return res
|
|
}
|
|
|
|
function getRawDirName (dir) {
|
|
return dir.rawName || ((dir.name) + "." + (Object.keys(dir.modifiers || {}).join('.')))
|
|
}
|
|
|
|
function callHook$1 (dir, hook, vnode, oldVnode, isDestroy) {
|
|
var fn = dir.def && dir.def[hook];
|
|
if (fn) {
|
|
fn(vnode.elm, dir, vnode, oldVnode, isDestroy);
|
|
}
|
|
}
|
|
|
|
var baseModules = [
|
|
ref,
|
|
directives
|
|
];
|
|
|
|
/* */
|
|
|
|
function updateAttrs (oldVnode, vnode) {
|
|
if (!oldVnode.data.attrs && !vnode.data.attrs) {
|
|
return
|
|
}
|
|
var key, cur, old;
|
|
var elm = vnode.elm;
|
|
var oldAttrs = oldVnode.data.attrs || {};
|
|
var attrs = vnode.data.attrs || {};
|
|
// clone observed objects, as the user probably wants to mutate it
|
|
if (attrs.__ob__) {
|
|
attrs = vnode.data.attrs = extend({}, attrs);
|
|
}
|
|
|
|
for (key in attrs) {
|
|
cur = attrs[key];
|
|
old = oldAttrs[key];
|
|
if (old !== cur) {
|
|
setAttr(elm, key, cur);
|
|
}
|
|
}
|
|
// #4391: in IE9, setting type can reset value for input[type=radio]
|
|
/* istanbul ignore if */
|
|
if (isIE9 && attrs.value !== oldAttrs.value) {
|
|
setAttr(elm, 'value', attrs.value);
|
|
}
|
|
for (key in oldAttrs) {
|
|
if (attrs[key] == null) {
|
|
if (isXlink(key)) {
|
|
elm.removeAttributeNS(xlinkNS, getXlinkProp(key));
|
|
} else if (!isEnumeratedAttr(key)) {
|
|
elm.removeAttribute(key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function setAttr (el, key, value) {
|
|
if (isBooleanAttr(key)) {
|
|
// set attribute for blank value
|
|
// e.g. <option disabled>Select one</option>
|
|
if (isFalsyAttrValue(value)) {
|
|
el.removeAttribute(key);
|
|
} else {
|
|
el.setAttribute(key, key);
|
|
}
|
|
} else if (isEnumeratedAttr(key)) {
|
|
el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true');
|
|
} else if (isXlink(key)) {
|
|
if (isFalsyAttrValue(value)) {
|
|
el.removeAttributeNS(xlinkNS, getXlinkProp(key));
|
|
} else {
|
|
el.setAttributeNS(xlinkNS, key, value);
|
|
}
|
|
} else {
|
|
if (isFalsyAttrValue(value)) {
|
|
el.removeAttribute(key);
|
|
} else {
|
|
el.setAttribute(key, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
var attrs = {
|
|
create: updateAttrs,
|
|
update: updateAttrs
|
|
};
|
|
|
|
/* */
|
|
|
|
function updateClass (oldVnode, vnode) {
|
|
var el = vnode.elm;
|
|
var data = vnode.data;
|
|
var oldData = oldVnode.data;
|
|
if (!data.staticClass && !data.class &&
|
|
(!oldData || (!oldData.staticClass && !oldData.class))) {
|
|
return
|
|
}
|
|
|
|
var cls = genClassForVnode(vnode);
|
|
|
|
// handle transition classes
|
|
var transitionClass = el._transitionClasses;
|
|
if (transitionClass) {
|
|
cls = concat(cls, stringifyClass(transitionClass));
|
|
}
|
|
|
|
// set the class
|
|
if (cls !== el._prevClass) {
|
|
el.setAttribute('class', cls);
|
|
el._prevClass = cls;
|
|
}
|
|
}
|
|
|
|
var klass = {
|
|
create: updateClass,
|
|
update: updateClass
|
|
};
|
|
|
|
/* */
|
|
|
|
var validDivisionCharRE = /[\w).+\-_$\]]/;
|
|
|
|
function parseFilters (exp) {
|
|
var inSingle = false;
|
|
var inDouble = false;
|
|
var inTemplateString = false;
|
|
var inRegex = false;
|
|
var curly = 0;
|
|
var square = 0;
|
|
var paren = 0;
|
|
var lastFilterIndex = 0;
|
|
var c, prev, i, expression, filters;
|
|
|
|
for (i = 0; i < exp.length; i++) {
|
|
prev = c;
|
|
c = exp.charCodeAt(i);
|
|
if (inSingle) {
|
|
if (c === 0x27 && prev !== 0x5C) { inSingle = false; }
|
|
} else if (inDouble) {
|
|
if (c === 0x22 && prev !== 0x5C) { inDouble = false; }
|
|
} else if (inTemplateString) {
|
|
if (c === 0x60 && prev !== 0x5C) { inTemplateString = false; }
|
|
} else if (inRegex) {
|
|
if (c === 0x2f && prev !== 0x5C) { inRegex = false; }
|
|
} else if (
|
|
c === 0x7C && // pipe
|
|
exp.charCodeAt(i + 1) !== 0x7C &&
|
|
exp.charCodeAt(i - 1) !== 0x7C &&
|
|
!curly && !square && !paren
|
|
) {
|
|
if (expression === undefined) {
|
|
// first filter, end of expression
|
|
lastFilterIndex = i + 1;
|
|
expression = exp.slice(0, i).trim();
|
|
} else {
|
|
pushFilter();
|
|
}
|
|
} else {
|
|
switch (c) {
|
|
case 0x22: inDouble = true; break // "
|
|
case 0x27: inSingle = true; break // '
|
|
case 0x60: inTemplateString = true; break // `
|
|
case 0x28: paren++; break // (
|
|
case 0x29: paren--; break // )
|
|
case 0x5B: square++; break // [
|
|
case 0x5D: square--; break // ]
|
|
case 0x7B: curly++; break // {
|
|
case 0x7D: curly--; break // }
|
|
}
|
|
if (c === 0x2f) { // /
|
|
var j = i - 1;
|
|
var p = (void 0);
|
|
// find first non-whitespace prev char
|
|
for (; j >= 0; j--) {
|
|
p = exp.charAt(j);
|
|
if (p !== ' ') { break }
|
|
}
|
|
if (!p || !validDivisionCharRE.test(p)) {
|
|
inRegex = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (expression === undefined) {
|
|
expression = exp.slice(0, i).trim();
|
|
} else if (lastFilterIndex !== 0) {
|
|
pushFilter();
|
|
}
|
|
|
|
function pushFilter () {
|
|
(filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim());
|
|
lastFilterIndex = i + 1;
|
|
}
|
|
|
|
if (filters) {
|
|
for (i = 0; i < filters.length; i++) {
|
|
expression = wrapFilter(expression, filters[i]);
|
|
}
|
|
}
|
|
|
|
return expression
|
|
}
|
|
|
|
function wrapFilter (exp, filter) {
|
|
var i = filter.indexOf('(');
|
|
if (i < 0) {
|
|
// _f: resolveFilter
|
|
return ("_f(\"" + filter + "\")(" + exp + ")")
|
|
} else {
|
|
var name = filter.slice(0, i);
|
|
var args = filter.slice(i + 1);
|
|
return ("_f(\"" + name + "\")(" + exp + "," + args)
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function baseWarn (msg) {
|
|
console.error(("[Vue compiler]: " + msg));
|
|
}
|
|
|
|
function pluckModuleFunction (
|
|
modules,
|
|
key
|
|
) {
|
|
return modules
|
|
? modules.map(function (m) { return m[key]; }).filter(function (_) { return _; })
|
|
: []
|
|
}
|
|
|
|
function addProp (el, name, value) {
|
|
(el.props || (el.props = [])).push({ name: name, value: value });
|
|
}
|
|
|
|
function addAttr (el, name, value) {
|
|
(el.attrs || (el.attrs = [])).push({ name: name, value: value });
|
|
}
|
|
|
|
function addDirective (
|
|
el,
|
|
name,
|
|
rawName,
|
|
value,
|
|
arg,
|
|
modifiers
|
|
) {
|
|
(el.directives || (el.directives = [])).push({ name: name, rawName: rawName, value: value, arg: arg, modifiers: modifiers });
|
|
}
|
|
|
|
function addHandler (
|
|
el,
|
|
name,
|
|
value,
|
|
modifiers,
|
|
important
|
|
) {
|
|
// check capture modifier
|
|
if (modifiers && modifiers.capture) {
|
|
delete modifiers.capture;
|
|
name = '!' + name; // mark the event as captured
|
|
}
|
|
if (modifiers && modifiers.once) {
|
|
delete modifiers.once;
|
|
name = '~' + name; // mark the event as once
|
|
}
|
|
var events;
|
|
if (modifiers && modifiers.native) {
|
|
delete modifiers.native;
|
|
events = el.nativeEvents || (el.nativeEvents = {});
|
|
} else {
|
|
events = el.events || (el.events = {});
|
|
}
|
|
var newHandler = { value: value, modifiers: modifiers };
|
|
var handlers = events[name];
|
|
/* istanbul ignore if */
|
|
if (Array.isArray(handlers)) {
|
|
important ? handlers.unshift(newHandler) : handlers.push(newHandler);
|
|
} else if (handlers) {
|
|
events[name] = important ? [newHandler, handlers] : [handlers, newHandler];
|
|
} else {
|
|
events[name] = newHandler;
|
|
}
|
|
}
|
|
|
|
function getBindingAttr (
|
|
el,
|
|
name,
|
|
getStatic
|
|
) {
|
|
var dynamicValue =
|
|
getAndRemoveAttr(el, ':' + name) ||
|
|
getAndRemoveAttr(el, 'v-bind:' + name);
|
|
if (dynamicValue != null) {
|
|
return parseFilters(dynamicValue)
|
|
} else if (getStatic !== false) {
|
|
var staticValue = getAndRemoveAttr(el, name);
|
|
if (staticValue != null) {
|
|
return JSON.stringify(staticValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
function getAndRemoveAttr (el, name) {
|
|
var val;
|
|
if ((val = el.attrsMap[name]) != null) {
|
|
var list = el.attrsList;
|
|
for (var i = 0, l = list.length; i < l; i++) {
|
|
if (list[i].name === name) {
|
|
list.splice(i, 1);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return val
|
|
}
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Cross-platform code generation for component v-model
|
|
*/
|
|
function genComponentModel (
|
|
el,
|
|
value,
|
|
modifiers
|
|
) {
|
|
var ref = modifiers || {};
|
|
var number = ref.number;
|
|
var trim = ref.trim;
|
|
|
|
var baseValueExpression = '$$v';
|
|
var valueExpression = baseValueExpression;
|
|
if (trim) {
|
|
valueExpression =
|
|
"(typeof " + baseValueExpression + " === 'string'" +
|
|
"? " + baseValueExpression + ".trim()" +
|
|
": " + baseValueExpression + ")";
|
|
}
|
|
if (number) {
|
|
valueExpression = "_n(" + valueExpression + ")";
|
|
}
|
|
var assignment = genAssignmentCode(value, valueExpression);
|
|
|
|
el.model = {
|
|
value: ("(" + value + ")"),
|
|
callback: ("function (" + baseValueExpression + ") {" + assignment + "}")
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Cross-platform codegen helper for generating v-model value assignment code.
|
|
*/
|
|
function genAssignmentCode (
|
|
value,
|
|
assignment
|
|
) {
|
|
var modelRs = parseModel(value);
|
|
if (modelRs.idx === null) {
|
|
return (value + "=" + assignment)
|
|
} else {
|
|
return "var $$exp = " + (modelRs.exp) + ", $$idx = " + (modelRs.idx) + ";" +
|
|
"if (!Array.isArray($$exp)){" +
|
|
value + "=" + assignment + "}" +
|
|
"else{$$exp.splice($$idx, 1, " + assignment + ")}"
|
|
}
|
|
}
|
|
|
|
/**
|
|
* parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val)
|
|
*
|
|
* for loop possible cases:
|
|
*
|
|
* - test
|
|
* - test[idx]
|
|
* - test[test1[idx]]
|
|
* - test["a"][idx]
|
|
* - xxx.test[a[a].test1[idx]]
|
|
* - test.xxx.a["asa"][test1[idx]]
|
|
*
|
|
*/
|
|
|
|
var len;
|
|
var str;
|
|
var chr;
|
|
var index$1;
|
|
var expressionPos;
|
|
var expressionEndPos;
|
|
|
|
function parseModel (val) {
|
|
str = val;
|
|
len = str.length;
|
|
index$1 = expressionPos = expressionEndPos = 0;
|
|
|
|
if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
|
|
return {
|
|
exp: val,
|
|
idx: null
|
|
}
|
|
}
|
|
|
|
while (!eof()) {
|
|
chr = next();
|
|
/* istanbul ignore if */
|
|
if (isStringStart(chr)) {
|
|
parseString(chr);
|
|
} else if (chr === 0x5B) {
|
|
parseBracket(chr);
|
|
}
|
|
}
|
|
|
|
return {
|
|
exp: val.substring(0, expressionPos),
|
|
idx: val.substring(expressionPos + 1, expressionEndPos)
|
|
}
|
|
}
|
|
|
|
function next () {
|
|
return str.charCodeAt(++index$1)
|
|
}
|
|
|
|
function eof () {
|
|
return index$1 >= len
|
|
}
|
|
|
|
function isStringStart (chr) {
|
|
return chr === 0x22 || chr === 0x27
|
|
}
|
|
|
|
function parseBracket (chr) {
|
|
var inBracket = 1;
|
|
expressionPos = index$1;
|
|
while (!eof()) {
|
|
chr = next();
|
|
if (isStringStart(chr)) {
|
|
parseString(chr);
|
|
continue
|
|
}
|
|
if (chr === 0x5B) { inBracket++; }
|
|
if (chr === 0x5D) { inBracket--; }
|
|
if (inBracket === 0) {
|
|
expressionEndPos = index$1;
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
function parseString (chr) {
|
|
var stringQuote = chr;
|
|
while (!eof()) {
|
|
chr = next();
|
|
if (chr === stringQuote) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var warn$1;
|
|
|
|
// in some cases, the event used has to be determined at runtime
|
|
// so we used some reserved tokens during compile.
|
|
var RANGE_TOKEN = '__r';
|
|
var CHECKBOX_RADIO_TOKEN = '__c';
|
|
|
|
function model (
|
|
el,
|
|
dir,
|
|
_warn
|
|
) {
|
|
warn$1 = _warn;
|
|
var value = dir.value;
|
|
var modifiers = dir.modifiers;
|
|
var tag = el.tag;
|
|
var type = el.attrsMap.type;
|
|
|
|
{
|
|
var dynamicType = el.attrsMap['v-bind:type'] || el.attrsMap[':type'];
|
|
if (tag === 'input' && dynamicType) {
|
|
warn$1(
|
|
"<input :type=\"" + dynamicType + "\" v-model=\"" + value + "\">:\n" +
|
|
"v-model does not support dynamic input types. Use v-if branches instead."
|
|
);
|
|
}
|
|
// inputs with type="file" are read only and setting the input's
|
|
// value will throw an error.
|
|
if (tag === 'input' && type === 'file') {
|
|
warn$1(
|
|
"<" + (el.tag) + " v-model=\"" + value + "\" type=\"file\">:\n" +
|
|
"File inputs are read only. Use a v-on:change listener instead."
|
|
);
|
|
}
|
|
}
|
|
|
|
if (tag === 'select') {
|
|
genSelect(el, value, modifiers);
|
|
} else if (tag === 'input' && type === 'checkbox') {
|
|
genCheckboxModel(el, value, modifiers);
|
|
} else if (tag === 'input' && type === 'radio') {
|
|
genRadioModel(el, value, modifiers);
|
|
} else if (tag === 'input' || tag === 'textarea') {
|
|
genDefaultModel(el, value, modifiers);
|
|
} else if (!config.isReservedTag(tag)) {
|
|
genComponentModel(el, value, modifiers);
|
|
// component v-model doesn't need extra runtime
|
|
return false
|
|
} else {
|
|
warn$1(
|
|
"<" + (el.tag) + " v-model=\"" + value + "\">: " +
|
|
"v-model is not supported on this element type. " +
|
|
'If you are working with contenteditable, it\'s recommended to ' +
|
|
'wrap a library dedicated for that purpose inside a custom component.'
|
|
);
|
|
}
|
|
|
|
// ensure runtime directive metadata
|
|
return true
|
|
}
|
|
|
|
function genCheckboxModel (
|
|
el,
|
|
value,
|
|
modifiers
|
|
) {
|
|
if ("development" !== 'production' &&
|
|
el.attrsMap.checked != null) {
|
|
warn$1(
|
|
"<" + (el.tag) + " v-model=\"" + value + "\" checked>:\n" +
|
|
"inline checked attributes will be ignored when using v-model. " +
|
|
'Declare initial values in the component\'s data option instead.'
|
|
);
|
|
}
|
|
var number = modifiers && modifiers.number;
|
|
var valueBinding = getBindingAttr(el, 'value') || 'null';
|
|
var trueValueBinding = getBindingAttr(el, 'true-value') || 'true';
|
|
var falseValueBinding = getBindingAttr(el, 'false-value') || 'false';
|
|
addProp(el, 'checked',
|
|
"Array.isArray(" + value + ")" +
|
|
"?_i(" + value + "," + valueBinding + ")>-1" + (
|
|
trueValueBinding === 'true'
|
|
? (":(" + value + ")")
|
|
: (":_q(" + value + "," + trueValueBinding + ")")
|
|
)
|
|
);
|
|
addHandler(el, CHECKBOX_RADIO_TOKEN,
|
|
"var $$a=" + value + "," +
|
|
'$$el=$event.target,' +
|
|
"$$c=$$el.checked?(" + trueValueBinding + "):(" + falseValueBinding + ");" +
|
|
'if(Array.isArray($$a)){' +
|
|
"var $$v=" + (number ? '_n(' + valueBinding + ')' : valueBinding) + "," +
|
|
'$$i=_i($$a,$$v);' +
|
|
"if($$c){$$i<0&&(" + value + "=$$a.concat($$v))}" +
|
|
"else{$$i>-1&&(" + value + "=$$a.slice(0,$$i).concat($$a.slice($$i+1)))}" +
|
|
"}else{" + value + "=$$c}",
|
|
null, true
|
|
);
|
|
}
|
|
|
|
function genRadioModel (
|
|
el,
|
|
value,
|
|
modifiers
|
|
) {
|
|
if ("development" !== 'production' &&
|
|
el.attrsMap.checked != null) {
|
|
warn$1(
|
|
"<" + (el.tag) + " v-model=\"" + value + "\" checked>:\n" +
|
|
"inline checked attributes will be ignored when using v-model. " +
|
|
'Declare initial values in the component\'s data option instead.'
|
|
);
|
|
}
|
|
var number = modifiers && modifiers.number;
|
|
var valueBinding = getBindingAttr(el, 'value') || 'null';
|
|
valueBinding = number ? ("_n(" + valueBinding + ")") : valueBinding;
|
|
addProp(el, 'checked', ("_q(" + value + "," + valueBinding + ")"));
|
|
addHandler(el, CHECKBOX_RADIO_TOKEN, genAssignmentCode(value, valueBinding), null, true);
|
|
}
|
|
|
|
function genSelect (
|
|
el,
|
|
value,
|
|
modifiers
|
|
) {
|
|
{
|
|
el.children.some(checkOptionWarning);
|
|
}
|
|
|
|
var number = modifiers && modifiers.number;
|
|
var selectedVal = "Array.prototype.filter" +
|
|
".call($event.target.options,function(o){return o.selected})" +
|
|
".map(function(o){var val = \"_value\" in o ? o._value : o.value;" +
|
|
"return " + (number ? '_n(val)' : 'val') + "})";
|
|
|
|
var assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]';
|
|
var code = "var $$selectedVal = " + selectedVal + ";";
|
|
code = code + " " + (genAssignmentCode(value, assignment));
|
|
addHandler(el, 'change', code, null, true);
|
|
}
|
|
|
|
function checkOptionWarning (option) {
|
|
if (option.type === 1 &&
|
|
option.tag === 'option' &&
|
|
option.attrsMap.selected != null) {
|
|
warn$1(
|
|
"<select v-model=\"" + (option.parent.attrsMap['v-model']) + "\">:\n" +
|
|
'inline selected attributes on <option> will be ignored when using v-model. ' +
|
|
'Declare initial values in the component\'s data option instead.'
|
|
);
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
function genDefaultModel (
|
|
el,
|
|
value,
|
|
modifiers
|
|
) {
|
|
var type = el.attrsMap.type;
|
|
var ref = modifiers || {};
|
|
var lazy = ref.lazy;
|
|
var number = ref.number;
|
|
var trim = ref.trim;
|
|
var needCompositionGuard = !lazy && type !== 'range';
|
|
var event = lazy
|
|
? 'change'
|
|
: type === 'range'
|
|
? RANGE_TOKEN
|
|
: 'input';
|
|
|
|
var valueExpression = '$event.target.value';
|
|
if (trim) {
|
|
valueExpression = "$event.target.value.trim()";
|
|
}
|
|
if (number) {
|
|
valueExpression = "_n(" + valueExpression + ")";
|
|
}
|
|
|
|
var code = genAssignmentCode(value, valueExpression);
|
|
if (needCompositionGuard) {
|
|
code = "if($event.target.composing)return;" + code;
|
|
}
|
|
|
|
addProp(el, 'value', ("(" + value + ")"));
|
|
addHandler(el, event, code, null, true);
|
|
if (trim || number || type === 'number') {
|
|
addHandler(el, 'blur', '$forceUpdate()');
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
// normalize v-model event tokens that can only be determined at runtime.
|
|
// it's important to place the event as the first in the array because
|
|
// the whole point is ensuring the v-model callback gets called before
|
|
// user-attached handlers.
|
|
function normalizeEvents (on) {
|
|
var event;
|
|
/* istanbul ignore if */
|
|
if (on[RANGE_TOKEN]) {
|
|
// IE input[type=range] only supports `change` event
|
|
event = isIE ? 'change' : 'input';
|
|
on[event] = [].concat(on[RANGE_TOKEN], on[event] || []);
|
|
delete on[RANGE_TOKEN];
|
|
}
|
|
if (on[CHECKBOX_RADIO_TOKEN]) {
|
|
// Chrome fires microtasks in between click/change, leads to #4521
|
|
event = isChrome ? 'click' : 'change';
|
|
on[event] = [].concat(on[CHECKBOX_RADIO_TOKEN], on[event] || []);
|
|
delete on[CHECKBOX_RADIO_TOKEN];
|
|
}
|
|
}
|
|
|
|
var target$1;
|
|
|
|
function add$1 (
|
|
event,
|
|
handler,
|
|
once,
|
|
capture
|
|
) {
|
|
if (once) {
|
|
var oldHandler = handler;
|
|
var _target = target$1; // save current target element in closure
|
|
handler = function (ev) {
|
|
var res = arguments.length === 1
|
|
? oldHandler(ev)
|
|
: oldHandler.apply(null, arguments);
|
|
if (res !== null) {
|
|
remove$2(event, handler, capture, _target);
|
|
}
|
|
};
|
|
}
|
|
target$1.addEventListener(event, handler, capture);
|
|
}
|
|
|
|
function remove$2 (
|
|
event,
|
|
handler,
|
|
capture,
|
|
_target
|
|
) {
|
|
(_target || target$1).removeEventListener(event, handler, capture);
|
|
}
|
|
|
|
function updateDOMListeners (oldVnode, vnode) {
|
|
if (!oldVnode.data.on && !vnode.data.on) {
|
|
return
|
|
}
|
|
var on = vnode.data.on || {};
|
|
var oldOn = oldVnode.data.on || {};
|
|
target$1 = vnode.elm;
|
|
normalizeEvents(on);
|
|
updateListeners(on, oldOn, add$1, remove$2, vnode.context);
|
|
}
|
|
|
|
var events = {
|
|
create: updateDOMListeners,
|
|
update: updateDOMListeners
|
|
};
|
|
|
|
/* */
|
|
|
|
function updateDOMProps (oldVnode, vnode) {
|
|
if (!oldVnode.data.domProps && !vnode.data.domProps) {
|
|
return
|
|
}
|
|
var key, cur;
|
|
var elm = vnode.elm;
|
|
var oldProps = oldVnode.data.domProps || {};
|
|
var props = vnode.data.domProps || {};
|
|
// clone observed objects, as the user probably wants to mutate it
|
|
if (props.__ob__) {
|
|
props = vnode.data.domProps = extend({}, props);
|
|
}
|
|
|
|
for (key in oldProps) {
|
|
if (props[key] == null) {
|
|
elm[key] = '';
|
|
}
|
|
}
|
|
for (key in props) {
|
|
cur = props[key];
|
|
// ignore children if the node has textContent or innerHTML,
|
|
// as these will throw away existing DOM nodes and cause removal errors
|
|
// on subsequent patches (#3360)
|
|
if (key === 'textContent' || key === 'innerHTML') {
|
|
if (vnode.children) { vnode.children.length = 0; }
|
|
if (cur === oldProps[key]) { continue }
|
|
}
|
|
|
|
if (key === 'value') {
|
|
// store value as _value as well since
|
|
// non-string values will be stringified
|
|
elm._value = cur;
|
|
// avoid resetting cursor position when value is the same
|
|
var strCur = cur == null ? '' : String(cur);
|
|
if (shouldUpdateValue(elm, vnode, strCur)) {
|
|
elm.value = strCur;
|
|
}
|
|
} else {
|
|
elm[key] = cur;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check platforms/web/util/attrs.js acceptValue
|
|
|
|
|
|
function shouldUpdateValue (
|
|
elm,
|
|
vnode,
|
|
checkVal
|
|
) {
|
|
return (!elm.composing && (
|
|
vnode.tag === 'option' ||
|
|
isDirty(elm, checkVal) ||
|
|
isInputChanged(elm, checkVal)
|
|
))
|
|
}
|
|
|
|
function isDirty (elm, checkVal) {
|
|
// return true when textbox (.number and .trim) loses focus and its value is not equal to the updated value
|
|
return document.activeElement !== elm && elm.value !== checkVal
|
|
}
|
|
|
|
function isInputChanged (elm, newVal) {
|
|
var value = elm.value;
|
|
var modifiers = elm._vModifiers; // injected by v-model runtime
|
|
if ((modifiers && modifiers.number) || elm.type === 'number') {
|
|
return toNumber(value) !== toNumber(newVal)
|
|
}
|
|
if (modifiers && modifiers.trim) {
|
|
return value.trim() !== newVal.trim()
|
|
}
|
|
return value !== newVal
|
|
}
|
|
|
|
var domProps = {
|
|
create: updateDOMProps,
|
|
update: updateDOMProps
|
|
};
|
|
|
|
/* */
|
|
|
|
var parseStyleText = cached(function (cssText) {
|
|
var res = {};
|
|
var listDelimiter = /;(?![^(]*\))/g;
|
|
var propertyDelimiter = /:(.+)/;
|
|
cssText.split(listDelimiter).forEach(function (item) {
|
|
if (item) {
|
|
var tmp = item.split(propertyDelimiter);
|
|
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
|
|
}
|
|
});
|
|
return res
|
|
});
|
|
|
|
// merge static and dynamic style data on the same vnode
|
|
function normalizeStyleData (data) {
|
|
var style = normalizeStyleBinding(data.style);
|
|
// static style is pre-processed into an object during compilation
|
|
// and is always a fresh object, so it's safe to merge into it
|
|
return data.staticStyle
|
|
? extend(data.staticStyle, style)
|
|
: style
|
|
}
|
|
|
|
// normalize possible array / string values into Object
|
|
function normalizeStyleBinding (bindingStyle) {
|
|
if (Array.isArray(bindingStyle)) {
|
|
return toObject(bindingStyle)
|
|
}
|
|
if (typeof bindingStyle === 'string') {
|
|
return parseStyleText(bindingStyle)
|
|
}
|
|
return bindingStyle
|
|
}
|
|
|
|
/**
|
|
* parent component style should be after child's
|
|
* so that parent component's style could override it
|
|
*/
|
|
function getStyle (vnode, checkChild) {
|
|
var res = {};
|
|
var styleData;
|
|
|
|
if (checkChild) {
|
|
var childNode = vnode;
|
|
while (childNode.componentInstance) {
|
|
childNode = childNode.componentInstance._vnode;
|
|
if (childNode.data && (styleData = normalizeStyleData(childNode.data))) {
|
|
extend(res, styleData);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((styleData = normalizeStyleData(vnode.data))) {
|
|
extend(res, styleData);
|
|
}
|
|
|
|
var parentNode = vnode;
|
|
while ((parentNode = parentNode.parent)) {
|
|
if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {
|
|
extend(res, styleData);
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
/* */
|
|
|
|
var cssVarRE = /^--/;
|
|
var importantRE = /\s*!important$/;
|
|
var setProp = function (el, name, val) {
|
|
/* istanbul ignore if */
|
|
if (cssVarRE.test(name)) {
|
|
el.style.setProperty(name, val);
|
|
} else if (importantRE.test(val)) {
|
|
el.style.setProperty(name, val.replace(importantRE, ''), 'important');
|
|
} else {
|
|
el.style[normalize(name)] = val;
|
|
}
|
|
};
|
|
|
|
var prefixes = ['Webkit', 'Moz', 'ms'];
|
|
|
|
var testEl;
|
|
var normalize = cached(function (prop) {
|
|
testEl = testEl || document.createElement('div');
|
|
prop = camelize(prop);
|
|
if (prop !== 'filter' && (prop in testEl.style)) {
|
|
return prop
|
|
}
|
|
var upper = prop.charAt(0).toUpperCase() + prop.slice(1);
|
|
for (var i = 0; i < prefixes.length; i++) {
|
|
var prefixed = prefixes[i] + upper;
|
|
if (prefixed in testEl.style) {
|
|
return prefixed
|
|
}
|
|
}
|
|
});
|
|
|
|
function updateStyle (oldVnode, vnode) {
|
|
var data = vnode.data;
|
|
var oldData = oldVnode.data;
|
|
|
|
if (!data.staticStyle && !data.style &&
|
|
!oldData.staticStyle && !oldData.style) {
|
|
return
|
|
}
|
|
|
|
var cur, name;
|
|
var el = vnode.elm;
|
|
var oldStaticStyle = oldVnode.data.staticStyle;
|
|
var oldStyleBinding = oldVnode.data.style || {};
|
|
|
|
// if static style exists, stylebinding already merged into it when doing normalizeStyleData
|
|
var oldStyle = oldStaticStyle || oldStyleBinding;
|
|
|
|
var style = normalizeStyleBinding(vnode.data.style) || {};
|
|
|
|
vnode.data.style = style.__ob__ ? extend({}, style) : style;
|
|
|
|
var newStyle = getStyle(vnode, true);
|
|
|
|
for (name in oldStyle) {
|
|
if (newStyle[name] == null) {
|
|
setProp(el, name, '');
|
|
}
|
|
}
|
|
for (name in newStyle) {
|
|
cur = newStyle[name];
|
|
if (cur !== oldStyle[name]) {
|
|
// ie9 setting to null has no effect, must use empty string
|
|
setProp(el, name, cur == null ? '' : cur);
|
|
}
|
|
}
|
|
}
|
|
|
|
var style = {
|
|
create: updateStyle,
|
|
update: updateStyle
|
|
};
|
|
|
|
/* */
|
|
|
|
/**
|
|
* Add class with compatibility for SVG since classList is not supported on
|
|
* SVG elements in IE
|
|
*/
|
|
function addClass (el, cls) {
|
|
/* istanbul ignore if */
|
|
if (!cls || !(cls = cls.trim())) {
|
|
return
|
|
}
|
|
|
|
/* istanbul ignore else */
|
|
if (el.classList) {
|
|
if (cls.indexOf(' ') > -1) {
|
|
cls.split(/\s+/).forEach(function (c) { return el.classList.add(c); });
|
|
} else {
|
|
el.classList.add(cls);
|
|
}
|
|
} else {
|
|
var cur = " " + (el.getAttribute('class') || '') + " ";
|
|
if (cur.indexOf(' ' + cls + ' ') < 0) {
|
|
el.setAttribute('class', (cur + cls).trim());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove class with compatibility for SVG since classList is not supported on
|
|
* SVG elements in IE
|
|
*/
|
|
function removeClass (el, cls) {
|
|
/* istanbul ignore if */
|
|
if (!cls || !(cls = cls.trim())) {
|
|
return
|
|
}
|
|
|
|
/* istanbul ignore else */
|
|
if (el.classList) {
|
|
if (cls.indexOf(' ') > -1) {
|
|
cls.split(/\s+/).forEach(function (c) { return el.classList.remove(c); });
|
|
} else {
|
|
el.classList.remove(cls);
|
|
}
|
|
} else {
|
|
var cur = " " + (el.getAttribute('class') || '') + " ";
|
|
var tar = ' ' + cls + ' ';
|
|
while (cur.indexOf(tar) >= 0) {
|
|
cur = cur.replace(tar, ' ');
|
|
}
|
|
el.setAttribute('class', cur.trim());
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function resolveTransition (def$$1) {
|
|
if (!def$$1) {
|
|
return
|
|
}
|
|
/* istanbul ignore else */
|
|
if (typeof def$$1 === 'object') {
|
|
var res = {};
|
|
if (def$$1.css !== false) {
|
|
extend(res, autoCssTransition(def$$1.name || 'v'));
|
|
}
|
|
extend(res, def$$1);
|
|
return res
|
|
} else if (typeof def$$1 === 'string') {
|
|
return autoCssTransition(def$$1)
|
|
}
|
|
}
|
|
|
|
var autoCssTransition = cached(function (name) {
|
|
return {
|
|
enterClass: (name + "-enter"),
|
|
enterToClass: (name + "-enter-to"),
|
|
enterActiveClass: (name + "-enter-active"),
|
|
leaveClass: (name + "-leave"),
|
|
leaveToClass: (name + "-leave-to"),
|
|
leaveActiveClass: (name + "-leave-active")
|
|
}
|
|
});
|
|
|
|
var hasTransition = inBrowser && !isIE9;
|
|
var TRANSITION = 'transition';
|
|
var ANIMATION = 'animation';
|
|
|
|
// Transition property/event sniffing
|
|
var transitionProp = 'transition';
|
|
var transitionEndEvent = 'transitionend';
|
|
var animationProp = 'animation';
|
|
var animationEndEvent = 'animationend';
|
|
if (hasTransition) {
|
|
/* istanbul ignore if */
|
|
if (window.ontransitionend === undefined &&
|
|
window.onwebkittransitionend !== undefined) {
|
|
transitionProp = 'WebkitTransition';
|
|
transitionEndEvent = 'webkitTransitionEnd';
|
|
}
|
|
if (window.onanimationend === undefined &&
|
|
window.onwebkitanimationend !== undefined) {
|
|
animationProp = 'WebkitAnimation';
|
|
animationEndEvent = 'webkitAnimationEnd';
|
|
}
|
|
}
|
|
|
|
// binding to window is necessary to make hot reload work in IE in strict mode
|
|
var raf = inBrowser && window.requestAnimationFrame
|
|
? window.requestAnimationFrame.bind(window)
|
|
: setTimeout;
|
|
|
|
function nextFrame (fn) {
|
|
raf(function () {
|
|
raf(fn);
|
|
});
|
|
}
|
|
|
|
function addTransitionClass (el, cls) {
|
|
(el._transitionClasses || (el._transitionClasses = [])).push(cls);
|
|
addClass(el, cls);
|
|
}
|
|
|
|
function removeTransitionClass (el, cls) {
|
|
if (el._transitionClasses) {
|
|
remove(el._transitionClasses, cls);
|
|
}
|
|
removeClass(el, cls);
|
|
}
|
|
|
|
function whenTransitionEnds (
|
|
el,
|
|
expectedType,
|
|
cb
|
|
) {
|
|
var ref = getTransitionInfo(el, expectedType);
|
|
var type = ref.type;
|
|
var timeout = ref.timeout;
|
|
var propCount = ref.propCount;
|
|
if (!type) { return cb() }
|
|
var event = type === TRANSITION ? transitionEndEvent : animationEndEvent;
|
|
var ended = 0;
|
|
var end = function () {
|
|
el.removeEventListener(event, onEnd);
|
|
cb();
|
|
};
|
|
var onEnd = function (e) {
|
|
if (e.target === el) {
|
|
if (++ended >= propCount) {
|
|
end();
|
|
}
|
|
}
|
|
};
|
|
setTimeout(function () {
|
|
if (ended < propCount) {
|
|
end();
|
|
}
|
|
}, timeout + 1);
|
|
el.addEventListener(event, onEnd);
|
|
}
|
|
|
|
var transformRE = /\b(transform|all)(,|$)/;
|
|
|
|
function getTransitionInfo (el, expectedType) {
|
|
var styles = window.getComputedStyle(el);
|
|
var transitioneDelays = styles[transitionProp + 'Delay'].split(', ');
|
|
var transitionDurations = styles[transitionProp + 'Duration'].split(', ');
|
|
var transitionTimeout = getTimeout(transitioneDelays, transitionDurations);
|
|
var animationDelays = styles[animationProp + 'Delay'].split(', ');
|
|
var animationDurations = styles[animationProp + 'Duration'].split(', ');
|
|
var animationTimeout = getTimeout(animationDelays, animationDurations);
|
|
|
|
var type;
|
|
var timeout = 0;
|
|
var propCount = 0;
|
|
/* istanbul ignore if */
|
|
if (expectedType === TRANSITION) {
|
|
if (transitionTimeout > 0) {
|
|
type = TRANSITION;
|
|
timeout = transitionTimeout;
|
|
propCount = transitionDurations.length;
|
|
}
|
|
} else if (expectedType === ANIMATION) {
|
|
if (animationTimeout > 0) {
|
|
type = ANIMATION;
|
|
timeout = animationTimeout;
|
|
propCount = animationDurations.length;
|
|
}
|
|
} else {
|
|
timeout = Math.max(transitionTimeout, animationTimeout);
|
|
type = timeout > 0
|
|
? transitionTimeout > animationTimeout
|
|
? TRANSITION
|
|
: ANIMATION
|
|
: null;
|
|
propCount = type
|
|
? type === TRANSITION
|
|
? transitionDurations.length
|
|
: animationDurations.length
|
|
: 0;
|
|
}
|
|
var hasTransform =
|
|
type === TRANSITION &&
|
|
transformRE.test(styles[transitionProp + 'Property']);
|
|
return {
|
|
type: type,
|
|
timeout: timeout,
|
|
propCount: propCount,
|
|
hasTransform: hasTransform
|
|
}
|
|
}
|
|
|
|
function getTimeout (delays, durations) {
|
|
/* istanbul ignore next */
|
|
while (delays.length < durations.length) {
|
|
delays = delays.concat(delays);
|
|
}
|
|
|
|
return Math.max.apply(null, durations.map(function (d, i) {
|
|
return toMs(d) + toMs(delays[i])
|
|
}))
|
|
}
|
|
|
|
function toMs (s) {
|
|
return Number(s.slice(0, -1)) * 1000
|
|
}
|
|
|
|
/* */
|
|
|
|
function enter (vnode, toggleDisplay) {
|
|
var el = vnode.elm;
|
|
|
|
// call leave callback now
|
|
if (el._leaveCb) {
|
|
el._leaveCb.cancelled = true;
|
|
el._leaveCb();
|
|
}
|
|
|
|
var data = resolveTransition(vnode.data.transition);
|
|
if (!data) {
|
|
return
|
|
}
|
|
|
|
/* istanbul ignore if */
|
|
if (el._enterCb || el.nodeType !== 1) {
|
|
return
|
|
}
|
|
|
|
var css = data.css;
|
|
var type = data.type;
|
|
var enterClass = data.enterClass;
|
|
var enterToClass = data.enterToClass;
|
|
var enterActiveClass = data.enterActiveClass;
|
|
var appearClass = data.appearClass;
|
|
var appearToClass = data.appearToClass;
|
|
var appearActiveClass = data.appearActiveClass;
|
|
var beforeEnter = data.beforeEnter;
|
|
var enter = data.enter;
|
|
var afterEnter = data.afterEnter;
|
|
var enterCancelled = data.enterCancelled;
|
|
var beforeAppear = data.beforeAppear;
|
|
var appear = data.appear;
|
|
var afterAppear = data.afterAppear;
|
|
var appearCancelled = data.appearCancelled;
|
|
var duration = data.duration;
|
|
|
|
// activeInstance will always be the <transition> component managing this
|
|
// transition. One edge case to check is when the <transition> is placed
|
|
// as the root node of a child component. In that case we need to check
|
|
// <transition>'s parent for appear check.
|
|
var context = activeInstance;
|
|
var transitionNode = activeInstance.$vnode;
|
|
while (transitionNode && transitionNode.parent) {
|
|
transitionNode = transitionNode.parent;
|
|
context = transitionNode.context;
|
|
}
|
|
|
|
var isAppear = !context._isMounted || !vnode.isRootInsert;
|
|
|
|
if (isAppear && !appear && appear !== '') {
|
|
return
|
|
}
|
|
|
|
var startClass = isAppear && appearClass
|
|
? appearClass
|
|
: enterClass;
|
|
var activeClass = isAppear && appearActiveClass
|
|
? appearActiveClass
|
|
: enterActiveClass;
|
|
var toClass = isAppear && appearToClass
|
|
? appearToClass
|
|
: enterToClass;
|
|
|
|
var beforeEnterHook = isAppear
|
|
? (beforeAppear || beforeEnter)
|
|
: beforeEnter;
|
|
var enterHook = isAppear
|
|
? (typeof appear === 'function' ? appear : enter)
|
|
: enter;
|
|
var afterEnterHook = isAppear
|
|
? (afterAppear || afterEnter)
|
|
: afterEnter;
|
|
var enterCancelledHook = isAppear
|
|
? (appearCancelled || enterCancelled)
|
|
: enterCancelled;
|
|
|
|
var explicitEnterDuration = toNumber(
|
|
isObject(duration)
|
|
? duration.enter
|
|
: duration
|
|
);
|
|
|
|
if ("development" !== 'production' && explicitEnterDuration != null) {
|
|
checkDuration(explicitEnterDuration, 'enter', vnode);
|
|
}
|
|
|
|
var expectsCSS = css !== false && !isIE9;
|
|
var userWantsControl = getHookAgumentsLength(enterHook);
|
|
|
|
var cb = el._enterCb = once(function () {
|
|
if (expectsCSS) {
|
|
removeTransitionClass(el, toClass);
|
|
removeTransitionClass(el, activeClass);
|
|
}
|
|
if (cb.cancelled) {
|
|
if (expectsCSS) {
|
|
removeTransitionClass(el, startClass);
|
|
}
|
|
enterCancelledHook && enterCancelledHook(el);
|
|
} else {
|
|
afterEnterHook && afterEnterHook(el);
|
|
}
|
|
el._enterCb = null;
|
|
});
|
|
|
|
if (!vnode.data.show) {
|
|
// remove pending leave element on enter by injecting an insert hook
|
|
mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'insert', function () {
|
|
var parent = el.parentNode;
|
|
var pendingNode = parent && parent._pending && parent._pending[vnode.key];
|
|
if (pendingNode &&
|
|
pendingNode.tag === vnode.tag &&
|
|
pendingNode.elm._leaveCb) {
|
|
pendingNode.elm._leaveCb();
|
|
}
|
|
enterHook && enterHook(el, cb);
|
|
});
|
|
}
|
|
|
|
// start enter transition
|
|
beforeEnterHook && beforeEnterHook(el);
|
|
if (expectsCSS) {
|
|
addTransitionClass(el, startClass);
|
|
addTransitionClass(el, activeClass);
|
|
nextFrame(function () {
|
|
addTransitionClass(el, toClass);
|
|
removeTransitionClass(el, startClass);
|
|
if (!cb.cancelled && !userWantsControl) {
|
|
if (isValidDuration(explicitEnterDuration)) {
|
|
setTimeout(cb, explicitEnterDuration);
|
|
} else {
|
|
whenTransitionEnds(el, type, cb);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (vnode.data.show) {
|
|
toggleDisplay && toggleDisplay();
|
|
enterHook && enterHook(el, cb);
|
|
}
|
|
|
|
if (!expectsCSS && !userWantsControl) {
|
|
cb();
|
|
}
|
|
}
|
|
|
|
function leave (vnode, rm) {
|
|
var el = vnode.elm;
|
|
|
|
// call enter callback now
|
|
if (el._enterCb) {
|
|
el._enterCb.cancelled = true;
|
|
el._enterCb();
|
|
}
|
|
|
|
var data = resolveTransition(vnode.data.transition);
|
|
if (!data) {
|
|
return rm()
|
|
}
|
|
|
|
/* istanbul ignore if */
|
|
if (el._leaveCb || el.nodeType !== 1) {
|
|
return
|
|
}
|
|
|
|
var css = data.css;
|
|
var type = data.type;
|
|
var leaveClass = data.leaveClass;
|
|
var leaveToClass = data.leaveToClass;
|
|
var leaveActiveClass = data.leaveActiveClass;
|
|
var beforeLeave = data.beforeLeave;
|
|
var leave = data.leave;
|
|
var afterLeave = data.afterLeave;
|
|
var leaveCancelled = data.leaveCancelled;
|
|
var delayLeave = data.delayLeave;
|
|
var duration = data.duration;
|
|
|
|
var expectsCSS = css !== false && !isIE9;
|
|
var userWantsControl = getHookAgumentsLength(leave);
|
|
|
|
var explicitLeaveDuration = toNumber(
|
|
isObject(duration)
|
|
? duration.leave
|
|
: duration
|
|
);
|
|
|
|
if ("development" !== 'production' && explicitLeaveDuration != null) {
|
|
checkDuration(explicitLeaveDuration, 'leave', vnode);
|
|
}
|
|
|
|
var cb = el._leaveCb = once(function () {
|
|
if (el.parentNode && el.parentNode._pending) {
|
|
el.parentNode._pending[vnode.key] = null;
|
|
}
|
|
if (expectsCSS) {
|
|
removeTransitionClass(el, leaveToClass);
|
|
removeTransitionClass(el, leaveActiveClass);
|
|
}
|
|
if (cb.cancelled) {
|
|
if (expectsCSS) {
|
|
removeTransitionClass(el, leaveClass);
|
|
}
|
|
leaveCancelled && leaveCancelled(el);
|
|
} else {
|
|
rm();
|
|
afterLeave && afterLeave(el);
|
|
}
|
|
el._leaveCb = null;
|
|
});
|
|
|
|
if (delayLeave) {
|
|
delayLeave(performLeave);
|
|
} else {
|
|
performLeave();
|
|
}
|
|
|
|
function performLeave () {
|
|
// the delayed leave may have already been cancelled
|
|
if (cb.cancelled) {
|
|
return
|
|
}
|
|
// record leaving element
|
|
if (!vnode.data.show) {
|
|
(el.parentNode._pending || (el.parentNode._pending = {}))[vnode.key] = vnode;
|
|
}
|
|
beforeLeave && beforeLeave(el);
|
|
if (expectsCSS) {
|
|
addTransitionClass(el, leaveClass);
|
|
addTransitionClass(el, leaveActiveClass);
|
|
nextFrame(function () {
|
|
addTransitionClass(el, leaveToClass);
|
|
removeTransitionClass(el, leaveClass);
|
|
if (!cb.cancelled && !userWantsControl) {
|
|
if (isValidDuration(explicitLeaveDuration)) {
|
|
setTimeout(cb, explicitLeaveDuration);
|
|
} else {
|
|
whenTransitionEnds(el, type, cb);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
leave && leave(el, cb);
|
|
if (!expectsCSS && !userWantsControl) {
|
|
cb();
|
|
}
|
|
}
|
|
}
|
|
|
|
// only used in dev mode
|
|
function checkDuration (val, name, vnode) {
|
|
if (typeof val !== 'number') {
|
|
warn(
|
|
"<transition> explicit " + name + " duration is not a valid number - " +
|
|
"got " + (JSON.stringify(val)) + ".",
|
|
vnode.context
|
|
);
|
|
} else if (isNaN(val)) {
|
|
warn(
|
|
"<transition> explicit " + name + " duration is NaN - " +
|
|
'the duration expression might be incorrect.',
|
|
vnode.context
|
|
);
|
|
}
|
|
}
|
|
|
|
function isValidDuration (val) {
|
|
return typeof val === 'number' && !isNaN(val)
|
|
}
|
|
|
|
/**
|
|
* Normalize a transition hook's argument length. The hook may be:
|
|
* - a merged hook (invoker) with the original in .fns
|
|
* - a wrapped component method (check ._length)
|
|
* - a plain function (.length)
|
|
*/
|
|
function getHookAgumentsLength (fn) {
|
|
if (!fn) { return false }
|
|
var invokerFns = fn.fns;
|
|
if (invokerFns) {
|
|
// invoker
|
|
return getHookAgumentsLength(
|
|
Array.isArray(invokerFns)
|
|
? invokerFns[0]
|
|
: invokerFns
|
|
)
|
|
} else {
|
|
return (fn._length || fn.length) > 1
|
|
}
|
|
}
|
|
|
|
function _enter (_, vnode) {
|
|
if (!vnode.data.show) {
|
|
enter(vnode);
|
|
}
|
|
}
|
|
|
|
var transition = inBrowser ? {
|
|
create: _enter,
|
|
activate: _enter,
|
|
remove: function remove$$1 (vnode, rm) {
|
|
/* istanbul ignore else */
|
|
if (!vnode.data.show) {
|
|
leave(vnode, rm);
|
|
} else {
|
|
rm();
|
|
}
|
|
}
|
|
} : {};
|
|
|
|
var platformModules = [
|
|
attrs,
|
|
klass,
|
|
events,
|
|
domProps,
|
|
style,
|
|
transition
|
|
];
|
|
|
|
/* */
|
|
|
|
// the directive module should be applied last, after all
|
|
// built-in modules have been applied.
|
|
var modules = platformModules.concat(baseModules);
|
|
|
|
var patch = createPatchFunction({ nodeOps: nodeOps, modules: modules });
|
|
|
|
/**
|
|
* Not type checking this file because flow doesn't like attaching
|
|
* properties to Elements.
|
|
*/
|
|
|
|
/* istanbul ignore if */
|
|
if (isIE9) {
|
|
// http://www.matts411.com/post/internet-explorer-9-oninput/
|
|
document.addEventListener('selectionchange', function () {
|
|
var el = document.activeElement;
|
|
if (el && el.vmodel) {
|
|
trigger(el, 'input');
|
|
}
|
|
});
|
|
}
|
|
|
|
var model$1 = {
|
|
inserted: function inserted (el, binding, vnode) {
|
|
if (vnode.tag === 'select') {
|
|
var cb = function () {
|
|
setSelected(el, binding, vnode.context);
|
|
};
|
|
cb();
|
|
/* istanbul ignore if */
|
|
if (isIE || isEdge) {
|
|
setTimeout(cb, 0);
|
|
}
|
|
} else if (vnode.tag === 'textarea' || el.type === 'text') {
|
|
el._vModifiers = binding.modifiers;
|
|
if (!binding.modifiers.lazy) {
|
|
if (!isAndroid) {
|
|
el.addEventListener('compositionstart', onCompositionStart);
|
|
el.addEventListener('compositionend', onCompositionEnd);
|
|
}
|
|
/* istanbul ignore if */
|
|
if (isIE9) {
|
|
el.vmodel = true;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
componentUpdated: function componentUpdated (el, binding, vnode) {
|
|
if (vnode.tag === 'select') {
|
|
setSelected(el, binding, vnode.context);
|
|
// in case the options rendered by v-for have changed,
|
|
// it's possible that the value is out-of-sync with the rendered options.
|
|
// detect such cases and filter out values that no longer has a matching
|
|
// option in the DOM.
|
|
var needReset = el.multiple
|
|
? binding.value.some(function (v) { return hasNoMatchingOption(v, el.options); })
|
|
: binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options);
|
|
if (needReset) {
|
|
trigger(el, 'change');
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function setSelected (el, binding, vm) {
|
|
var value = binding.value;
|
|
var isMultiple = el.multiple;
|
|
if (isMultiple && !Array.isArray(value)) {
|
|
"development" !== 'production' && warn(
|
|
"<select multiple v-model=\"" + (binding.expression) + "\"> " +
|
|
"expects an Array value for its binding, but got " + (Object.prototype.toString.call(value).slice(8, -1)),
|
|
vm
|
|
);
|
|
return
|
|
}
|
|
var selected, option;
|
|
for (var i = 0, l = el.options.length; i < l; i++) {
|
|
option = el.options[i];
|
|
if (isMultiple) {
|
|
selected = looseIndexOf(value, getValue(option)) > -1;
|
|
if (option.selected !== selected) {
|
|
option.selected = selected;
|
|
}
|
|
} else {
|
|
if (looseEqual(getValue(option), value)) {
|
|
if (el.selectedIndex !== i) {
|
|
el.selectedIndex = i;
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
if (!isMultiple) {
|
|
el.selectedIndex = -1;
|
|
}
|
|
}
|
|
|
|
function hasNoMatchingOption (value, options) {
|
|
for (var i = 0, l = options.length; i < l; i++) {
|
|
if (looseEqual(getValue(options[i]), value)) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
function getValue (option) {
|
|
return '_value' in option
|
|
? option._value
|
|
: option.value
|
|
}
|
|
|
|
function onCompositionStart (e) {
|
|
e.target.composing = true;
|
|
}
|
|
|
|
function onCompositionEnd (e) {
|
|
e.target.composing = false;
|
|
trigger(e.target, 'input');
|
|
}
|
|
|
|
function trigger (el, type) {
|
|
var e = document.createEvent('HTMLEvents');
|
|
e.initEvent(type, true, true);
|
|
el.dispatchEvent(e);
|
|
}
|
|
|
|
/* */
|
|
|
|
// recursively search for possible transition defined inside the component root
|
|
function locateNode (vnode) {
|
|
return vnode.componentInstance && (!vnode.data || !vnode.data.transition)
|
|
? locateNode(vnode.componentInstance._vnode)
|
|
: vnode
|
|
}
|
|
|
|
var show = {
|
|
bind: function bind (el, ref, vnode) {
|
|
var value = ref.value;
|
|
|
|
vnode = locateNode(vnode);
|
|
var transition = vnode.data && vnode.data.transition;
|
|
var originalDisplay = el.__vOriginalDisplay =
|
|
el.style.display === 'none' ? '' : el.style.display;
|
|
if (value && transition && !isIE9) {
|
|
vnode.data.show = true;
|
|
enter(vnode, function () {
|
|
el.style.display = originalDisplay;
|
|
});
|
|
} else {
|
|
el.style.display = value ? originalDisplay : 'none';
|
|
}
|
|
},
|
|
|
|
update: function update (el, ref, vnode) {
|
|
var value = ref.value;
|
|
var oldValue = ref.oldValue;
|
|
|
|
/* istanbul ignore if */
|
|
if (value === oldValue) { return }
|
|
vnode = locateNode(vnode);
|
|
var transition = vnode.data && vnode.data.transition;
|
|
if (transition && !isIE9) {
|
|
vnode.data.show = true;
|
|
if (value) {
|
|
enter(vnode, function () {
|
|
el.style.display = el.__vOriginalDisplay;
|
|
});
|
|
} else {
|
|
leave(vnode, function () {
|
|
el.style.display = 'none';
|
|
});
|
|
}
|
|
} else {
|
|
el.style.display = value ? el.__vOriginalDisplay : 'none';
|
|
}
|
|
},
|
|
|
|
unbind: function unbind (
|
|
el,
|
|
binding,
|
|
vnode,
|
|
oldVnode,
|
|
isDestroy
|
|
) {
|
|
if (!isDestroy) {
|
|
el.style.display = el.__vOriginalDisplay;
|
|
}
|
|
}
|
|
};
|
|
|
|
var platformDirectives = {
|
|
model: model$1,
|
|
show: show
|
|
};
|
|
|
|
/* */
|
|
|
|
// Provides transition support for a single element/component.
|
|
// supports transition mode (out-in / in-out)
|
|
|
|
var transitionProps = {
|
|
name: String,
|
|
appear: Boolean,
|
|
css: Boolean,
|
|
mode: String,
|
|
type: String,
|
|
enterClass: String,
|
|
leaveClass: String,
|
|
enterToClass: String,
|
|
leaveToClass: String,
|
|
enterActiveClass: String,
|
|
leaveActiveClass: String,
|
|
appearClass: String,
|
|
appearActiveClass: String,
|
|
appearToClass: String,
|
|
duration: [Number, String, Object]
|
|
};
|
|
|
|
// in case the child is also an abstract component, e.g. <keep-alive>
|
|
// we want to recursively retrieve the real component to be rendered
|
|
function getRealChild (vnode) {
|
|
var compOptions = vnode && vnode.componentOptions;
|
|
if (compOptions && compOptions.Ctor.options.abstract) {
|
|
return getRealChild(getFirstComponentChild(compOptions.children))
|
|
} else {
|
|
return vnode
|
|
}
|
|
}
|
|
|
|
function extractTransitionData (comp) {
|
|
var data = {};
|
|
var options = comp.$options;
|
|
// props
|
|
for (var key in options.propsData) {
|
|
data[key] = comp[key];
|
|
}
|
|
// events.
|
|
// extract listeners and pass them directly to the transition methods
|
|
var listeners = options._parentListeners;
|
|
for (var key$1 in listeners) {
|
|
data[camelize(key$1)] = listeners[key$1];
|
|
}
|
|
return data
|
|
}
|
|
|
|
function placeholder (h, rawChild) {
|
|
return /\d-keep-alive$/.test(rawChild.tag)
|
|
? h('keep-alive')
|
|
: null
|
|
}
|
|
|
|
function hasParentTransition (vnode) {
|
|
while ((vnode = vnode.parent)) {
|
|
if (vnode.data.transition) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
function isSameChild (child, oldChild) {
|
|
return oldChild.key === child.key && oldChild.tag === child.tag
|
|
}
|
|
|
|
var Transition = {
|
|
name: 'transition',
|
|
props: transitionProps,
|
|
abstract: true,
|
|
|
|
render: function render (h) {
|
|
var this$1 = this;
|
|
|
|
var children = this.$slots.default;
|
|
if (!children) {
|
|
return
|
|
}
|
|
|
|
// filter out text nodes (possible whitespaces)
|
|
children = children.filter(function (c) { return c.tag; });
|
|
/* istanbul ignore if */
|
|
if (!children.length) {
|
|
return
|
|
}
|
|
|
|
// warn multiple elements
|
|
if ("development" !== 'production' && children.length > 1) {
|
|
warn(
|
|
'<transition> can only be used on a single element. Use ' +
|
|
'<transition-group> for lists.',
|
|
this.$parent
|
|
);
|
|
}
|
|
|
|
var mode = this.mode;
|
|
|
|
// warn invalid mode
|
|
if ("development" !== 'production' &&
|
|
mode && mode !== 'in-out' && mode !== 'out-in') {
|
|
warn(
|
|
'invalid <transition> mode: ' + mode,
|
|
this.$parent
|
|
);
|
|
}
|
|
|
|
var rawChild = children[0];
|
|
|
|
// if this is a component root node and the component's
|
|
// parent container node also has transition, skip.
|
|
if (hasParentTransition(this.$vnode)) {
|
|
return rawChild
|
|
}
|
|
|
|
// apply transition data to child
|
|
// use getRealChild() to ignore abstract components e.g. keep-alive
|
|
var child = getRealChild(rawChild);
|
|
/* istanbul ignore if */
|
|
if (!child) {
|
|
return rawChild
|
|
}
|
|
|
|
if (this._leaving) {
|
|
return placeholder(h, rawChild)
|
|
}
|
|
|
|
// ensure a key that is unique to the vnode type and to this transition
|
|
// component instance. This key will be used to remove pending leaving nodes
|
|
// during entering.
|
|
var id = "__transition-" + (this._uid) + "-";
|
|
child.key = child.key == null
|
|
? id + child.tag
|
|
: isPrimitive(child.key)
|
|
? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key)
|
|
: child.key;
|
|
|
|
var data = (child.data || (child.data = {})).transition = extractTransitionData(this);
|
|
var oldRawChild = this._vnode;
|
|
var oldChild = getRealChild(oldRawChild);
|
|
|
|
// mark v-show
|
|
// so that the transition module can hand over the control to the directive
|
|
if (child.data.directives && child.data.directives.some(function (d) { return d.name === 'show'; })) {
|
|
child.data.show = true;
|
|
}
|
|
|
|
if (oldChild && oldChild.data && !isSameChild(child, oldChild)) {
|
|
// replace old child transition data with fresh one
|
|
// important for dynamic transitions!
|
|
var oldData = oldChild && (oldChild.data.transition = extend({}, data));
|
|
// handle transition mode
|
|
if (mode === 'out-in') {
|
|
// return placeholder node and queue update when leave finishes
|
|
this._leaving = true;
|
|
mergeVNodeHook(oldData, 'afterLeave', function () {
|
|
this$1._leaving = false;
|
|
this$1.$forceUpdate();
|
|
});
|
|
return placeholder(h, rawChild)
|
|
} else if (mode === 'in-out') {
|
|
var delayedLeave;
|
|
var performLeave = function () { delayedLeave(); };
|
|
mergeVNodeHook(data, 'afterEnter', performLeave);
|
|
mergeVNodeHook(data, 'enterCancelled', performLeave);
|
|
mergeVNodeHook(oldData, 'delayLeave', function (leave) { delayedLeave = leave; });
|
|
}
|
|
}
|
|
|
|
return rawChild
|
|
}
|
|
};
|
|
|
|
/* */
|
|
|
|
// Provides transition support for list items.
|
|
// supports move transitions using the FLIP technique.
|
|
|
|
// Because the vdom's children update algorithm is "unstable" - i.e.
|
|
// it doesn't guarantee the relative positioning of removed elements,
|
|
// we force transition-group to update its children into two passes:
|
|
// in the first pass, we remove all nodes that need to be removed,
|
|
// triggering their leaving transition; in the second pass, we insert/move
|
|
// into the final disired state. This way in the second pass removed
|
|
// nodes will remain where they should be.
|
|
|
|
var props = extend({
|
|
tag: String,
|
|
moveClass: String
|
|
}, transitionProps);
|
|
|
|
delete props.mode;
|
|
|
|
var TransitionGroup = {
|
|
props: props,
|
|
|
|
render: function render (h) {
|
|
var tag = this.tag || this.$vnode.data.tag || 'span';
|
|
var map = Object.create(null);
|
|
var prevChildren = this.prevChildren = this.children;
|
|
var rawChildren = this.$slots.default || [];
|
|
var children = this.children = [];
|
|
var transitionData = extractTransitionData(this);
|
|
|
|
for (var i = 0; i < rawChildren.length; i++) {
|
|
var c = rawChildren[i];
|
|
if (c.tag) {
|
|
if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
|
|
children.push(c);
|
|
map[c.key] = c
|
|
;(c.data || (c.data = {})).transition = transitionData;
|
|
} else {
|
|
var opts = c.componentOptions;
|
|
var name = opts ? (opts.Ctor.options.name || opts.tag || '') : c.tag;
|
|
warn(("<transition-group> children must be keyed: <" + name + ">"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prevChildren) {
|
|
var kept = [];
|
|
var removed = [];
|
|
for (var i$1 = 0; i$1 < prevChildren.length; i$1++) {
|
|
var c$1 = prevChildren[i$1];
|
|
c$1.data.transition = transitionData;
|
|
c$1.data.pos = c$1.elm.getBoundingClientRect();
|
|
if (map[c$1.key]) {
|
|
kept.push(c$1);
|
|
} else {
|
|
removed.push(c$1);
|
|
}
|
|
}
|
|
this.kept = h(tag, null, kept);
|
|
this.removed = removed;
|
|
}
|
|
|
|
return h(tag, null, children)
|
|
},
|
|
|
|
beforeUpdate: function beforeUpdate () {
|
|
// force removing pass
|
|
this.__patch__(
|
|
this._vnode,
|
|
this.kept,
|
|
false, // hydrating
|
|
true // removeOnly (!important, avoids unnecessary moves)
|
|
);
|
|
this._vnode = this.kept;
|
|
},
|
|
|
|
updated: function updated () {
|
|
var children = this.prevChildren;
|
|
var moveClass = this.moveClass || ((this.name || 'v') + '-move');
|
|
if (!children.length || !this.hasMove(children[0].elm, moveClass)) {
|
|
return
|
|
}
|
|
|
|
// we divide the work into three loops to avoid mixing DOM reads and writes
|
|
// in each iteration - which helps prevent layout thrashing.
|
|
children.forEach(callPendingCbs);
|
|
children.forEach(recordPosition);
|
|
children.forEach(applyTranslation);
|
|
|
|
// force reflow to put everything in position
|
|
var body = document.body;
|
|
var f = body.offsetHeight; // eslint-disable-line
|
|
|
|
children.forEach(function (c) {
|
|
if (c.data.moved) {
|
|
var el = c.elm;
|
|
var s = el.style;
|
|
addTransitionClass(el, moveClass);
|
|
s.transform = s.WebkitTransform = s.transitionDuration = '';
|
|
el.addEventListener(transitionEndEvent, el._moveCb = function cb (e) {
|
|
if (!e || /transform$/.test(e.propertyName)) {
|
|
el.removeEventListener(transitionEndEvent, cb);
|
|
el._moveCb = null;
|
|
removeTransitionClass(el, moveClass);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
methods: {
|
|
hasMove: function hasMove (el, moveClass) {
|
|
/* istanbul ignore if */
|
|
if (!hasTransition) {
|
|
return false
|
|
}
|
|
if (this._hasMove != null) {
|
|
return this._hasMove
|
|
}
|
|
// Detect whether an element with the move class applied has
|
|
// CSS transitions. Since the element may be inside an entering
|
|
// transition at this very moment, we make a clone of it and remove
|
|
// all other transition classes applied to ensure only the move class
|
|
// is applied.
|
|
var clone = el.cloneNode();
|
|
if (el._transitionClasses) {
|
|
el._transitionClasses.forEach(function (cls) { removeClass(clone, cls); });
|
|
}
|
|
addClass(clone, moveClass);
|
|
clone.style.display = 'none';
|
|
this.$el.appendChild(clone);
|
|
var info = getTransitionInfo(clone);
|
|
this.$el.removeChild(clone);
|
|
return (this._hasMove = info.hasTransform)
|
|
}
|
|
}
|
|
};
|
|
|
|
function callPendingCbs (c) {
|
|
/* istanbul ignore if */
|
|
if (c.elm._moveCb) {
|
|
c.elm._moveCb();
|
|
}
|
|
/* istanbul ignore if */
|
|
if (c.elm._enterCb) {
|
|
c.elm._enterCb();
|
|
}
|
|
}
|
|
|
|
function recordPosition (c) {
|
|
c.data.newPos = c.elm.getBoundingClientRect();
|
|
}
|
|
|
|
function applyTranslation (c) {
|
|
var oldPos = c.data.pos;
|
|
var newPos = c.data.newPos;
|
|
var dx = oldPos.left - newPos.left;
|
|
var dy = oldPos.top - newPos.top;
|
|
if (dx || dy) {
|
|
c.data.moved = true;
|
|
var s = c.elm.style;
|
|
s.transform = s.WebkitTransform = "translate(" + dx + "px," + dy + "px)";
|
|
s.transitionDuration = '0s';
|
|
}
|
|
}
|
|
|
|
var platformComponents = {
|
|
Transition: Transition,
|
|
TransitionGroup: TransitionGroup
|
|
};
|
|
|
|
/* */
|
|
|
|
// install platform specific utils
|
|
Vue$3.config.mustUseProp = mustUseProp;
|
|
Vue$3.config.isReservedTag = isReservedTag;
|
|
Vue$3.config.getTagNamespace = getTagNamespace;
|
|
Vue$3.config.isUnknownElement = isUnknownElement;
|
|
|
|
// install platform runtime directives & components
|
|
extend(Vue$3.options.directives, platformDirectives);
|
|
extend(Vue$3.options.components, platformComponents);
|
|
|
|
// install platform patch function
|
|
Vue$3.prototype.__patch__ = inBrowser ? patch : noop;
|
|
|
|
// public mount method
|
|
Vue$3.prototype.$mount = function (
|
|
el,
|
|
hydrating
|
|
) {
|
|
el = el && inBrowser ? query(el) : undefined;
|
|
return mountComponent(this, el, hydrating)
|
|
};
|
|
|
|
// devtools global hook
|
|
/* istanbul ignore next */
|
|
setTimeout(function () {
|
|
if (config.devtools) {
|
|
if (devtools) {
|
|
devtools.emit('init', Vue$3);
|
|
} else if ("development" !== 'production' && isChrome) {
|
|
console[console.info ? 'info' : 'log'](
|
|
'Download the Vue Devtools extension for a better development experience:\n' +
|
|
'https://github.com/vuejs/vue-devtools'
|
|
);
|
|
}
|
|
}
|
|
if ("development" !== 'production' &&
|
|
config.productionTip !== false &&
|
|
inBrowser && typeof console !== 'undefined') {
|
|
console[console.info ? 'info' : 'log'](
|
|
"You are running Vue in development mode.\n" +
|
|
"Make sure to turn on production mode when deploying for production.\n" +
|
|
"See more tips at https://vuejs.org/guide/deployment.html"
|
|
);
|
|
}
|
|
}, 0);
|
|
|
|
/* */
|
|
|
|
// check whether current browser encodes a char inside attribute values
|
|
function shouldDecode (content, encoded) {
|
|
var div = document.createElement('div');
|
|
div.innerHTML = "<div a=\"" + content + "\">";
|
|
return div.innerHTML.indexOf(encoded) > 0
|
|
}
|
|
|
|
// #3663
|
|
// IE encodes newlines inside attribute values while other browsers don't
|
|
var shouldDecodeNewlines = inBrowser ? shouldDecode('\n', ' ') : false;
|
|
|
|
/* */
|
|
|
|
var isUnaryTag = makeMap(
|
|
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
|
|
'link,meta,param,source,track,wbr',
|
|
true
|
|
);
|
|
|
|
// Elements that you can, intentionally, leave open
|
|
// (and which close themselves)
|
|
var canBeLeftOpenTag = makeMap(
|
|
'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source',
|
|
true
|
|
);
|
|
|
|
// HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3
|
|
// Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
|
|
var isNonPhrasingTag = makeMap(
|
|
'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
|
|
'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
|
|
'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
|
|
'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
|
|
'title,tr,track',
|
|
true
|
|
);
|
|
|
|
/* */
|
|
|
|
var decoder;
|
|
|
|
function decode (html) {
|
|
decoder = decoder || document.createElement('div');
|
|
decoder.innerHTML = html;
|
|
return decoder.textContent
|
|
}
|
|
|
|
/**
|
|
* Not type-checking this file because it's mostly vendor code.
|
|
*/
|
|
|
|
/*!
|
|
* HTML Parser By John Resig (ejohn.org)
|
|
* Modified by Juriy "kangax" Zaytsev
|
|
* Original code by Erik Arvidsson, Mozilla Public License
|
|
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
|
*/
|
|
|
|
// Regular Expressions for parsing tags and attributes
|
|
var singleAttrIdentifier = /([^\s"'<>/=]+)/;
|
|
var singleAttrAssign = /(?:=)/;
|
|
var singleAttrValues = [
|
|
// attr value double quotes
|
|
/"([^"]*)"+/.source,
|
|
// attr value, single quotes
|
|
/'([^']*)'+/.source,
|
|
// attr value, no quotes
|
|
/([^\s"'=<>`]+)/.source
|
|
];
|
|
var attribute = new RegExp(
|
|
'^\\s*' + singleAttrIdentifier.source +
|
|
'(?:\\s*(' + singleAttrAssign.source + ')' +
|
|
'\\s*(?:' + singleAttrValues.join('|') + '))?'
|
|
);
|
|
|
|
// could use https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName
|
|
// but for Vue templates we can enforce a simple charset
|
|
var ncname = '[a-zA-Z_][\\w\\-\\.]*';
|
|
var qnameCapture = '((?:' + ncname + '\\:)?' + ncname + ')';
|
|
var startTagOpen = new RegExp('^<' + qnameCapture);
|
|
var startTagClose = /^\s*(\/?)>/;
|
|
var endTag = new RegExp('^<\\/' + qnameCapture + '[^>]*>');
|
|
var doctype = /^<!DOCTYPE [^>]+>/i;
|
|
var comment = /^<!--/;
|
|
var conditionalComment = /^<!\[/;
|
|
|
|
var IS_REGEX_CAPTURING_BROKEN = false;
|
|
'x'.replace(/x(.)?/g, function (m, g) {
|
|
IS_REGEX_CAPTURING_BROKEN = g === '';
|
|
});
|
|
|
|
// Special Elements (can contain anything)
|
|
var isScriptOrStyle = makeMap('script,style', true);
|
|
var reCache = {};
|
|
|
|
var decodingMap = {
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
'&': '&',
|
|
' ': '\n'
|
|
};
|
|
var encodedAttr = /&(?:lt|gt|quot|amp);/g;
|
|
var encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#10);/g;
|
|
|
|
function decodeAttr (value, shouldDecodeNewlines) {
|
|
var re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr;
|
|
return value.replace(re, function (match) { return decodingMap[match]; })
|
|
}
|
|
|
|
function parseHTML (html, options) {
|
|
var stack = [];
|
|
var expectHTML = options.expectHTML;
|
|
var isUnaryTag$$1 = options.isUnaryTag || no;
|
|
var index = 0;
|
|
var last, lastTag;
|
|
while (html) {
|
|
last = html;
|
|
// Make sure we're not in a script or style element
|
|
if (!lastTag || !isScriptOrStyle(lastTag)) {
|
|
var textEnd = html.indexOf('<');
|
|
if (textEnd === 0) {
|
|
// Comment:
|
|
if (comment.test(html)) {
|
|
var commentEnd = html.indexOf('-->');
|
|
|
|
if (commentEnd >= 0) {
|
|
advance(commentEnd + 3);
|
|
continue
|
|
}
|
|
}
|
|
|
|
// http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
|
if (conditionalComment.test(html)) {
|
|
var conditionalEnd = html.indexOf(']>');
|
|
|
|
if (conditionalEnd >= 0) {
|
|
advance(conditionalEnd + 2);
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Doctype:
|
|
var doctypeMatch = html.match(doctype);
|
|
if (doctypeMatch) {
|
|
advance(doctypeMatch[0].length);
|
|
continue
|
|
}
|
|
|
|
// End tag:
|
|
var endTagMatch = html.match(endTag);
|
|
if (endTagMatch) {
|
|
var curIndex = index;
|
|
advance(endTagMatch[0].length);
|
|
parseEndTag(endTagMatch[1], curIndex, index);
|
|
continue
|
|
}
|
|
|
|
// Start tag:
|
|
var startTagMatch = parseStartTag();
|
|
if (startTagMatch) {
|
|
handleStartTag(startTagMatch);
|
|
continue
|
|
}
|
|
}
|
|
|
|
var text = (void 0), rest$1 = (void 0), next = (void 0);
|
|
if (textEnd >= 0) {
|
|
rest$1 = html.slice(textEnd);
|
|
while (
|
|
!endTag.test(rest$1) &&
|
|
!startTagOpen.test(rest$1) &&
|
|
!comment.test(rest$1) &&
|
|
!conditionalComment.test(rest$1)
|
|
) {
|
|
// < in plain text, be forgiving and treat it as text
|
|
next = rest$1.indexOf('<', 1);
|
|
if (next < 0) { break }
|
|
textEnd += next;
|
|
rest$1 = html.slice(textEnd);
|
|
}
|
|
text = html.substring(0, textEnd);
|
|
advance(textEnd);
|
|
}
|
|
|
|
if (textEnd < 0) {
|
|
text = html;
|
|
html = '';
|
|
}
|
|
|
|
if (options.chars && text) {
|
|
options.chars(text);
|
|
}
|
|
} else {
|
|
var stackedTag = lastTag.toLowerCase();
|
|
var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'));
|
|
var endTagLength = 0;
|
|
var rest = html.replace(reStackedTag, function (all, text, endTag) {
|
|
endTagLength = endTag.length;
|
|
if (stackedTag !== 'script' && stackedTag !== 'style' && stackedTag !== 'noscript') {
|
|
text = text
|
|
.replace(/<!--([\s\S]*?)-->/g, '$1')
|
|
.replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
|
|
}
|
|
if (options.chars) {
|
|
options.chars(text);
|
|
}
|
|
return ''
|
|
});
|
|
index += html.length - rest.length;
|
|
html = rest;
|
|
parseEndTag(stackedTag, index - endTagLength, index);
|
|
}
|
|
|
|
if (html === last) {
|
|
options.chars && options.chars(html);
|
|
if ("development" !== 'production' && !stack.length && options.warn) {
|
|
options.warn(("Mal-formatted tag at end of template: \"" + html + "\""));
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
// Clean up any remaining tags
|
|
parseEndTag();
|
|
|
|
function advance (n) {
|
|
index += n;
|
|
html = html.substring(n);
|
|
}
|
|
|
|
function parseStartTag () {
|
|
var start = html.match(startTagOpen);
|
|
if (start) {
|
|
var match = {
|
|
tagName: start[1],
|
|
attrs: [],
|
|
start: index
|
|
};
|
|
advance(start[0].length);
|
|
var end, attr;
|
|
while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
|
|
advance(attr[0].length);
|
|
match.attrs.push(attr);
|
|
}
|
|
if (end) {
|
|
match.unarySlash = end[1];
|
|
advance(end[0].length);
|
|
match.end = index;
|
|
return match
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleStartTag (match) {
|
|
var tagName = match.tagName;
|
|
var unarySlash = match.unarySlash;
|
|
|
|
if (expectHTML) {
|
|
if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
|
|
parseEndTag(lastTag);
|
|
}
|
|
if (canBeLeftOpenTag(tagName) && lastTag === tagName) {
|
|
parseEndTag(tagName);
|
|
}
|
|
}
|
|
|
|
var unary = isUnaryTag$$1(tagName) || tagName === 'html' && lastTag === 'head' || !!unarySlash;
|
|
|
|
var l = match.attrs.length;
|
|
var attrs = new Array(l);
|
|
for (var i = 0; i < l; i++) {
|
|
var args = match.attrs[i];
|
|
// hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
|
|
if (IS_REGEX_CAPTURING_BROKEN && args[0].indexOf('""') === -1) {
|
|
if (args[3] === '') { delete args[3]; }
|
|
if (args[4] === '') { delete args[4]; }
|
|
if (args[5] === '') { delete args[5]; }
|
|
}
|
|
var value = args[3] || args[4] || args[5] || '';
|
|
attrs[i] = {
|
|
name: args[1],
|
|
value: decodeAttr(
|
|
value,
|
|
options.shouldDecodeNewlines
|
|
)
|
|
};
|
|
}
|
|
|
|
if (!unary) {
|
|
stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs });
|
|
lastTag = tagName;
|
|
}
|
|
|
|
if (options.start) {
|
|
options.start(tagName, attrs, unary, match.start, match.end);
|
|
}
|
|
}
|
|
|
|
function parseEndTag (tagName, start, end) {
|
|
var pos, lowerCasedTagName;
|
|
if (start == null) { start = index; }
|
|
if (end == null) { end = index; }
|
|
|
|
if (tagName) {
|
|
lowerCasedTagName = tagName.toLowerCase();
|
|
}
|
|
|
|
// Find the closest opened tag of the same type
|
|
if (tagName) {
|
|
for (pos = stack.length - 1; pos >= 0; pos--) {
|
|
if (stack[pos].lowerCasedTag === lowerCasedTagName) {
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
// If no tag name is provided, clean shop
|
|
pos = 0;
|
|
}
|
|
|
|
if (pos >= 0) {
|
|
// Close all the open elements, up the stack
|
|
for (var i = stack.length - 1; i >= pos; i--) {
|
|
if ("development" !== 'production' &&
|
|
(i > pos || !tagName) &&
|
|
options.warn) {
|
|
options.warn(
|
|
("tag <" + (stack[i].tag) + "> has no matching end tag.")
|
|
);
|
|
}
|
|
if (options.end) {
|
|
options.end(stack[i].tag, start, end);
|
|
}
|
|
}
|
|
|
|
// Remove the open elements from the stack
|
|
stack.length = pos;
|
|
lastTag = pos && stack[pos - 1].tag;
|
|
} else if (lowerCasedTagName === 'br') {
|
|
if (options.start) {
|
|
options.start(tagName, [], true, start, end);
|
|
}
|
|
} else if (lowerCasedTagName === 'p') {
|
|
if (options.start) {
|
|
options.start(tagName, [], false, start, end);
|
|
}
|
|
if (options.end) {
|
|
options.end(tagName, start, end);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var defaultTagRE = /\{\{((?:.|\n)+?)\}\}/g;
|
|
var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g;
|
|
|
|
var buildRegex = cached(function (delimiters) {
|
|
var open = delimiters[0].replace(regexEscapeRE, '\\$&');
|
|
var close = delimiters[1].replace(regexEscapeRE, '\\$&');
|
|
return new RegExp(open + '((?:.|\\n)+?)' + close, 'g')
|
|
});
|
|
|
|
function parseText (
|
|
text,
|
|
delimiters
|
|
) {
|
|
var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE;
|
|
if (!tagRE.test(text)) {
|
|
return
|
|
}
|
|
var tokens = [];
|
|
var lastIndex = tagRE.lastIndex = 0;
|
|
var match, index;
|
|
while ((match = tagRE.exec(text))) {
|
|
index = match.index;
|
|
// push text token
|
|
if (index > lastIndex) {
|
|
tokens.push(JSON.stringify(text.slice(lastIndex, index)));
|
|
}
|
|
// tag token
|
|
var exp = parseFilters(match[1].trim());
|
|
tokens.push(("_s(" + exp + ")"));
|
|
lastIndex = index + match[0].length;
|
|
}
|
|
if (lastIndex < text.length) {
|
|
tokens.push(JSON.stringify(text.slice(lastIndex)));
|
|
}
|
|
return tokens.join('+')
|
|
}
|
|
|
|
/* */
|
|
|
|
var dirRE = /^v-|^@|^:/;
|
|
var forAliasRE = /(.*?)\s+(?:in|of)\s+(.*)/;
|
|
var forIteratorRE = /\((\{[^}]*\}|[^,]*),([^,]*)(?:,([^,]*))?\)/;
|
|
var bindRE = /^:|^v-bind:/;
|
|
var onRE = /^@|^v-on:/;
|
|
var argRE = /:(.*)$/;
|
|
var modifierRE = /\.[^.]+/g;
|
|
|
|
var decodeHTMLCached = cached(decode);
|
|
|
|
// configurable state
|
|
var warn$2;
|
|
var platformGetTagNamespace;
|
|
var platformMustUseProp;
|
|
var platformIsPreTag;
|
|
var preTransforms;
|
|
var transforms;
|
|
var postTransforms;
|
|
var delimiters;
|
|
|
|
/**
|
|
* Convert HTML string to AST.
|
|
*/
|
|
function parse (
|
|
template,
|
|
options
|
|
) {
|
|
warn$2 = options.warn || baseWarn;
|
|
platformGetTagNamespace = options.getTagNamespace || no;
|
|
platformMustUseProp = options.mustUseProp || no;
|
|
platformIsPreTag = options.isPreTag || no;
|
|
preTransforms = pluckModuleFunction(options.modules, 'preTransformNode');
|
|
transforms = pluckModuleFunction(options.modules, 'transformNode');
|
|
postTransforms = pluckModuleFunction(options.modules, 'postTransformNode');
|
|
delimiters = options.delimiters;
|
|
|
|
var stack = [];
|
|
var preserveWhitespace = options.preserveWhitespace !== false;
|
|
var root;
|
|
var currentParent;
|
|
var inVPre = false;
|
|
var inPre = false;
|
|
var warned = false;
|
|
|
|
function endPre (element) {
|
|
// check pre state
|
|
if (element.pre) {
|
|
inVPre = false;
|
|
}
|
|
if (platformIsPreTag(element.tag)) {
|
|
inPre = false;
|
|
}
|
|
}
|
|
|
|
parseHTML(template, {
|
|
warn: warn$2,
|
|
expectHTML: options.expectHTML,
|
|
isUnaryTag: options.isUnaryTag,
|
|
shouldDecodeNewlines: options.shouldDecodeNewlines,
|
|
start: function start (tag, attrs, unary) {
|
|
// check namespace.
|
|
// inherit parent ns if there is one
|
|
var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);
|
|
|
|
// handle IE svg bug
|
|
/* istanbul ignore if */
|
|
if (isIE && ns === 'svg') {
|
|
attrs = guardIESVGBug(attrs);
|
|
}
|
|
|
|
var element = {
|
|
type: 1,
|
|
tag: tag,
|
|
attrsList: attrs,
|
|
attrsMap: makeAttrsMap(attrs),
|
|
parent: currentParent,
|
|
children: []
|
|
};
|
|
if (ns) {
|
|
element.ns = ns;
|
|
}
|
|
|
|
if (isForbiddenTag(element) && !isServerRendering()) {
|
|
element.forbidden = true;
|
|
"development" !== 'production' && warn$2(
|
|
'Templates should only be responsible for mapping the state to the ' +
|
|
'UI. Avoid placing tags with side-effects in your templates, such as ' +
|
|
"<" + tag + ">" + ', as they will not be parsed.'
|
|
);
|
|
}
|
|
|
|
// apply pre-transforms
|
|
for (var i = 0; i < preTransforms.length; i++) {
|
|
preTransforms[i](element, options);
|
|
}
|
|
|
|
if (!inVPre) {
|
|
processPre(element);
|
|
if (element.pre) {
|
|
inVPre = true;
|
|
}
|
|
}
|
|
if (platformIsPreTag(element.tag)) {
|
|
inPre = true;
|
|
}
|
|
if (inVPre) {
|
|
processRawAttrs(element);
|
|
} else {
|
|
processFor(element);
|
|
processIf(element);
|
|
processOnce(element);
|
|
processKey(element);
|
|
|
|
// determine whether this is a plain element after
|
|
// removing structural attributes
|
|
element.plain = !element.key && !attrs.length;
|
|
|
|
processRef(element);
|
|
processSlot(element);
|
|
processComponent(element);
|
|
for (var i$1 = 0; i$1 < transforms.length; i$1++) {
|
|
transforms[i$1](element, options);
|
|
}
|
|
processAttrs(element);
|
|
}
|
|
|
|
function checkRootConstraints (el) {
|
|
if ("development" !== 'production' && !warned) {
|
|
if (el.tag === 'slot' || el.tag === 'template') {
|
|
warned = true;
|
|
warn$2(
|
|
"Cannot use <" + (el.tag) + "> as component root element because it may " +
|
|
'contain multiple nodes.'
|
|
);
|
|
}
|
|
if (el.attrsMap.hasOwnProperty('v-for')) {
|
|
warned = true;
|
|
warn$2(
|
|
'Cannot use v-for on stateful component root element because ' +
|
|
'it renders multiple elements.'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// tree management
|
|
if (!root) {
|
|
root = element;
|
|
checkRootConstraints(root);
|
|
} else if (!stack.length) {
|
|
// allow root elements with v-if, v-else-if and v-else
|
|
if (root.if && (element.elseif || element.else)) {
|
|
checkRootConstraints(element);
|
|
addIfCondition(root, {
|
|
exp: element.elseif,
|
|
block: element
|
|
});
|
|
} else if ("development" !== 'production' && !warned) {
|
|
warned = true;
|
|
warn$2(
|
|
"Component template should contain exactly one root element. " +
|
|
"If you are using v-if on multiple elements, " +
|
|
"use v-else-if to chain them instead."
|
|
);
|
|
}
|
|
}
|
|
if (currentParent && !element.forbidden) {
|
|
if (element.elseif || element.else) {
|
|
processIfConditions(element, currentParent);
|
|
} else if (element.slotScope) { // scoped slot
|
|
currentParent.plain = false;
|
|
var name = element.slotTarget || '"default"';(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element;
|
|
} else {
|
|
currentParent.children.push(element);
|
|
element.parent = currentParent;
|
|
}
|
|
}
|
|
if (!unary) {
|
|
currentParent = element;
|
|
stack.push(element);
|
|
} else {
|
|
endPre(element);
|
|
}
|
|
// apply post-transforms
|
|
for (var i$2 = 0; i$2 < postTransforms.length; i$2++) {
|
|
postTransforms[i$2](element, options);
|
|
}
|
|
},
|
|
|
|
end: function end () {
|
|
// remove trailing whitespace
|
|
var element = stack[stack.length - 1];
|
|
var lastNode = element.children[element.children.length - 1];
|
|
if (lastNode && lastNode.type === 3 && lastNode.text === ' ' && !inPre) {
|
|
element.children.pop();
|
|
}
|
|
// pop stack
|
|
stack.length -= 1;
|
|
currentParent = stack[stack.length - 1];
|
|
endPre(element);
|
|
},
|
|
|
|
chars: function chars (text) {
|
|
if (!currentParent) {
|
|
if ("development" !== 'production' && !warned && text === template) {
|
|
warned = true;
|
|
warn$2(
|
|
'Component template requires a root element, rather than just text.'
|
|
);
|
|
}
|
|
return
|
|
}
|
|
// IE textarea placeholder bug
|
|
/* istanbul ignore if */
|
|
if (isIE &&
|
|
currentParent.tag === 'textarea' &&
|
|
currentParent.attrsMap.placeholder === text) {
|
|
return
|
|
}
|
|
var children = currentParent.children;
|
|
text = inPre || text.trim()
|
|
? decodeHTMLCached(text)
|
|
// only preserve whitespace if its not right after a starting tag
|
|
: preserveWhitespace && children.length ? ' ' : '';
|
|
if (text) {
|
|
var expression;
|
|
if (!inVPre && text !== ' ' && (expression = parseText(text, delimiters))) {
|
|
children.push({
|
|
type: 2,
|
|
expression: expression,
|
|
text: text
|
|
});
|
|
} else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') {
|
|
children.push({
|
|
type: 3,
|
|
text: text
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return root
|
|
}
|
|
|
|
function processPre (el) {
|
|
if (getAndRemoveAttr(el, 'v-pre') != null) {
|
|
el.pre = true;
|
|
}
|
|
}
|
|
|
|
function processRawAttrs (el) {
|
|
var l = el.attrsList.length;
|
|
if (l) {
|
|
var attrs = el.attrs = new Array(l);
|
|
for (var i = 0; i < l; i++) {
|
|
attrs[i] = {
|
|
name: el.attrsList[i].name,
|
|
value: JSON.stringify(el.attrsList[i].value)
|
|
};
|
|
}
|
|
} else if (!el.pre) {
|
|
// non root node in pre blocks with no attributes
|
|
el.plain = true;
|
|
}
|
|
}
|
|
|
|
function processKey (el) {
|
|
var exp = getBindingAttr(el, 'key');
|
|
if (exp) {
|
|
if ("development" !== 'production' && el.tag === 'template') {
|
|
warn$2("<template> cannot be keyed. Place the key on real elements instead.");
|
|
}
|
|
el.key = exp;
|
|
}
|
|
}
|
|
|
|
function processRef (el) {
|
|
var ref = getBindingAttr(el, 'ref');
|
|
if (ref) {
|
|
el.ref = ref;
|
|
el.refInFor = checkInFor(el);
|
|
}
|
|
}
|
|
|
|
function processFor (el) {
|
|
var exp;
|
|
if ((exp = getAndRemoveAttr(el, 'v-for'))) {
|
|
var inMatch = exp.match(forAliasRE);
|
|
if (!inMatch) {
|
|
"development" !== 'production' && warn$2(
|
|
("Invalid v-for expression: " + exp)
|
|
);
|
|
return
|
|
}
|
|
el.for = inMatch[2].trim();
|
|
var alias = inMatch[1].trim();
|
|
var iteratorMatch = alias.match(forIteratorRE);
|
|
if (iteratorMatch) {
|
|
el.alias = iteratorMatch[1].trim();
|
|
el.iterator1 = iteratorMatch[2].trim();
|
|
if (iteratorMatch[3]) {
|
|
el.iterator2 = iteratorMatch[3].trim();
|
|
}
|
|
} else {
|
|
el.alias = alias;
|
|
}
|
|
}
|
|
}
|
|
|
|
function processIf (el) {
|
|
var exp = getAndRemoveAttr(el, 'v-if');
|
|
if (exp) {
|
|
el.if = exp;
|
|
addIfCondition(el, {
|
|
exp: exp,
|
|
block: el
|
|
});
|
|
} else {
|
|
if (getAndRemoveAttr(el, 'v-else') != null) {
|
|
el.else = true;
|
|
}
|
|
var elseif = getAndRemoveAttr(el, 'v-else-if');
|
|
if (elseif) {
|
|
el.elseif = elseif;
|
|
}
|
|
}
|
|
}
|
|
|
|
function processIfConditions (el, parent) {
|
|
var prev = findPrevElement(parent.children);
|
|
if (prev && prev.if) {
|
|
addIfCondition(prev, {
|
|
exp: el.elseif,
|
|
block: el
|
|
});
|
|
} else {
|
|
warn$2(
|
|
"v-" + (el.elseif ? ('else-if="' + el.elseif + '"') : 'else') + " " +
|
|
"used on element <" + (el.tag) + "> without corresponding v-if."
|
|
);
|
|
}
|
|
}
|
|
|
|
function findPrevElement (children) {
|
|
var i = children.length;
|
|
while (i--) {
|
|
if (children[i].type === 1) {
|
|
return children[i]
|
|
} else {
|
|
if ("development" !== 'production' && children[i].text !== ' ') {
|
|
warn$2(
|
|
"text \"" + (children[i].text.trim()) + "\" between v-if and v-else(-if) " +
|
|
"will be ignored."
|
|
);
|
|
}
|
|
children.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
function addIfCondition (el, condition) {
|
|
if (!el.ifConditions) {
|
|
el.ifConditions = [];
|
|
}
|
|
el.ifConditions.push(condition);
|
|
}
|
|
|
|
function processOnce (el) {
|
|
var once$$1 = getAndRemoveAttr(el, 'v-once');
|
|
if (once$$1 != null) {
|
|
el.once = true;
|
|
}
|
|
}
|
|
|
|
function processSlot (el) {
|
|
if (el.tag === 'slot') {
|
|
el.slotName = getBindingAttr(el, 'name');
|
|
if ("development" !== 'production' && el.key) {
|
|
warn$2(
|
|
"`key` does not work on <slot> because slots are abstract outlets " +
|
|
"and can possibly expand into multiple elements. " +
|
|
"Use the key on a wrapping element instead."
|
|
);
|
|
}
|
|
} else {
|
|
var slotTarget = getBindingAttr(el, 'slot');
|
|
if (slotTarget) {
|
|
el.slotTarget = slotTarget === '""' ? '"default"' : slotTarget;
|
|
}
|
|
if (el.tag === 'template') {
|
|
el.slotScope = getAndRemoveAttr(el, 'scope');
|
|
}
|
|
}
|
|
}
|
|
|
|
function processComponent (el) {
|
|
var binding;
|
|
if ((binding = getBindingAttr(el, 'is'))) {
|
|
el.component = binding;
|
|
}
|
|
if (getAndRemoveAttr(el, 'inline-template') != null) {
|
|
el.inlineTemplate = true;
|
|
}
|
|
}
|
|
|
|
function processAttrs (el) {
|
|
var list = el.attrsList;
|
|
var i, l, name, rawName, value, arg, modifiers, isProp;
|
|
for (i = 0, l = list.length; i < l; i++) {
|
|
name = rawName = list[i].name;
|
|
value = list[i].value;
|
|
if (dirRE.test(name)) {
|
|
// mark element as dynamic
|
|
el.hasBindings = true;
|
|
// modifiers
|
|
modifiers = parseModifiers(name);
|
|
if (modifiers) {
|
|
name = name.replace(modifierRE, '');
|
|
}
|
|
if (bindRE.test(name)) { // v-bind
|
|
name = name.replace(bindRE, '');
|
|
value = parseFilters(value);
|
|
isProp = false;
|
|
if (modifiers) {
|
|
if (modifiers.prop) {
|
|
isProp = true;
|
|
name = camelize(name);
|
|
if (name === 'innerHtml') { name = 'innerHTML'; }
|
|
}
|
|
if (modifiers.camel) {
|
|
name = camelize(name);
|
|
}
|
|
}
|
|
if (isProp || platformMustUseProp(el.tag, el.attrsMap.type, name)) {
|
|
addProp(el, name, value);
|
|
} else {
|
|
addAttr(el, name, value);
|
|
}
|
|
} else if (onRE.test(name)) { // v-on
|
|
name = name.replace(onRE, '');
|
|
addHandler(el, name, value, modifiers);
|
|
} else { // normal directives
|
|
name = name.replace(dirRE, '');
|
|
// parse arg
|
|
var argMatch = name.match(argRE);
|
|
if (argMatch && (arg = argMatch[1])) {
|
|
name = name.slice(0, -(arg.length + 1));
|
|
}
|
|
addDirective(el, name, rawName, value, arg, modifiers);
|
|
if ("development" !== 'production' && name === 'model') {
|
|
checkForAliasModel(el, value);
|
|
}
|
|
}
|
|
} else {
|
|
// literal attribute
|
|
{
|
|
var expression = parseText(value, delimiters);
|
|
if (expression) {
|
|
warn$2(
|
|
name + "=\"" + value + "\": " +
|
|
'Interpolation inside attributes has been removed. ' +
|
|
'Use v-bind or the colon shorthand instead. For example, ' +
|
|
'instead of <div id="{{ val }}">, use <div :id="val">.'
|
|
);
|
|
}
|
|
}
|
|
addAttr(el, name, JSON.stringify(value));
|
|
}
|
|
}
|
|
}
|
|
|
|
function checkInFor (el) {
|
|
var parent = el;
|
|
while (parent) {
|
|
if (parent.for !== undefined) {
|
|
return true
|
|
}
|
|
parent = parent.parent;
|
|
}
|
|
return false
|
|
}
|
|
|
|
function parseModifiers (name) {
|
|
var match = name.match(modifierRE);
|
|
if (match) {
|
|
var ret = {};
|
|
match.forEach(function (m) { ret[m.slice(1)] = true; });
|
|
return ret
|
|
}
|
|
}
|
|
|
|
function makeAttrsMap (attrs) {
|
|
var map = {};
|
|
for (var i = 0, l = attrs.length; i < l; i++) {
|
|
if ("development" !== 'production' && map[attrs[i].name] && !isIE) {
|
|
warn$2('duplicate attribute: ' + attrs[i].name);
|
|
}
|
|
map[attrs[i].name] = attrs[i].value;
|
|
}
|
|
return map
|
|
}
|
|
|
|
function isForbiddenTag (el) {
|
|
return (
|
|
el.tag === 'style' ||
|
|
(el.tag === 'script' && (
|
|
!el.attrsMap.type ||
|
|
el.attrsMap.type === 'text/javascript'
|
|
))
|
|
)
|
|
}
|
|
|
|
var ieNSBug = /^xmlns:NS\d+/;
|
|
var ieNSPrefix = /^NS\d+:/;
|
|
|
|
/* istanbul ignore next */
|
|
function guardIESVGBug (attrs) {
|
|
var res = [];
|
|
for (var i = 0; i < attrs.length; i++) {
|
|
var attr = attrs[i];
|
|
if (!ieNSBug.test(attr.name)) {
|
|
attr.name = attr.name.replace(ieNSPrefix, '');
|
|
res.push(attr);
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
function checkForAliasModel (el, value) {
|
|
var _el = el;
|
|
while (_el) {
|
|
if (_el.for && _el.alias === value) {
|
|
warn$2(
|
|
"<" + (el.tag) + " v-model=\"" + value + "\">: " +
|
|
"You are binding v-model directly to a v-for iteration alias. " +
|
|
"This will not be able to modify the v-for source array because " +
|
|
"writing to the alias is like modifying a function local variable. " +
|
|
"Consider using an array of objects and use v-model on an object property instead."
|
|
);
|
|
}
|
|
_el = _el.parent;
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
var isStaticKey;
|
|
var isPlatformReservedTag;
|
|
|
|
var genStaticKeysCached = cached(genStaticKeys$1);
|
|
|
|
/**
|
|
* Goal of the optimizer: walk the generated template AST tree
|
|
* and detect sub-trees that are purely static, i.e. parts of
|
|
* the DOM that never needs to change.
|
|
*
|
|
* Once we detect these sub-trees, we can:
|
|
*
|
|
* 1. Hoist them into constants, so that we no longer need to
|
|
* create fresh nodes for them on each re-render;
|
|
* 2. Completely skip them in the patching process.
|
|
*/
|
|
function optimize (root, options) {
|
|
if (!root) { return }
|
|
isStaticKey = genStaticKeysCached(options.staticKeys || '');
|
|
isPlatformReservedTag = options.isReservedTag || no;
|
|
// first pass: mark all non-static nodes.
|
|
markStatic$1(root);
|
|
// second pass: mark static roots.
|
|
markStaticRoots(root, false);
|
|
}
|
|
|
|
function genStaticKeys$1 (keys) {
|
|
return makeMap(
|
|
'type,tag,attrsList,attrsMap,plain,parent,children,attrs' +
|
|
(keys ? ',' + keys : '')
|
|
)
|
|
}
|
|
|
|
function markStatic$1 (node) {
|
|
node.static = isStatic(node);
|
|
if (node.type === 1) {
|
|
// do not make component slot content static. this avoids
|
|
// 1. components not able to mutate slot nodes
|
|
// 2. static slot content fails for hot-reloading
|
|
if (
|
|
!isPlatformReservedTag(node.tag) &&
|
|
node.tag !== 'slot' &&
|
|
node.attrsMap['inline-template'] == null
|
|
) {
|
|
return
|
|
}
|
|
for (var i = 0, l = node.children.length; i < l; i++) {
|
|
var child = node.children[i];
|
|
markStatic$1(child);
|
|
if (!child.static) {
|
|
node.static = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function markStaticRoots (node, isInFor) {
|
|
if (node.type === 1) {
|
|
if (node.static || node.once) {
|
|
node.staticInFor = isInFor;
|
|
}
|
|
// For a node to qualify as a static root, it should have children that
|
|
// are not just static text. Otherwise the cost of hoisting out will
|
|
// outweigh the benefits and it's better off to just always render it fresh.
|
|
if (node.static && node.children.length && !(
|
|
node.children.length === 1 &&
|
|
node.children[0].type === 3
|
|
)) {
|
|
node.staticRoot = true;
|
|
return
|
|
} else {
|
|
node.staticRoot = false;
|
|
}
|
|
if (node.children) {
|
|
for (var i = 0, l = node.children.length; i < l; i++) {
|
|
markStaticRoots(node.children[i], isInFor || !!node.for);
|
|
}
|
|
}
|
|
if (node.ifConditions) {
|
|
walkThroughConditionsBlocks(node.ifConditions, isInFor);
|
|
}
|
|
}
|
|
}
|
|
|
|
function walkThroughConditionsBlocks (conditionBlocks, isInFor) {
|
|
for (var i = 1, len = conditionBlocks.length; i < len; i++) {
|
|
markStaticRoots(conditionBlocks[i].block, isInFor);
|
|
}
|
|
}
|
|
|
|
function isStatic (node) {
|
|
if (node.type === 2) { // expression
|
|
return false
|
|
}
|
|
if (node.type === 3) { // text
|
|
return true
|
|
}
|
|
return !!(node.pre || (
|
|
!node.hasBindings && // no dynamic bindings
|
|
!node.if && !node.for && // not v-if or v-for or v-else
|
|
!isBuiltInTag(node.tag) && // not a built-in
|
|
isPlatformReservedTag(node.tag) && // not a component
|
|
!isDirectChildOfTemplateFor(node) &&
|
|
Object.keys(node).every(isStaticKey)
|
|
))
|
|
}
|
|
|
|
function isDirectChildOfTemplateFor (node) {
|
|
while (node.parent) {
|
|
node = node.parent;
|
|
if (node.tag !== 'template') {
|
|
return false
|
|
}
|
|
if (node.for) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
/* */
|
|
|
|
var fnExpRE = /^\s*([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/;
|
|
var simplePathRE = /^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?']|\[".*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*\s*$/;
|
|
|
|
// keyCode aliases
|
|
var keyCodes = {
|
|
esc: 27,
|
|
tab: 9,
|
|
enter: 13,
|
|
space: 32,
|
|
up: 38,
|
|
left: 37,
|
|
right: 39,
|
|
down: 40,
|
|
'delete': [8, 46]
|
|
};
|
|
|
|
// #4868: modifiers that prevent the execution of the listener
|
|
// need to explicitly return null so that we can determine whether to remove
|
|
// the listener for .once
|
|
var genGuard = function (condition) { return ("if(" + condition + ")return null;"); };
|
|
|
|
var modifierCode = {
|
|
stop: '$event.stopPropagation();',
|
|
prevent: '$event.preventDefault();',
|
|
self: genGuard("$event.target !== $event.currentTarget"),
|
|
ctrl: genGuard("!$event.ctrlKey"),
|
|
shift: genGuard("!$event.shiftKey"),
|
|
alt: genGuard("!$event.altKey"),
|
|
meta: genGuard("!$event.metaKey"),
|
|
left: genGuard("$event.button !== 0"),
|
|
middle: genGuard("$event.button !== 1"),
|
|
right: genGuard("$event.button !== 2")
|
|
};
|
|
|
|
function genHandlers (events, native) {
|
|
var res = native ? 'nativeOn:{' : 'on:{';
|
|
for (var name in events) {
|
|
res += "\"" + name + "\":" + (genHandler(name, events[name])) + ",";
|
|
}
|
|
return res.slice(0, -1) + '}'
|
|
}
|
|
|
|
function genHandler (
|
|
name,
|
|
handler
|
|
) {
|
|
if (!handler) {
|
|
return 'function(){}'
|
|
} else if (Array.isArray(handler)) {
|
|
return ("[" + (handler.map(function (handler) { return genHandler(name, handler); }).join(',')) + "]")
|
|
} else if (!handler.modifiers) {
|
|
return fnExpRE.test(handler.value) || simplePathRE.test(handler.value)
|
|
? handler.value
|
|
: ("function($event){" + (handler.value) + "}")
|
|
} else {
|
|
var code = '';
|
|
var keys = [];
|
|
for (var key in handler.modifiers) {
|
|
if (modifierCode[key]) {
|
|
code += modifierCode[key];
|
|
} else {
|
|
keys.push(key);
|
|
}
|
|
}
|
|
if (keys.length) {
|
|
code = genKeyFilter(keys) + code;
|
|
}
|
|
var handlerCode = simplePathRE.test(handler.value)
|
|
? handler.value + '($event)'
|
|
: handler.value;
|
|
return ("function($event){" + code + handlerCode + "}")
|
|
}
|
|
}
|
|
|
|
function genKeyFilter (keys) {
|
|
return ("if(" + (keys.map(genFilterCode).join('&&')) + ")return null;")
|
|
}
|
|
|
|
function genFilterCode (key) {
|
|
var keyVal = parseInt(key, 10);
|
|
if (keyVal) {
|
|
return ("$event.keyCode!==" + keyVal)
|
|
}
|
|
var alias = keyCodes[key];
|
|
return ("_k($event.keyCode," + (JSON.stringify(key)) + (alias ? ',' + JSON.stringify(alias) : '') + ")")
|
|
}
|
|
|
|
/* */
|
|
|
|
function bind$1 (el, dir) {
|
|
el.wrapData = function (code) {
|
|
return ("_b(" + code + ",'" + (el.tag) + "'," + (dir.value) + (dir.modifiers && dir.modifiers.prop ? ',true' : '') + ")")
|
|
};
|
|
}
|
|
|
|
/* */
|
|
|
|
var baseDirectives = {
|
|
bind: bind$1,
|
|
cloak: noop
|
|
};
|
|
|
|
/* */
|
|
|
|
// configurable state
|
|
var warn$3;
|
|
var transforms$1;
|
|
var dataGenFns;
|
|
var platformDirectives$1;
|
|
var isPlatformReservedTag$1;
|
|
var staticRenderFns;
|
|
var onceCount;
|
|
var currentOptions;
|
|
|
|
function generate (
|
|
ast,
|
|
options
|
|
) {
|
|
// save previous staticRenderFns so generate calls can be nested
|
|
var prevStaticRenderFns = staticRenderFns;
|
|
var currentStaticRenderFns = staticRenderFns = [];
|
|
var prevOnceCount = onceCount;
|
|
onceCount = 0;
|
|
currentOptions = options;
|
|
warn$3 = options.warn || baseWarn;
|
|
transforms$1 = pluckModuleFunction(options.modules, 'transformCode');
|
|
dataGenFns = pluckModuleFunction(options.modules, 'genData');
|
|
platformDirectives$1 = options.directives || {};
|
|
isPlatformReservedTag$1 = options.isReservedTag || no;
|
|
var code = ast ? genElement(ast) : '_c("div")';
|
|
staticRenderFns = prevStaticRenderFns;
|
|
onceCount = prevOnceCount;
|
|
return {
|
|
render: ("with(this){return " + code + "}"),
|
|
staticRenderFns: currentStaticRenderFns
|
|
}
|
|
}
|
|
|
|
function genElement (el) {
|
|
if (el.staticRoot && !el.staticProcessed) {
|
|
return genStatic(el)
|
|
} else if (el.once && !el.onceProcessed) {
|
|
return genOnce(el)
|
|
} else if (el.for && !el.forProcessed) {
|
|
return genFor(el)
|
|
} else if (el.if && !el.ifProcessed) {
|
|
return genIf(el)
|
|
} else if (el.tag === 'template' && !el.slotTarget) {
|
|
return genChildren(el) || 'void 0'
|
|
} else if (el.tag === 'slot') {
|
|
return genSlot(el)
|
|
} else {
|
|
// component or element
|
|
var code;
|
|
if (el.component) {
|
|
code = genComponent(el.component, el);
|
|
} else {
|
|
var data = el.plain ? undefined : genData(el);
|
|
|
|
var children = el.inlineTemplate ? null : genChildren(el, true);
|
|
code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";
|
|
}
|
|
// module transforms
|
|
for (var i = 0; i < transforms$1.length; i++) {
|
|
code = transforms$1[i](el, code);
|
|
}
|
|
return code
|
|
}
|
|
}
|
|
|
|
// hoist static sub-trees out
|
|
function genStatic (el) {
|
|
el.staticProcessed = true;
|
|
staticRenderFns.push(("with(this){return " + (genElement(el)) + "}"));
|
|
return ("_m(" + (staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")")
|
|
}
|
|
|
|
// v-once
|
|
function genOnce (el) {
|
|
el.onceProcessed = true;
|
|
if (el.if && !el.ifProcessed) {
|
|
return genIf(el)
|
|
} else if (el.staticInFor) {
|
|
var key = '';
|
|
var parent = el.parent;
|
|
while (parent) {
|
|
if (parent.for) {
|
|
key = parent.key;
|
|
break
|
|
}
|
|
parent = parent.parent;
|
|
}
|
|
if (!key) {
|
|
"development" !== 'production' && warn$3(
|
|
"v-once can only be used inside v-for that is keyed. "
|
|
);
|
|
return genElement(el)
|
|
}
|
|
return ("_o(" + (genElement(el)) + "," + (onceCount++) + (key ? ("," + key) : "") + ")")
|
|
} else {
|
|
return genStatic(el)
|
|
}
|
|
}
|
|
|
|
function genIf (el) {
|
|
el.ifProcessed = true; // avoid recursion
|
|
return genIfConditions(el.ifConditions.slice())
|
|
}
|
|
|
|
function genIfConditions (conditions) {
|
|
if (!conditions.length) {
|
|
return '_e()'
|
|
}
|
|
|
|
var condition = conditions.shift();
|
|
if (condition.exp) {
|
|
return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions)))
|
|
} else {
|
|
return ("" + (genTernaryExp(condition.block)))
|
|
}
|
|
|
|
// v-if with v-once should generate code like (a)?_m(0):_m(1)
|
|
function genTernaryExp (el) {
|
|
return el.once ? genOnce(el) : genElement(el)
|
|
}
|
|
}
|
|
|
|
function genFor (el) {
|
|
var exp = el.for;
|
|
var alias = el.alias;
|
|
var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : '';
|
|
var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : '';
|
|
|
|
if (
|
|
"development" !== 'production' &&
|
|
maybeComponent(el) && el.tag !== 'slot' && el.tag !== 'template' && !el.key
|
|
) {
|
|
warn$3(
|
|
"<" + (el.tag) + " v-for=\"" + alias + " in " + exp + "\">: component lists rendered with " +
|
|
"v-for should have explicit keys. " +
|
|
"See https://vuejs.org/guide/list.html#key for more info.",
|
|
true /* tip */
|
|
);
|
|
}
|
|
|
|
el.forProcessed = true; // avoid recursion
|
|
return "_l((" + exp + ")," +
|
|
"function(" + alias + iterator1 + iterator2 + "){" +
|
|
"return " + (genElement(el)) +
|
|
'})'
|
|
}
|
|
|
|
function genData (el) {
|
|
var data = '{';
|
|
|
|
// directives first.
|
|
// directives may mutate the el's other properties before they are generated.
|
|
var dirs = genDirectives(el);
|
|
if (dirs) { data += dirs + ','; }
|
|
|
|
// key
|
|
if (el.key) {
|
|
data += "key:" + (el.key) + ",";
|
|
}
|
|
// ref
|
|
if (el.ref) {
|
|
data += "ref:" + (el.ref) + ",";
|
|
}
|
|
if (el.refInFor) {
|
|
data += "refInFor:true,";
|
|
}
|
|
// pre
|
|
if (el.pre) {
|
|
data += "pre:true,";
|
|
}
|
|
// record original tag name for components using "is" attribute
|
|
if (el.component) {
|
|
data += "tag:\"" + (el.tag) + "\",";
|
|
}
|
|
// module data generation functions
|
|
for (var i = 0; i < dataGenFns.length; i++) {
|
|
data += dataGenFns[i](el);
|
|
}
|
|
// attributes
|
|
if (el.attrs) {
|
|
data += "attrs:{" + (genProps(el.attrs)) + "},";
|
|
}
|
|
// DOM props
|
|
if (el.props) {
|
|
data += "domProps:{" + (genProps(el.props)) + "},";
|
|
}
|
|
// event handlers
|
|
if (el.events) {
|
|
data += (genHandlers(el.events)) + ",";
|
|
}
|
|
if (el.nativeEvents) {
|
|
data += (genHandlers(el.nativeEvents, true)) + ",";
|
|
}
|
|
// slot target
|
|
if (el.slotTarget) {
|
|
data += "slot:" + (el.slotTarget) + ",";
|
|
}
|
|
// scoped slots
|
|
if (el.scopedSlots) {
|
|
data += (genScopedSlots(el.scopedSlots)) + ",";
|
|
}
|
|
// component v-model
|
|
if (el.model) {
|
|
data += "model:{value:" + (el.model.value) + ",callback:" + (el.model.callback) + "},";
|
|
}
|
|
// inline-template
|
|
if (el.inlineTemplate) {
|
|
var inlineTemplate = genInlineTemplate(el);
|
|
if (inlineTemplate) {
|
|
data += inlineTemplate + ",";
|
|
}
|
|
}
|
|
data = data.replace(/,$/, '') + '}';
|
|
// v-bind data wrap
|
|
if (el.wrapData) {
|
|
data = el.wrapData(data);
|
|
}
|
|
return data
|
|
}
|
|
|
|
function genDirectives (el) {
|
|
var dirs = el.directives;
|
|
if (!dirs) { return }
|
|
var res = 'directives:[';
|
|
var hasRuntime = false;
|
|
var i, l, dir, needRuntime;
|
|
for (i = 0, l = dirs.length; i < l; i++) {
|
|
dir = dirs[i];
|
|
needRuntime = true;
|
|
var gen = platformDirectives$1[dir.name] || baseDirectives[dir.name];
|
|
if (gen) {
|
|
// compile-time directive that manipulates AST.
|
|
// returns true if it also needs a runtime counterpart.
|
|
needRuntime = !!gen(el, dir, warn$3);
|
|
}
|
|
if (needRuntime) {
|
|
hasRuntime = true;
|
|
res += "{name:\"" + (dir.name) + "\",rawName:\"" + (dir.rawName) + "\"" + (dir.value ? (",value:(" + (dir.value) + "),expression:" + (JSON.stringify(dir.value))) : '') + (dir.arg ? (",arg:\"" + (dir.arg) + "\"") : '') + (dir.modifiers ? (",modifiers:" + (JSON.stringify(dir.modifiers))) : '') + "},";
|
|
}
|
|
}
|
|
if (hasRuntime) {
|
|
return res.slice(0, -1) + ']'
|
|
}
|
|
}
|
|
|
|
function genInlineTemplate (el) {
|
|
var ast = el.children[0];
|
|
if ("development" !== 'production' && (
|
|
el.children.length > 1 || ast.type !== 1
|
|
)) {
|
|
warn$3('Inline-template components must have exactly one child element.');
|
|
}
|
|
if (ast.type === 1) {
|
|
var inlineRenderFns = generate(ast, currentOptions);
|
|
return ("inlineTemplate:{render:function(){" + (inlineRenderFns.render) + "},staticRenderFns:[" + (inlineRenderFns.staticRenderFns.map(function (code) { return ("function(){" + code + "}"); }).join(',')) + "]}")
|
|
}
|
|
}
|
|
|
|
function genScopedSlots (slots) {
|
|
return ("scopedSlots:_u([" + (Object.keys(slots).map(function (key) { return genScopedSlot(key, slots[key]); }).join(',')) + "])")
|
|
}
|
|
|
|
function genScopedSlot (key, el) {
|
|
return "[" + key + ",function(" + (String(el.attrsMap.scope)) + "){" +
|
|
"return " + (el.tag === 'template'
|
|
? genChildren(el) || 'void 0'
|
|
: genElement(el)) + "}]"
|
|
}
|
|
|
|
function genChildren (el, checkSkip) {
|
|
var children = el.children;
|
|
if (children.length) {
|
|
var el$1 = children[0];
|
|
// optimize single v-for
|
|
if (children.length === 1 &&
|
|
el$1.for &&
|
|
el$1.tag !== 'template' &&
|
|
el$1.tag !== 'slot') {
|
|
return genElement(el$1)
|
|
}
|
|
var normalizationType = getNormalizationType(children);
|
|
return ("[" + (children.map(genNode).join(',')) + "]" + (checkSkip
|
|
? normalizationType ? ("," + normalizationType) : ''
|
|
: ''))
|
|
}
|
|
}
|
|
|
|
// determine the normalization needed for the children array.
|
|
// 0: no normalization needed
|
|
// 1: simple normalization needed (possible 1-level deep nested array)
|
|
// 2: full normalization needed
|
|
function getNormalizationType (children) {
|
|
var res = 0;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var el = children[i];
|
|
if (el.type !== 1) {
|
|
continue
|
|
}
|
|
if (needsNormalization(el) ||
|
|
(el.ifConditions && el.ifConditions.some(function (c) { return needsNormalization(c.block); }))) {
|
|
res = 2;
|
|
break
|
|
}
|
|
if (maybeComponent(el) ||
|
|
(el.ifConditions && el.ifConditions.some(function (c) { return maybeComponent(c.block); }))) {
|
|
res = 1;
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
function needsNormalization (el) {
|
|
return el.for !== undefined || el.tag === 'template' || el.tag === 'slot'
|
|
}
|
|
|
|
function maybeComponent (el) {
|
|
return !isPlatformReservedTag$1(el.tag)
|
|
}
|
|
|
|
function genNode (node) {
|
|
if (node.type === 1) {
|
|
return genElement(node)
|
|
} else {
|
|
return genText(node)
|
|
}
|
|
}
|
|
|
|
function genText (text) {
|
|
return ("_v(" + (text.type === 2
|
|
? text.expression // no need for () because already wrapped in _s()
|
|
: transformSpecialNewlines(JSON.stringify(text.text))) + ")")
|
|
}
|
|
|
|
function genSlot (el) {
|
|
var slotName = el.slotName || '"default"';
|
|
var children = genChildren(el);
|
|
var res = "_t(" + slotName + (children ? ("," + children) : '');
|
|
var attrs = el.attrs && ("{" + (el.attrs.map(function (a) { return ((camelize(a.name)) + ":" + (a.value)); }).join(',')) + "}");
|
|
var bind$$1 = el.attrsMap['v-bind'];
|
|
if ((attrs || bind$$1) && !children) {
|
|
res += ",null";
|
|
}
|
|
if (attrs) {
|
|
res += "," + attrs;
|
|
}
|
|
if (bind$$1) {
|
|
res += (attrs ? '' : ',null') + "," + bind$$1;
|
|
}
|
|
return res + ')'
|
|
}
|
|
|
|
// componentName is el.component, take it as argument to shun flow's pessimistic refinement
|
|
function genComponent (componentName, el) {
|
|
var children = el.inlineTemplate ? null : genChildren(el, true);
|
|
return ("_c(" + componentName + "," + (genData(el)) + (children ? ("," + children) : '') + ")")
|
|
}
|
|
|
|
function genProps (props) {
|
|
var res = '';
|
|
for (var i = 0; i < props.length; i++) {
|
|
var prop = props[i];
|
|
res += "\"" + (prop.name) + "\":" + (transformSpecialNewlines(prop.value)) + ",";
|
|
}
|
|
return res.slice(0, -1)
|
|
}
|
|
|
|
// #3895, #4268
|
|
function transformSpecialNewlines (text) {
|
|
return text
|
|
.replace(/\u2028/g, '\\u2028')
|
|
.replace(/\u2029/g, '\\u2029')
|
|
}
|
|
|
|
/* */
|
|
|
|
// operators like typeof, instanceof and in are allowed
|
|
var prohibitedKeywordRE = new RegExp('\\b' + (
|
|
'do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +
|
|
'super,throw,while,yield,delete,export,import,return,switch,default,' +
|
|
'extends,finally,continue,debugger,function,arguments'
|
|
).split(',').join('\\b|\\b') + '\\b');
|
|
// check valid identifier for v-for
|
|
var identRE = /[A-Za-z_$][\w$]*/;
|
|
// strip strings in expressions
|
|
var stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;
|
|
|
|
// detect problematic expressions in a template
|
|
function detectErrors (ast) {
|
|
var errors = [];
|
|
if (ast) {
|
|
checkNode(ast, errors);
|
|
}
|
|
return errors
|
|
}
|
|
|
|
function checkNode (node, errors) {
|
|
if (node.type === 1) {
|
|
for (var name in node.attrsMap) {
|
|
if (dirRE.test(name)) {
|
|
var value = node.attrsMap[name];
|
|
if (value) {
|
|
if (name === 'v-for') {
|
|
checkFor(node, ("v-for=\"" + value + "\""), errors);
|
|
} else {
|
|
checkExpression(value, (name + "=\"" + value + "\""), errors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (node.children) {
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
checkNode(node.children[i], errors);
|
|
}
|
|
}
|
|
} else if (node.type === 2) {
|
|
checkExpression(node.expression, node.text, errors);
|
|
}
|
|
}
|
|
|
|
function checkFor (node, text, errors) {
|
|
checkExpression(node.for || '', text, errors);
|
|
checkIdentifier(node.alias, 'v-for alias', text, errors);
|
|
checkIdentifier(node.iterator1, 'v-for iterator', text, errors);
|
|
checkIdentifier(node.iterator2, 'v-for iterator', text, errors);
|
|
}
|
|
|
|
function checkIdentifier (ident, type, text, errors) {
|
|
if (typeof ident === 'string' && !identRE.test(ident)) {
|
|
errors.push(("invalid " + type + " \"" + ident + "\" in expression: " + (text.trim())));
|
|
}
|
|
}
|
|
|
|
function checkExpression (exp, text, errors) {
|
|
try {
|
|
new Function(("return " + exp));
|
|
} catch (e) {
|
|
var keywordMatch = exp.replace(stripStringRE, '').match(prohibitedKeywordRE);
|
|
if (keywordMatch) {
|
|
errors.push(
|
|
"avoid using JavaScript keyword as property name: " +
|
|
"\"" + (keywordMatch[0]) + "\" in expression " + (text.trim())
|
|
);
|
|
} else {
|
|
errors.push(("invalid expression: " + (text.trim())));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function baseCompile (
|
|
template,
|
|
options
|
|
) {
|
|
var ast = parse(template.trim(), options);
|
|
optimize(ast, options);
|
|
var code = generate(ast, options);
|
|
return {
|
|
ast: ast,
|
|
render: code.render,
|
|
staticRenderFns: code.staticRenderFns
|
|
}
|
|
}
|
|
|
|
function makeFunction (code, errors) {
|
|
try {
|
|
return new Function(code)
|
|
} catch (err) {
|
|
errors.push({ err: err, code: code });
|
|
return noop
|
|
}
|
|
}
|
|
|
|
function createCompiler (baseOptions) {
|
|
var functionCompileCache = Object.create(null);
|
|
|
|
function compile (
|
|
template,
|
|
options
|
|
) {
|
|
var finalOptions = Object.create(baseOptions);
|
|
var errors = [];
|
|
var tips = [];
|
|
finalOptions.warn = function (msg, tip$$1) {
|
|
(tip$$1 ? tips : errors).push(msg);
|
|
};
|
|
|
|
if (options) {
|
|
// merge custom modules
|
|
if (options.modules) {
|
|
finalOptions.modules = (baseOptions.modules || []).concat(options.modules);
|
|
}
|
|
// merge custom directives
|
|
if (options.directives) {
|
|
finalOptions.directives = extend(
|
|
Object.create(baseOptions.directives),
|
|
options.directives
|
|
);
|
|
}
|
|
// copy other options
|
|
for (var key in options) {
|
|
if (key !== 'modules' && key !== 'directives') {
|
|
finalOptions[key] = options[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
var compiled = baseCompile(template, finalOptions);
|
|
{
|
|
errors.push.apply(errors, detectErrors(compiled.ast));
|
|
}
|
|
compiled.errors = errors;
|
|
compiled.tips = tips;
|
|
return compiled
|
|
}
|
|
|
|
function compileToFunctions (
|
|
template,
|
|
options,
|
|
vm
|
|
) {
|
|
options = options || {};
|
|
|
|
/* istanbul ignore if */
|
|
{
|
|
// detect possible CSP restriction
|
|
try {
|
|
new Function('return 1');
|
|
} catch (e) {
|
|
if (e.toString().match(/unsafe-eval|CSP/)) {
|
|
warn(
|
|
'It seems you are using the standalone build of Vue.js in an ' +
|
|
'environment with Content Security Policy that prohibits unsafe-eval. ' +
|
|
'The template compiler cannot work in this environment. Consider ' +
|
|
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
|
|
'templates into render functions.'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// check cache
|
|
var key = options.delimiters
|
|
? String(options.delimiters) + template
|
|
: template;
|
|
if (functionCompileCache[key]) {
|
|
return functionCompileCache[key]
|
|
}
|
|
|
|
// compile
|
|
var compiled = compile(template, options);
|
|
|
|
// check compilation errors/tips
|
|
{
|
|
if (compiled.errors && compiled.errors.length) {
|
|
warn(
|
|
"Error compiling template:\n\n" + template + "\n\n" +
|
|
compiled.errors.map(function (e) { return ("- " + e); }).join('\n') + '\n',
|
|
vm
|
|
);
|
|
}
|
|
if (compiled.tips && compiled.tips.length) {
|
|
compiled.tips.forEach(function (msg) { return tip(msg, vm); });
|
|
}
|
|
}
|
|
|
|
// turn code into functions
|
|
var res = {};
|
|
var fnGenErrors = [];
|
|
res.render = makeFunction(compiled.render, fnGenErrors);
|
|
var l = compiled.staticRenderFns.length;
|
|
res.staticRenderFns = new Array(l);
|
|
for (var i = 0; i < l; i++) {
|
|
res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors);
|
|
}
|
|
|
|
// check function generation errors.
|
|
// this should only happen if there is a bug in the compiler itself.
|
|
// mostly for codegen development use
|
|
/* istanbul ignore if */
|
|
{
|
|
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
|
|
warn(
|
|
"Failed to generate render function:\n\n" +
|
|
fnGenErrors.map(function (ref) {
|
|
var err = ref.err;
|
|
var code = ref.code;
|
|
|
|
return ((err.toString()) + " in\n\n" + code + "\n");
|
|
}).join('\n'),
|
|
vm
|
|
);
|
|
}
|
|
}
|
|
|
|
return (functionCompileCache[key] = res)
|
|
}
|
|
|
|
return {
|
|
compile: compile,
|
|
compileToFunctions: compileToFunctions
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function transformNode (el, options) {
|
|
var warn = options.warn || baseWarn;
|
|
var staticClass = getAndRemoveAttr(el, 'class');
|
|
if ("development" !== 'production' && staticClass) {
|
|
var expression = parseText(staticClass, options.delimiters);
|
|
if (expression) {
|
|
warn(
|
|
"class=\"" + staticClass + "\": " +
|
|
'Interpolation inside attributes has been removed. ' +
|
|
'Use v-bind or the colon shorthand instead. For example, ' +
|
|
'instead of <div class="{{ val }}">, use <div :class="val">.'
|
|
);
|
|
}
|
|
}
|
|
if (staticClass) {
|
|
el.staticClass = JSON.stringify(staticClass);
|
|
}
|
|
var classBinding = getBindingAttr(el, 'class', false /* getStatic */);
|
|
if (classBinding) {
|
|
el.classBinding = classBinding;
|
|
}
|
|
}
|
|
|
|
function genData$1 (el) {
|
|
var data = '';
|
|
if (el.staticClass) {
|
|
data += "staticClass:" + (el.staticClass) + ",";
|
|
}
|
|
if (el.classBinding) {
|
|
data += "class:" + (el.classBinding) + ",";
|
|
}
|
|
return data
|
|
}
|
|
|
|
var klass$1 = {
|
|
staticKeys: ['staticClass'],
|
|
transformNode: transformNode,
|
|
genData: genData$1
|
|
};
|
|
|
|
/* */
|
|
|
|
function transformNode$1 (el, options) {
|
|
var warn = options.warn || baseWarn;
|
|
var staticStyle = getAndRemoveAttr(el, 'style');
|
|
if (staticStyle) {
|
|
/* istanbul ignore if */
|
|
{
|
|
var expression = parseText(staticStyle, options.delimiters);
|
|
if (expression) {
|
|
warn(
|
|
"style=\"" + staticStyle + "\": " +
|
|
'Interpolation inside attributes has been removed. ' +
|
|
'Use v-bind or the colon shorthand instead. For example, ' +
|
|
'instead of <div style="{{ val }}">, use <div :style="val">.'
|
|
);
|
|
}
|
|
}
|
|
el.staticStyle = JSON.stringify(parseStyleText(staticStyle));
|
|
}
|
|
|
|
var styleBinding = getBindingAttr(el, 'style', false /* getStatic */);
|
|
if (styleBinding) {
|
|
el.styleBinding = styleBinding;
|
|
}
|
|
}
|
|
|
|
function genData$2 (el) {
|
|
var data = '';
|
|
if (el.staticStyle) {
|
|
data += "staticStyle:" + (el.staticStyle) + ",";
|
|
}
|
|
if (el.styleBinding) {
|
|
data += "style:(" + (el.styleBinding) + "),";
|
|
}
|
|
return data
|
|
}
|
|
|
|
var style$1 = {
|
|
staticKeys: ['staticStyle'],
|
|
transformNode: transformNode$1,
|
|
genData: genData$2
|
|
};
|
|
|
|
var modules$1 = [
|
|
klass$1,
|
|
style$1
|
|
];
|
|
|
|
/* */
|
|
|
|
function text (el, dir) {
|
|
if (dir.value) {
|
|
addProp(el, 'textContent', ("_s(" + (dir.value) + ")"));
|
|
}
|
|
}
|
|
|
|
/* */
|
|
|
|
function html (el, dir) {
|
|
if (dir.value) {
|
|
addProp(el, 'innerHTML', ("_s(" + (dir.value) + ")"));
|
|
}
|
|
}
|
|
|
|
var directives$1 = {
|
|
model: model,
|
|
text: text,
|
|
html: html
|
|
};
|
|
|
|
/* */
|
|
|
|
var baseOptions = {
|
|
expectHTML: true,
|
|
modules: modules$1,
|
|
directives: directives$1,
|
|
isPreTag: isPreTag,
|
|
isUnaryTag: isUnaryTag,
|
|
mustUseProp: mustUseProp,
|
|
isReservedTag: isReservedTag,
|
|
getTagNamespace: getTagNamespace,
|
|
staticKeys: genStaticKeys(modules$1)
|
|
};
|
|
|
|
var ref$1 = createCompiler(baseOptions);
|
|
var compileToFunctions = ref$1.compileToFunctions;
|
|
|
|
/* */
|
|
|
|
var idToTemplate = cached(function (id) {
|
|
var el = query(id);
|
|
return el && el.innerHTML
|
|
});
|
|
|
|
var mount = Vue$3.prototype.$mount;
|
|
Vue$3.prototype.$mount = function (
|
|
el,
|
|
hydrating
|
|
) {
|
|
el = el && query(el);
|
|
|
|
/* istanbul ignore if */
|
|
if (el === document.body || el === document.documentElement) {
|
|
"development" !== 'production' && warn(
|
|
"Do not mount Vue to <html> or <body> - mount to normal elements instead."
|
|
);
|
|
return this
|
|
}
|
|
|
|
var options = this.$options;
|
|
// resolve template/el and convert to render function
|
|
if (!options.render) {
|
|
var template = options.template;
|
|
if (template) {
|
|
if (typeof template === 'string') {
|
|
if (template.charAt(0) === '#') {
|
|
template = idToTemplate(template);
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && !template) {
|
|
warn(
|
|
("Template element not found or is empty: " + (options.template)),
|
|
this
|
|
);
|
|
}
|
|
}
|
|
} else if (template.nodeType) {
|
|
template = template.innerHTML;
|
|
} else {
|
|
{
|
|
warn('invalid template option:' + template, this);
|
|
}
|
|
return this
|
|
}
|
|
} else if (el) {
|
|
template = getOuterHTML(el);
|
|
}
|
|
if (template) {
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && config.performance && perf) {
|
|
perf.mark('compile');
|
|
}
|
|
|
|
var ref = compileToFunctions(template, {
|
|
shouldDecodeNewlines: shouldDecodeNewlines,
|
|
delimiters: options.delimiters
|
|
}, this);
|
|
var render = ref.render;
|
|
var staticRenderFns = ref.staticRenderFns;
|
|
options.render = render;
|
|
options.staticRenderFns = staticRenderFns;
|
|
|
|
/* istanbul ignore if */
|
|
if ("development" !== 'production' && config.performance && perf) {
|
|
perf.mark('compile end');
|
|
perf.measure(((this._name) + " compile"), 'compile', 'compile end');
|
|
}
|
|
}
|
|
}
|
|
return mount.call(this, el, hydrating)
|
|
};
|
|
|
|
/**
|
|
* Get outerHTML of elements, taking care
|
|
* of SVG elements in IE as well.
|
|
*/
|
|
function getOuterHTML (el) {
|
|
if (el.outerHTML) {
|
|
return el.outerHTML
|
|
} else {
|
|
var container = document.createElement('div');
|
|
container.appendChild(el.cloneNode(true));
|
|
return container.innerHTML
|
|
}
|
|
}
|
|
|
|
Vue$3.compile = compileToFunctions;
|
|
|
|
return Vue$3;
|
|
|
|
})));
|
|
|
|
/*! tether 1.3.3 */
|
|
|
|
(function(root, factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(factory);
|
|
} else if (typeof exports === 'object') {
|
|
module.exports = factory(require, exports, module);
|
|
} else {
|
|
root.Tether = factory();
|
|
}
|
|
}(this, function(require, exports, module) {
|
|
|
|
'use strict';
|
|
|
|
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
|
|
|
var TetherBase = undefined;
|
|
if (typeof TetherBase === 'undefined') {
|
|
TetherBase = { modules: [] };
|
|
}
|
|
|
|
var zeroElement = null;
|
|
|
|
// Same as native getBoundingClientRect, except it takes into account parent <frame> offsets
|
|
// if the element lies within a nested document (<frame> or <iframe>-like).
|
|
function getActualBoundingClientRect(node) {
|
|
var boundingRect = node.getBoundingClientRect();
|
|
|
|
// The original object returned by getBoundingClientRect is immutable, so we clone it
|
|
// We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9
|
|
var rect = {};
|
|
for (var k in boundingRect) {
|
|
rect[k] = boundingRect[k];
|
|
}
|
|
|
|
if (node.ownerDocument !== document) {
|
|
var _frameElement = node.ownerDocument.defaultView.frameElement;
|
|
if (_frameElement) {
|
|
var frameRect = getActualBoundingClientRect(_frameElement);
|
|
rect.top += frameRect.top;
|
|
rect.bottom += frameRect.top;
|
|
rect.left += frameRect.left;
|
|
rect.right += frameRect.left;
|
|
}
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
function getScrollParents(el) {
|
|
// In firefox if the el is inside an iframe with display: none; window.getComputedStyle() will return null;
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=548397
|
|
var computedStyle = getComputedStyle(el) || {};
|
|
var position = computedStyle.position;
|
|
var parents = [];
|
|
|
|
if (position === 'fixed') {
|
|
return [el];
|
|
}
|
|
|
|
var parent = el;
|
|
while ((parent = parent.parentNode) && parent && parent.nodeType === 1) {
|
|
var style = undefined;
|
|
try {
|
|
style = getComputedStyle(parent);
|
|
} catch (err) {}
|
|
|
|
if (typeof style === 'undefined' || style === null) {
|
|
parents.push(parent);
|
|
return parents;
|
|
}
|
|
|
|
var _style = style;
|
|
var overflow = _style.overflow;
|
|
var overflowX = _style.overflowX;
|
|
var overflowY = _style.overflowY;
|
|
|
|
if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
|
|
if (position !== 'absolute' || ['relative', 'absolute', 'fixed'].indexOf(style.position) >= 0) {
|
|
parents.push(parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
parents.push(el.ownerDocument.body);
|
|
|
|
// If the node is within a frame, account for the parent window scroll
|
|
if (el.ownerDocument !== document) {
|
|
parents.push(el.ownerDocument.defaultView);
|
|
}
|
|
|
|
return parents;
|
|
}
|
|
|
|
var uniqueId = (function () {
|
|
var id = 0;
|
|
return function () {
|
|
return ++id;
|
|
};
|
|
})();
|
|
|
|
var zeroPosCache = {};
|
|
var getOrigin = function getOrigin() {
|
|
// getBoundingClientRect is unfortunately too accurate. It introduces a pixel or two of
|
|
// jitter as the user scrolls that messes with our ability to detect if two positions
|
|
// are equivilant or not. We place an element at the top left of the page that will
|
|
// get the same jitter, so we can cancel the two out.
|
|
var node = zeroElement;
|
|
if (!node) {
|
|
node = document.createElement('div');
|
|
node.setAttribute('data-tether-id', uniqueId());
|
|
extend(node.style, {
|
|
top: 0,
|
|
left: 0,
|
|
position: 'absolute'
|
|
});
|
|
|
|
document.body.appendChild(node);
|
|
|
|
zeroElement = node;
|
|
}
|
|
|
|
var id = node.getAttribute('data-tether-id');
|
|
if (typeof zeroPosCache[id] === 'undefined') {
|
|
zeroPosCache[id] = getActualBoundingClientRect(node);
|
|
|
|
// Clear the cache when this position call is done
|
|
defer(function () {
|
|
delete zeroPosCache[id];
|
|
});
|
|
}
|
|
|
|
return zeroPosCache[id];
|
|
};
|
|
|
|
function removeUtilElements() {
|
|
if (zeroElement) {
|
|
document.body.removeChild(zeroElement);
|
|
}
|
|
zeroElement = null;
|
|
};
|
|
|
|
function getBounds(el) {
|
|
var doc = undefined;
|
|
if (el === document) {
|
|
doc = document;
|
|
el = document.documentElement;
|
|
} else {
|
|
doc = el.ownerDocument;
|
|
}
|
|
|
|
var docEl = doc.documentElement;
|
|
|
|
var box = getActualBoundingClientRect(el);
|
|
|
|
var origin = getOrigin();
|
|
|
|
box.top -= origin.top;
|
|
box.left -= origin.left;
|
|
|
|
if (typeof box.width === 'undefined') {
|
|
box.width = document.body.scrollWidth - box.left - box.right;
|
|
}
|
|
if (typeof box.height === 'undefined') {
|
|
box.height = document.body.scrollHeight - box.top - box.bottom;
|
|
}
|
|
|
|
box.top = box.top - docEl.clientTop;
|
|
box.left = box.left - docEl.clientLeft;
|
|
box.right = doc.body.clientWidth - box.width - box.left;
|
|
box.bottom = doc.body.clientHeight - box.height - box.top;
|
|
|
|
return box;
|
|
}
|
|
|
|
function getOffsetParent(el) {
|
|
return el.offsetParent || document.documentElement;
|
|
}
|
|
|
|
function getScrollBarSize() {
|
|
var inner = document.createElement('div');
|
|
inner.style.width = '100%';
|
|
inner.style.height = '200px';
|
|
|
|
var outer = document.createElement('div');
|
|
extend(outer.style, {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
pointerEvents: 'none',
|
|
visibility: 'hidden',
|
|
width: '200px',
|
|
height: '150px',
|
|
overflow: 'hidden'
|
|
});
|
|
|
|
outer.appendChild(inner);
|
|
|
|
document.body.appendChild(outer);
|
|
|
|
var widthContained = inner.offsetWidth;
|
|
outer.style.overflow = 'scroll';
|
|
var widthScroll = inner.offsetWidth;
|
|
|
|
if (widthContained === widthScroll) {
|
|
widthScroll = outer.clientWidth;
|
|
}
|
|
|
|
document.body.removeChild(outer);
|
|
|
|
var width = widthContained - widthScroll;
|
|
|
|
return { width: width, height: width };
|
|
}
|
|
|
|
function extend() {
|
|
var out = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
|
|
|
var args = [];
|
|
|
|
Array.prototype.push.apply(args, arguments);
|
|
|
|
args.slice(1).forEach(function (obj) {
|
|
if (obj) {
|
|
for (var key in obj) {
|
|
if (({}).hasOwnProperty.call(obj, key)) {
|
|
out[key] = obj[key];
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return out;
|
|
}
|
|
|
|
function removeClass(el, name) {
|
|
if (typeof el.classList !== 'undefined') {
|
|
name.split(' ').forEach(function (cls) {
|
|
if (cls.trim()) {
|
|
el.classList.remove(cls);
|
|
}
|
|
});
|
|
} else {
|
|
var regex = new RegExp('(^| )' + name.split(' ').join('|') + '( |$)', 'gi');
|
|
var className = getClassName(el).replace(regex, ' ');
|
|
setClassName(el, className);
|
|
}
|
|
}
|
|
|
|
function addClass(el, name) {
|
|
if (typeof el.classList !== 'undefined') {
|
|
name.split(' ').forEach(function (cls) {
|
|
if (cls.trim()) {
|
|
el.classList.add(cls);
|
|
}
|
|
});
|
|
} else {
|
|
removeClass(el, name);
|
|
var cls = getClassName(el) + (' ' + name);
|
|
setClassName(el, cls);
|
|
}
|
|
}
|
|
|
|
function hasClass(el, name) {
|
|
if (typeof el.classList !== 'undefined') {
|
|
return el.classList.contains(name);
|
|
}
|
|
var className = getClassName(el);
|
|
return new RegExp('(^| )' + name + '( |$)', 'gi').test(className);
|
|
}
|
|
|
|
function getClassName(el) {
|
|
// Can't use just SVGAnimatedString here since nodes within a Frame in IE have
|
|
// completely separately SVGAnimatedString base classes
|
|
if (el.className instanceof el.ownerDocument.defaultView.SVGAnimatedString) {
|
|
return el.className.baseVal;
|
|
}
|
|
return el.className;
|
|
}
|
|
|
|
function setClassName(el, className) {
|
|
el.setAttribute('class', className);
|
|
}
|
|
|
|
function updateClasses(el, add, all) {
|
|
// Of the set of 'all' classes, we need the 'add' classes, and only the
|
|
// 'add' classes to be set.
|
|
all.forEach(function (cls) {
|
|
if (add.indexOf(cls) === -1 && hasClass(el, cls)) {
|
|
removeClass(el, cls);
|
|
}
|
|
});
|
|
|
|
add.forEach(function (cls) {
|
|
if (!hasClass(el, cls)) {
|
|
addClass(el, cls);
|
|
}
|
|
});
|
|
}
|
|
|
|
var deferred = [];
|
|
|
|
var defer = function defer(fn) {
|
|
deferred.push(fn);
|
|
};
|
|
|
|
var flush = function flush() {
|
|
var fn = undefined;
|
|
while (fn = deferred.pop()) {
|
|
fn();
|
|
}
|
|
};
|
|
|
|
var Evented = (function () {
|
|
function Evented() {
|
|
_classCallCheck(this, Evented);
|
|
}
|
|
|
|
_createClass(Evented, [{
|
|
key: 'on',
|
|
value: function on(event, handler, ctx) {
|
|
var once = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
|
|
|
|
if (typeof this.bindings === 'undefined') {
|
|
this.bindings = {};
|
|
}
|
|
if (typeof this.bindings[event] === 'undefined') {
|
|
this.bindings[event] = [];
|
|
}
|
|
this.bindings[event].push({ handler: handler, ctx: ctx, once: once });
|
|
}
|
|
}, {
|
|
key: 'once',
|
|
value: function once(event, handler, ctx) {
|
|
this.on(event, handler, ctx, true);
|
|
}
|
|
}, {
|
|
key: 'off',
|
|
value: function off(event, handler) {
|
|
if (typeof this.bindings === 'undefined' || typeof this.bindings[event] === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
if (typeof handler === 'undefined') {
|
|
delete this.bindings[event];
|
|
} else {
|
|
var i = 0;
|
|
while (i < this.bindings[event].length) {
|
|
if (this.bindings[event][i].handler === handler) {
|
|
this.bindings[event].splice(i, 1);
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'trigger',
|
|
value: function trigger(event) {
|
|
if (typeof this.bindings !== 'undefined' && this.bindings[event]) {
|
|
var i = 0;
|
|
|
|
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
args[_key - 1] = arguments[_key];
|
|
}
|
|
|
|
while (i < this.bindings[event].length) {
|
|
var _bindings$event$i = this.bindings[event][i];
|
|
var handler = _bindings$event$i.handler;
|
|
var ctx = _bindings$event$i.ctx;
|
|
var once = _bindings$event$i.once;
|
|
|
|
var context = ctx;
|
|
if (typeof context === 'undefined') {
|
|
context = this;
|
|
}
|
|
|
|
handler.apply(context, args);
|
|
|
|
if (once) {
|
|
this.bindings[event].splice(i, 1);
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return Evented;
|
|
})();
|
|
|
|
TetherBase.Utils = {
|
|
getActualBoundingClientRect: getActualBoundingClientRect,
|
|
getScrollParents: getScrollParents,
|
|
getBounds: getBounds,
|
|
getOffsetParent: getOffsetParent,
|
|
extend: extend,
|
|
addClass: addClass,
|
|
removeClass: removeClass,
|
|
hasClass: hasClass,
|
|
updateClasses: updateClasses,
|
|
defer: defer,
|
|
flush: flush,
|
|
uniqueId: uniqueId,
|
|
Evented: Evented,
|
|
getScrollBarSize: getScrollBarSize,
|
|
removeUtilElements: removeUtilElements
|
|
};
|
|
/* globals TetherBase, performance */
|
|
|
|
'use strict';
|
|
|
|
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
|
|
|
|
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
|
|
|
var _get = function get(_x6, _x7, _x8) { var _again = true; _function: while (_again) { var object = _x6, property = _x7, receiver = _x8; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x6 = parent; _x7 = property; _x8 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
if (typeof TetherBase === 'undefined') {
|
|
throw new Error('You must include the utils.js file before tether.js');
|
|
}
|
|
|
|
var _TetherBase$Utils = TetherBase.Utils;
|
|
var getScrollParents = _TetherBase$Utils.getScrollParents;
|
|
var getBounds = _TetherBase$Utils.getBounds;
|
|
var getOffsetParent = _TetherBase$Utils.getOffsetParent;
|
|
var extend = _TetherBase$Utils.extend;
|
|
var addClass = _TetherBase$Utils.addClass;
|
|
var removeClass = _TetherBase$Utils.removeClass;
|
|
var updateClasses = _TetherBase$Utils.updateClasses;
|
|
var defer = _TetherBase$Utils.defer;
|
|
var flush = _TetherBase$Utils.flush;
|
|
var getScrollBarSize = _TetherBase$Utils.getScrollBarSize;
|
|
var removeUtilElements = _TetherBase$Utils.removeUtilElements;
|
|
|
|
function within(a, b) {
|
|
var diff = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];
|
|
|
|
return a + diff >= b && b >= a - diff;
|
|
}
|
|
|
|
var transformKey = (function () {
|
|
if (typeof document === 'undefined') {
|
|
return '';
|
|
}
|
|
var el = document.createElement('div');
|
|
|
|
var transforms = ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform'];
|
|
for (var i = 0; i < transforms.length; ++i) {
|
|
var key = transforms[i];
|
|
if (el.style[key] !== undefined) {
|
|
return key;
|
|
}
|
|
}
|
|
})();
|
|
|
|
var tethers = [];
|
|
|
|
var position = function position() {
|
|
tethers.forEach(function (tether) {
|
|
tether.position(false);
|
|
});
|
|
flush();
|
|
};
|
|
|
|
function now() {
|
|
if (typeof performance !== 'undefined' && typeof performance.now !== 'undefined') {
|
|
return performance.now();
|
|
}
|
|
return +new Date();
|
|
}
|
|
|
|
(function () {
|
|
var lastCall = null;
|
|
var lastDuration = null;
|
|
var pendingTimeout = null;
|
|
|
|
var tick = function tick() {
|
|
if (typeof lastDuration !== 'undefined' && lastDuration > 16) {
|
|
// We voluntarily throttle ourselves if we can't manage 60fps
|
|
lastDuration = Math.min(lastDuration - 16, 250);
|
|
|
|
// Just in case this is the last event, remember to position just once more
|
|
pendingTimeout = setTimeout(tick, 250);
|
|
return;
|
|
}
|
|
|
|
if (typeof lastCall !== 'undefined' && now() - lastCall < 10) {
|
|
// Some browsers call events a little too frequently, refuse to run more than is reasonable
|
|
return;
|
|
}
|
|
|
|
if (pendingTimeout != null) {
|
|
clearTimeout(pendingTimeout);
|
|
pendingTimeout = null;
|
|
}
|
|
|
|
lastCall = now();
|
|
position();
|
|
lastDuration = now() - lastCall;
|
|
};
|
|
|
|
if (typeof window !== 'undefined' && typeof window.addEventListener !== 'undefined') {
|
|
['resize', 'scroll', 'touchmove'].forEach(function (event) {
|
|
window.addEventListener(event, tick);
|
|
});
|
|
}
|
|
})();
|
|
|
|
var MIRROR_LR = {
|
|
center: 'center',
|
|
left: 'right',
|
|
right: 'left'
|
|
};
|
|
|
|
var MIRROR_TB = {
|
|
middle: 'middle',
|
|
top: 'bottom',
|
|
bottom: 'top'
|
|
};
|
|
|
|
var OFFSET_MAP = {
|
|
top: 0,
|
|
left: 0,
|
|
middle: '50%',
|
|
center: '50%',
|
|
bottom: '100%',
|
|
right: '100%'
|
|
};
|
|
|
|
var autoToFixedAttachment = function autoToFixedAttachment(attachment, relativeToAttachment) {
|
|
var left = attachment.left;
|
|
var top = attachment.top;
|
|
|
|
if (left === 'auto') {
|
|
left = MIRROR_LR[relativeToAttachment.left];
|
|
}
|
|
|
|
if (top === 'auto') {
|
|
top = MIRROR_TB[relativeToAttachment.top];
|
|
}
|
|
|
|
return { left: left, top: top };
|
|
};
|
|
|
|
var attachmentToOffset = function attachmentToOffset(attachment) {
|
|
var left = attachment.left;
|
|
var top = attachment.top;
|
|
|
|
if (typeof OFFSET_MAP[attachment.left] !== 'undefined') {
|
|
left = OFFSET_MAP[attachment.left];
|
|
}
|
|
|
|
if (typeof OFFSET_MAP[attachment.top] !== 'undefined') {
|
|
top = OFFSET_MAP[attachment.top];
|
|
}
|
|
|
|
return { left: left, top: top };
|
|
};
|
|
|
|
function addOffset() {
|
|
var out = { top: 0, left: 0 };
|
|
|
|
for (var _len = arguments.length, offsets = Array(_len), _key = 0; _key < _len; _key++) {
|
|
offsets[_key] = arguments[_key];
|
|
}
|
|
|
|
offsets.forEach(function (_ref) {
|
|
var top = _ref.top;
|
|
var left = _ref.left;
|
|
|
|
if (typeof top === 'string') {
|
|
top = parseFloat(top, 10);
|
|
}
|
|
if (typeof left === 'string') {
|
|
left = parseFloat(left, 10);
|
|
}
|
|
|
|
out.top += top;
|
|
out.left += left;
|
|
});
|
|
|
|
return out;
|
|
}
|
|
|
|
function offsetToPx(offset, size) {
|
|
if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) {
|
|
offset.left = parseFloat(offset.left, 10) / 100 * size.width;
|
|
}
|
|
if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) {
|
|
offset.top = parseFloat(offset.top, 10) / 100 * size.height;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
var parseOffset = function parseOffset(value) {
|
|
var _value$split = value.split(' ');
|
|
|
|
var _value$split2 = _slicedToArray(_value$split, 2);
|
|
|
|
var top = _value$split2[0];
|
|
var left = _value$split2[1];
|
|
|
|
return { top: top, left: left };
|
|
};
|
|
var parseAttachment = parseOffset;
|
|
|
|
var TetherClass = (function (_Evented) {
|
|
_inherits(TetherClass, _Evented);
|
|
|
|
function TetherClass(options) {
|
|
var _this = this;
|
|
|
|
_classCallCheck(this, TetherClass);
|
|
|
|
_get(Object.getPrototypeOf(TetherClass.prototype), 'constructor', this).call(this);
|
|
this.position = this.position.bind(this);
|
|
|
|
tethers.push(this);
|
|
|
|
this.history = [];
|
|
|
|
this.setOptions(options, false);
|
|
|
|
TetherBase.modules.forEach(function (module) {
|
|
if (typeof module.initialize !== 'undefined') {
|
|
module.initialize.call(_this);
|
|
}
|
|
});
|
|
|
|
this.position();
|
|
}
|
|
|
|
_createClass(TetherClass, [{
|
|
key: 'getClass',
|
|
value: function getClass() {
|
|
var key = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
|
|
var classes = this.options.classes;
|
|
|
|
if (typeof classes !== 'undefined' && classes[key]) {
|
|
return this.options.classes[key];
|
|
} else if (this.options.classPrefix) {
|
|
return this.options.classPrefix + '-' + key;
|
|
} else {
|
|
return key;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'setOptions',
|
|
value: function setOptions(options) {
|
|
var _this2 = this;
|
|
|
|
var pos = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
|
|
|
|
var defaults = {
|
|
offset: '0 0',
|
|
targetOffset: '0 0',
|
|
targetAttachment: 'auto auto',
|
|
classPrefix: 'tether'
|
|
};
|
|
|
|
this.options = extend(defaults, options);
|
|
|
|
var _options = this.options;
|
|
var element = _options.element;
|
|
var target = _options.target;
|
|
var targetModifier = _options.targetModifier;
|
|
|
|
this.element = element;
|
|
this.target = target;
|
|
this.targetModifier = targetModifier;
|
|
|
|
if (this.target === 'viewport') {
|
|
this.target = document.body;
|
|
this.targetModifier = 'visible';
|
|
} else if (this.target === 'scroll-handle') {
|
|
this.target = document.body;
|
|
this.targetModifier = 'scroll-handle';
|
|
}
|
|
|
|
['element', 'target'].forEach(function (key) {
|
|
if (typeof _this2[key] === 'undefined') {
|
|
throw new Error('Tether Error: Both element and target must be defined');
|
|
}
|
|
|
|
if (typeof _this2[key].jquery !== 'undefined') {
|
|
_this2[key] = _this2[key][0];
|
|
} else if (typeof _this2[key] === 'string') {
|
|
_this2[key] = document.querySelector(_this2[key]);
|
|
}
|
|
});
|
|
|
|
addClass(this.element, this.getClass('element'));
|
|
if (!(this.options.addTargetClasses === false)) {
|
|
addClass(this.target, this.getClass('target'));
|
|
}
|
|
|
|
if (!this.options.attachment) {
|
|
throw new Error('Tether Error: You must provide an attachment');
|
|
}
|
|
|
|
this.targetAttachment = parseAttachment(this.options.targetAttachment);
|
|
this.attachment = parseAttachment(this.options.attachment);
|
|
this.offset = parseOffset(this.options.offset);
|
|
this.targetOffset = parseOffset(this.options.targetOffset);
|
|
|
|
if (typeof this.scrollParents !== 'undefined') {
|
|
this.disable();
|
|
}
|
|
|
|
if (this.targetModifier === 'scroll-handle') {
|
|
this.scrollParents = [this.target];
|
|
} else {
|
|
this.scrollParents = getScrollParents(this.target);
|
|
}
|
|
|
|
if (!(this.options.enabled === false)) {
|
|
this.enable(pos);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'getTargetBounds',
|
|
value: function getTargetBounds() {
|
|
if (typeof this.targetModifier !== 'undefined') {
|
|
if (this.targetModifier === 'visible') {
|
|
if (this.target === document.body) {
|
|
return { top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth };
|
|
} else {
|
|
var bounds = getBounds(this.target);
|
|
|
|
var out = {
|
|
height: bounds.height,
|
|
width: bounds.width,
|
|
top: bounds.top,
|
|
left: bounds.left
|
|
};
|
|
|
|
out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top));
|
|
out.height = Math.min(out.height, bounds.height - (bounds.top + bounds.height - (pageYOffset + innerHeight)));
|
|
out.height = Math.min(innerHeight, out.height);
|
|
out.height -= 2;
|
|
|
|
out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left));
|
|
out.width = Math.min(out.width, bounds.width - (bounds.left + bounds.width - (pageXOffset + innerWidth)));
|
|
out.width = Math.min(innerWidth, out.width);
|
|
out.width -= 2;
|
|
|
|
if (out.top < pageYOffset) {
|
|
out.top = pageYOffset;
|
|
}
|
|
if (out.left < pageXOffset) {
|
|
out.left = pageXOffset;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
} else if (this.targetModifier === 'scroll-handle') {
|
|
var bounds = undefined;
|
|
var target = this.target;
|
|
if (target === document.body) {
|
|
target = document.documentElement;
|
|
|
|
bounds = {
|
|
left: pageXOffset,
|
|
top: pageYOffset,
|
|
height: innerHeight,
|
|
width: innerWidth
|
|
};
|
|
} else {
|
|
bounds = getBounds(target);
|
|
}
|
|
|
|
var style = getComputedStyle(target);
|
|
|
|
var hasBottomScroll = target.scrollWidth > target.clientWidth || [style.overflow, style.overflowX].indexOf('scroll') >= 0 || this.target !== document.body;
|
|
|
|
var scrollBottom = 0;
|
|
if (hasBottomScroll) {
|
|
scrollBottom = 15;
|
|
}
|
|
|
|
var height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom;
|
|
|
|
var out = {
|
|
width: 15,
|
|
height: height * 0.975 * (height / target.scrollHeight),
|
|
left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15
|
|
};
|
|
|
|
var fitAdj = 0;
|
|
if (height < 408 && this.target === document.body) {
|
|
fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58;
|
|
}
|
|
|
|
if (this.target !== document.body) {
|
|
out.height = Math.max(out.height, 24);
|
|
}
|
|
|
|
var scrollPercentage = this.target.scrollTop / (target.scrollHeight - height);
|
|
out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth);
|
|
|
|
if (this.target === document.body) {
|
|
out.height = Math.max(out.height, 24);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
} else {
|
|
return getBounds(this.target);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'clearCache',
|
|
value: function clearCache() {
|
|
this._cache = {};
|
|
}
|
|
}, {
|
|
key: 'cache',
|
|
value: function cache(k, getter) {
|
|
// More than one module will often need the same DOM info, so
|
|
// we keep a cache which is cleared on each position call
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
if (typeof this._cache[k] === 'undefined') {
|
|
this._cache[k] = getter.call(this);
|
|
}
|
|
|
|
return this._cache[k];
|
|
}
|
|
}, {
|
|
key: 'enable',
|
|
value: function enable() {
|
|
var _this3 = this;
|
|
|
|
var pos = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
|
|
|
|
if (!(this.options.addTargetClasses === false)) {
|
|
addClass(this.target, this.getClass('enabled'));
|
|
}
|
|
addClass(this.element, this.getClass('enabled'));
|
|
this.enabled = true;
|
|
|
|
this.scrollParents.forEach(function (parent) {
|
|
if (parent !== _this3.target.ownerDocument) {
|
|
parent.addEventListener('scroll', _this3.position);
|
|
}
|
|
});
|
|
|
|
if (pos) {
|
|
this.position();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
var _this4 = this;
|
|
|
|
removeClass(this.target, this.getClass('enabled'));
|
|
removeClass(this.element, this.getClass('enabled'));
|
|
this.enabled = false;
|
|
|
|
if (typeof this.scrollParents !== 'undefined') {
|
|
this.scrollParents.forEach(function (parent) {
|
|
parent.removeEventListener('scroll', _this4.position);
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'destroy',
|
|
value: function destroy() {
|
|
var _this5 = this;
|
|
|
|
this.disable();
|
|
|
|
tethers.forEach(function (tether, i) {
|
|
if (tether === _this5) {
|
|
tethers.splice(i, 1);
|
|
}
|
|
});
|
|
|
|
// Remove any elements we were using for convenience from the DOM
|
|
if (tethers.length === 0) {
|
|
removeUtilElements();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'updateAttachClasses',
|
|
value: function updateAttachClasses(elementAttach, targetAttach) {
|
|
var _this6 = this;
|
|
|
|
elementAttach = elementAttach || this.attachment;
|
|
targetAttach = targetAttach || this.targetAttachment;
|
|
var sides = ['left', 'top', 'bottom', 'right', 'middle', 'center'];
|
|
|
|
if (typeof this._addAttachClasses !== 'undefined' && this._addAttachClasses.length) {
|
|
// updateAttachClasses can be called more than once in a position call, so
|
|
// we need to clean up after ourselves such that when the last defer gets
|
|
// ran it doesn't add any extra classes from previous calls.
|
|
this._addAttachClasses.splice(0, this._addAttachClasses.length);
|
|
}
|
|
|
|
if (typeof this._addAttachClasses === 'undefined') {
|
|
this._addAttachClasses = [];
|
|
}
|
|
var add = this._addAttachClasses;
|
|
|
|
if (elementAttach.top) {
|
|
add.push(this.getClass('element-attached') + '-' + elementAttach.top);
|
|
}
|
|
if (elementAttach.left) {
|
|
add.push(this.getClass('element-attached') + '-' + elementAttach.left);
|
|
}
|
|
if (targetAttach.top) {
|
|
add.push(this.getClass('target-attached') + '-' + targetAttach.top);
|
|
}
|
|
if (targetAttach.left) {
|
|
add.push(this.getClass('target-attached') + '-' + targetAttach.left);
|
|
}
|
|
|
|
var all = [];
|
|
sides.forEach(function (side) {
|
|
all.push(_this6.getClass('element-attached') + '-' + side);
|
|
all.push(_this6.getClass('target-attached') + '-' + side);
|
|
});
|
|
|
|
defer(function () {
|
|
if (!(typeof _this6._addAttachClasses !== 'undefined')) {
|
|
return;
|
|
}
|
|
|
|
updateClasses(_this6.element, _this6._addAttachClasses, all);
|
|
if (!(_this6.options.addTargetClasses === false)) {
|
|
updateClasses(_this6.target, _this6._addAttachClasses, all);
|
|
}
|
|
|
|
delete _this6._addAttachClasses;
|
|
});
|
|
}
|
|
}, {
|
|
key: 'position',
|
|
value: function position() {
|
|
var _this7 = this;
|
|
|
|
var flushChanges = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
|
|
|
|
// flushChanges commits the changes immediately, leave true unless you are positioning multiple
|
|
// tethers (in which case call Tether.Utils.flush yourself when you're done)
|
|
|
|
if (!this.enabled) {
|
|
return;
|
|
}
|
|
|
|
this.clearCache();
|
|
|
|
// Turn 'auto' attachments into the appropriate corner or edge
|
|
var targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment);
|
|
|
|
this.updateAttachClasses(this.attachment, targetAttachment);
|
|
|
|
var elementPos = this.cache('element-bounds', function () {
|
|
return getBounds(_this7.element);
|
|
});
|
|
|
|
var width = elementPos.width;
|
|
var height = elementPos.height;
|
|
|
|
if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
|
|
var _lastSize = this.lastSize;
|
|
|
|
// We cache the height and width to make it possible to position elements that are
|
|
// getting hidden.
|
|
width = _lastSize.width;
|
|
height = _lastSize.height;
|
|
} else {
|
|
this.lastSize = { width: width, height: height };
|
|
}
|
|
|
|
var targetPos = this.cache('target-bounds', function () {
|
|
return _this7.getTargetBounds();
|
|
});
|
|
var targetSize = targetPos;
|
|
|
|
// Get an actual px offset from the attachment
|
|
var offset = offsetToPx(attachmentToOffset(this.attachment), { width: width, height: height });
|
|
var targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize);
|
|
|
|
var manualOffset = offsetToPx(this.offset, { width: width, height: height });
|
|
var manualTargetOffset = offsetToPx(this.targetOffset, targetSize);
|
|
|
|
// Add the manually provided offset
|
|
offset = addOffset(offset, manualOffset);
|
|
targetOffset = addOffset(targetOffset, manualTargetOffset);
|
|
|
|
// It's now our goal to make (element position + offset) == (target position + target offset)
|
|
var left = targetPos.left + targetOffset.left - offset.left;
|
|
var top = targetPos.top + targetOffset.top - offset.top;
|
|
|
|
for (var i = 0; i < TetherBase.modules.length; ++i) {
|
|
var _module2 = TetherBase.modules[i];
|
|
var ret = _module2.position.call(this, {
|
|
left: left,
|
|
top: top,
|
|
targetAttachment: targetAttachment,
|
|
targetPos: targetPos,
|
|
elementPos: elementPos,
|
|
offset: offset,
|
|
targetOffset: targetOffset,
|
|
manualOffset: manualOffset,
|
|
manualTargetOffset: manualTargetOffset,
|
|
scrollbarSize: scrollbarSize,
|
|
attachment: this.attachment
|
|
});
|
|
|
|
if (ret === false) {
|
|
return false;
|
|
} else if (typeof ret === 'undefined' || typeof ret !== 'object') {
|
|
continue;
|
|
} else {
|
|
top = ret.top;
|
|
left = ret.left;
|
|
}
|
|
}
|
|
|
|
// We describe the position three different ways to give the optimizer
|
|
// a chance to decide the best possible way to position the element
|
|
// with the fewest repaints.
|
|
var next = {
|
|
// It's position relative to the page (absolute positioning when
|
|
// the element is a child of the body)
|
|
page: {
|
|
top: top,
|
|
left: left
|
|
},
|
|
|
|
// It's position relative to the viewport (fixed positioning)
|
|
viewport: {
|
|
top: top - pageYOffset,
|
|
bottom: pageYOffset - top - height + innerHeight,
|
|
left: left - pageXOffset,
|
|
right: pageXOffset - left - width + innerWidth
|
|
}
|
|
};
|
|
|
|
var doc = this.target.ownerDocument;
|
|
var win = doc.defaultView;
|
|
|
|
var scrollbarSize = undefined;
|
|
if (doc.body.scrollWidth > win.innerWidth) {
|
|
scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
|
|
next.viewport.bottom -= scrollbarSize.height;
|
|
}
|
|
|
|
if (doc.body.scrollHeight > win.innerHeight) {
|
|
scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
|
|
next.viewport.right -= scrollbarSize.width;
|
|
}
|
|
|
|
if (['', 'static'].indexOf(doc.body.style.position) === -1 || ['', 'static'].indexOf(doc.body.parentElement.style.position) === -1) {
|
|
// Absolute positioning in the body will be relative to the page, not the 'initial containing block'
|
|
next.page.bottom = doc.body.scrollHeight - top - height;
|
|
next.page.right = doc.body.scrollWidth - left - width;
|
|
}
|
|
|
|
if (typeof this.options.optimizations !== 'undefined' && this.options.optimizations.moveElement !== false && !(typeof this.targetModifier !== 'undefined')) {
|
|
(function () {
|
|
var offsetParent = _this7.cache('target-offsetparent', function () {
|
|
return getOffsetParent(_this7.target);
|
|
});
|
|
var offsetPosition = _this7.cache('target-offsetparent-bounds', function () {
|
|
return getBounds(offsetParent);
|
|
});
|
|
var offsetParentStyle = getComputedStyle(offsetParent);
|
|
var offsetParentSize = offsetPosition;
|
|
|
|
var offsetBorder = {};
|
|
['Top', 'Left', 'Bottom', 'Right'].forEach(function (side) {
|
|
offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle['border' + side + 'Width']);
|
|
});
|
|
|
|
offsetPosition.right = doc.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right;
|
|
offsetPosition.bottom = doc.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom;
|
|
|
|
if (next.page.top >= offsetPosition.top + offsetBorder.top && next.page.bottom >= offsetPosition.bottom) {
|
|
if (next.page.left >= offsetPosition.left + offsetBorder.left && next.page.right >= offsetPosition.right) {
|
|
// We're within the visible part of the target's scroll parent
|
|
var scrollTop = offsetParent.scrollTop;
|
|
var scrollLeft = offsetParent.scrollLeft;
|
|
|
|
// It's position relative to the target's offset parent (absolute positioning when
|
|
// the element is moved to be a child of the target's offset parent).
|
|
next.offset = {
|
|
top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top,
|
|
left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left
|
|
};
|
|
}
|
|
}
|
|
})();
|
|
}
|
|
|
|
// We could also travel up the DOM and try each containing context, rather than only
|
|
// looking at the body, but we're gonna get diminishing returns.
|
|
|
|
this.move(next);
|
|
|
|
this.history.unshift(next);
|
|
|
|
if (this.history.length > 3) {
|
|
this.history.pop();
|
|
}
|
|
|
|
if (flushChanges) {
|
|
flush();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// THE ISSUE
|
|
}, {
|
|
key: 'move',
|
|
value: function move(pos) {
|
|
var _this8 = this;
|
|
|
|
if (!(typeof this.element.parentNode !== 'undefined')) {
|
|
return;
|
|
}
|
|
|
|
var same = {};
|
|
|
|
for (var type in pos) {
|
|
same[type] = {};
|
|
|
|
for (var key in pos[type]) {
|
|
var found = false;
|
|
|
|
for (var i = 0; i < this.history.length; ++i) {
|
|
var point = this.history[i];
|
|
if (typeof point[type] !== 'undefined' && !within(point[type][key], pos[type][key])) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
same[type][key] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
var css = { top: '', left: '', right: '', bottom: '' };
|
|
|
|
var transcribe = function transcribe(_same, _pos) {
|
|
var hasOptimizations = typeof _this8.options.optimizations !== 'undefined';
|
|
var gpu = hasOptimizations ? _this8.options.optimizations.gpu : null;
|
|
if (gpu !== false) {
|
|
var yPos = undefined,
|
|
xPos = undefined;
|
|
if (_same.top) {
|
|
css.top = 0;
|
|
yPos = _pos.top;
|
|
} else {
|
|
css.bottom = 0;
|
|
yPos = -_pos.bottom;
|
|
}
|
|
|
|
if (_same.left) {
|
|
css.left = 0;
|
|
xPos = _pos.left;
|
|
} else {
|
|
css.right = 0;
|
|
xPos = -_pos.right;
|
|
}
|
|
|
|
css[transformKey] = 'translateX(' + Math.round(xPos) + 'px) translateY(' + Math.round(yPos) + 'px)';
|
|
|
|
if (transformKey !== 'msTransform') {
|
|
// The Z transform will keep this in the GPU (faster, and prevents artifacts),
|
|
// but IE9 doesn't support 3d transforms and will choke.
|
|
css[transformKey] += " translateZ(0)";
|
|
}
|
|
} else {
|
|
if (_same.top) {
|
|
css.top = _pos.top + 'px';
|
|
} else {
|
|
css.bottom = _pos.bottom + 'px';
|
|
}
|
|
|
|
if (_same.left) {
|
|
css.left = _pos.left + 'px';
|
|
} else {
|
|
css.right = _pos.right + 'px';
|
|
}
|
|
}
|
|
};
|
|
|
|
var moved = false;
|
|
if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) {
|
|
css.position = 'absolute';
|
|
transcribe(same.page, pos.page);
|
|
} else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) {
|
|
css.position = 'fixed';
|
|
transcribe(same.viewport, pos.viewport);
|
|
} else if (typeof same.offset !== 'undefined' && same.offset.top && same.offset.left) {
|
|
(function () {
|
|
css.position = 'absolute';
|
|
var offsetParent = _this8.cache('target-offsetparent', function () {
|
|
return getOffsetParent(_this8.target);
|
|
});
|
|
|
|
if (getOffsetParent(_this8.element) !== offsetParent) {
|
|
defer(function () {
|
|
_this8.element.parentNode.removeChild(_this8.element);
|
|
offsetParent.appendChild(_this8.element);
|
|
});
|
|
}
|
|
|
|
transcribe(same.offset, pos.offset);
|
|
moved = true;
|
|
})();
|
|
} else {
|
|
css.position = 'absolute';
|
|
transcribe({ top: true, left: true }, pos.page);
|
|
}
|
|
|
|
if (!moved) {
|
|
var offsetParentIsBody = true;
|
|
var currentNode = this.element.parentNode;
|
|
while (currentNode && currentNode.nodeType === 1 && currentNode.tagName !== 'BODY') {
|
|
if (getComputedStyle(currentNode).position !== 'static') {
|
|
offsetParentIsBody = false;
|
|
break;
|
|
}
|
|
|
|
currentNode = currentNode.parentNode;
|
|
}
|
|
|
|
if (!offsetParentIsBody) {
|
|
this.element.parentNode.removeChild(this.element);
|
|
this.element.ownerDocument.body.appendChild(this.element);
|
|
}
|
|
}
|
|
|
|
// Any css change will trigger a repaint, so let's avoid one if nothing changed
|
|
var writeCSS = {};
|
|
var write = false;
|
|
for (var key in css) {
|
|
var val = css[key];
|
|
var elVal = this.element.style[key];
|
|
|
|
if (elVal !== val) {
|
|
write = true;
|
|
writeCSS[key] = val;
|
|
}
|
|
}
|
|
|
|
if (write) {
|
|
defer(function () {
|
|
extend(_this8.element.style, writeCSS);
|
|
});
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return TetherClass;
|
|
})(Evented);
|
|
|
|
TetherClass.modules = [];
|
|
|
|
TetherBase.position = position;
|
|
|
|
var Tether = extend(TetherClass, TetherBase);
|
|
/* globals TetherBase */
|
|
|
|
'use strict';
|
|
|
|
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
|
|
|
|
var _TetherBase$Utils = TetherBase.Utils;
|
|
var getBounds = _TetherBase$Utils.getBounds;
|
|
var extend = _TetherBase$Utils.extend;
|
|
var updateClasses = _TetherBase$Utils.updateClasses;
|
|
var defer = _TetherBase$Utils.defer;
|
|
|
|
var BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom'];
|
|
|
|
function getBoundingRect(tether, to) {
|
|
if (to === 'scrollParent') {
|
|
to = tether.scrollParents[0];
|
|
} else if (to === 'window') {
|
|
to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset];
|
|
}
|
|
|
|
if (to === document) {
|
|
to = to.documentElement;
|
|
}
|
|
|
|
if (typeof to.nodeType !== 'undefined') {
|
|
(function () {
|
|
var node = to;
|
|
var size = getBounds(to);
|
|
var pos = size;
|
|
var style = getComputedStyle(to);
|
|
|
|
to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top];
|
|
|
|
// Account any parent Frames scroll offset
|
|
if (node.ownerDocument !== document) {
|
|
var win = node.ownerDocument.defaultView;
|
|
to[0] += win.pageXOffset;
|
|
to[1] += win.pageYOffset;
|
|
to[2] += win.pageXOffset;
|
|
to[3] += win.pageYOffset;
|
|
}
|
|
|
|
BOUNDS_FORMAT.forEach(function (side, i) {
|
|
side = side[0].toUpperCase() + side.substr(1);
|
|
if (side === 'Top' || side === 'Left') {
|
|
to[i] += parseFloat(style['border' + side + 'Width']);
|
|
} else {
|
|
to[i] -= parseFloat(style['border' + side + 'Width']);
|
|
}
|
|
});
|
|
})();
|
|
}
|
|
|
|
return to;
|
|
}
|
|
|
|
TetherBase.modules.push({
|
|
position: function position(_ref) {
|
|
var _this = this;
|
|
|
|
var top = _ref.top;
|
|
var left = _ref.left;
|
|
var targetAttachment = _ref.targetAttachment;
|
|
|
|
if (!this.options.constraints) {
|
|
return true;
|
|
}
|
|
|
|
var _cache = this.cache('element-bounds', function () {
|
|
return getBounds(_this.element);
|
|
});
|
|
|
|
var height = _cache.height;
|
|
var width = _cache.width;
|
|
|
|
if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
|
|
var _lastSize = this.lastSize;
|
|
|
|
// Handle the item getting hidden as a result of our positioning without glitching
|
|
// the classes in and out
|
|
width = _lastSize.width;
|
|
height = _lastSize.height;
|
|
}
|
|
|
|
var targetSize = this.cache('target-bounds', function () {
|
|
return _this.getTargetBounds();
|
|
});
|
|
|
|
var targetHeight = targetSize.height;
|
|
var targetWidth = targetSize.width;
|
|
|
|
var allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')];
|
|
|
|
this.options.constraints.forEach(function (constraint) {
|
|
var outOfBoundsClass = constraint.outOfBoundsClass;
|
|
var pinnedClass = constraint.pinnedClass;
|
|
|
|
if (outOfBoundsClass) {
|
|
allClasses.push(outOfBoundsClass);
|
|
}
|
|
if (pinnedClass) {
|
|
allClasses.push(pinnedClass);
|
|
}
|
|
});
|
|
|
|
allClasses.forEach(function (cls) {
|
|
['left', 'top', 'right', 'bottom'].forEach(function (side) {
|
|
allClasses.push(cls + '-' + side);
|
|
});
|
|
});
|
|
|
|
var addClasses = [];
|
|
|
|
var tAttachment = extend({}, targetAttachment);
|
|
var eAttachment = extend({}, this.attachment);
|
|
|
|
this.options.constraints.forEach(function (constraint) {
|
|
var to = constraint.to;
|
|
var attachment = constraint.attachment;
|
|
var pin = constraint.pin;
|
|
|
|
if (typeof attachment === 'undefined') {
|
|
attachment = '';
|
|
}
|
|
|
|
var changeAttachX = undefined,
|
|
changeAttachY = undefined;
|
|
if (attachment.indexOf(' ') >= 0) {
|
|
var _attachment$split = attachment.split(' ');
|
|
|
|
var _attachment$split2 = _slicedToArray(_attachment$split, 2);
|
|
|
|
changeAttachY = _attachment$split2[0];
|
|
changeAttachX = _attachment$split2[1];
|
|
} else {
|
|
changeAttachX = changeAttachY = attachment;
|
|
}
|
|
|
|
var bounds = getBoundingRect(_this, to);
|
|
|
|
if (changeAttachY === 'target' || changeAttachY === 'both') {
|
|
if (top < bounds[1] && tAttachment.top === 'top') {
|
|
top += targetHeight;
|
|
tAttachment.top = 'bottom';
|
|
}
|
|
|
|
if (top + height > bounds[3] && tAttachment.top === 'bottom') {
|
|
top -= targetHeight;
|
|
tAttachment.top = 'top';
|
|
}
|
|
}
|
|
|
|
if (changeAttachY === 'together') {
|
|
if (tAttachment.top === 'top') {
|
|
if (eAttachment.top === 'bottom' && top < bounds[1]) {
|
|
top += targetHeight;
|
|
tAttachment.top = 'bottom';
|
|
|
|
top += height;
|
|
eAttachment.top = 'top';
|
|
} else if (eAttachment.top === 'top' && top + height > bounds[3] && top - (height - targetHeight) >= bounds[1]) {
|
|
top -= height - targetHeight;
|
|
tAttachment.top = 'bottom';
|
|
|
|
eAttachment.top = 'bottom';
|
|
}
|
|
}
|
|
|
|
if (tAttachment.top === 'bottom') {
|
|
if (eAttachment.top === 'top' && top + height > bounds[3]) {
|
|
top -= targetHeight;
|
|
tAttachment.top = 'top';
|
|
|
|
top -= height;
|
|
eAttachment.top = 'bottom';
|
|
} else if (eAttachment.top === 'bottom' && top < bounds[1] && top + (height * 2 - targetHeight) <= bounds[3]) {
|
|
top += height - targetHeight;
|
|
tAttachment.top = 'top';
|
|
|
|
eAttachment.top = 'top';
|
|
}
|
|
}
|
|
|
|
if (tAttachment.top === 'middle') {
|
|
if (top + height > bounds[3] && eAttachment.top === 'top') {
|
|
top -= height;
|
|
eAttachment.top = 'bottom';
|
|
} else if (top < bounds[1] && eAttachment.top === 'bottom') {
|
|
top += height;
|
|
eAttachment.top = 'top';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (changeAttachX === 'target' || changeAttachX === 'both') {
|
|
if (left < bounds[0] && tAttachment.left === 'left') {
|
|
left += targetWidth;
|
|
tAttachment.left = 'right';
|
|
}
|
|
|
|
if (left + width > bounds[2] && tAttachment.left === 'right') {
|
|
left -= targetWidth;
|
|
tAttachment.left = 'left';
|
|
}
|
|
}
|
|
|
|
if (changeAttachX === 'together') {
|
|
if (left < bounds[0] && tAttachment.left === 'left') {
|
|
if (eAttachment.left === 'right') {
|
|
left += targetWidth;
|
|
tAttachment.left = 'right';
|
|
|
|
left += width;
|
|
eAttachment.left = 'left';
|
|
} else if (eAttachment.left === 'left') {
|
|
left += targetWidth;
|
|
tAttachment.left = 'right';
|
|
|
|
left -= width;
|
|
eAttachment.left = 'right';
|
|
}
|
|
} else if (left + width > bounds[2] && tAttachment.left === 'right') {
|
|
if (eAttachment.left === 'left') {
|
|
left -= targetWidth;
|
|
tAttachment.left = 'left';
|
|
|
|
left -= width;
|
|
eAttachment.left = 'right';
|
|
} else if (eAttachment.left === 'right') {
|
|
left -= targetWidth;
|
|
tAttachment.left = 'left';
|
|
|
|
left += width;
|
|
eAttachment.left = 'left';
|
|
}
|
|
} else if (tAttachment.left === 'center') {
|
|
if (left + width > bounds[2] && eAttachment.left === 'left') {
|
|
left -= width;
|
|
eAttachment.left = 'right';
|
|
} else if (left < bounds[0] && eAttachment.left === 'right') {
|
|
left += width;
|
|
eAttachment.left = 'left';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (changeAttachY === 'element' || changeAttachY === 'both') {
|
|
if (top < bounds[1] && eAttachment.top === 'bottom') {
|
|
top += height;
|
|
eAttachment.top = 'top';
|
|
}
|
|
|
|
if (top + height > bounds[3] && eAttachment.top === 'top') {
|
|
top -= height;
|
|
eAttachment.top = 'bottom';
|
|
}
|
|
}
|
|
|
|
if (changeAttachX === 'element' || changeAttachX === 'both') {
|
|
if (left < bounds[0]) {
|
|
if (eAttachment.left === 'right') {
|
|
left += width;
|
|
eAttachment.left = 'left';
|
|
} else if (eAttachment.left === 'center') {
|
|
left += width / 2;
|
|
eAttachment.left = 'left';
|
|
}
|
|
}
|
|
|
|
if (left + width > bounds[2]) {
|
|
if (eAttachment.left === 'left') {
|
|
left -= width;
|
|
eAttachment.left = 'right';
|
|
} else if (eAttachment.left === 'center') {
|
|
left -= width / 2;
|
|
eAttachment.left = 'right';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof pin === 'string') {
|
|
pin = pin.split(',').map(function (p) {
|
|
return p.trim();
|
|
});
|
|
} else if (pin === true) {
|
|
pin = ['top', 'left', 'right', 'bottom'];
|
|
}
|
|
|
|
pin = pin || [];
|
|
|
|
var pinned = [];
|
|
var oob = [];
|
|
|
|
if (top < bounds[1]) {
|
|
if (pin.indexOf('top') >= 0) {
|
|
top = bounds[1];
|
|
pinned.push('top');
|
|
} else {
|
|
oob.push('top');
|
|
}
|
|
}
|
|
|
|
if (top + height > bounds[3]) {
|
|
if (pin.indexOf('bottom') >= 0) {
|
|
top = bounds[3] - height;
|
|
pinned.push('bottom');
|
|
} else {
|
|
oob.push('bottom');
|
|
}
|
|
}
|
|
|
|
if (left < bounds[0]) {
|
|
if (pin.indexOf('left') >= 0) {
|
|
left = bounds[0];
|
|
pinned.push('left');
|
|
} else {
|
|
oob.push('left');
|
|
}
|
|
}
|
|
|
|
if (left + width > bounds[2]) {
|
|
if (pin.indexOf('right') >= 0) {
|
|
left = bounds[2] - width;
|
|
pinned.push('right');
|
|
} else {
|
|
oob.push('right');
|
|
}
|
|
}
|
|
|
|
if (pinned.length) {
|
|
(function () {
|
|
var pinnedClass = undefined;
|
|
if (typeof _this.options.pinnedClass !== 'undefined') {
|
|
pinnedClass = _this.options.pinnedClass;
|
|
} else {
|
|
pinnedClass = _this.getClass('pinned');
|
|
}
|
|
|
|
addClasses.push(pinnedClass);
|
|
pinned.forEach(function (side) {
|
|
addClasses.push(pinnedClass + '-' + side);
|
|
});
|
|
})();
|
|
}
|
|
|
|
if (oob.length) {
|
|
(function () {
|
|
var oobClass = undefined;
|
|
if (typeof _this.options.outOfBoundsClass !== 'undefined') {
|
|
oobClass = _this.options.outOfBoundsClass;
|
|
} else {
|
|
oobClass = _this.getClass('out-of-bounds');
|
|
}
|
|
|
|
addClasses.push(oobClass);
|
|
oob.forEach(function (side) {
|
|
addClasses.push(oobClass + '-' + side);
|
|
});
|
|
})();
|
|
}
|
|
|
|
if (pinned.indexOf('left') >= 0 || pinned.indexOf('right') >= 0) {
|
|
eAttachment.left = tAttachment.left = false;
|
|
}
|
|
if (pinned.indexOf('top') >= 0 || pinned.indexOf('bottom') >= 0) {
|
|
eAttachment.top = tAttachment.top = false;
|
|
}
|
|
|
|
if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== _this.attachment.top || eAttachment.left !== _this.attachment.left) {
|
|
_this.updateAttachClasses(eAttachment, tAttachment);
|
|
_this.trigger('update', {
|
|
attachment: eAttachment,
|
|
targetAttachment: tAttachment
|
|
});
|
|
}
|
|
});
|
|
|
|
defer(function () {
|
|
if (!(_this.options.addTargetClasses === false)) {
|
|
updateClasses(_this.target, addClasses, allClasses);
|
|
}
|
|
updateClasses(_this.element, addClasses, allClasses);
|
|
});
|
|
|
|
return { top: top, left: left };
|
|
}
|
|
});
|
|
/* globals TetherBase */
|
|
|
|
'use strict';
|
|
|
|
var _TetherBase$Utils = TetherBase.Utils;
|
|
var getBounds = _TetherBase$Utils.getBounds;
|
|
var updateClasses = _TetherBase$Utils.updateClasses;
|
|
var defer = _TetherBase$Utils.defer;
|
|
|
|
TetherBase.modules.push({
|
|
position: function position(_ref) {
|
|
var _this = this;
|
|
|
|
var top = _ref.top;
|
|
var left = _ref.left;
|
|
|
|
var _cache = this.cache('element-bounds', function () {
|
|
return getBounds(_this.element);
|
|
});
|
|
|
|
var height = _cache.height;
|
|
var width = _cache.width;
|
|
|
|
var targetPos = this.getTargetBounds();
|
|
|
|
var bottom = top + height;
|
|
var right = left + width;
|
|
|
|
var abutted = [];
|
|
if (top <= targetPos.bottom && bottom >= targetPos.top) {
|
|
['left', 'right'].forEach(function (side) {
|
|
var targetPosSide = targetPos[side];
|
|
if (targetPosSide === left || targetPosSide === right) {
|
|
abutted.push(side);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (left <= targetPos.right && right >= targetPos.left) {
|
|
['top', 'bottom'].forEach(function (side) {
|
|
var targetPosSide = targetPos[side];
|
|
if (targetPosSide === top || targetPosSide === bottom) {
|
|
abutted.push(side);
|
|
}
|
|
});
|
|
}
|
|
|
|
var allClasses = [];
|
|
var addClasses = [];
|
|
|
|
var sides = ['left', 'top', 'right', 'bottom'];
|
|
allClasses.push(this.getClass('abutted'));
|
|
sides.forEach(function (side) {
|
|
allClasses.push(_this.getClass('abutted') + '-' + side);
|
|
});
|
|
|
|
if (abutted.length) {
|
|
addClasses.push(this.getClass('abutted'));
|
|
}
|
|
|
|
abutted.forEach(function (side) {
|
|
addClasses.push(_this.getClass('abutted') + '-' + side);
|
|
});
|
|
|
|
defer(function () {
|
|
if (!(_this.options.addTargetClasses === false)) {
|
|
updateClasses(_this.target, addClasses, allClasses);
|
|
}
|
|
updateClasses(_this.element, addClasses, allClasses);
|
|
});
|
|
|
|
return true;
|
|
}
|
|
});
|
|
/* globals TetherBase */
|
|
|
|
'use strict';
|
|
|
|
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
|
|
|
|
TetherBase.modules.push({
|
|
position: function position(_ref) {
|
|
var top = _ref.top;
|
|
var left = _ref.left;
|
|
|
|
if (!this.options.shift) {
|
|
return;
|
|
}
|
|
|
|
var shift = this.options.shift;
|
|
if (typeof this.options.shift === 'function') {
|
|
shift = this.options.shift.call(this, { top: top, left: left });
|
|
}
|
|
|
|
var shiftTop = undefined,
|
|
shiftLeft = undefined;
|
|
if (typeof shift === 'string') {
|
|
shift = shift.split(' ');
|
|
shift[1] = shift[1] || shift[0];
|
|
|
|
var _shift = shift;
|
|
|
|
var _shift2 = _slicedToArray(_shift, 2);
|
|
|
|
shiftTop = _shift2[0];
|
|
shiftLeft = _shift2[1];
|
|
|
|
shiftTop = parseFloat(shiftTop, 10);
|
|
shiftLeft = parseFloat(shiftLeft, 10);
|
|
} else {
|
|
shiftTop = shift.top;
|
|
shiftLeft = shift.left;
|
|
}
|
|
|
|
top += shiftTop;
|
|
left += shiftLeft;
|
|
|
|
return { top: top, left: left };
|
|
}
|
|
});
|
|
return Tether;
|
|
|
|
}));
|
|
|
|
/**
|
|
* This model is used by admin/analyse_album.blade.php, to analyse all images.
|
|
* @constructor
|
|
*/
|
|
function AnalyseAlbumViewModel() {
|
|
this.el = '#analyse-album';
|
|
|
|
this.data = {
|
|
imagesFailed: [],
|
|
imagesToAnalyse: [],
|
|
imagesInProgress: [],
|
|
imagesRecentlyCompleted: [],
|
|
numberSuccessful: 0,
|
|
numberFailed: 0
|
|
};
|
|
|
|
this.computed = {
|
|
failedPercentage: function () {
|
|
var result = 0;
|
|
|
|
if (this.numberTotal > 0)
|
|
{
|
|
result = (this.numberFailed / this.numberTotal) * 100;
|
|
}
|
|
|
|
return result.toFixed(2) + '%';
|
|
},
|
|
isCompleted: function () {
|
|
return this.numberTotal > 0 && (this.numberSuccessful + this.numberFailed >= this.numberTotal);
|
|
},
|
|
latestCompletedImages: function() {
|
|
var startIndex = this.imagesRecentlyCompleted.length - 3 < 0
|
|
? 0
|
|
: this.imagesRecentlyCompleted.length - 3;
|
|
var endIndex = startIndex + 3;
|
|
|
|
return this.imagesRecentlyCompleted.slice(startIndex, endIndex);
|
|
},
|
|
numberTotal: function () {
|
|
return this.imagesToAnalyse.length;
|
|
},
|
|
successfulPercentage: function () {
|
|
var result = 0;
|
|
|
|
if (this.numberTotal > 0)
|
|
{
|
|
result = (this.numberSuccessful / this.numberTotal) * 100;
|
|
}
|
|
|
|
return result.toFixed(2) + '%';
|
|
}
|
|
};
|
|
|
|
this.methods = {
|
|
// This method is called when an image is added to the array, automatically issue it for analysis
|
|
// item is an instance of AnalyseImageViewModel
|
|
analyseImage: function (item) {
|
|
var self = this;
|
|
this.imagesToAnalyse.push(item);
|
|
|
|
$.ajax(
|
|
item.url,
|
|
{
|
|
beforeSend: function() {
|
|
self.imagesInProgress.push(item);
|
|
},
|
|
dataType: 'json',
|
|
error: function (xhr, textStatus, errorThrown) {
|
|
self.numberFailed++;
|
|
self.imagesFailed.push({
|
|
'name': item.name,
|
|
'reason': textStatus
|
|
});
|
|
item.isSuccessful = false;
|
|
item.isPending = false;
|
|
},
|
|
method: 'POST',
|
|
success: function (data) {
|
|
if (data.is_successful) {
|
|
self.numberSuccessful++;
|
|
item.isSuccessful = true;
|
|
item.isPending = false;
|
|
|
|
// Push into our "recently completed" array
|
|
self.imagesRecentlyCompleted.push(item);
|
|
var indexToRemove = self.imagesInProgress.indexOf(item);
|
|
if (indexToRemove > -1)
|
|
{
|
|
self.imagesInProgress.splice(indexToRemove, 1);
|
|
}
|
|
|
|
// Remove it again after a few seconds
|
|
/*window.setTimeout(function() {
|
|
var indexToRemove = self.imagesRecentlyCompleted.indexOf(item);
|
|
if (indexToRemove > -1) {
|
|
self.imagesRecentlyCompleted.splice(indexToRemove, 1);
|
|
}
|
|
}, 2000);*/
|
|
}
|
|
else {
|
|
self.numberFailed++;
|
|
self.imagesFailed.push({
|
|
'name': item.name,
|
|
'reason': data.message
|
|
});
|
|
item.isSuccessful = false;
|
|
item.isPending = false;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* This model is used by admin/analyse_album.blade.php, as a sub-model of AnalyseAlbumViewModel.
|
|
* @param image_info Array of information about the image
|
|
* @constructor
|
|
*/
|
|
function AnalyseImageViewModel(image_info) {
|
|
this.isPending = true;
|
|
this.isSuccessful = false;
|
|
this.name = image_info.name;
|
|
this.photoID = image_info.photo_id;
|
|
this.url = image_info.url;
|
|
}
|
|
|
|
/**
|
|
* This model is used by admin/show_album.blade.php to handle photo changes.
|
|
* @param album_id ID of the album the photos are in
|
|
* @param language Array containing language strings
|
|
* @param urls Array containing URLs
|
|
* @constructor
|
|
*/
|
|
function EditPhotosViewModel(album_id, language, urls) {
|
|
this.el = '#photos-tab';
|
|
|
|
this.data = {
|
|
albums: [],
|
|
bulkModifyMethod: '',
|
|
isSubmitting: false,
|
|
photoIDs: [],
|
|
photoIDsAvailable: [],
|
|
selectAllInAlbum: 0
|
|
};
|
|
|
|
// When a photo is un-selected, remove the "select all in album" flag as the user has overridden the selection
|
|
/*self.photoIDs.subscribe(function (changes)
|
|
{
|
|
if (changes[0].status !== 'deleted')
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.selectAllInAlbum(0);
|
|
}, null, 'arrayChange');*/
|
|
|
|
this.methods = {
|
|
// Called when the Apply button on the "bulk apply selected actions" form is clicked
|
|
bulkModifySelected: function (e) {
|
|
if (this.isSubmitting) {
|
|
return true;
|
|
}
|
|
|
|
var self = this;
|
|
var bulk_form = $(e.target).closest('form');
|
|
|
|
if (this.bulkModifyMethod === 'change_album') {
|
|
// Prompt for the new album to move to
|
|
this.promptForNewAlbum(function (dialog) {
|
|
var album_id = $('select', dialog).val();
|
|
$('input[name="new-album-id"]', bulk_form).val(album_id);
|
|
|
|
self.isSubmitting = true;
|
|
$('button[name="bulk-apply"]', bulk_form).click();
|
|
_bt_showLoadingModal();
|
|
});
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
else if (this.bulkModifyMethod === 'delete') {
|
|
// Prompt for a confirmation - are you sure?!
|
|
bootbox.dialog({
|
|
message: language.delete_bulk_confirm_message,
|
|
title: language.delete_bulk_confirm_title,
|
|
buttons: {
|
|
cancel: {
|
|
label: language.action_cancel,
|
|
className: "btn-secondary"
|
|
},
|
|
confirm: {
|
|
label: language.action_delete,
|
|
className: "btn-danger",
|
|
callback: function () {
|
|
self.isSubmitting = true;
|
|
$('button[name="bulk-apply"]', bulk_form).click();
|
|
_bt_showLoadingModal();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
|
|
// All other methods submit the form as normal
|
|
return true;
|
|
},
|
|
changeAlbum: function (e) {
|
|
this.selectPhotoSingle(e.target);
|
|
|
|
var photo_id = this.photoIDs[0];
|
|
this.photoIDs = [];
|
|
|
|
this.promptForNewAlbum(function (dialog) {
|
|
var album_id = $('select', dialog).val();
|
|
$.post(urls.move_photo.replace(/\/0$/, '/' + photo_id), {'new_album_id': album_id}, function () {
|
|
window.location.reload();
|
|
});
|
|
//_bt_showLoadingModal();
|
|
});
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
deletePhoto: function (e) {
|
|
var self = this;
|
|
this.selectPhotoSingle(e.target);
|
|
|
|
var photo_id = self.photoIDs[0];
|
|
this.photoIDs = [];
|
|
|
|
bootbox.dialog({
|
|
message: language.delete_confirm_message,
|
|
title: language.delete_confirm_title,
|
|
buttons: {
|
|
cancel: {
|
|
label: language.action_cancel,
|
|
className: "btn-secondary"
|
|
},
|
|
confirm: {
|
|
label: language.action_delete,
|
|
className: "btn-danger",
|
|
callback: function () {
|
|
var url = urls.delete_photo;
|
|
url = url.replace(/\/0$/, '/' + photo_id);
|
|
|
|
$('.loading', parent).show();
|
|
|
|
$.post(url, {'_method': 'DELETE'}, function (data) {
|
|
window.location.reload();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
flip: function (horizontal, vertical, parent) {
|
|
var url = urls.flip_photo;
|
|
url = url.replace('/0/', '/' + this.photoIDs[0] + '/');
|
|
|
|
if (horizontal) {
|
|
url = url.replace(/\/-1\//, '/1/');
|
|
}
|
|
else {
|
|
url = url.replace(/\/-1\//, '/0/');
|
|
}
|
|
|
|
if (vertical) {
|
|
url = url.replace(/\/-2$/, '/1');
|
|
}
|
|
else {
|
|
url = url.replace(/\/-2$/, '/0');
|
|
}
|
|
|
|
$('.loading', parent).show();
|
|
$.post(url, function () {
|
|
var image = $('img.photo-thumbnail', parent);
|
|
var originalUrl = image.data('original-src');
|
|
image.attr('src', originalUrl + "&_=" + new Date().getTime());
|
|
|
|
$('.loading', parent).hide();
|
|
});
|
|
|
|
this.photoIDs = [];
|
|
},
|
|
flipBoth: function (e) {
|
|
this.selectPhotoSingle(e.target);
|
|
this.flip(true, true, $(e.target).closest('.photo'));
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
flipHorizontal: function (e) {
|
|
this.selectPhotoSingle(e.target);
|
|
this.flip(true, false, $(e.target).closest('.photo'));
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
flipVertical: function (e) {
|
|
this.selectPhotoSingle(e.target);
|
|
this.flip(false, true, $(e.target).closest('.photo'));
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
isPhotoSelected: function(photoID) {
|
|
if (this.photoIDs.indexOf(photoID) > -1)
|
|
{
|
|
return 'checked';
|
|
}
|
|
|
|
return '';
|
|
},
|
|
promptForNewAlbum: function (callback_on_selected) {
|
|
var albums = this.albums;
|
|
var select = $('<select/>')
|
|
.attr('name', 'album_id')
|
|
.addClass('form-control');
|
|
|
|
for (var i = 0; i < albums.length; i++) {
|
|
var option = $('<option/>')
|
|
.attr('value', albums[i].id)
|
|
.html(albums[i].name)
|
|
.appendTo(select);
|
|
|
|
// Pre-select the current album
|
|
if (album_id === albums[i].id) {
|
|
option.attr('selected', 'selected');
|
|
}
|
|
}
|
|
|
|
bootbox.dialog({
|
|
message: $('<p/>').html(language.change_album_message).prop('outerHTML') + select.prop('outerHTML'),
|
|
title: language.change_album_title,
|
|
buttons: {
|
|
cancel: {
|
|
label: language.action_cancel,
|
|
className: 'btn-secondary'
|
|
},
|
|
confirm: {
|
|
label: language.action_continue,
|
|
className: 'btn-success',
|
|
callback: function () {
|
|
callback_on_selected(this);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
},
|
|
regenerateThumbnails: function (e) {
|
|
this.selectPhotoSingle(e.target);
|
|
var parent = $(e.target).closest('.photo');
|
|
|
|
var url = urls.regenerate_thumbnails;
|
|
url = url.replace(/\/0$/, '/' + this.photoIDs[0]);
|
|
|
|
$('.loading', parent).show();
|
|
$.post(url, function () {
|
|
var image = $('img.photo-thumbnail', parent);
|
|
var originalUrl = image.data('original-src');
|
|
image.attr('src', originalUrl + "&_=" + new Date().getTime());
|
|
|
|
$('.loading', parent).hide();
|
|
});
|
|
|
|
this.photoIDs = [];
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
rotate: function (angle, parent) {
|
|
var url = urls.rotate_photo;
|
|
url = url.replace('/0/', '/' + this.photoIDs[0] + '/');
|
|
url = url.replace(/\/1$/, '/' + angle);
|
|
|
|
$('.loading', parent).show();
|
|
$.post(url, function () {
|
|
var image = $('img.photo-thumbnail', parent);
|
|
var originalUrl = image.data('original-src');
|
|
image.attr('src', originalUrl + "&_=" + new Date().getTime());
|
|
|
|
$('.loading', parent).hide();
|
|
});
|
|
|
|
this.photoIDs = [];
|
|
},
|
|
rotateLeft: function (e) {
|
|
this.selectPhotoSingle(e.target);
|
|
this.rotate(90, $(e.target).closest('.photo'));
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
rotateRight: function(e)
|
|
{
|
|
this.selectPhotoSingle(e.target);
|
|
this.rotate(270, $(e.target).closest('.photo'));
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
selectAll: function() {
|
|
var self = this;
|
|
bootbox.dialog({
|
|
title: language.select_all_choice_title,
|
|
message: language.select_all_choice_message,
|
|
buttons: {
|
|
select_all: {
|
|
label: language.select_all_choice_all_action,
|
|
className: 'btn-secondary',
|
|
callback: function()
|
|
{
|
|
self.selectAllInAlbum = 1;
|
|
for (i = 0; i < self.photoIDsAvailable.length; i++)
|
|
{
|
|
self.photoIDs.push(self.photoIDsAvailable[i]);
|
|
}
|
|
}
|
|
},
|
|
select_visible: {
|
|
label: language.select_all_choice_visible_action,
|
|
className: 'btn-primary',
|
|
callback: function()
|
|
{
|
|
self.selectAllInAlbum = 0;
|
|
for (i = 0; i < self.photoIDsAvailable.length; i++)
|
|
{
|
|
self.photoIDs.push(self.photoIDsAvailable[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return false;
|
|
},
|
|
selectNone: function() {
|
|
this.photoIDs = [];
|
|
this.selectAllInAlbum = 0;
|
|
|
|
return false;
|
|
},
|
|
selectPhotoSingle: function (link_item) {
|
|
// Get the photo ID from the clicked link
|
|
var parent = $(link_item).closest('.photo');
|
|
var photo_id = $(parent).data('photo-id');
|
|
|
|
// Save the photo ID
|
|
this.photoIDs = [];
|
|
this.photoIDs.push(photo_id);
|
|
|
|
// Hide the dropdown
|
|
$(link_item).dropdown('toggle');
|
|
},
|
|
switchToUploadTab: function (e) {
|
|
$('.nav-tabs a[href="#upload-tab"]').tab('show');
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
function SlideShowViewModel(required_timeout_ms) {
|
|
this.el = '#slideshow-container';
|
|
|
|
this.data = {
|
|
current: null,
|
|
currentIndex: 0,
|
|
images: [],
|
|
interval: null,
|
|
isPaused: false,
|
|
isRunning: false
|
|
};
|
|
|
|
this.methods = {
|
|
changeCurrentImage: function(photo_id)
|
|
{
|
|
for (var i = 0; i < this.images.length; i++)
|
|
{
|
|
var this_image = this.images[i];
|
|
if (this_image.id === photo_id)
|
|
{
|
|
this.current = this_image;
|
|
this.currentIndex = i;
|
|
window.clearInterval(this.interval);
|
|
this.interval = window.setInterval(this.rotateNextImage, required_timeout_ms);
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
continueSlideshow: function() {
|
|
this.isPaused = false;
|
|
this.interval = window.setInterval(this.rotateNextImage, required_timeout_ms);
|
|
},
|
|
pauseSlideshow: function() {
|
|
this.isPaused = true;
|
|
window.clearInterval(this.interval);
|
|
},
|
|
rotateNextImage: function() {
|
|
var next_index = this.currentIndex + 1;
|
|
if (next_index >= this.images.length)
|
|
{
|
|
next_index = 0;
|
|
}
|
|
|
|
this.current = this.images[next_index];
|
|
this.currentIndex = next_index;
|
|
},
|
|
startSlideshow: function() {
|
|
if (this.images.length <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.interval = window.setInterval(this.rotateNextImage, required_timeout_ms);
|
|
|
|
this.current = this.images[0];
|
|
this.isRunning = true;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* This model is used by admin/show_album.blade.php to handle photo uploads.
|
|
* @param album_id ID of the album the photos are being uploaded to
|
|
* @param queue_token Unique token of the upload queue to save the photos to
|
|
* @param language Array containing language strings
|
|
* @param urls Array containing URLs
|
|
* @constructor
|
|
*/
|
|
function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
|
this.el = '#upload-tab';
|
|
|
|
this.data = {
|
|
currentStatus: '',
|
|
imagesFailed: 0,
|
|
imagesTotal: 0,
|
|
imagesUploaded: 0,
|
|
isBulkUploadInProgress: false,
|
|
isUploadInProgress: false,
|
|
statusMessages: []
|
|
};
|
|
|
|
this.computed = {
|
|
failedPercentage: function () {
|
|
var result = 0;
|
|
|
|
if (this.imagesTotal > 0)
|
|
{
|
|
result = (this.imagesFailed / this.imagesTotal) * 100;
|
|
}
|
|
|
|
return result.toFixed(2) + '%';
|
|
},
|
|
successfulPercentage: function () {
|
|
var result = 0;
|
|
|
|
if (this.imagesTotal > 0)
|
|
{
|
|
result = (this.imagesUploaded / this.imagesTotal) * 100;
|
|
}
|
|
|
|
return result.toFixed(2) + '%';
|
|
}
|
|
};
|
|
|
|
this.methods = {
|
|
// This method is called when an image is uploaded - regardless if it fails or not
|
|
onUploadCompleted: function () {
|
|
this.currentStatus = language.upload_status
|
|
.replace(':current', (this.imagesUploaded + this.imagesFailed))
|
|
.replace(':total', this.imagesTotal);
|
|
|
|
if ((this.imagesFailed + this.imagesUploaded) >= this.imagesTotal) {
|
|
this.isUploadInProgress = false;
|
|
|
|
if (this.imagesFailed === 0 && this.imagesUploaded > 0) {
|
|
window.location = urls.analyse;
|
|
}
|
|
}
|
|
},
|
|
// This method is called when an uploaded image fails
|
|
onUploadFailed: function (data, file_name) {
|
|
this.imagesFailed++;
|
|
this.statusMessages.push({
|
|
'message_class': 'text-danger',
|
|
'message_text': language.image_failed.replace(':file_name', file_name)
|
|
});
|
|
this.onUploadCompleted();
|
|
},
|
|
// This method is called when an uploaded image succeeds
|
|
onUploadSuccessful: function (data, file_name) {
|
|
if (data.is_successful) {
|
|
this.imagesUploaded++;
|
|
// Don't add to statusMessages() array so user only sees errors
|
|
/*self.statusMessages.push({
|
|
'message_class': 'text-success',
|
|
'message_text': language.image_uploaded.replace(':file_name', file_name)
|
|
});*/
|
|
this.onUploadCompleted();
|
|
}
|
|
else {
|
|
this.onUploadFailed(data, file_name);
|
|
}
|
|
},
|
|
uploadFile: function uploadImageFile(formObject, imageFile) {
|
|
var self = this;
|
|
var formData = new FormData();
|
|
formData.append('album_id', album_id);
|
|
formData.append('queue_token', queue_token);
|
|
formData.append('photo[]', imageFile, imageFile.name);
|
|
|
|
$.ajax(
|
|
{
|
|
contentType: false,
|
|
data: formData,
|
|
error: function (data) {
|
|
self.onUploadFailed(data, imageFile.name);
|
|
},
|
|
method: $(formObject).attr('method'),
|
|
processData: false,
|
|
success: function (data) {
|
|
self.onUploadSuccessful(data, imageFile.name);
|
|
},
|
|
url: $(formObject).attr('action')
|
|
}
|
|
);
|
|
this.isUploadInProgress = true;
|
|
|
|
this.currentStatus = language.upload_status
|
|
.replace(':current', 0)
|
|
.replace(':total', this.imagesTotal);
|
|
},
|
|
uploadBulkFiles: function(event) {
|
|
this.isBulkUploadInProgress = true;
|
|
return true;
|
|
},
|
|
uploadIndividualFiles: function(event) {
|
|
var fileSelect = $('input[type=file]', event.target);
|
|
|
|
// Get the selected files
|
|
var files = fileSelect[0].files;
|
|
|
|
// Reset statistics
|
|
this.currentStatus = '';
|
|
this.statusMessages = [];
|
|
this.imagesUploaded = 0;
|
|
this.imagesFailed = 0;
|
|
this.imagesTotal = files.length;
|
|
this.isUploadInProgress = true;
|
|
|
|
// Loop through each of the selected files and upload them individually
|
|
for (var i = 0; i < files.length; i++)
|
|
{
|
|
var file = files[i];
|
|
|
|
// We're only interested in image files
|
|
if (!file.type.match('image.*'))
|
|
{
|
|
alert(language.not_an_image_file.replace(':file_name', file.name));
|
|
this.onUploadFailed(null, file.name);
|
|
continue;
|
|
}
|
|
|
|
// Upload the file
|
|
this.uploadFile(event.target, file);
|
|
}
|
|
|
|
// Prevent standard form upload
|
|
event.preventDefault();
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
function StorageLocationViewModel()
|
|
{
|
|
this.el = '#storage-options';
|
|
this.data = {
|
|
storage_driver: 'LocalFilesystemSource'
|
|
};
|
|
}
|
|
/*!
|
|
* typeahead.js 0.11.1
|
|
* https://github.com/twitter/typeahead.js
|
|
* Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
|
|
*/
|
|
|
|
(function(root, factory) {
|
|
if (typeof define === "function" && define.amd) {
|
|
define("bloodhound", [ "jquery" ], function(a0) {
|
|
return root["Bloodhound"] = factory(a0);
|
|
});
|
|
} else if (typeof exports === "object") {
|
|
module.exports = factory(require("jquery"));
|
|
} else {
|
|
root["Bloodhound"] = factory(jQuery);
|
|
}
|
|
})(this, function($) {
|
|
var _ = function() {
|
|
"use strict";
|
|
return {
|
|
isMsie: function() {
|
|
return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
|
|
},
|
|
isBlankString: function(str) {
|
|
return !str || /^\s*$/.test(str);
|
|
},
|
|
escapeRegExChars: function(str) {
|
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
},
|
|
isString: function(obj) {
|
|
return typeof obj === "string";
|
|
},
|
|
isNumber: function(obj) {
|
|
return typeof obj === "number";
|
|
},
|
|
isArray: $.isArray,
|
|
isFunction: $.isFunction,
|
|
isObject: $.isPlainObject,
|
|
isUndefined: function(obj) {
|
|
return typeof obj === "undefined";
|
|
},
|
|
isElement: function(obj) {
|
|
return !!(obj && obj.nodeType === 1);
|
|
},
|
|
isJQuery: function(obj) {
|
|
return obj instanceof $;
|
|
},
|
|
toStr: function toStr(s) {
|
|
return _.isUndefined(s) || s === null ? "" : s + "";
|
|
},
|
|
bind: $.proxy,
|
|
each: function(collection, cb) {
|
|
$.each(collection, reverseArgs);
|
|
function reverseArgs(index, value) {
|
|
return cb(value, index);
|
|
}
|
|
},
|
|
map: $.map,
|
|
filter: $.grep,
|
|
every: function(obj, test) {
|
|
var result = true;
|
|
if (!obj) {
|
|
return result;
|
|
}
|
|
$.each(obj, function(key, val) {
|
|
if (!(result = test.call(null, val, key, obj))) {
|
|
return false;
|
|
}
|
|
});
|
|
return !!result;
|
|
},
|
|
some: function(obj, test) {
|
|
var result = false;
|
|
if (!obj) {
|
|
return result;
|
|
}
|
|
$.each(obj, function(key, val) {
|
|
if (result = test.call(null, val, key, obj)) {
|
|
return false;
|
|
}
|
|
});
|
|
return !!result;
|
|
},
|
|
mixin: $.extend,
|
|
identity: function(x) {
|
|
return x;
|
|
},
|
|
clone: function(obj) {
|
|
return $.extend(true, {}, obj);
|
|
},
|
|
getIdGenerator: function() {
|
|
var counter = 0;
|
|
return function() {
|
|
return counter++;
|
|
};
|
|
},
|
|
templatify: function templatify(obj) {
|
|
return $.isFunction(obj) ? obj : template;
|
|
function template() {
|
|
return String(obj);
|
|
}
|
|
},
|
|
defer: function(fn) {
|
|
setTimeout(fn, 0);
|
|
},
|
|
debounce: function(func, wait, immediate) {
|
|
var timeout, result;
|
|
return function() {
|
|
var context = this, args = arguments, later, callNow;
|
|
later = function() {
|
|
timeout = null;
|
|
if (!immediate) {
|
|
result = func.apply(context, args);
|
|
}
|
|
};
|
|
callNow = immediate && !timeout;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
if (callNow) {
|
|
result = func.apply(context, args);
|
|
}
|
|
return result;
|
|
};
|
|
},
|
|
throttle: function(func, wait) {
|
|
var context, args, timeout, result, previous, later;
|
|
previous = 0;
|
|
later = function() {
|
|
previous = new Date();
|
|
timeout = null;
|
|
result = func.apply(context, args);
|
|
};
|
|
return function() {
|
|
var now = new Date(), remaining = wait - (now - previous);
|
|
context = this;
|
|
args = arguments;
|
|
if (remaining <= 0) {
|
|
clearTimeout(timeout);
|
|
timeout = null;
|
|
previous = now;
|
|
result = func.apply(context, args);
|
|
} else if (!timeout) {
|
|
timeout = setTimeout(later, remaining);
|
|
}
|
|
return result;
|
|
};
|
|
},
|
|
stringify: function(val) {
|
|
return _.isString(val) ? val : JSON.stringify(val);
|
|
},
|
|
noop: function() {}
|
|
};
|
|
}();
|
|
var VERSION = "0.11.1";
|
|
var tokenizers = function() {
|
|
"use strict";
|
|
return {
|
|
nonword: nonword,
|
|
whitespace: whitespace,
|
|
obj: {
|
|
nonword: getObjTokenizer(nonword),
|
|
whitespace: getObjTokenizer(whitespace)
|
|
}
|
|
};
|
|
function whitespace(str) {
|
|
str = _.toStr(str);
|
|
return str ? str.split(/\s+/) : [];
|
|
}
|
|
function nonword(str) {
|
|
str = _.toStr(str);
|
|
return str ? str.split(/\W+/) : [];
|
|
}
|
|
function getObjTokenizer(tokenizer) {
|
|
return function setKey(keys) {
|
|
keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
|
|
return function tokenize(o) {
|
|
var tokens = [];
|
|
_.each(keys, function(k) {
|
|
tokens = tokens.concat(tokenizer(_.toStr(o[k])));
|
|
});
|
|
return tokens;
|
|
};
|
|
};
|
|
}
|
|
}();
|
|
var LruCache = function() {
|
|
"use strict";
|
|
function LruCache(maxSize) {
|
|
this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
|
|
this.reset();
|
|
if (this.maxSize <= 0) {
|
|
this.set = this.get = $.noop;
|
|
}
|
|
}
|
|
_.mixin(LruCache.prototype, {
|
|
set: function set(key, val) {
|
|
var tailItem = this.list.tail, node;
|
|
if (this.size >= this.maxSize) {
|
|
this.list.remove(tailItem);
|
|
delete this.hash[tailItem.key];
|
|
this.size--;
|
|
}
|
|
if (node = this.hash[key]) {
|
|
node.val = val;
|
|
this.list.moveToFront(node);
|
|
} else {
|
|
node = new Node(key, val);
|
|
this.list.add(node);
|
|
this.hash[key] = node;
|
|
this.size++;
|
|
}
|
|
},
|
|
get: function get(key) {
|
|
var node = this.hash[key];
|
|
if (node) {
|
|
this.list.moveToFront(node);
|
|
return node.val;
|
|
}
|
|
},
|
|
reset: function reset() {
|
|
this.size = 0;
|
|
this.hash = {};
|
|
this.list = new List();
|
|
}
|
|
});
|
|
function List() {
|
|
this.head = this.tail = null;
|
|
}
|
|
_.mixin(List.prototype, {
|
|
add: function add(node) {
|
|
if (this.head) {
|
|
node.next = this.head;
|
|
this.head.prev = node;
|
|
}
|
|
this.head = node;
|
|
this.tail = this.tail || node;
|
|
},
|
|
remove: function remove(node) {
|
|
node.prev ? node.prev.next = node.next : this.head = node.next;
|
|
node.next ? node.next.prev = node.prev : this.tail = node.prev;
|
|
},
|
|
moveToFront: function(node) {
|
|
this.remove(node);
|
|
this.add(node);
|
|
}
|
|
});
|
|
function Node(key, val) {
|
|
this.key = key;
|
|
this.val = val;
|
|
this.prev = this.next = null;
|
|
}
|
|
return LruCache;
|
|
}();
|
|
var PersistentStorage = function() {
|
|
"use strict";
|
|
var LOCAL_STORAGE;
|
|
try {
|
|
LOCAL_STORAGE = window.localStorage;
|
|
LOCAL_STORAGE.setItem("~~~", "!");
|
|
LOCAL_STORAGE.removeItem("~~~");
|
|
} catch (err) {
|
|
LOCAL_STORAGE = null;
|
|
}
|
|
function PersistentStorage(namespace, override) {
|
|
this.prefix = [ "__", namespace, "__" ].join("");
|
|
this.ttlKey = "__ttl__";
|
|
this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
|
|
this.ls = override || LOCAL_STORAGE;
|
|
!this.ls && this._noop();
|
|
}
|
|
_.mixin(PersistentStorage.prototype, {
|
|
_prefix: function(key) {
|
|
return this.prefix + key;
|
|
},
|
|
_ttlKey: function(key) {
|
|
return this._prefix(key) + this.ttlKey;
|
|
},
|
|
_noop: function() {
|
|
this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
|
|
},
|
|
_safeSet: function(key, val) {
|
|
try {
|
|
this.ls.setItem(key, val);
|
|
} catch (err) {
|
|
if (err.name === "QuotaExceededError") {
|
|
this.clear();
|
|
this._noop();
|
|
}
|
|
}
|
|
},
|
|
get: function(key) {
|
|
if (this.isExpired(key)) {
|
|
this.remove(key);
|
|
}
|
|
return decode(this.ls.getItem(this._prefix(key)));
|
|
},
|
|
set: function(key, val, ttl) {
|
|
if (_.isNumber(ttl)) {
|
|
this._safeSet(this._ttlKey(key), encode(now() + ttl));
|
|
} else {
|
|
this.ls.removeItem(this._ttlKey(key));
|
|
}
|
|
return this._safeSet(this._prefix(key), encode(val));
|
|
},
|
|
remove: function(key) {
|
|
this.ls.removeItem(this._ttlKey(key));
|
|
this.ls.removeItem(this._prefix(key));
|
|
return this;
|
|
},
|
|
clear: function() {
|
|
var i, keys = gatherMatchingKeys(this.keyMatcher);
|
|
for (i = keys.length; i--; ) {
|
|
this.remove(keys[i]);
|
|
}
|
|
return this;
|
|
},
|
|
isExpired: function(key) {
|
|
var ttl = decode(this.ls.getItem(this._ttlKey(key)));
|
|
return _.isNumber(ttl) && now() > ttl ? true : false;
|
|
}
|
|
});
|
|
return PersistentStorage;
|
|
function now() {
|
|
return new Date().getTime();
|
|
}
|
|
function encode(val) {
|
|
return JSON.stringify(_.isUndefined(val) ? null : val);
|
|
}
|
|
function decode(val) {
|
|
return $.parseJSON(val);
|
|
}
|
|
function gatherMatchingKeys(keyMatcher) {
|
|
var i, key, keys = [], len = LOCAL_STORAGE.length;
|
|
for (i = 0; i < len; i++) {
|
|
if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
|
|
keys.push(key.replace(keyMatcher, ""));
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
}();
|
|
var Transport = function() {
|
|
"use strict";
|
|
var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
|
|
function Transport(o) {
|
|
o = o || {};
|
|
this.cancelled = false;
|
|
this.lastReq = null;
|
|
this._send = o.transport;
|
|
this._get = o.limiter ? o.limiter(this._get) : this._get;
|
|
this._cache = o.cache === false ? new LruCache(0) : sharedCache;
|
|
}
|
|
Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
|
|
maxPendingRequests = num;
|
|
};
|
|
Transport.resetCache = function resetCache() {
|
|
sharedCache.reset();
|
|
};
|
|
_.mixin(Transport.prototype, {
|
|
_fingerprint: function fingerprint(o) {
|
|
o = o || {};
|
|
return o.url + o.type + $.param(o.data || {});
|
|
},
|
|
_get: function(o, cb) {
|
|
var that = this, fingerprint, jqXhr;
|
|
fingerprint = this._fingerprint(o);
|
|
if (this.cancelled || fingerprint !== this.lastReq) {
|
|
return;
|
|
}
|
|
if (jqXhr = pendingRequests[fingerprint]) {
|
|
jqXhr.done(done).fail(fail);
|
|
} else if (pendingRequestsCount < maxPendingRequests) {
|
|
pendingRequestsCount++;
|
|
pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
|
|
} else {
|
|
this.onDeckRequestArgs = [].slice.call(arguments, 0);
|
|
}
|
|
function done(resp) {
|
|
cb(null, resp);
|
|
that._cache.set(fingerprint, resp);
|
|
}
|
|
function fail() {
|
|
cb(true);
|
|
}
|
|
function always() {
|
|
pendingRequestsCount--;
|
|
delete pendingRequests[fingerprint];
|
|
if (that.onDeckRequestArgs) {
|
|
that._get.apply(that, that.onDeckRequestArgs);
|
|
that.onDeckRequestArgs = null;
|
|
}
|
|
}
|
|
},
|
|
get: function(o, cb) {
|
|
var resp, fingerprint;
|
|
cb = cb || $.noop;
|
|
o = _.isString(o) ? {
|
|
url: o
|
|
} : o || {};
|
|
fingerprint = this._fingerprint(o);
|
|
this.cancelled = false;
|
|
this.lastReq = fingerprint;
|
|
if (resp = this._cache.get(fingerprint)) {
|
|
cb(null, resp);
|
|
} else {
|
|
this._get(o, cb);
|
|
}
|
|
},
|
|
cancel: function() {
|
|
this.cancelled = true;
|
|
}
|
|
});
|
|
return Transport;
|
|
}();
|
|
var SearchIndex = window.SearchIndex = function() {
|
|
"use strict";
|
|
var CHILDREN = "c", IDS = "i";
|
|
function SearchIndex(o) {
|
|
o = o || {};
|
|
if (!o.datumTokenizer || !o.queryTokenizer) {
|
|
$.error("datumTokenizer and queryTokenizer are both required");
|
|
}
|
|
this.identify = o.identify || _.stringify;
|
|
this.datumTokenizer = o.datumTokenizer;
|
|
this.queryTokenizer = o.queryTokenizer;
|
|
this.reset();
|
|
}
|
|
_.mixin(SearchIndex.prototype, {
|
|
bootstrap: function bootstrap(o) {
|
|
this.datums = o.datums;
|
|
this.trie = o.trie;
|
|
},
|
|
add: function(data) {
|
|
var that = this;
|
|
data = _.isArray(data) ? data : [ data ];
|
|
_.each(data, function(datum) {
|
|
var id, tokens;
|
|
that.datums[id = that.identify(datum)] = datum;
|
|
tokens = normalizeTokens(that.datumTokenizer(datum));
|
|
_.each(tokens, function(token) {
|
|
var node, chars, ch;
|
|
node = that.trie;
|
|
chars = token.split("");
|
|
while (ch = chars.shift()) {
|
|
node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
|
|
node[IDS].push(id);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
get: function get(ids) {
|
|
var that = this;
|
|
return _.map(ids, function(id) {
|
|
return that.datums[id];
|
|
});
|
|
},
|
|
search: function search(query) {
|
|
var that = this, tokens, matches;
|
|
tokens = normalizeTokens(this.queryTokenizer(query));
|
|
_.each(tokens, function(token) {
|
|
var node, chars, ch, ids;
|
|
if (matches && matches.length === 0) {
|
|
return false;
|
|
}
|
|
node = that.trie;
|
|
chars = token.split("");
|
|
while (node && (ch = chars.shift())) {
|
|
node = node[CHILDREN][ch];
|
|
}
|
|
if (node && chars.length === 0) {
|
|
ids = node[IDS].slice(0);
|
|
matches = matches ? getIntersection(matches, ids) : ids;
|
|
} else {
|
|
matches = [];
|
|
return false;
|
|
}
|
|
});
|
|
return matches ? _.map(unique(matches), function(id) {
|
|
return that.datums[id];
|
|
}) : [];
|
|
},
|
|
all: function all() {
|
|
var values = [];
|
|
for (var key in this.datums) {
|
|
values.push(this.datums[key]);
|
|
}
|
|
return values;
|
|
},
|
|
reset: function reset() {
|
|
this.datums = {};
|
|
this.trie = newNode();
|
|
},
|
|
serialize: function serialize() {
|
|
return {
|
|
datums: this.datums,
|
|
trie: this.trie
|
|
};
|
|
}
|
|
});
|
|
return SearchIndex;
|
|
function normalizeTokens(tokens) {
|
|
tokens = _.filter(tokens, function(token) {
|
|
return !!token;
|
|
});
|
|
tokens = _.map(tokens, function(token) {
|
|
return token.toLowerCase();
|
|
});
|
|
return tokens;
|
|
}
|
|
function newNode() {
|
|
var node = {};
|
|
node[IDS] = [];
|
|
node[CHILDREN] = {};
|
|
return node;
|
|
}
|
|
function unique(array) {
|
|
var seen = {}, uniques = [];
|
|
for (var i = 0, len = array.length; i < len; i++) {
|
|
if (!seen[array[i]]) {
|
|
seen[array[i]] = true;
|
|
uniques.push(array[i]);
|
|
}
|
|
}
|
|
return uniques;
|
|
}
|
|
function getIntersection(arrayA, arrayB) {
|
|
var ai = 0, bi = 0, intersection = [];
|
|
arrayA = arrayA.sort();
|
|
arrayB = arrayB.sort();
|
|
var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
|
|
while (ai < lenArrayA && bi < lenArrayB) {
|
|
if (arrayA[ai] < arrayB[bi]) {
|
|
ai++;
|
|
} else if (arrayA[ai] > arrayB[bi]) {
|
|
bi++;
|
|
} else {
|
|
intersection.push(arrayA[ai]);
|
|
ai++;
|
|
bi++;
|
|
}
|
|
}
|
|
return intersection;
|
|
}
|
|
}();
|
|
var Prefetch = function() {
|
|
"use strict";
|
|
var keys;
|
|
keys = {
|
|
data: "data",
|
|
protocol: "protocol",
|
|
thumbprint: "thumbprint"
|
|
};
|
|
function Prefetch(o) {
|
|
this.url = o.url;
|
|
this.ttl = o.ttl;
|
|
this.cache = o.cache;
|
|
this.prepare = o.prepare;
|
|
this.transform = o.transform;
|
|
this.transport = o.transport;
|
|
this.thumbprint = o.thumbprint;
|
|
this.storage = new PersistentStorage(o.cacheKey);
|
|
}
|
|
_.mixin(Prefetch.prototype, {
|
|
_settings: function settings() {
|
|
return {
|
|
url: this.url,
|
|
type: "GET",
|
|
dataType: "json"
|
|
};
|
|
},
|
|
store: function store(data) {
|
|
if (!this.cache) {
|
|
return;
|
|
}
|
|
this.storage.set(keys.data, data, this.ttl);
|
|
this.storage.set(keys.protocol, location.protocol, this.ttl);
|
|
this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
|
|
},
|
|
fromCache: function fromCache() {
|
|
var stored = {}, isExpired;
|
|
if (!this.cache) {
|
|
return null;
|
|
}
|
|
stored.data = this.storage.get(keys.data);
|
|
stored.protocol = this.storage.get(keys.protocol);
|
|
stored.thumbprint = this.storage.get(keys.thumbprint);
|
|
isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
|
|
return stored.data && !isExpired ? stored.data : null;
|
|
},
|
|
fromNetwork: function(cb) {
|
|
var that = this, settings;
|
|
if (!cb) {
|
|
return;
|
|
}
|
|
settings = this.prepare(this._settings());
|
|
this.transport(settings).fail(onError).done(onResponse);
|
|
function onError() {
|
|
cb(true);
|
|
}
|
|
function onResponse(resp) {
|
|
cb(null, that.transform(resp));
|
|
}
|
|
},
|
|
clear: function clear() {
|
|
this.storage.clear();
|
|
return this;
|
|
}
|
|
});
|
|
return Prefetch;
|
|
}();
|
|
var Remote = function() {
|
|
"use strict";
|
|
function Remote(o) {
|
|
this.url = o.url;
|
|
this.prepare = o.prepare;
|
|
this.transform = o.transform;
|
|
this.transport = new Transport({
|
|
cache: o.cache,
|
|
limiter: o.limiter,
|
|
transport: o.transport
|
|
});
|
|
}
|
|
_.mixin(Remote.prototype, {
|
|
_settings: function settings() {
|
|
return {
|
|
url: this.url,
|
|
type: "GET",
|
|
dataType: "json"
|
|
};
|
|
},
|
|
get: function get(query, cb) {
|
|
var that = this, settings;
|
|
if (!cb) {
|
|
return;
|
|
}
|
|
query = query || "";
|
|
settings = this.prepare(query, this._settings());
|
|
return this.transport.get(settings, onResponse);
|
|
function onResponse(err, resp) {
|
|
err ? cb([]) : cb(that.transform(resp));
|
|
}
|
|
},
|
|
cancelLastRequest: function cancelLastRequest() {
|
|
this.transport.cancel();
|
|
}
|
|
});
|
|
return Remote;
|
|
}();
|
|
var oParser = function() {
|
|
"use strict";
|
|
return function parse(o) {
|
|
var defaults, sorter;
|
|
defaults = {
|
|
initialize: true,
|
|
identify: _.stringify,
|
|
datumTokenizer: null,
|
|
queryTokenizer: null,
|
|
sufficient: 5,
|
|
sorter: null,
|
|
local: [],
|
|
prefetch: null,
|
|
remote: null
|
|
};
|
|
o = _.mixin(defaults, o || {});
|
|
!o.datumTokenizer && $.error("datumTokenizer is required");
|
|
!o.queryTokenizer && $.error("queryTokenizer is required");
|
|
sorter = o.sorter;
|
|
o.sorter = sorter ? function(x) {
|
|
return x.sort(sorter);
|
|
} : _.identity;
|
|
o.local = _.isFunction(o.local) ? o.local() : o.local;
|
|
o.prefetch = parsePrefetch(o.prefetch);
|
|
o.remote = parseRemote(o.remote);
|
|
return o;
|
|
};
|
|
function parsePrefetch(o) {
|
|
var defaults;
|
|
if (!o) {
|
|
return null;
|
|
}
|
|
defaults = {
|
|
url: null,
|
|
ttl: 24 * 60 * 60 * 1e3,
|
|
cache: true,
|
|
cacheKey: null,
|
|
thumbprint: "",
|
|
prepare: _.identity,
|
|
transform: _.identity,
|
|
transport: null
|
|
};
|
|
o = _.isString(o) ? {
|
|
url: o
|
|
} : o;
|
|
o = _.mixin(defaults, o);
|
|
!o.url && $.error("prefetch requires url to be set");
|
|
o.transform = o.filter || o.transform;
|
|
o.cacheKey = o.cacheKey || o.url;
|
|
o.thumbprint = VERSION + o.thumbprint;
|
|
o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
|
|
return o;
|
|
}
|
|
function parseRemote(o) {
|
|
var defaults;
|
|
if (!o) {
|
|
return;
|
|
}
|
|
defaults = {
|
|
url: null,
|
|
cache: true,
|
|
prepare: null,
|
|
replace: null,
|
|
wildcard: null,
|
|
limiter: null,
|
|
rateLimitBy: "debounce",
|
|
rateLimitWait: 300,
|
|
transform: _.identity,
|
|
transport: null
|
|
};
|
|
o = _.isString(o) ? {
|
|
url: o
|
|
} : o;
|
|
o = _.mixin(defaults, o);
|
|
!o.url && $.error("remote requires url to be set");
|
|
o.transform = o.filter || o.transform;
|
|
o.prepare = toRemotePrepare(o);
|
|
o.limiter = toLimiter(o);
|
|
o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
|
|
delete o.replace;
|
|
delete o.wildcard;
|
|
delete o.rateLimitBy;
|
|
delete o.rateLimitWait;
|
|
return o;
|
|
}
|
|
function toRemotePrepare(o) {
|
|
var prepare, replace, wildcard;
|
|
prepare = o.prepare;
|
|
replace = o.replace;
|
|
wildcard = o.wildcard;
|
|
if (prepare) {
|
|
return prepare;
|
|
}
|
|
if (replace) {
|
|
prepare = prepareByReplace;
|
|
} else if (o.wildcard) {
|
|
prepare = prepareByWildcard;
|
|
} else {
|
|
prepare = idenityPrepare;
|
|
}
|
|
return prepare;
|
|
function prepareByReplace(query, settings) {
|
|
settings.url = replace(settings.url, query);
|
|
return settings;
|
|
}
|
|
function prepareByWildcard(query, settings) {
|
|
settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
|
|
return settings;
|
|
}
|
|
function idenityPrepare(query, settings) {
|
|
return settings;
|
|
}
|
|
}
|
|
function toLimiter(o) {
|
|
var limiter, method, wait;
|
|
limiter = o.limiter;
|
|
method = o.rateLimitBy;
|
|
wait = o.rateLimitWait;
|
|
if (!limiter) {
|
|
limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
|
|
}
|
|
return limiter;
|
|
function debounce(wait) {
|
|
return function debounce(fn) {
|
|
return _.debounce(fn, wait);
|
|
};
|
|
}
|
|
function throttle(wait) {
|
|
return function throttle(fn) {
|
|
return _.throttle(fn, wait);
|
|
};
|
|
}
|
|
}
|
|
function callbackToDeferred(fn) {
|
|
return function wrapper(o) {
|
|
var deferred = $.Deferred();
|
|
fn(o, onSuccess, onError);
|
|
return deferred;
|
|
function onSuccess(resp) {
|
|
_.defer(function() {
|
|
deferred.resolve(resp);
|
|
});
|
|
}
|
|
function onError(err) {
|
|
_.defer(function() {
|
|
deferred.reject(err);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
}();
|
|
var Bloodhound = function() {
|
|
"use strict";
|
|
var old;
|
|
old = window && window.Bloodhound;
|
|
function Bloodhound(o) {
|
|
o = oParser(o);
|
|
this.sorter = o.sorter;
|
|
this.identify = o.identify;
|
|
this.sufficient = o.sufficient;
|
|
this.local = o.local;
|
|
this.remote = o.remote ? new Remote(o.remote) : null;
|
|
this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
|
|
this.index = new SearchIndex({
|
|
identify: this.identify,
|
|
datumTokenizer: o.datumTokenizer,
|
|
queryTokenizer: o.queryTokenizer
|
|
});
|
|
o.initialize !== false && this.initialize();
|
|
}
|
|
Bloodhound.noConflict = function noConflict() {
|
|
window && (window.Bloodhound = old);
|
|
return Bloodhound;
|
|
};
|
|
Bloodhound.tokenizers = tokenizers;
|
|
_.mixin(Bloodhound.prototype, {
|
|
__ttAdapter: function ttAdapter() {
|
|
var that = this;
|
|
return this.remote ? withAsync : withoutAsync;
|
|
function withAsync(query, sync, async) {
|
|
return that.search(query, sync, async);
|
|
}
|
|
function withoutAsync(query, sync) {
|
|
return that.search(query, sync);
|
|
}
|
|
},
|
|
_loadPrefetch: function loadPrefetch() {
|
|
var that = this, deferred, serialized;
|
|
deferred = $.Deferred();
|
|
if (!this.prefetch) {
|
|
deferred.resolve();
|
|
} else if (serialized = this.prefetch.fromCache()) {
|
|
this.index.bootstrap(serialized);
|
|
deferred.resolve();
|
|
} else {
|
|
this.prefetch.fromNetwork(done);
|
|
}
|
|
return deferred.promise();
|
|
function done(err, data) {
|
|
if (err) {
|
|
return deferred.reject();
|
|
}
|
|
that.add(data);
|
|
that.prefetch.store(that.index.serialize());
|
|
deferred.resolve();
|
|
}
|
|
},
|
|
_initialize: function initialize() {
|
|
var that = this, deferred;
|
|
this.clear();
|
|
(this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
|
|
return this.initPromise;
|
|
function addLocalToIndex() {
|
|
that.add(that.local);
|
|
}
|
|
},
|
|
initialize: function initialize(force) {
|
|
return !this.initPromise || force ? this._initialize() : this.initPromise;
|
|
},
|
|
add: function add(data) {
|
|
this.index.add(data);
|
|
return this;
|
|
},
|
|
get: function get(ids) {
|
|
ids = _.isArray(ids) ? ids : [].slice.call(arguments);
|
|
return this.index.get(ids);
|
|
},
|
|
search: function search(query, sync, async) {
|
|
var that = this, local;
|
|
local = this.sorter(this.index.search(query));
|
|
sync(this.remote ? local.slice() : local);
|
|
if (this.remote && local.length < this.sufficient) {
|
|
this.remote.get(query, processRemote);
|
|
} else if (this.remote) {
|
|
this.remote.cancelLastRequest();
|
|
}
|
|
return this;
|
|
function processRemote(remote) {
|
|
var nonDuplicates = [];
|
|
_.each(remote, function(r) {
|
|
!_.some(local, function(l) {
|
|
return that.identify(r) === that.identify(l);
|
|
}) && nonDuplicates.push(r);
|
|
});
|
|
async && async(nonDuplicates);
|
|
}
|
|
},
|
|
all: function all() {
|
|
return this.index.all();
|
|
},
|
|
clear: function clear() {
|
|
this.index.reset();
|
|
return this;
|
|
},
|
|
clearPrefetchCache: function clearPrefetchCache() {
|
|
this.prefetch && this.prefetch.clear();
|
|
return this;
|
|
},
|
|
clearRemoteCache: function clearRemoteCache() {
|
|
Transport.resetCache();
|
|
return this;
|
|
},
|
|
ttAdapter: function ttAdapter() {
|
|
return this.__ttAdapter();
|
|
}
|
|
});
|
|
return Bloodhound;
|
|
}();
|
|
return Bloodhound;
|
|
});
|
|
|
|
(function(root, factory) {
|
|
if (typeof define === "function" && define.amd) {
|
|
define("typeahead.js", [ "jquery" ], function(a0) {
|
|
return factory(a0);
|
|
});
|
|
} else if (typeof exports === "object") {
|
|
module.exports = factory(require("jquery"));
|
|
} else {
|
|
factory(jQuery);
|
|
}
|
|
})(this, function($) {
|
|
var _ = function() {
|
|
"use strict";
|
|
return {
|
|
isMsie: function() {
|
|
return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
|
|
},
|
|
isBlankString: function(str) {
|
|
return !str || /^\s*$/.test(str);
|
|
},
|
|
escapeRegExChars: function(str) {
|
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
},
|
|
isString: function(obj) {
|
|
return typeof obj === "string";
|
|
},
|
|
isNumber: function(obj) {
|
|
return typeof obj === "number";
|
|
},
|
|
isArray: $.isArray,
|
|
isFunction: $.isFunction,
|
|
isObject: $.isPlainObject,
|
|
isUndefined: function(obj) {
|
|
return typeof obj === "undefined";
|
|
},
|
|
isElement: function(obj) {
|
|
return !!(obj && obj.nodeType === 1);
|
|
},
|
|
isJQuery: function(obj) {
|
|
return obj instanceof $;
|
|
},
|
|
toStr: function toStr(s) {
|
|
return _.isUndefined(s) || s === null ? "" : s + "";
|
|
},
|
|
bind: $.proxy,
|
|
each: function(collection, cb) {
|
|
$.each(collection, reverseArgs);
|
|
function reverseArgs(index, value) {
|
|
return cb(value, index);
|
|
}
|
|
},
|
|
map: $.map,
|
|
filter: $.grep,
|
|
every: function(obj, test) {
|
|
var result = true;
|
|
if (!obj) {
|
|
return result;
|
|
}
|
|
$.each(obj, function(key, val) {
|
|
if (!(result = test.call(null, val, key, obj))) {
|
|
return false;
|
|
}
|
|
});
|
|
return !!result;
|
|
},
|
|
some: function(obj, test) {
|
|
var result = false;
|
|
if (!obj) {
|
|
return result;
|
|
}
|
|
$.each(obj, function(key, val) {
|
|
if (result = test.call(null, val, key, obj)) {
|
|
return false;
|
|
}
|
|
});
|
|
return !!result;
|
|
},
|
|
mixin: $.extend,
|
|
identity: function(x) {
|
|
return x;
|
|
},
|
|
clone: function(obj) {
|
|
return $.extend(true, {}, obj);
|
|
},
|
|
getIdGenerator: function() {
|
|
var counter = 0;
|
|
return function() {
|
|
return counter++;
|
|
};
|
|
},
|
|
templatify: function templatify(obj) {
|
|
return $.isFunction(obj) ? obj : template;
|
|
function template() {
|
|
return String(obj);
|
|
}
|
|
},
|
|
defer: function(fn) {
|
|
setTimeout(fn, 0);
|
|
},
|
|
debounce: function(func, wait, immediate) {
|
|
var timeout, result;
|
|
return function() {
|
|
var context = this, args = arguments, later, callNow;
|
|
later = function() {
|
|
timeout = null;
|
|
if (!immediate) {
|
|
result = func.apply(context, args);
|
|
}
|
|
};
|
|
callNow = immediate && !timeout;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
if (callNow) {
|
|
result = func.apply(context, args);
|
|
}
|
|
return result;
|
|
};
|
|
},
|
|
throttle: function(func, wait) {
|
|
var context, args, timeout, result, previous, later;
|
|
previous = 0;
|
|
later = function() {
|
|
previous = new Date();
|
|
timeout = null;
|
|
result = func.apply(context, args);
|
|
};
|
|
return function() {
|
|
var now = new Date(), remaining = wait - (now - previous);
|
|
context = this;
|
|
args = arguments;
|
|
if (remaining <= 0) {
|
|
clearTimeout(timeout);
|
|
timeout = null;
|
|
previous = now;
|
|
result = func.apply(context, args);
|
|
} else if (!timeout) {
|
|
timeout = setTimeout(later, remaining);
|
|
}
|
|
return result;
|
|
};
|
|
},
|
|
stringify: function(val) {
|
|
return _.isString(val) ? val : JSON.stringify(val);
|
|
},
|
|
noop: function() {}
|
|
};
|
|
}();
|
|
var WWW = function() {
|
|
"use strict";
|
|
var defaultClassNames = {
|
|
wrapper: "twitter-typeahead",
|
|
input: "tt-input",
|
|
hint: "tt-hint",
|
|
menu: "tt-menu",
|
|
dataset: "tt-dataset",
|
|
suggestion: "tt-suggestion",
|
|
selectable: "tt-selectable",
|
|
empty: "tt-empty",
|
|
open: "tt-open",
|
|
cursor: "tt-cursor",
|
|
highlight: "tt-highlight"
|
|
};
|
|
return build;
|
|
function build(o) {
|
|
var www, classes;
|
|
classes = _.mixin({}, defaultClassNames, o);
|
|
www = {
|
|
css: buildCss(),
|
|
classes: classes,
|
|
html: buildHtml(classes),
|
|
selectors: buildSelectors(classes)
|
|
};
|
|
return {
|
|
css: www.css,
|
|
html: www.html,
|
|
classes: www.classes,
|
|
selectors: www.selectors,
|
|
mixin: function(o) {
|
|
_.mixin(o, www);
|
|
}
|
|
};
|
|
}
|
|
function buildHtml(c) {
|
|
return {
|
|
wrapper: '<span class="' + c.wrapper + '"></span>',
|
|
menu: '<div class="' + c.menu + '"></div>'
|
|
};
|
|
}
|
|
function buildSelectors(classes) {
|
|
var selectors = {};
|
|
_.each(classes, function(v, k) {
|
|
selectors[k] = "." + v;
|
|
});
|
|
return selectors;
|
|
}
|
|
function buildCss() {
|
|
var css = {
|
|
wrapper: {
|
|
position: "relative",
|
|
display: "inline-block"
|
|
},
|
|
hint: {
|
|
position: "absolute",
|
|
top: "0",
|
|
left: "0",
|
|
borderColor: "transparent",
|
|
boxShadow: "none",
|
|
opacity: "1"
|
|
},
|
|
input: {
|
|
position: "relative",
|
|
verticalAlign: "top",
|
|
backgroundColor: "transparent"
|
|
},
|
|
inputWithNoHint: {
|
|
position: "relative",
|
|
verticalAlign: "top"
|
|
},
|
|
menu: {
|
|
position: "absolute",
|
|
top: "100%",
|
|
left: "0",
|
|
zIndex: "100",
|
|
display: "none"
|
|
},
|
|
ltr: {
|
|
left: "0",
|
|
right: "auto"
|
|
},
|
|
rtl: {
|
|
left: "auto",
|
|
right: " 0"
|
|
}
|
|
};
|
|
if (_.isMsie()) {
|
|
_.mixin(css.input, {
|
|
backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
|
|
});
|
|
}
|
|
return css;
|
|
}
|
|
}();
|
|
var EventBus = function() {
|
|
"use strict";
|
|
var namespace, deprecationMap;
|
|
namespace = "typeahead:";
|
|
deprecationMap = {
|
|
render: "rendered",
|
|
cursorchange: "cursorchanged",
|
|
select: "selected",
|
|
autocomplete: "autocompleted"
|
|
};
|
|
function EventBus(o) {
|
|
if (!o || !o.el) {
|
|
$.error("EventBus initialized without el");
|
|
}
|
|
this.$el = $(o.el);
|
|
}
|
|
_.mixin(EventBus.prototype, {
|
|
_trigger: function(type, args) {
|
|
var $e;
|
|
$e = $.Event(namespace + type);
|
|
(args = args || []).unshift($e);
|
|
this.$el.trigger.apply(this.$el, args);
|
|
return $e;
|
|
},
|
|
before: function(type) {
|
|
var args, $e;
|
|
args = [].slice.call(arguments, 1);
|
|
$e = this._trigger("before" + type, args);
|
|
return $e.isDefaultPrevented();
|
|
},
|
|
trigger: function(type) {
|
|
var deprecatedType;
|
|
this._trigger(type, [].slice.call(arguments, 1));
|
|
if (deprecatedType = deprecationMap[type]) {
|
|
this._trigger(deprecatedType, [].slice.call(arguments, 1));
|
|
}
|
|
}
|
|
});
|
|
return EventBus;
|
|
}();
|
|
var EventEmitter = function() {
|
|
"use strict";
|
|
var splitter = /\s+/, nextTick = getNextTick();
|
|
return {
|
|
onSync: onSync,
|
|
onAsync: onAsync,
|
|
off: off,
|
|
trigger: trigger
|
|
};
|
|
function on(method, types, cb, context) {
|
|
var type;
|
|
if (!cb) {
|
|
return this;
|
|
}
|
|
types = types.split(splitter);
|
|
cb = context ? bindContext(cb, context) : cb;
|
|
this._callbacks = this._callbacks || {};
|
|
while (type = types.shift()) {
|
|
this._callbacks[type] = this._callbacks[type] || {
|
|
sync: [],
|
|
async: []
|
|
};
|
|
this._callbacks[type][method].push(cb);
|
|
}
|
|
return this;
|
|
}
|
|
function onAsync(types, cb, context) {
|
|
return on.call(this, "async", types, cb, context);
|
|
}
|
|
function onSync(types, cb, context) {
|
|
return on.call(this, "sync", types, cb, context);
|
|
}
|
|
function off(types) {
|
|
var type;
|
|
if (!this._callbacks) {
|
|
return this;
|
|
}
|
|
types = types.split(splitter);
|
|
while (type = types.shift()) {
|
|
delete this._callbacks[type];
|
|
}
|
|
return this;
|
|
}
|
|
function trigger(types) {
|
|
var type, callbacks, args, syncFlush, asyncFlush;
|
|
if (!this._callbacks) {
|
|
return this;
|
|
}
|
|
types = types.split(splitter);
|
|
args = [].slice.call(arguments, 1);
|
|
while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
|
|
syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
|
|
asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
|
|
syncFlush() && nextTick(asyncFlush);
|
|
}
|
|
return this;
|
|
}
|
|
function getFlush(callbacks, context, args) {
|
|
return flush;
|
|
function flush() {
|
|
var cancelled;
|
|
for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
|
|
cancelled = callbacks[i].apply(context, args) === false;
|
|
}
|
|
return !cancelled;
|
|
}
|
|
}
|
|
function getNextTick() {
|
|
var nextTickFn;
|
|
if (window.setImmediate) {
|
|
nextTickFn = function nextTickSetImmediate(fn) {
|
|
setImmediate(function() {
|
|
fn();
|
|
});
|
|
};
|
|
} else {
|
|
nextTickFn = function nextTickSetTimeout(fn) {
|
|
setTimeout(function() {
|
|
fn();
|
|
}, 0);
|
|
};
|
|
}
|
|
return nextTickFn;
|
|
}
|
|
function bindContext(fn, context) {
|
|
return fn.bind ? fn.bind(context) : function() {
|
|
fn.apply(context, [].slice.call(arguments, 0));
|
|
};
|
|
}
|
|
}();
|
|
var highlight = function(doc) {
|
|
"use strict";
|
|
var defaults = {
|
|
node: null,
|
|
pattern: null,
|
|
tagName: "strong",
|
|
className: null,
|
|
wordsOnly: false,
|
|
caseSensitive: false
|
|
};
|
|
return function hightlight(o) {
|
|
var regex;
|
|
o = _.mixin({}, defaults, o);
|
|
if (!o.node || !o.pattern) {
|
|
return;
|
|
}
|
|
o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
|
|
regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
|
|
traverse(o.node, hightlightTextNode);
|
|
function hightlightTextNode(textNode) {
|
|
var match, patternNode, wrapperNode;
|
|
if (match = regex.exec(textNode.data)) {
|
|
wrapperNode = doc.createElement(o.tagName);
|
|
o.className && (wrapperNode.className = o.className);
|
|
patternNode = textNode.splitText(match.index);
|
|
patternNode.splitText(match[0].length);
|
|
wrapperNode.appendChild(patternNode.cloneNode(true));
|
|
textNode.parentNode.replaceChild(wrapperNode, patternNode);
|
|
}
|
|
return !!match;
|
|
}
|
|
function traverse(el, hightlightTextNode) {
|
|
var childNode, TEXT_NODE_TYPE = 3;
|
|
for (var i = 0; i < el.childNodes.length; i++) {
|
|
childNode = el.childNodes[i];
|
|
if (childNode.nodeType === TEXT_NODE_TYPE) {
|
|
i += hightlightTextNode(childNode) ? 1 : 0;
|
|
} else {
|
|
traverse(childNode, hightlightTextNode);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function getRegex(patterns, caseSensitive, wordsOnly) {
|
|
var escapedPatterns = [], regexStr;
|
|
for (var i = 0, len = patterns.length; i < len; i++) {
|
|
escapedPatterns.push(_.escapeRegExChars(patterns[i]));
|
|
}
|
|
regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
|
|
return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
|
|
}
|
|
}(window.document);
|
|
var Input = function() {
|
|
"use strict";
|
|
var specialKeyCodeMap;
|
|
specialKeyCodeMap = {
|
|
9: "tab",
|
|
27: "esc",
|
|
37: "left",
|
|
39: "right",
|
|
13: "enter",
|
|
38: "up",
|
|
40: "down"
|
|
};
|
|
function Input(o, www) {
|
|
o = o || {};
|
|
if (!o.input) {
|
|
$.error("input is missing");
|
|
}
|
|
www.mixin(this);
|
|
this.$hint = $(o.hint);
|
|
this.$input = $(o.input);
|
|
this.query = this.$input.val();
|
|
this.queryWhenFocused = this.hasFocus() ? this.query : null;
|
|
this.$overflowHelper = buildOverflowHelper(this.$input);
|
|
this._checkLanguageDirection();
|
|
if (this.$hint.length === 0) {
|
|
this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
|
|
}
|
|
}
|
|
Input.normalizeQuery = function(str) {
|
|
return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
|
|
};
|
|
_.mixin(Input.prototype, EventEmitter, {
|
|
_onBlur: function onBlur() {
|
|
this.resetInputValue();
|
|
this.trigger("blurred");
|
|
},
|
|
_onFocus: function onFocus() {
|
|
this.queryWhenFocused = this.query;
|
|
this.trigger("focused");
|
|
},
|
|
_onKeydown: function onKeydown($e) {
|
|
var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
|
|
this._managePreventDefault(keyName, $e);
|
|
if (keyName && this._shouldTrigger(keyName, $e)) {
|
|
this.trigger(keyName + "Keyed", $e);
|
|
}
|
|
},
|
|
_onInput: function onInput() {
|
|
this._setQuery(this.getInputValue());
|
|
this.clearHintIfInvalid();
|
|
this._checkLanguageDirection();
|
|
},
|
|
_managePreventDefault: function managePreventDefault(keyName, $e) {
|
|
var preventDefault;
|
|
switch (keyName) {
|
|
case "up":
|
|
case "down":
|
|
preventDefault = !withModifier($e);
|
|
break;
|
|
|
|
default:
|
|
preventDefault = false;
|
|
}
|
|
preventDefault && $e.preventDefault();
|
|
},
|
|
_shouldTrigger: function shouldTrigger(keyName, $e) {
|
|
var trigger;
|
|
switch (keyName) {
|
|
case "tab":
|
|
trigger = !withModifier($e);
|
|
break;
|
|
|
|
default:
|
|
trigger = true;
|
|
}
|
|
return trigger;
|
|
},
|
|
_checkLanguageDirection: function checkLanguageDirection() {
|
|
var dir = (this.$input.css("direction") || "ltr").toLowerCase();
|
|
if (this.dir !== dir) {
|
|
this.dir = dir;
|
|
this.$hint.attr("dir", dir);
|
|
this.trigger("langDirChanged", dir);
|
|
}
|
|
},
|
|
_setQuery: function setQuery(val, silent) {
|
|
var areEquivalent, hasDifferentWhitespace;
|
|
areEquivalent = areQueriesEquivalent(val, this.query);
|
|
hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
|
|
this.query = val;
|
|
if (!silent && !areEquivalent) {
|
|
this.trigger("queryChanged", this.query);
|
|
} else if (!silent && hasDifferentWhitespace) {
|
|
this.trigger("whitespaceChanged", this.query);
|
|
}
|
|
},
|
|
bind: function() {
|
|
var that = this, onBlur, onFocus, onKeydown, onInput;
|
|
onBlur = _.bind(this._onBlur, this);
|
|
onFocus = _.bind(this._onFocus, this);
|
|
onKeydown = _.bind(this._onKeydown, this);
|
|
onInput = _.bind(this._onInput, this);
|
|
this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
|
|
if (!_.isMsie() || _.isMsie() > 9) {
|
|
this.$input.on("input.tt", onInput);
|
|
} else {
|
|
this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
|
|
if (specialKeyCodeMap[$e.which || $e.keyCode]) {
|
|
return;
|
|
}
|
|
_.defer(_.bind(that._onInput, that, $e));
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
focus: function focus() {
|
|
this.$input.focus();
|
|
},
|
|
blur: function blur() {
|
|
this.$input.blur();
|
|
},
|
|
getLangDir: function getLangDir() {
|
|
return this.dir;
|
|
},
|
|
getQuery: function getQuery() {
|
|
return this.query || "";
|
|
},
|
|
setQuery: function setQuery(val, silent) {
|
|
this.setInputValue(val);
|
|
this._setQuery(val, silent);
|
|
},
|
|
hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
|
|
return this.query !== this.queryWhenFocused;
|
|
},
|
|
getInputValue: function getInputValue() {
|
|
return this.$input.val();
|
|
},
|
|
setInputValue: function setInputValue(value) {
|
|
this.$input.val(value);
|
|
this.clearHintIfInvalid();
|
|
this._checkLanguageDirection();
|
|
},
|
|
resetInputValue: function resetInputValue() {
|
|
this.setInputValue(this.query);
|
|
},
|
|
getHint: function getHint() {
|
|
return this.$hint.val();
|
|
},
|
|
setHint: function setHint(value) {
|
|
this.$hint.val(value);
|
|
},
|
|
clearHint: function clearHint() {
|
|
this.setHint("");
|
|
},
|
|
clearHintIfInvalid: function clearHintIfInvalid() {
|
|
var val, hint, valIsPrefixOfHint, isValid;
|
|
val = this.getInputValue();
|
|
hint = this.getHint();
|
|
valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
|
|
isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
|
|
!isValid && this.clearHint();
|
|
},
|
|
hasFocus: function hasFocus() {
|
|
return this.$input.is(":focus");
|
|
},
|
|
hasOverflow: function hasOverflow() {
|
|
var constraint = this.$input.width() - 2;
|
|
this.$overflowHelper.text(this.getInputValue());
|
|
return this.$overflowHelper.width() >= constraint;
|
|
},
|
|
isCursorAtEnd: function() {
|
|
var valueLength, selectionStart, range;
|
|
valueLength = this.$input.val().length;
|
|
selectionStart = this.$input[0].selectionStart;
|
|
if (_.isNumber(selectionStart)) {
|
|
return selectionStart === valueLength;
|
|
} else if (document.selection) {
|
|
range = document.selection.createRange();
|
|
range.moveStart("character", -valueLength);
|
|
return valueLength === range.text.length;
|
|
}
|
|
return true;
|
|
},
|
|
destroy: function destroy() {
|
|
this.$hint.off(".tt");
|
|
this.$input.off(".tt");
|
|
this.$overflowHelper.remove();
|
|
this.$hint = this.$input = this.$overflowHelper = $("<div>");
|
|
}
|
|
});
|
|
return Input;
|
|
function buildOverflowHelper($input) {
|
|
return $('<pre aria-hidden="true"></pre>').css({
|
|
position: "absolute",
|
|
visibility: "hidden",
|
|
whiteSpace: "pre",
|
|
fontFamily: $input.css("font-family"),
|
|
fontSize: $input.css("font-size"),
|
|
fontStyle: $input.css("font-style"),
|
|
fontVariant: $input.css("font-variant"),
|
|
fontWeight: $input.css("font-weight"),
|
|
wordSpacing: $input.css("word-spacing"),
|
|
letterSpacing: $input.css("letter-spacing"),
|
|
textIndent: $input.css("text-indent"),
|
|
textRendering: $input.css("text-rendering"),
|
|
textTransform: $input.css("text-transform")
|
|
}).insertAfter($input);
|
|
}
|
|
function areQueriesEquivalent(a, b) {
|
|
return Input.normalizeQuery(a) === Input.normalizeQuery(b);
|
|
}
|
|
function withModifier($e) {
|
|
return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
|
|
}
|
|
}();
|
|
var Dataset = function() {
|
|
"use strict";
|
|
var keys, nameGenerator;
|
|
keys = {
|
|
val: "tt-selectable-display",
|
|
obj: "tt-selectable-object"
|
|
};
|
|
nameGenerator = _.getIdGenerator();
|
|
function Dataset(o, www) {
|
|
o = o || {};
|
|
o.templates = o.templates || {};
|
|
o.templates.notFound = o.templates.notFound || o.templates.empty;
|
|
if (!o.source) {
|
|
$.error("missing source");
|
|
}
|
|
if (!o.node) {
|
|
$.error("missing node");
|
|
}
|
|
if (o.name && !isValidName(o.name)) {
|
|
$.error("invalid dataset name: " + o.name);
|
|
}
|
|
www.mixin(this);
|
|
this.highlight = !!o.highlight;
|
|
this.name = o.name || nameGenerator();
|
|
this.limit = o.limit || 5;
|
|
this.displayFn = getDisplayFn(o.display || o.displayKey);
|
|
this.templates = getTemplates(o.templates, this.displayFn);
|
|
this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
|
|
this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
|
|
this._resetLastSuggestion();
|
|
this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
|
|
}
|
|
Dataset.extractData = function extractData(el) {
|
|
var $el = $(el);
|
|
if ($el.data(keys.obj)) {
|
|
return {
|
|
val: $el.data(keys.val) || "",
|
|
obj: $el.data(keys.obj) || null
|
|
};
|
|
}
|
|
return null;
|
|
};
|
|
_.mixin(Dataset.prototype, EventEmitter, {
|
|
_overwrite: function overwrite(query, suggestions) {
|
|
suggestions = suggestions || [];
|
|
if (suggestions.length) {
|
|
this._renderSuggestions(query, suggestions);
|
|
} else if (this.async && this.templates.pending) {
|
|
this._renderPending(query);
|
|
} else if (!this.async && this.templates.notFound) {
|
|
this._renderNotFound(query);
|
|
} else {
|
|
this._empty();
|
|
}
|
|
this.trigger("rendered", this.name, suggestions, false);
|
|
},
|
|
_append: function append(query, suggestions) {
|
|
suggestions = suggestions || [];
|
|
if (suggestions.length && this.$lastSuggestion.length) {
|
|
this._appendSuggestions(query, suggestions);
|
|
} else if (suggestions.length) {
|
|
this._renderSuggestions(query, suggestions);
|
|
} else if (!this.$lastSuggestion.length && this.templates.notFound) {
|
|
this._renderNotFound(query);
|
|
}
|
|
this.trigger("rendered", this.name, suggestions, true);
|
|
},
|
|
_renderSuggestions: function renderSuggestions(query, suggestions) {
|
|
var $fragment;
|
|
$fragment = this._getSuggestionsFragment(query, suggestions);
|
|
this.$lastSuggestion = $fragment.children().last();
|
|
this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
|
|
},
|
|
_appendSuggestions: function appendSuggestions(query, suggestions) {
|
|
var $fragment, $lastSuggestion;
|
|
$fragment = this._getSuggestionsFragment(query, suggestions);
|
|
$lastSuggestion = $fragment.children().last();
|
|
this.$lastSuggestion.after($fragment);
|
|
this.$lastSuggestion = $lastSuggestion;
|
|
},
|
|
_renderPending: function renderPending(query) {
|
|
var template = this.templates.pending;
|
|
this._resetLastSuggestion();
|
|
template && this.$el.html(template({
|
|
query: query,
|
|
dataset: this.name
|
|
}));
|
|
},
|
|
_renderNotFound: function renderNotFound(query) {
|
|
var template = this.templates.notFound;
|
|
this._resetLastSuggestion();
|
|
template && this.$el.html(template({
|
|
query: query,
|
|
dataset: this.name
|
|
}));
|
|
},
|
|
_empty: function empty() {
|
|
this.$el.empty();
|
|
this._resetLastSuggestion();
|
|
},
|
|
_getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
|
|
var that = this, fragment;
|
|
fragment = document.createDocumentFragment();
|
|
_.each(suggestions, function getSuggestionNode(suggestion) {
|
|
var $el, context;
|
|
context = that._injectQuery(query, suggestion);
|
|
$el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
|
|
fragment.appendChild($el[0]);
|
|
});
|
|
this.highlight && highlight({
|
|
className: this.classes.highlight,
|
|
node: fragment,
|
|
pattern: query
|
|
});
|
|
return $(fragment);
|
|
},
|
|
_getFooter: function getFooter(query, suggestions) {
|
|
return this.templates.footer ? this.templates.footer({
|
|
query: query,
|
|
suggestions: suggestions,
|
|
dataset: this.name
|
|
}) : null;
|
|
},
|
|
_getHeader: function getHeader(query, suggestions) {
|
|
return this.templates.header ? this.templates.header({
|
|
query: query,
|
|
suggestions: suggestions,
|
|
dataset: this.name
|
|
}) : null;
|
|
},
|
|
_resetLastSuggestion: function resetLastSuggestion() {
|
|
this.$lastSuggestion = $();
|
|
},
|
|
_injectQuery: function injectQuery(query, obj) {
|
|
return _.isObject(obj) ? _.mixin({
|
|
_query: query
|
|
}, obj) : obj;
|
|
},
|
|
update: function update(query) {
|
|
var that = this, canceled = false, syncCalled = false, rendered = 0;
|
|
this.cancel();
|
|
this.cancel = function cancel() {
|
|
canceled = true;
|
|
that.cancel = $.noop;
|
|
that.async && that.trigger("asyncCanceled", query);
|
|
};
|
|
this.source(query, sync, async);
|
|
!syncCalled && sync([]);
|
|
function sync(suggestions) {
|
|
if (syncCalled) {
|
|
return;
|
|
}
|
|
syncCalled = true;
|
|
suggestions = (suggestions || []).slice(0, that.limit);
|
|
rendered = suggestions.length;
|
|
that._overwrite(query, suggestions);
|
|
if (rendered < that.limit && that.async) {
|
|
that.trigger("asyncRequested", query);
|
|
}
|
|
}
|
|
function async(suggestions) {
|
|
suggestions = suggestions || [];
|
|
if (!canceled && rendered < that.limit) {
|
|
that.cancel = $.noop;
|
|
rendered += suggestions.length;
|
|
that._append(query, suggestions.slice(0, that.limit - rendered));
|
|
that.async && that.trigger("asyncReceived", query);
|
|
}
|
|
}
|
|
},
|
|
cancel: $.noop,
|
|
clear: function clear() {
|
|
this._empty();
|
|
this.cancel();
|
|
this.trigger("cleared");
|
|
},
|
|
isEmpty: function isEmpty() {
|
|
return this.$el.is(":empty");
|
|
},
|
|
destroy: function destroy() {
|
|
this.$el = $("<div>");
|
|
}
|
|
});
|
|
return Dataset;
|
|
function getDisplayFn(display) {
|
|
display = display || _.stringify;
|
|
return _.isFunction(display) ? display : displayFn;
|
|
function displayFn(obj) {
|
|
return obj[display];
|
|
}
|
|
}
|
|
function getTemplates(templates, displayFn) {
|
|
return {
|
|
notFound: templates.notFound && _.templatify(templates.notFound),
|
|
pending: templates.pending && _.templatify(templates.pending),
|
|
header: templates.header && _.templatify(templates.header),
|
|
footer: templates.footer && _.templatify(templates.footer),
|
|
suggestion: templates.suggestion || suggestionTemplate
|
|
};
|
|
function suggestionTemplate(context) {
|
|
return $("<div>").text(displayFn(context));
|
|
}
|
|
}
|
|
function isValidName(str) {
|
|
return /^[_a-zA-Z0-9-]+$/.test(str);
|
|
}
|
|
}();
|
|
var Menu = function() {
|
|
"use strict";
|
|
function Menu(o, www) {
|
|
var that = this;
|
|
o = o || {};
|
|
if (!o.node) {
|
|
$.error("node is required");
|
|
}
|
|
www.mixin(this);
|
|
this.$node = $(o.node);
|
|
this.query = null;
|
|
this.datasets = _.map(o.datasets, initializeDataset);
|
|
function initializeDataset(oDataset) {
|
|
var node = that.$node.find(oDataset.node).first();
|
|
oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
|
|
return new Dataset(oDataset, www);
|
|
}
|
|
}
|
|
_.mixin(Menu.prototype, EventEmitter, {
|
|
_onSelectableClick: function onSelectableClick($e) {
|
|
this.trigger("selectableClicked", $($e.currentTarget));
|
|
},
|
|
_onRendered: function onRendered(type, dataset, suggestions, async) {
|
|
this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
|
|
this.trigger("datasetRendered", dataset, suggestions, async);
|
|
},
|
|
_onCleared: function onCleared() {
|
|
this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
|
|
this.trigger("datasetCleared");
|
|
},
|
|
_propagate: function propagate() {
|
|
this.trigger.apply(this, arguments);
|
|
},
|
|
_allDatasetsEmpty: function allDatasetsEmpty() {
|
|
return _.every(this.datasets, isDatasetEmpty);
|
|
function isDatasetEmpty(dataset) {
|
|
return dataset.isEmpty();
|
|
}
|
|
},
|
|
_getSelectables: function getSelectables() {
|
|
return this.$node.find(this.selectors.selectable);
|
|
},
|
|
_removeCursor: function _removeCursor() {
|
|
var $selectable = this.getActiveSelectable();
|
|
$selectable && $selectable.removeClass(this.classes.cursor);
|
|
},
|
|
_ensureVisible: function ensureVisible($el) {
|
|
var elTop, elBottom, nodeScrollTop, nodeHeight;
|
|
elTop = $el.position().top;
|
|
elBottom = elTop + $el.outerHeight(true);
|
|
nodeScrollTop = this.$node.scrollTop();
|
|
nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
|
|
if (elTop < 0) {
|
|
this.$node.scrollTop(nodeScrollTop + elTop);
|
|
} else if (nodeHeight < elBottom) {
|
|
this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
|
|
}
|
|
},
|
|
bind: function() {
|
|
var that = this, onSelectableClick;
|
|
onSelectableClick = _.bind(this._onSelectableClick, this);
|
|
this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
|
|
_.each(this.datasets, function(dataset) {
|
|
dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that);
|
|
});
|
|
return this;
|
|
},
|
|
isOpen: function isOpen() {
|
|
return this.$node.hasClass(this.classes.open);
|
|
},
|
|
open: function open() {
|
|
this.$node.addClass(this.classes.open);
|
|
},
|
|
close: function close() {
|
|
this.$node.removeClass(this.classes.open);
|
|
this._removeCursor();
|
|
},
|
|
setLanguageDirection: function setLanguageDirection(dir) {
|
|
this.$node.attr("dir", dir);
|
|
},
|
|
selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
|
|
var $selectables, $oldCursor, oldIndex, newIndex;
|
|
$oldCursor = this.getActiveSelectable();
|
|
$selectables = this._getSelectables();
|
|
oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
|
|
newIndex = oldIndex + delta;
|
|
newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
|
|
newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
|
|
return newIndex === -1 ? null : $selectables.eq(newIndex);
|
|
},
|
|
setCursor: function setCursor($selectable) {
|
|
this._removeCursor();
|
|
if ($selectable = $selectable && $selectable.first()) {
|
|
$selectable.addClass(this.classes.cursor);
|
|
this._ensureVisible($selectable);
|
|
}
|
|
},
|
|
getSelectableData: function getSelectableData($el) {
|
|
return $el && $el.length ? Dataset.extractData($el) : null;
|
|
},
|
|
getActiveSelectable: function getActiveSelectable() {
|
|
var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
|
|
return $selectable.length ? $selectable : null;
|
|
},
|
|
getTopSelectable: function getTopSelectable() {
|
|
var $selectable = this._getSelectables().first();
|
|
return $selectable.length ? $selectable : null;
|
|
},
|
|
update: function update(query) {
|
|
var isValidUpdate = query !== this.query;
|
|
if (isValidUpdate) {
|
|
this.query = query;
|
|
_.each(this.datasets, updateDataset);
|
|
}
|
|
return isValidUpdate;
|
|
function updateDataset(dataset) {
|
|
dataset.update(query);
|
|
}
|
|
},
|
|
empty: function empty() {
|
|
_.each(this.datasets, clearDataset);
|
|
this.query = null;
|
|
this.$node.addClass(this.classes.empty);
|
|
function clearDataset(dataset) {
|
|
dataset.clear();
|
|
}
|
|
},
|
|
destroy: function destroy() {
|
|
this.$node.off(".tt");
|
|
this.$node = $("<div>");
|
|
_.each(this.datasets, destroyDataset);
|
|
function destroyDataset(dataset) {
|
|
dataset.destroy();
|
|
}
|
|
}
|
|
});
|
|
return Menu;
|
|
}();
|
|
var DefaultMenu = function() {
|
|
"use strict";
|
|
var s = Menu.prototype;
|
|
function DefaultMenu() {
|
|
Menu.apply(this, [].slice.call(arguments, 0));
|
|
}
|
|
_.mixin(DefaultMenu.prototype, Menu.prototype, {
|
|
open: function open() {
|
|
!this._allDatasetsEmpty() && this._show();
|
|
return s.open.apply(this, [].slice.call(arguments, 0));
|
|
},
|
|
close: function close() {
|
|
this._hide();
|
|
return s.close.apply(this, [].slice.call(arguments, 0));
|
|
},
|
|
_onRendered: function onRendered() {
|
|
if (this._allDatasetsEmpty()) {
|
|
this._hide();
|
|
} else {
|
|
this.isOpen() && this._show();
|
|
}
|
|
return s._onRendered.apply(this, [].slice.call(arguments, 0));
|
|
},
|
|
_onCleared: function onCleared() {
|
|
if (this._allDatasetsEmpty()) {
|
|
this._hide();
|
|
} else {
|
|
this.isOpen() && this._show();
|
|
}
|
|
return s._onCleared.apply(this, [].slice.call(arguments, 0));
|
|
},
|
|
setLanguageDirection: function setLanguageDirection(dir) {
|
|
this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
|
|
return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
|
|
},
|
|
_hide: function hide() {
|
|
this.$node.hide();
|
|
},
|
|
_show: function show() {
|
|
this.$node.css("display", "block");
|
|
}
|
|
});
|
|
return DefaultMenu;
|
|
}();
|
|
var Typeahead = function() {
|
|
"use strict";
|
|
function Typeahead(o, www) {
|
|
var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
|
|
o = o || {};
|
|
if (!o.input) {
|
|
$.error("missing input");
|
|
}
|
|
if (!o.menu) {
|
|
$.error("missing menu");
|
|
}
|
|
if (!o.eventBus) {
|
|
$.error("missing event bus");
|
|
}
|
|
www.mixin(this);
|
|
this.eventBus = o.eventBus;
|
|
this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
|
|
this.input = o.input;
|
|
this.menu = o.menu;
|
|
this.enabled = true;
|
|
this.active = false;
|
|
this.input.hasFocus() && this.activate();
|
|
this.dir = this.input.getLangDir();
|
|
this._hacks();
|
|
this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this);
|
|
onFocused = c(this, "activate", "open", "_onFocused");
|
|
onBlurred = c(this, "deactivate", "_onBlurred");
|
|
onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
|
|
onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
|
|
onEscKeyed = c(this, "isActive", "_onEscKeyed");
|
|
onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
|
|
onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
|
|
onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
|
|
onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
|
|
onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
|
|
onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
|
|
this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this);
|
|
}
|
|
_.mixin(Typeahead.prototype, {
|
|
_hacks: function hacks() {
|
|
var $input, $menu;
|
|
$input = this.input.$input || $("<div>");
|
|
$menu = this.menu.$node || $("<div>");
|
|
$input.on("blur.tt", function($e) {
|
|
var active, isActive, hasActive;
|
|
active = document.activeElement;
|
|
isActive = $menu.is(active);
|
|
hasActive = $menu.has(active).length > 0;
|
|
if (_.isMsie() && (isActive || hasActive)) {
|
|
$e.preventDefault();
|
|
$e.stopImmediatePropagation();
|
|
_.defer(function() {
|
|
$input.focus();
|
|
});
|
|
}
|
|
});
|
|
$menu.on("mousedown.tt", function($e) {
|
|
$e.preventDefault();
|
|
});
|
|
},
|
|
_onSelectableClicked: function onSelectableClicked(type, $el) {
|
|
this.select($el);
|
|
},
|
|
_onDatasetCleared: function onDatasetCleared() {
|
|
this._updateHint();
|
|
},
|
|
_onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
|
|
this._updateHint();
|
|
this.eventBus.trigger("render", suggestions, async, dataset);
|
|
},
|
|
_onAsyncRequested: function onAsyncRequested(type, dataset, query) {
|
|
this.eventBus.trigger("asyncrequest", query, dataset);
|
|
},
|
|
_onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
|
|
this.eventBus.trigger("asynccancel", query, dataset);
|
|
},
|
|
_onAsyncReceived: function onAsyncReceived(type, dataset, query) {
|
|
this.eventBus.trigger("asyncreceive", query, dataset);
|
|
},
|
|
_onFocused: function onFocused() {
|
|
this._minLengthMet() && this.menu.update(this.input.getQuery());
|
|
},
|
|
_onBlurred: function onBlurred() {
|
|
if (this.input.hasQueryChangedSinceLastFocus()) {
|
|
this.eventBus.trigger("change", this.input.getQuery());
|
|
}
|
|
},
|
|
_onEnterKeyed: function onEnterKeyed(type, $e) {
|
|
var $selectable;
|
|
if ($selectable = this.menu.getActiveSelectable()) {
|
|
this.select($selectable) && $e.preventDefault();
|
|
}
|
|
},
|
|
_onTabKeyed: function onTabKeyed(type, $e) {
|
|
var $selectable;
|
|
if ($selectable = this.menu.getActiveSelectable()) {
|
|
this.select($selectable) && $e.preventDefault();
|
|
} else if ($selectable = this.menu.getTopSelectable()) {
|
|
this.autocomplete($selectable) && $e.preventDefault();
|
|
}
|
|
},
|
|
_onEscKeyed: function onEscKeyed() {
|
|
this.close();
|
|
},
|
|
_onUpKeyed: function onUpKeyed() {
|
|
this.moveCursor(-1);
|
|
},
|
|
_onDownKeyed: function onDownKeyed() {
|
|
this.moveCursor(+1);
|
|
},
|
|
_onLeftKeyed: function onLeftKeyed() {
|
|
if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
|
|
this.autocomplete(this.menu.getTopSelectable());
|
|
}
|
|
},
|
|
_onRightKeyed: function onRightKeyed() {
|
|
if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
|
|
this.autocomplete(this.menu.getTopSelectable());
|
|
}
|
|
},
|
|
_onQueryChanged: function onQueryChanged(e, query) {
|
|
this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
|
|
},
|
|
_onWhitespaceChanged: function onWhitespaceChanged() {
|
|
this._updateHint();
|
|
},
|
|
_onLangDirChanged: function onLangDirChanged(e, dir) {
|
|
if (this.dir !== dir) {
|
|
this.dir = dir;
|
|
this.menu.setLanguageDirection(dir);
|
|
}
|
|
},
|
|
_openIfActive: function openIfActive() {
|
|
this.isActive() && this.open();
|
|
},
|
|
_minLengthMet: function minLengthMet(query) {
|
|
query = _.isString(query) ? query : this.input.getQuery() || "";
|
|
return query.length >= this.minLength;
|
|
},
|
|
_updateHint: function updateHint() {
|
|
var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
|
|
$selectable = this.menu.getTopSelectable();
|
|
data = this.menu.getSelectableData($selectable);
|
|
val = this.input.getInputValue();
|
|
if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
|
|
query = Input.normalizeQuery(val);
|
|
escapedQuery = _.escapeRegExChars(query);
|
|
frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
|
|
match = frontMatchRegEx.exec(data.val);
|
|
match && this.input.setHint(val + match[1]);
|
|
} else {
|
|
this.input.clearHint();
|
|
}
|
|
},
|
|
isEnabled: function isEnabled() {
|
|
return this.enabled;
|
|
},
|
|
enable: function enable() {
|
|
this.enabled = true;
|
|
},
|
|
disable: function disable() {
|
|
this.enabled = false;
|
|
},
|
|
isActive: function isActive() {
|
|
return this.active;
|
|
},
|
|
activate: function activate() {
|
|
if (this.isActive()) {
|
|
return true;
|
|
} else if (!this.isEnabled() || this.eventBus.before("active")) {
|
|
return false;
|
|
} else {
|
|
this.active = true;
|
|
this.eventBus.trigger("active");
|
|
return true;
|
|
}
|
|
},
|
|
deactivate: function deactivate() {
|
|
if (!this.isActive()) {
|
|
return true;
|
|
} else if (this.eventBus.before("idle")) {
|
|
return false;
|
|
} else {
|
|
this.active = false;
|
|
this.close();
|
|
this.eventBus.trigger("idle");
|
|
return true;
|
|
}
|
|
},
|
|
isOpen: function isOpen() {
|
|
return this.menu.isOpen();
|
|
},
|
|
open: function open() {
|
|
if (!this.isOpen() && !this.eventBus.before("open")) {
|
|
this.menu.open();
|
|
this._updateHint();
|
|
this.eventBus.trigger("open");
|
|
}
|
|
return this.isOpen();
|
|
},
|
|
close: function close() {
|
|
if (this.isOpen() && !this.eventBus.before("close")) {
|
|
this.menu.close();
|
|
this.input.clearHint();
|
|
this.input.resetInputValue();
|
|
this.eventBus.trigger("close");
|
|
}
|
|
return !this.isOpen();
|
|
},
|
|
setVal: function setVal(val) {
|
|
this.input.setQuery(_.toStr(val));
|
|
},
|
|
getVal: function getVal() {
|
|
return this.input.getQuery();
|
|
},
|
|
select: function select($selectable) {
|
|
var data = this.menu.getSelectableData($selectable);
|
|
if (data && !this.eventBus.before("select", data.obj)) {
|
|
this.input.setQuery(data.val, true);
|
|
this.eventBus.trigger("select", data.obj);
|
|
this.close();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
autocomplete: function autocomplete($selectable) {
|
|
var query, data, isValid;
|
|
query = this.input.getQuery();
|
|
data = this.menu.getSelectableData($selectable);
|
|
isValid = data && query !== data.val;
|
|
if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
|
|
this.input.setQuery(data.val);
|
|
this.eventBus.trigger("autocomplete", data.obj);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
moveCursor: function moveCursor(delta) {
|
|
var query, $candidate, data, payload, cancelMove;
|
|
query = this.input.getQuery();
|
|
$candidate = this.menu.selectableRelativeToCursor(delta);
|
|
data = this.menu.getSelectableData($candidate);
|
|
payload = data ? data.obj : null;
|
|
cancelMove = this._minLengthMet() && this.menu.update(query);
|
|
if (!cancelMove && !this.eventBus.before("cursorchange", payload)) {
|
|
this.menu.setCursor($candidate);
|
|
if (data) {
|
|
this.input.setInputValue(data.val);
|
|
} else {
|
|
this.input.resetInputValue();
|
|
this._updateHint();
|
|
}
|
|
this.eventBus.trigger("cursorchange", payload);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
destroy: function destroy() {
|
|
this.input.destroy();
|
|
this.menu.destroy();
|
|
}
|
|
});
|
|
return Typeahead;
|
|
function c(ctx) {
|
|
var methods = [].slice.call(arguments, 1);
|
|
return function() {
|
|
var args = [].slice.call(arguments);
|
|
_.each(methods, function(method) {
|
|
return ctx[method].apply(ctx, args);
|
|
});
|
|
};
|
|
}
|
|
}();
|
|
(function() {
|
|
"use strict";
|
|
var old, keys, methods;
|
|
old = $.fn.typeahead;
|
|
keys = {
|
|
www: "tt-www",
|
|
attrs: "tt-attrs",
|
|
typeahead: "tt-typeahead"
|
|
};
|
|
methods = {
|
|
initialize: function initialize(o, datasets) {
|
|
var www;
|
|
datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
|
|
o = o || {};
|
|
www = WWW(o.classNames);
|
|
return this.each(attach);
|
|
function attach() {
|
|
var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor;
|
|
_.each(datasets, function(d) {
|
|
d.highlight = !!o.highlight;
|
|
});
|
|
$input = $(this);
|
|
$wrapper = $(www.html.wrapper);
|
|
$hint = $elOrNull(o.hint);
|
|
$menu = $elOrNull(o.menu);
|
|
defaultHint = o.hint !== false && !$hint;
|
|
defaultMenu = o.menu !== false && !$menu;
|
|
defaultHint && ($hint = buildHintFromInput($input, www));
|
|
defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
|
|
$hint && $hint.val("");
|
|
$input = prepInput($input, www);
|
|
if (defaultHint || defaultMenu) {
|
|
$wrapper.css(www.css.wrapper);
|
|
$input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
|
|
$input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
|
|
}
|
|
MenuConstructor = defaultMenu ? DefaultMenu : Menu;
|
|
eventBus = new EventBus({
|
|
el: $input
|
|
});
|
|
input = new Input({
|
|
hint: $hint,
|
|
input: $input
|
|
}, www);
|
|
menu = new MenuConstructor({
|
|
node: $menu,
|
|
datasets: datasets
|
|
}, www);
|
|
typeahead = new Typeahead({
|
|
input: input,
|
|
menu: menu,
|
|
eventBus: eventBus,
|
|
minLength: o.minLength
|
|
}, www);
|
|
$input.data(keys.www, www);
|
|
$input.data(keys.typeahead, typeahead);
|
|
}
|
|
},
|
|
isEnabled: function isEnabled() {
|
|
var enabled;
|
|
ttEach(this.first(), function(t) {
|
|
enabled = t.isEnabled();
|
|
});
|
|
return enabled;
|
|
},
|
|
enable: function enable() {
|
|
ttEach(this, function(t) {
|
|
t.enable();
|
|
});
|
|
return this;
|
|
},
|
|
disable: function disable() {
|
|
ttEach(this, function(t) {
|
|
t.disable();
|
|
});
|
|
return this;
|
|
},
|
|
isActive: function isActive() {
|
|
var active;
|
|
ttEach(this.first(), function(t) {
|
|
active = t.isActive();
|
|
});
|
|
return active;
|
|
},
|
|
activate: function activate() {
|
|
ttEach(this, function(t) {
|
|
t.activate();
|
|
});
|
|
return this;
|
|
},
|
|
deactivate: function deactivate() {
|
|
ttEach(this, function(t) {
|
|
t.deactivate();
|
|
});
|
|
return this;
|
|
},
|
|
isOpen: function isOpen() {
|
|
var open;
|
|
ttEach(this.first(), function(t) {
|
|
open = t.isOpen();
|
|
});
|
|
return open;
|
|
},
|
|
open: function open() {
|
|
ttEach(this, function(t) {
|
|
t.open();
|
|
});
|
|
return this;
|
|
},
|
|
close: function close() {
|
|
ttEach(this, function(t) {
|
|
t.close();
|
|
});
|
|
return this;
|
|
},
|
|
select: function select(el) {
|
|
var success = false, $el = $(el);
|
|
ttEach(this.first(), function(t) {
|
|
success = t.select($el);
|
|
});
|
|
return success;
|
|
},
|
|
autocomplete: function autocomplete(el) {
|
|
var success = false, $el = $(el);
|
|
ttEach(this.first(), function(t) {
|
|
success = t.autocomplete($el);
|
|
});
|
|
return success;
|
|
},
|
|
moveCursor: function moveCursoe(delta) {
|
|
var success = false;
|
|
ttEach(this.first(), function(t) {
|
|
success = t.moveCursor(delta);
|
|
});
|
|
return success;
|
|
},
|
|
val: function val(newVal) {
|
|
var query;
|
|
if (!arguments.length) {
|
|
ttEach(this.first(), function(t) {
|
|
query = t.getVal();
|
|
});
|
|
return query;
|
|
} else {
|
|
ttEach(this, function(t) {
|
|
t.setVal(newVal);
|
|
});
|
|
return this;
|
|
}
|
|
},
|
|
destroy: function destroy() {
|
|
ttEach(this, function(typeahead, $input) {
|
|
revert($input);
|
|
typeahead.destroy();
|
|
});
|
|
return this;
|
|
}
|
|
};
|
|
$.fn.typeahead = function(method) {
|
|
if (methods[method]) {
|
|
return methods[method].apply(this, [].slice.call(arguments, 1));
|
|
} else {
|
|
return methods.initialize.apply(this, arguments);
|
|
}
|
|
};
|
|
$.fn.typeahead.noConflict = function noConflict() {
|
|
$.fn.typeahead = old;
|
|
return this;
|
|
};
|
|
function ttEach($els, fn) {
|
|
$els.each(function() {
|
|
var $input = $(this), typeahead;
|
|
(typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
|
|
});
|
|
}
|
|
function buildHintFromInput($input, www) {
|
|
return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({
|
|
autocomplete: "off",
|
|
spellcheck: "false",
|
|
tabindex: -1
|
|
});
|
|
}
|
|
function prepInput($input, www) {
|
|
$input.data(keys.attrs, {
|
|
dir: $input.attr("dir"),
|
|
autocomplete: $input.attr("autocomplete"),
|
|
spellcheck: $input.attr("spellcheck"),
|
|
style: $input.attr("style")
|
|
});
|
|
$input.addClass(www.classes.input).attr({
|
|
autocomplete: "off",
|
|
spellcheck: false
|
|
});
|
|
try {
|
|
!$input.attr("dir") && $input.attr("dir", "auto");
|
|
} catch (e) {}
|
|
return $input;
|
|
}
|
|
function getBackgroundStyles($el) {
|
|
return {
|
|
backgroundAttachment: $el.css("background-attachment"),
|
|
backgroundClip: $el.css("background-clip"),
|
|
backgroundColor: $el.css("background-color"),
|
|
backgroundImage: $el.css("background-image"),
|
|
backgroundOrigin: $el.css("background-origin"),
|
|
backgroundPosition: $el.css("background-position"),
|
|
backgroundRepeat: $el.css("background-repeat"),
|
|
backgroundSize: $el.css("background-size")
|
|
};
|
|
}
|
|
function revert($input) {
|
|
var www, $wrapper;
|
|
www = $input.data(keys.www);
|
|
$wrapper = $input.parent().filter(www.selectors.wrapper);
|
|
_.each($input.data(keys.attrs), function(val, key) {
|
|
_.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
|
|
});
|
|
$input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
|
|
if ($wrapper.length) {
|
|
$input.detach().insertAfter($wrapper);
|
|
$wrapper.remove();
|
|
}
|
|
}
|
|
function $elOrNull(obj) {
|
|
var isValid, $el;
|
|
isValid = _.isJQuery(obj) || _.isElement(obj);
|
|
$el = isValid ? $(obj).first() : [];
|
|
return $el.length ? $el : null;
|
|
}
|
|
})();
|
|
});
|
|
/*!
|
|
* Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)
|
|
* Copyright 2011-2017 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
*/
|
|
|
|
if (typeof jQuery === 'undefined') {
|
|
throw new Error('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.')
|
|
}
|
|
|
|
+function ($) {
|
|
var version = $.fn.jquery.split(' ')[0].split('.')
|
|
if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] >= 4)) {
|
|
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0')
|
|
}
|
|
}(jQuery);
|
|
|
|
|
|
+function () {
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): util.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Util = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Private TransitionEnd Helpers
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var transition = false;
|
|
|
|
var MAX_UID = 1000000;
|
|
|
|
var TransitionEndEvent = {
|
|
WebkitTransition: 'webkitTransitionEnd',
|
|
MozTransition: 'transitionend',
|
|
OTransition: 'oTransitionEnd otransitionend',
|
|
transition: 'transitionend'
|
|
};
|
|
|
|
// shoutout AngusCroll (https://goo.gl/pxwQGp)
|
|
function toType(obj) {
|
|
return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
|
|
}
|
|
|
|
function isElement(obj) {
|
|
return (obj[0] || obj).nodeType;
|
|
}
|
|
|
|
function getSpecialTransitionEndEvent() {
|
|
return {
|
|
bindType: transition.end,
|
|
delegateType: transition.end,
|
|
handle: function handle(event) {
|
|
if ($(event.target).is(this)) {
|
|
return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
|
|
}
|
|
return undefined;
|
|
}
|
|
};
|
|
}
|
|
|
|
function transitionEndTest() {
|
|
if (window.QUnit) {
|
|
return false;
|
|
}
|
|
|
|
var el = document.createElement('bootstrap');
|
|
|
|
for (var name in TransitionEndEvent) {
|
|
if (el.style[name] !== undefined) {
|
|
return {
|
|
end: TransitionEndEvent[name]
|
|
};
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function transitionEndEmulator(duration) {
|
|
var _this = this;
|
|
|
|
var called = false;
|
|
|
|
$(this).one(Util.TRANSITION_END, function () {
|
|
called = true;
|
|
});
|
|
|
|
setTimeout(function () {
|
|
if (!called) {
|
|
Util.triggerTransitionEnd(_this);
|
|
}
|
|
}, duration);
|
|
|
|
return this;
|
|
}
|
|
|
|
function setTransitionEndSupport() {
|
|
transition = transitionEndTest();
|
|
|
|
$.fn.emulateTransitionEnd = transitionEndEmulator;
|
|
|
|
if (Util.supportsTransitionEnd()) {
|
|
$.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Public Util Api
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Util = {
|
|
|
|
TRANSITION_END: 'bsTransitionEnd',
|
|
|
|
getUID: function getUID(prefix) {
|
|
do {
|
|
// eslint-disable-next-line no-bitwise
|
|
prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
|
|
} while (document.getElementById(prefix));
|
|
return prefix;
|
|
},
|
|
getSelectorFromElement: function getSelectorFromElement(element) {
|
|
var selector = element.getAttribute('data-target');
|
|
|
|
if (!selector) {
|
|
selector = element.getAttribute('href') || '';
|
|
selector = /^#[a-z]/i.test(selector) ? selector : null;
|
|
}
|
|
|
|
return selector;
|
|
},
|
|
reflow: function reflow(element) {
|
|
return element.offsetHeight;
|
|
},
|
|
triggerTransitionEnd: function triggerTransitionEnd(element) {
|
|
$(element).trigger(transition.end);
|
|
},
|
|
supportsTransitionEnd: function supportsTransitionEnd() {
|
|
return Boolean(transition);
|
|
},
|
|
typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
|
|
for (var property in configTypes) {
|
|
if (configTypes.hasOwnProperty(property)) {
|
|
var expectedTypes = configTypes[property];
|
|
var value = config[property];
|
|
var valueType = value && isElement(value) ? 'element' : toType(value);
|
|
|
|
if (!new RegExp(expectedTypes).test(valueType)) {
|
|
throw new Error(componentName.toUpperCase() + ': ' + ('Option "' + property + '" provided type "' + valueType + '" ') + ('but expected type "' + expectedTypes + '".'));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
setTransitionEndSupport();
|
|
|
|
return Util;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): alert.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Alert = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'alert';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.alert';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var TRANSITION_DURATION = 150;
|
|
|
|
var Selector = {
|
|
DISMISS: '[data-dismiss="alert"]'
|
|
};
|
|
|
|
var Event = {
|
|
CLOSE: 'close' + EVENT_KEY,
|
|
CLOSED: 'closed' + EVENT_KEY,
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
ALERT: 'alert',
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Alert = function () {
|
|
function Alert(element) {
|
|
_classCallCheck(this, Alert);
|
|
|
|
this._element = element;
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Alert.prototype.close = function close(element) {
|
|
element = element || this._element;
|
|
|
|
var rootElement = this._getRootElement(element);
|
|
var customEvent = this._triggerCloseEvent(rootElement);
|
|
|
|
if (customEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
this._removeElement(rootElement);
|
|
};
|
|
|
|
Alert.prototype.dispose = function dispose() {
|
|
$.removeData(this._element, DATA_KEY);
|
|
this._element = null;
|
|
};
|
|
|
|
// private
|
|
|
|
Alert.prototype._getRootElement = function _getRootElement(element) {
|
|
var selector = Util.getSelectorFromElement(element);
|
|
var parent = false;
|
|
|
|
if (selector) {
|
|
parent = $(selector)[0];
|
|
}
|
|
|
|
if (!parent) {
|
|
parent = $(element).closest('.' + ClassName.ALERT)[0];
|
|
}
|
|
|
|
return parent;
|
|
};
|
|
|
|
Alert.prototype._triggerCloseEvent = function _triggerCloseEvent(element) {
|
|
var closeEvent = $.Event(Event.CLOSE);
|
|
|
|
$(element).trigger(closeEvent);
|
|
return closeEvent;
|
|
};
|
|
|
|
Alert.prototype._removeElement = function _removeElement(element) {
|
|
var _this2 = this;
|
|
|
|
$(element).removeClass(ClassName.SHOW);
|
|
|
|
if (!Util.supportsTransitionEnd() || !$(element).hasClass(ClassName.FADE)) {
|
|
this._destroyElement(element);
|
|
return;
|
|
}
|
|
|
|
$(element).one(Util.TRANSITION_END, function (event) {
|
|
return _this2._destroyElement(element, event);
|
|
}).emulateTransitionEnd(TRANSITION_DURATION);
|
|
};
|
|
|
|
Alert.prototype._destroyElement = function _destroyElement(element) {
|
|
$(element).detach().trigger(Event.CLOSED).remove();
|
|
};
|
|
|
|
// static
|
|
|
|
Alert._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var $element = $(this);
|
|
var data = $element.data(DATA_KEY);
|
|
|
|
if (!data) {
|
|
data = new Alert(this);
|
|
$element.data(DATA_KEY, data);
|
|
}
|
|
|
|
if (config === 'close') {
|
|
data[config](this);
|
|
}
|
|
});
|
|
};
|
|
|
|
Alert._handleDismiss = function _handleDismiss(alertInstance) {
|
|
return function (event) {
|
|
if (event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
alertInstance.close(this);
|
|
};
|
|
};
|
|
|
|
_createClass(Alert, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}]);
|
|
|
|
return Alert;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Alert._jQueryInterface;
|
|
$.fn[NAME].Constructor = Alert;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Alert._jQueryInterface;
|
|
};
|
|
|
|
return Alert;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): button.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Button = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'button';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.button';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
|
|
var ClassName = {
|
|
ACTIVE: 'active',
|
|
BUTTON: 'btn',
|
|
FOCUS: 'focus'
|
|
};
|
|
|
|
var Selector = {
|
|
DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
|
|
DATA_TOGGLE: '[data-toggle="buttons"]',
|
|
INPUT: 'input',
|
|
ACTIVE: '.active',
|
|
BUTTON: '.btn'
|
|
};
|
|
|
|
var Event = {
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
|
|
FOCUS_BLUR_DATA_API: 'focus' + EVENT_KEY + DATA_API_KEY + ' ' + ('blur' + EVENT_KEY + DATA_API_KEY)
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Button = function () {
|
|
function Button(element) {
|
|
_classCallCheck(this, Button);
|
|
|
|
this._element = element;
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Button.prototype.toggle = function toggle() {
|
|
var triggerChangeEvent = true;
|
|
var rootElement = $(this._element).closest(Selector.DATA_TOGGLE)[0];
|
|
|
|
if (rootElement) {
|
|
var input = $(this._element).find(Selector.INPUT)[0];
|
|
|
|
if (input) {
|
|
if (input.type === 'radio') {
|
|
if (input.checked && $(this._element).hasClass(ClassName.ACTIVE)) {
|
|
triggerChangeEvent = false;
|
|
} else {
|
|
var activeElement = $(rootElement).find(Selector.ACTIVE)[0];
|
|
|
|
if (activeElement) {
|
|
$(activeElement).removeClass(ClassName.ACTIVE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (triggerChangeEvent) {
|
|
input.checked = !$(this._element).hasClass(ClassName.ACTIVE);
|
|
$(input).trigger('change');
|
|
}
|
|
|
|
input.focus();
|
|
}
|
|
}
|
|
|
|
this._element.setAttribute('aria-pressed', !$(this._element).hasClass(ClassName.ACTIVE));
|
|
|
|
if (triggerChangeEvent) {
|
|
$(this._element).toggleClass(ClassName.ACTIVE);
|
|
}
|
|
};
|
|
|
|
Button.prototype.dispose = function dispose() {
|
|
$.removeData(this._element, DATA_KEY);
|
|
this._element = null;
|
|
};
|
|
|
|
// static
|
|
|
|
Button._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
|
|
if (!data) {
|
|
data = new Button(this);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (config === 'toggle') {
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(Button, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}]);
|
|
|
|
return Button;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
|
|
event.preventDefault();
|
|
|
|
var button = event.target;
|
|
|
|
if (!$(button).hasClass(ClassName.BUTTON)) {
|
|
button = $(button).closest(Selector.BUTTON);
|
|
}
|
|
|
|
Button._jQueryInterface.call($(button), 'toggle');
|
|
}).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
|
|
var button = $(event.target).closest(Selector.BUTTON)[0];
|
|
$(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type));
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Button._jQueryInterface;
|
|
$.fn[NAME].Constructor = Button;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Button._jQueryInterface;
|
|
};
|
|
|
|
return Button;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): carousel.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Carousel = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'carousel';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.carousel';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var TRANSITION_DURATION = 600;
|
|
var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
|
|
var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
|
|
|
|
var Default = {
|
|
interval: 5000,
|
|
keyboard: true,
|
|
slide: false,
|
|
pause: 'hover',
|
|
wrap: true
|
|
};
|
|
|
|
var DefaultType = {
|
|
interval: '(number|boolean)',
|
|
keyboard: 'boolean',
|
|
slide: '(boolean|string)',
|
|
pause: '(string|boolean)',
|
|
wrap: 'boolean'
|
|
};
|
|
|
|
var Direction = {
|
|
NEXT: 'next',
|
|
PREV: 'prev',
|
|
LEFT: 'left',
|
|
RIGHT: 'right'
|
|
};
|
|
|
|
var Event = {
|
|
SLIDE: 'slide' + EVENT_KEY,
|
|
SLID: 'slid' + EVENT_KEY,
|
|
KEYDOWN: 'keydown' + EVENT_KEY,
|
|
MOUSEENTER: 'mouseenter' + EVENT_KEY,
|
|
MOUSELEAVE: 'mouseleave' + EVENT_KEY,
|
|
LOAD_DATA_API: 'load' + EVENT_KEY + DATA_API_KEY,
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
CAROUSEL: 'carousel',
|
|
ACTIVE: 'active',
|
|
SLIDE: 'slide',
|
|
RIGHT: 'carousel-item-right',
|
|
LEFT: 'carousel-item-left',
|
|
NEXT: 'carousel-item-next',
|
|
PREV: 'carousel-item-prev',
|
|
ITEM: 'carousel-item'
|
|
};
|
|
|
|
var Selector = {
|
|
ACTIVE: '.active',
|
|
ACTIVE_ITEM: '.active.carousel-item',
|
|
ITEM: '.carousel-item',
|
|
NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
|
|
INDICATORS: '.carousel-indicators',
|
|
DATA_SLIDE: '[data-slide], [data-slide-to]',
|
|
DATA_RIDE: '[data-ride="carousel"]'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Carousel = function () {
|
|
function Carousel(element, config) {
|
|
_classCallCheck(this, Carousel);
|
|
|
|
this._items = null;
|
|
this._interval = null;
|
|
this._activeElement = null;
|
|
|
|
this._isPaused = false;
|
|
this._isSliding = false;
|
|
|
|
this._config = this._getConfig(config);
|
|
this._element = $(element)[0];
|
|
this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0];
|
|
|
|
this._addEventListeners();
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Carousel.prototype.next = function next() {
|
|
if (this._isSliding) {
|
|
throw new Error('Carousel is sliding');
|
|
}
|
|
this._slide(Direction.NEXT);
|
|
};
|
|
|
|
Carousel.prototype.nextWhenVisible = function nextWhenVisible() {
|
|
// Don't call next when the page isn't visible
|
|
if (!document.hidden) {
|
|
this.next();
|
|
}
|
|
};
|
|
|
|
Carousel.prototype.prev = function prev() {
|
|
if (this._isSliding) {
|
|
throw new Error('Carousel is sliding');
|
|
}
|
|
this._slide(Direction.PREVIOUS);
|
|
};
|
|
|
|
Carousel.prototype.pause = function pause(event) {
|
|
if (!event) {
|
|
this._isPaused = true;
|
|
}
|
|
|
|
if ($(this._element).find(Selector.NEXT_PREV)[0] && Util.supportsTransitionEnd()) {
|
|
Util.triggerTransitionEnd(this._element);
|
|
this.cycle(true);
|
|
}
|
|
|
|
clearInterval(this._interval);
|
|
this._interval = null;
|
|
};
|
|
|
|
Carousel.prototype.cycle = function cycle(event) {
|
|
if (!event) {
|
|
this._isPaused = false;
|
|
}
|
|
|
|
if (this._interval) {
|
|
clearInterval(this._interval);
|
|
this._interval = null;
|
|
}
|
|
|
|
if (this._config.interval && !this._isPaused) {
|
|
this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
|
|
}
|
|
};
|
|
|
|
Carousel.prototype.to = function to(index) {
|
|
var _this3 = this;
|
|
|
|
this._activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0];
|
|
|
|
var activeIndex = this._getItemIndex(this._activeElement);
|
|
|
|
if (index > this._items.length - 1 || index < 0) {
|
|
return;
|
|
}
|
|
|
|
if (this._isSliding) {
|
|
$(this._element).one(Event.SLID, function () {
|
|
return _this3.to(index);
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (activeIndex === index) {
|
|
this.pause();
|
|
this.cycle();
|
|
return;
|
|
}
|
|
|
|
var direction = index > activeIndex ? Direction.NEXT : Direction.PREVIOUS;
|
|
|
|
this._slide(direction, this._items[index]);
|
|
};
|
|
|
|
Carousel.prototype.dispose = function dispose() {
|
|
$(this._element).off(EVENT_KEY);
|
|
$.removeData(this._element, DATA_KEY);
|
|
|
|
this._items = null;
|
|
this._config = null;
|
|
this._element = null;
|
|
this._interval = null;
|
|
this._isPaused = null;
|
|
this._isSliding = null;
|
|
this._activeElement = null;
|
|
this._indicatorsElement = null;
|
|
};
|
|
|
|
// private
|
|
|
|
Carousel.prototype._getConfig = function _getConfig(config) {
|
|
config = $.extend({}, Default, config);
|
|
Util.typeCheckConfig(NAME, config, DefaultType);
|
|
return config;
|
|
};
|
|
|
|
Carousel.prototype._addEventListeners = function _addEventListeners() {
|
|
var _this4 = this;
|
|
|
|
if (this._config.keyboard) {
|
|
$(this._element).on(Event.KEYDOWN, function (event) {
|
|
return _this4._keydown(event);
|
|
});
|
|
}
|
|
|
|
if (this._config.pause === 'hover' && !('ontouchstart' in document.documentElement)) {
|
|
$(this._element).on(Event.MOUSEENTER, function (event) {
|
|
return _this4.pause(event);
|
|
}).on(Event.MOUSELEAVE, function (event) {
|
|
return _this4.cycle(event);
|
|
});
|
|
}
|
|
};
|
|
|
|
Carousel.prototype._keydown = function _keydown(event) {
|
|
if (/input|textarea/i.test(event.target.tagName)) {
|
|
return;
|
|
}
|
|
|
|
switch (event.which) {
|
|
case ARROW_LEFT_KEYCODE:
|
|
event.preventDefault();
|
|
this.prev();
|
|
break;
|
|
case ARROW_RIGHT_KEYCODE:
|
|
event.preventDefault();
|
|
this.next();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
};
|
|
|
|
Carousel.prototype._getItemIndex = function _getItemIndex(element) {
|
|
this._items = $.makeArray($(element).parent().find(Selector.ITEM));
|
|
return this._items.indexOf(element);
|
|
};
|
|
|
|
Carousel.prototype._getItemByDirection = function _getItemByDirection(direction, activeElement) {
|
|
var isNextDirection = direction === Direction.NEXT;
|
|
var isPrevDirection = direction === Direction.PREVIOUS;
|
|
var activeIndex = this._getItemIndex(activeElement);
|
|
var lastItemIndex = this._items.length - 1;
|
|
var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
|
|
|
|
if (isGoingToWrap && !this._config.wrap) {
|
|
return activeElement;
|
|
}
|
|
|
|
var delta = direction === Direction.PREVIOUS ? -1 : 1;
|
|
var itemIndex = (activeIndex + delta) % this._items.length;
|
|
|
|
return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
|
|
};
|
|
|
|
Carousel.prototype._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
|
|
var slideEvent = $.Event(Event.SLIDE, {
|
|
relatedTarget: relatedTarget,
|
|
direction: eventDirectionName
|
|
});
|
|
|
|
$(this._element).trigger(slideEvent);
|
|
|
|
return slideEvent;
|
|
};
|
|
|
|
Carousel.prototype._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
|
|
if (this._indicatorsElement) {
|
|
$(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
|
|
|
|
var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];
|
|
|
|
if (nextIndicator) {
|
|
$(nextIndicator).addClass(ClassName.ACTIVE);
|
|
}
|
|
}
|
|
};
|
|
|
|
Carousel.prototype._slide = function _slide(direction, element) {
|
|
var _this5 = this;
|
|
|
|
var activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0];
|
|
var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
|
|
|
|
var isCycling = Boolean(this._interval);
|
|
|
|
var directionalClassName = void 0;
|
|
var orderClassName = void 0;
|
|
var eventDirectionName = void 0;
|
|
|
|
if (direction === Direction.NEXT) {
|
|
directionalClassName = ClassName.LEFT;
|
|
orderClassName = ClassName.NEXT;
|
|
eventDirectionName = Direction.LEFT;
|
|
} else {
|
|
directionalClassName = ClassName.RIGHT;
|
|
orderClassName = ClassName.PREV;
|
|
eventDirectionName = Direction.RIGHT;
|
|
}
|
|
|
|
if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) {
|
|
this._isSliding = false;
|
|
return;
|
|
}
|
|
|
|
var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
|
|
if (slideEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
if (!activeElement || !nextElement) {
|
|
// some weirdness is happening, so we bail
|
|
return;
|
|
}
|
|
|
|
this._isSliding = true;
|
|
|
|
if (isCycling) {
|
|
this.pause();
|
|
}
|
|
|
|
this._setActiveIndicatorElement(nextElement);
|
|
|
|
var slidEvent = $.Event(Event.SLID, {
|
|
relatedTarget: nextElement,
|
|
direction: eventDirectionName
|
|
});
|
|
|
|
if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.SLIDE)) {
|
|
|
|
$(nextElement).addClass(orderClassName);
|
|
|
|
Util.reflow(nextElement);
|
|
|
|
$(activeElement).addClass(directionalClassName);
|
|
$(nextElement).addClass(directionalClassName);
|
|
|
|
$(activeElement).one(Util.TRANSITION_END, function () {
|
|
$(nextElement).removeClass(directionalClassName + ' ' + orderClassName).addClass(ClassName.ACTIVE);
|
|
|
|
$(activeElement).removeClass(ClassName.ACTIVE + ' ' + orderClassName + ' ' + directionalClassName);
|
|
|
|
_this5._isSliding = false;
|
|
|
|
setTimeout(function () {
|
|
return $(_this5._element).trigger(slidEvent);
|
|
}, 0);
|
|
}).emulateTransitionEnd(TRANSITION_DURATION);
|
|
} else {
|
|
$(activeElement).removeClass(ClassName.ACTIVE);
|
|
$(nextElement).addClass(ClassName.ACTIVE);
|
|
|
|
this._isSliding = false;
|
|
$(this._element).trigger(slidEvent);
|
|
}
|
|
|
|
if (isCycling) {
|
|
this.cycle();
|
|
}
|
|
};
|
|
|
|
// static
|
|
|
|
Carousel._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
var _config = $.extend({}, Default, $(this).data());
|
|
|
|
if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
|
|
$.extend(_config, config);
|
|
}
|
|
|
|
var action = typeof config === 'string' ? config : _config.slide;
|
|
|
|
if (!data) {
|
|
data = new Carousel(this, _config);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'number') {
|
|
data.to(config);
|
|
} else if (typeof action === 'string') {
|
|
if (data[action] === undefined) {
|
|
throw new Error('No method named "' + action + '"');
|
|
}
|
|
data[action]();
|
|
} else if (_config.interval) {
|
|
data.pause();
|
|
data.cycle();
|
|
}
|
|
});
|
|
};
|
|
|
|
Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
|
|
var selector = Util.getSelectorFromElement(this);
|
|
|
|
if (!selector) {
|
|
return;
|
|
}
|
|
|
|
var target = $(selector)[0];
|
|
|
|
if (!target || !$(target).hasClass(ClassName.CAROUSEL)) {
|
|
return;
|
|
}
|
|
|
|
var config = $.extend({}, $(target).data(), $(this).data());
|
|
var slideIndex = this.getAttribute('data-slide-to');
|
|
|
|
if (slideIndex) {
|
|
config.interval = false;
|
|
}
|
|
|
|
Carousel._jQueryInterface.call($(target), config);
|
|
|
|
if (slideIndex) {
|
|
$(target).data(DATA_KEY).to(slideIndex);
|
|
}
|
|
|
|
event.preventDefault();
|
|
};
|
|
|
|
_createClass(Carousel, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
}
|
|
}]);
|
|
|
|
return Carousel;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler);
|
|
|
|
$(window).on(Event.LOAD_DATA_API, function () {
|
|
$(Selector.DATA_RIDE).each(function () {
|
|
var $carousel = $(this);
|
|
Carousel._jQueryInterface.call($carousel, $carousel.data());
|
|
});
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Carousel._jQueryInterface;
|
|
$.fn[NAME].Constructor = Carousel;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Carousel._jQueryInterface;
|
|
};
|
|
|
|
return Carousel;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): collapse.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Collapse = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'collapse';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.collapse';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var TRANSITION_DURATION = 600;
|
|
|
|
var Default = {
|
|
toggle: true,
|
|
parent: ''
|
|
};
|
|
|
|
var DefaultType = {
|
|
toggle: 'boolean',
|
|
parent: 'string'
|
|
};
|
|
|
|
var Event = {
|
|
SHOW: 'show' + EVENT_KEY,
|
|
SHOWN: 'shown' + EVENT_KEY,
|
|
HIDE: 'hide' + EVENT_KEY,
|
|
HIDDEN: 'hidden' + EVENT_KEY,
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
SHOW: 'show',
|
|
COLLAPSE: 'collapse',
|
|
COLLAPSING: 'collapsing',
|
|
COLLAPSED: 'collapsed'
|
|
};
|
|
|
|
var Dimension = {
|
|
WIDTH: 'width',
|
|
HEIGHT: 'height'
|
|
};
|
|
|
|
var Selector = {
|
|
ACTIVES: '.card > .show, .card > .collapsing',
|
|
DATA_TOGGLE: '[data-toggle="collapse"]'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Collapse = function () {
|
|
function Collapse(element, config) {
|
|
_classCallCheck(this, Collapse);
|
|
|
|
this._isTransitioning = false;
|
|
this._element = element;
|
|
this._config = this._getConfig(config);
|
|
this._triggerArray = $.makeArray($('[data-toggle="collapse"][href="#' + element.id + '"],' + ('[data-toggle="collapse"][data-target="#' + element.id + '"]')));
|
|
|
|
this._parent = this._config.parent ? this._getParent() : null;
|
|
|
|
if (!this._config.parent) {
|
|
this._addAriaAndCollapsedClass(this._element, this._triggerArray);
|
|
}
|
|
|
|
if (this._config.toggle) {
|
|
this.toggle();
|
|
}
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Collapse.prototype.toggle = function toggle() {
|
|
if ($(this._element).hasClass(ClassName.SHOW)) {
|
|
this.hide();
|
|
} else {
|
|
this.show();
|
|
}
|
|
};
|
|
|
|
Collapse.prototype.show = function show() {
|
|
var _this6 = this;
|
|
|
|
if (this._isTransitioning) {
|
|
throw new Error('Collapse is transitioning');
|
|
}
|
|
|
|
if ($(this._element).hasClass(ClassName.SHOW)) {
|
|
return;
|
|
}
|
|
|
|
var actives = void 0;
|
|
var activesData = void 0;
|
|
|
|
if (this._parent) {
|
|
actives = $.makeArray($(this._parent).find(Selector.ACTIVES));
|
|
if (!actives.length) {
|
|
actives = null;
|
|
}
|
|
}
|
|
|
|
if (actives) {
|
|
activesData = $(actives).data(DATA_KEY);
|
|
if (activesData && activesData._isTransitioning) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
var startEvent = $.Event(Event.SHOW);
|
|
$(this._element).trigger(startEvent);
|
|
if (startEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
if (actives) {
|
|
Collapse._jQueryInterface.call($(actives), 'hide');
|
|
if (!activesData) {
|
|
$(actives).data(DATA_KEY, null);
|
|
}
|
|
}
|
|
|
|
var dimension = this._getDimension();
|
|
|
|
$(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING);
|
|
|
|
this._element.style[dimension] = 0;
|
|
this._element.setAttribute('aria-expanded', true);
|
|
|
|
if (this._triggerArray.length) {
|
|
$(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true);
|
|
}
|
|
|
|
this.setTransitioning(true);
|
|
|
|
var complete = function complete() {
|
|
$(_this6._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW);
|
|
|
|
_this6._element.style[dimension] = '';
|
|
|
|
_this6.setTransitioning(false);
|
|
|
|
$(_this6._element).trigger(Event.SHOWN);
|
|
};
|
|
|
|
if (!Util.supportsTransitionEnd()) {
|
|
complete();
|
|
return;
|
|
}
|
|
|
|
var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
|
|
var scrollSize = 'scroll' + capitalizedDimension;
|
|
|
|
$(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
|
|
|
|
this._element.style[dimension] = this._element[scrollSize] + 'px';
|
|
};
|
|
|
|
Collapse.prototype.hide = function hide() {
|
|
var _this7 = this;
|
|
|
|
if (this._isTransitioning) {
|
|
throw new Error('Collapse is transitioning');
|
|
}
|
|
|
|
if (!$(this._element).hasClass(ClassName.SHOW)) {
|
|
return;
|
|
}
|
|
|
|
var startEvent = $.Event(Event.HIDE);
|
|
$(this._element).trigger(startEvent);
|
|
if (startEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
var dimension = this._getDimension();
|
|
var offsetDimension = dimension === Dimension.WIDTH ? 'offsetWidth' : 'offsetHeight';
|
|
|
|
this._element.style[dimension] = this._element[offsetDimension] + 'px';
|
|
|
|
Util.reflow(this._element);
|
|
|
|
$(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW);
|
|
|
|
this._element.setAttribute('aria-expanded', false);
|
|
|
|
if (this._triggerArray.length) {
|
|
$(this._triggerArray).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);
|
|
}
|
|
|
|
this.setTransitioning(true);
|
|
|
|
var complete = function complete() {
|
|
_this7.setTransitioning(false);
|
|
$(_this7._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN);
|
|
};
|
|
|
|
this._element.style[dimension] = '';
|
|
|
|
if (!Util.supportsTransitionEnd()) {
|
|
complete();
|
|
return;
|
|
}
|
|
|
|
$(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
|
|
};
|
|
|
|
Collapse.prototype.setTransitioning = function setTransitioning(isTransitioning) {
|
|
this._isTransitioning = isTransitioning;
|
|
};
|
|
|
|
Collapse.prototype.dispose = function dispose() {
|
|
$.removeData(this._element, DATA_KEY);
|
|
|
|
this._config = null;
|
|
this._parent = null;
|
|
this._element = null;
|
|
this._triggerArray = null;
|
|
this._isTransitioning = null;
|
|
};
|
|
|
|
// private
|
|
|
|
Collapse.prototype._getConfig = function _getConfig(config) {
|
|
config = $.extend({}, Default, config);
|
|
config.toggle = Boolean(config.toggle); // coerce string values
|
|
Util.typeCheckConfig(NAME, config, DefaultType);
|
|
return config;
|
|
};
|
|
|
|
Collapse.prototype._getDimension = function _getDimension() {
|
|
var hasWidth = $(this._element).hasClass(Dimension.WIDTH);
|
|
return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
|
|
};
|
|
|
|
Collapse.prototype._getParent = function _getParent() {
|
|
var _this8 = this;
|
|
|
|
var parent = $(this._config.parent)[0];
|
|
var selector = '[data-toggle="collapse"][data-parent="' + this._config.parent + '"]';
|
|
|
|
$(parent).find(selector).each(function (i, element) {
|
|
_this8._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
|
|
});
|
|
|
|
return parent;
|
|
};
|
|
|
|
Collapse.prototype._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
|
|
if (element) {
|
|
var isOpen = $(element).hasClass(ClassName.SHOW);
|
|
element.setAttribute('aria-expanded', isOpen);
|
|
|
|
if (triggerArray.length) {
|
|
$(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
|
|
}
|
|
}
|
|
};
|
|
|
|
// static
|
|
|
|
Collapse._getTargetFromElement = function _getTargetFromElement(element) {
|
|
var selector = Util.getSelectorFromElement(element);
|
|
return selector ? $(selector)[0] : null;
|
|
};
|
|
|
|
Collapse._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var $this = $(this);
|
|
var data = $this.data(DATA_KEY);
|
|
var _config = $.extend({}, Default, $this.data(), (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' && config);
|
|
|
|
if (!data && _config.toggle && /show|hide/.test(config)) {
|
|
_config.toggle = false;
|
|
}
|
|
|
|
if (!data) {
|
|
data = new Collapse(this, _config);
|
|
$this.data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(Collapse, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
}
|
|
}]);
|
|
|
|
return Collapse;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
|
|
event.preventDefault();
|
|
|
|
var target = Collapse._getTargetFromElement(this);
|
|
var data = $(target).data(DATA_KEY);
|
|
var config = data ? 'toggle' : $(this).data();
|
|
|
|
Collapse._jQueryInterface.call($(target), config);
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Collapse._jQueryInterface;
|
|
$.fn[NAME].Constructor = Collapse;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Collapse._jQueryInterface;
|
|
};
|
|
|
|
return Collapse;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): dropdown.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Dropdown = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'dropdown';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.dropdown';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
|
|
var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
|
|
var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
|
|
var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
|
|
|
|
var Event = {
|
|
HIDE: 'hide' + EVENT_KEY,
|
|
HIDDEN: 'hidden' + EVENT_KEY,
|
|
SHOW: 'show' + EVENT_KEY,
|
|
SHOWN: 'shown' + EVENT_KEY,
|
|
CLICK: 'click' + EVENT_KEY,
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
|
|
FOCUSIN_DATA_API: 'focusin' + EVENT_KEY + DATA_API_KEY,
|
|
KEYDOWN_DATA_API: 'keydown' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
BACKDROP: 'dropdown-backdrop',
|
|
DISABLED: 'disabled',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector = {
|
|
BACKDROP: '.dropdown-backdrop',
|
|
DATA_TOGGLE: '[data-toggle="dropdown"]',
|
|
FORM_CHILD: '.dropdown form',
|
|
ROLE_MENU: '[role="menu"]',
|
|
ROLE_LISTBOX: '[role="listbox"]',
|
|
NAVBAR_NAV: '.navbar-nav',
|
|
VISIBLE_ITEMS: '[role="menu"] li:not(.disabled) a, ' + '[role="listbox"] li:not(.disabled) a'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Dropdown = function () {
|
|
function Dropdown(element) {
|
|
_classCallCheck(this, Dropdown);
|
|
|
|
this._element = element;
|
|
|
|
this._addEventListeners();
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Dropdown.prototype.toggle = function toggle() {
|
|
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
|
|
return false;
|
|
}
|
|
|
|
var parent = Dropdown._getParentFromElement(this);
|
|
var isActive = $(parent).hasClass(ClassName.SHOW);
|
|
|
|
Dropdown._clearMenus();
|
|
|
|
if (isActive) {
|
|
return false;
|
|
}
|
|
|
|
if ('ontouchstart' in document.documentElement && !$(parent).closest(Selector.NAVBAR_NAV).length) {
|
|
|
|
// if mobile we use a backdrop because click events don't delegate
|
|
var dropdown = document.createElement('div');
|
|
dropdown.className = ClassName.BACKDROP;
|
|
$(dropdown).insertBefore(this);
|
|
$(dropdown).on('click', Dropdown._clearMenus);
|
|
}
|
|
|
|
var relatedTarget = {
|
|
relatedTarget: this
|
|
};
|
|
var showEvent = $.Event(Event.SHOW, relatedTarget);
|
|
|
|
$(parent).trigger(showEvent);
|
|
|
|
if (showEvent.isDefaultPrevented()) {
|
|
return false;
|
|
}
|
|
|
|
this.focus();
|
|
this.setAttribute('aria-expanded', true);
|
|
|
|
$(parent).toggleClass(ClassName.SHOW);
|
|
$(parent).trigger($.Event(Event.SHOWN, relatedTarget));
|
|
|
|
return false;
|
|
};
|
|
|
|
Dropdown.prototype.dispose = function dispose() {
|
|
$.removeData(this._element, DATA_KEY);
|
|
$(this._element).off(EVENT_KEY);
|
|
this._element = null;
|
|
};
|
|
|
|
// private
|
|
|
|
Dropdown.prototype._addEventListeners = function _addEventListeners() {
|
|
$(this._element).on(Event.CLICK, this.toggle);
|
|
};
|
|
|
|
// static
|
|
|
|
Dropdown._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
|
|
if (!data) {
|
|
data = new Dropdown(this);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config].call(this);
|
|
}
|
|
});
|
|
};
|
|
|
|
Dropdown._clearMenus = function _clearMenus(event) {
|
|
if (event && event.which === RIGHT_MOUSE_BUTTON_WHICH) {
|
|
return;
|
|
}
|
|
|
|
var backdrop = $(Selector.BACKDROP)[0];
|
|
if (backdrop) {
|
|
backdrop.parentNode.removeChild(backdrop);
|
|
}
|
|
|
|
var toggles = $.makeArray($(Selector.DATA_TOGGLE));
|
|
|
|
for (var i = 0; i < toggles.length; i++) {
|
|
var parent = Dropdown._getParentFromElement(toggles[i]);
|
|
var relatedTarget = {
|
|
relatedTarget: toggles[i]
|
|
};
|
|
|
|
if (!$(parent).hasClass(ClassName.SHOW)) {
|
|
continue;
|
|
}
|
|
|
|
if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'focusin') && $.contains(parent, event.target)) {
|
|
continue;
|
|
}
|
|
|
|
var hideEvent = $.Event(Event.HIDE, relatedTarget);
|
|
$(parent).trigger(hideEvent);
|
|
if (hideEvent.isDefaultPrevented()) {
|
|
continue;
|
|
}
|
|
|
|
toggles[i].setAttribute('aria-expanded', 'false');
|
|
|
|
$(parent).removeClass(ClassName.SHOW).trigger($.Event(Event.HIDDEN, relatedTarget));
|
|
}
|
|
};
|
|
|
|
Dropdown._getParentFromElement = function _getParentFromElement(element) {
|
|
var parent = void 0;
|
|
var selector = Util.getSelectorFromElement(element);
|
|
|
|
if (selector) {
|
|
parent = $(selector)[0];
|
|
}
|
|
|
|
return parent || element.parentNode;
|
|
};
|
|
|
|
Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
|
|
if (!/(38|40|27|32)/.test(event.which) || /input|textarea/i.test(event.target.tagName)) {
|
|
return;
|
|
}
|
|
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
|
|
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
|
|
return;
|
|
}
|
|
|
|
var parent = Dropdown._getParentFromElement(this);
|
|
var isActive = $(parent).hasClass(ClassName.SHOW);
|
|
|
|
if (!isActive && event.which !== ESCAPE_KEYCODE || isActive && event.which === ESCAPE_KEYCODE) {
|
|
|
|
if (event.which === ESCAPE_KEYCODE) {
|
|
var toggle = $(parent).find(Selector.DATA_TOGGLE)[0];
|
|
$(toggle).trigger('focus');
|
|
}
|
|
|
|
$(this).trigger('click');
|
|
return;
|
|
}
|
|
|
|
var items = $(parent).find(Selector.VISIBLE_ITEMS).get();
|
|
|
|
if (!items.length) {
|
|
return;
|
|
}
|
|
|
|
var index = items.indexOf(event.target);
|
|
|
|
if (event.which === ARROW_UP_KEYCODE && index > 0) {
|
|
// up
|
|
index--;
|
|
}
|
|
|
|
if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
|
|
// down
|
|
index++;
|
|
}
|
|
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
|
|
items[index].focus();
|
|
};
|
|
|
|
_createClass(Dropdown, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}]);
|
|
|
|
return Dropdown;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.ROLE_MENU, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.ROLE_LISTBOX, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + ' ' + Event.FOCUSIN_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, Dropdown.prototype.toggle).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
|
|
e.stopPropagation();
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Dropdown._jQueryInterface;
|
|
$.fn[NAME].Constructor = Dropdown;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Dropdown._jQueryInterface;
|
|
};
|
|
|
|
return Dropdown;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): modal.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Modal = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'modal';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.modal';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var TRANSITION_DURATION = 300;
|
|
var BACKDROP_TRANSITION_DURATION = 150;
|
|
var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
|
|
|
|
var Default = {
|
|
backdrop: true,
|
|
keyboard: true,
|
|
focus: true,
|
|
show: true
|
|
};
|
|
|
|
var DefaultType = {
|
|
backdrop: '(boolean|string)',
|
|
keyboard: 'boolean',
|
|
focus: 'boolean',
|
|
show: 'boolean'
|
|
};
|
|
|
|
var Event = {
|
|
HIDE: 'hide' + EVENT_KEY,
|
|
HIDDEN: 'hidden' + EVENT_KEY,
|
|
SHOW: 'show' + EVENT_KEY,
|
|
SHOWN: 'shown' + EVENT_KEY,
|
|
FOCUSIN: 'focusin' + EVENT_KEY,
|
|
RESIZE: 'resize' + EVENT_KEY,
|
|
CLICK_DISMISS: 'click.dismiss' + EVENT_KEY,
|
|
KEYDOWN_DISMISS: 'keydown.dismiss' + EVENT_KEY,
|
|
MOUSEUP_DISMISS: 'mouseup.dismiss' + EVENT_KEY,
|
|
MOUSEDOWN_DISMISS: 'mousedown.dismiss' + EVENT_KEY,
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
|
|
BACKDROP: 'modal-backdrop',
|
|
OPEN: 'modal-open',
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector = {
|
|
DIALOG: '.modal-dialog',
|
|
DATA_TOGGLE: '[data-toggle="modal"]',
|
|
DATA_DISMISS: '[data-dismiss="modal"]',
|
|
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Modal = function () {
|
|
function Modal(element, config) {
|
|
_classCallCheck(this, Modal);
|
|
|
|
this._config = this._getConfig(config);
|
|
this._element = element;
|
|
this._dialog = $(element).find(Selector.DIALOG)[0];
|
|
this._backdrop = null;
|
|
this._isShown = false;
|
|
this._isBodyOverflowing = false;
|
|
this._ignoreBackdropClick = false;
|
|
this._isTransitioning = false;
|
|
this._originalBodyPadding = 0;
|
|
this._scrollbarWidth = 0;
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Modal.prototype.toggle = function toggle(relatedTarget) {
|
|
return this._isShown ? this.hide() : this.show(relatedTarget);
|
|
};
|
|
|
|
Modal.prototype.show = function show(relatedTarget) {
|
|
var _this9 = this;
|
|
|
|
if (this._isTransitioning) {
|
|
throw new Error('Modal is transitioning');
|
|
}
|
|
|
|
if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)) {
|
|
this._isTransitioning = true;
|
|
}
|
|
var showEvent = $.Event(Event.SHOW, {
|
|
relatedTarget: relatedTarget
|
|
});
|
|
|
|
$(this._element).trigger(showEvent);
|
|
|
|
if (this._isShown || showEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
this._isShown = true;
|
|
|
|
this._checkScrollbar();
|
|
this._setScrollbar();
|
|
|
|
$(document.body).addClass(ClassName.OPEN);
|
|
|
|
this._setEscapeEvent();
|
|
this._setResizeEvent();
|
|
|
|
$(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) {
|
|
return _this9.hide(event);
|
|
});
|
|
|
|
$(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () {
|
|
$(_this9._element).one(Event.MOUSEUP_DISMISS, function (event) {
|
|
if ($(event.target).is(_this9._element)) {
|
|
_this9._ignoreBackdropClick = true;
|
|
}
|
|
});
|
|
});
|
|
|
|
this._showBackdrop(function () {
|
|
return _this9._showElement(relatedTarget);
|
|
});
|
|
};
|
|
|
|
Modal.prototype.hide = function hide(event) {
|
|
var _this10 = this;
|
|
|
|
if (event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
if (this._isTransitioning) {
|
|
throw new Error('Modal is transitioning');
|
|
}
|
|
|
|
var transition = Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE);
|
|
if (transition) {
|
|
this._isTransitioning = true;
|
|
}
|
|
|
|
var hideEvent = $.Event(Event.HIDE);
|
|
$(this._element).trigger(hideEvent);
|
|
|
|
if (!this._isShown || hideEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
this._isShown = false;
|
|
|
|
this._setEscapeEvent();
|
|
this._setResizeEvent();
|
|
|
|
$(document).off(Event.FOCUSIN);
|
|
|
|
$(this._element).removeClass(ClassName.SHOW);
|
|
|
|
$(this._element).off(Event.CLICK_DISMISS);
|
|
$(this._dialog).off(Event.MOUSEDOWN_DISMISS);
|
|
|
|
if (transition) {
|
|
$(this._element).one(Util.TRANSITION_END, function (event) {
|
|
return _this10._hideModal(event);
|
|
}).emulateTransitionEnd(TRANSITION_DURATION);
|
|
} else {
|
|
this._hideModal();
|
|
}
|
|
};
|
|
|
|
Modal.prototype.dispose = function dispose() {
|
|
$.removeData(this._element, DATA_KEY);
|
|
|
|
$(window, document, this._element, this._backdrop).off(EVENT_KEY);
|
|
|
|
this._config = null;
|
|
this._element = null;
|
|
this._dialog = null;
|
|
this._backdrop = null;
|
|
this._isShown = null;
|
|
this._isBodyOverflowing = null;
|
|
this._ignoreBackdropClick = null;
|
|
this._originalBodyPadding = null;
|
|
this._scrollbarWidth = null;
|
|
};
|
|
|
|
// private
|
|
|
|
Modal.prototype._getConfig = function _getConfig(config) {
|
|
config = $.extend({}, Default, config);
|
|
Util.typeCheckConfig(NAME, config, DefaultType);
|
|
return config;
|
|
};
|
|
|
|
Modal.prototype._showElement = function _showElement(relatedTarget) {
|
|
var _this11 = this;
|
|
|
|
var transition = Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE);
|
|
|
|
if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
|
|
// don't move modals dom position
|
|
document.body.appendChild(this._element);
|
|
}
|
|
|
|
this._element.style.display = 'block';
|
|
this._element.removeAttribute('aria-hidden');
|
|
this._element.scrollTop = 0;
|
|
|
|
if (transition) {
|
|
Util.reflow(this._element);
|
|
}
|
|
|
|
$(this._element).addClass(ClassName.SHOW);
|
|
|
|
if (this._config.focus) {
|
|
this._enforceFocus();
|
|
}
|
|
|
|
var shownEvent = $.Event(Event.SHOWN, {
|
|
relatedTarget: relatedTarget
|
|
});
|
|
|
|
var transitionComplete = function transitionComplete() {
|
|
if (_this11._config.focus) {
|
|
_this11._element.focus();
|
|
}
|
|
_this11._isTransitioning = false;
|
|
$(_this11._element).trigger(shownEvent);
|
|
};
|
|
|
|
if (transition) {
|
|
$(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(TRANSITION_DURATION);
|
|
} else {
|
|
transitionComplete();
|
|
}
|
|
};
|
|
|
|
Modal.prototype._enforceFocus = function _enforceFocus() {
|
|
var _this12 = this;
|
|
|
|
$(document).off(Event.FOCUSIN) // guard against infinite focus loop
|
|
.on(Event.FOCUSIN, function (event) {
|
|
if (document !== event.target && _this12._element !== event.target && !$(_this12._element).has(event.target).length) {
|
|
_this12._element.focus();
|
|
}
|
|
});
|
|
};
|
|
|
|
Modal.prototype._setEscapeEvent = function _setEscapeEvent() {
|
|
var _this13 = this;
|
|
|
|
if (this._isShown && this._config.keyboard) {
|
|
$(this._element).on(Event.KEYDOWN_DISMISS, function (event) {
|
|
if (event.which === ESCAPE_KEYCODE) {
|
|
_this13.hide();
|
|
}
|
|
});
|
|
} else if (!this._isShown) {
|
|
$(this._element).off(Event.KEYDOWN_DISMISS);
|
|
}
|
|
};
|
|
|
|
Modal.prototype._setResizeEvent = function _setResizeEvent() {
|
|
var _this14 = this;
|
|
|
|
if (this._isShown) {
|
|
$(window).on(Event.RESIZE, function (event) {
|
|
return _this14._handleUpdate(event);
|
|
});
|
|
} else {
|
|
$(window).off(Event.RESIZE);
|
|
}
|
|
};
|
|
|
|
Modal.prototype._hideModal = function _hideModal() {
|
|
var _this15 = this;
|
|
|
|
this._element.style.display = 'none';
|
|
this._element.setAttribute('aria-hidden', 'true');
|
|
this._isTransitioning = false;
|
|
this._showBackdrop(function () {
|
|
$(document.body).removeClass(ClassName.OPEN);
|
|
_this15._resetAdjustments();
|
|
_this15._resetScrollbar();
|
|
$(_this15._element).trigger(Event.HIDDEN);
|
|
});
|
|
};
|
|
|
|
Modal.prototype._removeBackdrop = function _removeBackdrop() {
|
|
if (this._backdrop) {
|
|
$(this._backdrop).remove();
|
|
this._backdrop = null;
|
|
}
|
|
};
|
|
|
|
Modal.prototype._showBackdrop = function _showBackdrop(callback) {
|
|
var _this16 = this;
|
|
|
|
var animate = $(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : '';
|
|
|
|
if (this._isShown && this._config.backdrop) {
|
|
var doAnimate = Util.supportsTransitionEnd() && animate;
|
|
|
|
this._backdrop = document.createElement('div');
|
|
this._backdrop.className = ClassName.BACKDROP;
|
|
|
|
if (animate) {
|
|
$(this._backdrop).addClass(animate);
|
|
}
|
|
|
|
$(this._backdrop).appendTo(document.body);
|
|
|
|
$(this._element).on(Event.CLICK_DISMISS, function (event) {
|
|
if (_this16._ignoreBackdropClick) {
|
|
_this16._ignoreBackdropClick = false;
|
|
return;
|
|
}
|
|
if (event.target !== event.currentTarget) {
|
|
return;
|
|
}
|
|
if (_this16._config.backdrop === 'static') {
|
|
_this16._element.focus();
|
|
} else {
|
|
_this16.hide();
|
|
}
|
|
});
|
|
|
|
if (doAnimate) {
|
|
Util.reflow(this._backdrop);
|
|
}
|
|
|
|
$(this._backdrop).addClass(ClassName.SHOW);
|
|
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
|
|
if (!doAnimate) {
|
|
callback();
|
|
return;
|
|
}
|
|
|
|
$(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
|
|
} else if (!this._isShown && this._backdrop) {
|
|
$(this._backdrop).removeClass(ClassName.SHOW);
|
|
|
|
var callbackRemove = function callbackRemove() {
|
|
_this16._removeBackdrop();
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)) {
|
|
$(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
|
|
} else {
|
|
callbackRemove();
|
|
}
|
|
} else if (callback) {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------
|
|
// the following methods are used to handle overflowing modals
|
|
// todo (fat): these should probably be refactored out of modal.js
|
|
// ----------------------------------------------------------------------
|
|
|
|
Modal.prototype._handleUpdate = function _handleUpdate() {
|
|
this._adjustDialog();
|
|
};
|
|
|
|
Modal.prototype._adjustDialog = function _adjustDialog() {
|
|
var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
|
|
|
|
if (!this._isBodyOverflowing && isModalOverflowing) {
|
|
this._element.style.paddingLeft = this._scrollbarWidth + 'px';
|
|
}
|
|
|
|
if (this._isBodyOverflowing && !isModalOverflowing) {
|
|
this._element.style.paddingRight = this._scrollbarWidth + 'px';
|
|
}
|
|
};
|
|
|
|
Modal.prototype._resetAdjustments = function _resetAdjustments() {
|
|
this._element.style.paddingLeft = '';
|
|
this._element.style.paddingRight = '';
|
|
};
|
|
|
|
Modal.prototype._checkScrollbar = function _checkScrollbar() {
|
|
this._isBodyOverflowing = document.body.clientWidth < window.innerWidth;
|
|
this._scrollbarWidth = this._getScrollbarWidth();
|
|
};
|
|
|
|
Modal.prototype._setScrollbar = function _setScrollbar() {
|
|
var bodyPadding = parseInt($(Selector.FIXED_CONTENT).css('padding-right') || 0, 10);
|
|
|
|
this._originalBodyPadding = document.body.style.paddingRight || '';
|
|
|
|
if (this._isBodyOverflowing) {
|
|
document.body.style.paddingRight = bodyPadding + this._scrollbarWidth + 'px';
|
|
}
|
|
};
|
|
|
|
Modal.prototype._resetScrollbar = function _resetScrollbar() {
|
|
document.body.style.paddingRight = this._originalBodyPadding;
|
|
};
|
|
|
|
Modal.prototype._getScrollbarWidth = function _getScrollbarWidth() {
|
|
// thx d.walsh
|
|
var scrollDiv = document.createElement('div');
|
|
scrollDiv.className = ClassName.SCROLLBAR_MEASURER;
|
|
document.body.appendChild(scrollDiv);
|
|
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
|
document.body.removeChild(scrollDiv);
|
|
return scrollbarWidth;
|
|
};
|
|
|
|
// static
|
|
|
|
Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
var _config = $.extend({}, Modal.Default, $(this).data(), (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' && config);
|
|
|
|
if (!data) {
|
|
data = new Modal(this, _config);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config](relatedTarget);
|
|
} else if (_config.show) {
|
|
data.show(relatedTarget);
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(Modal, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
}
|
|
}]);
|
|
|
|
return Modal;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
|
|
var _this17 = this;
|
|
|
|
var target = void 0;
|
|
var selector = Util.getSelectorFromElement(this);
|
|
|
|
if (selector) {
|
|
target = $(selector)[0];
|
|
}
|
|
|
|
var config = $(target).data(DATA_KEY) ? 'toggle' : $.extend({}, $(target).data(), $(this).data());
|
|
|
|
if (this.tagName === 'A' || this.tagName === 'AREA') {
|
|
event.preventDefault();
|
|
}
|
|
|
|
var $target = $(target).one(Event.SHOW, function (showEvent) {
|
|
if (showEvent.isDefaultPrevented()) {
|
|
// only register focus restorer if modal will actually get shown
|
|
return;
|
|
}
|
|
|
|
$target.one(Event.HIDDEN, function () {
|
|
if ($(_this17).is(':visible')) {
|
|
_this17.focus();
|
|
}
|
|
});
|
|
});
|
|
|
|
Modal._jQueryInterface.call($(target), config, this);
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Modal._jQueryInterface;
|
|
$.fn[NAME].Constructor = Modal;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Modal._jQueryInterface;
|
|
};
|
|
|
|
return Modal;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): scrollspy.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var ScrollSpy = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'scrollspy';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.scrollspy';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
|
|
var Default = {
|
|
offset: 10,
|
|
method: 'auto',
|
|
target: ''
|
|
};
|
|
|
|
var DefaultType = {
|
|
offset: 'number',
|
|
method: 'string',
|
|
target: '(string|element)'
|
|
};
|
|
|
|
var Event = {
|
|
ACTIVATE: 'activate' + EVENT_KEY,
|
|
SCROLL: 'scroll' + EVENT_KEY,
|
|
LOAD_DATA_API: 'load' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
DROPDOWN_ITEM: 'dropdown-item',
|
|
DROPDOWN_MENU: 'dropdown-menu',
|
|
NAV_LINK: 'nav-link',
|
|
NAV: 'nav',
|
|
ACTIVE: 'active'
|
|
};
|
|
|
|
var Selector = {
|
|
DATA_SPY: '[data-spy="scroll"]',
|
|
ACTIVE: '.active',
|
|
LIST_ITEM: '.list-item',
|
|
LI: 'li',
|
|
LI_DROPDOWN: 'li.dropdown',
|
|
NAV_LINKS: '.nav-link',
|
|
DROPDOWN: '.dropdown',
|
|
DROPDOWN_ITEMS: '.dropdown-item',
|
|
DROPDOWN_TOGGLE: '.dropdown-toggle'
|
|
};
|
|
|
|
var OffsetMethod = {
|
|
OFFSET: 'offset',
|
|
POSITION: 'position'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var ScrollSpy = function () {
|
|
function ScrollSpy(element, config) {
|
|
var _this18 = this;
|
|
|
|
_classCallCheck(this, ScrollSpy);
|
|
|
|
this._element = element;
|
|
this._scrollElement = element.tagName === 'BODY' ? window : element;
|
|
this._config = this._getConfig(config);
|
|
this._selector = this._config.target + ' ' + Selector.NAV_LINKS + ',' + (this._config.target + ' ' + Selector.DROPDOWN_ITEMS);
|
|
this._offsets = [];
|
|
this._targets = [];
|
|
this._activeTarget = null;
|
|
this._scrollHeight = 0;
|
|
|
|
$(this._scrollElement).on(Event.SCROLL, function (event) {
|
|
return _this18._process(event);
|
|
});
|
|
|
|
this.refresh();
|
|
this._process();
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
ScrollSpy.prototype.refresh = function refresh() {
|
|
var _this19 = this;
|
|
|
|
var autoMethod = this._scrollElement !== this._scrollElement.window ? OffsetMethod.POSITION : OffsetMethod.OFFSET;
|
|
|
|
var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
|
|
|
|
var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
|
|
|
|
this._offsets = [];
|
|
this._targets = [];
|
|
|
|
this._scrollHeight = this._getScrollHeight();
|
|
|
|
var targets = $.makeArray($(this._selector));
|
|
|
|
targets.map(function (element) {
|
|
var target = void 0;
|
|
var targetSelector = Util.getSelectorFromElement(element);
|
|
|
|
if (targetSelector) {
|
|
target = $(targetSelector)[0];
|
|
}
|
|
|
|
if (target && (target.offsetWidth || target.offsetHeight)) {
|
|
// todo (fat): remove sketch reliance on jQuery position/offset
|
|
return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
|
|
}
|
|
return null;
|
|
}).filter(function (item) {
|
|
return item;
|
|
}).sort(function (a, b) {
|
|
return a[0] - b[0];
|
|
}).forEach(function (item) {
|
|
_this19._offsets.push(item[0]);
|
|
_this19._targets.push(item[1]);
|
|
});
|
|
};
|
|
|
|
ScrollSpy.prototype.dispose = function dispose() {
|
|
$.removeData(this._element, DATA_KEY);
|
|
$(this._scrollElement).off(EVENT_KEY);
|
|
|
|
this._element = null;
|
|
this._scrollElement = null;
|
|
this._config = null;
|
|
this._selector = null;
|
|
this._offsets = null;
|
|
this._targets = null;
|
|
this._activeTarget = null;
|
|
this._scrollHeight = null;
|
|
};
|
|
|
|
// private
|
|
|
|
ScrollSpy.prototype._getConfig = function _getConfig(config) {
|
|
config = $.extend({}, Default, config);
|
|
|
|
if (typeof config.target !== 'string') {
|
|
var id = $(config.target).attr('id');
|
|
if (!id) {
|
|
id = Util.getUID(NAME);
|
|
$(config.target).attr('id', id);
|
|
}
|
|
config.target = '#' + id;
|
|
}
|
|
|
|
Util.typeCheckConfig(NAME, config, DefaultType);
|
|
|
|
return config;
|
|
};
|
|
|
|
ScrollSpy.prototype._getScrollTop = function _getScrollTop() {
|
|
return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
|
|
};
|
|
|
|
ScrollSpy.prototype._getScrollHeight = function _getScrollHeight() {
|
|
return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
|
|
};
|
|
|
|
ScrollSpy.prototype._getOffsetHeight = function _getOffsetHeight() {
|
|
return this._scrollElement === window ? window.innerHeight : this._scrollElement.offsetHeight;
|
|
};
|
|
|
|
ScrollSpy.prototype._process = function _process() {
|
|
var scrollTop = this._getScrollTop() + this._config.offset;
|
|
var scrollHeight = this._getScrollHeight();
|
|
var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
|
|
|
|
if (this._scrollHeight !== scrollHeight) {
|
|
this.refresh();
|
|
}
|
|
|
|
if (scrollTop >= maxScroll) {
|
|
var target = this._targets[this._targets.length - 1];
|
|
|
|
if (this._activeTarget !== target) {
|
|
this._activate(target);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
|
|
this._activeTarget = null;
|
|
this._clear();
|
|
return;
|
|
}
|
|
|
|
for (var i = this._offsets.length; i--;) {
|
|
var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (this._offsets[i + 1] === undefined || scrollTop < this._offsets[i + 1]);
|
|
|
|
if (isActiveTarget) {
|
|
this._activate(this._targets[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
ScrollSpy.prototype._activate = function _activate(target) {
|
|
this._activeTarget = target;
|
|
|
|
this._clear();
|
|
|
|
var queries = this._selector.split(',');
|
|
queries = queries.map(function (selector) {
|
|
return selector + '[data-target="' + target + '"],' + (selector + '[href="' + target + '"]');
|
|
});
|
|
|
|
var $link = $(queries.join(','));
|
|
|
|
if ($link.hasClass(ClassName.DROPDOWN_ITEM)) {
|
|
$link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
|
|
$link.addClass(ClassName.ACTIVE);
|
|
} else {
|
|
// todo (fat) this is kinda sus...
|
|
// recursively add actives to tested nav-links
|
|
$link.parents(Selector.LI).find('> ' + Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
|
|
}
|
|
|
|
$(this._scrollElement).trigger(Event.ACTIVATE, {
|
|
relatedTarget: target
|
|
});
|
|
};
|
|
|
|
ScrollSpy.prototype._clear = function _clear() {
|
|
$(this._selector).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
|
|
};
|
|
|
|
// static
|
|
|
|
ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
var _config = (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' && config;
|
|
|
|
if (!data) {
|
|
data = new ScrollSpy(this, _config);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(ScrollSpy, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
}
|
|
}]);
|
|
|
|
return ScrollSpy;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(window).on(Event.LOAD_DATA_API, function () {
|
|
var scrollSpys = $.makeArray($(Selector.DATA_SPY));
|
|
|
|
for (var i = scrollSpys.length; i--;) {
|
|
var $spy = $(scrollSpys[i]);
|
|
ScrollSpy._jQueryInterface.call($spy, $spy.data());
|
|
}
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = ScrollSpy._jQueryInterface;
|
|
$.fn[NAME].Constructor = ScrollSpy;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return ScrollSpy._jQueryInterface;
|
|
};
|
|
|
|
return ScrollSpy;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): tab.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Tab = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'tab';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.tab';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var TRANSITION_DURATION = 150;
|
|
|
|
var Event = {
|
|
HIDE: 'hide' + EVENT_KEY,
|
|
HIDDEN: 'hidden' + EVENT_KEY,
|
|
SHOW: 'show' + EVENT_KEY,
|
|
SHOWN: 'shown' + EVENT_KEY,
|
|
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
DROPDOWN_MENU: 'dropdown-menu',
|
|
ACTIVE: 'active',
|
|
DISABLED: 'disabled',
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector = {
|
|
A: 'a',
|
|
LI: 'li',
|
|
DROPDOWN: '.dropdown',
|
|
LIST: 'ul:not(.dropdown-menu), ol:not(.dropdown-menu), nav:not(.dropdown-menu)',
|
|
FADE_CHILD: '> .nav-item .fade, > .fade',
|
|
ACTIVE: '.active',
|
|
ACTIVE_CHILD: '> .nav-item > .active, > .active',
|
|
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"]',
|
|
DROPDOWN_TOGGLE: '.dropdown-toggle',
|
|
DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Tab = function () {
|
|
function Tab(element) {
|
|
_classCallCheck(this, Tab);
|
|
|
|
this._element = element;
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Tab.prototype.show = function show() {
|
|
var _this20 = this;
|
|
|
|
if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName.ACTIVE) || $(this._element).hasClass(ClassName.DISABLED)) {
|
|
return;
|
|
}
|
|
|
|
var target = void 0;
|
|
var previous = void 0;
|
|
var listElement = $(this._element).closest(Selector.LIST)[0];
|
|
var selector = Util.getSelectorFromElement(this._element);
|
|
|
|
if (listElement) {
|
|
previous = $.makeArray($(listElement).find(Selector.ACTIVE));
|
|
previous = previous[previous.length - 1];
|
|
}
|
|
|
|
var hideEvent = $.Event(Event.HIDE, {
|
|
relatedTarget: this._element
|
|
});
|
|
|
|
var showEvent = $.Event(Event.SHOW, {
|
|
relatedTarget: previous
|
|
});
|
|
|
|
if (previous) {
|
|
$(previous).trigger(hideEvent);
|
|
}
|
|
|
|
$(this._element).trigger(showEvent);
|
|
|
|
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
if (selector) {
|
|
target = $(selector)[0];
|
|
}
|
|
|
|
this._activate(this._element, listElement);
|
|
|
|
var complete = function complete() {
|
|
var hiddenEvent = $.Event(Event.HIDDEN, {
|
|
relatedTarget: _this20._element
|
|
});
|
|
|
|
var shownEvent = $.Event(Event.SHOWN, {
|
|
relatedTarget: previous
|
|
});
|
|
|
|
$(previous).trigger(hiddenEvent);
|
|
$(_this20._element).trigger(shownEvent);
|
|
};
|
|
|
|
if (target) {
|
|
this._activate(target, target.parentNode, complete);
|
|
} else {
|
|
complete();
|
|
}
|
|
};
|
|
|
|
Tab.prototype.dispose = function dispose() {
|
|
$.removeClass(this._element, DATA_KEY);
|
|
this._element = null;
|
|
};
|
|
|
|
// private
|
|
|
|
Tab.prototype._activate = function _activate(element, container, callback) {
|
|
var _this21 = this;
|
|
|
|
var active = $(container).find(Selector.ACTIVE_CHILD)[0];
|
|
var isTransitioning = callback && Util.supportsTransitionEnd() && (active && $(active).hasClass(ClassName.FADE) || Boolean($(container).find(Selector.FADE_CHILD)[0]));
|
|
|
|
var complete = function complete() {
|
|
return _this21._transitionComplete(element, active, isTransitioning, callback);
|
|
};
|
|
|
|
if (active && isTransitioning) {
|
|
$(active).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
|
|
} else {
|
|
complete();
|
|
}
|
|
|
|
if (active) {
|
|
$(active).removeClass(ClassName.SHOW);
|
|
}
|
|
};
|
|
|
|
Tab.prototype._transitionComplete = function _transitionComplete(element, active, isTransitioning, callback) {
|
|
if (active) {
|
|
$(active).removeClass(ClassName.ACTIVE);
|
|
|
|
var dropdownChild = $(active.parentNode).find(Selector.DROPDOWN_ACTIVE_CHILD)[0];
|
|
|
|
if (dropdownChild) {
|
|
$(dropdownChild).removeClass(ClassName.ACTIVE);
|
|
}
|
|
|
|
active.setAttribute('aria-expanded', false);
|
|
}
|
|
|
|
$(element).addClass(ClassName.ACTIVE);
|
|
element.setAttribute('aria-expanded', true);
|
|
|
|
if (isTransitioning) {
|
|
Util.reflow(element);
|
|
$(element).addClass(ClassName.SHOW);
|
|
} else {
|
|
$(element).removeClass(ClassName.FADE);
|
|
}
|
|
|
|
if (element.parentNode && $(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) {
|
|
|
|
var dropdownElement = $(element).closest(Selector.DROPDOWN)[0];
|
|
if (dropdownElement) {
|
|
$(dropdownElement).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
|
|
}
|
|
|
|
element.setAttribute('aria-expanded', true);
|
|
}
|
|
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
// static
|
|
|
|
Tab._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var $this = $(this);
|
|
var data = $this.data(DATA_KEY);
|
|
|
|
if (!data) {
|
|
data = new Tab(this);
|
|
$this.data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(Tab, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}]);
|
|
|
|
return Tab;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
|
|
event.preventDefault();
|
|
Tab._jQueryInterface.call($(this), 'show');
|
|
});
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Tab._jQueryInterface;
|
|
$.fn[NAME].Constructor = Tab;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Tab._jQueryInterface;
|
|
};
|
|
|
|
return Tab;
|
|
}(jQuery);
|
|
|
|
/* global Tether */
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): tooltip.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Tooltip = function ($) {
|
|
|
|
/**
|
|
* Check for Tether dependency
|
|
* Tether - http://tether.io/
|
|
*/
|
|
if (typeof Tether === 'undefined') {
|
|
throw new Error('Bootstrap tooltips require Tether (http://tether.io/)');
|
|
}
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'tooltip';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.tooltip';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
var TRANSITION_DURATION = 150;
|
|
var CLASS_PREFIX = 'bs-tether';
|
|
|
|
var Default = {
|
|
animation: true,
|
|
template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-inner"></div></div>',
|
|
trigger: 'hover focus',
|
|
title: '',
|
|
delay: 0,
|
|
html: false,
|
|
selector: false,
|
|
placement: 'top',
|
|
offset: '0 0',
|
|
constraints: [],
|
|
container: false
|
|
};
|
|
|
|
var DefaultType = {
|
|
animation: 'boolean',
|
|
template: 'string',
|
|
title: '(string|element|function)',
|
|
trigger: 'string',
|
|
delay: '(number|object)',
|
|
html: 'boolean',
|
|
selector: '(string|boolean)',
|
|
placement: '(string|function)',
|
|
offset: 'string',
|
|
constraints: 'array',
|
|
container: '(string|element|boolean)'
|
|
};
|
|
|
|
var AttachmentMap = {
|
|
TOP: 'bottom center',
|
|
RIGHT: 'middle left',
|
|
BOTTOM: 'top center',
|
|
LEFT: 'middle right'
|
|
};
|
|
|
|
var HoverState = {
|
|
SHOW: 'show',
|
|
OUT: 'out'
|
|
};
|
|
|
|
var Event = {
|
|
HIDE: 'hide' + EVENT_KEY,
|
|
HIDDEN: 'hidden' + EVENT_KEY,
|
|
SHOW: 'show' + EVENT_KEY,
|
|
SHOWN: 'shown' + EVENT_KEY,
|
|
INSERTED: 'inserted' + EVENT_KEY,
|
|
CLICK: 'click' + EVENT_KEY,
|
|
FOCUSIN: 'focusin' + EVENT_KEY,
|
|
FOCUSOUT: 'focusout' + EVENT_KEY,
|
|
MOUSEENTER: 'mouseenter' + EVENT_KEY,
|
|
MOUSELEAVE: 'mouseleave' + EVENT_KEY
|
|
};
|
|
|
|
var ClassName = {
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector = {
|
|
TOOLTIP: '.tooltip',
|
|
TOOLTIP_INNER: '.tooltip-inner'
|
|
};
|
|
|
|
var TetherClass = {
|
|
element: false,
|
|
enabled: false
|
|
};
|
|
|
|
var Trigger = {
|
|
HOVER: 'hover',
|
|
FOCUS: 'focus',
|
|
CLICK: 'click',
|
|
MANUAL: 'manual'
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Tooltip = function () {
|
|
function Tooltip(element, config) {
|
|
_classCallCheck(this, Tooltip);
|
|
|
|
// private
|
|
this._isEnabled = true;
|
|
this._timeout = 0;
|
|
this._hoverState = '';
|
|
this._activeTrigger = {};
|
|
this._isTransitioning = false;
|
|
this._tether = null;
|
|
|
|
// protected
|
|
this.element = element;
|
|
this.config = this._getConfig(config);
|
|
this.tip = null;
|
|
|
|
this._setListeners();
|
|
}
|
|
|
|
// getters
|
|
|
|
// public
|
|
|
|
Tooltip.prototype.enable = function enable() {
|
|
this._isEnabled = true;
|
|
};
|
|
|
|
Tooltip.prototype.disable = function disable() {
|
|
this._isEnabled = false;
|
|
};
|
|
|
|
Tooltip.prototype.toggleEnabled = function toggleEnabled() {
|
|
this._isEnabled = !this._isEnabled;
|
|
};
|
|
|
|
Tooltip.prototype.toggle = function toggle(event) {
|
|
if (event) {
|
|
var dataKey = this.constructor.DATA_KEY;
|
|
var context = $(event.currentTarget).data(dataKey);
|
|
|
|
if (!context) {
|
|
context = new this.constructor(event.currentTarget, this._getDelegateConfig());
|
|
$(event.currentTarget).data(dataKey, context);
|
|
}
|
|
|
|
context._activeTrigger.click = !context._activeTrigger.click;
|
|
|
|
if (context._isWithActiveTrigger()) {
|
|
context._enter(null, context);
|
|
} else {
|
|
context._leave(null, context);
|
|
}
|
|
} else {
|
|
|
|
if ($(this.getTipElement()).hasClass(ClassName.SHOW)) {
|
|
this._leave(null, this);
|
|
return;
|
|
}
|
|
|
|
this._enter(null, this);
|
|
}
|
|
};
|
|
|
|
Tooltip.prototype.dispose = function dispose() {
|
|
clearTimeout(this._timeout);
|
|
|
|
this.cleanupTether();
|
|
|
|
$.removeData(this.element, this.constructor.DATA_KEY);
|
|
|
|
$(this.element).off(this.constructor.EVENT_KEY);
|
|
$(this.element).closest('.modal').off('hide.bs.modal');
|
|
|
|
if (this.tip) {
|
|
$(this.tip).remove();
|
|
}
|
|
|
|
this._isEnabled = null;
|
|
this._timeout = null;
|
|
this._hoverState = null;
|
|
this._activeTrigger = null;
|
|
this._tether = null;
|
|
|
|
this.element = null;
|
|
this.config = null;
|
|
this.tip = null;
|
|
};
|
|
|
|
Tooltip.prototype.show = function show() {
|
|
var _this22 = this;
|
|
|
|
if ($(this.element).css('display') === 'none') {
|
|
throw new Error('Please use show on visible elements');
|
|
}
|
|
|
|
var showEvent = $.Event(this.constructor.Event.SHOW);
|
|
if (this.isWithContent() && this._isEnabled) {
|
|
if (this._isTransitioning) {
|
|
throw new Error('Tooltip is transitioning');
|
|
}
|
|
$(this.element).trigger(showEvent);
|
|
|
|
var isInTheDom = $.contains(this.element.ownerDocument.documentElement, this.element);
|
|
|
|
if (showEvent.isDefaultPrevented() || !isInTheDom) {
|
|
return;
|
|
}
|
|
|
|
var tip = this.getTipElement();
|
|
var tipId = Util.getUID(this.constructor.NAME);
|
|
|
|
tip.setAttribute('id', tipId);
|
|
this.element.setAttribute('aria-describedby', tipId);
|
|
|
|
this.setContent();
|
|
|
|
if (this.config.animation) {
|
|
$(tip).addClass(ClassName.FADE);
|
|
}
|
|
|
|
var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
|
|
|
|
var attachment = this._getAttachment(placement);
|
|
|
|
var container = this.config.container === false ? document.body : $(this.config.container);
|
|
|
|
$(tip).data(this.constructor.DATA_KEY, this).appendTo(container);
|
|
|
|
$(this.element).trigger(this.constructor.Event.INSERTED);
|
|
|
|
this._tether = new Tether({
|
|
attachment: attachment,
|
|
element: tip,
|
|
target: this.element,
|
|
classes: TetherClass,
|
|
classPrefix: CLASS_PREFIX,
|
|
offset: this.config.offset,
|
|
constraints: this.config.constraints,
|
|
addTargetClasses: false
|
|
});
|
|
|
|
Util.reflow(tip);
|
|
this._tether.position();
|
|
|
|
$(tip).addClass(ClassName.SHOW);
|
|
|
|
var complete = function complete() {
|
|
var prevHoverState = _this22._hoverState;
|
|
_this22._hoverState = null;
|
|
_this22._isTransitioning = false;
|
|
|
|
$(_this22.element).trigger(_this22.constructor.Event.SHOWN);
|
|
|
|
if (prevHoverState === HoverState.OUT) {
|
|
_this22._leave(null, _this22);
|
|
}
|
|
};
|
|
|
|
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
|
|
this._isTransitioning = true;
|
|
$(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(Tooltip._TRANSITION_DURATION);
|
|
return;
|
|
}
|
|
|
|
complete();
|
|
}
|
|
};
|
|
|
|
Tooltip.prototype.hide = function hide(callback) {
|
|
var _this23 = this;
|
|
|
|
var tip = this.getTipElement();
|
|
var hideEvent = $.Event(this.constructor.Event.HIDE);
|
|
if (this._isTransitioning) {
|
|
throw new Error('Tooltip is transitioning');
|
|
}
|
|
var complete = function complete() {
|
|
if (_this23._hoverState !== HoverState.SHOW && tip.parentNode) {
|
|
tip.parentNode.removeChild(tip);
|
|
}
|
|
|
|
_this23.element.removeAttribute('aria-describedby');
|
|
$(_this23.element).trigger(_this23.constructor.Event.HIDDEN);
|
|
_this23._isTransitioning = false;
|
|
_this23.cleanupTether();
|
|
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
$(this.element).trigger(hideEvent);
|
|
|
|
if (hideEvent.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
$(tip).removeClass(ClassName.SHOW);
|
|
|
|
this._activeTrigger[Trigger.CLICK] = false;
|
|
this._activeTrigger[Trigger.FOCUS] = false;
|
|
this._activeTrigger[Trigger.HOVER] = false;
|
|
|
|
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
|
|
this._isTransitioning = true;
|
|
$(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
|
|
} else {
|
|
complete();
|
|
}
|
|
|
|
this._hoverState = '';
|
|
};
|
|
|
|
// protected
|
|
|
|
Tooltip.prototype.isWithContent = function isWithContent() {
|
|
return Boolean(this.getTitle());
|
|
};
|
|
|
|
Tooltip.prototype.getTipElement = function getTipElement() {
|
|
return this.tip = this.tip || $(this.config.template)[0];
|
|
};
|
|
|
|
Tooltip.prototype.setContent = function setContent() {
|
|
var $tip = $(this.getTipElement());
|
|
|
|
this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle());
|
|
|
|
$tip.removeClass(ClassName.FADE + ' ' + ClassName.SHOW);
|
|
|
|
this.cleanupTether();
|
|
};
|
|
|
|
Tooltip.prototype.setElementContent = function setElementContent($element, content) {
|
|
var html = this.config.html;
|
|
if ((typeof content === 'undefined' ? 'undefined' : _typeof(content)) === 'object' && (content.nodeType || content.jquery)) {
|
|
// content is a DOM node or a jQuery
|
|
if (html) {
|
|
if (!$(content).parent().is($element)) {
|
|
$element.empty().append(content);
|
|
}
|
|
} else {
|
|
$element.text($(content).text());
|
|
}
|
|
} else {
|
|
$element[html ? 'html' : 'text'](content);
|
|
}
|
|
};
|
|
|
|
Tooltip.prototype.getTitle = function getTitle() {
|
|
var title = this.element.getAttribute('data-original-title');
|
|
|
|
if (!title) {
|
|
title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
|
|
}
|
|
|
|
return title;
|
|
};
|
|
|
|
Tooltip.prototype.cleanupTether = function cleanupTether() {
|
|
if (this._tether) {
|
|
this._tether.destroy();
|
|
}
|
|
};
|
|
|
|
// private
|
|
|
|
Tooltip.prototype._getAttachment = function _getAttachment(placement) {
|
|
return AttachmentMap[placement.toUpperCase()];
|
|
};
|
|
|
|
Tooltip.prototype._setListeners = function _setListeners() {
|
|
var _this24 = this;
|
|
|
|
var triggers = this.config.trigger.split(' ');
|
|
|
|
triggers.forEach(function (trigger) {
|
|
if (trigger === 'click') {
|
|
$(_this24.element).on(_this24.constructor.Event.CLICK, _this24.config.selector, function (event) {
|
|
return _this24.toggle(event);
|
|
});
|
|
} else if (trigger !== Trigger.MANUAL) {
|
|
var eventIn = trigger === Trigger.HOVER ? _this24.constructor.Event.MOUSEENTER : _this24.constructor.Event.FOCUSIN;
|
|
var eventOut = trigger === Trigger.HOVER ? _this24.constructor.Event.MOUSELEAVE : _this24.constructor.Event.FOCUSOUT;
|
|
|
|
$(_this24.element).on(eventIn, _this24.config.selector, function (event) {
|
|
return _this24._enter(event);
|
|
}).on(eventOut, _this24.config.selector, function (event) {
|
|
return _this24._leave(event);
|
|
});
|
|
}
|
|
|
|
$(_this24.element).closest('.modal').on('hide.bs.modal', function () {
|
|
return _this24.hide();
|
|
});
|
|
});
|
|
|
|
if (this.config.selector) {
|
|
this.config = $.extend({}, this.config, {
|
|
trigger: 'manual',
|
|
selector: ''
|
|
});
|
|
} else {
|
|
this._fixTitle();
|
|
}
|
|
};
|
|
|
|
Tooltip.prototype._fixTitle = function _fixTitle() {
|
|
var titleType = _typeof(this.element.getAttribute('data-original-title'));
|
|
if (this.element.getAttribute('title') || titleType !== 'string') {
|
|
this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
|
|
this.element.setAttribute('title', '');
|
|
}
|
|
};
|
|
|
|
Tooltip.prototype._enter = function _enter(event, context) {
|
|
var dataKey = this.constructor.DATA_KEY;
|
|
|
|
context = context || $(event.currentTarget).data(dataKey);
|
|
|
|
if (!context) {
|
|
context = new this.constructor(event.currentTarget, this._getDelegateConfig());
|
|
$(event.currentTarget).data(dataKey, context);
|
|
}
|
|
|
|
if (event) {
|
|
context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
|
|
}
|
|
|
|
if ($(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) {
|
|
context._hoverState = HoverState.SHOW;
|
|
return;
|
|
}
|
|
|
|
clearTimeout(context._timeout);
|
|
|
|
context._hoverState = HoverState.SHOW;
|
|
|
|
if (!context.config.delay || !context.config.delay.show) {
|
|
context.show();
|
|
return;
|
|
}
|
|
|
|
context._timeout = setTimeout(function () {
|
|
if (context._hoverState === HoverState.SHOW) {
|
|
context.show();
|
|
}
|
|
}, context.config.delay.show);
|
|
};
|
|
|
|
Tooltip.prototype._leave = function _leave(event, context) {
|
|
var dataKey = this.constructor.DATA_KEY;
|
|
|
|
context = context || $(event.currentTarget).data(dataKey);
|
|
|
|
if (!context) {
|
|
context = new this.constructor(event.currentTarget, this._getDelegateConfig());
|
|
$(event.currentTarget).data(dataKey, context);
|
|
}
|
|
|
|
if (event) {
|
|
context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
|
|
}
|
|
|
|
if (context._isWithActiveTrigger()) {
|
|
return;
|
|
}
|
|
|
|
clearTimeout(context._timeout);
|
|
|
|
context._hoverState = HoverState.OUT;
|
|
|
|
if (!context.config.delay || !context.config.delay.hide) {
|
|
context.hide();
|
|
return;
|
|
}
|
|
|
|
context._timeout = setTimeout(function () {
|
|
if (context._hoverState === HoverState.OUT) {
|
|
context.hide();
|
|
}
|
|
}, context.config.delay.hide);
|
|
};
|
|
|
|
Tooltip.prototype._isWithActiveTrigger = function _isWithActiveTrigger() {
|
|
for (var trigger in this._activeTrigger) {
|
|
if (this._activeTrigger[trigger]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
Tooltip.prototype._getConfig = function _getConfig(config) {
|
|
config = $.extend({}, this.constructor.Default, $(this.element).data(), config);
|
|
|
|
if (config.delay && typeof config.delay === 'number') {
|
|
config.delay = {
|
|
show: config.delay,
|
|
hide: config.delay
|
|
};
|
|
}
|
|
|
|
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
|
|
|
|
return config;
|
|
};
|
|
|
|
Tooltip.prototype._getDelegateConfig = function _getDelegateConfig() {
|
|
var config = {};
|
|
|
|
if (this.config) {
|
|
for (var key in this.config) {
|
|
if (this.constructor.Default[key] !== this.config[key]) {
|
|
config[key] = this.config[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return config;
|
|
};
|
|
|
|
// static
|
|
|
|
Tooltip._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
var _config = (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' && config;
|
|
|
|
if (!data && /dispose|hide/.test(config)) {
|
|
return;
|
|
}
|
|
|
|
if (!data) {
|
|
data = new Tooltip(this, _config);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(Tooltip, null, [{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
}
|
|
}, {
|
|
key: 'NAME',
|
|
get: function get() {
|
|
return NAME;
|
|
}
|
|
}, {
|
|
key: 'DATA_KEY',
|
|
get: function get() {
|
|
return DATA_KEY;
|
|
}
|
|
}, {
|
|
key: 'Event',
|
|
get: function get() {
|
|
return Event;
|
|
}
|
|
}, {
|
|
key: 'EVENT_KEY',
|
|
get: function get() {
|
|
return EVENT_KEY;
|
|
}
|
|
}, {
|
|
key: 'DefaultType',
|
|
get: function get() {
|
|
return DefaultType;
|
|
}
|
|
}]);
|
|
|
|
return Tooltip;
|
|
}();
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Tooltip._jQueryInterface;
|
|
$.fn[NAME].Constructor = Tooltip;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Tooltip._jQueryInterface;
|
|
};
|
|
|
|
return Tooltip;
|
|
}(jQuery);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v4.0.0-alpha.6): popover.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Popover = function ($) {
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'popover';
|
|
var VERSION = '4.0.0-alpha.6';
|
|
var DATA_KEY = 'bs.popover';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
|
|
var Default = $.extend({}, Tooltip.Default, {
|
|
placement: 'right',
|
|
trigger: 'click',
|
|
content: '',
|
|
template: '<div class="popover" role="tooltip">' + '<h3 class="popover-title"></h3>' + '<div class="popover-content"></div></div>'
|
|
});
|
|
|
|
var DefaultType = $.extend({}, Tooltip.DefaultType, {
|
|
content: '(string|element|function)'
|
|
});
|
|
|
|
var ClassName = {
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector = {
|
|
TITLE: '.popover-title',
|
|
CONTENT: '.popover-content'
|
|
};
|
|
|
|
var Event = {
|
|
HIDE: 'hide' + EVENT_KEY,
|
|
HIDDEN: 'hidden' + EVENT_KEY,
|
|
SHOW: 'show' + EVENT_KEY,
|
|
SHOWN: 'shown' + EVENT_KEY,
|
|
INSERTED: 'inserted' + EVENT_KEY,
|
|
CLICK: 'click' + EVENT_KEY,
|
|
FOCUSIN: 'focusin' + EVENT_KEY,
|
|
FOCUSOUT: 'focusout' + EVENT_KEY,
|
|
MOUSEENTER: 'mouseenter' + EVENT_KEY,
|
|
MOUSELEAVE: 'mouseleave' + EVENT_KEY
|
|
};
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var Popover = function (_Tooltip) {
|
|
_inherits(Popover, _Tooltip);
|
|
|
|
function Popover() {
|
|
_classCallCheck(this, Popover);
|
|
|
|
return _possibleConstructorReturn(this, _Tooltip.apply(this, arguments));
|
|
}
|
|
|
|
// overrides
|
|
|
|
Popover.prototype.isWithContent = function isWithContent() {
|
|
return this.getTitle() || this._getContent();
|
|
};
|
|
|
|
Popover.prototype.getTipElement = function getTipElement() {
|
|
return this.tip = this.tip || $(this.config.template)[0];
|
|
};
|
|
|
|
Popover.prototype.setContent = function setContent() {
|
|
var $tip = $(this.getTipElement());
|
|
|
|
// we use append for html objects to maintain js events
|
|
this.setElementContent($tip.find(Selector.TITLE), this.getTitle());
|
|
this.setElementContent($tip.find(Selector.CONTENT), this._getContent());
|
|
|
|
$tip.removeClass(ClassName.FADE + ' ' + ClassName.SHOW);
|
|
|
|
this.cleanupTether();
|
|
};
|
|
|
|
// private
|
|
|
|
Popover.prototype._getContent = function _getContent() {
|
|
return this.element.getAttribute('data-content') || (typeof this.config.content === 'function' ? this.config.content.call(this.element) : this.config.content);
|
|
};
|
|
|
|
// static
|
|
|
|
Popover._jQueryInterface = function _jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = $(this).data(DATA_KEY);
|
|
var _config = (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' ? config : null;
|
|
|
|
if (!data && /destroy|hide/.test(config)) {
|
|
return;
|
|
}
|
|
|
|
if (!data) {
|
|
data = new Popover(this, _config);
|
|
$(this).data(DATA_KEY, data);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (data[config] === undefined) {
|
|
throw new Error('No method named "' + config + '"');
|
|
}
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass(Popover, null, [{
|
|
key: 'VERSION',
|
|
|
|
|
|
// getters
|
|
|
|
get: function get() {
|
|
return VERSION;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
}
|
|
}, {
|
|
key: 'NAME',
|
|
get: function get() {
|
|
return NAME;
|
|
}
|
|
}, {
|
|
key: 'DATA_KEY',
|
|
get: function get() {
|
|
return DATA_KEY;
|
|
}
|
|
}, {
|
|
key: 'Event',
|
|
get: function get() {
|
|
return Event;
|
|
}
|
|
}, {
|
|
key: 'EVENT_KEY',
|
|
get: function get() {
|
|
return EVENT_KEY;
|
|
}
|
|
}, {
|
|
key: 'DefaultType',
|
|
get: function get() {
|
|
return DefaultType;
|
|
}
|
|
}]);
|
|
|
|
return Popover;
|
|
}(Tooltip);
|
|
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
$.fn[NAME] = Popover._jQueryInterface;
|
|
$.fn[NAME].Constructor = Popover;
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return Popover._jQueryInterface;
|
|
};
|
|
|
|
return Popover;
|
|
}(jQuery);
|
|
|
|
}();
|