1 /*! JointJS v0.9.0 - JavaScript diagramming library 2014-05-13
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * jQuery JavaScript Library v2.0.3
13 * http://sizzlejs.com/
15 * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
16 * Released under the MIT license
17 * http://jquery.org/license
19 * Date: 2013-07-03T13:30Z
21 (function( window, undefined ) {
23 // Can't do this because several apps including ASP.NET trace
24 // the stack via arguments.caller.callee and Firefox dies if
25 // you try to trace through "use strict" call chains. (#13335)
26 // Support: Firefox 18+
29 // A central reference to the root jQuery(document)
32 // The deferred used on DOM ready
36 // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
37 core_strundefined = typeof undefined,
39 // Use the correct document accordingly with window argument (sandbox)
40 location = window.location,
41 document = window.document,
42 docElem = document.documentElement,
44 // Map over jQuery in case of overwrite
45 _jQuery = window.jQuery,
47 // Map over the $ in case of overwrite
50 // [[Class]] -> type pairs
53 // List of deleted data cache ids, so we can reuse them
56 core_version = "2.0.3",
58 // Save a reference to some core methods
59 core_concat = core_deletedIds.concat,
60 core_push = core_deletedIds.push,
61 core_slice = core_deletedIds.slice,
62 core_indexOf = core_deletedIds.indexOf,
63 core_toString = class2type.toString,
64 core_hasOwn = class2type.hasOwnProperty,
65 core_trim = core_version.trim,
67 // Define a local copy of jQuery
68 jQuery = function( selector, context ) {
69 // The jQuery object is actually just the init constructor 'enhanced'
70 return new jQuery.fn.init( selector, context, rootjQuery );
73 // Used for matching numbers
74 core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
76 // Used for splitting on whitespace
77 core_rnotwhite = /\S+/g,
79 // A simple way to check for HTML strings
80 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
81 // Strict HTML recognition (#11290: must start with <)
82 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
84 // Match a standalone tag
85 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
87 // Matches dashed string for camelizing
89 rdashAlpha = /-([\da-z])/gi,
91 // Used by jQuery.camelCase as callback to replace()
92 fcamelCase = function( all, letter ) {
93 return letter.toUpperCase();
96 // The ready event handler and self cleanup method
97 completed = function() {
98 document.removeEventListener( "DOMContentLoaded", completed, false );
99 window.removeEventListener( "load", completed, false );
103 jQuery.fn = jQuery.prototype = {
104 // The current version of jQuery being used
105 jquery: core_version,
108 init: function( selector, context, rootjQuery ) {
111 // HANDLE: $(""), $(null), $(undefined), $(false)
116 // Handle HTML strings
117 if ( typeof selector === "string" ) {
118 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
119 // Assume that strings that start and end with <> are HTML and skip the regex check
120 match = [ null, selector, null ];
123 match = rquickExpr.exec( selector );
126 // Match html or make sure no context is specified for #id
127 if ( match && (match[1] || !context) ) {
129 // HANDLE: $(html) -> $(array)
131 context = context instanceof jQuery ? context[0] : context;
133 // scripts is true for back-compat
134 jQuery.merge( this, jQuery.parseHTML(
136 context && context.nodeType ? context.ownerDocument || context : document,
140 // HANDLE: $(html, props)
141 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
142 for ( match in context ) {
143 // Properties of context are called as methods if possible
144 if ( jQuery.isFunction( this[ match ] ) ) {
145 this[ match ]( context[ match ] );
147 // ...and otherwise set as attributes
149 this.attr( match, context[ match ] );
158 elem = document.getElementById( match[2] );
160 // Check parentNode to catch when Blackberry 4.6 returns
161 // nodes that are no longer in the document #6963
162 if ( elem && elem.parentNode ) {
163 // Inject the element directly into the jQuery object
168 this.context = document;
169 this.selector = selector;
173 // HANDLE: $(expr, $(...))
174 } else if ( !context || context.jquery ) {
175 return ( context || rootjQuery ).find( selector );
177 // HANDLE: $(expr, context)
178 // (which is just equivalent to: $(context).find(expr)
180 return this.constructor( context ).find( selector );
183 // HANDLE: $(DOMElement)
184 } else if ( selector.nodeType ) {
185 this.context = this[0] = selector;
189 // HANDLE: $(function)
190 // Shortcut for document ready
191 } else if ( jQuery.isFunction( selector ) ) {
192 return rootjQuery.ready( selector );
195 if ( selector.selector !== undefined ) {
196 this.selector = selector.selector;
197 this.context = selector.context;
200 return jQuery.makeArray( selector, this );
203 // Start with an empty selector
206 // The default length of a jQuery object is 0
209 toArray: function() {
210 return core_slice.call( this );
213 // Get the Nth element in the matched element set OR
214 // Get the whole matched element set as a clean array
215 get: function( num ) {
218 // Return a 'clean' array
221 // Return just the object
222 ( num < 0 ? this[ this.length + num ] : this[ num ] );
225 // Take an array of elements and push it onto the stack
226 // (returning the new matched element set)
227 pushStack: function( elems ) {
229 // Build a new jQuery matched element set
230 var ret = jQuery.merge( this.constructor(), elems );
232 // Add the old object onto the stack (as a reference)
233 ret.prevObject = this;
234 ret.context = this.context;
236 // Return the newly-formed element set
240 // Execute a callback for every element in the matched set.
241 // (You can seed the arguments with an array of args, but this is
242 // only used internally.)
243 each: function( callback, args ) {
244 return jQuery.each( this, callback, args );
247 ready: function( fn ) {
249 jQuery.ready.promise().done( fn );
255 return this.pushStack( core_slice.apply( this, arguments ) );
263 return this.eq( -1 );
267 var len = this.length,
268 j = +i + ( i < 0 ? len : 0 );
269 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
272 map: function( callback ) {
273 return this.pushStack( jQuery.map(this, function( elem, i ) {
274 return callback.call( elem, i, elem );
279 return this.prevObject || this.constructor(null);
282 // For internal use only.
283 // Behaves like an Array's method, not like a jQuery method.
289 // Give the init function the jQuery prototype for later instantiation
290 jQuery.fn.init.prototype = jQuery.fn;
292 jQuery.extend = jQuery.fn.extend = function() {
293 var options, name, src, copy, copyIsArray, clone,
294 target = arguments[0] || {},
296 length = arguments.length,
299 // Handle a deep copy situation
300 if ( typeof target === "boolean" ) {
302 target = arguments[1] || {};
303 // skip the boolean and the target
307 // Handle case when target is a string or something (possible in deep copy)
308 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
312 // extend jQuery itself if only one argument is passed
313 if ( length === i ) {
318 for ( ; i < length; i++ ) {
319 // Only deal with non-null/undefined values
320 if ( (options = arguments[ i ]) != null ) {
321 // Extend the base object
322 for ( name in options ) {
323 src = target[ name ];
324 copy = options[ name ];
326 // Prevent never-ending loop
327 if ( target === copy ) {
331 // Recurse if we're merging plain objects or arrays
332 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
335 clone = src && jQuery.isArray(src) ? src : [];
338 clone = src && jQuery.isPlainObject(src) ? src : {};
341 // Never move original objects, clone them
342 target[ name ] = jQuery.extend( deep, clone, copy );
344 // Don't bring in undefined values
345 } else if ( copy !== undefined ) {
346 target[ name ] = copy;
352 // Return the modified object
357 // Unique for each copy of jQuery on the page
358 expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
360 noConflict: function( deep ) {
361 if ( window.$ === jQuery ) {
365 if ( deep && window.jQuery === jQuery ) {
366 window.jQuery = _jQuery;
372 // Is the DOM ready to be used? Set to true once it occurs.
375 // A counter to track how many items to wait for before
376 // the ready event fires. See #6781
379 // Hold (or release) the ready event
380 holdReady: function( hold ) {
384 jQuery.ready( true );
388 // Handle when the DOM is ready
389 ready: function( wait ) {
391 // Abort if there are pending holds or we're already ready
392 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
396 // Remember that the DOM is ready
397 jQuery.isReady = true;
399 // If a normal DOM Ready event fired, decrement, and wait if need be
400 if ( wait !== true && --jQuery.readyWait > 0 ) {
404 // If there are functions bound, to execute
405 readyList.resolveWith( document, [ jQuery ] );
407 // Trigger any bound ready events
408 if ( jQuery.fn.trigger ) {
409 jQuery( document ).trigger("ready").off("ready");
413 // See test/unit/core.js for details concerning isFunction.
414 // Since version 1.3, DOM methods and functions like alert
415 // aren't supported. They return false on IE (#2968).
416 isFunction: function( obj ) {
417 return jQuery.type(obj) === "function";
420 isArray: Array.isArray,
422 isWindow: function( obj ) {
423 return obj != null && obj === obj.window;
426 isNumeric: function( obj ) {
427 return !isNaN( parseFloat(obj) ) && isFinite( obj );
430 type: function( obj ) {
432 return String( obj );
434 // Support: Safari <= 5.1 (functionish RegExp)
435 return typeof obj === "object" || typeof obj === "function" ?
436 class2type[ core_toString.call(obj) ] || "object" :
440 isPlainObject: function( obj ) {
441 // Not plain objects:
442 // - Any object or value whose internal [[Class]] property is not "[object Object]"
445 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
449 // Support: Firefox <20
450 // The try/catch suppresses exceptions thrown when attempting to access
451 // the "constructor" property of certain host objects, ie. |window.location|
452 // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
454 if ( obj.constructor &&
455 !core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
462 // If the function hasn't returned already, we're confident that
463 // |obj| is a plain object, created by {} or constructed with new Object
467 isEmptyObject: function( obj ) {
469 for ( name in obj ) {
475 error: function( msg ) {
476 throw new Error( msg );
479 // data: string of html
480 // context (optional): If specified, the fragment will be created in this context, defaults to document
481 // keepScripts (optional): If true, will include scripts passed in the html string
482 parseHTML: function( data, context, keepScripts ) {
483 if ( !data || typeof data !== "string" ) {
486 if ( typeof context === "boolean" ) {
487 keepScripts = context;
490 context = context || document;
492 var parsed = rsingleTag.exec( data ),
493 scripts = !keepScripts && [];
497 return [ context.createElement( parsed[1] ) ];
500 parsed = jQuery.buildFragment( [ data ], context, scripts );
503 jQuery( scripts ).remove();
506 return jQuery.merge( [], parsed.childNodes );
509 parseJSON: JSON.parse,
511 // Cross-browser xml parsing
512 parseXML: function( data ) {
514 if ( !data || typeof data !== "string" ) {
520 tmp = new DOMParser();
521 xml = tmp.parseFromString( data , "text/xml" );
526 if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
527 jQuery.error( "Invalid XML: " + data );
534 // Evaluates a script in a global context
535 globalEval: function( code ) {
539 code = jQuery.trim( code );
542 // If the code includes a valid, prologue position
543 // strict mode pragma, execute code by injecting a
544 // script tag into the document.
545 if ( code.indexOf("use strict") === 1 ) {
546 script = document.createElement("script");
548 document.head.appendChild( script ).parentNode.removeChild( script );
550 // Otherwise, avoid the DOM node creation, insertion
551 // and removal by using an indirect global eval
557 // Convert dashed to camelCase; used by the css and data modules
558 // Microsoft forgot to hump their vendor prefix (#9572)
559 camelCase: function( string ) {
560 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
563 nodeName: function( elem, name ) {
564 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
567 // args is for internal usage only
568 each: function( obj, callback, args ) {
572 isArray = isArraylike( obj );
576 for ( ; i < length; i++ ) {
577 value = callback.apply( obj[ i ], args );
579 if ( value === false ) {
585 value = callback.apply( obj[ i ], args );
587 if ( value === false ) {
593 // A special, fast, case for the most common use of each
596 for ( ; i < length; i++ ) {
597 value = callback.call( obj[ i ], i, obj[ i ] );
599 if ( value === false ) {
605 value = callback.call( obj[ i ], i, obj[ i ] );
607 if ( value === false ) {
617 trim: function( text ) {
618 return text == null ? "" : core_trim.call( text );
621 // results is for internal usage only
622 makeArray: function( arr, results ) {
623 var ret = results || [];
626 if ( isArraylike( Object(arr) ) ) {
628 typeof arr === "string" ?
632 core_push.call( ret, arr );
639 inArray: function( elem, arr, i ) {
640 return arr == null ? -1 : core_indexOf.call( arr, elem, i );
643 merge: function( first, second ) {
644 var l = second.length,
648 if ( typeof l === "number" ) {
649 for ( ; j < l; j++ ) {
650 first[ i++ ] = second[ j ];
653 while ( second[j] !== undefined ) {
654 first[ i++ ] = second[ j++ ];
663 grep: function( elems, callback, inv ) {
667 length = elems.length;
670 // Go through the array, only saving the items
671 // that pass the validator function
672 for ( ; i < length; i++ ) {
673 retVal = !!callback( elems[ i ], i );
674 if ( inv !== retVal ) {
675 ret.push( elems[ i ] );
682 // arg is for internal usage only
683 map: function( elems, callback, arg ) {
686 length = elems.length,
687 isArray = isArraylike( elems ),
690 // Go through the array, translating each of the items to their
692 for ( ; i < length; i++ ) {
693 value = callback( elems[ i ], i, arg );
695 if ( value != null ) {
696 ret[ ret.length ] = value;
700 // Go through every key on the object,
703 value = callback( elems[ i ], i, arg );
705 if ( value != null ) {
706 ret[ ret.length ] = value;
711 // Flatten any nested arrays
712 return core_concat.apply( [], ret );
715 // A global GUID counter for objects
718 // Bind a function to a context, optionally partially applying any
720 proxy: function( fn, context ) {
721 var tmp, args, proxy;
723 if ( typeof context === "string" ) {
729 // Quick check to determine if target is callable, in the spec
730 // this throws a TypeError, but we will just return undefined.
731 if ( !jQuery.isFunction( fn ) ) {
736 args = core_slice.call( arguments, 2 );
738 return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
741 // Set the guid of unique handler to the same of original handler, so it can be removed
742 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
747 // Multifunctional method to get and set values of a collection
748 // The value/s can optionally be executed if it's a function
749 access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
751 length = elems.length,
755 if ( jQuery.type( key ) === "object" ) {
758 jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
762 } else if ( value !== undefined ) {
765 if ( !jQuery.isFunction( value ) ) {
770 // Bulk operations run against the entire set
772 fn.call( elems, value );
775 // ...except when executing function values
778 fn = function( elem, key, value ) {
779 return bulk.call( jQuery( elem ), value );
785 for ( ; i < length; i++ ) {
786 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
797 length ? fn( elems[0], key ) : emptyGet;
802 // A method for quickly swapping in/out CSS properties to get correct calculations.
803 // Note: this method belongs to the css module but it's needed here for the support module.
804 // If support gets modularized, this method should be moved back to the css module.
805 swap: function( elem, options, callback, args ) {
809 // Remember the old values, and insert the new ones
810 for ( name in options ) {
811 old[ name ] = elem.style[ name ];
812 elem.style[ name ] = options[ name ];
815 ret = callback.apply( elem, args || [] );
817 // Revert the old values
818 for ( name in options ) {
819 elem.style[ name ] = old[ name ];
826 jQuery.ready.promise = function( obj ) {
829 readyList = jQuery.Deferred();
831 // Catch cases where $(document).ready() is called after the browser event has already occurred.
832 // we once tried to use readyState "interactive" here, but it caused issues like the one
833 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
834 if ( document.readyState === "complete" ) {
835 // Handle it asynchronously to allow scripts the opportunity to delay ready
836 setTimeout( jQuery.ready );
840 // Use the handy event callback
841 document.addEventListener( "DOMContentLoaded", completed, false );
843 // A fallback to window.onload, that will always work
844 window.addEventListener( "load", completed, false );
847 return readyList.promise( obj );
850 // Populate the class2type map
851 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
852 class2type[ "[object " + name + "]" ] = name.toLowerCase();
855 function isArraylike( obj ) {
856 var length = obj.length,
857 type = jQuery.type( obj );
859 if ( jQuery.isWindow( obj ) ) {
863 if ( obj.nodeType === 1 && length ) {
867 return type === "array" || type !== "function" &&
869 typeof length === "number" && length > 0 && ( length - 1 ) in obj );
872 // All jQuery objects should point back to these
873 rootjQuery = jQuery(document);
875 * Sizzle CSS Selector Engine v1.9.4-pre
876 * http://sizzlejs.com/
878 * Copyright 2013 jQuery Foundation, Inc. and other contributors
879 * Released under the MIT license
880 * http://jquery.org/license
884 (function( window, undefined ) {
896 // Local document vars
906 // Instance-specific data
907 expando = "sizzle" + -(new Date()),
908 preferredDoc = window.document,
911 classCache = createCache(),
912 tokenCache = createCache(),
913 compilerCache = createCache(),
914 hasDuplicate = false,
915 sortOrder = function( a, b ) {
923 // General-purpose constants
924 strundefined = typeof undefined,
925 MAX_NEGATIVE = 1 << 31,
928 hasOwn = ({}).hasOwnProperty,
931 push_native = arr.push,
934 // Use a stripped-down indexOf if we can't use a native one
935 indexOf = arr.indexOf || function( elem ) {
938 for ( ; i < len; i++ ) {
939 if ( this[i] === elem ) {
946 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
948 // Regular expressions
950 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
951 whitespace = "[\\x20\\t\\r\\n\\f]",
952 // http://www.w3.org/TR/css3-syntax/#characters
953 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
955 // Loosely modeled on CSS identifier characters
956 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
957 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
958 identifier = characterEncoding.replace( "w", "w#" ),
960 // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
961 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
962 "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
964 // Prefer arguments quoted,
965 // then not containing pseudos/brackets,
966 // then attribute selectors/non-parenthetical expressions,
967 // then anything else
968 // These preferences are here to reduce the number of selectors
969 // needing tokenize in the PSEUDO preFilter
970 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
972 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
973 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
975 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
976 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
978 rsibling = new RegExp( whitespace + "*[+~]" ),
979 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
981 rpseudo = new RegExp( pseudos ),
982 ridentifier = new RegExp( "^" + identifier + "$" ),
985 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
986 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
987 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
988 "ATTR": new RegExp( "^" + attributes ),
989 "PSEUDO": new RegExp( "^" + pseudos ),
990 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
991 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
992 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
993 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
994 // For use in libraries implementing .is()
995 // We use this for POS matching in `select`
996 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
997 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
1000 rnative = /^[^{]+\{\s*\[native \w/,
1002 // Easily-parseable/retrievable ID or TAG or CLASS selectors
1003 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
1005 rinputs = /^(?:input|select|textarea|button)$/i,
1010 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
1011 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
1012 funescape = function( _, escaped, escapedWhitespace ) {
1013 var high = "0x" + escaped - 0x10000;
1014 // NaN means non-codepoint
1016 // Workaround erroneous numeric interpretation of +"0x"
1017 return high !== high || escapedWhitespace ?
1021 String.fromCharCode( high + 0x10000 ) :
1022 // Supplemental Plane codepoint (surrogate pair)
1023 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
1026 // Optimize for push.apply( _, NodeList )
1029 (arr = slice.call( preferredDoc.childNodes )),
1030 preferredDoc.childNodes
1032 // Support: Android<4.0
1033 // Detect silently failing push.apply
1034 arr[ preferredDoc.childNodes.length ].nodeType;
1036 push = { apply: arr.length ?
1038 // Leverage slice if possible
1039 function( target, els ) {
1040 push_native.apply( target, slice.call(els) );
1044 // Otherwise append directly
1045 function( target, els ) {
1046 var j = target.length,
1048 // Can't trust NodeList.length
1049 while ( (target[j++] = els[i++]) ) {}
1050 target.length = j - 1;
1055 function Sizzle( selector, context, results, seed ) {
1056 var match, elem, m, nodeType,
1058 i, groups, old, nid, newContext, newSelector;
1060 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
1061 setDocument( context );
1064 context = context || document;
1065 results = results || [];
1067 if ( !selector || typeof selector !== "string" ) {
1071 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
1075 if ( documentIsHTML && !seed ) {
1078 if ( (match = rquickExpr.exec( selector )) ) {
1079 // Speed-up: Sizzle("#ID")
1080 if ( (m = match[1]) ) {
1081 if ( nodeType === 9 ) {
1082 elem = context.getElementById( m );
1083 // Check parentNode to catch when Blackberry 4.6 returns
1084 // nodes that are no longer in the document #6963
1085 if ( elem && elem.parentNode ) {
1086 // Handle the case where IE, Opera, and Webkit return items
1087 // by name instead of ID
1088 if ( elem.id === m ) {
1089 results.push( elem );
1096 // Context is not a document
1097 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
1098 contains( context, elem ) && elem.id === m ) {
1099 results.push( elem );
1104 // Speed-up: Sizzle("TAG")
1105 } else if ( match[2] ) {
1106 push.apply( results, context.getElementsByTagName( selector ) );
1109 // Speed-up: Sizzle(".CLASS")
1110 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
1111 push.apply( results, context.getElementsByClassName( m ) );
1117 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
1118 nid = old = expando;
1119 newContext = context;
1120 newSelector = nodeType === 9 && selector;
1122 // qSA works strangely on Element-rooted queries
1123 // We can work around this by specifying an extra ID on the root
1124 // and working up from there (Thanks to Andrew Dupont for the technique)
1125 // IE 8 doesn't work on object elements
1126 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
1127 groups = tokenize( selector );
1129 if ( (old = context.getAttribute("id")) ) {
1130 nid = old.replace( rescape, "\\$&" );
1132 context.setAttribute( "id", nid );
1134 nid = "[id='" + nid + "'] ";
1138 groups[i] = nid + toSelector( groups[i] );
1140 newContext = rsibling.test( selector ) && context.parentNode || context;
1141 newSelector = groups.join(",");
1144 if ( newSelector ) {
1146 push.apply( results,
1147 newContext.querySelectorAll( newSelector )
1153 context.removeAttribute("id");
1161 return select( selector.replace( rtrim, "$1" ), context, results, seed );
1165 * Create key-value caches of limited size
1166 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
1167 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
1168 * deleting the oldest entry
1170 function createCache() {
1173 function cache( key, value ) {
1174 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
1175 if ( keys.push( key += " " ) > Expr.cacheLength ) {
1176 // Only keep the most recent entries
1177 delete cache[ keys.shift() ];
1179 return (cache[ key ] = value);
1185 * Mark a function for special use by Sizzle
1186 * @param {Function} fn The function to mark
1188 function markFunction( fn ) {
1189 fn[ expando ] = true;
1194 * Support testing using an element
1195 * @param {Function} fn Passed the created div and expects a boolean result
1197 function assert( fn ) {
1198 var div = document.createElement("div");
1205 // Remove from its parent by default
1206 if ( div.parentNode ) {
1207 div.parentNode.removeChild( div );
1209 // release memory in IE
1215 * Adds the same handler for all of the specified attrs
1216 * @param {String} attrs Pipe-separated list of attributes
1217 * @param {Function} handler The method that will be applied
1219 function addHandle( attrs, handler ) {
1220 var arr = attrs.split("|"),
1224 Expr.attrHandle[ arr[i] ] = handler;
1229 * Checks document order of two siblings
1230 * @param {Element} a
1231 * @param {Element} b
1232 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
1234 function siblingCheck( a, b ) {
1236 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
1237 ( ~b.sourceIndex || MAX_NEGATIVE ) -
1238 ( ~a.sourceIndex || MAX_NEGATIVE );
1240 // Use IE sourceIndex if available on both nodes
1245 // Check if b follows a
1247 while ( (cur = cur.nextSibling) ) {
1258 * Returns a function to use in pseudos for input types
1259 * @param {String} type
1261 function createInputPseudo( type ) {
1262 return function( elem ) {
1263 var name = elem.nodeName.toLowerCase();
1264 return name === "input" && elem.type === type;
1269 * Returns a function to use in pseudos for buttons
1270 * @param {String} type
1272 function createButtonPseudo( type ) {
1273 return function( elem ) {
1274 var name = elem.nodeName.toLowerCase();
1275 return (name === "input" || name === "button") && elem.type === type;
1280 * Returns a function to use in pseudos for positionals
1281 * @param {Function} fn
1283 function createPositionalPseudo( fn ) {
1284 return markFunction(function( argument ) {
1285 argument = +argument;
1286 return markFunction(function( seed, matches ) {
1288 matchIndexes = fn( [], seed.length, argument ),
1289 i = matchIndexes.length;
1291 // Match elements found at the specified indexes
1293 if ( seed[ (j = matchIndexes[i]) ] ) {
1294 seed[j] = !(matches[j] = seed[j]);
1303 * @param {Element|Object} elem An element or a document
1305 isXML = Sizzle.isXML = function( elem ) {
1306 // documentElement is verified for cases where it doesn't yet exist
1307 // (such as loading iframes in IE - #4833)
1308 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1309 return documentElement ? documentElement.nodeName !== "HTML" : false;
1312 // Expose support vars for convenience
1313 support = Sizzle.support = {};
1316 * Sets document-related variables once based on the current document
1317 * @param {Element|Object} [doc] An element or document object to use to set the document
1318 * @returns {Object} Returns the current document
1320 setDocument = Sizzle.setDocument = function( node ) {
1321 var doc = node ? node.ownerDocument || node : preferredDoc,
1322 parent = doc.defaultView;
1324 // If no document and documentElement is available, return
1325 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1331 docElem = doc.documentElement;
1334 documentIsHTML = !isXML( doc );
1337 // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1338 // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1339 // IE6-8 do not support the defaultView property so parent will be undefined
1340 if ( parent && parent.attachEvent && parent !== parent.top ) {
1341 parent.attachEvent( "onbeforeunload", function() {
1347 ---------------------------------------------------------------------- */
1350 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1351 support.attributes = assert(function( div ) {
1352 div.className = "i";
1353 return !div.getAttribute("className");
1357 ---------------------------------------------------------------------- */
1359 // Check if getElementsByTagName("*") returns only elements
1360 support.getElementsByTagName = assert(function( div ) {
1361 div.appendChild( doc.createComment("") );
1362 return !div.getElementsByTagName("*").length;
1365 // Check if getElementsByClassName can be trusted
1366 support.getElementsByClassName = assert(function( div ) {
1367 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1369 // Support: Safari<4
1370 // Catch class over-caching
1371 div.firstChild.className = "i";
1372 // Support: Opera<10
1373 // Catch gEBCN failure to find non-leading classes
1374 return div.getElementsByClassName("i").length === 2;
1378 // Check if getElementById returns elements by name
1379 // The broken getElementById methods don't pick up programatically-set names,
1380 // so use a roundabout getElementsByName test
1381 support.getById = assert(function( div ) {
1382 docElem.appendChild( div ).id = expando;
1383 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1386 // ID find and filter
1387 if ( support.getById ) {
1388 Expr.find["ID"] = function( id, context ) {
1389 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1390 var m = context.getElementById( id );
1391 // Check parentNode to catch when Blackberry 4.6 returns
1392 // nodes that are no longer in the document #6963
1393 return m && m.parentNode ? [m] : [];
1396 Expr.filter["ID"] = function( id ) {
1397 var attrId = id.replace( runescape, funescape );
1398 return function( elem ) {
1399 return elem.getAttribute("id") === attrId;
1404 // getElementById is not reliable as a find shortcut
1405 delete Expr.find["ID"];
1407 Expr.filter["ID"] = function( id ) {
1408 var attrId = id.replace( runescape, funescape );
1409 return function( elem ) {
1410 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1411 return node && node.value === attrId;
1417 Expr.find["TAG"] = support.getElementsByTagName ?
1418 function( tag, context ) {
1419 if ( typeof context.getElementsByTagName !== strundefined ) {
1420 return context.getElementsByTagName( tag );
1423 function( tag, context ) {
1427 results = context.getElementsByTagName( tag );
1429 // Filter out possible comments
1430 if ( tag === "*" ) {
1431 while ( (elem = results[i++]) ) {
1432 if ( elem.nodeType === 1 ) {
1443 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1444 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1445 return context.getElementsByClassName( className );
1449 /* QSA/matchesSelector
1450 ---------------------------------------------------------------------- */
1452 // QSA and matchesSelector support
1454 // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1457 // qSa(:focus) reports false when true (Chrome 21)
1458 // We allow this because of a bug in IE8/9 that throws an error
1459 // whenever `document.activeElement` is accessed on an iframe
1460 // So, we allow :focus to pass through QSA all the time to avoid the IE error
1461 // See http://bugs.jquery.com/ticket/13378
1464 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1466 // Regex strategy adopted from Diego Perini
1467 assert(function( div ) {
1468 // Select is set to empty string on purpose
1469 // This is to test IE's treatment of not explicitly
1470 // setting a boolean content attribute,
1471 // since its presence should be enough
1472 // http://bugs.jquery.com/ticket/12359
1473 div.innerHTML = "<select><option selected=''></option></select>";
1476 // Boolean attributes and "value" are not treated correctly
1477 if ( !div.querySelectorAll("[selected]").length ) {
1478 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1481 // Webkit/Opera - :checked should return selected option elements
1482 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1483 // IE8 throws error here and will not see later tests
1484 if ( !div.querySelectorAll(":checked").length ) {
1485 rbuggyQSA.push(":checked");
1489 assert(function( div ) {
1491 // Support: Opera 10-12/IE8
1492 // ^= $= *= and empty values
1493 // Should not select anything
1494 // Support: Windows 8 Native Apps
1495 // The type attribute is restricted during .innerHTML assignment
1496 var input = doc.createElement("input");
1497 input.setAttribute( "type", "hidden" );
1498 div.appendChild( input ).setAttribute( "t", "" );
1500 if ( div.querySelectorAll("[t^='']").length ) {
1501 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1504 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1505 // IE8 throws error here and will not see later tests
1506 if ( !div.querySelectorAll(":enabled").length ) {
1507 rbuggyQSA.push( ":enabled", ":disabled" );
1510 // Opera 10-11 does not throw on post-comma invalid pseudos
1511 div.querySelectorAll("*,:x");
1512 rbuggyQSA.push(",.*:");
1516 if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
1517 docElem.mozMatchesSelector ||
1518 docElem.oMatchesSelector ||
1519 docElem.msMatchesSelector) )) ) {
1521 assert(function( div ) {
1522 // Check to see if it's possible to do matchesSelector
1523 // on a disconnected node (IE 9)
1524 support.disconnectedMatch = matches.call( div, "div" );
1526 // This should fail with an exception
1527 // Gecko does not error, returns false instead
1528 matches.call( div, "[s!='']:x" );
1529 rbuggyMatches.push( "!=", pseudos );
1533 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1534 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1537 ---------------------------------------------------------------------- */
1539 // Element contains another
1540 // Purposefully does not implement inclusive descendent
1541 // As in, an element does not contain itself
1542 contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
1544 var adown = a.nodeType === 9 ? a.documentElement : a,
1545 bup = b && b.parentNode;
1546 return a === bup || !!( bup && bup.nodeType === 1 && (
1548 adown.contains( bup ) :
1549 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1554 while ( (b = b.parentNode) ) {
1564 ---------------------------------------------------------------------- */
1566 // Document order sorting
1567 sortOrder = docElem.compareDocumentPosition ?
1570 // Flag for duplicate removal
1572 hasDuplicate = true;
1576 var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
1579 // Disconnected nodes
1581 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1583 // Choose the first element that is related to our preferred document
1584 if ( a === doc || contains(preferredDoc, a) ) {
1587 if ( b === doc || contains(preferredDoc, b) ) {
1591 // Maintain original order
1593 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1597 return compare & 4 ? -1 : 1;
1600 // Not directly comparable, sort on existence of method
1601 return a.compareDocumentPosition ? -1 : 1;
1611 // Exit early if the nodes are identical
1613 hasDuplicate = true;
1616 // Parentless nodes are either documents or disconnected
1617 } else if ( !aup || !bup ) {
1618 return a === doc ? -1 :
1623 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1626 // If the nodes are siblings, we can do a quick check
1627 } else if ( aup === bup ) {
1628 return siblingCheck( a, b );
1631 // Otherwise we need full lists of their ancestors for comparison
1633 while ( (cur = cur.parentNode) ) {
1637 while ( (cur = cur.parentNode) ) {
1641 // Walk down the tree looking for a discrepancy
1642 while ( ap[i] === bp[i] ) {
1647 // Do a sibling check if the nodes have a common ancestor
1648 siblingCheck( ap[i], bp[i] ) :
1650 // Otherwise nodes in our document sort first
1651 ap[i] === preferredDoc ? -1 :
1652 bp[i] === preferredDoc ? 1 :
1659 Sizzle.matches = function( expr, elements ) {
1660 return Sizzle( expr, null, null, elements );
1663 Sizzle.matchesSelector = function( elem, expr ) {
1664 // Set document vars if needed
1665 if ( ( elem.ownerDocument || elem ) !== document ) {
1666 setDocument( elem );
1669 // Make sure that attribute selectors are quoted
1670 expr = expr.replace( rattributeQuotes, "='$1']" );
1672 if ( support.matchesSelector && documentIsHTML &&
1673 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1674 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
1677 var ret = matches.call( elem, expr );
1679 // IE 9's matchesSelector returns false on disconnected nodes
1680 if ( ret || support.disconnectedMatch ||
1681 // As well, disconnected nodes are said to be in a document
1683 elem.document && elem.document.nodeType !== 11 ) {
1689 return Sizzle( expr, document, null, [elem] ).length > 0;
1692 Sizzle.contains = function( context, elem ) {
1693 // Set document vars if needed
1694 if ( ( context.ownerDocument || context ) !== document ) {
1695 setDocument( context );
1697 return contains( context, elem );
1700 Sizzle.attr = function( elem, name ) {
1701 // Set document vars if needed
1702 if ( ( elem.ownerDocument || elem ) !== document ) {
1703 setDocument( elem );
1706 var fn = Expr.attrHandle[ name.toLowerCase() ],
1707 // Don't get fooled by Object.prototype properties (jQuery #13807)
1708 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1709 fn( elem, name, !documentIsHTML ) :
1712 return val === undefined ?
1713 support.attributes || !documentIsHTML ?
1714 elem.getAttribute( name ) :
1715 (val = elem.getAttributeNode(name)) && val.specified ?
1721 Sizzle.error = function( msg ) {
1722 throw new Error( "Syntax error, unrecognized expression: " + msg );
1726 * Document sorting and removing duplicates
1727 * @param {ArrayLike} results
1729 Sizzle.uniqueSort = function( results ) {
1735 // Unless we *know* we can detect duplicates, assume their presence
1736 hasDuplicate = !support.detectDuplicates;
1737 sortInput = !support.sortStable && results.slice( 0 );
1738 results.sort( sortOrder );
1740 if ( hasDuplicate ) {
1741 while ( (elem = results[i++]) ) {
1742 if ( elem === results[ i ] ) {
1743 j = duplicates.push( i );
1747 results.splice( duplicates[ j ], 1 );
1755 * Utility function for retrieving the text value of an array of DOM nodes
1756 * @param {Array|Element} elem
1758 getText = Sizzle.getText = function( elem ) {
1762 nodeType = elem.nodeType;
1765 // If no nodeType, this is expected to be an array
1766 for ( ; (node = elem[i]); i++ ) {
1767 // Do not traverse comment nodes
1768 ret += getText( node );
1770 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1771 // Use textContent for elements
1772 // innerText usage removed for consistency of new lines (see #11153)
1773 if ( typeof elem.textContent === "string" ) {
1774 return elem.textContent;
1776 // Traverse its children
1777 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1778 ret += getText( elem );
1781 } else if ( nodeType === 3 || nodeType === 4 ) {
1782 return elem.nodeValue;
1784 // Do not include comment or processing instruction nodes
1789 Expr = Sizzle.selectors = {
1791 // Can be adjusted by the user
1794 createPseudo: markFunction,
1803 ">": { dir: "parentNode", first: true },
1804 " ": { dir: "parentNode" },
1805 "+": { dir: "previousSibling", first: true },
1806 "~": { dir: "previousSibling" }
1810 "ATTR": function( match ) {
1811 match[1] = match[1].replace( runescape, funescape );
1813 // Move the given value to match[3] whether quoted or unquoted
1814 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
1816 if ( match[2] === "~=" ) {
1817 match[3] = " " + match[3] + " ";
1820 return match.slice( 0, 4 );
1823 "CHILD": function( match ) {
1824 /* matches from matchExpr["CHILD"]
1825 1 type (only|nth|...)
1826 2 what (child|of-type)
1827 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1828 4 xn-component of xn+y argument ([+-]?\d*n|)
1829 5 sign of xn-component
1831 7 sign of y-component
1834 match[1] = match[1].toLowerCase();
1836 if ( match[1].slice( 0, 3 ) === "nth" ) {
1837 // nth-* requires argument
1839 Sizzle.error( match[0] );
1842 // numeric x and y parameters for Expr.filter.CHILD
1843 // remember that false/true cast respectively to 0/1
1844 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1845 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1847 // other types prohibit arguments
1848 } else if ( match[3] ) {
1849 Sizzle.error( match[0] );
1855 "PSEUDO": function( match ) {
1857 unquoted = !match[5] && match[2];
1859 if ( matchExpr["CHILD"].test( match[0] ) ) {
1863 // Accept quoted arguments as-is
1864 if ( match[3] && match[4] !== undefined ) {
1865 match[2] = match[4];
1867 // Strip excess characters from unquoted arguments
1868 } else if ( unquoted && rpseudo.test( unquoted ) &&
1869 // Get excess from tokenize (recursively)
1870 (excess = tokenize( unquoted, true )) &&
1871 // advance to the next closing parenthesis
1872 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1874 // excess is a negative index
1875 match[0] = match[0].slice( 0, excess );
1876 match[2] = unquoted.slice( 0, excess );
1879 // Return only captures needed by the pseudo filter method (type and argument)
1880 return match.slice( 0, 3 );
1886 "TAG": function( nodeNameSelector ) {
1887 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1888 return nodeNameSelector === "*" ?
1889 function() { return true; } :
1891 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1895 "CLASS": function( className ) {
1896 var pattern = classCache[ className + " " ];
1899 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1900 classCache( className, function( elem ) {
1901 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
1905 "ATTR": function( name, operator, check ) {
1906 return function( elem ) {
1907 var result = Sizzle.attr( elem, name );
1909 if ( result == null ) {
1910 return operator === "!=";
1918 return operator === "=" ? result === check :
1919 operator === "!=" ? result !== check :
1920 operator === "^=" ? check && result.indexOf( check ) === 0 :
1921 operator === "*=" ? check && result.indexOf( check ) > -1 :
1922 operator === "$=" ? check && result.slice( -check.length ) === check :
1923 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
1924 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1929 "CHILD": function( type, what, argument, first, last ) {
1930 var simple = type.slice( 0, 3 ) !== "nth",
1931 forward = type.slice( -4 ) !== "last",
1932 ofType = what === "of-type";
1934 return first === 1 && last === 0 ?
1936 // Shortcut for :nth-*(n)
1938 return !!elem.parentNode;
1941 function( elem, context, xml ) {
1942 var cache, outerCache, node, diff, nodeIndex, start,
1943 dir = simple !== forward ? "nextSibling" : "previousSibling",
1944 parent = elem.parentNode,
1945 name = ofType && elem.nodeName.toLowerCase(),
1946 useCache = !xml && !ofType;
1950 // :(first|last|only)-(child|of-type)
1954 while ( (node = node[ dir ]) ) {
1955 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
1959 // Reverse direction for :only-* (if we haven't yet done so)
1960 start = dir = type === "only" && !start && "nextSibling";
1965 start = [ forward ? parent.firstChild : parent.lastChild ];
1967 // non-xml :nth-child(...) stores cache data on `parent`
1968 if ( forward && useCache ) {
1969 // Seek `elem` from a previously-cached index
1970 outerCache = parent[ expando ] || (parent[ expando ] = {});
1971 cache = outerCache[ type ] || [];
1972 nodeIndex = cache[0] === dirruns && cache[1];
1973 diff = cache[0] === dirruns && cache[2];
1974 node = nodeIndex && parent.childNodes[ nodeIndex ];
1976 while ( (node = ++nodeIndex && node && node[ dir ] ||
1978 // Fallback to seeking `elem` from the start
1979 (diff = nodeIndex = 0) || start.pop()) ) {
1981 // When found, cache indexes on `parent` and break
1982 if ( node.nodeType === 1 && ++diff && node === elem ) {
1983 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
1988 // Use previously-cached element index if available
1989 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
1992 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
1994 // Use the same loop as above to seek `elem` from the start
1995 while ( (node = ++nodeIndex && node && node[ dir ] ||
1996 (diff = nodeIndex = 0) || start.pop()) ) {
1998 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
1999 // Cache the index of each encountered element
2001 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
2004 if ( node === elem ) {
2011 // Incorporate the offset, then check against cycle size
2013 return diff === first || ( diff % first === 0 && diff / first >= 0 );
2018 "PSEUDO": function( pseudo, argument ) {
2019 // pseudo-class names are case-insensitive
2020 // http://www.w3.org/TR/selectors/#pseudo-classes
2021 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
2022 // Remember that setFilters inherits from pseudos
2024 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
2025 Sizzle.error( "unsupported pseudo: " + pseudo );
2027 // The user may use createPseudo to indicate that
2028 // arguments are needed to create the filter function
2029 // just as Sizzle does
2030 if ( fn[ expando ] ) {
2031 return fn( argument );
2034 // But maintain support for old signatures
2035 if ( fn.length > 1 ) {
2036 args = [ pseudo, pseudo, "", argument ];
2037 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
2038 markFunction(function( seed, matches ) {
2040 matched = fn( seed, argument ),
2043 idx = indexOf.call( seed, matched[i] );
2044 seed[ idx ] = !( matches[ idx ] = matched[i] );
2048 return fn( elem, 0, args );
2057 // Potentially complex pseudos
2058 "not": markFunction(function( selector ) {
2059 // Trim the selector passed to compile
2060 // to avoid treating leading and trailing
2061 // spaces as combinators
2064 matcher = compile( selector.replace( rtrim, "$1" ) );
2066 return matcher[ expando ] ?
2067 markFunction(function( seed, matches, context, xml ) {
2069 unmatched = matcher( seed, null, xml, [] ),
2072 // Match elements unmatched by `matcher`
2074 if ( (elem = unmatched[i]) ) {
2075 seed[i] = !(matches[i] = elem);
2079 function( elem, context, xml ) {
2081 matcher( input, null, xml, results );
2082 return !results.pop();
2086 "has": markFunction(function( selector ) {
2087 return function( elem ) {
2088 return Sizzle( selector, elem ).length > 0;
2092 "contains": markFunction(function( text ) {
2093 return function( elem ) {
2094 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2098 // "Whether an element is represented by a :lang() selector
2099 // is based solely on the element's language value
2100 // being equal to the identifier C,
2101 // or beginning with the identifier C immediately followed by "-".
2102 // The matching of C against the element's language value is performed case-insensitively.
2103 // The identifier C does not have to be a valid language name."
2104 // http://www.w3.org/TR/selectors/#lang-pseudo
2105 "lang": markFunction( function( lang ) {
2106 // lang value must be a valid identifier
2107 if ( !ridentifier.test(lang || "") ) {
2108 Sizzle.error( "unsupported lang: " + lang );
2110 lang = lang.replace( runescape, funescape ).toLowerCase();
2111 return function( elem ) {
2114 if ( (elemLang = documentIsHTML ?
2116 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2118 elemLang = elemLang.toLowerCase();
2119 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2121 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2127 "target": function( elem ) {
2128 var hash = window.location && window.location.hash;
2129 return hash && hash.slice( 1 ) === elem.id;
2132 "root": function( elem ) {
2133 return elem === docElem;
2136 "focus": function( elem ) {
2137 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2140 // Boolean properties
2141 "enabled": function( elem ) {
2142 return elem.disabled === false;
2145 "disabled": function( elem ) {
2146 return elem.disabled === true;
2149 "checked": function( elem ) {
2150 // In CSS3, :checked should return both checked and selected elements
2151 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2152 var nodeName = elem.nodeName.toLowerCase();
2153 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2156 "selected": function( elem ) {
2157 // Accessing this property makes selected-by-default
2158 // options in Safari work properly
2159 if ( elem.parentNode ) {
2160 elem.parentNode.selectedIndex;
2163 return elem.selected === true;
2167 "empty": function( elem ) {
2168 // http://www.w3.org/TR/selectors/#empty-pseudo
2169 // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
2170 // not comment, processing instructions, or others
2171 // Thanks to Diego Perini for the nodeName shortcut
2172 // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
2173 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2174 if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
2181 "parent": function( elem ) {
2182 return !Expr.pseudos["empty"]( elem );
2185 // Element/input types
2186 "header": function( elem ) {
2187 return rheader.test( elem.nodeName );
2190 "input": function( elem ) {
2191 return rinputs.test( elem.nodeName );
2194 "button": function( elem ) {
2195 var name = elem.nodeName.toLowerCase();
2196 return name === "input" && elem.type === "button" || name === "button";
2199 "text": function( elem ) {
2201 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
2202 // use getAttribute instead to test this case
2203 return elem.nodeName.toLowerCase() === "input" &&
2204 elem.type === "text" &&
2205 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
2208 // Position-in-collection
2209 "first": createPositionalPseudo(function() {
2213 "last": createPositionalPseudo(function( matchIndexes, length ) {
2214 return [ length - 1 ];
2217 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2218 return [ argument < 0 ? argument + length : argument ];
2221 "even": createPositionalPseudo(function( matchIndexes, length ) {
2223 for ( ; i < length; i += 2 ) {
2224 matchIndexes.push( i );
2226 return matchIndexes;
2229 "odd": createPositionalPseudo(function( matchIndexes, length ) {
2231 for ( ; i < length; i += 2 ) {
2232 matchIndexes.push( i );
2234 return matchIndexes;
2237 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2238 var i = argument < 0 ? argument + length : argument;
2239 for ( ; --i >= 0; ) {
2240 matchIndexes.push( i );
2242 return matchIndexes;
2245 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2246 var i = argument < 0 ? argument + length : argument;
2247 for ( ; ++i < length; ) {
2248 matchIndexes.push( i );
2250 return matchIndexes;
2255 Expr.pseudos["nth"] = Expr.pseudos["eq"];
2257 // Add button/input type pseudos
2258 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2259 Expr.pseudos[ i ] = createInputPseudo( i );
2261 for ( i in { submit: true, reset: true } ) {
2262 Expr.pseudos[ i ] = createButtonPseudo( i );
2265 // Easy API for creating new setFilters
2266 function setFilters() {}
2267 setFilters.prototype = Expr.filters = Expr.pseudos;
2268 Expr.setFilters = new setFilters();
2270 function tokenize( selector, parseOnly ) {
2271 var matched, match, tokens, type,
2272 soFar, groups, preFilters,
2273 cached = tokenCache[ selector + " " ];
2276 return parseOnly ? 0 : cached.slice( 0 );
2281 preFilters = Expr.preFilter;
2285 // Comma and first run
2286 if ( !matched || (match = rcomma.exec( soFar )) ) {
2288 // Don't consume trailing commas as valid
2289 soFar = soFar.slice( match[0].length ) || soFar;
2291 groups.push( tokens = [] );
2297 if ( (match = rcombinators.exec( soFar )) ) {
2298 matched = match.shift();
2301 // Cast descendant combinators to space
2302 type: match[0].replace( rtrim, " " )
2304 soFar = soFar.slice( matched.length );
2308 for ( type in Expr.filter ) {
2309 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2310 (match = preFilters[ type ]( match ))) ) {
2311 matched = match.shift();
2317 soFar = soFar.slice( matched.length );
2326 // Return the length of the invalid excess
2327 // if we're just parsing
2328 // Otherwise, throw an error or return tokens
2332 Sizzle.error( selector ) :
2334 tokenCache( selector, groups ).slice( 0 );
2337 function toSelector( tokens ) {
2339 len = tokens.length,
2341 for ( ; i < len; i++ ) {
2342 selector += tokens[i].value;
2347 function addCombinator( matcher, combinator, base ) {
2348 var dir = combinator.dir,
2349 checkNonElements = base && dir === "parentNode",
2352 return combinator.first ?
2353 // Check against closest ancestor/preceding element
2354 function( elem, context, xml ) {
2355 while ( (elem = elem[ dir ]) ) {
2356 if ( elem.nodeType === 1 || checkNonElements ) {
2357 return matcher( elem, context, xml );
2362 // Check against all ancestor/preceding elements
2363 function( elem, context, xml ) {
2364 var data, cache, outerCache,
2365 dirkey = dirruns + " " + doneName;
2367 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2369 while ( (elem = elem[ dir ]) ) {
2370 if ( elem.nodeType === 1 || checkNonElements ) {
2371 if ( matcher( elem, context, xml ) ) {
2377 while ( (elem = elem[ dir ]) ) {
2378 if ( elem.nodeType === 1 || checkNonElements ) {
2379 outerCache = elem[ expando ] || (elem[ expando ] = {});
2380 if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
2381 if ( (data = cache[1]) === true || data === cachedruns ) {
2382 return data === true;
2385 cache = outerCache[ dir ] = [ dirkey ];
2386 cache[1] = matcher( elem, context, xml ) || cachedruns;
2387 if ( cache[1] === true ) {
2397 function elementMatcher( matchers ) {
2398 return matchers.length > 1 ?
2399 function( elem, context, xml ) {
2400 var i = matchers.length;
2402 if ( !matchers[i]( elem, context, xml ) ) {
2411 function condense( unmatched, map, filter, context, xml ) {
2415 len = unmatched.length,
2416 mapped = map != null;
2418 for ( ; i < len; i++ ) {
2419 if ( (elem = unmatched[i]) ) {
2420 if ( !filter || filter( elem, context, xml ) ) {
2421 newUnmatched.push( elem );
2429 return newUnmatched;
2432 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2433 if ( postFilter && !postFilter[ expando ] ) {
2434 postFilter = setMatcher( postFilter );
2436 if ( postFinder && !postFinder[ expando ] ) {
2437 postFinder = setMatcher( postFinder, postSelector );
2439 return markFunction(function( seed, results, context, xml ) {
2443 preexisting = results.length,
2445 // Get initial elements from seed or context
2446 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2448 // Prefilter to get matcher input, preserving a map for seed-results synchronization
2449 matcherIn = preFilter && ( seed || !selector ) ?
2450 condense( elems, preMap, preFilter, context, xml ) :
2453 matcherOut = matcher ?
2454 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2455 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2457 // ...intermediate processing is necessary
2460 // ...otherwise use results directly
2464 // Find primary matches
2466 matcher( matcherIn, matcherOut, context, xml );
2471 temp = condense( matcherOut, postMap );
2472 postFilter( temp, [], context, xml );
2474 // Un-match failing elements by moving them back to matcherIn
2477 if ( (elem = temp[i]) ) {
2478 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2484 if ( postFinder || preFilter ) {
2486 // Get the final matcherOut by condensing this intermediate into postFinder contexts
2488 i = matcherOut.length;
2490 if ( (elem = matcherOut[i]) ) {
2491 // Restore matcherIn since elem is not yet a final match
2492 temp.push( (matcherIn[i] = elem) );
2495 postFinder( null, (matcherOut = []), temp, xml );
2498 // Move matched elements from seed to results to keep them synchronized
2499 i = matcherOut.length;
2501 if ( (elem = matcherOut[i]) &&
2502 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2504 seed[temp] = !(results[temp] = elem);
2509 // Add elements to results, through postFinder if defined
2511 matcherOut = condense(
2512 matcherOut === results ?
2513 matcherOut.splice( preexisting, matcherOut.length ) :
2517 postFinder( null, results, matcherOut, xml );
2519 push.apply( results, matcherOut );
2525 function matcherFromTokens( tokens ) {
2526 var checkContext, matcher, j,
2527 len = tokens.length,
2528 leadingRelative = Expr.relative[ tokens[0].type ],
2529 implicitRelative = leadingRelative || Expr.relative[" "],
2530 i = leadingRelative ? 1 : 0,
2532 // The foundational matcher ensures that elements are reachable from top-level context(s)
2533 matchContext = addCombinator( function( elem ) {
2534 return elem === checkContext;
2535 }, implicitRelative, true ),
2536 matchAnyContext = addCombinator( function( elem ) {
2537 return indexOf.call( checkContext, elem ) > -1;
2538 }, implicitRelative, true ),
2539 matchers = [ function( elem, context, xml ) {
2540 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2541 (checkContext = context).nodeType ?
2542 matchContext( elem, context, xml ) :
2543 matchAnyContext( elem, context, xml ) );
2546 for ( ; i < len; i++ ) {
2547 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2548 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2550 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2552 // Return special upon seeing a positional matcher
2553 if ( matcher[ expando ] ) {
2554 // Find the next relative operator (if any) for proper handling
2556 for ( ; j < len; j++ ) {
2557 if ( Expr.relative[ tokens[j].type ] ) {
2562 i > 1 && elementMatcher( matchers ),
2563 i > 1 && toSelector(
2564 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2565 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2566 ).replace( rtrim, "$1" ),
2568 i < j && matcherFromTokens( tokens.slice( i, j ) ),
2569 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2570 j < len && toSelector( tokens )
2573 matchers.push( matcher );
2577 return elementMatcher( matchers );
2580 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2581 // A counter to specify which element is currently being matched
2582 var matcherCachedRuns = 0,
2583 bySet = setMatchers.length > 0,
2584 byElement = elementMatchers.length > 0,
2585 superMatcher = function( seed, context, xml, results, expandContext ) {
2586 var elem, j, matcher,
2590 unmatched = seed && [],
2591 outermost = expandContext != null,
2592 contextBackup = outermostContext,
2593 // We must always have either seed elements or context
2594 elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
2595 // Use integer dirruns iff this is the outermost matcher
2596 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
2599 outermostContext = context !== document && context;
2600 cachedruns = matcherCachedRuns;
2603 // Add elements passing elementMatchers directly to results
2604 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2605 for ( ; (elem = elems[i]) != null; i++ ) {
2606 if ( byElement && elem ) {
2608 while ( (matcher = elementMatchers[j++]) ) {
2609 if ( matcher( elem, context, xml ) ) {
2610 results.push( elem );
2615 dirruns = dirrunsUnique;
2616 cachedruns = ++matcherCachedRuns;
2620 // Track unmatched elements for set filters
2622 // They will have gone through all possible matchers
2623 if ( (elem = !matcher && elem) ) {
2627 // Lengthen the array for every element, matched or not
2629 unmatched.push( elem );
2634 // Apply set filters to unmatched elements
2636 if ( bySet && i !== matchedCount ) {
2638 while ( (matcher = setMatchers[j++]) ) {
2639 matcher( unmatched, setMatched, context, xml );
2643 // Reintegrate element matches to eliminate the need for sorting
2644 if ( matchedCount > 0 ) {
2646 if ( !(unmatched[i] || setMatched[i]) ) {
2647 setMatched[i] = pop.call( results );
2652 // Discard index placeholder values to get only actual matches
2653 setMatched = condense( setMatched );
2656 // Add matches to results
2657 push.apply( results, setMatched );
2659 // Seedless set matches succeeding multiple successful matchers stipulate sorting
2660 if ( outermost && !seed && setMatched.length > 0 &&
2661 ( matchedCount + setMatchers.length ) > 1 ) {
2663 Sizzle.uniqueSort( results );
2667 // Override manipulation of globals by nested matchers
2669 dirruns = dirrunsUnique;
2670 outermostContext = contextBackup;
2677 markFunction( superMatcher ) :
2681 compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
2684 elementMatchers = [],
2685 cached = compilerCache[ selector + " " ];
2688 // Generate a function of recursive functions that can be used to check each element
2690 group = tokenize( selector );
2694 cached = matcherFromTokens( group[i] );
2695 if ( cached[ expando ] ) {
2696 setMatchers.push( cached );
2698 elementMatchers.push( cached );
2702 // Cache the compiled function
2703 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2708 function multipleContexts( selector, contexts, results ) {
2710 len = contexts.length;
2711 for ( ; i < len; i++ ) {
2712 Sizzle( selector, contexts[i], results );
2717 function select( selector, context, results, seed ) {
2718 var i, tokens, token, type, find,
2719 match = tokenize( selector );
2722 // Try to minimize operations if there is only one group
2723 if ( match.length === 1 ) {
2725 // Take a shortcut and set the context if the root selector is an ID
2726 tokens = match[0] = match[0].slice( 0 );
2727 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2728 support.getById && context.nodeType === 9 && documentIsHTML &&
2729 Expr.relative[ tokens[1].type ] ) {
2731 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2735 selector = selector.slice( tokens.shift().value.length );
2738 // Fetch a seed set for right-to-left matching
2739 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2743 // Abort if we hit a combinator
2744 if ( Expr.relative[ (type = token.type) ] ) {
2747 if ( (find = Expr.find[ type ]) ) {
2748 // Search, expanding context for leading sibling combinators
2750 token.matches[0].replace( runescape, funescape ),
2751 rsibling.test( tokens[0].type ) && context.parentNode || context
2754 // If seed is empty or no tokens remain, we can return early
2755 tokens.splice( i, 1 );
2756 selector = seed.length && toSelector( tokens );
2758 push.apply( results, seed );
2769 // Compile and execute a filtering function
2770 // Provide `match` to avoid retokenization if we modified the selector above
2771 compile( selector, match )(
2776 rsibling.test( selector )
2781 // One-time assignments
2784 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2786 // Support: Chrome<14
2787 // Always assume duplicates if they aren't passed to the comparison function
2788 support.detectDuplicates = hasDuplicate;
2790 // Initialize against the default document
2793 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2794 // Detached nodes confoundingly follow *each other*
2795 support.sortDetached = assert(function( div1 ) {
2796 // Should return 1, but returns 4 (following)
2797 return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2801 // Prevent attribute/property "interpolation"
2802 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2803 if ( !assert(function( div ) {
2804 div.innerHTML = "<a href='#'></a>";
2805 return div.firstChild.getAttribute("href") === "#" ;
2807 addHandle( "type|href|height|width", function( elem, name, isXML ) {
2809 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2815 // Use defaultValue in place of getAttribute("value")
2816 if ( !support.attributes || !assert(function( div ) {
2817 div.innerHTML = "<input/>";
2818 div.firstChild.setAttribute( "value", "" );
2819 return div.firstChild.getAttribute( "value" ) === "";
2821 addHandle( "value", function( elem, name, isXML ) {
2822 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2823 return elem.defaultValue;
2829 // Use getAttributeNode to fetch booleans when getAttribute lies
2830 if ( !assert(function( div ) {
2831 return div.getAttribute("disabled") == null;
2833 addHandle( booleans, function( elem, name, isXML ) {
2836 return (val = elem.getAttributeNode( name )) && val.specified ?
2838 elem[ name ] === true ? name.toLowerCase() : null;
2843 jQuery.find = Sizzle;
2844 jQuery.expr = Sizzle.selectors;
2845 jQuery.expr[":"] = jQuery.expr.pseudos;
2846 jQuery.unique = Sizzle.uniqueSort;
2847 jQuery.text = Sizzle.getText;
2848 jQuery.isXMLDoc = Sizzle.isXML;
2849 jQuery.contains = Sizzle.contains;
2853 // String to Object options format cache
2854 var optionsCache = {};
2856 // Convert String-formatted options into Object-formatted ones and store in cache
2857 function createOptions( options ) {
2858 var object = optionsCache[ options ] = {};
2859 jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
2860 object[ flag ] = true;
2866 * Create a callback list using the following parameters:
2868 * options: an optional list of space-separated options that will change how
2869 * the callback list behaves or a more traditional option object
2871 * By default a callback list will act like an event callback list and can be
2872 * "fired" multiple times.
2876 * once: will ensure the callback list can only be fired once (like a Deferred)
2878 * memory: will keep track of previous values and will call any callback added
2879 * after the list has been fired right away with the latest "memorized"
2880 * values (like a Deferred)
2882 * unique: will ensure a callback can only be added once (no duplicate in the list)
2884 * stopOnFalse: interrupt callings when a callback returns false
2887 jQuery.Callbacks = function( options ) {
2889 // Convert options from String-formatted to Object-formatted if needed
2890 // (we check in cache first)
2891 options = typeof options === "string" ?
2892 ( optionsCache[ options ] || createOptions( options ) ) :
2893 jQuery.extend( {}, options );
2895 var // Last fire value (for non-forgettable lists)
2897 // Flag to know if list was already fired
2899 // Flag to know if list is currently firing
2901 // First callback to fire (used internally by add and fireWith)
2903 // End of the loop when firing
2905 // Index of currently firing callback (modified by remove if needed)
2907 // Actual callback list
2909 // Stack of fire calls for repeatable lists
2910 stack = !options.once && [],
2912 fire = function( data ) {
2913 memory = options.memory && data;
2915 firingIndex = firingStart || 0;
2917 firingLength = list.length;
2919 for ( ; list && firingIndex < firingLength; firingIndex++ ) {
2920 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
2921 memory = false; // To prevent further calls using add
2928 if ( stack.length ) {
2929 fire( stack.shift() );
2931 } else if ( memory ) {
2938 // Actual Callbacks object
2940 // Add a callback or a collection of callbacks to the list
2943 // First, we save the current length
2944 var start = list.length;
2945 (function add( args ) {
2946 jQuery.each( args, function( _, arg ) {
2947 var type = jQuery.type( arg );
2948 if ( type === "function" ) {
2949 if ( !options.unique || !self.has( arg ) ) {
2952 } else if ( arg && arg.length && type !== "string" ) {
2953 // Inspect recursively
2958 // Do we need to add the callbacks to the
2959 // current firing batch?
2961 firingLength = list.length;
2962 // With memory, if we're not firing then
2963 // we should call right away
2964 } else if ( memory ) {
2965 firingStart = start;
2971 // Remove a callback from the list
2972 remove: function() {
2974 jQuery.each( arguments, function( _, arg ) {
2976 while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
2977 list.splice( index, 1 );
2978 // Handle firing indexes
2980 if ( index <= firingLength ) {
2983 if ( index <= firingIndex ) {
2992 // Check if a given callback is in the list.
2993 // If no argument is given, return whether or not list has callbacks attached.
2994 has: function( fn ) {
2995 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
2997 // Remove all callbacks from the list
3003 // Have the list do nothing anymore
3004 disable: function() {
3005 list = stack = memory = undefined;
3009 disabled: function() {
3012 // Lock the list in its current state
3021 locked: function() {
3024 // Call all callbacks with the given context and arguments
3025 fireWith: function( context, args ) {
3026 if ( list && ( !fired || stack ) ) {
3028 args = [ context, args.slice ? args.slice() : args ];
3037 // Call all the callbacks with the given arguments
3039 self.fireWith( this, arguments );
3042 // To know if the callbacks have already been called at least once
3052 Deferred: function( func ) {
3054 // action, add listener, listener list, final state
3055 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3056 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3057 [ "notify", "progress", jQuery.Callbacks("memory") ]
3064 always: function() {
3065 deferred.done( arguments ).fail( arguments );
3068 then: function( /* fnDone, fnFail, fnProgress */ ) {
3069 var fns = arguments;
3070 return jQuery.Deferred(function( newDefer ) {
3071 jQuery.each( tuples, function( i, tuple ) {
3072 var action = tuple[ 0 ],
3073 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3074 // deferred[ done | fail | progress ] for forwarding actions to newDefer
3075 deferred[ tuple[1] ](function() {
3076 var returned = fn && fn.apply( this, arguments );
3077 if ( returned && jQuery.isFunction( returned.promise ) ) {
3079 .done( newDefer.resolve )
3080 .fail( newDefer.reject )
3081 .progress( newDefer.notify );
3083 newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3090 // Get a promise for this deferred
3091 // If obj is provided, the promise aspect is added to the object
3092 promise: function( obj ) {
3093 return obj != null ? jQuery.extend( obj, promise ) : promise;
3098 // Keep pipe for back-compat
3099 promise.pipe = promise.then;
3101 // Add list-specific methods
3102 jQuery.each( tuples, function( i, tuple ) {
3103 var list = tuple[ 2 ],
3104 stateString = tuple[ 3 ];
3106 // promise[ done | fail | progress ] = list.add
3107 promise[ tuple[1] ] = list.add;
3110 if ( stateString ) {
3111 list.add(function() {
3112 // state = [ resolved | rejected ]
3113 state = stateString;
3115 // [ reject_list | resolve_list ].disable; progress_list.lock
3116 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3119 // deferred[ resolve | reject | notify ]
3120 deferred[ tuple[0] ] = function() {
3121 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3124 deferred[ tuple[0] + "With" ] = list.fireWith;
3127 // Make the deferred a promise
3128 promise.promise( deferred );
3130 // Call given func if any
3132 func.call( deferred, deferred );
3140 when: function( subordinate /* , ..., subordinateN */ ) {
3142 resolveValues = core_slice.call( arguments ),
3143 length = resolveValues.length,
3145 // the count of uncompleted subordinates
3146 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3148 // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3149 deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3151 // Update function for both resolve and progress values
3152 updateFunc = function( i, contexts, values ) {
3153 return function( value ) {
3154 contexts[ i ] = this;
3155 values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
3156 if( values === progressValues ) {
3157 deferred.notifyWith( contexts, values );
3158 } else if ( !( --remaining ) ) {
3159 deferred.resolveWith( contexts, values );
3164 progressValues, progressContexts, resolveContexts;
3166 // add listeners to Deferred subordinates; treat others as resolved
3168 progressValues = new Array( length );
3169 progressContexts = new Array( length );
3170 resolveContexts = new Array( length );
3171 for ( ; i < length; i++ ) {
3172 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3173 resolveValues[ i ].promise()
3174 .done( updateFunc( i, resolveContexts, resolveValues ) )
3175 .fail( deferred.reject )
3176 .progress( updateFunc( i, progressContexts, progressValues ) );
3183 // if we're not waiting on anything, resolve the master
3185 deferred.resolveWith( resolveContexts, resolveValues );
3188 return deferred.promise();
3191 jQuery.support = (function( support ) {
3192 var input = document.createElement("input"),
3193 fragment = document.createDocumentFragment(),
3194 div = document.createElement("div"),
3195 select = document.createElement("select"),
3196 opt = select.appendChild( document.createElement("option") );
3198 // Finish early in limited environments
3199 if ( !input.type ) {
3203 input.type = "checkbox";
3205 // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
3206 // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
3207 support.checkOn = input.value !== "";
3209 // Must access the parent to make an option select properly
3210 // Support: IE9, IE10
3211 support.optSelected = opt.selected;
3213 // Will be defined later
3214 support.reliableMarginRight = true;
3215 support.boxSizingReliable = true;
3216 support.pixelPosition = false;
3218 // Make sure checked status is properly cloned
3219 // Support: IE9, IE10
3220 input.checked = true;
3221 support.noCloneChecked = input.cloneNode( true ).checked;
3223 // Make sure that the options inside disabled selects aren't marked as disabled
3224 // (WebKit marks them as disabled)
3225 select.disabled = true;
3226 support.optDisabled = !opt.disabled;
3228 // Check if an input maintains its value after becoming a radio
3229 // Support: IE9, IE10
3230 input = document.createElement("input");
3232 input.type = "radio";
3233 support.radioValue = input.value === "t";
3235 // #11217 - WebKit loses check when the name is after the checked attribute
3236 input.setAttribute( "checked", "t" );
3237 input.setAttribute( "name", "t" );
3239 fragment.appendChild( input );
3241 // Support: Safari 5.1, Android 4.x, Android 2.3
3242 // old WebKit doesn't clone checked state correctly in fragments
3243 support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
3245 // Support: Firefox, Chrome, Safari
3246 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
3247 support.focusinBubbles = "onfocusin" in window;
3249 div.style.backgroundClip = "content-box";
3250 div.cloneNode( true ).style.backgroundClip = "";
3251 support.clearCloneStyle = div.style.backgroundClip === "content-box";
3253 // Run tests that need a body at doc ready
3255 var container, marginDiv,
3256 // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
3257 divReset = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",
3258 body = document.getElementsByTagName("body")[ 0 ];
3261 // Return for frameset docs that don't have a body
3265 container = document.createElement("div");
3266 container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
3268 // Check box-sizing and margin behavior.
3269 body.appendChild( container ).appendChild( div );
3271 // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
3272 div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%";
3274 // Workaround failing boxSizing test due to offsetWidth returning wrong value
3275 // with some non-1 values of body zoom, ticket #13543
3276 jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
3277 support.boxSizing = div.offsetWidth === 4;
3280 // Use window.getComputedStyle because jsdom on node.js will break without it.
3281 if ( window.getComputedStyle ) {
3282 support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
3283 support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
3285 // Support: Android 2.3
3286 // Check if div with explicit width and no margin-right incorrectly
3287 // gets computed margin-right based on width of container. (#3333)
3288 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
3289 marginDiv = div.appendChild( document.createElement("div") );
3290 marginDiv.style.cssText = div.style.cssText = divReset;
3291 marginDiv.style.marginRight = marginDiv.style.width = "0";
3292 div.style.width = "1px";
3294 support.reliableMarginRight =
3295 !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
3298 body.removeChild( container );
3305 Implementation Summary
3307 1. Enforce API surface and semantic compatibility with 1.9.x branch
3308 2. Improve the module's maintainability by reducing the storage
3309 paths to a single mechanism.
3310 3. Use the same single mechanism to support "private" and "user" data.
3311 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
3312 5. Avoid exposing implementation details on user objects (eg. expando properties)
3313 6. Provide a clear path for implementation upgrade to WeakMap in 2014
3315 var data_user, data_priv,
3316 rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
3317 rmultiDash = /([A-Z])/g;
3320 // Support: Android < 4,
3321 // Old WebKit does not have Object.preventExtensions/freeze method,
3322 // return new empty object instead with no [[set]] accessor
3323 Object.defineProperty( this.cache = {}, 0, {
3329 this.expando = jQuery.expando + Math.random();
3334 Data.accepts = function( owner ) {
3337 // - Node.ELEMENT_NODE
3338 // - Node.DOCUMENT_NODE
3341 return owner.nodeType ?
3342 owner.nodeType === 1 || owner.nodeType === 9 : true;
3346 key: function( owner ) {
3347 // We can accept data for non-element nodes in modern browsers,
3348 // but we should not, see #8335.
3349 // Always return the key for a frozen object.
3350 if ( !Data.accepts( owner ) ) {
3354 var descriptor = {},
3355 // Check if the owner object already has a cache key
3356 unlock = owner[ this.expando ];
3358 // If not, create one
3360 unlock = Data.uid++;
3362 // Secure it in a non-enumerable, non-writable property
3364 descriptor[ this.expando ] = { value: unlock };
3365 Object.defineProperties( owner, descriptor );
3367 // Support: Android < 4
3368 // Fallback to a less secure definition
3370 descriptor[ this.expando ] = unlock;
3371 jQuery.extend( owner, descriptor );
3375 // Ensure the cache object
3376 if ( !this.cache[ unlock ] ) {
3377 this.cache[ unlock ] = {};
3382 set: function( owner, data, value ) {
3384 // There may be an unlock assigned to this node,
3385 // if there is no entry for this "owner", create one inline
3386 // and set the unlock as though an owner entry had always existed
3387 unlock = this.key( owner ),
3388 cache = this.cache[ unlock ];
3390 // Handle: [ owner, key, value ] args
3391 if ( typeof data === "string" ) {
3392 cache[ data ] = value;
3394 // Handle: [ owner, { properties } ] args
3396 // Fresh assignments by object are shallow copied
3397 if ( jQuery.isEmptyObject( cache ) ) {
3398 jQuery.extend( this.cache[ unlock ], data );
3399 // Otherwise, copy the properties one-by-one to the cache object
3401 for ( prop in data ) {
3402 cache[ prop ] = data[ prop ];
3408 get: function( owner, key ) {
3409 // Either a valid cache is found, or will be created.
3410 // New caches will be created and the unlock returned,
3411 // allowing direct access to the newly created
3412 // empty data object. A valid owner object must be provided.
3413 var cache = this.cache[ this.key( owner ) ];
3415 return key === undefined ?
3416 cache : cache[ key ];
3418 access: function( owner, key, value ) {
3420 // In cases where either:
3422 // 1. No key was specified
3423 // 2. A string key was specified, but no value provided
3425 // Take the "read" path and allow the get method to determine
3426 // which value to return, respectively either:
3428 // 1. The entire cache object
3429 // 2. The data stored at the key
3431 if ( key === undefined ||
3432 ((key && typeof key === "string") && value === undefined) ) {
3434 stored = this.get( owner, key );
3436 return stored !== undefined ?
3437 stored : this.get( owner, jQuery.camelCase(key) );
3440 // [*]When the key is not a string, or both a key and value
3441 // are specified, set or extend (existing objects) with either:
3443 // 1. An object of properties
3444 // 2. A key and value
3446 this.set( owner, key, value );
3448 // Since the "set" path can have two possible entry points
3449 // return the expected data based on which path was taken[*]
3450 return value !== undefined ? value : key;
3452 remove: function( owner, key ) {
3454 unlock = this.key( owner ),
3455 cache = this.cache[ unlock ];
3457 if ( key === undefined ) {
3458 this.cache[ unlock ] = {};
3461 // Support array or space separated string of keys
3462 if ( jQuery.isArray( key ) ) {
3463 // If "name" is an array of keys...
3464 // When data is initially created, via ("key", "val") signature,
3465 // keys will be converted to camelCase.
3466 // Since there is no way to tell _how_ a key was added, remove
3467 // both plain key and camelCase key. #12786
3468 // This will only penalize the array argument path.
3469 name = key.concat( key.map( jQuery.camelCase ) );
3471 camel = jQuery.camelCase( key );
3472 // Try the string as a key before any manipulation
3473 if ( key in cache ) {
3474 name = [ key, camel ];
3476 // If a key with the spaces exists, use it.
3477 // Otherwise, create an array by matching non-whitespace
3479 name = name in cache ?
3480 [ name ] : ( name.match( core_rnotwhite ) || [] );
3486 delete cache[ name[ i ] ];
3490 hasData: function( owner ) {
3491 return !jQuery.isEmptyObject(
3492 this.cache[ owner[ this.expando ] ] || {}
3495 discard: function( owner ) {
3496 if ( owner[ this.expando ] ) {
3497 delete this.cache[ owner[ this.expando ] ];
3502 // These may be used throughout the jQuery core codebase
3503 data_user = new Data();
3504 data_priv = new Data();
3508 acceptData: Data.accepts,
3510 hasData: function( elem ) {
3511 return data_user.hasData( elem ) || data_priv.hasData( elem );
3514 data: function( elem, name, data ) {
3515 return data_user.access( elem, name, data );
3518 removeData: function( elem, name ) {
3519 data_user.remove( elem, name );
3522 // TODO: Now that all calls to _data and _removeData have been replaced
3523 // with direct calls to data_priv methods, these can be deprecated.
3524 _data: function( elem, name, data ) {
3525 return data_priv.access( elem, name, data );
3528 _removeData: function( elem, name ) {
3529 data_priv.remove( elem, name );
3534 data: function( key, value ) {
3541 if ( key === undefined ) {
3542 if ( this.length ) {
3543 data = data_user.get( elem );
3545 if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
3546 attrs = elem.attributes;
3547 for ( ; i < attrs.length; i++ ) {
3548 name = attrs[ i ].name;
3550 if ( name.indexOf( "data-" ) === 0 ) {
3551 name = jQuery.camelCase( name.slice(5) );
3552 dataAttr( elem, name, data[ name ] );
3555 data_priv.set( elem, "hasDataAttrs", true );
3562 // Sets multiple values
3563 if ( typeof key === "object" ) {
3564 return this.each(function() {
3565 data_user.set( this, key );
3569 return jQuery.access( this, function( value ) {
3571 camelKey = jQuery.camelCase( key );
3573 // The calling jQuery object (element matches) is not empty
3574 // (and therefore has an element appears at this[ 0 ]) and the
3575 // `value` parameter was not undefined. An empty jQuery object
3576 // will result in `undefined` for elem = this[ 0 ] which will
3577 // throw an exception if an attempt to read a data cache is made.
3578 if ( elem && value === undefined ) {
3579 // Attempt to get data from the cache
3580 // with the key as-is
3581 data = data_user.get( elem, key );
3582 if ( data !== undefined ) {
3586 // Attempt to get data from the cache
3587 // with the key camelized
3588 data = data_user.get( elem, camelKey );
3589 if ( data !== undefined ) {
3593 // Attempt to "discover" the data in
3594 // HTML5 custom data-* attrs
3595 data = dataAttr( elem, camelKey, undefined );
3596 if ( data !== undefined ) {
3600 // We tried really hard, but the data doesn't exist.
3605 this.each(function() {
3606 // First, attempt to store a copy or reference of any
3607 // data that might've been store with a camelCased key.
3608 var data = data_user.get( this, camelKey );
3610 // For HTML5 data-* attribute interop, we have to
3611 // store property names with dashes in a camelCase form.
3612 // This might not apply to all properties...*
3613 data_user.set( this, camelKey, value );
3615 // *... In the case of properties that might _actually_
3616 // have dashes, we need to also store a copy of that
3617 // unchanged property.
3618 if ( key.indexOf("-") !== -1 && data !== undefined ) {
3619 data_user.set( this, key, value );
3622 }, null, value, arguments.length > 1, null, true );
3625 removeData: function( key ) {
3626 return this.each(function() {
3627 data_user.remove( this, key );
3632 function dataAttr( elem, key, data ) {
3635 // If nothing was found internally, try to fetch any
3636 // data from the HTML5 data-* attribute
3637 if ( data === undefined && elem.nodeType === 1 ) {
3638 name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3639 data = elem.getAttribute( name );
3641 if ( typeof data === "string" ) {
3643 data = data === "true" ? true :
3644 data === "false" ? false :
3645 data === "null" ? null :
3646 // Only convert to a number if it doesn't change the string
3647 +data + "" === data ? +data :
3648 rbrace.test( data ) ? JSON.parse( data ) :
3652 // Make sure we set the data so it isn't changed later
3653 data_user.set( elem, key, data );
3661 queue: function( elem, type, data ) {
3665 type = ( type || "fx" ) + "queue";
3666 queue = data_priv.get( elem, type );
3668 // Speed up dequeue by getting out quickly if this is just a lookup
3670 if ( !queue || jQuery.isArray( data ) ) {
3671 queue = data_priv.access( elem, type, jQuery.makeArray(data) );
3680 dequeue: function( elem, type ) {
3681 type = type || "fx";
3683 var queue = jQuery.queue( elem, type ),
3684 startLength = queue.length,
3686 hooks = jQuery._queueHooks( elem, type ),
3688 jQuery.dequeue( elem, type );
3691 // If the fx queue is dequeued, always remove the progress sentinel
3692 if ( fn === "inprogress" ) {
3699 // Add a progress sentinel to prevent the fx queue from being
3700 // automatically dequeued
3701 if ( type === "fx" ) {
3702 queue.unshift( "inprogress" );
3705 // clear up the last queue stop function
3707 fn.call( elem, next, hooks );
3710 if ( !startLength && hooks ) {
3715 // not intended for public consumption - generates a queueHooks object, or returns the current one
3716 _queueHooks: function( elem, type ) {
3717 var key = type + "queueHooks";
3718 return data_priv.get( elem, key ) || data_priv.access( elem, key, {
3719 empty: jQuery.Callbacks("once memory").add(function() {
3720 data_priv.remove( elem, [ type + "queue", key ] );
3727 queue: function( type, data ) {
3730 if ( typeof type !== "string" ) {
3736 if ( arguments.length < setter ) {
3737 return jQuery.queue( this[0], type );
3740 return data === undefined ?
3742 this.each(function() {
3743 var queue = jQuery.queue( this, type, data );
3745 // ensure a hooks for this queue
3746 jQuery._queueHooks( this, type );
3748 if ( type === "fx" && queue[0] !== "inprogress" ) {
3749 jQuery.dequeue( this, type );
3753 dequeue: function( type ) {
3754 return this.each(function() {
3755 jQuery.dequeue( this, type );
3758 // Based off of the plugin by Clint Helfers, with permission.
3759 // http://blindsignals.com/index.php/2009/07/jquery-delay/
3760 delay: function( time, type ) {
3761 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
3762 type = type || "fx";
3764 return this.queue( type, function( next, hooks ) {
3765 var timeout = setTimeout( next, time );
3766 hooks.stop = function() {
3767 clearTimeout( timeout );
3771 clearQueue: function( type ) {
3772 return this.queue( type || "fx", [] );
3774 // Get a promise resolved when queues of a certain type
3775 // are emptied (fx is the type by default)
3776 promise: function( type, obj ) {
3779 defer = jQuery.Deferred(),
3782 resolve = function() {
3783 if ( !( --count ) ) {
3784 defer.resolveWith( elements, [ elements ] );
3788 if ( typeof type !== "string" ) {
3792 type = type || "fx";
3795 tmp = data_priv.get( elements[ i ], type + "queueHooks" );
3796 if ( tmp && tmp.empty ) {
3798 tmp.empty.add( resolve );
3802 return defer.promise( obj );
3805 var nodeHook, boolHook,
3806 rclass = /[\t\r\n\f]/g,
3808 rfocusable = /^(?:input|select|textarea|button)$/i;
3811 attr: function( name, value ) {
3812 return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
3815 removeAttr: function( name ) {
3816 return this.each(function() {
3817 jQuery.removeAttr( this, name );
3821 prop: function( name, value ) {
3822 return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
3825 removeProp: function( name ) {
3826 return this.each(function() {
3827 delete this[ jQuery.propFix[ name ] || name ];
3831 addClass: function( value ) {
3832 var classes, elem, cur, clazz, j,
3835 proceed = typeof value === "string" && value;
3837 if ( jQuery.isFunction( value ) ) {
3838 return this.each(function( j ) {
3839 jQuery( this ).addClass( value.call( this, j, this.className ) );
3844 // The disjunction here is for better compressibility (see removeClass)
3845 classes = ( value || "" ).match( core_rnotwhite ) || [];
3847 for ( ; i < len; i++ ) {
3849 cur = elem.nodeType === 1 && ( elem.className ?
3850 ( " " + elem.className + " " ).replace( rclass, " " ) :
3856 while ( (clazz = classes[j++]) ) {
3857 if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
3861 elem.className = jQuery.trim( cur );
3870 removeClass: function( value ) {
3871 var classes, elem, cur, clazz, j,
3874 proceed = arguments.length === 0 || typeof value === "string" && value;
3876 if ( jQuery.isFunction( value ) ) {
3877 return this.each(function( j ) {
3878 jQuery( this ).removeClass( value.call( this, j, this.className ) );
3882 classes = ( value || "" ).match( core_rnotwhite ) || [];
3884 for ( ; i < len; i++ ) {
3886 // This expression is here for better compressibility (see addClass)
3887 cur = elem.nodeType === 1 && ( elem.className ?
3888 ( " " + elem.className + " " ).replace( rclass, " " ) :
3894 while ( (clazz = classes[j++]) ) {
3895 // Remove *all* instances
3896 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
3897 cur = cur.replace( " " + clazz + " ", " " );
3900 elem.className = value ? jQuery.trim( cur ) : "";
3908 toggleClass: function( value, stateVal ) {
3909 var type = typeof value;
3911 if ( typeof stateVal === "boolean" && type === "string" ) {
3912 return stateVal ? this.addClass( value ) : this.removeClass( value );
3915 if ( jQuery.isFunction( value ) ) {
3916 return this.each(function( i ) {
3917 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
3921 return this.each(function() {
3922 if ( type === "string" ) {
3923 // toggle individual class names
3926 self = jQuery( this ),
3927 classNames = value.match( core_rnotwhite ) || [];
3929 while ( (className = classNames[ i++ ]) ) {
3930 // check each className given, space separated list
3931 if ( self.hasClass( className ) ) {
3932 self.removeClass( className );
3934 self.addClass( className );
3938 // Toggle whole class name
3939 } else if ( type === core_strundefined || type === "boolean" ) {
3940 if ( this.className ) {
3941 // store className if set
3942 data_priv.set( this, "__className__", this.className );
3945 // If the element has a class name or if we're passed "false",
3946 // then remove the whole classname (if there was one, the above saved it).
3947 // Otherwise bring back whatever was previously saved (if anything),
3948 // falling back to the empty string if nothing was stored.
3949 this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
3954 hasClass: function( selector ) {
3955 var className = " " + selector + " ",
3958 for ( ; i < l; i++ ) {
3959 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
3967 val: function( value ) {
3968 var hooks, ret, isFunction,
3971 if ( !arguments.length ) {
3973 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
3975 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
3981 return typeof ret === "string" ?
3982 // handle most common string cases
3983 ret.replace(rreturn, "") :
3984 // handle cases where value is null/undef or number
3985 ret == null ? "" : ret;
3991 isFunction = jQuery.isFunction( value );
3993 return this.each(function( i ) {
3996 if ( this.nodeType !== 1 ) {
4001 val = value.call( this, i, jQuery( this ).val() );
4006 // Treat null/undefined as ""; convert numbers to string
4007 if ( val == null ) {
4009 } else if ( typeof val === "number" ) {
4011 } else if ( jQuery.isArray( val ) ) {
4012 val = jQuery.map(val, function ( value ) {
4013 return value == null ? "" : value + "";
4017 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
4019 // If set returns undefined, fall back to normal setting
4020 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
4030 get: function( elem ) {
4031 // attributes.value is undefined in Blackberry 4.7 but
4032 // uses .value. See #6932
4033 var val = elem.attributes.value;
4034 return !val || val.specified ? elem.value : elem.text;
4038 get: function( elem ) {
4040 options = elem.options,
4041 index = elem.selectedIndex,
4042 one = elem.type === "select-one" || index < 0,
4043 values = one ? null : [],
4044 max = one ? index + 1 : options.length,
4049 // Loop through all the selected options
4050 for ( ; i < max; i++ ) {
4051 option = options[ i ];
4053 // IE6-9 doesn't update selected after form reset (#2551)
4054 if ( ( option.selected || i === index ) &&
4055 // Don't return options that are disabled or in a disabled optgroup
4056 ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
4057 ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
4059 // Get the specific value for the option
4060 value = jQuery( option ).val();
4062 // We don't need an array for one selects
4067 // Multi-Selects return an array
4068 values.push( value );
4075 set: function( elem, value ) {
4076 var optionSet, option,
4077 options = elem.options,
4078 values = jQuery.makeArray( value ),
4082 option = options[ i ];
4083 if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
4088 // force browsers to behave consistently when non-matching value is set
4090 elem.selectedIndex = -1;
4097 attr: function( elem, name, value ) {
4099 nType = elem.nodeType;
4101 // don't get/set attributes on text, comment and attribute nodes
4102 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4106 // Fallback to prop when attributes are not supported
4107 if ( typeof elem.getAttribute === core_strundefined ) {
4108 return jQuery.prop( elem, name, value );
4111 // All attributes are lowercase
4112 // Grab necessary hook if one is defined
4113 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
4114 name = name.toLowerCase();
4115 hooks = jQuery.attrHooks[ name ] ||
4116 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
4119 if ( value !== undefined ) {
4121 if ( value === null ) {
4122 jQuery.removeAttr( elem, name );
4124 } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
4128 elem.setAttribute( name, value + "" );
4132 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
4136 ret = jQuery.find.attr( elem, name );
4138 // Non-existent attributes return null, we normalize to undefined
4139 return ret == null ?
4145 removeAttr: function( elem, value ) {
4148 attrNames = value && value.match( core_rnotwhite );
4150 if ( attrNames && elem.nodeType === 1 ) {
4151 while ( (name = attrNames[i++]) ) {
4152 propName = jQuery.propFix[ name ] || name;
4154 // Boolean attributes get special treatment (#10870)
4155 if ( jQuery.expr.match.bool.test( name ) ) {
4156 // Set corresponding property to false
4157 elem[ propName ] = false;
4160 elem.removeAttribute( name );
4167 set: function( elem, value ) {
4168 if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
4169 // Setting the type on a radio button after the value resets the value in IE6-9
4170 // Reset value to default in case type is set after value during creation
4171 var val = elem.value;
4172 elem.setAttribute( "type", value );
4184 "class": "className"
4187 prop: function( elem, name, value ) {
4188 var ret, hooks, notxml,
4189 nType = elem.nodeType;
4191 // don't get/set properties on text, comment and attribute nodes
4192 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4196 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
4199 // Fix name and attach hooks
4200 name = jQuery.propFix[ name ] || name;
4201 hooks = jQuery.propHooks[ name ];
4204 if ( value !== undefined ) {
4205 return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
4207 ( elem[ name ] = value );
4210 return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
4218 get: function( elem ) {
4219 return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
4227 // Hooks for boolean attributes
4229 set: function( elem, value, name ) {
4230 if ( value === false ) {
4231 // Remove boolean attributes when set to false
4232 jQuery.removeAttr( elem, name );
4234 elem.setAttribute( name, name );
4239 jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
4240 var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
4242 jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
4243 var fn = jQuery.expr.attrHandle[ name ],
4246 /* jshint eqeqeq: false */
4247 // Temporarily disable this handler to check existence
4248 (jQuery.expr.attrHandle[ name ] = undefined) !=
4249 getter( elem, name, isXML ) ?
4251 name.toLowerCase() :
4255 jQuery.expr.attrHandle[ name ] = fn;
4262 // Selectedness for an option in an optgroup can be inaccurate
4263 if ( !jQuery.support.optSelected ) {
4264 jQuery.propHooks.selected = {
4265 get: function( elem ) {
4266 var parent = elem.parentNode;
4267 if ( parent && parent.parentNode ) {
4268 parent.parentNode.selectedIndex;
4287 jQuery.propFix[ this.toLowerCase() ] = this;
4290 // Radios and checkboxes getter/setter
4291 jQuery.each([ "radio", "checkbox" ], function() {
4292 jQuery.valHooks[ this ] = {
4293 set: function( elem, value ) {
4294 if ( jQuery.isArray( value ) ) {
4295 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
4299 if ( !jQuery.support.checkOn ) {
4300 jQuery.valHooks[ this ].get = function( elem ) {
4302 // "" is returned instead of "on" if a value isn't specified
4303 return elem.getAttribute("value") === null ? "on" : elem.value;
4307 var rkeyEvent = /^key/,
4308 rmouseEvent = /^(?:mouse|contextmenu)|click/,
4309 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4310 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4312 function returnTrue() {
4316 function returnFalse() {
4320 function safeActiveElement() {
4322 return document.activeElement;
4327 * Helper functions for managing events -- not part of the public interface.
4328 * Props to Dean Edwards' addEvent library for many of the ideas.
4334 add: function( elem, types, handler, data, selector ) {
4336 var handleObjIn, eventHandle, tmp,
4337 events, t, handleObj,
4338 special, handlers, type, namespaces, origType,
4339 elemData = data_priv.get( elem );
4341 // Don't attach events to noData or text/comment nodes (but allow plain objects)
4346 // Caller can pass in an object of custom data in lieu of the handler
4347 if ( handler.handler ) {
4348 handleObjIn = handler;
4349 handler = handleObjIn.handler;
4350 selector = handleObjIn.selector;
4353 // Make sure that the handler has a unique ID, used to find/remove it later
4354 if ( !handler.guid ) {
4355 handler.guid = jQuery.guid++;
4358 // Init the element's event structure and main handler, if this is the first
4359 if ( !(events = elemData.events) ) {
4360 events = elemData.events = {};
4362 if ( !(eventHandle = elemData.handle) ) {
4363 eventHandle = elemData.handle = function( e ) {
4364 // Discard the second event of a jQuery.event.trigger() and
4365 // when an event is called after a page has unloaded
4366 return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
4367 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
4370 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
4371 eventHandle.elem = elem;
4374 // Handle multiple events separated by a space
4375 types = ( types || "" ).match( core_rnotwhite ) || [""];
4378 tmp = rtypenamespace.exec( types[t] ) || [];
4379 type = origType = tmp[1];
4380 namespaces = ( tmp[2] || "" ).split( "." ).sort();
4382 // There *must* be a type, no attaching namespace-only handlers
4387 // If event changes its type, use the special event handlers for the changed type
4388 special = jQuery.event.special[ type ] || {};
4390 // If selector defined, determine special event api type, otherwise given type
4391 type = ( selector ? special.delegateType : special.bindType ) || type;
4393 // Update special based on newly reset type
4394 special = jQuery.event.special[ type ] || {};
4396 // handleObj is passed to all event handlers
4397 handleObj = jQuery.extend({
4404 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4405 namespace: namespaces.join(".")
4408 // Init the event handler queue if we're the first
4409 if ( !(handlers = events[ type ]) ) {
4410 handlers = events[ type ] = [];
4411 handlers.delegateCount = 0;
4413 // Only use addEventListener if the special events handler returns false
4414 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4415 if ( elem.addEventListener ) {
4416 elem.addEventListener( type, eventHandle, false );
4421 if ( special.add ) {
4422 special.add.call( elem, handleObj );
4424 if ( !handleObj.handler.guid ) {
4425 handleObj.handler.guid = handler.guid;
4429 // Add to the element's handler list, delegates in front
4431 handlers.splice( handlers.delegateCount++, 0, handleObj );
4433 handlers.push( handleObj );
4436 // Keep track of which events have ever been used, for event optimization
4437 jQuery.event.global[ type ] = true;
4440 // Nullify elem to prevent memory leaks in IE
4444 // Detach an event or set of events from an element
4445 remove: function( elem, types, handler, selector, mappedTypes ) {
4447 var j, origCount, tmp,
4448 events, t, handleObj,
4449 special, handlers, type, namespaces, origType,
4450 elemData = data_priv.hasData( elem ) && data_priv.get( elem );
4452 if ( !elemData || !(events = elemData.events) ) {
4456 // Once for each type.namespace in types; type may be omitted
4457 types = ( types || "" ).match( core_rnotwhite ) || [""];
4460 tmp = rtypenamespace.exec( types[t] ) || [];
4461 type = origType = tmp[1];
4462 namespaces = ( tmp[2] || "" ).split( "." ).sort();
4464 // Unbind all events (on this namespace, if provided) for the element
4466 for ( type in events ) {
4467 jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4472 special = jQuery.event.special[ type ] || {};
4473 type = ( selector ? special.delegateType : special.bindType ) || type;
4474 handlers = events[ type ] || [];
4475 tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4477 // Remove matching events
4478 origCount = j = handlers.length;
4480 handleObj = handlers[ j ];
4482 if ( ( mappedTypes || origType === handleObj.origType ) &&
4483 ( !handler || handler.guid === handleObj.guid ) &&
4484 ( !tmp || tmp.test( handleObj.namespace ) ) &&
4485 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4486 handlers.splice( j, 1 );
4488 if ( handleObj.selector ) {
4489 handlers.delegateCount--;
4491 if ( special.remove ) {
4492 special.remove.call( elem, handleObj );
4497 // Remove generic event handler if we removed something and no more handlers exist
4498 // (avoids potential for endless recursion during removal of special event handlers)
4499 if ( origCount && !handlers.length ) {
4500 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4501 jQuery.removeEvent( elem, type, elemData.handle );
4504 delete events[ type ];
4508 // Remove the expando if it's no longer used
4509 if ( jQuery.isEmptyObject( events ) ) {
4510 delete elemData.handle;
4511 data_priv.remove( elem, "events" );
4515 trigger: function( event, data, elem, onlyHandlers ) {
4517 var i, cur, tmp, bubbleType, ontype, handle, special,
4518 eventPath = [ elem || document ],
4519 type = core_hasOwn.call( event, "type" ) ? event.type : event,
4520 namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4522 cur = tmp = elem = elem || document;
4524 // Don't do events on text and comment nodes
4525 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4529 // focus/blur morphs to focusin/out; ensure we're not firing them right now
4530 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4534 if ( type.indexOf(".") >= 0 ) {
4535 // Namespaced trigger; create a regexp to match event type in handle()
4536 namespaces = type.split(".");
4537 type = namespaces.shift();
4540 ontype = type.indexOf(":") < 0 && "on" + type;
4542 // Caller can pass in a jQuery.Event object, Object, or just an event type string
4543 event = event[ jQuery.expando ] ?
4545 new jQuery.Event( type, typeof event === "object" && event );
4547 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4548 event.isTrigger = onlyHandlers ? 2 : 3;
4549 event.namespace = namespaces.join(".");
4550 event.namespace_re = event.namespace ?
4551 new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4554 // Clean up the event in case it is being reused
4555 event.result = undefined;
4556 if ( !event.target ) {
4557 event.target = elem;
4560 // Clone any incoming data and prepend the event, creating the handler arg list
4561 data = data == null ?
4563 jQuery.makeArray( data, [ event ] );
4565 // Allow special events to draw outside the lines
4566 special = jQuery.event.special[ type ] || {};
4567 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4571 // Determine event propagation path in advance, per W3C events spec (#9951)
4572 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4573 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4575 bubbleType = special.delegateType || type;
4576 if ( !rfocusMorph.test( bubbleType + type ) ) {
4577 cur = cur.parentNode;
4579 for ( ; cur; cur = cur.parentNode ) {
4580 eventPath.push( cur );
4584 // Only add window if we got to document (e.g., not plain obj or detached DOM)
4585 if ( tmp === (elem.ownerDocument || document) ) {
4586 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4590 // Fire handlers on the event path
4592 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4594 event.type = i > 1 ?
4596 special.bindType || type;
4599 handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
4601 handle.apply( cur, data );
4605 handle = ontype && cur[ ontype ];
4606 if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
4607 event.preventDefault();
4612 // If nobody prevented the default action, do it now
4613 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
4615 if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
4616 jQuery.acceptData( elem ) ) {
4618 // Call a native DOM method on the target with the same name name as the event.
4619 // Don't do default actions on window, that's where global variables be (#6170)
4620 if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
4622 // Don't re-trigger an onFOO event when we call its FOO() method
4623 tmp = elem[ ontype ];
4626 elem[ ontype ] = null;
4629 // Prevent re-triggering of the same event, since we already bubbled it above
4630 jQuery.event.triggered = type;
4632 jQuery.event.triggered = undefined;
4635 elem[ ontype ] = tmp;
4641 return event.result;
4644 dispatch: function( event ) {
4646 // Make a writable jQuery.Event from the native event object
4647 event = jQuery.event.fix( event );
4649 var i, j, ret, matched, handleObj,
4651 args = core_slice.call( arguments ),
4652 handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
4653 special = jQuery.event.special[ event.type ] || {};
4655 // Use the fix-ed jQuery.Event rather than the (read-only) native event
4657 event.delegateTarget = this;
4659 // Call the preDispatch hook for the mapped type, and let it bail if desired
4660 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
4664 // Determine handlers
4665 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
4667 // Run delegates first; they may want to stop propagation beneath us
4669 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
4670 event.currentTarget = matched.elem;
4673 while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
4675 // Triggered event must either 1) have no namespace, or
4676 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
4677 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
4679 event.handleObj = handleObj;
4680 event.data = handleObj.data;
4682 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
4683 .apply( matched.elem, args );
4685 if ( ret !== undefined ) {
4686 if ( (event.result = ret) === false ) {
4687 event.preventDefault();
4688 event.stopPropagation();
4695 // Call the postDispatch hook for the mapped type
4696 if ( special.postDispatch ) {
4697 special.postDispatch.call( this, event );
4700 return event.result;
4703 handlers: function( event, handlers ) {
4704 var i, matches, sel, handleObj,
4706 delegateCount = handlers.delegateCount,
4709 // Find delegate handlers
4710 // Black-hole SVG <use> instance trees (#13180)
4711 // Avoid non-left-click bubbling in Firefox (#3861)
4712 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
4714 for ( ; cur !== this; cur = cur.parentNode || this ) {
4716 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
4717 if ( cur.disabled !== true || event.type !== "click" ) {
4719 for ( i = 0; i < delegateCount; i++ ) {
4720 handleObj = handlers[ i ];
4722 // Don't conflict with Object.prototype properties (#13203)
4723 sel = handleObj.selector + " ";
4725 if ( matches[ sel ] === undefined ) {
4726 matches[ sel ] = handleObj.needsContext ?
4727 jQuery( sel, this ).index( cur ) >= 0 :
4728 jQuery.find( sel, this, null, [ cur ] ).length;
4730 if ( matches[ sel ] ) {
4731 matches.push( handleObj );
4734 if ( matches.length ) {
4735 handlerQueue.push({ elem: cur, handlers: matches });
4741 // Add the remaining (directly-bound) handlers
4742 if ( delegateCount < handlers.length ) {
4743 handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
4746 return handlerQueue;
4749 // Includes some event props shared by KeyEvent and MouseEvent
4750 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
4755 props: "char charCode key keyCode".split(" "),
4756 filter: function( event, original ) {
4758 // Add which for key events
4759 if ( event.which == null ) {
4760 event.which = original.charCode != null ? original.charCode : original.keyCode;
4768 props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
4769 filter: function( event, original ) {
4770 var eventDoc, doc, body,
4771 button = original.button;
4773 // Calculate pageX/Y if missing and clientX/Y available
4774 if ( event.pageX == null && original.clientX != null ) {
4775 eventDoc = event.target.ownerDocument || document;
4776 doc = eventDoc.documentElement;
4777 body = eventDoc.body;
4779 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
4780 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
4783 // Add which for click: 1 === left; 2 === middle; 3 === right
4784 // Note: button is not normalized, so don't use it
4785 if ( !event.which && button !== undefined ) {
4786 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
4793 fix: function( event ) {
4794 if ( event[ jQuery.expando ] ) {
4798 // Create a writable copy of the event object and normalize some properties
4801 originalEvent = event,
4802 fixHook = this.fixHooks[ type ];
4805 this.fixHooks[ type ] = fixHook =
4806 rmouseEvent.test( type ) ? this.mouseHooks :
4807 rkeyEvent.test( type ) ? this.keyHooks :
4810 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
4812 event = new jQuery.Event( originalEvent );
4817 event[ prop ] = originalEvent[ prop ];
4820 // Support: Cordova 2.5 (WebKit) (#13255)
4821 // All events should have a target; Cordova deviceready doesn't
4822 if ( !event.target ) {
4823 event.target = document;
4826 // Support: Safari 6.0+, Chrome < 28
4827 // Target should not be a text node (#504, #13143)
4828 if ( event.target.nodeType === 3 ) {
4829 event.target = event.target.parentNode;
4832 return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
4837 // Prevent triggered image.load events from bubbling to window.load
4841 // Fire native event if possible so blur/focus sequence is correct
4842 trigger: function() {
4843 if ( this !== safeActiveElement() && this.focus ) {
4848 delegateType: "focusin"
4851 trigger: function() {
4852 if ( this === safeActiveElement() && this.blur ) {
4857 delegateType: "focusout"
4860 // For checkbox, fire native event so checked state will be right
4861 trigger: function() {
4862 if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
4868 // For cross-browser consistency, don't fire native .click() on links
4869 _default: function( event ) {
4870 return jQuery.nodeName( event.target, "a" );
4875 postDispatch: function( event ) {
4877 // Support: Firefox 20+
4878 // Firefox doesn't alert if the returnValue field is not set.
4879 if ( event.result !== undefined ) {
4880 event.originalEvent.returnValue = event.result;
4886 simulate: function( type, elem, event, bubble ) {
4887 // Piggyback on a donor event to simulate a different one.
4888 // Fake originalEvent to avoid donor's stopPropagation, but if the
4889 // simulated event prevents default then we do the same on the donor.
4890 var e = jQuery.extend(
4900 jQuery.event.trigger( e, null, elem );
4902 jQuery.event.dispatch.call( elem, e );
4904 if ( e.isDefaultPrevented() ) {
4905 event.preventDefault();
4910 jQuery.removeEvent = function( elem, type, handle ) {
4911 if ( elem.removeEventListener ) {
4912 elem.removeEventListener( type, handle, false );
4916 jQuery.Event = function( src, props ) {
4917 // Allow instantiation without the 'new' keyword
4918 if ( !(this instanceof jQuery.Event) ) {
4919 return new jQuery.Event( src, props );
4923 if ( src && src.type ) {
4924 this.originalEvent = src;
4925 this.type = src.type;
4927 // Events bubbling up the document may have been marked as prevented
4928 // by a handler lower down the tree; reflect the correct value.
4929 this.isDefaultPrevented = ( src.defaultPrevented ||
4930 src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
4937 // Put explicitly provided properties onto the event object
4939 jQuery.extend( this, props );
4942 // Create a timestamp if incoming event doesn't have one
4943 this.timeStamp = src && src.timeStamp || jQuery.now();
4946 this[ jQuery.expando ] = true;
4949 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
4950 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
4951 jQuery.Event.prototype = {
4952 isDefaultPrevented: returnFalse,
4953 isPropagationStopped: returnFalse,
4954 isImmediatePropagationStopped: returnFalse,
4956 preventDefault: function() {
4957 var e = this.originalEvent;
4959 this.isDefaultPrevented = returnTrue;
4961 if ( e && e.preventDefault ) {
4965 stopPropagation: function() {
4966 var e = this.originalEvent;
4968 this.isPropagationStopped = returnTrue;
4970 if ( e && e.stopPropagation ) {
4971 e.stopPropagation();
4974 stopImmediatePropagation: function() {
4975 this.isImmediatePropagationStopped = returnTrue;
4976 this.stopPropagation();
4980 // Create mouseenter/leave events using mouseover/out and event-time checks
4981 // Support: Chrome 15+
4983 mouseenter: "mouseover",
4984 mouseleave: "mouseout"
4985 }, function( orig, fix ) {
4986 jQuery.event.special[ orig ] = {
4990 handle: function( event ) {
4993 related = event.relatedTarget,
4994 handleObj = event.handleObj;
4996 // For mousenter/leave call the handler if related is outside the target.
4997 // NB: No relatedTarget if the mouse left/entered the browser window
4998 if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
4999 event.type = handleObj.origType;
5000 ret = handleObj.handler.apply( this, arguments );
5008 // Create "bubbling" focus and blur events
5009 // Support: Firefox, Chrome, Safari
5010 if ( !jQuery.support.focusinBubbles ) {
5011 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
5013 // Attach a single capturing handler while someone wants focusin/focusout
5015 handler = function( event ) {
5016 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
5019 jQuery.event.special[ fix ] = {
5021 if ( attaches++ === 0 ) {
5022 document.addEventListener( orig, handler, true );
5025 teardown: function() {
5026 if ( --attaches === 0 ) {
5027 document.removeEventListener( orig, handler, true );
5036 on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
5039 // Types can be a map of types/handlers
5040 if ( typeof types === "object" ) {
5041 // ( types-Object, selector, data )
5042 if ( typeof selector !== "string" ) {
5043 // ( types-Object, data )
5044 data = data || selector;
5045 selector = undefined;
5047 for ( type in types ) {
5048 this.on( type, selector, data, types[ type ], one );
5053 if ( data == null && fn == null ) {
5056 data = selector = undefined;
5057 } else if ( fn == null ) {
5058 if ( typeof selector === "string" ) {
5059 // ( types, selector, fn )
5063 // ( types, data, fn )
5066 selector = undefined;
5069 if ( fn === false ) {
5077 fn = function( event ) {
5078 // Can use an empty set, since event contains the info
5079 jQuery().off( event );
5080 return origFn.apply( this, arguments );
5082 // Use same guid so caller can remove using origFn
5083 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
5085 return this.each( function() {
5086 jQuery.event.add( this, types, fn, data, selector );
5089 one: function( types, selector, data, fn ) {
5090 return this.on( types, selector, data, fn, 1 );
5092 off: function( types, selector, fn ) {
5093 var handleObj, type;
5094 if ( types && types.preventDefault && types.handleObj ) {
5095 // ( event ) dispatched jQuery.Event
5096 handleObj = types.handleObj;
5097 jQuery( types.delegateTarget ).off(
5098 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
5104 if ( typeof types === "object" ) {
5105 // ( types-object [, selector] )
5106 for ( type in types ) {
5107 this.off( type, selector, types[ type ] );
5111 if ( selector === false || typeof selector === "function" ) {
5114 selector = undefined;
5116 if ( fn === false ) {
5119 return this.each(function() {
5120 jQuery.event.remove( this, types, fn, selector );
5124 trigger: function( type, data ) {
5125 return this.each(function() {
5126 jQuery.event.trigger( type, data, this );
5129 triggerHandler: function( type, data ) {
5132 return jQuery.event.trigger( type, data, elem, true );
5136 var isSimple = /^.[^:#\[\.,]*$/,
5137 rparentsprev = /^(?:parents|prev(?:Until|All))/,
5138 rneedsContext = jQuery.expr.match.needsContext,
5139 // methods guaranteed to produce a unique set when starting from a unique set
5140 guaranteedUnique = {
5148 find: function( selector ) {
5154 if ( typeof selector !== "string" ) {
5155 return this.pushStack( jQuery( selector ).filter(function() {
5156 for ( i = 0; i < len; i++ ) {
5157 if ( jQuery.contains( self[ i ], this ) ) {
5164 for ( i = 0; i < len; i++ ) {
5165 jQuery.find( selector, self[ i ], ret );
5168 // Needed because $( selector, context ) becomes $( context ).find( selector )
5169 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5170 ret.selector = this.selector ? this.selector + " " + selector : selector;
5174 has: function( target ) {
5175 var targets = jQuery( target, this ),
5178 return this.filter(function() {
5180 for ( ; i < l; i++ ) {
5181 if ( jQuery.contains( this, targets[i] ) ) {
5188 not: function( selector ) {
5189 return this.pushStack( winnow(this, selector || [], true) );
5192 filter: function( selector ) {
5193 return this.pushStack( winnow(this, selector || [], false) );
5196 is: function( selector ) {
5200 // If this is a positional/relative selector, check membership in the returned set
5201 // so $("p:first").is("p:last") won't return true for a doc with two "p".
5202 typeof selector === "string" && rneedsContext.test( selector ) ?
5203 jQuery( selector ) :
5209 closest: function( selectors, context ) {
5214 pos = ( rneedsContext.test( selectors ) || typeof selectors !== "string" ) ?
5215 jQuery( selectors, context || this.context ) :
5218 for ( ; i < l; i++ ) {
5219 for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
5220 // Always skip document fragments
5221 if ( cur.nodeType < 11 && (pos ?
5222 pos.index(cur) > -1 :
5224 // Don't pass non-elements to Sizzle
5225 cur.nodeType === 1 &&
5226 jQuery.find.matchesSelector(cur, selectors)) ) {
5228 cur = matched.push( cur );
5234 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
5237 // Determine the position of an element within
5238 // the matched set of elements
5239 index: function( elem ) {
5241 // No argument, return index in parent
5243 return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
5246 // index in selector
5247 if ( typeof elem === "string" ) {
5248 return core_indexOf.call( jQuery( elem ), this[ 0 ] );
5251 // Locate the position of the desired element
5252 return core_indexOf.call( this,
5254 // If it receives a jQuery object, the first element is used
5255 elem.jquery ? elem[ 0 ] : elem
5259 add: function( selector, context ) {
5260 var set = typeof selector === "string" ?
5261 jQuery( selector, context ) :
5262 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5263 all = jQuery.merge( this.get(), set );
5265 return this.pushStack( jQuery.unique(all) );
5268 addBack: function( selector ) {
5269 return this.add( selector == null ?
5270 this.prevObject : this.prevObject.filter(selector)
5275 function sibling( cur, dir ) {
5276 while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
5282 parent: function( elem ) {
5283 var parent = elem.parentNode;
5284 return parent && parent.nodeType !== 11 ? parent : null;
5286 parents: function( elem ) {
5287 return jQuery.dir( elem, "parentNode" );
5289 parentsUntil: function( elem, i, until ) {
5290 return jQuery.dir( elem, "parentNode", until );
5292 next: function( elem ) {
5293 return sibling( elem, "nextSibling" );
5295 prev: function( elem ) {
5296 return sibling( elem, "previousSibling" );
5298 nextAll: function( elem ) {
5299 return jQuery.dir( elem, "nextSibling" );
5301 prevAll: function( elem ) {
5302 return jQuery.dir( elem, "previousSibling" );
5304 nextUntil: function( elem, i, until ) {
5305 return jQuery.dir( elem, "nextSibling", until );
5307 prevUntil: function( elem, i, until ) {
5308 return jQuery.dir( elem, "previousSibling", until );
5310 siblings: function( elem ) {
5311 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5313 children: function( elem ) {
5314 return jQuery.sibling( elem.firstChild );
5316 contents: function( elem ) {
5317 return elem.contentDocument || jQuery.merge( [], elem.childNodes );
5319 }, function( name, fn ) {
5320 jQuery.fn[ name ] = function( until, selector ) {
5321 var matched = jQuery.map( this, fn, until );
5323 if ( name.slice( -5 ) !== "Until" ) {
5327 if ( selector && typeof selector === "string" ) {
5328 matched = jQuery.filter( selector, matched );
5331 if ( this.length > 1 ) {
5332 // Remove duplicates
5333 if ( !guaranteedUnique[ name ] ) {
5334 jQuery.unique( matched );
5337 // Reverse order for parents* and prev-derivatives
5338 if ( rparentsprev.test( name ) ) {
5343 return this.pushStack( matched );
5348 filter: function( expr, elems, not ) {
5349 var elem = elems[ 0 ];
5352 expr = ":not(" + expr + ")";
5355 return elems.length === 1 && elem.nodeType === 1 ?
5356 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
5357 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
5358 return elem.nodeType === 1;
5362 dir: function( elem, dir, until ) {
5364 truncate = until !== undefined;
5366 while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
5367 if ( elem.nodeType === 1 ) {
5368 if ( truncate && jQuery( elem ).is( until ) ) {
5371 matched.push( elem );
5377 sibling: function( n, elem ) {
5380 for ( ; n; n = n.nextSibling ) {
5381 if ( n.nodeType === 1 && n !== elem ) {
5390 // Implement the identical functionality for filter and not
5391 function winnow( elements, qualifier, not ) {
5392 if ( jQuery.isFunction( qualifier ) ) {
5393 return jQuery.grep( elements, function( elem, i ) {
5395 return !!qualifier.call( elem, i, elem ) !== not;
5400 if ( qualifier.nodeType ) {
5401 return jQuery.grep( elements, function( elem ) {
5402 return ( elem === qualifier ) !== not;
5407 if ( typeof qualifier === "string" ) {
5408 if ( isSimple.test( qualifier ) ) {
5409 return jQuery.filter( qualifier, elements, not );
5412 qualifier = jQuery.filter( qualifier, elements );
5415 return jQuery.grep( elements, function( elem ) {
5416 return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
5419 var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
5420 rtagName = /<([\w:]+)/,
5421 rhtml = /<|&#?\w+;/,
5422 rnoInnerhtml = /<(?:script|style|link)/i,
5423 manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
5424 // checked="checked" or checked
5425 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5426 rscriptType = /^$|\/(?:java|ecma)script/i,
5427 rscriptTypeMasked = /^true\/(.*)/,
5428 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
5430 // We have to close these tags to support XHTML (#13200)
5434 option: [ 1, "<select multiple='multiple'>", "</select>" ],
5436 thead: [ 1, "<table>", "</table>" ],
5437 col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
5438 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
5439 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
5441 _default: [ 0, "", "" ]
5445 wrapMap.optgroup = wrapMap.option;
5447 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
5448 wrapMap.th = wrapMap.td;
5451 text: function( value ) {
5452 return jQuery.access( this, function( value ) {
5453 return value === undefined ?
5454 jQuery.text( this ) :
5455 this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
5456 }, null, value, arguments.length );
5459 append: function() {
5460 return this.domManip( arguments, function( elem ) {
5461 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5462 var target = manipulationTarget( this, elem );
5463 target.appendChild( elem );
5468 prepend: function() {
5469 return this.domManip( arguments, function( elem ) {
5470 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5471 var target = manipulationTarget( this, elem );
5472 target.insertBefore( elem, target.firstChild );
5477 before: function() {
5478 return this.domManip( arguments, function( elem ) {
5479 if ( this.parentNode ) {
5480 this.parentNode.insertBefore( elem, this );
5486 return this.domManip( arguments, function( elem ) {
5487 if ( this.parentNode ) {
5488 this.parentNode.insertBefore( elem, this.nextSibling );
5493 // keepData is for internal use only--do not document
5494 remove: function( selector, keepData ) {
5496 elems = selector ? jQuery.filter( selector, this ) : this,
5499 for ( ; (elem = elems[i]) != null; i++ ) {
5500 if ( !keepData && elem.nodeType === 1 ) {
5501 jQuery.cleanData( getAll( elem ) );
5504 if ( elem.parentNode ) {
5505 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
5506 setGlobalEval( getAll( elem, "script" ) );
5508 elem.parentNode.removeChild( elem );
5519 for ( ; (elem = this[i]) != null; i++ ) {
5520 if ( elem.nodeType === 1 ) {
5522 // Prevent memory leaks
5523 jQuery.cleanData( getAll( elem, false ) );
5525 // Remove any remaining nodes
5526 elem.textContent = "";
5533 clone: function( dataAndEvents, deepDataAndEvents ) {
5534 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
5535 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
5537 return this.map( function () {
5538 return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
5542 html: function( value ) {
5543 return jQuery.access( this, function( value ) {
5544 var elem = this[ 0 ] || {},
5548 if ( value === undefined && elem.nodeType === 1 ) {
5549 return elem.innerHTML;
5552 // See if we can take a shortcut and just use innerHTML
5553 if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
5554 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
5556 value = value.replace( rxhtmlTag, "<$1></$2>" );
5559 for ( ; i < l; i++ ) {
5560 elem = this[ i ] || {};
5562 // Remove element nodes and prevent memory leaks
5563 if ( elem.nodeType === 1 ) {
5564 jQuery.cleanData( getAll( elem, false ) );
5565 elem.innerHTML = value;
5571 // If using innerHTML throws an exception, use the fallback method
5576 this.empty().append( value );
5578 }, null, value, arguments.length );
5581 replaceWith: function() {
5583 // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
5584 args = jQuery.map( this, function( elem ) {
5585 return [ elem.nextSibling, elem.parentNode ];
5589 // Make the changes, replacing each context element with the new content
5590 this.domManip( arguments, function( elem ) {
5591 var next = args[ i++ ],
5592 parent = args[ i++ ];
5595 // Don't use the snapshot next if it has moved (#13810)
5596 if ( next && next.parentNode !== parent ) {
5597 next = this.nextSibling;
5599 jQuery( this ).remove();
5600 parent.insertBefore( elem, next );
5602 // Allow new content to include elements from the context set
5605 // Force removal if there was no new content (e.g., from empty arguments)
5606 return i ? this : this.remove();
5609 detach: function( selector ) {
5610 return this.remove( selector, true );
5613 domManip: function( args, callback, allowIntersection ) {
5615 // Flatten any nested arrays
5616 args = core_concat.apply( [], args );
5618 var fragment, first, scripts, hasScripts, node, doc,
5624 isFunction = jQuery.isFunction( value );
5626 // We can't cloneNode fragments that contain checked, in WebKit
5627 if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
5628 return this.each(function( index ) {
5629 var self = set.eq( index );
5631 args[ 0 ] = value.call( this, index, self.html() );
5633 self.domManip( args, callback, allowIntersection );
5638 fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
5639 first = fragment.firstChild;
5641 if ( fragment.childNodes.length === 1 ) {
5646 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5647 hasScripts = scripts.length;
5649 // Use the original fragment for the last item instead of the first because it can end up
5650 // being emptied incorrectly in certain situations (#8070).
5651 for ( ; i < l; i++ ) {
5654 if ( i !== iNoClone ) {
5655 node = jQuery.clone( node, true, true );
5657 // Keep references to cloned scripts for later restoration
5659 // Support: QtWebKit
5660 // jQuery.merge because core_push.apply(_, arraylike) throws
5661 jQuery.merge( scripts, getAll( node, "script" ) );
5665 callback.call( this[ i ], node, i );
5669 doc = scripts[ scripts.length - 1 ].ownerDocument;
5672 jQuery.map( scripts, restoreScript );
5674 // Evaluate executable scripts on first document insertion
5675 for ( i = 0; i < hasScripts; i++ ) {
5676 node = scripts[ i ];
5677 if ( rscriptType.test( node.type || "" ) &&
5678 !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
5681 // Hope ajax is available...
5682 jQuery._evalUrl( node.src );
5684 jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
5698 prependTo: "prepend",
5699 insertBefore: "before",
5700 insertAfter: "after",
5701 replaceAll: "replaceWith"
5702 }, function( name, original ) {
5703 jQuery.fn[ name ] = function( selector ) {
5706 insert = jQuery( selector ),
5707 last = insert.length - 1,
5710 for ( ; i <= last; i++ ) {
5711 elems = i === last ? this : this.clone( true );
5712 jQuery( insert[ i ] )[ original ]( elems );
5714 // Support: QtWebKit
5715 // .get() because core_push.apply(_, arraylike) throws
5716 core_push.apply( ret, elems.get() );
5719 return this.pushStack( ret );
5724 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5725 var i, l, srcElements, destElements,
5726 clone = elem.cloneNode( true ),
5727 inPage = jQuery.contains( elem.ownerDocument, elem );
5730 // Fix Cloning issues
5731 if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
5733 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
5734 destElements = getAll( clone );
5735 srcElements = getAll( elem );
5737 for ( i = 0, l = srcElements.length; i < l; i++ ) {
5738 fixInput( srcElements[ i ], destElements[ i ] );
5742 // Copy the events from the original to the clone
5743 if ( dataAndEvents ) {
5744 if ( deepDataAndEvents ) {
5745 srcElements = srcElements || getAll( elem );
5746 destElements = destElements || getAll( clone );
5748 for ( i = 0, l = srcElements.length; i < l; i++ ) {
5749 cloneCopyEvent( srcElements[ i ], destElements[ i ] );
5752 cloneCopyEvent( elem, clone );
5756 // Preserve script evaluation history
5757 destElements = getAll( clone, "script" );
5758 if ( destElements.length > 0 ) {
5759 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5762 // Return the cloned set
5766 buildFragment: function( elems, context, scripts, selection ) {
5767 var elem, tmp, tag, wrap, contains, j,
5770 fragment = context.createDocumentFragment(),
5773 for ( ; i < l; i++ ) {
5776 if ( elem || elem === 0 ) {
5778 // Add nodes directly
5779 if ( jQuery.type( elem ) === "object" ) {
5780 // Support: QtWebKit
5781 // jQuery.merge because core_push.apply(_, arraylike) throws
5782 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
5784 // Convert non-html into a text node
5785 } else if ( !rhtml.test( elem ) ) {
5786 nodes.push( context.createTextNode( elem ) );
5788 // Convert html into DOM nodes
5790 tmp = tmp || fragment.appendChild( context.createElement("div") );
5792 // Deserialize a standard representation
5793 tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
5794 wrap = wrapMap[ tag ] || wrapMap._default;
5795 tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
5797 // Descend through wrappers to the right content
5800 tmp = tmp.lastChild;
5803 // Support: QtWebKit
5804 // jQuery.merge because core_push.apply(_, arraylike) throws
5805 jQuery.merge( nodes, tmp.childNodes );
5807 // Remember the top-level container
5808 tmp = fragment.firstChild;
5811 // Support: Webkit, IE
5812 tmp.textContent = "";
5817 // Remove wrapper from fragment
5818 fragment.textContent = "";
5821 while ( (elem = nodes[ i++ ]) ) {
5823 // #4087 - If origin and destination elements are the same, and this is
5824 // that element, do not do anything
5825 if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
5829 contains = jQuery.contains( elem.ownerDocument, elem );
5831 // Append to fragment
5832 tmp = getAll( fragment.appendChild( elem ), "script" );
5834 // Preserve script evaluation history
5836 setGlobalEval( tmp );
5839 // Capture executables
5842 while ( (elem = tmp[ j++ ]) ) {
5843 if ( rscriptType.test( elem.type || "" ) ) {
5844 scripts.push( elem );
5853 cleanData: function( elems ) {
5854 var data, elem, events, type, key, j,
5855 special = jQuery.event.special,
5858 for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
5859 if ( Data.accepts( elem ) ) {
5860 key = elem[ data_priv.expando ];
5862 if ( key && (data = data_priv.cache[ key ]) ) {
5863 events = Object.keys( data.events || {} );
5864 if ( events.length ) {
5865 for ( j = 0; (type = events[j]) !== undefined; j++ ) {
5866 if ( special[ type ] ) {
5867 jQuery.event.remove( elem, type );
5869 // This is a shortcut to avoid jQuery.event.remove's overhead
5871 jQuery.removeEvent( elem, type, data.handle );
5875 if ( data_priv.cache[ key ] ) {
5876 // Discard any remaining `private` data
5877 delete data_priv.cache[ key ];
5881 // Discard any remaining `user` data
5882 delete data_user.cache[ elem[ data_user.expando ] ];
5886 _evalUrl: function( url ) {
5887 return jQuery.ajax({
5898 // Support: 1.x compatibility
5899 // Manipulating tables requires a tbody
5900 function manipulationTarget( elem, content ) {
5901 return jQuery.nodeName( elem, "table" ) &&
5902 jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
5904 elem.getElementsByTagName("tbody")[0] ||
5905 elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
5909 // Replace/restore the type attribute of script elements for safe DOM manipulation
5910 function disableScript( elem ) {
5911 elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
5914 function restoreScript( elem ) {
5915 var match = rscriptTypeMasked.exec( elem.type );
5918 elem.type = match[ 1 ];
5920 elem.removeAttribute("type");
5926 // Mark scripts as having already been evaluated
5927 function setGlobalEval( elems, refElements ) {
5928 var l = elems.length,
5931 for ( ; i < l; i++ ) {
5933 elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
5938 function cloneCopyEvent( src, dest ) {
5939 var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
5941 if ( dest.nodeType !== 1 ) {
5945 // 1. Copy private data: events, handlers, etc.
5946 if ( data_priv.hasData( src ) ) {
5947 pdataOld = data_priv.access( src );
5948 pdataCur = data_priv.set( dest, pdataOld );
5949 events = pdataOld.events;
5952 delete pdataCur.handle;
5953 pdataCur.events = {};
5955 for ( type in events ) {
5956 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
5957 jQuery.event.add( dest, type, events[ type ][ i ] );
5963 // 2. Copy user data
5964 if ( data_user.hasData( src ) ) {
5965 udataOld = data_user.access( src );
5966 udataCur = jQuery.extend( {}, udataOld );
5968 data_user.set( dest, udataCur );
5973 function getAll( context, tag ) {
5974 var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
5975 context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
5978 return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
5979 jQuery.merge( [ context ], ret ) :
5984 function fixInput( src, dest ) {
5985 var nodeName = dest.nodeName.toLowerCase();
5987 // Fails to persist the checked state of a cloned checkbox or radio button.
5988 if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
5989 dest.checked = src.checked;
5991 // Fails to return the selected option to the default selected state when cloning options
5992 } else if ( nodeName === "input" || nodeName === "textarea" ) {
5993 dest.defaultValue = src.defaultValue;
5997 wrapAll: function( html ) {
6000 if ( jQuery.isFunction( html ) ) {
6001 return this.each(function( i ) {
6002 jQuery( this ).wrapAll( html.call(this, i) );
6008 // The elements to wrap the target around
6009 wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
6011 if ( this[ 0 ].parentNode ) {
6012 wrap.insertBefore( this[ 0 ] );
6015 wrap.map(function() {
6018 while ( elem.firstElementChild ) {
6019 elem = elem.firstElementChild;
6029 wrapInner: function( html ) {
6030 if ( jQuery.isFunction( html ) ) {
6031 return this.each(function( i ) {
6032 jQuery( this ).wrapInner( html.call(this, i) );
6036 return this.each(function() {
6037 var self = jQuery( this ),
6038 contents = self.contents();
6040 if ( contents.length ) {
6041 contents.wrapAll( html );
6044 self.append( html );
6049 wrap: function( html ) {
6050 var isFunction = jQuery.isFunction( html );
6052 return this.each(function( i ) {
6053 jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
6057 unwrap: function() {
6058 return this.parent().each(function() {
6059 if ( !jQuery.nodeName( this, "body" ) ) {
6060 jQuery( this ).replaceWith( this.childNodes );
6066 // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6067 // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6068 rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6069 rmargin = /^margin/,
6070 rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6071 rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6072 rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6073 elemdisplay = { BODY: "block" },
6075 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6076 cssNormalTransform = {
6081 cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6082 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6084 // return a css property mapped to a potentially vendor prefixed property
6085 function vendorPropName( style, name ) {
6087 // shortcut for names that are not vendor prefixed
6088 if ( name in style ) {
6092 // check for vendor prefixed names
6093 var capName = name.charAt(0).toUpperCase() + name.slice(1),
6095 i = cssPrefixes.length;
6098 name = cssPrefixes[ i ] + capName;
6099 if ( name in style ) {
6107 function isHidden( elem, el ) {
6108 // isHidden might be called from jQuery#filter function;
6109 // in that case, element will be second argument
6111 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6114 // NOTE: we've included the "window" in window.getComputedStyle
6115 // because jsdom on node.js will break without it.
6116 function getStyles( elem ) {
6117 return window.getComputedStyle( elem, null );
6120 function showHide( elements, show ) {
6121 var display, elem, hidden,
6124 length = elements.length;
6126 for ( ; index < length; index++ ) {
6127 elem = elements[ index ];
6128 if ( !elem.style ) {
6132 values[ index ] = data_priv.get( elem, "olddisplay" );
6133 display = elem.style.display;
6135 // Reset the inline display of this element to learn if it is
6136 // being hidden by cascaded rules or not
6137 if ( !values[ index ] && display === "none" ) {
6138 elem.style.display = "";
6141 // Set elements which have been overridden with display: none
6142 // in a stylesheet to whatever the default browser style is
6143 // for such an element
6144 if ( elem.style.display === "" && isHidden( elem ) ) {
6145 values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6149 if ( !values[ index ] ) {
6150 hidden = isHidden( elem );
6152 if ( display && display !== "none" || !hidden ) {
6153 data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
6159 // Set the display of most of the elements in a second loop
6160 // to avoid the constant reflow
6161 for ( index = 0; index < length; index++ ) {
6162 elem = elements[ index ];
6163 if ( !elem.style ) {
6166 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6167 elem.style.display = show ? values[ index ] || "" : "none";
6175 css: function( name, value ) {
6176 return jQuery.access( this, function( elem, name, value ) {
6181 if ( jQuery.isArray( name ) ) {
6182 styles = getStyles( elem );
6185 for ( ; i < len; i++ ) {
6186 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6192 return value !== undefined ?
6193 jQuery.style( elem, name, value ) :
6194 jQuery.css( elem, name );
6195 }, name, value, arguments.length > 1 );
6198 return showHide( this, true );
6201 return showHide( this );
6203 toggle: function( state ) {
6204 if ( typeof state === "boolean" ) {
6205 return state ? this.show() : this.hide();
6208 return this.each(function() {
6209 if ( isHidden( this ) ) {
6210 jQuery( this ).show();
6212 jQuery( this ).hide();
6219 // Add in style property hooks for overriding the default
6220 // behavior of getting and setting a style property
6223 get: function( elem, computed ) {
6225 // We should always get a number back from opacity
6226 var ret = curCSS( elem, "opacity" );
6227 return ret === "" ? "1" : ret;
6233 // Don't automatically add "px" to these possibly-unitless properties
6235 "columnCount": true,
6236 "fillOpacity": true,
6247 // Add in properties whose names you wish to fix before
6248 // setting or getting the value
6250 // normalize float css property
6254 // Get and set the style property on a DOM Node
6255 style: function( elem, name, value, extra ) {
6256 // Don't set styles on text and comment nodes
6257 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6261 // Make sure that we're working with the right name
6262 var ret, type, hooks,
6263 origName = jQuery.camelCase( name ),
6266 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6268 // gets hook for the prefixed version
6269 // followed by the unprefixed version
6270 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6272 // Check if we're setting a value
6273 if ( value !== undefined ) {
6274 type = typeof value;
6276 // convert relative number strings (+= or -=) to relative numbers. #7345
6277 if ( type === "string" && (ret = rrelNum.exec( value )) ) {
6278 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
6283 // Make sure that NaN and null values aren't set. See: #7116
6284 if ( value == null || type === "number" && isNaN( value ) ) {
6288 // If a number was passed in, add 'px' to the (except for certain CSS properties)
6289 if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
6293 // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
6294 // but it would mean to define eight (for every problematic property) identical functions
6295 if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
6296 style[ name ] = "inherit";
6299 // If a hook was provided, use that value, otherwise just set the specified value
6300 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
6301 style[ name ] = value;
6305 // If a hook was provided get the non-computed value from there
6306 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
6310 // Otherwise just get the value from the style object
6311 return style[ name ];
6315 css: function( elem, name, extra, styles ) {
6316 var val, num, hooks,
6317 origName = jQuery.camelCase( name );
6319 // Make sure that we're working with the right name
6320 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
6322 // gets hook for the prefixed version
6323 // followed by the unprefixed version
6324 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6326 // If a hook was provided get the computed value from there
6327 if ( hooks && "get" in hooks ) {
6328 val = hooks.get( elem, true, extra );
6331 // Otherwise, if a way to get the computed value exists, use that
6332 if ( val === undefined ) {
6333 val = curCSS( elem, name, styles );
6336 //convert "normal" to computed value
6337 if ( val === "normal" && name in cssNormalTransform ) {
6338 val = cssNormalTransform[ name ];
6341 // Return, converting to number if forced or a qualifier was provided and val looks numeric
6342 if ( extra === "" || extra ) {
6343 num = parseFloat( val );
6344 return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
6350 curCSS = function( elem, name, _computed ) {
6351 var width, minWidth, maxWidth,
6352 computed = _computed || getStyles( elem ),
6355 // getPropertyValue is only needed for .css('filter') in IE9, see #12537
6356 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
6361 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
6362 ret = jQuery.style( elem, name );
6365 // Support: Safari 5.1
6366 // A tribute to the "awesome hack by Dean Edwards"
6367 // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
6368 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
6369 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
6371 // Remember the original values
6372 width = style.width;
6373 minWidth = style.minWidth;
6374 maxWidth = style.maxWidth;
6376 // Put in the new values to get a computed value out
6377 style.minWidth = style.maxWidth = style.width = ret;
6378 ret = computed.width;
6380 // Revert the changed values
6381 style.width = width;
6382 style.minWidth = minWidth;
6383 style.maxWidth = maxWidth;
6391 function setPositiveNumber( elem, value, subtract ) {
6392 var matches = rnumsplit.exec( value );
6394 // Guard against undefined "subtract", e.g., when used as in cssHooks
6395 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
6399 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
6400 var i = extra === ( isBorderBox ? "border" : "content" ) ?
6401 // If we already have the right measurement, avoid augmentation
6403 // Otherwise initialize for horizontal or vertical properties
6404 name === "width" ? 1 : 0,
6408 for ( ; i < 4; i += 2 ) {
6409 // both box models exclude margin, so add it if we want it
6410 if ( extra === "margin" ) {
6411 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
6414 if ( isBorderBox ) {
6415 // border-box includes padding, so remove it if we want content
6416 if ( extra === "content" ) {
6417 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6420 // at this point, extra isn't border nor margin, so remove border
6421 if ( extra !== "margin" ) {
6422 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6425 // at this point, extra isn't content, so add padding
6426 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6428 // at this point, extra isn't content nor padding, so add border
6429 if ( extra !== "padding" ) {
6430 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6438 function getWidthOrHeight( elem, name, extra ) {
6440 // Start with offset property, which is equivalent to the border-box value
6441 var valueIsBorderBox = true,
6442 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
6443 styles = getStyles( elem ),
6444 isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
6446 // some non-html elements return undefined for offsetWidth, so check for null/undefined
6447 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
6448 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
6449 if ( val <= 0 || val == null ) {
6450 // Fall back to computed then uncomputed css if necessary
6451 val = curCSS( elem, name, styles );
6452 if ( val < 0 || val == null ) {
6453 val = elem.style[ name ];
6456 // Computed unit is not pixels. Stop here and return.
6457 if ( rnumnonpx.test(val) ) {
6461 // we need the check for style in case a browser which returns unreliable values
6462 // for getComputedStyle silently falls back to the reliable elem.style
6463 valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
6465 // Normalize "", auto, and prepare for extra
6466 val = parseFloat( val ) || 0;
6469 // use the active box-sizing model to add/subtract irrelevant styles
6471 augmentWidthOrHeight(
6474 extra || ( isBorderBox ? "border" : "content" ),
6481 // Try to determine the default display value of an element
6482 function css_defaultDisplay( nodeName ) {
6484 display = elemdisplay[ nodeName ];
6487 display = actualDisplay( nodeName, doc );
6489 // If the simple way fails, read from inside an iframe
6490 if ( display === "none" || !display ) {
6491 // Use the already-created iframe if possible
6492 iframe = ( iframe ||
6493 jQuery("<iframe frameborder='0' width='0' height='0'/>")
6494 .css( "cssText", "display:block !important" )
6495 ).appendTo( doc.documentElement );
6497 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
6498 doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
6499 doc.write("<!doctype html><html><body>");
6502 display = actualDisplay( nodeName, doc );
6506 // Store the correct default display
6507 elemdisplay[ nodeName ] = display;
6513 // Called ONLY from within css_defaultDisplay
6514 function actualDisplay( name, doc ) {
6515 var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
6516 display = jQuery.css( elem[0], "display" );
6521 jQuery.each([ "height", "width" ], function( i, name ) {
6522 jQuery.cssHooks[ name ] = {
6523 get: function( elem, computed, extra ) {
6525 // certain elements can have dimension info if we invisibly show them
6526 // however, it must have a current display style that would benefit from this
6527 return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
6528 jQuery.swap( elem, cssShow, function() {
6529 return getWidthOrHeight( elem, name, extra );
6531 getWidthOrHeight( elem, name, extra );
6535 set: function( elem, value, extra ) {
6536 var styles = extra && getStyles( elem );
6537 return setPositiveNumber( elem, value, extra ?
6538 augmentWidthOrHeight(
6542 jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6550 // These hooks cannot be added until DOM ready because the support test
6551 // for it is not run until after DOM ready
6553 // Support: Android 2.3
6554 if ( !jQuery.support.reliableMarginRight ) {
6555 jQuery.cssHooks.marginRight = {
6556 get: function( elem, computed ) {
6558 // Support: Android 2.3
6559 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
6560 // Work around by temporarily setting element display to inline-block
6561 return jQuery.swap( elem, { "display": "inline-block" },
6562 curCSS, [ elem, "marginRight" ] );
6568 // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
6569 // getComputedStyle returns percent when specified for top/left/bottom/right
6570 // rather than make the css module depend on the offset module, we just check for it here
6571 if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
6572 jQuery.each( [ "top", "left" ], function( i, prop ) {
6573 jQuery.cssHooks[ prop ] = {
6574 get: function( elem, computed ) {
6576 computed = curCSS( elem, prop );
6577 // if curCSS returns percentage, fallback to offset
6578 return rnumnonpx.test( computed ) ?
6579 jQuery( elem ).position()[ prop ] + "px" :
6589 if ( jQuery.expr && jQuery.expr.filters ) {
6590 jQuery.expr.filters.hidden = function( elem ) {
6591 // Support: Opera <= 12.12
6592 // Opera reports offsetWidths and offsetHeights less than zero on some elements
6593 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
6596 jQuery.expr.filters.visible = function( elem ) {
6597 return !jQuery.expr.filters.hidden( elem );
6601 // These hooks are used by animate to expand properties
6606 }, function( prefix, suffix ) {
6607 jQuery.cssHooks[ prefix + suffix ] = {
6608 expand: function( value ) {
6612 // assumes a single number if not a string
6613 parts = typeof value === "string" ? value.split(" ") : [ value ];
6615 for ( ; i < 4; i++ ) {
6616 expanded[ prefix + cssExpand[ i ] + suffix ] =
6617 parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6624 if ( !rmargin.test( prefix ) ) {
6625 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6631 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
6632 rsubmittable = /^(?:input|select|textarea|keygen)/i;
6635 serialize: function() {
6636 return jQuery.param( this.serializeArray() );
6638 serializeArray: function() {
6639 return this.map(function(){
6640 // Can add propHook for "elements" to filter or add form elements
6641 var elements = jQuery.prop( this, "elements" );
6642 return elements ? jQuery.makeArray( elements ) : this;
6645 var type = this.type;
6646 // Use .is(":disabled") so that fieldset[disabled] works
6647 return this.name && !jQuery( this ).is( ":disabled" ) &&
6648 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
6649 ( this.checked || !manipulation_rcheckableType.test( type ) );
6651 .map(function( i, elem ){
6652 var val = jQuery( this ).val();
6654 return val == null ?
6656 jQuery.isArray( val ) ?
6657 jQuery.map( val, function( val ){
6658 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
6660 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
6665 //Serialize an array of form elements or a set of
6666 //key/values into a query string
6667 jQuery.param = function( a, traditional ) {
6670 add = function( key, value ) {
6671 // If value is a function, invoke it and return its value
6672 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
6673 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
6676 // Set traditional to true for jQuery <= 1.3.2 behavior.
6677 if ( traditional === undefined ) {
6678 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
6681 // If an array was passed in, assume that it is an array of form elements.
6682 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
6683 // Serialize the form elements
6684 jQuery.each( a, function() {
6685 add( this.name, this.value );
6689 // If traditional, encode the "old" way (the way 1.3.2 or older
6690 // did it), otherwise encode params recursively.
6691 for ( prefix in a ) {
6692 buildParams( prefix, a[ prefix ], traditional, add );
6696 // Return the resulting serialization
6697 return s.join( "&" ).replace( r20, "+" );
6700 function buildParams( prefix, obj, traditional, add ) {
6703 if ( jQuery.isArray( obj ) ) {
6704 // Serialize array item.
6705 jQuery.each( obj, function( i, v ) {
6706 if ( traditional || rbracket.test( prefix ) ) {
6707 // Treat each array item as a scalar.
6711 // Item is non-scalar (array or object), encode its numeric index.
6712 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
6716 } else if ( !traditional && jQuery.type( obj ) === "object" ) {
6717 // Serialize object item.
6718 for ( name in obj ) {
6719 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
6723 // Serialize scalar item.
6727 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
6728 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
6729 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
6731 // Handle event binding
6732 jQuery.fn[ name ] = function( data, fn ) {
6733 return arguments.length > 0 ?
6734 this.on( name, null, data, fn ) :
6735 this.trigger( name );
6740 hover: function( fnOver, fnOut ) {
6741 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
6744 bind: function( types, data, fn ) {
6745 return this.on( types, null, data, fn );
6747 unbind: function( types, fn ) {
6748 return this.off( types, null, fn );
6751 delegate: function( selector, types, data, fn ) {
6752 return this.on( types, selector, data, fn );
6754 undelegate: function( selector, types, fn ) {
6755 // ( namespace ) or ( selector, types [, fn] )
6756 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
6760 // Document location
6764 ajax_nonce = jQuery.now(),
6768 rts = /([?&])_=[^&]*/,
6769 rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
6770 // #7653, #8125, #8152: local protocol detection
6771 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
6772 rnoContent = /^(?:GET|HEAD)$/,
6773 rprotocol = /^\/\//,
6774 rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
6776 // Keep a copy of the old load method
6777 _load = jQuery.fn.load,
6780 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
6781 * 2) These are called:
6782 * - BEFORE asking for a transport
6783 * - AFTER param serialization (s.data is a string if s.processData is true)
6784 * 3) key is the dataType
6785 * 4) the catchall symbol "*" can be used
6786 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
6790 /* Transports bindings
6791 * 1) key is the dataType
6792 * 2) the catchall symbol "*" can be used
6793 * 3) selection will start with transport dataType and THEN go to "*" if needed
6797 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
6798 allTypes = "*/".concat("*");
6800 // #8138, IE may throw an exception when accessing
6801 // a field from window.location if document.domain has been set
6803 ajaxLocation = location.href;
6805 // Use the href attribute of an A element
6806 // since IE will modify it given document.location
6807 ajaxLocation = document.createElement( "a" );
6808 ajaxLocation.href = "";
6809 ajaxLocation = ajaxLocation.href;
6812 // Segment location into parts
6813 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
6815 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
6816 function addToPrefiltersOrTransports( structure ) {
6818 // dataTypeExpression is optional and defaults to "*"
6819 return function( dataTypeExpression, func ) {
6821 if ( typeof dataTypeExpression !== "string" ) {
6822 func = dataTypeExpression;
6823 dataTypeExpression = "*";
6828 dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
6830 if ( jQuery.isFunction( func ) ) {
6831 // For each dataType in the dataTypeExpression
6832 while ( (dataType = dataTypes[i++]) ) {
6833 // Prepend if requested
6834 if ( dataType[0] === "+" ) {
6835 dataType = dataType.slice( 1 ) || "*";
6836 (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
6840 (structure[ dataType ] = structure[ dataType ] || []).push( func );
6847 // Base inspection function for prefilters and transports
6848 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
6851 seekingTransport = ( structure === transports );
6853 function inspect( dataType ) {
6855 inspected[ dataType ] = true;
6856 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
6857 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
6858 if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
6859 options.dataTypes.unshift( dataTypeOrTransport );
6860 inspect( dataTypeOrTransport );
6862 } else if ( seekingTransport ) {
6863 return !( selected = dataTypeOrTransport );
6869 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
6872 // A special extend for ajax options
6873 // that takes "flat" options (not to be deep extended)
6875 function ajaxExtend( target, src ) {
6877 flatOptions = jQuery.ajaxSettings.flatOptions || {};
6879 for ( key in src ) {
6880 if ( src[ key ] !== undefined ) {
6881 ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
6885 jQuery.extend( true, target, deep );
6891 jQuery.fn.load = function( url, params, callback ) {
6892 if ( typeof url !== "string" && _load ) {
6893 return _load.apply( this, arguments );
6896 var selector, type, response,
6898 off = url.indexOf(" ");
6901 selector = url.slice( off );
6902 url = url.slice( 0, off );
6905 // If it's a function
6906 if ( jQuery.isFunction( params ) ) {
6908 // We assume that it's the callback
6912 // Otherwise, build a param string
6913 } else if ( params && typeof params === "object" ) {
6917 // If we have elements to modify, make the request
6918 if ( self.length > 0 ) {
6922 // if "type" variable is undefined, then "GET" method will be used
6926 }).done(function( responseText ) {
6928 // Save response for use in complete callback
6929 response = arguments;
6931 self.html( selector ?
6933 // If a selector was specified, locate the right elements in a dummy div
6934 // Exclude scripts to avoid IE 'Permission Denied' errors
6935 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
6937 // Otherwise use the full result
6940 }).complete( callback && function( jqXHR, status ) {
6941 self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
6948 // Attach a bunch of functions for handling common AJAX events
6949 jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
6950 jQuery.fn[ type ] = function( fn ){
6951 return this.on( type, fn );
6957 // Counter for holding the number of active queries
6960 // Last-Modified header cache for next request
6967 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
6971 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
6988 xml: "application/xml, text/xml",
6989 json: "application/json, text/javascript"
7000 text: "responseText",
7001 json: "responseJSON"
7005 // Keys separate source (or catchall "*") and destination types with a single space
7008 // Convert anything to text
7011 // Text to html (true = no transformation)
7014 // Evaluate text as a json expression
7015 "text json": jQuery.parseJSON,
7017 // Parse text as xml
7018 "text xml": jQuery.parseXML
7021 // For options that shouldn't be deep extended:
7022 // you can add your own custom options here if
7023 // and when you create one that shouldn't be
7024 // deep extended (see ajaxExtend)
7031 // Creates a full fledged settings object into target
7032 // with both ajaxSettings and settings fields.
7033 // If target is omitted, writes into ajaxSettings.
7034 ajaxSetup: function( target, settings ) {
7037 // Building a settings object
7038 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7040 // Extending ajaxSettings
7041 ajaxExtend( jQuery.ajaxSettings, target );
7044 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7045 ajaxTransport: addToPrefiltersOrTransports( transports ),
7048 ajax: function( url, options ) {
7050 // If url is an object, simulate pre-1.5 signature
7051 if ( typeof url === "object" ) {
7056 // Force options to be an object
7057 options = options || {};
7060 // URL without anti-cache param
7063 responseHeadersString,
7067 // Cross-domain detection vars
7069 // To know if global events are to be dispatched
7073 // Create the final options object
7074 s = jQuery.ajaxSetup( {}, options ),
7075 // Callbacks context
7076 callbackContext = s.context || s,
7077 // Context for global events is callbackContext if it is a DOM node or jQuery collection
7078 globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7079 jQuery( callbackContext ) :
7082 deferred = jQuery.Deferred(),
7083 completeDeferred = jQuery.Callbacks("once memory"),
7084 // Status-dependent callbacks
7085 statusCode = s.statusCode || {},
7086 // Headers (they are sent all at once)
7087 requestHeaders = {},
7088 requestHeadersNames = {},
7091 // Default abort message
7092 strAbort = "canceled",
7097 // Builds headers hashtable if needed
7098 getResponseHeader: function( key ) {
7100 if ( state === 2 ) {
7101 if ( !responseHeaders ) {
7102 responseHeaders = {};
7103 while ( (match = rheaders.exec( responseHeadersString )) ) {
7104 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7107 match = responseHeaders[ key.toLowerCase() ];
7109 return match == null ? null : match;
7113 getAllResponseHeaders: function() {
7114 return state === 2 ? responseHeadersString : null;
7117 // Caches the header
7118 setRequestHeader: function( name, value ) {
7119 var lname = name.toLowerCase();
7121 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7122 requestHeaders[ name ] = value;
7127 // Overrides response content-type header
7128 overrideMimeType: function( type ) {
7135 // Status-dependent callbacks
7136 statusCode: function( map ) {
7140 for ( code in map ) {
7141 // Lazy-add the new callback in a way that preserves old ones
7142 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7145 // Execute the appropriate callbacks
7146 jqXHR.always( map[ jqXHR.status ] );
7152 // Cancel the request
7153 abort: function( statusText ) {
7154 var finalText = statusText || strAbort;
7156 transport.abort( finalText );
7158 done( 0, finalText );
7164 deferred.promise( jqXHR ).complete = completeDeferred.add;
7165 jqXHR.success = jqXHR.done;
7166 jqXHR.error = jqXHR.fail;
7168 // Remove hash character (#7531: and string promotion)
7169 // Add protocol if not provided (prefilters might expect it)
7170 // Handle falsy url in the settings object (#10093: consistency with old signature)
7171 // We also use the url parameter if available
7172 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
7173 .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
7175 // Alias method option to type as per ticket #12004
7176 s.type = options.method || options.type || s.method || s.type;
7178 // Extract dataTypes list
7179 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
7181 // A cross-domain request is in order when we have a protocol:host:port mismatch
7182 if ( s.crossDomain == null ) {
7183 parts = rurl.exec( s.url.toLowerCase() );
7184 s.crossDomain = !!( parts &&
7185 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
7186 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
7187 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
7191 // Convert data if not already a string
7192 if ( s.data && s.processData && typeof s.data !== "string" ) {
7193 s.data = jQuery.param( s.data, s.traditional );
7197 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
7199 // If request was aborted inside a prefilter, stop there
7200 if ( state === 2 ) {
7204 // We can fire global events as of now if asked to
7205 fireGlobals = s.global;
7207 // Watch for a new set of requests
7208 if ( fireGlobals && jQuery.active++ === 0 ) {
7209 jQuery.event.trigger("ajaxStart");
7212 // Uppercase the type
7213 s.type = s.type.toUpperCase();
7215 // Determine if request has content
7216 s.hasContent = !rnoContent.test( s.type );
7218 // Save the URL in case we're toying with the If-Modified-Since
7219 // and/or If-None-Match header later on
7222 // More options handling for requests with no content
7223 if ( !s.hasContent ) {
7225 // If data is available, append data to url
7227 cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
7228 // #9682: remove data so that it's not used in an eventual retry
7232 // Add anti-cache in url if needed
7233 if ( s.cache === false ) {
7234 s.url = rts.test( cacheURL ) ?
7236 // If there is already a '_' parameter, set its value
7237 cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
7239 // Otherwise add one to the end
7240 cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
7244 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7245 if ( s.ifModified ) {
7246 if ( jQuery.lastModified[ cacheURL ] ) {
7247 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
7249 if ( jQuery.etag[ cacheURL ] ) {
7250 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
7254 // Set the correct header, if data is being sent
7255 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
7256 jqXHR.setRequestHeader( "Content-Type", s.contentType );
7259 // Set the Accepts header for the server, depending on the dataType
7260 jqXHR.setRequestHeader(
7262 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
7263 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
7267 // Check for headers option
7268 for ( i in s.headers ) {
7269 jqXHR.setRequestHeader( i, s.headers[ i ] );
7272 // Allow custom headers/mimetypes and early abort
7273 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
7274 // Abort if not done already and return
7275 return jqXHR.abort();
7278 // aborting is no longer a cancellation
7281 // Install callbacks on deferreds
7282 for ( i in { success: 1, error: 1, complete: 1 } ) {
7283 jqXHR[ i ]( s[ i ] );
7287 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
7289 // If no transport, we auto-abort
7291 done( -1, "No Transport" );
7293 jqXHR.readyState = 1;
7295 // Send global event
7296 if ( fireGlobals ) {
7297 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
7300 if ( s.async && s.timeout > 0 ) {
7301 timeoutTimer = setTimeout(function() {
7302 jqXHR.abort("timeout");
7308 transport.send( requestHeaders, done );
7310 // Propagate exception as error if not done
7313 // Simply rethrow otherwise
7320 // Callback for when everything is done
7321 function done( status, nativeStatusText, responses, headers ) {
7322 var isSuccess, success, error, response, modified,
7323 statusText = nativeStatusText;
7326 if ( state === 2 ) {
7330 // State is "done" now
7333 // Clear timeout if it exists
7334 if ( timeoutTimer ) {
7335 clearTimeout( timeoutTimer );
7338 // Dereference transport for early garbage collection
7339 // (no matter how long the jqXHR object will be used)
7340 transport = undefined;
7342 // Cache response headers
7343 responseHeadersString = headers || "";
7346 jqXHR.readyState = status > 0 ? 4 : 0;
7348 // Determine if successful
7349 isSuccess = status >= 200 && status < 300 || status === 304;
7351 // Get response data
7353 response = ajaxHandleResponses( s, jqXHR, responses );
7356 // Convert no matter what (that way responseXXX fields are always set)
7357 response = ajaxConvert( s, response, jqXHR, isSuccess );
7359 // If successful, handle type chaining
7362 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7363 if ( s.ifModified ) {
7364 modified = jqXHR.getResponseHeader("Last-Modified");
7366 jQuery.lastModified[ cacheURL ] = modified;
7368 modified = jqXHR.getResponseHeader("etag");
7370 jQuery.etag[ cacheURL ] = modified;
7375 if ( status === 204 || s.type === "HEAD" ) {
7376 statusText = "nocontent";
7379 } else if ( status === 304 ) {
7380 statusText = "notmodified";
7382 // If we have data, let's convert it
7384 statusText = response.state;
7385 success = response.data;
7386 error = response.error;
7390 // We extract error from statusText
7391 // then normalize statusText and status for non-aborts
7393 if ( status || !statusText ) {
7394 statusText = "error";
7401 // Set data for the fake xhr object
7402 jqXHR.status = status;
7403 jqXHR.statusText = ( nativeStatusText || statusText ) + "";
7407 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
7409 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
7412 // Status-dependent callbacks
7413 jqXHR.statusCode( statusCode );
7414 statusCode = undefined;
7416 if ( fireGlobals ) {
7417 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
7418 [ jqXHR, s, isSuccess ? success : error ] );
7422 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
7424 if ( fireGlobals ) {
7425 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
7426 // Handle the global AJAX counter
7427 if ( !( --jQuery.active ) ) {
7428 jQuery.event.trigger("ajaxStop");
7436 getJSON: function( url, data, callback ) {
7437 return jQuery.get( url, data, callback, "json" );
7440 getScript: function( url, callback ) {
7441 return jQuery.get( url, undefined, callback, "script" );
7445 jQuery.each( [ "get", "post" ], function( i, method ) {
7446 jQuery[ method ] = function( url, data, callback, type ) {
7447 // shift arguments if data argument was omitted
7448 if ( jQuery.isFunction( data ) ) {
7449 type = type || callback;
7454 return jQuery.ajax({
7464 /* Handles responses to an ajax request:
7465 * - finds the right dataType (mediates between content-type and expected dataType)
7466 * - returns the corresponding response
7468 function ajaxHandleResponses( s, jqXHR, responses ) {
7470 var ct, type, finalDataType, firstDataType,
7471 contents = s.contents,
7472 dataTypes = s.dataTypes;
7474 // Remove auto dataType and get content-type in the process
7475 while( dataTypes[ 0 ] === "*" ) {
7477 if ( ct === undefined ) {
7478 ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
7482 // Check if we're dealing with a known content-type
7484 for ( type in contents ) {
7485 if ( contents[ type ] && contents[ type ].test( ct ) ) {
7486 dataTypes.unshift( type );
7492 // Check to see if we have a response for the expected dataType
7493 if ( dataTypes[ 0 ] in responses ) {
7494 finalDataType = dataTypes[ 0 ];
7496 // Try convertible dataTypes
7497 for ( type in responses ) {
7498 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
7499 finalDataType = type;
7502 if ( !firstDataType ) {
7503 firstDataType = type;
7506 // Or just use first one
7507 finalDataType = finalDataType || firstDataType;
7510 // If we found a dataType
7511 // We add the dataType to the list if needed
7512 // and return the corresponding response
7513 if ( finalDataType ) {
7514 if ( finalDataType !== dataTypes[ 0 ] ) {
7515 dataTypes.unshift( finalDataType );
7517 return responses[ finalDataType ];
7521 /* Chain conversions given the request and the original response
7522 * Also sets the responseXXX fields on the jqXHR instance
7524 function ajaxConvert( s, response, jqXHR, isSuccess ) {
7525 var conv2, current, conv, tmp, prev,
7527 // Work with a copy of dataTypes in case we need to modify it for conversion
7528 dataTypes = s.dataTypes.slice();
7530 // Create converters map with lowercased keys
7531 if ( dataTypes[ 1 ] ) {
7532 for ( conv in s.converters ) {
7533 converters[ conv.toLowerCase() ] = s.converters[ conv ];
7537 current = dataTypes.shift();
7539 // Convert to each sequential dataType
7542 if ( s.responseFields[ current ] ) {
7543 jqXHR[ s.responseFields[ current ] ] = response;
7546 // Apply the dataFilter if provided
7547 if ( !prev && isSuccess && s.dataFilter ) {
7548 response = s.dataFilter( response, s.dataType );
7552 current = dataTypes.shift();
7556 // There's only work to do if current dataType is non-auto
7557 if ( current === "*" ) {
7561 // Convert response if prev dataType is non-auto and differs from current
7562 } else if ( prev !== "*" && prev !== current ) {
7564 // Seek a direct converter
7565 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
7567 // If none found, seek a pair
7569 for ( conv2 in converters ) {
7571 // If conv2 outputs current
7572 tmp = conv2.split( " " );
7573 if ( tmp[ 1 ] === current ) {
7575 // If prev can be converted to accepted input
7576 conv = converters[ prev + " " + tmp[ 0 ] ] ||
7577 converters[ "* " + tmp[ 0 ] ];
7579 // Condense equivalence converters
7580 if ( conv === true ) {
7581 conv = converters[ conv2 ];
7583 // Otherwise, insert the intermediate dataType
7584 } else if ( converters[ conv2 ] !== true ) {
7586 dataTypes.unshift( tmp[ 1 ] );
7594 // Apply converter (if not an equivalence)
7595 if ( conv !== true ) {
7597 // Unless errors are allowed to bubble, catch and return them
7598 if ( conv && s[ "throws" ] ) {
7599 response = conv( response );
7602 response = conv( response );
7604 return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
7612 return { state: "success", data: response };
7614 // Install script dataType
7617 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
7620 script: /(?:java|ecma)script/
7623 "text script": function( text ) {
7624 jQuery.globalEval( text );
7630 // Handle cache's special case and crossDomain
7631 jQuery.ajaxPrefilter( "script", function( s ) {
7632 if ( s.cache === undefined ) {
7635 if ( s.crossDomain ) {
7640 // Bind script tag hack transport
7641 jQuery.ajaxTransport( "script", function( s ) {
7642 // This transport only deals with cross domain requests
7643 if ( s.crossDomain ) {
7644 var script, callback;
7646 send: function( _, complete ) {
7647 script = jQuery("<script>").prop({
7649 charset: s.scriptCharset,
7653 callback = function( evt ) {
7657 complete( evt.type === "error" ? 404 : 200, evt.type );
7661 document.head.appendChild( script[ 0 ] );
7671 var oldCallbacks = [],
7672 rjsonp = /(=)\?(?=&|$)|\?\?/;
7674 // Default jsonp settings
7677 jsonpCallback: function() {
7678 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
7679 this[ callback ] = true;
7684 // Detect, normalize options and install callbacks for jsonp requests
7685 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
7687 var callbackName, overwritten, responseContainer,
7688 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
7690 typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
7693 // Handle iff the expected data type is "jsonp" or we have a parameter to set
7694 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
7696 // Get callback name, remembering preexisting value associated with it
7697 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
7701 // Insert callback into url or form data
7703 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
7704 } else if ( s.jsonp !== false ) {
7705 s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
7708 // Use data converter to retrieve json after script execution
7709 s.converters["script json"] = function() {
7710 if ( !responseContainer ) {
7711 jQuery.error( callbackName + " was not called" );
7713 return responseContainer[ 0 ];
7716 // force json dataType
7717 s.dataTypes[ 0 ] = "json";
7720 overwritten = window[ callbackName ];
7721 window[ callbackName ] = function() {
7722 responseContainer = arguments;
7725 // Clean-up function (fires after converters)
7726 jqXHR.always(function() {
7727 // Restore preexisting value
7728 window[ callbackName ] = overwritten;
7730 // Save back as free
7731 if ( s[ callbackName ] ) {
7732 // make sure that re-using the options doesn't screw things around
7733 s.jsonpCallback = originalSettings.jsonpCallback;
7735 // save the callback name for future use
7736 oldCallbacks.push( callbackName );
7739 // Call if it was a function and we have a response
7740 if ( responseContainer && jQuery.isFunction( overwritten ) ) {
7741 overwritten( responseContainer[ 0 ] );
7744 responseContainer = overwritten = undefined;
7747 // Delegate to script
7751 jQuery.ajaxSettings.xhr = function() {
7753 return new XMLHttpRequest();
7757 var xhrSupported = jQuery.ajaxSettings.xhr(),
7758 xhrSuccessStatus = {
7759 // file protocol always yields status code 0, assume 200
7762 // #1450: sometimes IE returns 1223 when it should be 204
7766 // We need to keep track of outbound xhr and abort them manually
7767 // because IE is not smart enough to do it all by itself
7771 if ( window.ActiveXObject ) {
7772 jQuery( window ).on( "unload", function() {
7773 for( var key in xhrCallbacks ) {
7774 xhrCallbacks[ key ]();
7776 xhrCallbacks = undefined;
7780 jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
7781 jQuery.support.ajax = xhrSupported = !!xhrSupported;
7783 jQuery.ajaxTransport(function( options ) {
7785 // Cross domain only allowed if supported through XMLHttpRequest
7786 if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
7788 send: function( headers, complete ) {
7790 xhr = options.xhr();
7791 xhr.open( options.type, options.url, options.async, options.username, options.password );
7792 // Apply custom fields if provided
7793 if ( options.xhrFields ) {
7794 for ( i in options.xhrFields ) {
7795 xhr[ i ] = options.xhrFields[ i ];
7798 // Override mime type if needed
7799 if ( options.mimeType && xhr.overrideMimeType ) {
7800 xhr.overrideMimeType( options.mimeType );
7802 // X-Requested-With header
7803 // For cross-domain requests, seeing as conditions for a preflight are
7804 // akin to a jigsaw puzzle, we simply never set it to be sure.
7805 // (it can always be set on a per-request basis or even using ajaxSetup)
7806 // For same-domain requests, won't change header if already provided.
7807 if ( !options.crossDomain && !headers["X-Requested-With"] ) {
7808 headers["X-Requested-With"] = "XMLHttpRequest";
7811 for ( i in headers ) {
7812 xhr.setRequestHeader( i, headers[ i ] );
7815 callback = function( type ) {
7818 delete xhrCallbacks[ id ];
7819 callback = xhr.onload = xhr.onerror = null;
7820 if ( type === "abort" ) {
7822 } else if ( type === "error" ) {
7824 // file protocol always yields status 0, assume 404
7830 xhrSuccessStatus[ xhr.status ] || xhr.status,
7833 // #11426: When requesting binary data, IE9 will throw an exception
7834 // on any attempt to access responseText
7835 typeof xhr.responseText === "string" ? {
7836 text: xhr.responseText
7838 xhr.getAllResponseHeaders()
7845 xhr.onload = callback();
7846 xhr.onerror = callback("error");
7847 // Create the abort callback
7848 callback = xhrCallbacks[( id = xhrId++ )] = callback("abort");
7849 // Do send the request
7850 // This may raise an exception which is actually
7851 // handled in jQuery.ajax (so no try/catch here)
7852 xhr.send( options.hasContent && options.data || null );
7863 rfxtypes = /^(?:toggle|show|hide)$/,
7864 rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
7865 rrun = /queueHooks$/,
7866 animationPrefilters = [ defaultPrefilter ],
7868 "*": [function( prop, value ) {
7869 var tween = this.createTween( prop, value ),
7870 target = tween.cur(),
7871 parts = rfxnum.exec( value ),
7872 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
7874 // Starting value computation is required for potential unit mismatches
7875 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
7876 rfxnum.exec( jQuery.css( tween.elem, prop ) ),
7880 if ( start && start[ 3 ] !== unit ) {
7881 // Trust units reported by jQuery.css
7882 unit = unit || start[ 3 ];
7884 // Make sure we update the tween properties later on
7885 parts = parts || [];
7887 // Iteratively approximate from a nonzero starting point
7888 start = +target || 1;
7891 // If previous iteration zeroed out, double until we get *something*
7892 // Use a string for doubling factor so we don't accidentally see scale as unchanged below
7893 scale = scale || ".5";
7896 start = start / scale;
7897 jQuery.style( tween.elem, prop, start + unit );
7899 // Update scale, tolerating zero or NaN from tween.cur()
7900 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
7901 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
7904 // Update tween properties
7906 start = tween.start = +start || +target || 0;
7908 // If a +=/-= token was provided, we're doing a relative animation
7909 tween.end = parts[ 1 ] ?
7910 start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
7918 // Animations created synchronously will run synchronously
7919 function createFxNow() {
7920 setTimeout(function() {
7923 return ( fxNow = jQuery.now() );
7926 function createTween( value, prop, animation ) {
7928 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
7930 length = collection.length;
7931 for ( ; index < length; index++ ) {
7932 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
7934 // we're done with this property
7940 function Animation( elem, properties, options ) {
7944 length = animationPrefilters.length,
7945 deferred = jQuery.Deferred().always( function() {
7946 // don't match elem in the :animated selector
7953 var currentTime = fxNow || createFxNow(),
7954 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
7955 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
7956 temp = remaining / animation.duration || 0,
7959 length = animation.tweens.length;
7961 for ( ; index < length ; index++ ) {
7962 animation.tweens[ index ].run( percent );
7965 deferred.notifyWith( elem, [ animation, percent, remaining ]);
7967 if ( percent < 1 && length ) {
7970 deferred.resolveWith( elem, [ animation ] );
7974 animation = deferred.promise({
7976 props: jQuery.extend( {}, properties ),
7977 opts: jQuery.extend( true, { specialEasing: {} }, options ),
7978 originalProperties: properties,
7979 originalOptions: options,
7980 startTime: fxNow || createFxNow(),
7981 duration: options.duration,
7983 createTween: function( prop, end ) {
7984 var tween = jQuery.Tween( elem, animation.opts, prop, end,
7985 animation.opts.specialEasing[ prop ] || animation.opts.easing );
7986 animation.tweens.push( tween );
7989 stop: function( gotoEnd ) {
7991 // if we are going to the end, we want to run all the tweens
7992 // otherwise we skip this part
7993 length = gotoEnd ? animation.tweens.length : 0;
7998 for ( ; index < length ; index++ ) {
7999 animation.tweens[ index ].run( 1 );
8002 // resolve when we played the last frame
8003 // otherwise, reject
8005 deferred.resolveWith( elem, [ animation, gotoEnd ] );
8007 deferred.rejectWith( elem, [ animation, gotoEnd ] );
8012 props = animation.props;
8014 propFilter( props, animation.opts.specialEasing );
8016 for ( ; index < length ; index++ ) {
8017 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8023 jQuery.map( props, createTween, animation );
8025 if ( jQuery.isFunction( animation.opts.start ) ) {
8026 animation.opts.start.call( elem, animation );
8030 jQuery.extend( tick, {
8033 queue: animation.opts.queue
8037 // attach callbacks from options
8038 return animation.progress( animation.opts.progress )
8039 .done( animation.opts.done, animation.opts.complete )
8040 .fail( animation.opts.fail )
8041 .always( animation.opts.always );
8044 function propFilter( props, specialEasing ) {
8045 var index, name, easing, value, hooks;
8047 // camelCase, specialEasing and expand cssHook pass
8048 for ( index in props ) {
8049 name = jQuery.camelCase( index );
8050 easing = specialEasing[ name ];
8051 value = props[ index ];
8052 if ( jQuery.isArray( value ) ) {
8053 easing = value[ 1 ];
8054 value = props[ index ] = value[ 0 ];
8057 if ( index !== name ) {
8058 props[ name ] = value;
8059 delete props[ index ];
8062 hooks = jQuery.cssHooks[ name ];
8063 if ( hooks && "expand" in hooks ) {
8064 value = hooks.expand( value );
8065 delete props[ name ];
8067 // not quite $.extend, this wont overwrite keys already present.
8068 // also - reusing 'index' from above because we have the correct "name"
8069 for ( index in value ) {
8070 if ( !( index in props ) ) {
8071 props[ index ] = value[ index ];
8072 specialEasing[ index ] = easing;
8076 specialEasing[ name ] = easing;
8081 jQuery.Animation = jQuery.extend( Animation, {
8083 tweener: function( props, callback ) {
8084 if ( jQuery.isFunction( props ) ) {
8088 props = props.split(" ");
8093 length = props.length;
8095 for ( ; index < length ; index++ ) {
8096 prop = props[ index ];
8097 tweeners[ prop ] = tweeners[ prop ] || [];
8098 tweeners[ prop ].unshift( callback );
8102 prefilter: function( callback, prepend ) {
8104 animationPrefilters.unshift( callback );
8106 animationPrefilters.push( callback );
8111 function defaultPrefilter( elem, props, opts ) {
8112 /* jshint validthis: true */
8113 var prop, value, toggle, tween, hooks, oldfire,
8117 hidden = elem.nodeType && isHidden( elem ),
8118 dataShow = data_priv.get( elem, "fxshow" );
8120 // handle queue: false promises
8121 if ( !opts.queue ) {
8122 hooks = jQuery._queueHooks( elem, "fx" );
8123 if ( hooks.unqueued == null ) {
8125 oldfire = hooks.empty.fire;
8126 hooks.empty.fire = function() {
8127 if ( !hooks.unqueued ) {
8134 anim.always(function() {
8135 // doing this makes sure that the complete handler will be called
8136 // before this completes
8137 anim.always(function() {
8139 if ( !jQuery.queue( elem, "fx" ).length ) {
8146 // height/width overflow pass
8147 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
8148 // Make sure that nothing sneaks out
8149 // Record all 3 overflow attributes because IE9-10 do not
8150 // change the overflow attribute when overflowX and
8151 // overflowY are set to the same value
8152 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
8154 // Set display property to inline-block for height/width
8155 // animations on inline elements that are having width/height animated
8156 if ( jQuery.css( elem, "display" ) === "inline" &&
8157 jQuery.css( elem, "float" ) === "none" ) {
8159 style.display = "inline-block";
8163 if ( opts.overflow ) {
8164 style.overflow = "hidden";
8165 anim.always(function() {
8166 style.overflow = opts.overflow[ 0 ];
8167 style.overflowX = opts.overflow[ 1 ];
8168 style.overflowY = opts.overflow[ 2 ];
8174 for ( prop in props ) {
8175 value = props[ prop ];
8176 if ( rfxtypes.exec( value ) ) {
8177 delete props[ prop ];
8178 toggle = toggle || value === "toggle";
8179 if ( value === ( hidden ? "hide" : "show" ) ) {
8181 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
8182 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
8188 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
8192 if ( !jQuery.isEmptyObject( orig ) ) {
8194 if ( "hidden" in dataShow ) {
8195 hidden = dataShow.hidden;
8198 dataShow = data_priv.access( elem, "fxshow", {} );
8201 // store state if its toggle - enables .stop().toggle() to "reverse"
8203 dataShow.hidden = !hidden;
8206 jQuery( elem ).show();
8208 anim.done(function() {
8209 jQuery( elem ).hide();
8212 anim.done(function() {
8215 data_priv.remove( elem, "fxshow" );
8216 for ( prop in orig ) {
8217 jQuery.style( elem, prop, orig[ prop ] );
8220 for ( prop in orig ) {
8221 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
8223 if ( !( prop in dataShow ) ) {
8224 dataShow[ prop ] = tween.start;
8226 tween.end = tween.start;
8227 tween.start = prop === "width" || prop === "height" ? 1 : 0;
8234 function Tween( elem, options, prop, end, easing ) {
8235 return new Tween.prototype.init( elem, options, prop, end, easing );
8237 jQuery.Tween = Tween;
8241 init: function( elem, options, prop, end, easing, unit ) {
8244 this.easing = easing || "swing";
8245 this.options = options;
8246 this.start = this.now = this.cur();
8248 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
8251 var hooks = Tween.propHooks[ this.prop ];
8253 return hooks && hooks.get ?
8255 Tween.propHooks._default.get( this );
8257 run: function( percent ) {
8259 hooks = Tween.propHooks[ this.prop ];
8261 if ( this.options.duration ) {
8262 this.pos = eased = jQuery.easing[ this.easing ](
8263 percent, this.options.duration * percent, 0, 1, this.options.duration
8266 this.pos = eased = percent;
8268 this.now = ( this.end - this.start ) * eased + this.start;
8270 if ( this.options.step ) {
8271 this.options.step.call( this.elem, this.now, this );
8274 if ( hooks && hooks.set ) {
8277 Tween.propHooks._default.set( this );
8283 Tween.prototype.init.prototype = Tween.prototype;
8287 get: function( tween ) {
8290 if ( tween.elem[ tween.prop ] != null &&
8291 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
8292 return tween.elem[ tween.prop ];
8295 // passing an empty string as a 3rd parameter to .css will automatically
8296 // attempt a parseFloat and fallback to a string if the parse fails
8297 // so, simple values such as "10px" are parsed to Float.
8298 // complex values such as "rotate(1rad)" are returned as is.
8299 result = jQuery.css( tween.elem, tween.prop, "" );
8300 // Empty strings, null, undefined and "auto" are converted to 0.
8301 return !result || result === "auto" ? 0 : result;
8303 set: function( tween ) {
8304 // use step hook for back compat - use cssHook if its there - use .style if its
8305 // available and use plain properties where available
8306 if ( jQuery.fx.step[ tween.prop ] ) {
8307 jQuery.fx.step[ tween.prop ]( tween );
8308 } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
8309 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
8311 tween.elem[ tween.prop ] = tween.now;
8318 // Panic based approach to setting things on disconnected nodes
8320 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
8321 set: function( tween ) {
8322 if ( tween.elem.nodeType && tween.elem.parentNode ) {
8323 tween.elem[ tween.prop ] = tween.now;
8328 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
8329 var cssFn = jQuery.fn[ name ];
8330 jQuery.fn[ name ] = function( speed, easing, callback ) {
8331 return speed == null || typeof speed === "boolean" ?
8332 cssFn.apply( this, arguments ) :
8333 this.animate( genFx( name, true ), speed, easing, callback );
8338 fadeTo: function( speed, to, easing, callback ) {
8340 // show any hidden elements after setting opacity to 0
8341 return this.filter( isHidden ).css( "opacity", 0 ).show()
8343 // animate to the value specified
8344 .end().animate({ opacity: to }, speed, easing, callback );
8346 animate: function( prop, speed, easing, callback ) {
8347 var empty = jQuery.isEmptyObject( prop ),
8348 optall = jQuery.speed( speed, easing, callback ),
8349 doAnimation = function() {
8350 // Operate on a copy of prop so per-property easing won't be lost
8351 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
8353 // Empty animations, or finishing resolves immediately
8354 if ( empty || data_priv.get( this, "finish" ) ) {
8358 doAnimation.finish = doAnimation;
8360 return empty || optall.queue === false ?
8361 this.each( doAnimation ) :
8362 this.queue( optall.queue, doAnimation );
8364 stop: function( type, clearQueue, gotoEnd ) {
8365 var stopQueue = function( hooks ) {
8366 var stop = hooks.stop;
8371 if ( typeof type !== "string" ) {
8372 gotoEnd = clearQueue;
8376 if ( clearQueue && type !== false ) {
8377 this.queue( type || "fx", [] );
8380 return this.each(function() {
8382 index = type != null && type + "queueHooks",
8383 timers = jQuery.timers,
8384 data = data_priv.get( this );
8387 if ( data[ index ] && data[ index ].stop ) {
8388 stopQueue( data[ index ] );
8391 for ( index in data ) {
8392 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
8393 stopQueue( data[ index ] );
8398 for ( index = timers.length; index--; ) {
8399 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
8400 timers[ index ].anim.stop( gotoEnd );
8402 timers.splice( index, 1 );
8406 // start the next in the queue if the last step wasn't forced
8407 // timers currently will call their complete callbacks, which will dequeue
8408 // but only if they were gotoEnd
8409 if ( dequeue || !gotoEnd ) {
8410 jQuery.dequeue( this, type );
8414 finish: function( type ) {
8415 if ( type !== false ) {
8416 type = type || "fx";
8418 return this.each(function() {
8420 data = data_priv.get( this ),
8421 queue = data[ type + "queue" ],
8422 hooks = data[ type + "queueHooks" ],
8423 timers = jQuery.timers,
8424 length = queue ? queue.length : 0;
8426 // enable finishing flag on private data
8429 // empty the queue first
8430 jQuery.queue( this, type, [] );
8432 if ( hooks && hooks.stop ) {
8433 hooks.stop.call( this, true );
8436 // look for any active animations, and finish them
8437 for ( index = timers.length; index--; ) {
8438 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
8439 timers[ index ].anim.stop( true );
8440 timers.splice( index, 1 );
8444 // look for any animations in the old queue and finish them
8445 for ( index = 0; index < length; index++ ) {
8446 if ( queue[ index ] && queue[ index ].finish ) {
8447 queue[ index ].finish.call( this );
8451 // turn off finishing flag
8457 // Generate parameters to create a standard animation
8458 function genFx( type, includeWidth ) {
8460 attrs = { height: type },
8463 // if we include width, step value is 1 to do all cssExpand values,
8464 // if we don't include width, step value is 2 to skip over Left and Right
8465 includeWidth = includeWidth? 1 : 0;
8466 for( ; i < 4 ; i += 2 - includeWidth ) {
8467 which = cssExpand[ i ];
8468 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
8471 if ( includeWidth ) {
8472 attrs.opacity = attrs.width = type;
8478 // Generate shortcuts for custom animations
8480 slideDown: genFx("show"),
8481 slideUp: genFx("hide"),
8482 slideToggle: genFx("toggle"),
8483 fadeIn: { opacity: "show" },
8484 fadeOut: { opacity: "hide" },
8485 fadeToggle: { opacity: "toggle" }
8486 }, function( name, props ) {
8487 jQuery.fn[ name ] = function( speed, easing, callback ) {
8488 return this.animate( props, speed, easing, callback );
8492 jQuery.speed = function( speed, easing, fn ) {
8493 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
8494 complete: fn || !fn && easing ||
8495 jQuery.isFunction( speed ) && speed,
8497 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
8500 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
8501 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
8503 // normalize opt.queue - true/undefined/null -> "fx"
8504 if ( opt.queue == null || opt.queue === true ) {
8509 opt.old = opt.complete;
8511 opt.complete = function() {
8512 if ( jQuery.isFunction( opt.old ) ) {
8513 opt.old.call( this );
8517 jQuery.dequeue( this, opt.queue );
8525 linear: function( p ) {
8528 swing: function( p ) {
8529 return 0.5 - Math.cos( p*Math.PI ) / 2;
8534 jQuery.fx = Tween.prototype.init;
8535 jQuery.fx.tick = function() {
8537 timers = jQuery.timers,
8540 fxNow = jQuery.now();
8542 for ( ; i < timers.length; i++ ) {
8543 timer = timers[ i ];
8544 // Checks the timer has not already been removed
8545 if ( !timer() && timers[ i ] === timer ) {
8546 timers.splice( i--, 1 );
8550 if ( !timers.length ) {
8556 jQuery.fx.timer = function( timer ) {
8557 if ( timer() && jQuery.timers.push( timer ) ) {
8562 jQuery.fx.interval = 13;
8564 jQuery.fx.start = function() {
8566 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
8570 jQuery.fx.stop = function() {
8571 clearInterval( timerId );
8575 jQuery.fx.speeds = {
8582 // Back Compat <1.8 extension point
8583 jQuery.fx.step = {};
8585 if ( jQuery.expr && jQuery.expr.filters ) {
8586 jQuery.expr.filters.animated = function( elem ) {
8587 return jQuery.grep(jQuery.timers, function( fn ) {
8588 return elem === fn.elem;
8592 jQuery.fn.offset = function( options ) {
8593 if ( arguments.length ) {
8594 return options === undefined ?
8596 this.each(function( i ) {
8597 jQuery.offset.setOffset( this, options, i );
8603 box = { top: 0, left: 0 },
8604 doc = elem && elem.ownerDocument;
8610 docElem = doc.documentElement;
8612 // Make sure it's not a disconnected DOM node
8613 if ( !jQuery.contains( docElem, elem ) ) {
8617 // If we don't have gBCR, just use 0,0 rather than error
8618 // BlackBerry 5, iOS 3 (original iPhone)
8619 if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
8620 box = elem.getBoundingClientRect();
8622 win = getWindow( doc );
8624 top: box.top + win.pageYOffset - docElem.clientTop,
8625 left: box.left + win.pageXOffset - docElem.clientLeft
8631 setOffset: function( elem, options, i ) {
8632 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
8633 position = jQuery.css( elem, "position" ),
8634 curElem = jQuery( elem ),
8637 // Set position first, in-case top/left are set even on static elem
8638 if ( position === "static" ) {
8639 elem.style.position = "relative";
8642 curOffset = curElem.offset();
8643 curCSSTop = jQuery.css( elem, "top" );
8644 curCSSLeft = jQuery.css( elem, "left" );
8645 calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
8647 // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
8648 if ( calculatePosition ) {
8649 curPosition = curElem.position();
8650 curTop = curPosition.top;
8651 curLeft = curPosition.left;
8654 curTop = parseFloat( curCSSTop ) || 0;
8655 curLeft = parseFloat( curCSSLeft ) || 0;
8658 if ( jQuery.isFunction( options ) ) {
8659 options = options.call( elem, i, curOffset );
8662 if ( options.top != null ) {
8663 props.top = ( options.top - curOffset.top ) + curTop;
8665 if ( options.left != null ) {
8666 props.left = ( options.left - curOffset.left ) + curLeft;
8669 if ( "using" in options ) {
8670 options.using.call( elem, props );
8673 curElem.css( props );
8681 position: function() {
8686 var offsetParent, offset,
8688 parentOffset = { top: 0, left: 0 };
8690 // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
8691 if ( jQuery.css( elem, "position" ) === "fixed" ) {
8692 // We assume that getBoundingClientRect is available when computed position is fixed
8693 offset = elem.getBoundingClientRect();
8696 // Get *real* offsetParent
8697 offsetParent = this.offsetParent();
8699 // Get correct offsets
8700 offset = this.offset();
8701 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
8702 parentOffset = offsetParent.offset();
8705 // Add offsetParent borders
8706 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
8707 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
8710 // Subtract parent offsets and element margins
8712 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
8713 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
8717 offsetParent: function() {
8718 return this.map(function() {
8719 var offsetParent = this.offsetParent || docElem;
8721 while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
8722 offsetParent = offsetParent.offsetParent;
8725 return offsetParent || docElem;
8731 // Create scrollLeft and scrollTop methods
8732 jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
8733 var top = "pageYOffset" === prop;
8735 jQuery.fn[ method ] = function( val ) {
8736 return jQuery.access( this, function( elem, method, val ) {
8737 var win = getWindow( elem );
8739 if ( val === undefined ) {
8740 return win ? win[ prop ] : elem[ method ];
8745 !top ? val : window.pageXOffset,
8746 top ? val : window.pageYOffset
8750 elem[ method ] = val;
8752 }, method, val, arguments.length, null );
8756 function getWindow( elem ) {
8757 return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
8759 // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
8760 jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
8761 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
8762 // margin is only for outerHeight, outerWidth
8763 jQuery.fn[ funcName ] = function( margin, value ) {
8764 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
8765 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
8767 return jQuery.access( this, function( elem, type, value ) {
8770 if ( jQuery.isWindow( elem ) ) {
8771 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
8772 // isn't a whole lot we can do. See pull request at this URL for discussion:
8773 // https://github.com/jquery/jquery/pull/764
8774 return elem.document.documentElement[ "client" + name ];
8777 // Get document width or height
8778 if ( elem.nodeType === 9 ) {
8779 doc = elem.documentElement;
8781 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
8782 // whichever is greatest
8784 elem.body[ "scroll" + name ], doc[ "scroll" + name ],
8785 elem.body[ "offset" + name ], doc[ "offset" + name ],
8786 doc[ "client" + name ]
8790 return value === undefined ?
8791 // Get width or height on the element, requesting but not forcing parseFloat
8792 jQuery.css( elem, type, extra ) :
8794 // Set width or height on the element
8795 jQuery.style( elem, type, value, extra );
8796 }, type, chainable ? margin : undefined, chainable, null );
8800 // Limit scope pollution from any deprecated API
8803 // The number of elements contained in the matched element set
8804 jQuery.fn.size = function() {
8808 jQuery.fn.andSelf = jQuery.fn.addBack;
8811 if ( typeof module === "object" && module && typeof module.exports === "object" ) {
8812 // Expose jQuery as module.exports in loaders that implement the Node
8813 // module pattern (including browserify). Do not create the global, since
8814 // the user will be storing it themselves locally, and globals are frowned
8815 // upon in the Node module world.
8816 module.exports = jQuery;
8818 // Register as a named AMD module, since jQuery can be concatenated with other
8819 // files that may use define, but not via a proper concatenation script that
8820 // understands anonymous AMD modules. A named AMD is safest and most robust
8821 // way to register. Lowercase jquery is used because AMD module names are
8822 // derived from file names, and jQuery is normally delivered in a lowercase
8823 // file name. Do this after creating the global so that if an AMD module wants
8824 // to call noConflict to hide this version of jQuery, it will work.
8825 if ( typeof define === "function" && define.amd ) {
8826 define( "jquery", [], function () { return jQuery; } );
8830 // If there is a window object, that at least has a document property,
8831 // define jQuery and $ identifiers
8832 if ( typeof window === "object" && typeof window.document === "object" ) {
8833 window.jQuery = window.$ = jQuery;
8840 * Lo-Dash 2.2.1 (Custom Build) <http://lodash.com/>
8841 * Build: `lodash modern -o ./dist/lodash.js`
8842 * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
8843 * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
8844 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
8845 * Available under MIT license <http://lodash.com/license>
8849 /** Used as a safe reference for `undefined` in pre ES5 environments */
8852 /** Used to pool arrays and objects used internally */
8856 /** Used to generate unique IDs */
8859 /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
8860 var keyPrefix = +new Date + '';
8862 /** Used as the size when optimizations are enabled for large arrays */
8863 var largeArraySize = 75;
8865 /** Used as the max size of the `arrayPool` and `objectPool` */
8866 var maxPoolSize = 40;
8868 /** Used to detect and test whitespace */
8871 ' \t\x0B\f\xA0\ufeff' +
8874 '\n\r\u2028\u2029' +
8876 // unicode category "Zs" space separators
8877 '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
8880 /** Used to match empty string literals in compiled template source */
8881 var reEmptyStringLeading = /\b__p \+= '';/g,
8882 reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
8883 reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
8886 * Used to match ES6 template delimiters
8887 * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
8889 var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
8891 /** Used to match regexp flags from their coerced string values */
8892 var reFlags = /\w*$/;
8894 /** Used to detected named functions */
8895 var reFuncName = /^function[ \n\r\t]+\w/;
8897 /** Used to match "interpolate" template delimiters */
8898 var reInterpolate = /<%=([\s\S]+?)%>/g;
8900 /** Used to match leading whitespace and zeros to be removed */
8901 var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
8903 /** Used to ensure capturing order of template delimiters */
8904 var reNoMatch = /($^)/;
8906 /** Used to detect functions containing a `this` reference */
8907 var reThis = /\bthis\b/;
8909 /** Used to match unescaped characters in compiled string literals */
8910 var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
8912 /** Used to assign default `context` object properties */
8913 var contextProps = [
8914 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
8915 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
8916 'parseInt', 'setImmediate', 'setTimeout'
8919 /** Used to make template sourceURLs easier to identify */
8920 var templateCounter = 0;
8922 /** `Object#toString` result shortcuts */
8923 var argsClass = '[object Arguments]',
8924 arrayClass = '[object Array]',
8925 boolClass = '[object Boolean]',
8926 dateClass = '[object Date]',
8927 funcClass = '[object Function]',
8928 numberClass = '[object Number]',
8929 objectClass = '[object Object]',
8930 regexpClass = '[object RegExp]',
8931 stringClass = '[object String]';
8933 /** Used to identify object classifications that `_.clone` supports */
8934 var cloneableClasses = {};
8935 cloneableClasses[funcClass] = false;
8936 cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
8937 cloneableClasses[boolClass] = cloneableClasses[dateClass] =
8938 cloneableClasses[numberClass] = cloneableClasses[objectClass] =
8939 cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
8941 /** Used as an internal `_.debounce` options object */
8942 var debounceOptions = {
8948 /** Used as the property descriptor for `__bindData__` */
8950 'configurable': false,
8951 'enumerable': false,
8956 /** Used to determine if values are of the language type Object */
8966 /** Used to escape characters for inclusion in compiled string literals */
8967 var stringEscapes = {
8977 /** Used as a reference to the global object */
8978 var root = (objectTypes[typeof window] && window) || this;
8980 /** Detect free variable `exports` */
8981 var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
8983 /** Detect free variable `module` */
8984 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
8986 /** Detect the popular CommonJS extension `module.exports` */
8987 var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
8989 /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
8990 var freeGlobal = objectTypes[typeof global] && global;
8991 if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
8995 /*--------------------------------------------------------------------------*/
8998 * The base implementation of `_.indexOf` without support for binary searches
8999 * or `fromIndex` constraints.
9002 * @param {Array} array The array to search.
9003 * @param {*} value The value to search for.
9004 * @param {number} [fromIndex=0] The index to search from.
9005 * @returns {number} Returns the index of the matched value or `-1`.
9007 function baseIndexOf(array, value, fromIndex) {
9008 var index = (fromIndex || 0) - 1,
9009 length = array ? array.length : 0;
9011 while (++index < length) {
9012 if (array[index] === value) {
9020 * An implementation of `_.contains` for cache objects that mimics the return
9021 * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
9024 * @param {Object} cache The cache object to inspect.
9025 * @param {*} value The value to search for.
9026 * @returns {number} Returns `0` if `value` is found, else `-1`.
9028 function cacheIndexOf(cache, value) {
9029 var type = typeof value;
9030 cache = cache.cache;
9032 if (type == 'boolean' || value == null) {
9033 return cache[value] ? 0 : -1;
9035 if (type != 'number' && type != 'string') {
9038 var key = type == 'number' ? value : keyPrefix + value;
9039 cache = (cache = cache[type]) && cache[key];
9041 return type == 'object'
9042 ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
9047 * Adds a given value to the corresponding cache object.
9050 * @param {*} value The value to add to the cache.
9052 function cachePush(value) {
9053 var cache = this.cache,
9054 type = typeof value;
9056 if (type == 'boolean' || value == null) {
9057 cache[value] = true;
9059 if (type != 'number' && type != 'string') {
9062 var key = type == 'number' ? value : keyPrefix + value,
9063 typeCache = cache[type] || (cache[type] = {});
9065 if (type == 'object') {
9066 (typeCache[key] || (typeCache[key] = [])).push(value);
9068 typeCache[key] = true;
9074 * Used by `_.max` and `_.min` as the default callback when a given
9075 * collection is a string value.
9078 * @param {string} value The character to inspect.
9079 * @returns {number} Returns the code unit of given character.
9081 function charAtCallback(value) {
9082 return value.charCodeAt(0);
9086 * Used by `sortBy` to compare transformed `collection` elements, stable sorting
9087 * them in ascending order.
9090 * @param {Object} a The object to compare to `b`.
9091 * @param {Object} b The object to compare to `a`.
9092 * @returns {number} Returns the sort order indicator of `1` or `-1`.
9094 function compareAscending(a, b) {
9095 var ac = a.criteria,
9098 // ensure a stable sort in V8 and other engines
9099 // http://code.google.com/p/v8/issues/detail?id=90
9101 if (ac > bc || typeof ac == 'undefined') {
9104 if (ac < bc || typeof bc == 'undefined') {
9108 // The JS engine embedded in Adobe applications like InDesign has a buggy
9109 // `Array#sort` implementation that causes it, under certain circumstances,
9110 // to return the same value for `a` and `b`.
9111 // See https://github.com/jashkenas/underscore/pull/1247
9112 return a.index - b.index;
9116 * Creates a cache object to optimize linear searches of large arrays.
9119 * @param {Array} [array=[]] The array to search.
9120 * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
9122 function createCache(array) {
9124 length = array.length,
9126 mid = array[(length / 2) | 0],
9127 last = array[length - 1];
9129 if (first && typeof first == 'object' &&
9130 mid && typeof mid == 'object' && last && typeof last == 'object') {
9133 var cache = getObject();
9134 cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
9136 var result = getObject();
9137 result.array = array;
9138 result.cache = cache;
9139 result.push = cachePush;
9141 while (++index < length) {
9142 result.push(array[index]);
9148 * Used by `template` to escape characters for inclusion in compiled
9152 * @param {string} match The matched character to escape.
9153 * @returns {string} Returns the escaped character.
9155 function escapeStringChar(match) {
9156 return '\\' + stringEscapes[match];
9160 * Gets an array from the array pool or creates a new one if the pool is empty.
9163 * @returns {Array} The array from the pool.
9165 function getArray() {
9166 return arrayPool.pop() || [];
9170 * Gets an object from the object pool or creates a new one if the pool is empty.
9173 * @returns {Object} The object from the pool.
9175 function getObject() {
9176 return objectPool.pop() || {
9194 * A no-operation function.
9199 // no operation performed
9203 * Releases the given array back to the array pool.
9206 * @param {Array} [array] The array to release.
9208 function releaseArray(array) {
9210 if (arrayPool.length < maxPoolSize) {
9211 arrayPool.push(array);
9216 * Releases the given object back to the object pool.
9219 * @param {Object} [object] The object to release.
9221 function releaseObject(object) {
9222 var cache = object.cache;
9224 releaseObject(cache);
9226 object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
9227 if (objectPool.length < maxPoolSize) {
9228 objectPool.push(object);
9233 * Slices the `collection` from the `start` index up to, but not including,
9236 * Note: This function is used instead of `Array#slice` to support node lists
9237 * in IE < 9 and to ensure dense arrays are returned.
9240 * @param {Array|Object|string} collection The collection to slice.
9241 * @param {number} start The start index.
9242 * @param {number} end The end index.
9243 * @returns {Array} Returns the new array.
9245 function slice(array, start, end) {
9246 start || (start = 0);
9247 if (typeof end == 'undefined') {
9248 end = array ? array.length : 0;
9251 length = end - start || 0,
9252 result = Array(length < 0 ? 0 : length);
9254 while (++index < length) {
9255 result[index] = array[start + index];
9260 /*--------------------------------------------------------------------------*/
9263 * Create a new `lodash` function using the given context object.
9267 * @category Utilities
9268 * @param {Object} [context=root] The context object.
9269 * @returns {Function} Returns the `lodash` function.
9271 function runInContext(context) {
9272 // Avoid issues with some ES3 environments that attempt to use values, named
9273 // after built-in constructors like `Object`, for the creation of literals.
9274 // ES5 clears this up by stating that literals must use built-in constructors.
9275 // See http://es5.github.io/#x11.1.5.
9276 context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
9278 /** Native constructor references */
9279 var Array = context.Array,
9280 Boolean = context.Boolean,
9281 Date = context.Date,
9282 Function = context.Function,
9283 Math = context.Math,
9284 Number = context.Number,
9285 Object = context.Object,
9286 RegExp = context.RegExp,
9287 String = context.String,
9288 TypeError = context.TypeError;
9291 * Used for `Array` method references.
9293 * Normally `Array.prototype` would suffice, however, using an array literal
9294 * avoids issues in Narwhal.
9298 /** Used for native method references */
9299 var objectProto = Object.prototype;
9301 /** Used to restore the original `_` reference in `noConflict` */
9302 var oldDash = context._;
9304 /** Used to detect if a method is native */
9305 var reNative = RegExp('^' +
9306 String(objectProto.valueOf)
9307 .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
9308 .replace(/valueOf|for [^\]]+/g, '.+?') + '$'
9311 /** Native method shortcuts */
9312 var ceil = Math.ceil,
9313 clearTimeout = context.clearTimeout,
9315 fnToString = Function.prototype.toString,
9316 getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
9317 hasOwnProperty = objectProto.hasOwnProperty,
9318 now = reNative.test(now = Date.now) && now || function() { return +new Date; },
9319 push = arrayRef.push,
9320 setImmediate = context.setImmediate,
9321 setTimeout = context.setTimeout,
9322 splice = arrayRef.splice,
9323 toString = objectProto.toString,
9324 unshift = arrayRef.unshift;
9326 var defineProperty = (function() {
9329 func = reNative.test(func = Object.defineProperty) && func,
9330 result = func(o, o, o) && func;
9335 /* Native method shortcuts for methods with the same name as other `lodash` methods */
9336 var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind,
9337 nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate,
9338 nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
9339 nativeIsFinite = context.isFinite,
9340 nativeIsNaN = context.isNaN,
9341 nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
9342 nativeMax = Math.max,
9343 nativeMin = Math.min,
9344 nativeParseInt = context.parseInt,
9345 nativeRandom = Math.random,
9346 nativeSlice = arrayRef.slice;
9348 /** Detect various environments */
9349 var isIeOpera = reNative.test(context.attachEvent),
9350 isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera);
9352 /** Used to lookup a built-in constructor by [[Class]] */
9353 var ctorByClass = {};
9354 ctorByClass[arrayClass] = Array;
9355 ctorByClass[boolClass] = Boolean;
9356 ctorByClass[dateClass] = Date;
9357 ctorByClass[funcClass] = Function;
9358 ctorByClass[objectClass] = Object;
9359 ctorByClass[numberClass] = Number;
9360 ctorByClass[regexpClass] = RegExp;
9361 ctorByClass[stringClass] = String;
9363 /*--------------------------------------------------------------------------*/
9366 * Creates a `lodash` object which wraps the given value to enable intuitive
9369 * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
9370 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
9373 * Chaining is supported in custom builds as long as the `value` method is
9374 * implicitly or explicitly included in the build.
9376 * The chainable wrapper functions are:
9377 * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
9378 * `compose`, `concat`, `countBy`, `createCallback`, `curry`, `debounce`,
9379 * `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`,
9380 * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`,
9381 * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`,
9382 * `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`,
9383 * `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, `range`, `reject`,
9384 * `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
9385 * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
9386 * `unzip`, `values`, `where`, `without`, `wrap`, and `zip`
9388 * The non-chainable wrapper functions are:
9389 * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
9390 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
9391 * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
9392 * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
9393 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
9394 * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
9395 * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
9396 * `template`, `unescape`, `uniqueId`, and `value`
9398 * The wrapper functions `first` and `last` return wrapped values when `n` is
9399 * provided, otherwise they return unwrapped values.
9401 * Explicit chaining can be enabled by using the `_.chain` method.
9405 * @category Chaining
9406 * @param {*} value The value to wrap in a `lodash` instance.
9407 * @returns {Object} Returns a `lodash` instance.
9410 * var wrapped = _([1, 2, 3]);
9412 * // returns an unwrapped value
9413 * wrapped.reduce(function(sum, num) {
9418 * // returns a wrapped value
9419 * var squares = wrapped.map(function(num) {
9423 * _.isArray(squares);
9426 * _.isArray(squares.value());
9429 function lodash(value) {
9430 // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
9431 return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
9433 : new lodashWrapper(value);
9437 * A fast path for creating `lodash` wrapper objects.
9440 * @param {*} value The value to wrap in a `lodash` instance.
9441 * @param {boolean} chainAll A flag to enable chaining for all methods
9442 * @returns {Object} Returns a `lodash` instance.
9444 function lodashWrapper(value, chainAll) {
9445 this.__chain__ = !!chainAll;
9446 this.__wrapped__ = value;
9448 // ensure `new lodashWrapper` is an instance of `lodash`
9449 lodashWrapper.prototype = lodash.prototype;
9452 * An object used to flag environments features.
9458 var support = lodash.support = {};
9461 * Detect if `Function#bind` exists and is inferred to be fast (all but V8).
9463 * @memberOf _.support
9466 support.fastBind = nativeBind && !isV8;
9469 * Detect if functions can be decompiled by `Function#toString`
9470 * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
9472 * @memberOf _.support
9475 support.funcDecomp = !reNative.test(context.WinRTError) && reThis.test(runInContext);
9478 * Detect if `Function#name` is supported (all but IE).
9480 * @memberOf _.support
9483 support.funcNames = typeof Function.name == 'string';
9486 * By default, the template delimiters used by Lo-Dash are similar to those in
9487 * embedded Ruby (ERB). Change the following template settings to use alternative
9494 lodash.templateSettings = {
9497 * Used to detect `data` property values to be HTML-escaped.
9499 * @memberOf _.templateSettings
9502 'escape': /<%-([\s\S]+?)%>/g,
9505 * Used to detect code to be evaluated.
9507 * @memberOf _.templateSettings
9510 'evaluate': /<%([\s\S]+?)%>/g,
9513 * Used to detect `data` property values to inject.
9515 * @memberOf _.templateSettings
9518 'interpolate': reInterpolate,
9521 * Used to reference the data object in the template text.
9523 * @memberOf _.templateSettings
9529 * Used to import variables into the compiled template.
9531 * @memberOf _.templateSettings
9537 * A reference to the `lodash` function.
9539 * @memberOf _.templateSettings.imports
9546 /*--------------------------------------------------------------------------*/
9549 * The base implementation of `_.clone` without argument juggling or support
9550 * for `thisArg` binding.
9553 * @param {*} value The value to clone.
9554 * @param {boolean} [deep=false] Specify a deep clone.
9555 * @param {Function} [callback] The function to customize cloning values.
9556 * @param {Array} [stackA=[]] Tracks traversed source objects.
9557 * @param {Array} [stackB=[]] Associates clones with source counterparts.
9558 * @returns {*} Returns the cloned value.
9560 function baseClone(value, deep, callback, stackA, stackB) {
9562 var result = callback(value);
9563 if (typeof result != 'undefined') {
9567 // inspect [[Class]]
9568 var isObj = isObject(value);
9570 var className = toString.call(value);
9571 if (!cloneableClasses[className]) {
9574 var ctor = ctorByClass[className];
9575 switch (className) {
9578 return new ctor(+value);
9582 return new ctor(value);
9585 result = ctor(value.source, reFlags.exec(value));
9586 result.lastIndex = value.lastIndex;
9592 var isArr = isArray(value);
9594 // check for circular references and return corresponding clone
9595 var initedStack = !stackA;
9596 stackA || (stackA = getArray());
9597 stackB || (stackB = getArray());
9599 var length = stackA.length;
9601 if (stackA[length] == value) {
9602 return stackB[length];
9605 result = isArr ? ctor(value.length) : {};
9608 result = isArr ? slice(value) : assign({}, value);
9610 // add array properties assigned by `RegExp#exec`
9612 if (hasOwnProperty.call(value, 'index')) {
9613 result.index = value.index;
9615 if (hasOwnProperty.call(value, 'input')) {
9616 result.input = value.input;
9619 // exit for shallow clone
9623 // add the source value to the stack of traversed objects
9624 // and associate it with its clone
9626 stackB.push(result);
9628 // recursively populate clone (susceptible to call stack limits)
9629 (isArr ? forEach : forOwn)(value, function(objValue, key) {
9630 result[key] = baseClone(objValue, deep, callback, stackA, stackB);
9634 releaseArray(stackA);
9635 releaseArray(stackB);
9641 * The base implementation of `_.createCallback` without support for creating
9642 * "_.pluck" or "_.where" style callbacks.
9645 * @param {*} [func=identity] The value to convert to a callback.
9646 * @param {*} [thisArg] The `this` binding of the created callback.
9647 * @param {number} [argCount] The number of arguments the callback accepts.
9648 * @returns {Function} Returns a callback function.
9650 function baseCreateCallback(func, thisArg, argCount) {
9651 if (typeof func != 'function') {
9654 // exit early if there is no `thisArg`
9655 if (typeof thisArg == 'undefined') {
9658 var bindData = func.__bindData__ || (support.funcNames && !func.name);
9659 if (typeof bindData == 'undefined') {
9660 var source = reThis && fnToString.call(func);
9661 if (!support.funcNames && source && !reFuncName.test(source)) {
9664 if (support.funcNames || !bindData) {
9665 // checks if `func` references the `this` keyword and stores the result
9666 bindData = !support.funcDecomp || reThis.test(source);
9667 setBindData(func, bindData);
9670 // exit early if there are no `this` references or `func` is bound
9671 if (bindData !== true && (bindData && bindData[1] & 1)) {
9675 case 1: return function(value) {
9676 return func.call(thisArg, value);
9678 case 2: return function(a, b) {
9679 return func.call(thisArg, a, b);
9681 case 3: return function(value, index, collection) {
9682 return func.call(thisArg, value, index, collection);
9684 case 4: return function(accumulator, value, index, collection) {
9685 return func.call(thisArg, accumulator, value, index, collection);
9688 return bind(func, thisArg);
9692 * The base implementation of `_.flatten` without support for callback
9693 * shorthands or `thisArg` binding.
9696 * @param {Array} array The array to flatten.
9697 * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
9698 * @param {boolean} [isArgArrays=false] A flag to restrict flattening to arrays and `arguments` objects.
9699 * @param {number} [fromIndex=0] The index to start from.
9700 * @returns {Array} Returns a new flattened array.
9702 function baseFlatten(array, isShallow, isArgArrays, fromIndex) {
9703 var index = (fromIndex || 0) - 1,
9704 length = array ? array.length : 0,
9707 while (++index < length) {
9708 var value = array[index];
9710 if (value && typeof value == 'object' && typeof value.length == 'number'
9711 && (isArray(value) || isArguments(value))) {
9712 // recursively flatten arrays (susceptible to call stack limits)
9714 value = baseFlatten(value, isShallow, isArgArrays);
9717 valLength = value.length,
9718 resIndex = result.length;
9720 result.length += valLength;
9721 while (++valIndex < valLength) {
9722 result[resIndex++] = value[valIndex];
9724 } else if (!isArgArrays) {
9732 * The base implementation of `_.isEqual`, without support for `thisArg` binding,
9733 * that allows partial "_.where" style comparisons.
9736 * @param {*} a The value to compare.
9737 * @param {*} b The other value to compare.
9738 * @param {Function} [callback] The function to customize comparing values.
9739 * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
9740 * @param {Array} [stackA=[]] Tracks traversed `a` objects.
9741 * @param {Array} [stackB=[]] Tracks traversed `b` objects.
9742 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
9744 function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
9745 // used to indicate that when comparing objects, `a` has at least the properties of `b`
9747 var result = callback(a, b);
9748 if (typeof result != 'undefined') {
9752 // exit early for identical values
9754 // treat `+0` vs. `-0` as not equal
9755 return a !== 0 || (1 / a == 1 / b);
9757 var type = typeof a,
9758 otherType = typeof b;
9760 // exit early for unlike primitive values
9762 !(a && objectTypes[type]) &&
9763 !(b && objectTypes[otherType])) {
9766 // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
9767 // http://es5.github.io/#x15.3.4.4
9768 if (a == null || b == null) {
9771 // compare [[Class]] names
9772 var className = toString.call(a),
9773 otherClass = toString.call(b);
9775 if (className == argsClass) {
9776 className = objectClass;
9778 if (otherClass == argsClass) {
9779 otherClass = objectClass;
9781 if (className != otherClass) {
9784 switch (className) {
9787 // coerce dates and booleans to numbers, dates to milliseconds and booleans
9788 // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
9792 // treat `NaN` vs. `NaN` as equal
9795 // but treat `+0` vs. `-0` as not equal
9796 : (a == 0 ? (1 / a == 1 / b) : a == +b);
9800 // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
9801 // treat string primitives and their corresponding object instances as equal
9802 return a == String(b);
9804 var isArr = className == arrayClass;
9806 // unwrap any `lodash` wrapped values
9807 if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) {
9808 return baseIsEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, isWhere, stackA, stackB);
9810 // exit for functions and DOM nodes
9811 if (className != objectClass) {
9814 // in older versions of Opera, `arguments` objects have `Array` constructors
9815 var ctorA = a.constructor,
9816 ctorB = b.constructor;
9818 // non `Object` object instances with different constructors are not equal
9819 if (ctorA != ctorB && !(
9820 isFunction(ctorA) && ctorA instanceof ctorA &&
9821 isFunction(ctorB) && ctorB instanceof ctorB
9826 // assume cyclic structures are equal
9827 // the algorithm for detecting cyclic structures is adapted from ES 5.1
9828 // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
9829 var initedStack = !stackA;
9830 stackA || (stackA = getArray());
9831 stackB || (stackB = getArray());
9833 var length = stackA.length;
9835 if (stackA[length] == a) {
9836 return stackB[length] == b;
9842 // add `a` and `b` to the stack of traversed objects
9846 // recursively compare objects and arrays (susceptible to call stack limits)
9851 // compare lengths to determine if a deep comparison is necessary
9852 result = size == a.length;
9853 if (!result && !isWhere) {
9856 // deep compare the contents, ignoring non-numeric properties
9863 if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
9867 } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
9873 // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
9874 // which, in this case, is more costly
9875 forIn(b, function(value, key, b) {
9876 if (hasOwnProperty.call(b, key)) {
9877 // count the number of properties.
9879 // deep compare each property value.
9880 return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
9884 if (result && !isWhere) {
9885 // ensure both objects have the same number of properties
9886 forIn(a, function(value, key, a) {
9887 if (hasOwnProperty.call(a, key)) {
9888 // `size` will be `-1` if `a` has more properties than `b`
9889 return (result = --size > -1);
9894 releaseArray(stackA);
9895 releaseArray(stackB);
9901 * The base implementation of `_.merge` without argument juggling or support
9902 * for `thisArg` binding.
9905 * @param {Object} object The destination object.
9906 * @param {Object} source The source object.
9907 * @param {Function} [callback] The function to customize merging properties.
9908 * @param {Array} [stackA=[]] Tracks traversed source objects.
9909 * @param {Array} [stackB=[]] Associates values with source counterparts.
9911 function baseMerge(object, source, callback, stackA, stackB) {
9912 (isArray(source) ? forEach : forOwn)(source, function(source, key) {
9916 value = object[key];
9918 if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
9919 // avoid merging previously merged cyclic sources
9920 var stackLength = stackA.length;
9921 while (stackLength--) {
9922 if ((found = stackA[stackLength] == source)) {
9923 value = stackB[stackLength];
9930 result = callback(value, source);
9931 if ((isShallow = typeof result != 'undefined')) {
9937 ? (isArray(value) ? value : [])
9938 : (isPlainObject(value) ? value : {});
9940 // add `source` and associated `value` to the stack of traversed objects
9941 stackA.push(source);
9944 // recursively merge objects and arrays (susceptible to call stack limits)
9946 baseMerge(value, source, callback, stackA, stackB);
9952 result = callback(value, source);
9953 if (typeof result == 'undefined') {
9957 if (typeof result != 'undefined') {
9961 object[key] = value;
9966 * The base implementation of `_.uniq` without support for callback shorthands
9967 * or `thisArg` binding.
9970 * @param {Array} array The array to process.
9971 * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
9972 * @param {Function} [callback] The function called per iteration.
9973 * @returns {Array} Returns a duplicate-value-free array.
9975 function baseUniq(array, isSorted, callback) {
9977 indexOf = getIndexOf(),
9978 length = array ? array.length : 0,
9981 var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
9982 seen = (callback || isLarge) ? getArray() : result;
9985 var cache = createCache(seen);
9987 indexOf = cacheIndexOf;
9991 seen = callback ? seen : (releaseArray(seen), result);
9994 while (++index < length) {
9995 var value = array[index],
9996 computed = callback ? callback(value, index, array) : value;
9999 ? !index || seen[seen.length - 1] !== computed
10000 : indexOf(seen, computed) < 0
10002 if (callback || isLarge) {
10003 seen.push(computed);
10005 result.push(value);
10009 releaseArray(seen.array);
10010 releaseObject(seen);
10011 } else if (callback) {
10012 releaseArray(seen);
10018 * Creates a function that aggregates a collection, creating an object composed
10019 * of keys generated from the results of running each element of the collection
10020 * through a callback. The given `setter` function sets the keys and values
10021 * of the composed object.
10024 * @param {Function} setter The setter function.
10025 * @returns {Function} Returns the new aggregator function.
10027 function createAggregator(setter) {
10028 return function(collection, callback, thisArg) {
10030 callback = lodash.createCallback(callback, thisArg, 3);
10033 length = collection ? collection.length : 0;
10035 if (typeof length == 'number') {
10036 while (++index < length) {
10037 var value = collection[index];
10038 setter(result, value, callback(value, index, collection), collection);
10041 forOwn(collection, function(value, key, collection) {
10042 setter(result, value, callback(value, key, collection), collection);
10050 * Creates a function that, when called, either curries or invokes `func`
10051 * with an optional `this` binding and partially applied arguments.
10054 * @param {Function|string} func The function or method name to reference.
10055 * @param {number} bitmask The bitmask of method flags to compose.
10056 * The bitmask may be composed of the following flags:
10060 * 8 - `_.curry` (bound)
10062 * 32 - `_.partialRight`
10063 * @param {Array} [partialArgs] An array of arguments to prepend to those
10064 * provided to the new function.
10065 * @param {Array} [partialRightArgs] An array of arguments to append to those
10066 * provided to the new function.
10067 * @param {*} [thisArg] The `this` binding of `func`.
10068 * @param {number} [arity] The arity of `func`.
10069 * @returns {Function} Returns the new bound function.
10071 function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
10072 var isBind = bitmask & 1,
10073 isBindKey = bitmask & 2,
10074 isCurry = bitmask & 4,
10075 isCurryBound = bitmask & 8,
10076 isPartial = bitmask & 16,
10077 isPartialRight = bitmask & 32,
10080 if (!isBindKey && !isFunction(func)) {
10081 throw new TypeError;
10083 if (isPartial && !partialArgs.length) {
10085 isPartial = partialArgs = false;
10087 if (isPartialRight && !partialRightArgs.length) {
10089 isPartialRight = partialRightArgs = false;
10091 var bindData = func && func.__bindData__;
10093 if (isBind && !(bindData[1] & 1)) {
10094 bindData[4] = thisArg;
10096 if (!isBind && bindData[1] & 1) {
10099 if (isCurry && !(bindData[1] & 4)) {
10100 bindData[5] = arity;
10103 push.apply(bindData[2] || (bindData[2] = []), partialArgs);
10105 if (isPartialRight) {
10106 push.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
10108 bindData[1] |= bitmask;
10109 return createBound.apply(null, bindData);
10111 // use `Function#bind` if it exists and is fast
10112 // (in V8 `Function#bind` is slower except when partially applied)
10113 if (isBind && !(isBindKey || isCurry || isPartialRight) &&
10114 (support.fastBind || (nativeBind && isPartial))) {
10116 var args = [thisArg];
10117 push.apply(args, partialArgs);
10119 var bound = isPartial
10120 ? nativeBind.apply(func, args)
10121 : nativeBind.call(func, thisArg);
10124 bound = function() {
10125 // `Function#bind` spec
10126 // http://es5.github.io/#x15.3.4.5
10127 var args = arguments,
10128 thisBinding = isBind ? thisArg : this;
10130 if (isCurry || isPartial || isPartialRight) {
10131 args = nativeSlice.call(args);
10133 unshift.apply(args, partialArgs);
10135 if (isPartialRight) {
10136 push.apply(args, partialRightArgs);
10138 if (isCurry && args.length < arity) {
10139 bitmask |= 16 & ~32;
10140 return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity);
10144 func = thisBinding[key];
10146 if (this instanceof bound) {
10147 // ensure `new bound` is an instance of `func`
10148 thisBinding = createObject(func.prototype);
10150 // mimic the constructor's `return` behavior
10151 // http://es5.github.io/#x13.2.2
10152 var result = func.apply(thisBinding, args);
10153 return isObject(result) ? result : thisBinding;
10155 return func.apply(thisBinding, args);
10158 setBindData(bound, nativeSlice.call(arguments));
10163 * Creates a new object with the specified `prototype`.
10166 * @param {Object} prototype The prototype object.
10167 * @returns {Object} Returns the new object.
10169 function createObject(prototype) {
10170 return isObject(prototype) ? nativeCreate(prototype) : {};
10172 // fallback for browsers without `Object.create`
10173 if (!nativeCreate) {
10174 createObject = function(prototype) {
10175 if (isObject(prototype)) {
10176 noop.prototype = prototype;
10177 var result = new noop;
10178 noop.prototype = null;
10180 return result || {};
10185 * Used by `escape` to convert characters to HTML entities.
10188 * @param {string} match The matched character to escape.
10189 * @returns {string} Returns the escaped character.
10191 function escapeHtmlChar(match) {
10192 return htmlEscapes[match];
10196 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
10197 * customized, this method returns the custom method, otherwise it returns
10198 * the `baseIndexOf` function.
10201 * @returns {Function} Returns the "indexOf" function.
10203 function getIndexOf() {
10204 var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
10209 * Sets `this` binding data on a given function.
10212 * @param {Function} func The function to set data on.
10213 * @param {*} value The value to set.
10215 var setBindData = !defineProperty ? noop : function(func, value) {
10216 descriptor.value = value;
10217 defineProperty(func, '__bindData__', descriptor);
10221 * A fallback implementation of `isPlainObject` which checks if a given value
10222 * is an object created by the `Object` constructor, assuming objects created
10223 * by the `Object` constructor have no inherited enumerable properties and that
10224 * there are no `Object.prototype` extensions.
10227 * @param {*} value The value to check.
10228 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
10230 function shimIsPlainObject(value) {
10234 // avoid non Object objects, `arguments` objects, and DOM elements
10235 if (!(value && toString.call(value) == objectClass) ||
10236 (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
10239 // In most environments an object's own properties are iterated before
10240 // its inherited properties. If the last iterated property is an object's
10241 // own property then there are no inherited enumerable properties.
10242 forIn(value, function(value, key) {
10245 return typeof result == 'undefined' || hasOwnProperty.call(value, result);
10249 * Used by `unescape` to convert HTML entities to characters.
10252 * @param {string} match The matched character to unescape.
10253 * @returns {string} Returns the unescaped character.
10255 function unescapeHtmlChar(match) {
10256 return htmlUnescapes[match];
10259 /*--------------------------------------------------------------------------*/
10262 * Checks if `value` is an `arguments` object.
10266 * @category Objects
10267 * @param {*} value The value to check.
10268 * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
10271 * (function() { return _.isArguments(arguments); })(1, 2, 3);
10274 * _.isArguments([1, 2, 3]);
10277 function isArguments(value) {
10278 return value && typeof value == 'object' && typeof value.length == 'number' &&
10279 toString.call(value) == argsClass || false;
10283 * Checks if `value` is an array.
10288 * @category Objects
10289 * @param {*} value The value to check.
10290 * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
10293 * (function() { return _.isArray(arguments); })();
10296 * _.isArray([1, 2, 3]);
10299 var isArray = nativeIsArray || function(value) {
10300 return value && typeof value == 'object' && typeof value.length == 'number' &&
10301 toString.call(value) == arrayClass || false;
10305 * A fallback implementation of `Object.keys` which produces an array of the
10306 * given object's own enumerable property names.
10310 * @param {Object} object The object to inspect.
10311 * @returns {Array} Returns an array of property names.
10313 var shimKeys = function(object) {
10314 var index, iterable = object, result = [];
10315 if (!iterable) return result;
10316 if (!(objectTypes[typeof object])) return result;
10317 for (index in iterable) {
10318 if (hasOwnProperty.call(iterable, index)) {
10319 result.push(index);
10326 * Creates an array composed of the own enumerable property names of an object.
10330 * @category Objects
10331 * @param {Object} object The object to inspect.
10332 * @returns {Array} Returns an array of property names.
10335 * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
10336 * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
10338 var keys = !nativeKeys ? shimKeys : function(object) {
10339 if (!isObject(object)) {
10342 return nativeKeys(object);
10346 * Used to convert characters to HTML entities:
10348 * Though the `>` character is escaped for symmetry, characters like `>` and `/`
10349 * don't require escaping in HTML and have no special meaning unless they're part
10350 * of a tag or an unquoted attribute value.
10351 * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
10353 var htmlEscapes = {
10361 /** Used to convert HTML entities to characters */
10362 var htmlUnescapes = invert(htmlEscapes);
10364 /** Used to match HTML entities and HTML characters */
10365 var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
10366 reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
10368 /*--------------------------------------------------------------------------*/
10371 * Assigns own enumerable properties of source object(s) to the destination
10372 * object. Subsequent sources will overwrite property assignments of previous
10373 * sources. If a callback is provided it will be executed to produce the
10374 * assigned values. The callback is bound to `thisArg` and invoked with two
10375 * arguments; (objectValue, sourceValue).
10381 * @category Objects
10382 * @param {Object} object The destination object.
10383 * @param {...Object} [source] The source objects.
10384 * @param {Function} [callback] The function to customize assigning values.
10385 * @param {*} [thisArg] The `this` binding of `callback`.
10386 * @returns {Object} Returns the destination object.
10389 * _.assign({ 'name': 'moe' }, { 'age': 40 });
10390 * // => { 'name': 'moe', 'age': 40 }
10392 * var defaults = _.partialRight(_.assign, function(a, b) {
10393 * return typeof a == 'undefined' ? b : a;
10396 * var food = { 'name': 'apple' };
10397 * defaults(food, { 'name': 'banana', 'type': 'fruit' });
10398 * // => { 'name': 'apple', 'type': 'fruit' }
10400 var assign = function(object, source, guard) {
10401 var index, iterable = object, result = iterable;
10402 if (!iterable) return result;
10403 var args = arguments,
10405 argsLength = typeof guard == 'number' ? 2 : args.length;
10406 if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
10407 var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
10408 } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
10409 callback = args[--argsLength];
10411 while (++argsIndex < argsLength) {
10412 iterable = args[argsIndex];
10413 if (iterable && objectTypes[typeof iterable]) {
10415 ownProps = objectTypes[typeof iterable] && keys(iterable),
10416 length = ownProps ? ownProps.length : 0;
10418 while (++ownIndex < length) {
10419 index = ownProps[ownIndex];
10420 result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
10428 * Creates a clone of `value`. If `deep` is `true` nested objects will also
10429 * be cloned, otherwise they will be assigned by reference. If a callback
10430 * is provided it will be executed to produce the cloned values. If the
10431 * callback returns `undefined` cloning will be handled by the method instead.
10432 * The callback is bound to `thisArg` and invoked with one argument; (value).
10436 * @category Objects
10437 * @param {*} value The value to clone.
10438 * @param {boolean} [deep=false] Specify a deep clone.
10439 * @param {Function} [callback] The function to customize cloning values.
10440 * @param {*} [thisArg] The `this` binding of `callback`.
10441 * @returns {*} Returns the cloned value.
10445 * { 'name': 'moe', 'age': 40 },
10446 * { 'name': 'larry', 'age': 50 }
10449 * var shallow = _.clone(stooges);
10450 * shallow[0] === stooges[0];
10453 * var deep = _.clone(stooges, true);
10454 * deep[0] === stooges[0];
10458 * 'clone': _.partialRight(_.clone, function(value) {
10459 * return _.isElement(value) ? value.cloneNode(false) : undefined;
10463 * var clone = _.clone(document.body);
10464 * clone.childNodes.length;
10467 function clone(value, deep, callback, thisArg) {
10468 // allows working with "Collections" methods without using their `index`
10469 // and `collection` arguments for `deep` and `callback`
10470 if (typeof deep != 'boolean' && deep != null) {
10471 thisArg = callback;
10475 return baseClone(value, deep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
10479 * Creates a deep clone of `value`. If a callback is provided it will be
10480 * executed to produce the cloned values. If the callback returns `undefined`
10481 * cloning will be handled by the method instead. The callback is bound to
10482 * `thisArg` and invoked with one argument; (value).
10484 * Note: This method is loosely based on the structured clone algorithm. Functions
10485 * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
10486 * objects created by constructors other than `Object` are cloned to plain `Object` objects.
10487 * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
10491 * @category Objects
10492 * @param {*} value The value to deep clone.
10493 * @param {Function} [callback] The function to customize cloning values.
10494 * @param {*} [thisArg] The `this` binding of `callback`.
10495 * @returns {*} Returns the deep cloned value.
10499 * { 'name': 'moe', 'age': 40 },
10500 * { 'name': 'larry', 'age': 50 }
10503 * var deep = _.cloneDeep(stooges);
10504 * deep[0] === stooges[0];
10512 * var clone = _.cloneDeep(view, function(value) {
10513 * return _.isElement(value) ? value.cloneNode(true) : undefined;
10516 * clone.node == view.node;
10519 function cloneDeep(value, callback, thisArg) {
10520 return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
10524 * Assigns own enumerable properties of source object(s) to the destination
10525 * object for all destination properties that resolve to `undefined`. Once a
10526 * property is set, additional defaults of the same property will be ignored.
10531 * @category Objects
10532 * @param {Object} object The destination object.
10533 * @param {...Object} [source] The source objects.
10534 * @param- {Object} [guard] Allows working with `_.reduce` without using its
10535 * `key` and `object` arguments as sources.
10536 * @returns {Object} Returns the destination object.
10539 * var food = { 'name': 'apple' };
10540 * _.defaults(food, { 'name': 'banana', 'type': 'fruit' });
10541 * // => { 'name': 'apple', 'type': 'fruit' }
10543 var defaults = function(object, source, guard) {
10544 var index, iterable = object, result = iterable;
10545 if (!iterable) return result;
10546 var args = arguments,
10548 argsLength = typeof guard == 'number' ? 2 : args.length;
10549 while (++argsIndex < argsLength) {
10550 iterable = args[argsIndex];
10551 if (iterable && objectTypes[typeof iterable]) {
10553 ownProps = objectTypes[typeof iterable] && keys(iterable),
10554 length = ownProps ? ownProps.length : 0;
10556 while (++ownIndex < length) {
10557 index = ownProps[ownIndex];
10558 if (typeof result[index] == 'undefined') result[index] = iterable[index];
10566 * This method is like `_.findIndex` except that it returns the key of the
10567 * first element that passes the callback check, instead of the element itself.
10571 * @category Objects
10572 * @param {Object} object The object to search.
10573 * @param {Function|Object|string} [callback=identity] The function called per
10574 * iteration. If a property name or object is provided it will be used to
10575 * create a "_.pluck" or "_.where" style callback, respectively.
10576 * @param {*} [thisArg] The `this` binding of `callback`.
10577 * @returns {string|undefined} Returns the key of the found element, else `undefined`.
10580 * _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
10581 * return num % 2 == 0;
10583 * // => 'b' (property order is not guaranteed across environments)
10585 function findKey(object, callback, thisArg) {
10587 callback = lodash.createCallback(callback, thisArg, 3);
10588 forOwn(object, function(value, key, object) {
10589 if (callback(value, key, object)) {
10598 * This method is like `_.findKey` except that it iterates over elements
10599 * of a `collection` in the opposite order.
10603 * @category Objects
10604 * @param {Object} object The object to search.
10605 * @param {Function|Object|string} [callback=identity] The function called per
10606 * iteration. If a property name or object is provided it will be used to
10607 * create a "_.pluck" or "_.where" style callback, respectively.
10608 * @param {*} [thisArg] The `this` binding of `callback`.
10609 * @returns {string|undefined} Returns the key of the found element, else `undefined`.
10612 * _.findLastKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
10613 * return num % 2 == 1;
10615 * // => returns `c`, assuming `_.findKey` returns `a`
10617 function findLastKey(object, callback, thisArg) {
10619 callback = lodash.createCallback(callback, thisArg, 3);
10620 forOwnRight(object, function(value, key, object) {
10621 if (callback(value, key, object)) {
10630 * Iterates over own and inherited enumerable properties of an object,
10631 * executing the callback for each property. The callback is bound to `thisArg`
10632 * and invoked with three arguments; (value, key, object). Callbacks may exit
10633 * iteration early by explicitly returning `false`.
10638 * @category Objects
10639 * @param {Object} object The object to iterate over.
10640 * @param {Function} [callback=identity] The function called per iteration.
10641 * @param {*} [thisArg] The `this` binding of `callback`.
10642 * @returns {Object} Returns `object`.
10645 * function Dog(name) {
10646 * this.name = name;
10649 * Dog.prototype.bark = function() {
10650 * console.log('Woof, woof!');
10653 * _.forIn(new Dog('Dagny'), function(value, key) {
10654 * console.log(key);
10656 * // => logs 'bark' and 'name' (property order is not guaranteed across environments)
10658 var forIn = function(collection, callback, thisArg) {
10659 var index, iterable = collection, result = iterable;
10660 if (!iterable) return result;
10661 if (!objectTypes[typeof iterable]) return result;
10662 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
10663 for (index in iterable) {
10664 if (callback(iterable[index], index, collection) === false) return result;
10670 * This method is like `_.forIn` except that it iterates over elements
10671 * of a `collection` in the opposite order.
10675 * @category Objects
10676 * @param {Object} object The object to iterate over.
10677 * @param {Function} [callback=identity] The function called per iteration.
10678 * @param {*} [thisArg] The `this` binding of `callback`.
10679 * @returns {Object} Returns `object`.
10682 * function Dog(name) {
10683 * this.name = name;
10686 * Dog.prototype.bark = function() {
10687 * console.log('Woof, woof!');
10690 * _.forInRight(new Dog('Dagny'), function(value, key) {
10691 * console.log(key);
10693 * // => logs 'name' and 'bark' assuming `_.forIn ` logs 'bark' and 'name'
10695 function forInRight(object, callback, thisArg) {
10698 forIn(object, function(value, key) {
10699 pairs.push(key, value);
10702 var length = pairs.length;
10703 callback = baseCreateCallback(callback, thisArg, 3);
10705 if (callback(pairs[length--], pairs[length], object) === false) {
10713 * Iterates over own enumerable properties of an object, executing the callback
10714 * for each property. The callback is bound to `thisArg` and invoked with three
10715 * arguments; (value, key, object). Callbacks may exit iteration early by
10716 * explicitly returning `false`.
10721 * @category Objects
10722 * @param {Object} object The object to iterate over.
10723 * @param {Function} [callback=identity] The function called per iteration.
10724 * @param {*} [thisArg] The `this` binding of `callback`.
10725 * @returns {Object} Returns `object`.
10728 * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
10729 * console.log(key);
10731 * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
10733 var forOwn = function(collection, callback, thisArg) {
10734 var index, iterable = collection, result = iterable;
10735 if (!iterable) return result;
10736 if (!objectTypes[typeof iterable]) return result;
10737 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
10739 ownProps = objectTypes[typeof iterable] && keys(iterable),
10740 length = ownProps ? ownProps.length : 0;
10742 while (++ownIndex < length) {
10743 index = ownProps[ownIndex];
10744 if (callback(iterable[index], index, collection) === false) return result;
10750 * This method is like `_.forOwn` except that it iterates over elements
10751 * of a `collection` in the opposite order.
10755 * @category Objects
10756 * @param {Object} object The object to iterate over.
10757 * @param {Function} [callback=identity] The function called per iteration.
10758 * @param {*} [thisArg] The `this` binding of `callback`.
10759 * @returns {Object} Returns `object`.
10762 * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
10763 * console.log(key);
10765 * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
10767 function forOwnRight(object, callback, thisArg) {
10768 var props = keys(object),
10769 length = props.length;
10771 callback = baseCreateCallback(callback, thisArg, 3);
10773 var key = props[length];
10774 if (callback(object[key], key, object) === false) {
10782 * Creates a sorted array of property names of all enumerable properties,
10783 * own and inherited, of `object` that have function values.
10788 * @category Objects
10789 * @param {Object} object The object to inspect.
10790 * @returns {Array} Returns an array of property names that have function values.
10794 * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
10796 function functions(object) {
10798 forIn(object, function(value, key) {
10799 if (isFunction(value)) {
10803 return result.sort();
10807 * Checks if the specified object `property` exists and is a direct property,
10808 * instead of an inherited property.
10812 * @category Objects
10813 * @param {Object} object The object to check.
10814 * @param {string} property The property to check for.
10815 * @returns {boolean} Returns `true` if key is a direct property, else `false`.
10818 * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
10821 function has(object, property) {
10822 return object ? hasOwnProperty.call(object, property) : false;
10826 * Creates an object composed of the inverted keys and values of the given object.
10830 * @category Objects
10831 * @param {Object} object The object to invert.
10832 * @returns {Object} Returns the created inverted object.
10835 * _.invert({ 'first': 'moe', 'second': 'larry' });
10836 * // => { 'moe': 'first', 'larry': 'second' }
10838 function invert(object) {
10840 props = keys(object),
10841 length = props.length,
10844 while (++index < length) {
10845 var key = props[index];
10846 result[object[key]] = key;
10852 * Checks if `value` is a boolean value.
10856 * @category Objects
10857 * @param {*} value The value to check.
10858 * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
10861 * _.isBoolean(null);
10864 function isBoolean(value) {
10865 return value === true || value === false || toString.call(value) == boolClass;
10869 * Checks if `value` is a date.
10873 * @category Objects
10874 * @param {*} value The value to check.
10875 * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
10878 * _.isDate(new Date);
10881 function isDate(value) {
10882 return value ? (typeof value == 'object' && toString.call(value) == dateClass) : false;
10886 * Checks if `value` is a DOM element.
10890 * @category Objects
10891 * @param {*} value The value to check.
10892 * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
10895 * _.isElement(document.body);
10898 function isElement(value) {
10899 return value ? value.nodeType === 1 : false;
10903 * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
10904 * length of `0` and objects with no own enumerable properties are considered
10909 * @category Objects
10910 * @param {Array|Object|string} value The value to inspect.
10911 * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
10914 * _.isEmpty([1, 2, 3]);
10923 function isEmpty(value) {
10928 var className = toString.call(value),
10929 length = value.length;
10931 if ((className == arrayClass || className == stringClass || className == argsClass ) ||
10932 (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
10935 forOwn(value, function() {
10936 return (result = false);
10942 * Performs a deep comparison between two values to determine if they are
10943 * equivalent to each other. If a callback is provided it will be executed
10944 * to compare values. If the callback returns `undefined` comparisons will
10945 * be handled by the method instead. The callback is bound to `thisArg` and
10946 * invoked with two arguments; (a, b).
10950 * @category Objects
10951 * @param {*} a The value to compare.
10952 * @param {*} b The other value to compare.
10953 * @param {Function} [callback] The function to customize comparing values.
10954 * @param {*} [thisArg] The `this` binding of `callback`.
10955 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
10958 * var moe = { 'name': 'moe', 'age': 40 };
10959 * var copy = { 'name': 'moe', 'age': 40 };
10964 * _.isEqual(moe, copy);
10967 * var words = ['hello', 'goodbye'];
10968 * var otherWords = ['hi', 'goodbye'];
10970 * _.isEqual(words, otherWords, function(a, b) {
10971 * var reGreet = /^(?:hello|hi)$/i,
10972 * aGreet = _.isString(a) && reGreet.test(a),
10973 * bGreet = _.isString(b) && reGreet.test(b);
10975 * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
10979 function isEqual(a, b, callback, thisArg) {
10980 return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
10984 * Checks if `value` is, or can be coerced to, a finite number.
10986 * Note: This is not the same as native `isFinite` which will return true for
10987 * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
10991 * @category Objects
10992 * @param {*} value The value to check.
10993 * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
10996 * _.isFinite(-101);
10999 * _.isFinite('10');
11002 * _.isFinite(true);
11008 * _.isFinite(Infinity);
11011 function isFinite(value) {
11012 return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
11016 * Checks if `value` is a function.
11020 * @category Objects
11021 * @param {*} value The value to check.
11022 * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
11028 function isFunction(value) {
11029 return typeof value == 'function';
11033 * Checks if `value` is the language type of Object.
11034 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
11038 * @category Objects
11039 * @param {*} value The value to check.
11040 * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
11046 * _.isObject([1, 2, 3]);
11052 function isObject(value) {
11053 // check if the value is the ECMAScript language type of Object
11054 // http://es5.github.io/#x8
11055 // and avoid a V8 bug
11056 // http://code.google.com/p/v8/issues/detail?id=2291
11057 return !!(value && objectTypes[typeof value]);
11061 * Checks if `value` is `NaN`.
11063 * Note: This is not the same as native `isNaN` which will return `true` for
11064 * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
11068 * @category Objects
11069 * @param {*} value The value to check.
11070 * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
11076 * _.isNaN(new Number(NaN));
11079 * isNaN(undefined);
11082 * _.isNaN(undefined);
11085 function isNaN(value) {
11086 // `NaN` as a primitive is the only value that is not equal to itself
11087 // (perform the [[Class]] check first to avoid errors with some host objects in IE)
11088 return isNumber(value) && value != +value;
11092 * Checks if `value` is `null`.
11096 * @category Objects
11097 * @param {*} value The value to check.
11098 * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
11104 * _.isNull(undefined);
11107 function isNull(value) {
11108 return value === null;
11112 * Checks if `value` is a number.
11114 * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
11118 * @category Objects
11119 * @param {*} value The value to check.
11120 * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
11123 * _.isNumber(8.4 * 5);
11126 function isNumber(value) {
11127 return typeof value == 'number' || toString.call(value) == numberClass;
11131 * Checks if `value` is an object created by the `Object` constructor.
11135 * @category Objects
11136 * @param {*} value The value to check.
11137 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
11140 * function Stooge(name, age) {
11141 * this.name = name;
11145 * _.isPlainObject(new Stooge('moe', 40));
11148 * _.isPlainObject([1, 2, 3]);
11151 * _.isPlainObject({ 'name': 'moe', 'age': 40 });
11154 var isPlainObject = function(value) {
11155 if (!(value && toString.call(value) == objectClass)) {
11158 var valueOf = value.valueOf,
11159 objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
11162 ? (value == objProto || getPrototypeOf(value) == objProto)
11163 : shimIsPlainObject(value);
11167 * Checks if `value` is a regular expression.
11171 * @category Objects
11172 * @param {*} value The value to check.
11173 * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
11176 * _.isRegExp(/moe/);
11179 function isRegExp(value) {
11180 return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;
11184 * Checks if `value` is a string.
11188 * @category Objects
11189 * @param {*} value The value to check.
11190 * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
11193 * _.isString('moe');
11196 function isString(value) {
11197 return typeof value == 'string' || toString.call(value) == stringClass;
11201 * Checks if `value` is `undefined`.
11205 * @category Objects
11206 * @param {*} value The value to check.
11207 * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
11210 * _.isUndefined(void 0);
11213 function isUndefined(value) {
11214 return typeof value == 'undefined';
11218 * Recursively merges own enumerable properties of the source object(s), that
11219 * don't resolve to `undefined` into the destination object. Subsequent sources
11220 * will overwrite property assignments of previous sources. If a callback is
11221 * provided it will be executed to produce the merged values of the destination
11222 * and source properties. If the callback returns `undefined` merging will
11223 * be handled by the method instead. The callback is bound to `thisArg` and
11224 * invoked with two arguments; (objectValue, sourceValue).
11228 * @category Objects
11229 * @param {Object} object The destination object.
11230 * @param {...Object} [source] The source objects.
11231 * @param {Function} [callback] The function to customize merging properties.
11232 * @param {*} [thisArg] The `this` binding of `callback`.
11233 * @returns {Object} Returns the destination object.
11238 * { 'name': 'moe' },
11239 * { 'name': 'larry' }
11250 * _.merge(names, ages);
11251 * // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] }
11254 * 'fruits': ['apple'],
11255 * 'vegetables': ['beet']
11258 * var otherFood = {
11259 * 'fruits': ['banana'],
11260 * 'vegetables': ['carrot']
11263 * _.merge(food, otherFood, function(a, b) {
11264 * return _.isArray(a) ? a.concat(b) : undefined;
11266 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
11268 function merge(object) {
11269 var args = arguments,
11272 if (!isObject(object)) {
11275 // allows working with `_.reduce` and `_.reduceRight` without using
11276 // their `index` and `collection` arguments
11277 if (typeof args[2] != 'number') {
11278 length = args.length;
11280 if (length > 3 && typeof args[length - 2] == 'function') {
11281 var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
11282 } else if (length > 2 && typeof args[length - 1] == 'function') {
11283 callback = args[--length];
11285 var sources = nativeSlice.call(arguments, 1, length),
11287 stackA = getArray(),
11288 stackB = getArray();
11290 while (++index < length) {
11291 baseMerge(object, sources[index], callback, stackA, stackB);
11293 releaseArray(stackA);
11294 releaseArray(stackB);
11299 * Creates a shallow clone of `object` excluding the specified properties.
11300 * Property names may be specified as individual arguments or as arrays of
11301 * property names. If a callback is provided it will be executed for each
11302 * property of `object` omitting the properties the callback returns truey
11303 * for. The callback is bound to `thisArg` and invoked with three arguments;
11304 * (value, key, object).
11308 * @category Objects
11309 * @param {Object} object The source object.
11310 * @param {Function|...string|string[]} [callback] The properties to omit or the
11311 * function called per iteration.
11312 * @param {*} [thisArg] The `this` binding of `callback`.
11313 * @returns {Object} Returns an object without the omitted properties.
11316 * _.omit({ 'name': 'moe', 'age': 40 }, 'age');
11317 * // => { 'name': 'moe' }
11319 * _.omit({ 'name': 'moe', 'age': 40 }, function(value) {
11320 * return typeof value == 'number';
11322 * // => { 'name': 'moe' }
11324 function omit(object, callback, thisArg) {
11325 var indexOf = getIndexOf(),
11326 isFunc = typeof callback == 'function',
11330 callback = lodash.createCallback(callback, thisArg, 3);
11332 var props = baseFlatten(arguments, true, false, 1);
11334 forIn(object, function(value, key, object) {
11336 ? !callback(value, key, object)
11337 : indexOf(props, key) < 0
11339 result[key] = value;
11346 * Creates a two dimensional array of an object's key-value pairs,
11347 * i.e. `[[key1, value1], [key2, value2]]`.
11351 * @category Objects
11352 * @param {Object} object The object to inspect.
11353 * @returns {Array} Returns new array of key-value pairs.
11356 * _.pairs({ 'moe': 30, 'larry': 40 });
11357 * // => [['moe', 30], ['larry', 40]] (property order is not guaranteed across environments)
11359 function pairs(object) {
11361 props = keys(object),
11362 length = props.length,
11363 result = Array(length);
11365 while (++index < length) {
11366 var key = props[index];
11367 result[index] = [key, object[key]];
11373 * Creates a shallow clone of `object` composed of the specified properties.
11374 * Property names may be specified as individual arguments or as arrays of
11375 * property names. If a callback is provided it will be executed for each
11376 * property of `object` picking the properties the callback returns truey
11377 * for. The callback is bound to `thisArg` and invoked with three arguments;
11378 * (value, key, object).
11382 * @category Objects
11383 * @param {Object} object The source object.
11384 * @param {Function|...string|string[]} [callback] The function called per
11385 * iteration or property names to pick, specified as individual property
11386 * names or arrays of property names.
11387 * @param {*} [thisArg] The `this` binding of `callback`.
11388 * @returns {Object} Returns an object composed of the picked properties.
11391 * _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name');
11392 * // => { 'name': 'moe' }
11394 * _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) {
11395 * return key.charAt(0) != '_';
11397 * // => { 'name': 'moe' }
11399 function pick(object, callback, thisArg) {
11401 if (typeof callback != 'function') {
11403 props = baseFlatten(arguments, true, false, 1),
11404 length = isObject(object) ? props.length : 0;
11406 while (++index < length) {
11407 var key = props[index];
11408 if (key in object) {
11409 result[key] = object[key];
11413 callback = lodash.createCallback(callback, thisArg, 3);
11414 forIn(object, function(value, key, object) {
11415 if (callback(value, key, object)) {
11416 result[key] = value;
11424 * An alternative to `_.reduce` this method transforms `object` to a new
11425 * `accumulator` object which is the result of running each of its elements
11426 * through a callback, with each callback execution potentially mutating
11427 * the `accumulator` object. The callback is bound to `thisArg` and invoked
11428 * with four arguments; (accumulator, value, key, object). Callbacks may exit
11429 * iteration early by explicitly returning `false`.
11433 * @category Objects
11434 * @param {Array|Object} collection The collection to iterate over.
11435 * @param {Function} [callback=identity] The function called per iteration.
11436 * @param {*} [accumulator] The custom accumulator value.
11437 * @param {*} [thisArg] The `this` binding of `callback`.
11438 * @returns {*} Returns the accumulated value.
11441 * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
11444 * return result.push(num) < 3;
11449 * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
11450 * result[key] = num * 3;
11452 * // => { 'a': 3, 'b': 6, 'c': 9 }
11454 function transform(object, callback, accumulator, thisArg) {
11455 var isArr = isArray(object);
11456 callback = baseCreateCallback(callback, thisArg, 4);
11458 if (accumulator == null) {
11462 var ctor = object && object.constructor,
11463 proto = ctor && ctor.prototype;
11465 accumulator = createObject(proto);
11468 (isArr ? forEach : forOwn)(object, function(value, index, object) {
11469 return callback(accumulator, value, index, object);
11471 return accumulator;
11475 * Creates an array composed of the own enumerable property values of `object`.
11479 * @category Objects
11480 * @param {Object} object The object to inspect.
11481 * @returns {Array} Returns an array of property values.
11484 * _.values({ 'one': 1, 'two': 2, 'three': 3 });
11485 * // => [1, 2, 3] (property order is not guaranteed across environments)
11487 function values(object) {
11489 props = keys(object),
11490 length = props.length,
11491 result = Array(length);
11493 while (++index < length) {
11494 result[index] = object[props[index]];
11499 /*--------------------------------------------------------------------------*/
11502 * Creates an array of elements from the specified indexes, or keys, of the
11503 * `collection`. Indexes may be specified as individual arguments or as arrays
11508 * @category Collections
11509 * @param {Array|Object|string} collection The collection to iterate over.
11510 * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
11511 * to retrieve, specified as individual indexes or arrays of indexes.
11512 * @returns {Array} Returns a new array of elements corresponding to the
11513 * provided indexes.
11516 * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
11517 * // => ['a', 'c', 'e']
11519 * _.at(['moe', 'larry', 'curly'], 0, 2);
11520 * // => ['moe', 'curly']
11522 function at(collection) {
11523 var args = arguments,
11525 props = baseFlatten(args, true, false, 1),
11526 length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
11527 result = Array(length);
11529 while(++index < length) {
11530 result[index] = collection[props[index]];
11536 * Checks if a given value is present in a collection using strict equality
11537 * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
11538 * offset from the end of the collection.
11543 * @category Collections
11544 * @param {Array|Object|string} collection The collection to iterate over.
11545 * @param {*} target The value to check for.
11546 * @param {number} [fromIndex=0] The index to search from.
11547 * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
11550 * _.contains([1, 2, 3], 1);
11553 * _.contains([1, 2, 3], 1, 2);
11556 * _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
11559 * _.contains('curly', 'ur');
11562 function contains(collection, target, fromIndex) {
11564 indexOf = getIndexOf(),
11565 length = collection ? collection.length : 0,
11568 fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
11569 if (isArray(collection)) {
11570 result = indexOf(collection, target, fromIndex) > -1;
11571 } else if (typeof length == 'number') {
11572 result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
11574 forOwn(collection, function(value) {
11575 if (++index >= fromIndex) {
11576 return !(result = value === target);
11584 * Creates an object composed of keys generated from the results of running
11585 * each element of `collection` through the callback. The corresponding value
11586 * of each key is the number of times the key was returned by the callback.
11587 * The callback is bound to `thisArg` and invoked with three arguments;
11588 * (value, index|key, collection).
11590 * If a property name is provided for `callback` the created "_.pluck" style
11591 * callback will return the property value of the given element.
11593 * If an object is provided for `callback` the created "_.where" style callback
11594 * will return `true` for elements that have the properties of the given object,
11599 * @category Collections
11600 * @param {Array|Object|string} collection The collection to iterate over.
11601 * @param {Function|Object|string} [callback=identity] The function called
11602 * per iteration. If a property name or object is provided it will be used
11603 * to create a "_.pluck" or "_.where" style callback, respectively.
11604 * @param {*} [thisArg] The `this` binding of `callback`.
11605 * @returns {Object} Returns the composed aggregate object.
11608 * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
11609 * // => { '4': 1, '6': 2 }
11611 * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
11612 * // => { '4': 1, '6': 2 }
11614 * _.countBy(['one', 'two', 'three'], 'length');
11615 * // => { '3': 2, '5': 1 }
11617 var countBy = createAggregator(function(result, value, key) {
11618 (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
11622 * Checks if the given callback returns truey value for **all** elements of
11623 * a collection. The callback is bound to `thisArg` and invoked with three
11624 * arguments; (value, index|key, collection).
11626 * If a property name is provided for `callback` the created "_.pluck" style
11627 * callback will return the property value of the given element.
11629 * If an object is provided for `callback` the created "_.where" style callback
11630 * will return `true` for elements that have the properties of the given object,
11636 * @category Collections
11637 * @param {Array|Object|string} collection The collection to iterate over.
11638 * @param {Function|Object|string} [callback=identity] The function called
11639 * per iteration. If a property name or object is provided it will be used
11640 * to create a "_.pluck" or "_.where" style callback, respectively.
11641 * @param {*} [thisArg] The `this` binding of `callback`.
11642 * @returns {boolean} Returns `true` if all elements passed the callback check,
11646 * _.every([true, 1, null, 'yes'], Boolean);
11650 * { 'name': 'moe', 'age': 40 },
11651 * { 'name': 'larry', 'age': 50 }
11654 * // using "_.pluck" callback shorthand
11655 * _.every(stooges, 'age');
11658 * // using "_.where" callback shorthand
11659 * _.every(stooges, { 'age': 50 });
11662 function every(collection, callback, thisArg) {
11664 callback = lodash.createCallback(callback, thisArg, 3);
11667 length = collection ? collection.length : 0;
11669 if (typeof length == 'number') {
11670 while (++index < length) {
11671 if (!(result = !!callback(collection[index], index, collection))) {
11676 forOwn(collection, function(value, index, collection) {
11677 return (result = !!callback(value, index, collection));
11684 * Iterates over elements of a collection, returning an array of all elements
11685 * the callback returns truey for. The callback is bound to `thisArg` and
11686 * invoked with three arguments; (value, index|key, collection).
11688 * If a property name is provided for `callback` the created "_.pluck" style
11689 * callback will return the property value of the given element.
11691 * If an object is provided for `callback` the created "_.where" style callback
11692 * will return `true` for elements that have the properties of the given object,
11698 * @category Collections
11699 * @param {Array|Object|string} collection The collection to iterate over.
11700 * @param {Function|Object|string} [callback=identity] The function called
11701 * per iteration. If a property name or object is provided it will be used
11702 * to create a "_.pluck" or "_.where" style callback, respectively.
11703 * @param {*} [thisArg] The `this` binding of `callback`.
11704 * @returns {Array} Returns a new array of elements that passed the callback check.
11707 * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
11711 * { 'name': 'apple', 'organic': false, 'type': 'fruit' },
11712 * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
11715 * // using "_.pluck" callback shorthand
11716 * _.filter(food, 'organic');
11717 * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
11719 * // using "_.where" callback shorthand
11720 * _.filter(food, { 'type': 'fruit' });
11721 * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
11723 function filter(collection, callback, thisArg) {
11725 callback = lodash.createCallback(callback, thisArg, 3);
11728 length = collection ? collection.length : 0;
11730 if (typeof length == 'number') {
11731 while (++index < length) {
11732 var value = collection[index];
11733 if (callback(value, index, collection)) {
11734 result.push(value);
11738 forOwn(collection, function(value, index, collection) {
11739 if (callback(value, index, collection)) {
11740 result.push(value);
11748 * Iterates over elements of a collection, returning the first element that
11749 * the callback returns truey for. The callback is bound to `thisArg` and
11750 * invoked with three arguments; (value, index|key, collection).
11752 * If a property name is provided for `callback` the created "_.pluck" style
11753 * callback will return the property value of the given element.
11755 * If an object is provided for `callback` the created "_.where" style callback
11756 * will return `true` for elements that have the properties of the given object,
11761 * @alias detect, findWhere
11762 * @category Collections
11763 * @param {Array|Object|string} collection The collection to iterate over.
11764 * @param {Function|Object|string} [callback=identity] The function called
11765 * per iteration. If a property name or object is provided it will be used
11766 * to create a "_.pluck" or "_.where" style callback, respectively.
11767 * @param {*} [thisArg] The `this` binding of `callback`.
11768 * @returns {*} Returns the found element, else `undefined`.
11771 * _.find([1, 2, 3, 4], function(num) {
11772 * return num % 2 == 0;
11777 * { 'name': 'apple', 'organic': false, 'type': 'fruit' },
11778 * { 'name': 'banana', 'organic': true, 'type': 'fruit' },
11779 * { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
11782 * // using "_.where" callback shorthand
11783 * _.find(food, { 'type': 'vegetable' });
11784 * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
11786 * // using "_.pluck" callback shorthand
11787 * _.find(food, 'organic');
11788 * // => { 'name': 'banana', 'organic': true, 'type': 'fruit' }
11790 function find(collection, callback, thisArg) {
11791 callback = lodash.createCallback(callback, thisArg, 3);
11794 length = collection ? collection.length : 0;
11796 if (typeof length == 'number') {
11797 while (++index < length) {
11798 var value = collection[index];
11799 if (callback(value, index, collection)) {
11805 forOwn(collection, function(value, index, collection) {
11806 if (callback(value, index, collection)) {
11816 * This method is like `_.find` except that it iterates over elements
11817 * of a `collection` from right to left.
11821 * @category Collections
11822 * @param {Array|Object|string} collection The collection to iterate over.
11823 * @param {Function|Object|string} [callback=identity] The function called
11824 * per iteration. If a property name or object is provided it will be used
11825 * to create a "_.pluck" or "_.where" style callback, respectively.
11826 * @param {*} [thisArg] The `this` binding of `callback`.
11827 * @returns {*} Returns the found element, else `undefined`.
11830 * _.findLast([1, 2, 3, 4], function(num) {
11831 * return num % 2 == 1;
11835 function findLast(collection, callback, thisArg) {
11837 callback = lodash.createCallback(callback, thisArg, 3);
11838 forEachRight(collection, function(value, index, collection) {
11839 if (callback(value, index, collection)) {
11848 * Iterates over elements of a collection, executing the callback for each
11849 * element. The callback is bound to `thisArg` and invoked with three arguments;
11850 * (value, index|key, collection). Callbacks may exit iteration early by
11851 * explicitly returning `false`.
11856 * @category Collections
11857 * @param {Array|Object|string} collection The collection to iterate over.
11858 * @param {Function} [callback=identity] The function called per iteration.
11859 * @param {*} [thisArg] The `this` binding of `callback`.
11860 * @returns {Array|Object|string} Returns `collection`.
11863 * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
11864 * // => logs each number and returns '1,2,3'
11866 * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
11867 * // => logs each number and returns the object (property order is not guaranteed across environments)
11869 function forEach(collection, callback, thisArg) {
11871 length = collection ? collection.length : 0;
11873 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
11874 if (typeof length == 'number') {
11875 while (++index < length) {
11876 if (callback(collection[index], index, collection) === false) {
11881 forOwn(collection, callback);
11887 * This method is like `_.forEach` except that it iterates over elements
11888 * of a `collection` from right to left.
11893 * @category Collections
11894 * @param {Array|Object|string} collection The collection to iterate over.
11895 * @param {Function} [callback=identity] The function called per iteration.
11896 * @param {*} [thisArg] The `this` binding of `callback`.
11897 * @returns {Array|Object|string} Returns `collection`.
11900 * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
11901 * // => logs each number from right to left and returns '3,2,1'
11903 function forEachRight(collection, callback, thisArg) {
11904 var length = collection ? collection.length : 0;
11905 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
11906 if (typeof length == 'number') {
11908 if (callback(collection[length], length, collection) === false) {
11913 var props = keys(collection);
11914 length = props.length;
11915 forOwn(collection, function(value, key, collection) {
11916 key = props ? props[--length] : --length;
11917 return callback(collection[key], key, collection);
11924 * Creates an object composed of keys generated from the results of running
11925 * each element of a collection through the callback. The corresponding value
11926 * of each key is an array of the elements responsible for generating the key.
11927 * The callback is bound to `thisArg` and invoked with three arguments;
11928 * (value, index|key, collection).
11930 * If a property name is provided for `callback` the created "_.pluck" style
11931 * callback will return the property value of the given element.
11933 * If an object is provided for `callback` the created "_.where" style callback
11934 * will return `true` for elements that have the properties of the given object,
11939 * @category Collections
11940 * @param {Array|Object|string} collection The collection to iterate over.
11941 * @param {Function|Object|string} [callback=identity] The function called
11942 * per iteration. If a property name or object is provided it will be used
11943 * to create a "_.pluck" or "_.where" style callback, respectively.
11944 * @param {*} [thisArg] The `this` binding of `callback`.
11945 * @returns {Object} Returns the composed aggregate object.
11948 * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
11949 * // => { '4': [4.2], '6': [6.1, 6.4] }
11951 * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
11952 * // => { '4': [4.2], '6': [6.1, 6.4] }
11954 * // using "_.pluck" callback shorthand
11955 * _.groupBy(['one', 'two', 'three'], 'length');
11956 * // => { '3': ['one', 'two'], '5': ['three'] }
11958 var groupBy = createAggregator(function(result, value, key) {
11959 (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
11963 * Creates an object composed of keys generated from the results of running
11964 * each element of the collection through the given callback. The corresponding
11965 * value of each key is the last element responsible for generating the key.
11966 * The callback is bound to `thisArg` and invoked with three arguments;
11967 * (value, index|key, collection).
11969 * If a property name is provided for `callback` the created "_.pluck" style
11970 * callback will return the property value of the given element.
11972 * If an object is provided for `callback` the created "_.where" style callback
11973 * will return `true` for elements that have the properties of the given object,
11978 * @category Collections
11979 * @param {Array|Object|string} collection The collection to iterate over.
11980 * @param {Function|Object|string} [callback=identity] The function called
11981 * per iteration. If a property name or object is provided it will be used
11982 * to create a "_.pluck" or "_.where" style callback, respectively.
11983 * @param {*} [thisArg] The `this` binding of `callback`.
11984 * @returns {Object} Returns the composed aggregate object.
11988 * { 'dir': 'left', 'code': 97 },
11989 * { 'dir': 'right', 'code': 100 }
11992 * _.indexBy(keys, 'dir');
11993 * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
11995 * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
11996 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
11998 * _.indexBy(stooges, function(key) { this.fromCharCode(key.code); }, String);
11999 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
12001 var indexBy = createAggregator(function(result, value, key) {
12002 result[key] = value;
12006 * Invokes the method named by `methodName` on each element in the `collection`
12007 * returning an array of the results of each invoked method. Additional arguments
12008 * will be provided to each invoked method. If `methodName` is a function it
12009 * will be invoked for, and `this` bound to, each element in the `collection`.
12013 * @category Collections
12014 * @param {Array|Object|string} collection The collection to iterate over.
12015 * @param {Function|string} methodName The name of the method to invoke or
12016 * the function invoked per iteration.
12017 * @param {...*} [arg] Arguments to invoke the method with.
12018 * @returns {Array} Returns a new array of the results of each invoked method.
12021 * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
12022 * // => [[1, 5, 7], [1, 2, 3]]
12024 * _.invoke([123, 456], String.prototype.split, '');
12025 * // => [['1', '2', '3'], ['4', '5', '6']]
12027 function invoke(collection, methodName) {
12028 var args = nativeSlice.call(arguments, 2),
12030 isFunc = typeof methodName == 'function',
12031 length = collection ? collection.length : 0,
12032 result = Array(typeof length == 'number' ? length : 0);
12034 forEach(collection, function(value) {
12035 result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
12041 * Creates an array of values by running each element in the collection
12042 * through the callback. The callback is bound to `thisArg` and invoked with
12043 * three arguments; (value, index|key, collection).
12045 * If a property name is provided for `callback` the created "_.pluck" style
12046 * callback will return the property value of the given element.
12048 * If an object is provided for `callback` the created "_.where" style callback
12049 * will return `true` for elements that have the properties of the given object,
12055 * @category Collections
12056 * @param {Array|Object|string} collection The collection to iterate over.
12057 * @param {Function|Object|string} [callback=identity] The function called
12058 * per iteration. If a property name or object is provided it will be used
12059 * to create a "_.pluck" or "_.where" style callback, respectively.
12060 * @param {*} [thisArg] The `this` binding of `callback`.
12061 * @returns {Array} Returns a new array of the results of each `callback` execution.
12064 * _.map([1, 2, 3], function(num) { return num * 3; });
12067 * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
12068 * // => [3, 6, 9] (property order is not guaranteed across environments)
12071 * { 'name': 'moe', 'age': 40 },
12072 * { 'name': 'larry', 'age': 50 }
12075 * // using "_.pluck" callback shorthand
12076 * _.map(stooges, 'name');
12077 * // => ['moe', 'larry']
12079 function map(collection, callback, thisArg) {
12081 length = collection ? collection.length : 0;
12083 callback = lodash.createCallback(callback, thisArg, 3);
12084 if (typeof length == 'number') {
12085 var result = Array(length);
12086 while (++index < length) {
12087 result[index] = callback(collection[index], index, collection);
12091 forOwn(collection, function(value, key, collection) {
12092 result[++index] = callback(value, key, collection);
12099 * Retrieves the maximum value of a collection. If the collection is empty or
12100 * falsey `-Infinity` is returned. If a callback is provided it will be executed
12101 * for each value in the collection to generate the criterion by which the value
12102 * is ranked. The callback is bound to `thisArg` and invoked with three
12103 * arguments; (value, index, collection).
12105 * If a property name is provided for `callback` the created "_.pluck" style
12106 * callback will return the property value of the given element.
12108 * If an object is provided for `callback` the created "_.where" style callback
12109 * will return `true` for elements that have the properties of the given object,
12114 * @category Collections
12115 * @param {Array|Object|string} collection The collection to iterate over.
12116 * @param {Function|Object|string} [callback=identity] The function called
12117 * per iteration. If a property name or object is provided it will be used
12118 * to create a "_.pluck" or "_.where" style callback, respectively.
12119 * @param {*} [thisArg] The `this` binding of `callback`.
12120 * @returns {*} Returns the maximum value.
12123 * _.max([4, 2, 8, 6]);
12127 * { 'name': 'moe', 'age': 40 },
12128 * { 'name': 'larry', 'age': 50 }
12131 * _.max(stooges, function(stooge) { return stooge.age; });
12132 * // => { 'name': 'larry', 'age': 50 };
12134 * // using "_.pluck" callback shorthand
12135 * _.max(stooges, 'age');
12136 * // => { 'name': 'larry', 'age': 50 };
12138 function max(collection, callback, thisArg) {
12139 var computed = -Infinity,
12142 if (!callback && isArray(collection)) {
12144 length = collection.length;
12146 while (++index < length) {
12147 var value = collection[index];
12148 if (value > result) {
12153 callback = (!callback && isString(collection))
12155 : lodash.createCallback(callback, thisArg, 3);
12157 forEach(collection, function(value, index, collection) {
12158 var current = callback(value, index, collection);
12159 if (current > computed) {
12160 computed = current;
12169 * Retrieves the minimum value of a collection. If the collection is empty or
12170 * falsey `Infinity` is returned. If a callback is provided it will be executed
12171 * for each value in the collection to generate the criterion by which the value
12172 * is ranked. The callback is bound to `thisArg` and invoked with three
12173 * arguments; (value, index, collection).
12175 * If a property name is provided for `callback` the created "_.pluck" style
12176 * callback will return the property value of the given element.
12178 * If an object is provided for `callback` the created "_.where" style callback
12179 * will return `true` for elements that have the properties of the given object,
12184 * @category Collections
12185 * @param {Array|Object|string} collection The collection to iterate over.
12186 * @param {Function|Object|string} [callback=identity] The function called
12187 * per iteration. If a property name or object is provided it will be used
12188 * to create a "_.pluck" or "_.where" style callback, respectively.
12189 * @param {*} [thisArg] The `this` binding of `callback`.
12190 * @returns {*} Returns the minimum value.
12193 * _.min([4, 2, 8, 6]);
12197 * { 'name': 'moe', 'age': 40 },
12198 * { 'name': 'larry', 'age': 50 }
12201 * _.min(stooges, function(stooge) { return stooge.age; });
12202 * // => { 'name': 'moe', 'age': 40 };
12204 * // using "_.pluck" callback shorthand
12205 * _.min(stooges, 'age');
12206 * // => { 'name': 'moe', 'age': 40 };
12208 function min(collection, callback, thisArg) {
12209 var computed = Infinity,
12212 if (!callback && isArray(collection)) {
12214 length = collection.length;
12216 while (++index < length) {
12217 var value = collection[index];
12218 if (value < result) {
12223 callback = (!callback && isString(collection))
12225 : lodash.createCallback(callback, thisArg, 3);
12227 forEach(collection, function(value, index, collection) {
12228 var current = callback(value, index, collection);
12229 if (current < computed) {
12230 computed = current;
12239 * Retrieves the value of a specified property from all elements in the `collection`.
12244 * @category Collections
12245 * @param {Array|Object|string} collection The collection to iterate over.
12246 * @param {string} property The property to pluck.
12247 * @returns {Array} Returns a new array of property values.
12251 * { 'name': 'moe', 'age': 40 },
12252 * { 'name': 'larry', 'age': 50 }
12255 * _.pluck(stooges, 'name');
12256 * // => ['moe', 'larry']
12258 function pluck(collection, property) {
12260 length = collection ? collection.length : 0;
12262 if (typeof length == 'number') {
12263 var result = Array(length);
12264 while (++index < length) {
12265 result[index] = collection[index][property];
12268 return result || map(collection, property);
12272 * Reduces a collection to a value which is the accumulated result of running
12273 * each element in the collection through the callback, where each successive
12274 * callback execution consumes the return value of the previous execution. If
12275 * `accumulator` is not provided the first element of the collection will be
12276 * used as the initial `accumulator` value. The callback is bound to `thisArg`
12277 * and invoked with four arguments; (accumulator, value, index|key, collection).
12281 * @alias foldl, inject
12282 * @category Collections
12283 * @param {Array|Object|string} collection The collection to iterate over.
12284 * @param {Function} [callback=identity] The function called per iteration.
12285 * @param {*} [accumulator] Initial value of the accumulator.
12286 * @param {*} [thisArg] The `this` binding of `callback`.
12287 * @returns {*} Returns the accumulated value.
12290 * var sum = _.reduce([1, 2, 3], function(sum, num) {
12291 * return sum + num;
12295 * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
12296 * result[key] = num * 3;
12299 * // => { 'a': 3, 'b': 6, 'c': 9 }
12301 function reduce(collection, callback, accumulator, thisArg) {
12302 if (!collection) return accumulator;
12303 var noaccum = arguments.length < 3;
12304 callback = baseCreateCallback(callback, thisArg, 4);
12307 length = collection.length;
12309 if (typeof length == 'number') {
12311 accumulator = collection[++index];
12313 while (++index < length) {
12314 accumulator = callback(accumulator, collection[index], index, collection);
12317 forOwn(collection, function(value, index, collection) {
12318 accumulator = noaccum
12319 ? (noaccum = false, value)
12320 : callback(accumulator, value, index, collection)
12323 return accumulator;
12327 * This method is like `_.reduce` except that it iterates over elements
12328 * of a `collection` from right to left.
12333 * @category Collections
12334 * @param {Array|Object|string} collection The collection to iterate over.
12335 * @param {Function} [callback=identity] The function called per iteration.
12336 * @param {*} [accumulator] Initial value of the accumulator.
12337 * @param {*} [thisArg] The `this` binding of `callback`.
12338 * @returns {*} Returns the accumulated value.
12341 * var list = [[0, 1], [2, 3], [4, 5]];
12342 * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
12343 * // => [4, 5, 2, 3, 0, 1]
12345 function reduceRight(collection, callback, accumulator, thisArg) {
12346 var noaccum = arguments.length < 3;
12347 callback = baseCreateCallback(callback, thisArg, 4);
12348 forEachRight(collection, function(value, index, collection) {
12349 accumulator = noaccum
12350 ? (noaccum = false, value)
12351 : callback(accumulator, value, index, collection);
12353 return accumulator;
12357 * The opposite of `_.filter` this method returns the elements of a
12358 * collection that the callback does **not** return truey for.
12360 * If a property name is provided for `callback` the created "_.pluck" style
12361 * callback will return the property value of the given element.
12363 * If an object is provided for `callback` the created "_.where" style callback
12364 * will return `true` for elements that have the properties of the given object,
12369 * @category Collections
12370 * @param {Array|Object|string} collection The collection to iterate over.
12371 * @param {Function|Object|string} [callback=identity] The function called
12372 * per iteration. If a property name or object is provided it will be used
12373 * to create a "_.pluck" or "_.where" style callback, respectively.
12374 * @param {*} [thisArg] The `this` binding of `callback`.
12375 * @returns {Array} Returns a new array of elements that failed the callback check.
12378 * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
12382 * { 'name': 'apple', 'organic': false, 'type': 'fruit' },
12383 * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
12386 * // using "_.pluck" callback shorthand
12387 * _.reject(food, 'organic');
12388 * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
12390 * // using "_.where" callback shorthand
12391 * _.reject(food, { 'type': 'fruit' });
12392 * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
12394 function reject(collection, callback, thisArg) {
12395 callback = lodash.createCallback(callback, thisArg, 3);
12396 return filter(collection, function(value, index, collection) {
12397 return !callback(value, index, collection);
12402 * Retrieves a random element or `n` random elements from a collection.
12406 * @category Collections
12407 * @param {Array|Object|string} collection The collection to sample.
12408 * @param {number} [n] The number of elements to sample.
12409 * @param- {Object} [guard] Allows working with functions, like `_.map`,
12410 * without using their `key` and `object` arguments as sources.
12411 * @returns {Array} Returns the random sample(s) of `collection`.
12414 * _.sample([1, 2, 3, 4]);
12417 * _.sample([1, 2, 3, 4], 2);
12420 function sample(collection, n, guard) {
12421 var length = collection ? collection.length : 0;
12422 if (typeof length != 'number') {
12423 collection = values(collection);
12425 if (n == null || guard) {
12426 return collection ? collection[random(length - 1)] : undefined;
12428 var result = shuffle(collection);
12429 result.length = nativeMin(nativeMax(0, n), result.length);
12434 * Creates an array of shuffled values, using a version of the Fisher-Yates
12435 * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
12439 * @category Collections
12440 * @param {Array|Object|string} collection The collection to shuffle.
12441 * @returns {Array} Returns a new shuffled collection.
12444 * _.shuffle([1, 2, 3, 4, 5, 6]);
12445 * // => [4, 1, 6, 3, 5, 2]
12447 function shuffle(collection) {
12449 length = collection ? collection.length : 0,
12450 result = Array(typeof length == 'number' ? length : 0);
12452 forEach(collection, function(value) {
12453 var rand = random(++index);
12454 result[index] = result[rand];
12455 result[rand] = value;
12461 * Gets the size of the `collection` by returning `collection.length` for arrays
12462 * and array-like objects or the number of own enumerable properties for objects.
12466 * @category Collections
12467 * @param {Array|Object|string} collection The collection to inspect.
12468 * @returns {number} Returns `collection.length` or number of own enumerable properties.
12474 * _.size({ 'one': 1, 'two': 2, 'three': 3 });
12480 function size(collection) {
12481 var length = collection ? collection.length : 0;
12482 return typeof length == 'number' ? length : keys(collection).length;
12486 * Checks if the callback returns a truey value for **any** element of a
12487 * collection. The function returns as soon as it finds a passing value and
12488 * does not iterate over the entire collection. The callback is bound to
12489 * `thisArg` and invoked with three arguments; (value, index|key, collection).
12491 * If a property name is provided for `callback` the created "_.pluck" style
12492 * callback will return the property value of the given element.
12494 * If an object is provided for `callback` the created "_.where" style callback
12495 * will return `true` for elements that have the properties of the given object,
12501 * @category Collections
12502 * @param {Array|Object|string} collection The collection to iterate over.
12503 * @param {Function|Object|string} [callback=identity] The function called
12504 * per iteration. If a property name or object is provided it will be used
12505 * to create a "_.pluck" or "_.where" style callback, respectively.
12506 * @param {*} [thisArg] The `this` binding of `callback`.
12507 * @returns {boolean} Returns `true` if any element passed the callback check,
12511 * _.some([null, 0, 'yes', false], Boolean);
12515 * { 'name': 'apple', 'organic': false, 'type': 'fruit' },
12516 * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
12519 * // using "_.pluck" callback shorthand
12520 * _.some(food, 'organic');
12523 * // using "_.where" callback shorthand
12524 * _.some(food, { 'type': 'meat' });
12527 function some(collection, callback, thisArg) {
12529 callback = lodash.createCallback(callback, thisArg, 3);
12532 length = collection ? collection.length : 0;
12534 if (typeof length == 'number') {
12535 while (++index < length) {
12536 if ((result = callback(collection[index], index, collection))) {
12541 forOwn(collection, function(value, index, collection) {
12542 return !(result = callback(value, index, collection));
12549 * Creates an array of elements, sorted in ascending order by the results of
12550 * running each element in a collection through the callback. This method
12551 * performs a stable sort, that is, it will preserve the original sort order
12552 * of equal elements. The callback is bound to `thisArg` and invoked with
12553 * three arguments; (value, index|key, collection).
12555 * If a property name is provided for `callback` the created "_.pluck" style
12556 * callback will return the property value of the given element.
12558 * If an object is provided for `callback` the created "_.where" style callback
12559 * will return `true` for elements that have the properties of the given object,
12564 * @category Collections
12565 * @param {Array|Object|string} collection The collection to iterate over.
12566 * @param {Function|Object|string} [callback=identity] The function called
12567 * per iteration. If a property name or object is provided it will be used
12568 * to create a "_.pluck" or "_.where" style callback, respectively.
12569 * @param {*} [thisArg] The `this` binding of `callback`.
12570 * @returns {Array} Returns a new array of sorted elements.
12573 * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
12576 * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
12579 * // using "_.pluck" callback shorthand
12580 * _.sortBy(['banana', 'strawberry', 'apple'], 'length');
12581 * // => ['apple', 'banana', 'strawberry']
12583 function sortBy(collection, callback, thisArg) {
12585 length = collection ? collection.length : 0,
12586 result = Array(typeof length == 'number' ? length : 0);
12588 callback = lodash.createCallback(callback, thisArg, 3);
12589 forEach(collection, function(value, key, collection) {
12590 var object = result[++index] = getObject();
12591 object.criteria = callback(value, key, collection);
12592 object.index = index;
12593 object.value = value;
12596 length = result.length;
12597 result.sort(compareAscending);
12599 var object = result[length];
12600 result[length] = object.value;
12601 releaseObject(object);
12607 * Converts the `collection` to an array.
12611 * @category Collections
12612 * @param {Array|Object|string} collection The collection to convert.
12613 * @returns {Array} Returns the new converted array.
12616 * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
12619 function toArray(collection) {
12620 if (collection && typeof collection.length == 'number') {
12621 return slice(collection);
12623 return values(collection);
12627 * Performs a deep comparison of each element in a `collection` to the given
12628 * `properties` object, returning an array of all elements that have equivalent
12634 * @category Collections
12635 * @param {Array|Object|string} collection The collection to iterate over.
12636 * @param {Object} properties The object of property values to filter by.
12637 * @returns {Array} Returns a new array of elements that have the given properties.
12641 * { 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] },
12642 * { 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] }
12645 * _.where(stooges, { 'age': 40 });
12646 * // => [{ 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] }]
12648 * _.where(stooges, { 'quotes': ['Poifect!'] });
12649 * // => [{ 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }]
12651 var where = filter;
12653 /*--------------------------------------------------------------------------*/
12656 * Creates an array with all falsey values removed. The values `false`, `null`,
12657 * `0`, `""`, `undefined`, and `NaN` are all falsey.
12662 * @param {Array} array The array to compact.
12663 * @returns {Array} Returns a new array of filtered values.
12666 * _.compact([0, 1, false, 2, '', 3]);
12669 function compact(array) {
12671 length = array ? array.length : 0,
12674 while (++index < length) {
12675 var value = array[index];
12677 result.push(value);
12684 * Creates an array excluding all values of the provided arrays using strict
12685 * equality for comparisons, i.e. `===`.
12690 * @param {Array} array The array to process.
12691 * @param {...Array} [array] The arrays of values to exclude.
12692 * @returns {Array} Returns a new array of filtered values.
12695 * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
12698 function difference(array) {
12700 indexOf = getIndexOf(),
12701 length = array ? array.length : 0,
12702 seen = baseFlatten(arguments, true, true, 1),
12705 var isLarge = length >= largeArraySize && indexOf === baseIndexOf;
12708 var cache = createCache(seen);
12710 indexOf = cacheIndexOf;
12716 while (++index < length) {
12717 var value = array[index];
12718 if (indexOf(seen, value) < 0) {
12719 result.push(value);
12723 releaseObject(seen);
12729 * This method is like `_.find` except that it returns the index of the first
12730 * element that passes the callback check, instead of the element itself.
12735 * @param {Array} array The array to search.
12736 * @param {Function|Object|string} [callback=identity] The function called
12737 * per iteration. If a property name or object is provided it will be used
12738 * to create a "_.pluck" or "_.where" style callback, respectively.
12739 * @param {*} [thisArg] The `this` binding of `callback`.
12740 * @returns {number} Returns the index of the found element, else `-1`.
12743 * _.findIndex(['apple', 'banana', 'beet'], function(food) {
12744 * return /^b/.test(food);
12748 function findIndex(array, callback, thisArg) {
12750 length = array ? array.length : 0;
12752 callback = lodash.createCallback(callback, thisArg, 3);
12753 while (++index < length) {
12754 if (callback(array[index], index, array)) {
12762 * This method is like `_.findIndex` except that it iterates over elements
12763 * of a `collection` from right to left.
12768 * @param {Array} array The array to search.
12769 * @param {Function|Object|string} [callback=identity] The function called
12770 * per iteration. If a property name or object is provided it will be used
12771 * to create a "_.pluck" or "_.where" style callback, respectively.
12772 * @param {*} [thisArg] The `this` binding of `callback`.
12773 * @returns {number} Returns the index of the found element, else `-1`.
12776 * _.findLastIndex(['apple', 'banana', 'beet'], function(food) {
12777 * return /^b/.test(food);
12781 function findLastIndex(array, callback, thisArg) {
12782 var length = array ? array.length : 0;
12783 callback = lodash.createCallback(callback, thisArg, 3);
12785 if (callback(array[length], length, array)) {
12793 * Gets the first element or first `n` elements of an array. If a callback
12794 * is provided elements at the beginning of the array are returned as long
12795 * as the callback returns truey. The callback is bound to `thisArg` and
12796 * invoked with three arguments; (value, index, array).
12798 * If a property name is provided for `callback` the created "_.pluck" style
12799 * callback will return the property value of the given element.
12801 * If an object is provided for `callback` the created "_.where" style callback
12802 * will return `true` for elements that have the properties of the given object,
12807 * @alias head, take
12809 * @param {Array} array The array to query.
12810 * @param {Function|Object|number|string} [callback] The function called
12811 * per element or the number of elements to return. If a property name or
12812 * object is provided it will be used to create a "_.pluck" or "_.where"
12813 * style callback, respectively.
12814 * @param {*} [thisArg] The `this` binding of `callback`.
12815 * @returns {*} Returns the first element(s) of `array`.
12818 * _.first([1, 2, 3]);
12821 * _.first([1, 2, 3], 2);
12824 * _.first([1, 2, 3], function(num) {
12830 * { 'name': 'banana', 'organic': true },
12831 * { 'name': 'beet', 'organic': false },
12834 * // using "_.pluck" callback shorthand
12835 * _.first(food, 'organic');
12836 * // => [{ 'name': 'banana', 'organic': true }]
12839 * { 'name': 'apple', 'type': 'fruit' },
12840 * { 'name': 'banana', 'type': 'fruit' },
12841 * { 'name': 'beet', 'type': 'vegetable' }
12844 * // using "_.where" callback shorthand
12845 * _.first(food, { 'type': 'fruit' });
12846 * // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }]
12848 function first(array, callback, thisArg) {
12850 length = array ? array.length : 0;
12852 if (typeof callback != 'number' && callback != null) {
12854 callback = lodash.createCallback(callback, thisArg, 3);
12855 while (++index < length && callback(array[index], index, array)) {
12860 if (n == null || thisArg) {
12861 return array ? array[0] : undefined;
12864 return slice(array, 0, nativeMin(nativeMax(0, n), length));
12868 * Flattens a nested array (the nesting can be to any depth). If `isShallow`
12869 * is truey, the array will only be flattened a single level. If a callback
12870 * is provided each element of the array is passed through the callback before
12871 * flattening. The callback is bound to `thisArg` and invoked with three
12872 * arguments; (value, index, array).
12874 * If a property name is provided for `callback` the created "_.pluck" style
12875 * callback will return the property value of the given element.
12877 * If an object is provided for `callback` the created "_.where" style callback
12878 * will return `true` for elements that have the properties of the given object,
12884 * @param {Array} array The array to flatten.
12885 * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
12886 * @param {Function|Object|string} [callback=identity] The function called
12887 * per iteration. If a property name or object is provided it will be used
12888 * to create a "_.pluck" or "_.where" style callback, respectively.
12889 * @param {*} [thisArg] The `this` binding of `callback`.
12890 * @returns {Array} Returns a new flattened array.
12893 * _.flatten([1, [2], [3, [[4]]]]);
12894 * // => [1, 2, 3, 4];
12896 * _.flatten([1, [2], [3, [[4]]]], true);
12897 * // => [1, 2, 3, [[4]]];
12900 * { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] },
12901 * { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] }
12904 * // using "_.pluck" callback shorthand
12905 * _.flatten(stooges, 'quotes');
12906 * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!']
12908 function flatten(array, isShallow, callback, thisArg) {
12909 // juggle arguments
12910 if (typeof isShallow != 'boolean' && isShallow != null) {
12911 thisArg = callback;
12912 callback = !(thisArg && thisArg[isShallow] === array) ? isShallow : null;
12915 if (callback != null) {
12916 array = map(array, callback, thisArg);
12918 return baseFlatten(array, isShallow);
12922 * Gets the index at which the first occurrence of `value` is found using
12923 * strict equality for comparisons, i.e. `===`. If the array is already sorted
12924 * providing `true` for `fromIndex` will run a faster binary search.
12929 * @param {Array} array The array to search.
12930 * @param {*} value The value to search for.
12931 * @param {boolean|number} [fromIndex=0] The index to search from or `true`
12932 * to perform a binary search on a sorted array.
12933 * @returns {number} Returns the index of the matched value or `-1`.
12936 * _.indexOf([1, 2, 3, 1, 2, 3], 2);
12939 * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
12942 * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
12945 function indexOf(array, value, fromIndex) {
12946 if (typeof fromIndex == 'number') {
12947 var length = array ? array.length : 0;
12948 fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
12949 } else if (fromIndex) {
12950 var index = sortedIndex(array, value);
12951 return array[index] === value ? index : -1;
12953 return baseIndexOf(array, value, fromIndex);
12957 * Gets all but the last element or last `n` elements of an array. If a
12958 * callback is provided elements at the end of the array are excluded from
12959 * the result as long as the callback returns truey. The callback is bound
12960 * to `thisArg` and invoked with three arguments; (value, index, array).
12962 * If a property name is provided for `callback` the created "_.pluck" style
12963 * callback will return the property value of the given element.
12965 * If an object is provided for `callback` the created "_.where" style callback
12966 * will return `true` for elements that have the properties of the given object,
12972 * @param {Array} array The array to query.
12973 * @param {Function|Object|number|string} [callback=1] The function called
12974 * per element or the number of elements to exclude. If a property name or
12975 * object is provided it will be used to create a "_.pluck" or "_.where"
12976 * style callback, respectively.
12977 * @param {*} [thisArg] The `this` binding of `callback`.
12978 * @returns {Array} Returns a slice of `array`.
12981 * _.initial([1, 2, 3]);
12984 * _.initial([1, 2, 3], 2);
12987 * _.initial([1, 2, 3], function(num) {
12993 * { 'name': 'beet', 'organic': false },
12994 * { 'name': 'carrot', 'organic': true }
12997 * // using "_.pluck" callback shorthand
12998 * _.initial(food, 'organic');
12999 * // => [{ 'name': 'beet', 'organic': false }]
13002 * { 'name': 'banana', 'type': 'fruit' },
13003 * { 'name': 'beet', 'type': 'vegetable' },
13004 * { 'name': 'carrot', 'type': 'vegetable' }
13007 * // using "_.where" callback shorthand
13008 * _.initial(food, { 'type': 'vegetable' });
13009 * // => [{ 'name': 'banana', 'type': 'fruit' }]
13011 function initial(array, callback, thisArg) {
13013 length = array ? array.length : 0;
13015 if (typeof callback != 'number' && callback != null) {
13016 var index = length;
13017 callback = lodash.createCallback(callback, thisArg, 3);
13018 while (index-- && callback(array[index], index, array)) {
13022 n = (callback == null || thisArg) ? 1 : callback || n;
13024 return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
13028 * Creates an array of unique values present in all provided arrays using
13029 * strict equality for comparisons, i.e. `===`.
13034 * @param {...Array} [array] The arrays to inspect.
13035 * @returns {Array} Returns an array of composite values.
13038 * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
13041 function intersection(array) {
13042 var args = arguments,
13043 argsLength = args.length,
13045 caches = getArray(),
13047 indexOf = getIndexOf(),
13048 length = array ? array.length : 0,
13052 while (++argsIndex < argsLength) {
13053 var value = args[argsIndex];
13054 caches[argsIndex] = indexOf === baseIndexOf &&
13055 (value ? value.length : 0) >= largeArraySize &&
13056 createCache(argsIndex ? args[argsIndex] : seen);
13059 while (++index < length) {
13060 var cache = caches[0];
13061 value = array[index];
13063 if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
13064 argsIndex = argsLength;
13065 (cache || seen).push(value);
13066 while (--argsIndex) {
13067 cache = caches[argsIndex];
13068 if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
13072 result.push(value);
13075 while (argsLength--) {
13076 cache = caches[argsLength];
13078 releaseObject(cache);
13081 releaseArray(caches);
13082 releaseArray(seen);
13087 * Gets the last element or last `n` elements of an array. If a callback is
13088 * provided elements at the end of the array are returned as long as the
13089 * callback returns truey. The callback is bound to `thisArg` and invoked
13090 * with three arguments; (value, index, array).
13092 * If a property name is provided for `callback` the created "_.pluck" style
13093 * callback will return the property value of the given element.
13095 * If an object is provided for `callback` the created "_.where" style callback
13096 * will return `true` for elements that have the properties of the given object,
13102 * @param {Array} array The array to query.
13103 * @param {Function|Object|number|string} [callback] The function called
13104 * per element or the number of elements to return. If a property name or
13105 * object is provided it will be used to create a "_.pluck" or "_.where"
13106 * style callback, respectively.
13107 * @param {*} [thisArg] The `this` binding of `callback`.
13108 * @returns {*} Returns the last element(s) of `array`.
13111 * _.last([1, 2, 3]);
13114 * _.last([1, 2, 3], 2);
13117 * _.last([1, 2, 3], function(num) {
13123 * { 'name': 'beet', 'organic': false },
13124 * { 'name': 'carrot', 'organic': true }
13127 * // using "_.pluck" callback shorthand
13128 * _.last(food, 'organic');
13129 * // => [{ 'name': 'carrot', 'organic': true }]
13132 * { 'name': 'banana', 'type': 'fruit' },
13133 * { 'name': 'beet', 'type': 'vegetable' },
13134 * { 'name': 'carrot', 'type': 'vegetable' }
13137 * // using "_.where" callback shorthand
13138 * _.last(food, { 'type': 'vegetable' });
13139 * // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }]
13141 function last(array, callback, thisArg) {
13143 length = array ? array.length : 0;
13145 if (typeof callback != 'number' && callback != null) {
13146 var index = length;
13147 callback = lodash.createCallback(callback, thisArg, 3);
13148 while (index-- && callback(array[index], index, array)) {
13153 if (n == null || thisArg) {
13154 return array ? array[length - 1] : undefined;
13157 return slice(array, nativeMax(0, length - n));
13161 * Gets the index at which the last occurrence of `value` is found using strict
13162 * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
13163 * as the offset from the end of the collection.
13168 * @param {Array} array The array to search.
13169 * @param {*} value The value to search for.
13170 * @param {number} [fromIndex=array.length-1] The index to search from.
13171 * @returns {number} Returns the index of the matched value or `-1`.
13174 * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
13177 * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
13180 function lastIndexOf(array, value, fromIndex) {
13181 var index = array ? array.length : 0;
13182 if (typeof fromIndex == 'number') {
13183 index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
13186 if (array[index] === value) {
13194 * Removes all provided values from the given array using strict equality for
13195 * comparisons, i.e. `===`.
13200 * @param {Array} array The array to modify.
13201 * @param {...*} [value] The values to remove.
13202 * @returns {Array} Returns `array`.
13205 * var array = [1, 2, 3, 1, 2, 3];
13206 * _.pull(array, 2, 3);
13207 * console.log(array);
13210 function pull(array) {
13211 var args = arguments,
13213 argsLength = args.length,
13214 length = array ? array.length : 0;
13216 while (++argsIndex < argsLength) {
13218 value = args[argsIndex];
13219 while (++index < length) {
13220 if (array[index] === value) {
13221 splice.call(array, index--, 1);
13230 * Creates an array of numbers (positive and/or negative) progressing from
13231 * `start` up to but not including `end`. If `start` is less than `stop` a
13232 * zero-length range is created unless a negative `step` is specified.
13237 * @param {number} [start=0] The start of the range.
13238 * @param {number} end The end of the range.
13239 * @param {number} [step=1] The value to increment or decrement by.
13240 * @returns {Array} Returns a new range array.
13244 * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
13247 * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
13249 * _.range(0, 30, 5);
13250 * // => [0, 5, 10, 15, 20, 25]
13252 * _.range(0, -10, -1);
13253 * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
13255 * _.range(1, 4, 0);
13261 function range(start, end, step) {
13262 start = +start || 0;
13263 step = typeof step == 'number' ? step : (+step || 1);
13269 // use `Array(length)` so engines, like Chakra and V8, avoid slower modes
13270 // http://youtu.be/XAqIpGU8ZZk#t=17m25s
13272 length = nativeMax(0, ceil((end - start) / (step || 1))),
13273 result = Array(length);
13275 while (++index < length) {
13276 result[index] = start;
13283 * Removes all elements from an array that the callback returns truey for
13284 * and returns an array of removed elements. The callback is bound to `thisArg`
13285 * and invoked with three arguments; (value, index, array).
13287 * If a property name is provided for `callback` the created "_.pluck" style
13288 * callback will return the property value of the given element.
13290 * If an object is provided for `callback` the created "_.where" style callback
13291 * will return `true` for elements that have the properties of the given object,
13297 * @param {Array} array The array to modify.
13298 * @param {Function|Object|string} [callback=identity] The function called
13299 * per iteration. If a property name or object is provided it will be used
13300 * to create a "_.pluck" or "_.where" style callback, respectively.
13301 * @param {*} [thisArg] The `this` binding of `callback`.
13302 * @returns {Array} Returns a new array of removed elements.
13305 * var array = [1, 2, 3, 4, 5, 6];
13306 * var evens = _.remove(array, function(num) { return num % 2 == 0; });
13308 * console.log(array);
13311 * console.log(evens);
13314 function remove(array, callback, thisArg) {
13316 length = array ? array.length : 0,
13319 callback = lodash.createCallback(callback, thisArg, 3);
13320 while (++index < length) {
13321 var value = array[index];
13322 if (callback(value, index, array)) {
13323 result.push(value);
13324 splice.call(array, index--, 1);
13332 * The opposite of `_.initial` this method gets all but the first element or
13333 * first `n` elements of an array. If a callback function is provided elements
13334 * at the beginning of the array are excluded from the result as long as the
13335 * callback returns truey. The callback is bound to `thisArg` and invoked
13336 * with three arguments; (value, index, array).
13338 * If a property name is provided for `callback` the created "_.pluck" style
13339 * callback will return the property value of the given element.
13341 * If an object is provided for `callback` the created "_.where" style callback
13342 * will return `true` for elements that have the properties of the given object,
13347 * @alias drop, tail
13349 * @param {Array} array The array to query.
13350 * @param {Function|Object|number|string} [callback=1] The function called
13351 * per element or the number of elements to exclude. If a property name or
13352 * object is provided it will be used to create a "_.pluck" or "_.where"
13353 * style callback, respectively.
13354 * @param {*} [thisArg] The `this` binding of `callback`.
13355 * @returns {Array} Returns a slice of `array`.
13358 * _.rest([1, 2, 3]);
13361 * _.rest([1, 2, 3], 2);
13364 * _.rest([1, 2, 3], function(num) {
13370 * { 'name': 'banana', 'organic': true },
13371 * { 'name': 'beet', 'organic': false },
13374 * // using "_.pluck" callback shorthand
13375 * _.rest(food, 'organic');
13376 * // => [{ 'name': 'beet', 'organic': false }]
13379 * { 'name': 'apple', 'type': 'fruit' },
13380 * { 'name': 'banana', 'type': 'fruit' },
13381 * { 'name': 'beet', 'type': 'vegetable' }
13384 * // using "_.where" callback shorthand
13385 * _.rest(food, { 'type': 'fruit' });
13386 * // => [{ 'name': 'beet', 'type': 'vegetable' }]
13388 function rest(array, callback, thisArg) {
13389 if (typeof callback != 'number' && callback != null) {
13392 length = array ? array.length : 0;
13394 callback = lodash.createCallback(callback, thisArg, 3);
13395 while (++index < length && callback(array[index], index, array)) {
13399 n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
13401 return slice(array, n);
13405 * Uses a binary search to determine the smallest index at which a value
13406 * should be inserted into a given sorted array in order to maintain the sort
13407 * order of the array. If a callback is provided it will be executed for
13408 * `value` and each element of `array` to compute their sort ranking. The
13409 * callback is bound to `thisArg` and invoked with one argument; (value).
13411 * If a property name is provided for `callback` the created "_.pluck" style
13412 * callback will return the property value of the given element.
13414 * If an object is provided for `callback` the created "_.where" style callback
13415 * will return `true` for elements that have the properties of the given object,
13421 * @param {Array} array The array to inspect.
13422 * @param {*} value The value to evaluate.
13423 * @param {Function|Object|string} [callback=identity] The function called
13424 * per iteration. If a property name or object is provided it will be used
13425 * to create a "_.pluck" or "_.where" style callback, respectively.
13426 * @param {*} [thisArg] The `this` binding of `callback`.
13427 * @returns {number} Returns the index at which `value` should be inserted
13431 * _.sortedIndex([20, 30, 50], 40);
13434 * // using "_.pluck" callback shorthand
13435 * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
13439 * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
13442 * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
13443 * return dict.wordToNumber[word];
13447 * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
13448 * return this.wordToNumber[word];
13452 function sortedIndex(array, value, callback, thisArg) {
13454 high = array ? array.length : low;
13456 // explicitly reference `identity` for better inlining in Firefox
13457 callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
13458 value = callback(value);
13460 while (low < high) {
13461 var mid = (low + high) >>> 1;
13462 (callback(array[mid]) < value)
13470 * Creates an array of unique values, in order, of the provided arrays using
13471 * strict equality for comparisons, i.e. `===`.
13476 * @param {...Array} [array] The arrays to inspect.
13477 * @returns {Array} Returns an array of composite values.
13480 * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
13481 * // => [1, 2, 3, 101, 10]
13483 function union(array) {
13484 return baseUniq(baseFlatten(arguments, true, true));
13488 * Creates a duplicate-value-free version of an array using strict equality
13489 * for comparisons, i.e. `===`. If the array is sorted, providing
13490 * `true` for `isSorted` will use a faster algorithm. If a callback is provided
13491 * each element of `array` is passed through the callback before uniqueness
13492 * is computed. The callback is bound to `thisArg` and invoked with three
13493 * arguments; (value, index, array).
13495 * If a property name is provided for `callback` the created "_.pluck" style
13496 * callback will return the property value of the given element.
13498 * If an object is provided for `callback` the created "_.where" style callback
13499 * will return `true` for elements that have the properties of the given object,
13506 * @param {Array} array The array to process.
13507 * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
13508 * @param {Function|Object|string} [callback=identity] The function called
13509 * per iteration. If a property name or object is provided it will be used
13510 * to create a "_.pluck" or "_.where" style callback, respectively.
13511 * @param {*} [thisArg] The `this` binding of `callback`.
13512 * @returns {Array} Returns a duplicate-value-free array.
13515 * _.uniq([1, 2, 1, 3, 1]);
13518 * _.uniq([1, 1, 2, 2, 3], true);
13521 * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
13522 * // => ['A', 'b', 'C']
13524 * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
13525 * // => [1, 2.5, 3]
13527 * // using "_.pluck" callback shorthand
13528 * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
13529 * // => [{ 'x': 1 }, { 'x': 2 }]
13531 function uniq(array, isSorted, callback, thisArg) {
13532 // juggle arguments
13533 if (typeof isSorted != 'boolean' && isSorted != null) {
13534 thisArg = callback;
13535 callback = !(thisArg && thisArg[isSorted] === array) ? isSorted : null;
13538 if (callback != null) {
13539 callback = lodash.createCallback(callback, thisArg, 3);
13541 return baseUniq(array, isSorted, callback);
13545 * Creates an array excluding all provided values using strict equality for
13546 * comparisons, i.e. `===`.
13551 * @param {Array} array The array to filter.
13552 * @param {...*} [value] The values to exclude.
13553 * @returns {Array} Returns a new array of filtered values.
13556 * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
13559 function without(array) {
13560 return difference(array, nativeSlice.call(arguments, 1));
13564 * Creates an array of grouped elements, the first of which contains the first
13565 * elements of the given arrays, the second of which contains the second
13566 * elements of the given arrays, and so on.
13572 * @param {...Array} [array] Arrays to process.
13573 * @returns {Array} Returns a new array of grouped elements.
13576 * _.zip(['moe', 'larry'], [30, 40], [true, false]);
13577 * // => [['moe', 30, true], ['larry', 40, false]]
13580 var array = arguments.length > 1 ? arguments : arguments[0],
13582 length = array ? max(pluck(array, 'length')) : 0,
13583 result = Array(length < 0 ? 0 : length);
13585 while (++index < length) {
13586 result[index] = pluck(array, index);
13592 * Creates an object composed from arrays of `keys` and `values`. Provide
13593 * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
13594 * or two arrays, one of `keys` and one of corresponding `values`.
13600 * @param {Array} keys The array of keys.
13601 * @param {Array} [values=[]] The array of values.
13602 * @returns {Object} Returns an object composed of the given keys and
13603 * corresponding values.
13606 * _.zipObject(['moe', 'larry'], [30, 40]);
13607 * // => { 'moe': 30, 'larry': 40 }
13609 function zipObject(keys, values) {
13611 length = keys ? keys.length : 0,
13614 while (++index < length) {
13615 var key = keys[index];
13617 result[key] = values[index];
13619 result[key[0]] = key[1];
13625 /*--------------------------------------------------------------------------*/
13628 * Creates a function that executes `func`, with the `this` binding and
13629 * arguments of the created function, only after being called `n` times.
13633 * @category Functions
13634 * @param {number} n The number of times the function must be called before
13635 * `func` is executed.
13636 * @param {Function} func The function to restrict.
13637 * @returns {Function} Returns the new restricted function.
13640 * var saves = ['profile', 'settings'];
13642 * var done = _.after(saves.length, function() {
13643 * console.log('Done saving!');
13646 * _.forEach(saves, function(type) {
13647 * asyncSave({ 'type': type, 'complete': done });
13649 * // => logs 'Done saving!', after all saves have completed
13651 function after(n, func) {
13652 if (!isFunction(func)) {
13653 throw new TypeError;
13655 return function() {
13657 return func.apply(this, arguments);
13663 * Creates a function that, when called, invokes `func` with the `this`
13664 * binding of `thisArg` and prepends any additional `bind` arguments to those
13665 * provided to the bound function.
13669 * @category Functions
13670 * @param {Function} func The function to bind.
13671 * @param {*} [thisArg] The `this` binding of `func`.
13672 * @param {...*} [arg] Arguments to be partially applied.
13673 * @returns {Function} Returns the new bound function.
13676 * var func = function(greeting) {
13677 * return greeting + ' ' + this.name;
13680 * func = _.bind(func, { 'name': 'moe' }, 'hi');
13684 function bind(func, thisArg) {
13685 return arguments.length > 2
13686 ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg)
13687 : createBound(func, 1, null, null, thisArg);
13691 * Binds methods of an object to the object itself, overwriting the existing
13692 * method. Method names may be specified as individual arguments or as arrays
13693 * of method names. If no method names are provided all the function properties
13694 * of `object` will be bound.
13698 * @category Functions
13699 * @param {Object} object The object to bind and assign the bound methods to.
13700 * @param {...string} [methodName] The object method names to
13701 * bind, specified as individual method names or arrays of method names.
13702 * @returns {Object} Returns `object`.
13707 * 'onClick': function() { console.log('clicked ' + this.label); }
13711 * jQuery('#docs').on('click', view.onClick);
13712 * // => logs 'clicked docs', when the button is clicked
13714 function bindAll(object) {
13715 var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
13717 length = funcs.length;
13719 while (++index < length) {
13720 var key = funcs[index];
13721 object[key] = createBound(object[key], 1, null, null, object);
13727 * Creates a function that, when called, invokes the method at `object[key]`
13728 * and prepends any additional `bindKey` arguments to those provided to the bound
13729 * function. This method differs from `_.bind` by allowing bound functions to
13730 * reference methods that will be redefined or don't yet exist.
13731 * See http://michaux.ca/articles/lazy-function-definition-pattern.
13735 * @category Functions
13736 * @param {Object} object The object the method belongs to.
13737 * @param {string} key The key of the method.
13738 * @param {...*} [arg] Arguments to be partially applied.
13739 * @returns {Function} Returns the new bound function.
13744 * 'greet': function(greeting) {
13745 * return greeting + ' ' + this.name;
13749 * var func = _.bindKey(object, 'greet', 'hi');
13753 * object.greet = function(greeting) {
13754 * return greeting + ', ' + this.name + '!';
13760 function bindKey(object, key) {
13761 return arguments.length > 2
13762 ? createBound(key, 19, nativeSlice.call(arguments, 2), null, object)
13763 : createBound(key, 3, null, null, object);
13767 * Creates a function that is the composition of the provided functions,
13768 * where each function consumes the return value of the function that follows.
13769 * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
13770 * Each function is executed with the `this` binding of the composed function.
13774 * @category Functions
13775 * @param {...Function} [func] Functions to compose.
13776 * @returns {Function} Returns the new composed function.
13779 * var realNameMap = {
13780 * 'curly': 'jerome'
13783 * var format = function(name) {
13784 * name = realNameMap[name.toLowerCase()] || name;
13785 * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
13788 * var greet = function(formatted) {
13789 * return 'Hiya ' + formatted + '!';
13792 * var welcome = _.compose(greet, format);
13793 * welcome('curly');
13794 * // => 'Hiya Jerome!'
13796 function compose() {
13797 var funcs = arguments,
13798 length = funcs.length;
13801 if (!isFunction(funcs[length])) {
13802 throw new TypeError;
13805 return function() {
13806 var args = arguments,
13807 length = funcs.length;
13810 args = [funcs[length].apply(this, args)];
13817 * Produces a callback bound to an optional `thisArg`. If `func` is a property
13818 * name the created callback will return the property value for a given element.
13819 * If `func` is an object the created callback will return `true` for elements
13820 * that contain the equivalent object properties, otherwise it will return `false`.
13824 * @category Functions
13825 * @param {*} [func=identity] The value to convert to a callback.
13826 * @param {*} [thisArg] The `this` binding of the created callback.
13827 * @param {number} [argCount] The number of arguments the callback accepts.
13828 * @returns {Function} Returns a callback function.
13832 * { 'name': 'moe', 'age': 40 },
13833 * { 'name': 'larry', 'age': 50 }
13836 * // wrap to create custom callback shorthands
13837 * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
13838 * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
13839 * return !match ? func(callback, thisArg) : function(object) {
13840 * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
13844 * _.filter(stooges, 'age__gt45');
13845 * // => [{ 'name': 'larry', 'age': 50 }]
13847 function createCallback(func, thisArg, argCount) {
13848 var type = typeof func;
13849 if (func == null || type == 'function') {
13850 return baseCreateCallback(func, thisArg, argCount);
13852 // handle "_.pluck" style callback shorthands
13853 if (type != 'object') {
13854 return function(object) {
13855 return object[func];
13858 var props = keys(func),
13862 // handle "_.where" style callback shorthands
13863 if (props.length == 1 && a === a && !isObject(a)) {
13864 // fast path the common case of providing an object with a single
13865 // property containing a primitive value
13866 return function(object) {
13867 var b = object[key];
13868 return a === b && (a !== 0 || (1 / a == 1 / b));
13871 return function(object) {
13872 var length = props.length,
13876 if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
13885 * Creates a function which accepts one or more arguments of `func` that when
13886 * invoked either executes `func` returning its result, if all `func` arguments
13887 * have been provided, or returns a function that accepts one or more of the
13888 * remaining `func` arguments, and so on. The arity of `func` can be specified
13889 * if `func.length` is not sufficient.
13893 * @category Functions
13894 * @param {Function} func The function to curry.
13895 * @param {number} [arity=func.length] The arity of `func`.
13896 * @returns {Function} Returns the new curried function.
13899 * var curried = _.curry(function(a, b, c) {
13900 * console.log(a + b + c);
13903 * curried(1)(2)(3);
13906 * curried(1, 2)(3);
13909 * curried(1, 2, 3);
13912 function curry(func, arity) {
13913 arity = typeof arity == 'number' ? arity : (+arity || func.length);
13914 return createBound(func, 4, null, null, null, arity);
13918 * Creates a function that will delay the execution of `func` until after
13919 * `wait` milliseconds have elapsed since the last time it was invoked.
13920 * Provide an options object to indicate that `func` should be invoked on
13921 * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
13922 * to the debounced function will return the result of the last `func` call.
13924 * Note: If `leading` and `trailing` options are `true` `func` will be called
13925 * on the trailing edge of the timeout only if the the debounced function is
13926 * invoked more than once during the `wait` timeout.
13930 * @category Functions
13931 * @param {Function} func The function to debounce.
13932 * @param {number} wait The number of milliseconds to delay.
13933 * @param {Object} [options] The options object.
13934 * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
13935 * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
13936 * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
13937 * @returns {Function} Returns the new debounced function.
13940 * // avoid costly calculations while the window size is in flux
13941 * var lazyLayout = _.debounce(calculateLayout, 150);
13942 * jQuery(window).on('resize', lazyLayout);
13944 * // execute `sendMail` when the click event is fired, debouncing subsequent calls
13945 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
13947 * 'trailing': false
13950 * // ensure `batchLog` is executed once after 1 second of debounced calls
13951 * var source = new EventSource('/stream');
13952 * source.addEventListener('message', _.debounce(batchLog, 250, {
13956 function debounce(func, wait, options) {
13968 if (!isFunction(func)) {
13969 throw new TypeError;
13971 wait = nativeMax(0, wait) || 0;
13972 if (options === true) {
13973 var leading = true;
13975 } else if (isObject(options)) {
13976 leading = options.leading;
13977 maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
13978 trailing = 'trailing' in options ? options.trailing : trailing;
13980 var delayed = function() {
13981 var remaining = wait - (now() - stamp);
13982 if (remaining <= 0) {
13983 if (maxTimeoutId) {
13984 clearTimeout(maxTimeoutId);
13986 var isCalled = trailingCall;
13987 maxTimeoutId = timeoutId = trailingCall = undefined;
13989 lastCalled = now();
13990 result = func.apply(thisArg, args);
13993 timeoutId = setTimeout(delayed, remaining);
13997 var maxDelayed = function() {
13999 clearTimeout(timeoutId);
14001 maxTimeoutId = timeoutId = trailingCall = undefined;
14002 if (trailing || (maxWait !== wait)) {
14003 lastCalled = now();
14004 result = func.apply(thisArg, args);
14008 return function() {
14012 trailingCall = trailing && (timeoutId || !leading);
14014 if (maxWait === false) {
14015 var leadingCall = leading && !timeoutId;
14017 if (!maxTimeoutId && !leading) {
14018 lastCalled = stamp;
14020 var remaining = maxWait - (stamp - lastCalled);
14021 if (remaining <= 0) {
14022 if (maxTimeoutId) {
14023 maxTimeoutId = clearTimeout(maxTimeoutId);
14025 lastCalled = stamp;
14026 result = func.apply(thisArg, args);
14028 else if (!maxTimeoutId) {
14029 maxTimeoutId = setTimeout(maxDelayed, remaining);
14032 if (!timeoutId && wait !== maxWait) {
14033 timeoutId = setTimeout(delayed, wait);
14036 result = func.apply(thisArg, args);
14043 * Defers executing the `func` function until the current call stack has cleared.
14044 * Additional arguments will be provided to `func` when it is invoked.
14048 * @category Functions
14049 * @param {Function} func The function to defer.
14050 * @param {...*} [arg] Arguments to invoke the function with.
14051 * @returns {number} Returns the timer id.
14054 * _.defer(function() { console.log('deferred'); });
14055 * // returns from the function before 'deferred' is logged
14057 function defer(func) {
14058 if (!isFunction(func)) {
14059 throw new TypeError;
14061 var args = nativeSlice.call(arguments, 1);
14062 return setTimeout(function() { func.apply(undefined, args); }, 1);
14064 // use `setImmediate` if available in Node.js
14065 if (isV8 && moduleExports && typeof setImmediate == 'function') {
14066 defer = function(func) {
14067 if (!isFunction(func)) {
14068 throw new TypeError;
14070 return setImmediate.apply(context, arguments);
14075 * Executes the `func` function after `wait` milliseconds. Additional arguments
14076 * will be provided to `func` when it is invoked.
14080 * @category Functions
14081 * @param {Function} func The function to delay.
14082 * @param {number} wait The number of milliseconds to delay execution.
14083 * @param {...*} [arg] Arguments to invoke the function with.
14084 * @returns {number} Returns the timer id.
14087 * var log = _.bind(console.log, console);
14088 * _.delay(log, 1000, 'logged later');
14089 * // => 'logged later' (Appears after one second.)
14091 function delay(func, wait) {
14092 if (!isFunction(func)) {
14093 throw new TypeError;
14095 var args = nativeSlice.call(arguments, 2);
14096 return setTimeout(function() { func.apply(undefined, args); }, wait);
14100 * Creates a function that memoizes the result of `func`. If `resolver` is
14101 * provided it will be used to determine the cache key for storing the result
14102 * based on the arguments provided to the memoized function. By default, the
14103 * first argument provided to the memoized function is used as the cache key.
14104 * The `func` is executed with the `this` binding of the memoized function.
14105 * The result cache is exposed as the `cache` property on the memoized function.
14109 * @category Functions
14110 * @param {Function} func The function to have its output memoized.
14111 * @param {Function} [resolver] A function used to resolve the cache key.
14112 * @returns {Function} Returns the new memoizing function.
14115 * var fibonacci = _.memoize(function(n) {
14116 * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
14120 * 'moe': { 'name': 'moe', 'age': 40 },
14121 * 'curly': { 'name': 'curly', 'age': 60 }
14124 * // modifying the result cache
14125 * var stooge = _.memoize(function(name) { return data[name]; }, _.identity);
14127 * // => { 'name': 'curly', 'age': 60 }
14129 * stooge.cache.curly.name = 'jerome';
14131 * // => { 'name': 'jerome', 'age': 60 }
14133 function memoize(func, resolver) {
14134 if (!isFunction(func)) {
14135 throw new TypeError;
14137 var memoized = function() {
14138 var cache = memoized.cache,
14139 key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
14141 return hasOwnProperty.call(cache, key)
14143 : (cache[key] = func.apply(this, arguments));
14145 memoized.cache = {};
14150 * Creates a function that is restricted to execute `func` once. Repeat calls to
14151 * the function will return the value of the first call. The `func` is executed
14152 * with the `this` binding of the created function.
14156 * @category Functions
14157 * @param {Function} func The function to restrict.
14158 * @returns {Function} Returns the new restricted function.
14161 * var initialize = _.once(createApplication);
14164 * // `initialize` executes `createApplication` once
14166 function once(func) {
14170 if (!isFunction(func)) {
14171 throw new TypeError;
14173 return function() {
14178 result = func.apply(this, arguments);
14180 // clear the `func` variable so the function may be garbage collected
14187 * Creates a function that, when called, invokes `func` with any additional
14188 * `partial` arguments prepended to those provided to the new function. This
14189 * method is similar to `_.bind` except it does **not** alter the `this` binding.
14193 * @category Functions
14194 * @param {Function} func The function to partially apply arguments to.
14195 * @param {...*} [arg] Arguments to be partially applied.
14196 * @returns {Function} Returns the new partially applied function.
14199 * var greet = function(greeting, name) { return greeting + ' ' + name; };
14200 * var hi = _.partial(greet, 'hi');
14204 function partial(func) {
14205 return createBound(func, 16, nativeSlice.call(arguments, 1));
14209 * This method is like `_.partial` except that `partial` arguments are
14210 * appended to those provided to the new function.
14214 * @category Functions
14215 * @param {Function} func The function to partially apply arguments to.
14216 * @param {...*} [arg] Arguments to be partially applied.
14217 * @returns {Function} Returns the new partially applied function.
14220 * var defaultsDeep = _.partialRight(_.merge, _.defaults);
14223 * 'variable': 'data',
14224 * 'imports': { 'jq': $ }
14227 * defaultsDeep(options, _.templateSettings);
14233 * // => { '_': _, 'jq': $ }
14235 function partialRight(func) {
14236 return createBound(func, 32, null, nativeSlice.call(arguments, 1));
14240 * Creates a function that, when executed, will only call the `func` function
14241 * at most once per every `wait` milliseconds. Provide an options object to
14242 * indicate that `func` should be invoked on the leading and/or trailing edge
14243 * of the `wait` timeout. Subsequent calls to the throttled function will
14244 * return the result of the last `func` call.
14246 * Note: If `leading` and `trailing` options are `true` `func` will be called
14247 * on the trailing edge of the timeout only if the the throttled function is
14248 * invoked more than once during the `wait` timeout.
14252 * @category Functions
14253 * @param {Function} func The function to throttle.
14254 * @param {number} wait The number of milliseconds to throttle executions to.
14255 * @param {Object} [options] The options object.
14256 * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
14257 * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
14258 * @returns {Function} Returns the new throttled function.
14261 * // avoid excessively updating the position while scrolling
14262 * var throttled = _.throttle(updatePosition, 100);
14263 * jQuery(window).on('scroll', throttled);
14265 * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
14266 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
14267 * 'trailing': false
14270 function throttle(func, wait, options) {
14271 var leading = true,
14274 if (!isFunction(func)) {
14275 throw new TypeError;
14277 if (options === false) {
14279 } else if (isObject(options)) {
14280 leading = 'leading' in options ? options.leading : leading;
14281 trailing = 'trailing' in options ? options.trailing : trailing;
14283 debounceOptions.leading = leading;
14284 debounceOptions.maxWait = wait;
14285 debounceOptions.trailing = trailing;
14287 var result = debounce(func, wait, debounceOptions);
14292 * Creates a function that provides `value` to the wrapper function as its
14293 * first argument. Additional arguments provided to the function are appended
14294 * to those provided to the wrapper function. The wrapper is executed with
14295 * the `this` binding of the created function.
14299 * @category Functions
14300 * @param {*} value The value to wrap.
14301 * @param {Function} wrapper The wrapper function.
14302 * @returns {Function} Returns the new function.
14305 * var hello = function(name) { return 'hello ' + name; };
14306 * hello = _.wrap(hello, function(func) {
14307 * return 'before, ' + func('moe') + ', after';
14310 * // => 'before, hello moe, after'
14312 function wrap(value, wrapper) {
14313 if (!isFunction(wrapper)) {
14314 throw new TypeError;
14316 return function() {
14317 var args = [value];
14318 push.apply(args, arguments);
14319 return wrapper.apply(this, args);
14323 /*--------------------------------------------------------------------------*/
14326 * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
14327 * corresponding HTML entities.
14331 * @category Utilities
14332 * @param {string} string The string to escape.
14333 * @returns {string} Returns the escaped string.
14336 * _.escape('Moe, Larry & Curly');
14337 * // => 'Moe, Larry & Curly'
14339 function escape(string) {
14340 return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
14344 * This method returns the first argument provided to it.
14348 * @category Utilities
14349 * @param {*} value Any value.
14350 * @returns {*} Returns `value`.
14353 * var moe = { 'name': 'moe' };
14354 * moe === _.identity(moe);
14357 function identity(value) {
14362 * Adds function properties of a source object to the `lodash` function and
14363 * chainable wrapper.
14367 * @category Utilities
14368 * @param {Object} object The object of function properties to add to `lodash`.
14369 * @param {Object} object The object of function properties to add to `lodash`.
14373 * 'capitalize': function(string) {
14374 * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
14378 * _.capitalize('moe');
14381 * _('moe').capitalize();
14384 function mixin(object, source) {
14386 isFunc = !source || isFunction(ctor);
14389 ctor = lodashWrapper;
14393 forEach(functions(source), function(methodName) {
14394 var func = object[methodName] = source[methodName];
14396 ctor.prototype[methodName] = function() {
14397 var value = this.__wrapped__,
14400 push.apply(args, arguments);
14401 var result = func.apply(object, args);
14402 if (value && typeof value == 'object' && value === result) {
14405 result = new ctor(result);
14406 result.__chain__ = this.__chain__;
14414 * Reverts the '_' variable to its previous value and returns a reference to
14415 * the `lodash` function.
14419 * @category Utilities
14420 * @returns {Function} Returns the `lodash` function.
14423 * var lodash = _.noConflict();
14425 function noConflict() {
14426 context._ = oldDash;
14431 * Converts the given value into an integer of the specified radix.
14432 * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
14433 * `value` is a hexadecimal, in which case a `radix` of `16` is used.
14435 * Note: This method avoids differences in native ES3 and ES5 `parseInt`
14436 * implementations. See http://es5.github.io/#E.
14440 * @category Utilities
14441 * @param {string} value The value to parse.
14442 * @param {number} [radix] The radix used to interpret the value to parse.
14443 * @returns {number} Returns the new integer value.
14446 * _.parseInt('08');
14449 var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
14450 // Firefox and Opera still follow the ES3 specified implementation of `parseInt`
14451 return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
14455 * Produces a random number between `min` and `max` (inclusive). If only one
14456 * argument is provided a number between `0` and the given number will be
14457 * returned. If `floating` is truey or either `min` or `max` are floats a
14458 * floating-point number will be returned instead of an integer.
14462 * @category Utilities
14463 * @param {number} [min=0] The minimum possible value.
14464 * @param {number} [max=1] The maximum possible value.
14465 * @param {boolean} [floating=false] Specify returning a floating-point number.
14466 * @returns {number} Returns a random number.
14470 * // => an integer between 0 and 5
14473 * // => also an integer between 0 and 5
14475 * _.random(5, true);
14476 * // => a floating-point number between 0 and 5
14478 * _.random(1.2, 5.2);
14479 * // => a floating-point number between 1.2 and 5.2
14481 function random(min, max, floating) {
14482 var noMin = min == null,
14483 noMax = max == null;
14485 if (floating == null) {
14486 if (typeof min == 'boolean' && noMax) {
14490 else if (!noMax && typeof max == 'boolean') {
14495 if (noMin && noMax) {
14505 var rand = nativeRandom();
14506 return (floating || min % 1 || max % 1)
14507 ? nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max)
14508 : min + floor(rand * (max - min + 1));
14512 * Resolves the value of `property` on `object`. If `property` is a function
14513 * it will be invoked with the `this` binding of `object` and its result returned,
14514 * else the property value is returned. If `object` is falsey then `undefined`
14519 * @category Utilities
14520 * @param {Object} object The object to inspect.
14521 * @param {string} property The property to get the value of.
14522 * @returns {*} Returns the resolved value.
14526 * 'cheese': 'crumpets',
14527 * 'stuff': function() {
14528 * return 'nonsense';
14532 * _.result(object, 'cheese');
14535 * _.result(object, 'stuff');
14538 function result(object, property) {
14540 var value = object[property];
14541 return isFunction(value) ? object[property]() : value;
14546 * A micro-templating method that handles arbitrary delimiters, preserves
14547 * whitespace, and correctly escapes quotes within interpolated code.
14549 * Note: In the development build, `_.template` utilizes sourceURLs for easier
14550 * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
14552 * For more information on precompiling templates see:
14553 * http://lodash.com/#custom-builds
14555 * For more information on Chrome extension sandboxes see:
14556 * http://developer.chrome.com/stable/extensions/sandboxingEval.html
14560 * @category Utilities
14561 * @param {string} text The template text.
14562 * @param {Object} data The data object used to populate the text.
14563 * @param {Object} [options] The options object.
14564 * @param {RegExp} [options.escape] The "escape" delimiter.
14565 * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
14566 * @param {Object} [options.imports] An object to import into the template as local variables.
14567 * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
14568 * @param {string} [sourceURL] The sourceURL of the template's compiled source.
14569 * @param {string} [variable] The data object variable name.
14570 * @returns {Function|string} Returns a compiled function when no `data` object
14571 * is given, else it returns the interpolated text.
14574 * // using the "interpolate" delimiter to create a compiled template
14575 * var compiled = _.template('hello <%= name %>');
14576 * compiled({ 'name': 'moe' });
14577 * // => 'hello moe'
14579 * // using the "escape" delimiter to escape HTML in data property values
14580 * _.template('<b><%- value %></b>', { 'value': '<script>' });
14581 * // => '<b><script></b>'
14583 * // using the "evaluate" delimiter to generate HTML
14584 * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
14585 * _.template(list, { 'people': ['moe', 'larry'] });
14586 * // => '<li>moe</li><li>larry</li>'
14588 * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
14589 * _.template('hello ${ name }', { 'name': 'curly' });
14590 * // => 'hello curly'
14592 * // using the internal `print` function in "evaluate" delimiters
14593 * _.template('<% print("hello " + name); %>!', { 'name': 'larry' });
14594 * // => 'hello larry!'
14596 * // using a custom template delimiters
14597 * _.templateSettings = {
14598 * 'interpolate': /{{([\s\S]+?)}}/g
14601 * _.template('hello {{ name }}!', { 'name': 'mustache' });
14602 * // => 'hello mustache!'
14604 * // using the `imports` option to import jQuery
14605 * var list = '<% $.each(people, function(name) { %><li><%- name %></li><% }); %>';
14606 * _.template(list, { 'people': ['moe', 'larry'] }, { 'imports': { '$': jQuery } });
14607 * // => '<li>moe</li><li>larry</li>'
14609 * // using the `sourceURL` option to specify a custom sourceURL for the template
14610 * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
14612 * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
14614 * // using the `variable` option to ensure a with-statement isn't used in the compiled template
14615 * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
14617 * // => function(data) {
14618 * var __t, __p = '', __e = _.escape;
14619 * __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
14623 * // using the `source` property to inline compiled templates for meaningful
14624 * // line numbers in error messages and a stack trace
14625 * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
14627 * "main": ' + _.template(mainText).source + '\
14631 function template(text, data, options) {
14632 // based on John Resig's `tmpl` implementation
14633 // http://ejohn.org/blog/javascript-micro-templating/
14634 // and Laura Doktorova's doT.js
14635 // https://github.com/olado/doT
14636 var settings = lodash.templateSettings;
14637 text || (text = '');
14639 // avoid missing dependencies when `iteratorTemplate` is not defined
14640 options = defaults({}, options, settings);
14642 var imports = defaults({}, options.imports, settings.imports),
14643 importsKeys = keys(imports),
14644 importsValues = values(imports);
14648 interpolate = options.interpolate || reNoMatch,
14649 source = "__p += '";
14651 // compile the regexp to match each delimiter
14652 var reDelimiters = RegExp(
14653 (options.escape || reNoMatch).source + '|' +
14654 interpolate.source + '|' +
14655 (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
14656 (options.evaluate || reNoMatch).source + '|$'
14659 text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
14660 interpolateValue || (interpolateValue = esTemplateValue);
14662 // escape characters that cannot be included in string literals
14663 source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
14665 // replace delimiters with snippets
14667 source += "' +\n__e(" + escapeValue + ") +\n'";
14669 if (evaluateValue) {
14670 isEvaluating = true;
14671 source += "';\n" + evaluateValue + ";\n__p += '";
14673 if (interpolateValue) {
14674 source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
14676 index = offset + match.length;
14678 // the JS engine embedded in Adobe products requires returning the `match`
14679 // string in order to produce the correct `offset` value
14685 // if `variable` is not specified, wrap a with-statement around the generated
14686 // code to add the data object to the top of the scope chain
14687 var variable = options.variable,
14688 hasVariable = variable;
14690 if (!hasVariable) {
14692 source = 'with (' + variable + ') {\n' + source + '\n}\n';
14694 // cleanup code by stripping empty strings
14695 source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
14696 .replace(reEmptyStringMiddle, '$1')
14697 .replace(reEmptyStringTrailing, '$1;');
14699 // frame code as the function body
14700 source = 'function(' + variable + ') {\n' +
14701 (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
14702 "var __t, __p = '', __e = _.escape" +
14704 ? ', __j = Array.prototype.join;\n' +
14705 "function print() { __p += __j.call(arguments, '') }\n"
14711 // Use a sourceURL for easier debugging.
14712 // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
14713 var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
14716 var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
14722 return result(data);
14724 // provide the compiled function's source by its `toString` method, in
14725 // supported environments, or the `source` property as a convenience for
14726 // inlining compiled templates during the build process
14727 result.source = source;
14732 * Executes the callback `n` times, returning an array of the results
14733 * of each callback execution. The callback is bound to `thisArg` and invoked
14734 * with one argument; (index).
14738 * @category Utilities
14739 * @param {number} n The number of times to execute the callback.
14740 * @param {Function} callback The function called per iteration.
14741 * @param {*} [thisArg] The `this` binding of `callback`.
14742 * @returns {Array} Returns an array of the results of each `callback` execution.
14745 * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
14748 * _.times(3, function(n) { mage.castSpell(n); });
14749 * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
14751 * _.times(3, function(n) { this.cast(n); }, mage);
14752 * // => also calls `mage.castSpell(n)` three times
14754 function times(n, callback, thisArg) {
14755 n = (n = +n) > -1 ? n : 0;
14759 callback = baseCreateCallback(callback, thisArg, 1);
14760 while (++index < n) {
14761 result[index] = callback(index);
14767 * The inverse of `_.escape` this method converts the HTML entities
14768 * `&`, `<`, `>`, `"`, and `'` in `string` to their
14769 * corresponding characters.
14773 * @category Utilities
14774 * @param {string} string The string to unescape.
14775 * @returns {string} Returns the unescaped string.
14778 * _.unescape('Moe, Larry & Curly');
14779 * // => 'Moe, Larry & Curly'
14781 function unescape(string) {
14782 return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
14786 * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
14790 * @category Utilities
14791 * @param {string} [prefix] The value to prefix the ID with.
14792 * @returns {string} Returns the unique ID.
14795 * _.uniqueId('contact_');
14796 * // => 'contact_104'
14801 function uniqueId(prefix) {
14802 var id = ++idCounter;
14803 return String(prefix == null ? '' : prefix) + id;
14806 /*--------------------------------------------------------------------------*/
14809 * Creates a `lodash` object that wraps the given value with explicit
14810 * method chaining enabled.
14814 * @category Chaining
14815 * @param {*} value The value to wrap.
14816 * @returns {Object} Returns the wrapper object.
14820 * { 'name': 'moe', 'age': 40 },
14821 * { 'name': 'larry', 'age': 50 },
14822 * { 'name': 'curly', 'age': 60 }
14825 * var youngest = _.chain(stooges)
14827 * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
14830 * // => 'moe is 40'
14832 function chain(value) {
14833 value = new lodashWrapper(value);
14834 value.__chain__ = true;
14839 * Invokes `interceptor` with the `value` as the first argument and then
14840 * returns `value`. The purpose of this method is to "tap into" a method
14841 * chain in order to perform operations on intermediate results within
14846 * @category Chaining
14847 * @param {*} value The value to provide to `interceptor`.
14848 * @param {Function} interceptor The function to invoke.
14849 * @returns {*} Returns `value`.
14853 * .filter(function(num) { return num % 2 == 0; })
14854 * .tap(function(array) { console.log(array); })
14855 * .map(function(num) { return num * num; })
14857 * // => // [2, 4] (logged)
14860 function tap(value, interceptor) {
14861 interceptor(value);
14866 * Enables explicit method chaining on the wrapper object.
14870 * @category Chaining
14871 * @returns {*} Returns the wrapper object.
14875 * { 'name': 'moe', 'age': 40 },
14876 * { 'name': 'larry', 'age': 50 }
14879 * // without explicit chaining
14880 * _(stooges).first();
14881 * // => { 'name': 'moe', 'age': 40 }
14883 * // with explicit chaining
14884 * _(stooges).chain()
14888 * // => { 'age': 40 }
14890 function wrapperChain() {
14891 this.__chain__ = true;
14896 * Produces the `toString` result of the wrapped value.
14900 * @category Chaining
14901 * @returns {string} Returns the string result.
14904 * _([1, 2, 3]).toString();
14907 function wrapperToString() {
14908 return String(this.__wrapped__);
14912 * Extracts the wrapped value.
14917 * @category Chaining
14918 * @returns {*} Returns the wrapped value.
14921 * _([1, 2, 3]).valueOf();
14924 function wrapperValueOf() {
14925 return this.__wrapped__;
14928 /*--------------------------------------------------------------------------*/
14930 // add functions that return wrapped values when chaining
14931 lodash.after = after;
14932 lodash.assign = assign;
14934 lodash.bind = bind;
14935 lodash.bindAll = bindAll;
14936 lodash.bindKey = bindKey;
14937 lodash.chain = chain;
14938 lodash.compact = compact;
14939 lodash.compose = compose;
14940 lodash.countBy = countBy;
14941 lodash.createCallback = createCallback;
14942 lodash.curry = curry;
14943 lodash.debounce = debounce;
14944 lodash.defaults = defaults;
14945 lodash.defer = defer;
14946 lodash.delay = delay;
14947 lodash.difference = difference;
14948 lodash.filter = filter;
14949 lodash.flatten = flatten;
14950 lodash.forEach = forEach;
14951 lodash.forEachRight = forEachRight;
14952 lodash.forIn = forIn;
14953 lodash.forInRight = forInRight;
14954 lodash.forOwn = forOwn;
14955 lodash.forOwnRight = forOwnRight;
14956 lodash.functions = functions;
14957 lodash.groupBy = groupBy;
14958 lodash.indexBy = indexBy;
14959 lodash.initial = initial;
14960 lodash.intersection = intersection;
14961 lodash.invert = invert;
14962 lodash.invoke = invoke;
14963 lodash.keys = keys;
14966 lodash.memoize = memoize;
14967 lodash.merge = merge;
14969 lodash.omit = omit;
14970 lodash.once = once;
14971 lodash.pairs = pairs;
14972 lodash.partial = partial;
14973 lodash.partialRight = partialRight;
14974 lodash.pick = pick;
14975 lodash.pluck = pluck;
14976 lodash.pull = pull;
14977 lodash.range = range;
14978 lodash.reject = reject;
14979 lodash.remove = remove;
14980 lodash.rest = rest;
14981 lodash.shuffle = shuffle;
14982 lodash.sortBy = sortBy;
14984 lodash.throttle = throttle;
14985 lodash.times = times;
14986 lodash.toArray = toArray;
14987 lodash.transform = transform;
14988 lodash.union = union;
14989 lodash.uniq = uniq;
14990 lodash.values = values;
14991 lodash.where = where;
14992 lodash.without = without;
14993 lodash.wrap = wrap;
14995 lodash.zipObject = zipObject;
14998 lodash.collect = map;
14999 lodash.drop = rest;
15000 lodash.each = forEach;
15001 lodash.eachRight = forEachRight;
15002 lodash.extend = assign;
15003 lodash.methods = functions;
15004 lodash.object = zipObject;
15005 lodash.select = filter;
15006 lodash.tail = rest;
15007 lodash.unique = uniq;
15008 lodash.unzip = zip;
15010 // add functions to `lodash.prototype`
15013 /*--------------------------------------------------------------------------*/
15015 // add functions that return unwrapped values when chaining
15016 lodash.clone = clone;
15017 lodash.cloneDeep = cloneDeep;
15018 lodash.contains = contains;
15019 lodash.escape = escape;
15020 lodash.every = every;
15021 lodash.find = find;
15022 lodash.findIndex = findIndex;
15023 lodash.findKey = findKey;
15024 lodash.findLast = findLast;
15025 lodash.findLastIndex = findLastIndex;
15026 lodash.findLastKey = findLastKey;
15028 lodash.identity = identity;
15029 lodash.indexOf = indexOf;
15030 lodash.isArguments = isArguments;
15031 lodash.isArray = isArray;
15032 lodash.isBoolean = isBoolean;
15033 lodash.isDate = isDate;
15034 lodash.isElement = isElement;
15035 lodash.isEmpty = isEmpty;
15036 lodash.isEqual = isEqual;
15037 lodash.isFinite = isFinite;
15038 lodash.isFunction = isFunction;
15039 lodash.isNaN = isNaN;
15040 lodash.isNull = isNull;
15041 lodash.isNumber = isNumber;
15042 lodash.isObject = isObject;
15043 lodash.isPlainObject = isPlainObject;
15044 lodash.isRegExp = isRegExp;
15045 lodash.isString = isString;
15046 lodash.isUndefined = isUndefined;
15047 lodash.lastIndexOf = lastIndexOf;
15048 lodash.mixin = mixin;
15049 lodash.noConflict = noConflict;
15050 lodash.parseInt = parseInt;
15051 lodash.random = random;
15052 lodash.reduce = reduce;
15053 lodash.reduceRight = reduceRight;
15054 lodash.result = result;
15055 lodash.runInContext = runInContext;
15056 lodash.size = size;
15057 lodash.some = some;
15058 lodash.sortedIndex = sortedIndex;
15059 lodash.template = template;
15060 lodash.unescape = unescape;
15061 lodash.uniqueId = uniqueId;
15064 lodash.all = every;
15066 lodash.detect = find;
15067 lodash.findWhere = find;
15068 lodash.foldl = reduce;
15069 lodash.foldr = reduceRight;
15070 lodash.include = contains;
15071 lodash.inject = reduce;
15073 forOwn(lodash, function(func, methodName) {
15074 if (!lodash.prototype[methodName]) {
15075 lodash.prototype[methodName] = function() {
15076 var args = [this.__wrapped__],
15077 chainAll = this.__chain__;
15079 push.apply(args, arguments);
15080 var result = func.apply(lodash, args);
15082 ? new lodashWrapper(result, chainAll)
15088 /*--------------------------------------------------------------------------*/
15090 // add functions capable of returning wrapped and unwrapped values when chaining
15091 lodash.first = first;
15092 lodash.last = last;
15093 lodash.sample = sample;
15096 lodash.take = first;
15097 lodash.head = first;
15099 forOwn(lodash, function(func, methodName) {
15100 var callbackable = methodName !== 'sample';
15101 if (!lodash.prototype[methodName]) {
15102 lodash.prototype[methodName]= function(n, guard) {
15103 var chainAll = this.__chain__,
15104 result = func(this.__wrapped__, n, guard);
15106 return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
15108 : new lodashWrapper(result, chainAll);
15113 /*--------------------------------------------------------------------------*/
15116 * The semantic version number.
15122 lodash.VERSION = '2.2.1';
15124 // add "Chaining" functions to the wrapper
15125 lodash.prototype.chain = wrapperChain;
15126 lodash.prototype.toString = wrapperToString;
15127 lodash.prototype.value = wrapperValueOf;
15128 lodash.prototype.valueOf = wrapperValueOf;
15130 // add `Array` functions that return unwrapped values
15131 forEach(['join', 'pop', 'shift'], function(methodName) {
15132 var func = arrayRef[methodName];
15133 lodash.prototype[methodName] = function() {
15134 var chainAll = this.__chain__,
15135 result = func.apply(this.__wrapped__, arguments);
15138 ? new lodashWrapper(result, chainAll)
15143 // add `Array` functions that return the wrapped value
15144 forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
15145 var func = arrayRef[methodName];
15146 lodash.prototype[methodName] = function() {
15147 func.apply(this.__wrapped__, arguments);
15152 // add `Array` functions that return new wrapped values
15153 forEach(['concat', 'slice', 'splice'], function(methodName) {
15154 var func = arrayRef[methodName];
15155 lodash.prototype[methodName] = function() {
15156 return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
15163 /*--------------------------------------------------------------------------*/
15166 var _ = runInContext();
15168 // some AMD build optimizers, like r.js, check for condition patterns like the following:
15169 if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
15170 // Expose Lo-Dash to the global object even when an AMD loader is present in
15171 // case Lo-Dash was injected by a third-party script and not intended to be
15172 // loaded as a module. The global assignment can be reverted in the Lo-Dash
15173 // module by its `noConflict()` method.
15176 // define as an anonymous module so, through path mapping, it can be
15177 // referenced as the "underscore" module
15178 define(function() {
15182 // check for `exports` after `define` in case a build optimizer adds an `exports` object
15183 else if (freeExports && freeModule) {
15184 // in Node.js or RingoJS
15185 if (moduleExports) {
15186 (freeModule.exports = _)._ = _;
15188 // in Narwhal or Rhino -require
15194 // in a browser or Rhino
15199 // Backbone.js 1.0.0
15201 // (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
15202 // Backbone may be freely distributed under the MIT license.
15203 // For all details and documentation:
15204 // http://backbonejs.org
15211 // Save a reference to the global object (`window` in the browser, `exports`
15215 // Save the previous value of the `Backbone` variable, so that it can be
15216 // restored later on, if `noConflict` is used.
15217 var previousBackbone = root.Backbone;
15219 // Create local references to array methods we'll want to use later.
15221 var push = array.push;
15222 var slice = array.slice;
15223 var splice = array.splice;
15225 // The top-level namespace. All public Backbone classes and modules will
15226 // be attached to this. Exported for both the browser and the server.
15228 if (typeof exports !== 'undefined') {
15229 Backbone = exports;
15231 Backbone = root.Backbone = {};
15234 // Current version of the library. Keep in sync with `package.json`.
15235 Backbone.VERSION = '1.0.0';
15237 // Require Underscore, if we're on the server, and it's not already present.
15239 if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
15241 // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
15242 // the `$` variable.
15243 Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
15245 // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
15246 // to its previous owner. Returns a reference to this Backbone object.
15247 Backbone.noConflict = function() {
15248 root.Backbone = previousBackbone;
15252 // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
15253 // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
15254 // set a `X-Http-Method-Override` header.
15255 Backbone.emulateHTTP = false;
15257 // Turn on `emulateJSON` to support legacy servers that can't deal with direct
15258 // `application/json` requests ... will encode the body as
15259 // `application/x-www-form-urlencoded` instead and will send the model in a
15260 // form param named `model`.
15261 Backbone.emulateJSON = false;
15266 // A module that can be mixed in to *any object* in order to provide it with
15267 // custom events. You may bind with `on` or remove with `off` callback
15268 // functions to an event; `trigger`-ing an event fires all callbacks in
15271 // var object = {};
15272 // _.extend(object, Backbone.Events);
15273 // object.on('expand', function(){ alert('expanded'); });
15274 // object.trigger('expand');
15276 var Events = Backbone.Events = {
15278 // Bind an event to a `callback` function. Passing `"all"` will bind
15279 // the callback to all events fired.
15280 on: function(name, callback, context) {
15281 if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
15282 this._events || (this._events = {});
15283 var events = this._events[name] || (this._events[name] = []);
15284 events.push({callback: callback, context: context, ctx: context || this});
15288 // Bind an event to only be triggered a single time. After the first time
15289 // the callback is invoked, it will be removed.
15290 once: function(name, callback, context) {
15291 if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
15293 var once = _.once(function() {
15294 self.off(name, once);
15295 callback.apply(this, arguments);
15297 once._callback = callback;
15298 return this.on(name, once, context);
15301 // Remove one or many callbacks. If `context` is null, removes all
15302 // callbacks with that function. If `callback` is null, removes all
15303 // callbacks for the event. If `name` is null, removes all bound
15304 // callbacks for all events.
15305 off: function(name, callback, context) {
15306 var retain, ev, events, names, i, l, j, k;
15307 if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
15308 if (!name && !callback && !context) {
15313 names = name ? [name] : _.keys(this._events);
15314 for (i = 0, l = names.length; i < l; i++) {
15316 if (events = this._events[name]) {
15317 this._events[name] = retain = [];
15318 if (callback || context) {
15319 for (j = 0, k = events.length; j < k; j++) {
15321 if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
15322 (context && context !== ev.context)) {
15327 if (!retain.length) delete this._events[name];
15334 // Trigger one or many events, firing all bound callbacks. Callbacks are
15335 // passed the same arguments as `trigger` is, apart from the event name
15336 // (unless you're listening on `"all"`, which will cause your callback to
15337 // receive the true name of the event as the first argument).
15338 trigger: function(name) {
15339 if (!this._events) return this;
15340 var args = slice.call(arguments, 1);
15341 if (!eventsApi(this, 'trigger', name, args)) return this;
15342 var events = this._events[name];
15343 var allEvents = this._events.all;
15344 if (events) triggerEvents(events, args);
15345 if (allEvents) triggerEvents(allEvents, arguments);
15349 // Tell this object to stop listening to either specific events ... or
15350 // to every object it's currently listening to.
15351 stopListening: function(obj, name, callback) {
15352 var listeners = this._listeners;
15353 if (!listeners) return this;
15354 var deleteListener = !name && !callback;
15355 if (typeof name === 'object') callback = this;
15356 if (obj) (listeners = {})[obj._listenerId] = obj;
15357 for (var id in listeners) {
15358 listeners[id].off(name, callback, this);
15359 if (deleteListener) delete this._listeners[id];
15366 // Regular expression used to split event strings.
15367 var eventSplitter = /\s+/;
15369 // Implement fancy features of the Events API such as multiple event
15370 // names `"change blur"` and jQuery-style event maps `{change: action}`
15371 // in terms of the existing API.
15372 var eventsApi = function(obj, action, name, rest) {
15373 if (!name) return true;
15375 // Handle event maps.
15376 if (typeof name === 'object') {
15377 for (var key in name) {
15378 obj[action].apply(obj, [key, name[key]].concat(rest));
15383 // Handle space separated event names.
15384 if (eventSplitter.test(name)) {
15385 var names = name.split(eventSplitter);
15386 for (var i = 0, l = names.length; i < l; i++) {
15387 obj[action].apply(obj, [names[i]].concat(rest));
15395 // A difficult-to-believe, but optimized internal dispatch function for
15396 // triggering events. Tries to keep the usual cases speedy (most internal
15397 // Backbone events have 3 arguments).
15398 var triggerEvents = function(events, args) {
15399 var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
15400 switch (args.length) {
15401 case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
15402 case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
15403 case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
15404 case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
15405 default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
15409 var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
15411 // Inversion-of-control versions of `on` and `once`. Tell *this* object to
15412 // listen to an event in another object ... keeping track of what it's
15414 _.each(listenMethods, function(implementation, method) {
15415 Events[method] = function(obj, name, callback) {
15416 var listeners = this._listeners || (this._listeners = {});
15417 var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
15418 listeners[id] = obj;
15419 if (typeof name === 'object') callback = this;
15420 obj[implementation](name, callback, this);
15425 // Aliases for backwards compatibility.
15426 Events.bind = Events.on;
15427 Events.unbind = Events.off;
15429 // Allow the `Backbone` object to serve as a global event bus, for folks who
15430 // want global "pubsub" in a convenient place.
15431 _.extend(Backbone, Events);
15436 // Backbone **Models** are the basic data object in the framework --
15437 // frequently representing a row in a table in a database on your server.
15438 // A discrete chunk of data and a bunch of useful, related methods for
15439 // performing computations and transformations on that data.
15441 // Create a new model with the specified attributes. A client id (`cid`)
15442 // is automatically generated and assigned for you.
15443 var Model = Backbone.Model = function(attributes, options) {
15445 var attrs = attributes || {};
15446 options || (options = {});
15447 this.cid = _.uniqueId('c');
15448 this.attributes = {};
15449 _.extend(this, _.pick(options, modelOptions));
15450 if (options.parse) attrs = this.parse(attrs, options) || {};
15451 if (defaults = _.result(this, 'defaults')) {
15452 attrs = _.defaults({}, attrs, defaults);
15454 this.set(attrs, options);
15456 this.initialize.apply(this, arguments);
15459 // A list of options to be attached directly to the model, if provided.
15460 var modelOptions = ['url', 'urlRoot', 'collection'];
15462 // Attach all inheritable methods to the Model prototype.
15463 _.extend(Model.prototype, Events, {
15465 // A hash of attributes whose current and previous value differ.
15468 // The value returned during the last failed validation.
15469 validationError: null,
15471 // The default name for the JSON `id` attribute is `"id"`. MongoDB and
15472 // CouchDB users may want to set this to `"_id"`.
15475 // Initialize is an empty function by default. Override it with your own
15476 // initialization logic.
15477 initialize: function(){},
15479 // Return a copy of the model's `attributes` object.
15480 toJSON: function(options) {
15481 return _.clone(this.attributes);
15484 // Proxy `Backbone.sync` by default -- but override this if you need
15485 // custom syncing semantics for *this* particular model.
15487 return Backbone.sync.apply(this, arguments);
15490 // Get the value of an attribute.
15491 get: function(attr) {
15492 return this.attributes[attr];
15495 // Get the HTML-escaped value of an attribute.
15496 escape: function(attr) {
15497 return _.escape(this.get(attr));
15500 // Returns `true` if the attribute contains a value that is not null
15502 has: function(attr) {
15503 return this.get(attr) != null;
15506 // Set a hash of model attributes on the object, firing `"change"`. This is
15507 // the core primitive operation of a model, updating the data and notifying
15508 // anyone who needs to know about the change in state. The heart of the beast.
15509 set: function(key, val, options) {
15510 var attr, attrs, unset, changes, silent, changing, prev, current;
15511 if (key == null) return this;
15513 // Handle both `"key", value` and `{key: value}` -style arguments.
15514 if (typeof key === 'object') {
15518 (attrs = {})[key] = val;
15521 options || (options = {});
15524 if (!this._validate(attrs, options)) return false;
15526 // Extract attributes and options.
15527 unset = options.unset;
15528 silent = options.silent;
15530 changing = this._changing;
15531 this._changing = true;
15534 this._previousAttributes = _.clone(this.attributes);
15537 current = this.attributes, prev = this._previousAttributes;
15539 // Check for changes of `id`.
15540 if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
15542 // For each `set` attribute, update or delete the current value.
15543 for (attr in attrs) {
15545 if (!_.isEqual(current[attr], val)) changes.push(attr);
15546 if (!_.isEqual(prev[attr], val)) {
15547 this.changed[attr] = val;
15549 delete this.changed[attr];
15551 unset ? delete current[attr] : current[attr] = val;
15554 // Trigger all relevant attribute changes.
15556 if (changes.length) this._pending = true;
15557 for (var i = 0, l = changes.length; i < l; i++) {
15558 this.trigger('change:' + changes[i], this, current[changes[i]], options);
15562 // You might be wondering why there's a `while` loop here. Changes can
15563 // be recursively nested within `"change"` events.
15564 if (changing) return this;
15566 while (this._pending) {
15567 this._pending = false;
15568 this.trigger('change', this, options);
15571 this._pending = false;
15572 this._changing = false;
15576 // Remove an attribute from the model, firing `"change"`. `unset` is a noop
15577 // if the attribute doesn't exist.
15578 unset: function(attr, options) {
15579 return this.set(attr, void 0, _.extend({}, options, {unset: true}));
15582 // Clear all attributes on the model, firing `"change"`.
15583 clear: function(options) {
15585 for (var key in this.attributes) attrs[key] = void 0;
15586 return this.set(attrs, _.extend({}, options, {unset: true}));
15589 // Determine if the model has changed since the last `"change"` event.
15590 // If you specify an attribute name, determine if that attribute has changed.
15591 hasChanged: function(attr) {
15592 if (attr == null) return !_.isEmpty(this.changed);
15593 return _.has(this.changed, attr);
15596 // Return an object containing all the attributes that have changed, or
15597 // false if there are no changed attributes. Useful for determining what
15598 // parts of a view need to be updated and/or what attributes need to be
15599 // persisted to the server. Unset attributes will be set to undefined.
15600 // You can also pass an attributes object to diff against the model,
15601 // determining if there *would be* a change.
15602 changedAttributes: function(diff) {
15603 if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
15604 var val, changed = false;
15605 var old = this._changing ? this._previousAttributes : this.attributes;
15606 for (var attr in diff) {
15607 if (_.isEqual(old[attr], (val = diff[attr]))) continue;
15608 (changed || (changed = {}))[attr] = val;
15613 // Get the previous value of an attribute, recorded at the time the last
15614 // `"change"` event was fired.
15615 previous: function(attr) {
15616 if (attr == null || !this._previousAttributes) return null;
15617 return this._previousAttributes[attr];
15620 // Get all of the attributes of the model at the time of the previous
15621 // `"change"` event.
15622 previousAttributes: function() {
15623 return _.clone(this._previousAttributes);
15626 // Fetch the model from the server. If the server's representation of the
15627 // model differs from its current attributes, they will be overridden,
15628 // triggering a `"change"` event.
15629 fetch: function(options) {
15630 options = options ? _.clone(options) : {};
15631 if (options.parse === void 0) options.parse = true;
15633 var success = options.success;
15634 options.success = function(resp) {
15635 if (!model.set(model.parse(resp, options), options)) return false;
15636 if (success) success(model, resp, options);
15637 model.trigger('sync', model, resp, options);
15639 wrapError(this, options);
15640 return this.sync('read', this, options);
15643 // Set a hash of model attributes, and sync the model to the server.
15644 // If the server returns an attributes hash that differs, the model's
15645 // state will be `set` again.
15646 save: function(key, val, options) {
15647 var attrs, method, xhr, attributes = this.attributes;
15649 // Handle both `"key", value` and `{key: value}` -style arguments.
15650 if (key == null || typeof key === 'object') {
15654 (attrs = {})[key] = val;
15657 // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
15658 if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
15660 options = _.extend({validate: true}, options);
15662 // Do not persist invalid models.
15663 if (!this._validate(attrs, options)) return false;
15665 // Set temporary attributes if `{wait: true}`.
15666 if (attrs && options.wait) {
15667 this.attributes = _.extend({}, attributes, attrs);
15670 // After a successful server-side save, the client is (optionally)
15671 // updated with the server-side state.
15672 if (options.parse === void 0) options.parse = true;
15674 var success = options.success;
15675 options.success = function(resp) {
15676 // Ensure attributes are restored during synchronous saves.
15677 model.attributes = attributes;
15678 var serverAttrs = model.parse(resp, options);
15679 if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
15680 if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
15683 if (success) success(model, resp, options);
15684 model.trigger('sync', model, resp, options);
15686 wrapError(this, options);
15688 method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
15689 if (method === 'patch') options.attrs = attrs;
15690 xhr = this.sync(method, this, options);
15692 // Restore attributes.
15693 if (attrs && options.wait) this.attributes = attributes;
15698 // Destroy this model on the server if it was already persisted.
15699 // Optimistically removes the model from its collection, if it has one.
15700 // If `wait: true` is passed, waits for the server to respond before removal.
15701 destroy: function(options) {
15702 options = options ? _.clone(options) : {};
15704 var success = options.success;
15706 var destroy = function() {
15707 model.trigger('destroy', model, model.collection, options);
15710 options.success = function(resp) {
15711 if (options.wait || model.isNew()) destroy();
15712 if (success) success(model, resp, options);
15713 if (!model.isNew()) model.trigger('sync', model, resp, options);
15716 if (this.isNew()) {
15720 wrapError(this, options);
15722 var xhr = this.sync('delete', this, options);
15723 if (!options.wait) destroy();
15727 // Default URL for the model's representation on the server -- if you're
15728 // using Backbone's restful methods, override this to change the endpoint
15729 // that will be called.
15731 var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
15732 if (this.isNew()) return base;
15733 return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
15736 // **parse** converts a response into the hash of attributes to be `set` on
15737 // the model. The default implementation is just to pass the response along.
15738 parse: function(resp, options) {
15742 // Create a new model with identical attributes to this one.
15743 clone: function() {
15744 return new this.constructor(this.attributes);
15747 // A model is new if it has never been saved to the server, and lacks an id.
15748 isNew: function() {
15749 return this.id == null;
15752 // Check if the model is currently in a valid state.
15753 isValid: function(options) {
15754 return this._validate({}, _.extend(options || {}, { validate: true }));
15757 // Run validation against the next complete set of model attributes,
15758 // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
15759 _validate: function(attrs, options) {
15760 if (!options.validate || !this.validate) return true;
15761 attrs = _.extend({}, this.attributes, attrs);
15762 var error = this.validationError = this.validate(attrs, options) || null;
15763 if (!error) return true;
15764 this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
15770 // Underscore methods that we want to implement on the Model.
15771 var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
15773 // Mix in each Underscore method as a proxy to `Model#attributes`.
15774 _.each(modelMethods, function(method) {
15775 Model.prototype[method] = function() {
15776 var args = slice.call(arguments);
15777 args.unshift(this.attributes);
15778 return _[method].apply(_, args);
15782 // Backbone.Collection
15783 // -------------------
15785 // If models tend to represent a single row of data, a Backbone Collection is
15786 // more analagous to a table full of data ... or a small slice or page of that
15787 // table, or a collection of rows that belong together for a particular reason
15788 // -- all of the messages in this particular folder, all of the documents
15789 // belonging to this particular author, and so on. Collections maintain
15790 // indexes of their models, both in order, and for lookup by `id`.
15792 // Create a new **Collection**, perhaps to contain a specific type of `model`.
15793 // If a `comparator` is specified, the Collection will maintain
15794 // its models in sort order, as they're added and removed.
15795 var Collection = Backbone.Collection = function(models, options) {
15796 options || (options = {});
15797 if (options.url) this.url = options.url;
15798 if (options.model) this.model = options.model;
15799 if (options.comparator !== void 0) this.comparator = options.comparator;
15801 this.initialize.apply(this, arguments);
15802 if (models) this.reset(models, _.extend({silent: true}, options));
15805 // Default options for `Collection#set`.
15806 var setOptions = {add: true, remove: true, merge: true};
15807 var addOptions = {add: true, merge: false, remove: false};
15809 // Define the Collection's inheritable methods.
15810 _.extend(Collection.prototype, Events, {
15812 // The default model for a collection is just a **Backbone.Model**.
15813 // This should be overridden in most cases.
15816 // Initialize is an empty function by default. Override it with your own
15817 // initialization logic.
15818 initialize: function(){},
15820 // The JSON representation of a Collection is an array of the
15821 // models' attributes.
15822 toJSON: function(options) {
15823 return this.map(function(model){ return model.toJSON(options); });
15826 // Proxy `Backbone.sync` by default.
15828 return Backbone.sync.apply(this, arguments);
15831 // Add a model, or list of models to the set.
15832 add: function(models, options) {
15833 return this.set(models, _.defaults(options || {}, addOptions));
15836 // Remove a model, or a list of models from the set.
15837 remove: function(models, options) {
15838 models = _.isArray(models) ? models.slice() : [models];
15839 options || (options = {});
15840 var i, l, index, model;
15841 for (i = 0, l = models.length; i < l; i++) {
15842 model = this.get(models[i]);
15843 if (!model) continue;
15844 delete this._byId[model.id];
15845 delete this._byId[model.cid];
15846 index = this.indexOf(model);
15847 this.models.splice(index, 1);
15849 if (!options.silent) {
15850 options.index = index;
15851 model.trigger('remove', model, this, options);
15853 this._removeReference(model);
15858 // Update a collection by `set`-ing a new list of models, adding new ones,
15859 // removing models that are no longer present, and merging models that
15860 // already exist in the collection, as necessary. Similar to **Model#set**,
15861 // the core operation for updating the data contained by the collection.
15862 set: function(models, options) {
15863 options = _.defaults(options || {}, setOptions);
15864 if (options.parse) models = this.parse(models, options);
15865 if (!_.isArray(models)) models = models ? [models] : [];
15866 var i, l, model, attrs, existing, sort;
15867 var at = options.at;
15868 var sortable = this.comparator && (at == null) && options.sort !== false;
15869 var sortAttr = _.isString(this.comparator) ? this.comparator : null;
15870 var toAdd = [], toRemove = [], modelMap = {};
15872 // Turn bare objects into model references, and prevent invalid models
15873 // from being added.
15874 for (i = 0, l = models.length; i < l; i++) {
15875 if (!(model = this._prepareModel(models[i], options))) continue;
15877 // If a duplicate is found, prevent it from being added and
15878 // optionally merge it into the existing model.
15879 if (existing = this.get(model)) {
15880 if (options.remove) modelMap[existing.cid] = true;
15881 if (options.merge) {
15882 existing.set(model.attributes, options);
15883 if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
15886 // This is a new model, push it to the `toAdd` list.
15887 } else if (options.add) {
15890 // Listen to added models' events, and index models for lookup by
15891 // `id` and by `cid`.
15892 model.on('all', this._onModelEvent, this);
15893 this._byId[model.cid] = model;
15894 if (model.id != null) this._byId[model.id] = model;
15898 // Remove nonexistent models if appropriate.
15899 if (options.remove) {
15900 for (i = 0, l = this.length; i < l; ++i) {
15901 if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
15903 if (toRemove.length) this.remove(toRemove, options);
15906 // See if sorting is needed, update `length` and splice in new models.
15907 if (toAdd.length) {
15908 if (sortable) sort = true;
15909 this.length += toAdd.length;
15911 splice.apply(this.models, [at, 0].concat(toAdd));
15913 push.apply(this.models, toAdd);
15917 // Silently sort the collection if appropriate.
15918 if (sort) this.sort({silent: true});
15920 if (options.silent) return this;
15922 // Trigger `add` events.
15923 for (i = 0, l = toAdd.length; i < l; i++) {
15924 (model = toAdd[i]).trigger('add', model, this, options);
15927 // Trigger `sort` if the collection was sorted.
15928 if (sort) this.trigger('sort', this, options);
15932 // When you have more items than you want to add or remove individually,
15933 // you can reset the entire set with a new list of models, without firing
15934 // any granular `add` or `remove` events. Fires `reset` when finished.
15935 // Useful for bulk operations and optimizations.
15936 reset: function(models, options) {
15937 options || (options = {});
15938 for (var i = 0, l = this.models.length; i < l; i++) {
15939 this._removeReference(this.models[i]);
15941 options.previousModels = this.models;
15943 this.add(models, _.extend({silent: true}, options));
15944 if (!options.silent) this.trigger('reset', this, options);
15948 // Add a model to the end of the collection.
15949 push: function(model, options) {
15950 model = this._prepareModel(model, options);
15951 this.add(model, _.extend({at: this.length}, options));
15955 // Remove a model from the end of the collection.
15956 pop: function(options) {
15957 var model = this.at(this.length - 1);
15958 this.remove(model, options);
15962 // Add a model to the beginning of the collection.
15963 unshift: function(model, options) {
15964 model = this._prepareModel(model, options);
15965 this.add(model, _.extend({at: 0}, options));
15969 // Remove a model from the beginning of the collection.
15970 shift: function(options) {
15971 var model = this.at(0);
15972 this.remove(model, options);
15976 // Slice out a sub-array of models from the collection.
15977 slice: function(begin, end) {
15978 return this.models.slice(begin, end);
15981 // Get a model from the set by id.
15982 get: function(obj) {
15983 if (obj == null) return void 0;
15984 return this._byId[obj.id != null ? obj.id : obj.cid || obj];
15987 // Get the model at the given index.
15988 at: function(index) {
15989 return this.models[index];
15992 // Return models with matching attributes. Useful for simple cases of
15994 where: function(attrs, first) {
15995 if (_.isEmpty(attrs)) return first ? void 0 : [];
15996 return this[first ? 'find' : 'filter'](function(model) {
15997 for (var key in attrs) {
15998 if (attrs[key] !== model.get(key)) return false;
16004 // Return the first model with matching attributes. Useful for simple cases
16006 findWhere: function(attrs) {
16007 return this.where(attrs, true);
16010 // Force the collection to re-sort itself. You don't need to call this under
16011 // normal circumstances, as the set will maintain sort order as each item
16013 sort: function(options) {
16014 if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
16015 options || (options = {});
16017 // Run sort based on type of `comparator`.
16018 if (_.isString(this.comparator) || this.comparator.length === 1) {
16019 this.models = this.sortBy(this.comparator, this);
16021 this.models.sort(_.bind(this.comparator, this));
16024 if (!options.silent) this.trigger('sort', this, options);
16028 // Figure out the smallest index at which a model should be inserted so as
16029 // to maintain order.
16030 sortedIndex: function(model, value, context) {
16031 value || (value = this.comparator);
16032 var iterator = _.isFunction(value) ? value : function(model) {
16033 return model.get(value);
16035 return _.sortedIndex(this.models, model, iterator, context);
16038 // Pluck an attribute from each model in the collection.
16039 pluck: function(attr) {
16040 return _.invoke(this.models, 'get', attr);
16043 // Fetch the default set of models for this collection, resetting the
16044 // collection when they arrive. If `reset: true` is passed, the response
16045 // data will be passed through the `reset` method instead of `set`.
16046 fetch: function(options) {
16047 options = options ? _.clone(options) : {};
16048 if (options.parse === void 0) options.parse = true;
16049 var success = options.success;
16050 var collection = this;
16051 options.success = function(resp) {
16052 var method = options.reset ? 'reset' : 'set';
16053 collection[method](resp, options);
16054 if (success) success(collection, resp, options);
16055 collection.trigger('sync', collection, resp, options);
16057 wrapError(this, options);
16058 return this.sync('read', this, options);
16061 // Create a new instance of a model in this collection. Add the model to the
16062 // collection immediately, unless `wait: true` is passed, in which case we
16063 // wait for the server to agree.
16064 create: function(model, options) {
16065 options = options ? _.clone(options) : {};
16066 if (!(model = this._prepareModel(model, options))) return false;
16067 if (!options.wait) this.add(model, options);
16068 var collection = this;
16069 var success = options.success;
16070 options.success = function(resp) {
16071 if (options.wait) collection.add(model, options);
16072 if (success) success(model, resp, options);
16074 model.save(null, options);
16078 // **parse** converts a response into a list of models to be added to the
16079 // collection. The default implementation is just to pass it through.
16080 parse: function(resp, options) {
16084 // Create a new collection with an identical list of models as this one.
16085 clone: function() {
16086 return new this.constructor(this.models);
16089 // Private method to reset all internal state. Called when the collection
16090 // is first initialized or reset.
16091 _reset: function() {
16097 // Prepare a hash of attributes (or other model) to be added to this
16099 _prepareModel: function(attrs, options) {
16100 if (attrs instanceof Model) {
16101 if (!attrs.collection) attrs.collection = this;
16104 options || (options = {});
16105 options.collection = this;
16106 var model = new this.model(attrs, options);
16107 if (!model._validate(attrs, options)) {
16108 this.trigger('invalid', this, attrs, options);
16114 // Internal method to sever a model's ties to a collection.
16115 _removeReference: function(model) {
16116 if (this === model.collection) delete model.collection;
16117 model.off('all', this._onModelEvent, this);
16120 // Internal method called every time a model in the set fires an event.
16121 // Sets need to update their indexes when models change ids. All other
16122 // events simply proxy through. "add" and "remove" events that originate
16123 // in other collections are ignored.
16124 _onModelEvent: function(event, model, collection, options) {
16125 if ((event === 'add' || event === 'remove') && collection !== this) return;
16126 if (event === 'destroy') this.remove(model, options);
16127 if (model && event === 'change:' + model.idAttribute) {
16128 delete this._byId[model.previous(model.idAttribute)];
16129 if (model.id != null) this._byId[model.id] = model;
16131 this.trigger.apply(this, arguments);
16136 // Underscore methods that we want to implement on the Collection.
16137 // 90% of the core usefulness of Backbone Collections is actually implemented
16139 var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
16140 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
16141 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
16142 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
16143 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
16144 'isEmpty', 'chain'];
16146 // Mix in each Underscore method as a proxy to `Collection#models`.
16147 _.each(methods, function(method) {
16148 Collection.prototype[method] = function() {
16149 var args = slice.call(arguments);
16150 args.unshift(this.models);
16151 return _[method].apply(_, args);
16155 // Underscore methods that take a property name as an argument.
16156 var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
16158 // Use attributes instead of properties.
16159 _.each(attributeMethods, function(method) {
16160 Collection.prototype[method] = function(value, context) {
16161 var iterator = _.isFunction(value) ? value : function(model) {
16162 return model.get(value);
16164 return _[method](this.models, iterator, context);
16171 // Backbone Views are almost more convention than they are actual code. A View
16172 // is simply a JavaScript object that represents a logical chunk of UI in the
16173 // DOM. This might be a single item, an entire list, a sidebar or panel, or
16174 // even the surrounding frame which wraps your whole app. Defining a chunk of
16175 // UI as a **View** allows you to define your DOM events declaratively, without
16176 // having to worry about render order ... and makes it easy for the view to
16177 // react to specific changes in the state of your models.
16179 // Creating a Backbone.View creates its initial element outside of the DOM,
16180 // if an existing element is not provided...
16181 var View = Backbone.View = function(options) {
16182 this.cid = _.uniqueId('view');
16183 this._configure(options || {});
16184 this._ensureElement();
16185 this.initialize.apply(this, arguments);
16186 this.delegateEvents();
16189 // Cached regex to split keys for `delegate`.
16190 var delegateEventSplitter = /^(\S+)\s*(.*)$/;
16192 // List of view options to be merged as properties.
16193 var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
16195 // Set up all inheritable **Backbone.View** properties and methods.
16196 _.extend(View.prototype, Events, {
16198 // The default `tagName` of a View's element is `"div"`.
16201 // jQuery delegate for element lookup, scoped to DOM elements within the
16202 // current view. This should be prefered to global lookups where possible.
16203 $: function(selector) {
16204 return this.$el.find(selector);
16207 // Initialize is an empty function by default. Override it with your own
16208 // initialization logic.
16209 initialize: function(){},
16211 // **render** is the core function that your view should override, in order
16212 // to populate its element (`this.el`), with the appropriate HTML. The
16213 // convention is for **render** to always return `this`.
16214 render: function() {
16218 // Remove this view by taking the element out of the DOM, and removing any
16219 // applicable Backbone.Events listeners.
16220 remove: function() {
16222 this.stopListening();
16226 // Change the view's element (`this.el` property), including event
16228 setElement: function(element, delegate) {
16229 if (this.$el) this.undelegateEvents();
16230 this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
16231 this.el = this.$el[0];
16232 if (delegate !== false) this.delegateEvents();
16236 // Set callbacks, where `this.events` is a hash of
16238 // *{"event selector": "callback"}*
16241 // 'mousedown .title': 'edit',
16242 // 'click .button': 'save'
16243 // 'click .open': function(e) { ... }
16246 // pairs. Callbacks will be bound to the view, with `this` set properly.
16247 // Uses event delegation for efficiency.
16248 // Omitting the selector binds the event to `this.el`.
16249 // This only works for delegate-able events: not `focus`, `blur`, and
16250 // not `change`, `submit`, and `reset` in Internet Explorer.
16251 delegateEvents: function(events) {
16252 if (!(events || (events = _.result(this, 'events')))) return this;
16253 this.undelegateEvents();
16254 for (var key in events) {
16255 var method = events[key];
16256 if (!_.isFunction(method)) method = this[events[key]];
16257 if (!method) continue;
16259 var match = key.match(delegateEventSplitter);
16260 var eventName = match[1], selector = match[2];
16261 method = _.bind(method, this);
16262 eventName += '.delegateEvents' + this.cid;
16263 if (selector === '') {
16264 this.$el.on(eventName, method);
16266 this.$el.on(eventName, selector, method);
16272 // Clears all callbacks previously bound to the view with `delegateEvents`.
16273 // You usually don't need to use this, but may wish to if you have multiple
16274 // Backbone views attached to the same DOM element.
16275 undelegateEvents: function() {
16276 this.$el.off('.delegateEvents' + this.cid);
16280 // Performs the initial configuration of a View with a set of options.
16281 // Keys with special meaning *(e.g. model, collection, id, className)* are
16282 // attached directly to the view. See `viewOptions` for an exhaustive
16284 _configure: function(options) {
16285 if (this.options) options = _.extend({}, _.result(this, 'options'), options);
16286 _.extend(this, _.pick(options, viewOptions));
16287 this.options = options;
16290 // Ensure that the View has a DOM element to render into.
16291 // If `this.el` is a string, pass it through `$()`, take the first
16292 // matching element, and re-assign it to `el`. Otherwise, create
16293 // an element from the `id`, `className` and `tagName` properties.
16294 _ensureElement: function() {
16296 var attrs = _.extend({}, _.result(this, 'attributes'));
16297 if (this.id) attrs.id = _.result(this, 'id');
16298 if (this.className) attrs['class'] = _.result(this, 'className');
16299 var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
16300 this.setElement($el, false);
16302 this.setElement(_.result(this, 'el'), false);
16311 // Override this function to change the manner in which Backbone persists
16312 // models to the server. You will be passed the type of request, and the
16313 // model in question. By default, makes a RESTful Ajax request
16314 // to the model's `url()`. Some possible customizations could be:
16316 // * Use `setTimeout` to batch rapid-fire updates into a single request.
16317 // * Send up the models as XML instead of JSON.
16318 // * Persist models via WebSockets instead of Ajax.
16320 // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
16321 // as `POST`, with a `_method` parameter containing the true HTTP method,
16322 // as well as all requests with the body as `application/x-www-form-urlencoded`
16323 // instead of `application/json` with the model in a param named `model`.
16324 // Useful when interfacing with server-side languages like **PHP** that make
16325 // it difficult to read the body of `PUT` requests.
16326 Backbone.sync = function(method, model, options) {
16327 var type = methodMap[method];
16329 // Default options, unless specified.
16330 _.defaults(options || (options = {}), {
16331 emulateHTTP: Backbone.emulateHTTP,
16332 emulateJSON: Backbone.emulateJSON
16335 // Default JSON-request options.
16336 var params = {type: type, dataType: 'json'};
16338 // Ensure that we have a URL.
16339 if (!options.url) {
16340 params.url = _.result(model, 'url') || urlError();
16343 // Ensure that we have the appropriate request data.
16344 if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
16345 params.contentType = 'application/json';
16346 params.data = JSON.stringify(options.attrs || model.toJSON(options));
16349 // For older servers, emulate JSON by encoding the request into an HTML-form.
16350 if (options.emulateJSON) {
16351 params.contentType = 'application/x-www-form-urlencoded';
16352 params.data = params.data ? {model: params.data} : {};
16355 // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
16356 // And an `X-HTTP-Method-Override` header.
16357 if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
16358 params.type = 'POST';
16359 if (options.emulateJSON) params.data._method = type;
16360 var beforeSend = options.beforeSend;
16361 options.beforeSend = function(xhr) {
16362 xhr.setRequestHeader('X-HTTP-Method-Override', type);
16363 if (beforeSend) return beforeSend.apply(this, arguments);
16367 // Don't process data on a non-GET request.
16368 if (params.type !== 'GET' && !options.emulateJSON) {
16369 params.processData = false;
16372 // If we're sending a `PATCH` request, and we're in an old Internet Explorer
16373 // that still has ActiveX enabled by default, override jQuery to use that
16374 // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
16375 if (params.type === 'PATCH' && window.ActiveXObject &&
16376 !(window.external && window.external.msActiveXFilteringEnabled)) {
16377 params.xhr = function() {
16378 return new ActiveXObject("Microsoft.XMLHTTP");
16382 // Make the request, allowing the user to override any Ajax options.
16383 var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
16384 model.trigger('request', model, xhr, options);
16388 // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
16393 'delete': 'DELETE',
16397 // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
16398 // Override this if you'd like to use a different library.
16399 Backbone.ajax = function() {
16400 return Backbone.$.ajax.apply(Backbone.$, arguments);
16406 // Routers map faux-URLs to actions, and fire events when routes are
16407 // matched. Creating a new one sets its `routes` hash, if not set statically.
16408 var Router = Backbone.Router = function(options) {
16409 options || (options = {});
16410 if (options.routes) this.routes = options.routes;
16411 this._bindRoutes();
16412 this.initialize.apply(this, arguments);
16415 // Cached regular expressions for matching named param parts and splatted
16416 // parts of route strings.
16417 var optionalParam = /\((.*?)\)/g;
16418 var namedParam = /(\(\?)?:\w+/g;
16419 var splatParam = /\*\w+/g;
16420 var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
16422 // Set up all inheritable **Backbone.Router** properties and methods.
16423 _.extend(Router.prototype, Events, {
16425 // Initialize is an empty function by default. Override it with your own
16426 // initialization logic.
16427 initialize: function(){},
16429 // Manually bind a single named route to a callback. For example:
16431 // this.route('search/:query/p:num', 'search', function(query, num) {
16435 route: function(route, name, callback) {
16436 if (!_.isRegExp(route)) route = this._routeToRegExp(route);
16437 if (_.isFunction(name)) {
16441 if (!callback) callback = this[name];
16443 Backbone.history.route(route, function(fragment) {
16444 var args = router._extractParameters(route, fragment);
16445 callback && callback.apply(router, args);
16446 router.trigger.apply(router, ['route:' + name].concat(args));
16447 router.trigger('route', name, args);
16448 Backbone.history.trigger('route', router, name, args);
16453 // Simple proxy to `Backbone.history` to save a fragment into the history.
16454 navigate: function(fragment, options) {
16455 Backbone.history.navigate(fragment, options);
16459 // Bind all defined routes to `Backbone.history`. We have to reverse the
16460 // order of the routes here to support behavior where the most general
16461 // routes can be defined at the bottom of the route map.
16462 _bindRoutes: function() {
16463 if (!this.routes) return;
16464 this.routes = _.result(this, 'routes');
16465 var route, routes = _.keys(this.routes);
16466 while ((route = routes.pop()) != null) {
16467 this.route(route, this.routes[route]);
16471 // Convert a route string into a regular expression, suitable for matching
16472 // against the current location hash.
16473 _routeToRegExp: function(route) {
16474 route = route.replace(escapeRegExp, '\\$&')
16475 .replace(optionalParam, '(?:$1)?')
16476 .replace(namedParam, function(match, optional){
16477 return optional ? match : '([^\/]+)';
16479 .replace(splatParam, '(.*?)');
16480 return new RegExp('^' + route + '$');
16483 // Given a route, and a URL fragment that it matches, return the array of
16484 // extracted decoded parameters. Empty or unmatched parameters will be
16485 // treated as `null` to normalize cross-browser behavior.
16486 _extractParameters: function(route, fragment) {
16487 var params = route.exec(fragment).slice(1);
16488 return _.map(params, function(param) {
16489 return param ? decodeURIComponent(param) : null;
16495 // Backbone.History
16496 // ----------------
16498 // Handles cross-browser history management, based on either
16499 // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
16500 // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
16501 // and URL fragments. If the browser supports neither (old IE, natch),
16502 // falls back to polling.
16503 var History = Backbone.History = function() {
16504 this.handlers = [];
16505 _.bindAll(this, 'checkUrl');
16507 // Ensure that `History` can be used outside of the browser.
16508 if (typeof window !== 'undefined') {
16509 this.location = window.location;
16510 this.history = window.history;
16514 // Cached regex for stripping a leading hash/slash and trailing space.
16515 var routeStripper = /^[#\/]|\s+$/g;
16517 // Cached regex for stripping leading and trailing slashes.
16518 var rootStripper = /^\/+|\/+$/g;
16520 // Cached regex for detecting MSIE.
16521 var isExplorer = /msie [\w.]+/;
16523 // Cached regex for removing a trailing slash.
16524 var trailingSlash = /\/$/;
16526 // Has the history handling already been started?
16527 History.started = false;
16529 // Set up all inheritable **Backbone.History** properties and methods.
16530 _.extend(History.prototype, Events, {
16532 // The default interval to poll for hash changes, if necessary, is
16533 // twenty times a second.
16536 // Gets the true hash value. Cannot use location.hash directly due to bug
16537 // in Firefox where location.hash will always be decoded.
16538 getHash: function(window) {
16539 var match = (window || this).location.href.match(/#(.*)$/);
16540 return match ? match[1] : '';
16543 // Get the cross-browser normalized URL fragment, either from the URL,
16544 // the hash, or the override.
16545 getFragment: function(fragment, forcePushState) {
16546 if (fragment == null) {
16547 if (this._hasPushState || !this._wantsHashChange || forcePushState) {
16548 fragment = this.location.pathname;
16549 var root = this.root.replace(trailingSlash, '');
16550 if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
16552 fragment = this.getHash();
16555 return fragment.replace(routeStripper, '');
16558 // Start the hash change handling, returning `true` if the current URL matches
16559 // an existing route, and `false` otherwise.
16560 start: function(options) {
16561 if (History.started) throw new Error("Backbone.history has already been started");
16562 History.started = true;
16564 // Figure out the initial configuration. Do we need an iframe?
16565 // Is pushState desired ... is it available?
16566 this.options = _.extend({}, {root: '/'}, this.options, options);
16567 this.root = this.options.root;
16568 this._wantsHashChange = this.options.hashChange !== false;
16569 this._wantsPushState = !!this.options.pushState;
16570 this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
16571 var fragment = this.getFragment();
16572 var docMode = document.documentMode;
16573 var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
16575 // Normalize root to always include a leading and trailing slash.
16576 this.root = ('/' + this.root + '/').replace(rootStripper, '/');
16578 if (oldIE && this._wantsHashChange) {
16579 this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
16580 this.navigate(fragment);
16583 // Depending on whether we're using pushState or hashes, and whether
16584 // 'onhashchange' is supported, determine how we check the URL state.
16585 if (this._hasPushState) {
16586 Backbone.$(window).on('popstate', this.checkUrl);
16587 } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
16588 Backbone.$(window).on('hashchange', this.checkUrl);
16589 } else if (this._wantsHashChange) {
16590 this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
16593 // Determine if we need to change the base url, for a pushState link
16594 // opened by a non-pushState browser.
16595 this.fragment = fragment;
16596 var loc = this.location;
16597 var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
16599 // If we've started off with a route from a `pushState`-enabled browser,
16600 // but we're currently in a browser that doesn't support it...
16601 if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
16602 this.fragment = this.getFragment(null, true);
16603 this.location.replace(this.root + this.location.search + '#' + this.fragment);
16604 // Return immediately as browser will do redirect to new url
16607 // Or if we've started out with a hash-based route, but we're currently
16608 // in a browser where it could be `pushState`-based instead...
16609 } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
16610 this.fragment = this.getHash().replace(routeStripper, '');
16611 this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
16614 if (!this.options.silent) return this.loadUrl();
16617 // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
16618 // but possibly useful for unit testing Routers.
16620 Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
16621 clearInterval(this._checkUrlInterval);
16622 History.started = false;
16625 // Add a route to be tested when the fragment changes. Routes added later
16626 // may override previous routes.
16627 route: function(route, callback) {
16628 this.handlers.unshift({route: route, callback: callback});
16631 // Checks the current URL to see if it has changed, and if it has,
16632 // calls `loadUrl`, normalizing across the hidden iframe.
16633 checkUrl: function(e) {
16634 var current = this.getFragment();
16635 if (current === this.fragment && this.iframe) {
16636 current = this.getFragment(this.getHash(this.iframe));
16638 if (current === this.fragment) return false;
16639 if (this.iframe) this.navigate(current);
16640 this.loadUrl() || this.loadUrl(this.getHash());
16643 // Attempt to load the current URL fragment. If a route succeeds with a
16644 // match, returns `true`. If no defined routes matches the fragment,
16645 // returns `false`.
16646 loadUrl: function(fragmentOverride) {
16647 var fragment = this.fragment = this.getFragment(fragmentOverride);
16648 var matched = _.any(this.handlers, function(handler) {
16649 if (handler.route.test(fragment)) {
16650 handler.callback(fragment);
16657 // Save a fragment into the hash history, or replace the URL state if the
16658 // 'replace' option is passed. You are responsible for properly URL-encoding
16659 // the fragment in advance.
16661 // The options object can contain `trigger: true` if you wish to have the
16662 // route callback be fired (not usually desirable), or `replace: true`, if
16663 // you wish to modify the current URL without adding an entry to the history.
16664 navigate: function(fragment, options) {
16665 if (!History.started) return false;
16666 if (!options || options === true) options = {trigger: options};
16667 fragment = this.getFragment(fragment || '');
16668 if (this.fragment === fragment) return;
16669 this.fragment = fragment;
16670 var url = this.root + fragment;
16672 // If pushState is available, we use it to set the fragment as a real URL.
16673 if (this._hasPushState) {
16674 this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
16676 // If hash changes haven't been explicitly disabled, update the hash
16677 // fragment to store history.
16678 } else if (this._wantsHashChange) {
16679 this._updateHash(this.location, fragment, options.replace);
16680 if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
16681 // Opening and closing the iframe tricks IE7 and earlier to push a
16682 // history entry on hash-tag change. When replace is true, we don't
16684 if(!options.replace) this.iframe.document.open().close();
16685 this._updateHash(this.iframe.location, fragment, options.replace);
16688 // If you've told us that you explicitly don't want fallback hashchange-
16689 // based history, then `navigate` becomes a page refresh.
16691 return this.location.assign(url);
16693 if (options.trigger) this.loadUrl(fragment);
16696 // Update the hash location, either replacing the current entry, or adding
16697 // a new one to the browser history.
16698 _updateHash: function(location, fragment, replace) {
16700 var href = location.href.replace(/(javascript:|#).*$/, '');
16701 location.replace(href + '#' + fragment);
16703 // Some browsers require that `hash` contains a leading #.
16704 location.hash = '#' + fragment;
16710 // Create the default Backbone.history.
16711 Backbone.history = new History;
16716 // Helper function to correctly set up the prototype chain, for subclasses.
16717 // Similar to `goog.inherits`, but uses a hash of prototype properties and
16718 // class properties to be extended.
16719 var extend = function(protoProps, staticProps) {
16723 // The constructor function for the new subclass is either defined by you
16724 // (the "constructor" property in your `extend` definition), or defaulted
16725 // by us to simply call the parent's constructor.
16726 if (protoProps && _.has(protoProps, 'constructor')) {
16727 child = protoProps.constructor;
16729 child = function(){ return parent.apply(this, arguments); };
16732 // Add static properties to the constructor function, if supplied.
16733 _.extend(child, parent, staticProps);
16735 // Set the prototype chain to inherit from `parent`, without calling
16736 // `parent`'s constructor function.
16737 var Surrogate = function(){ this.constructor = child; };
16738 Surrogate.prototype = parent.prototype;
16739 child.prototype = new Surrogate;
16741 // Add prototype properties (instance properties) to the subclass,
16743 if (protoProps) _.extend(child.prototype, protoProps);
16745 // Set a convenience property in case the parent's prototype is needed
16747 child.__super__ = parent.prototype;
16752 // Set up inheritance for the model, collection, router, view and history.
16753 Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
16755 // Throw an error when a URL is needed, and none is supplied.
16756 var urlError = function() {
16757 throw new Error('A "url" property or function must be specified');
16760 // Wrap an optional error callback with a fallback error event.
16761 var wrapError = function (model, options) {
16762 var error = options.error;
16763 options.error = function(resp) {
16764 if (error) error(model, resp, options);
16765 model.trigger('error', model, resp, options);
16774 // A tiny library for making your live easier when dealing with SVG.
16776 // Copyright © 2012 - 2014 client IO (http://client.io)
16778 (function(root, factory) {
16780 if (typeof define === 'function' && define.amd) {
16781 // AMD. Register as an anonymous module.
16782 define([], factory);
16785 // Browser globals.
16786 root.Vectorizer = root.V = factory();
16789 }(this, function() {
16791 // Well, if SVG is not supported, this library is useless.
16792 var SVGsupported = !!(window.SVGAngle || document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1'));
16796 xmlns: 'http://www.w3.org/2000/svg',
16797 xlink: 'http://www.w3.org/1999/xlink'
16800 var SVGversion = '1.1';
16802 // A function returning a unique identifier for this client session with every call.
16804 function uniqueId() {
16805 var id = ++idCounter + '';
16809 // Create SVG element.
16810 // -------------------
16812 function createElement(el, attrs, children) {
16814 if (!el) return undefined;
16816 // If `el` is an object, it is probably a native SVG element. Wrap it to VElement.
16817 if (typeof el === 'object') {
16818 return new VElement(el);
16820 attrs = attrs || {};
16822 // If `el` is a `'svg'` or `'SVG'` string, create a new SVG canvas.
16823 if (el.toLowerCase() === 'svg') {
16825 attrs.xmlns = ns.xmlns;
16826 attrs['xmlns:xlink'] = ns.xlink;
16827 attrs.version = SVGversion;
16829 } else if (el[0] === '<') {
16830 // Create element from an SVG string.
16831 // Allows constructs of type: `document.appendChild(Vectorizer('<rect></rect>').node)`.
16833 var svg = '<svg xmlns="' + ns.xmlns + '" xmlns:xlink="' + ns.xlink + '" version="' + SVGversion + '">' + el + '</svg>';
16834 var parser = new DOMParser();
16835 parser.async = false;
16836 var svgDoc = parser.parseFromString(svg, 'text/xml').documentElement;
16838 // Note that `createElement()` might also return an array should the SVG string passed as
16839 // the first argument contain more then one root element.
16840 if (svgDoc.childNodes.length > 1) {
16842 // Map child nodes to `VElement`s.
16844 for (var i = 0, len = svgDoc.childNodes.length; i < len; i++) {
16846 var childNode = svgDoc.childNodes[i];
16847 ret.push(new VElement(document.importNode(childNode, true)));
16852 return new VElement(document.importNode(svgDoc.firstChild, true));
16855 el = document.createElementNS(ns.xmlns, el);
16858 for (var key in attrs) {
16860 setAttribute(el, key, attrs[key]);
16863 // Normalize `children` array.
16864 if (Object.prototype.toString.call(children) != '[object Array]') children = [children];
16866 // Append children if they are specified.
16867 var i = 0, len = (children[0] && children.length) || 0, child;
16868 for (; i < len; i++) {
16869 child = children[i];
16870 el.appendChild(child instanceof VElement ? child.node : child);
16873 return new VElement(el);
16876 function setAttribute(el, name, value) {
16878 if (name.indexOf(':') > -1) {
16879 // Attribute names can be namespaced. E.g. `image` elements
16880 // have a `xlink:href` attribute to set the source of the image.
16881 var combinedKey = name.split(':');
16882 el.setAttributeNS(ns[combinedKey[0]], combinedKey[1], value);
16883 } else if (name === 'id') {
16886 el.setAttribute(name, value);
16890 function parseTransformString(transform) {
16896 var translateMatch = transform.match(/translate\((.*)\)/);
16897 if (translateMatch) {
16898 translate = translateMatch[1].split(',');
16900 var rotateMatch = transform.match(/rotate\((.*)\)/);
16902 rotate = rotateMatch[1].split(',');
16904 var scaleMatch = transform.match(/scale\((.*)\)/);
16906 scale = scaleMatch[1].split(',');
16910 var sx = (scale && scale[0]) ? parseFloat(scale[0]) : 1;
16914 tx: (translate && translate[0]) ? parseInt(translate[0], 10) : 0,
16915 ty: (translate && translate[1]) ? parseInt(translate[1], 10) : 0
16918 angle: (rotate && rotate[0]) ? parseInt(rotate[0], 10) : 0,
16919 cx: (rotate && rotate[1]) ? parseInt(rotate[1], 10) : undefined,
16920 cy: (rotate && rotate[2]) ? parseInt(rotate[2], 10) : undefined
16924 sy: (scale && scale[1]) ? parseFloat(scale[1]) : sx
16930 // Matrix decomposition.
16931 // ---------------------
16933 function deltaTransformPoint(matrix, point) {
16935 var dx = point.x * matrix.a + point.y * matrix.c + 0;
16936 var dy = point.x * matrix.b + point.y * matrix.d + 0;
16937 return { x: dx, y: dy };
16940 function decomposeMatrix(matrix) {
16942 // @see https://gist.github.com/2052247
16944 // calculate delta transform point
16945 var px = deltaTransformPoint(matrix, { x: 0, y: 1 });
16946 var py = deltaTransformPoint(matrix, { x: 1, y: 0 });
16949 var skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
16950 var skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x));
16954 translateX: matrix.e,
16955 translateY: matrix.f,
16956 scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
16957 scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
16960 rotation: skewX // rotation is the same as skew x
16967 function VElement(el) {
16969 if (!this.node.id) {
16970 this.node.id = uniqueId();
16974 // VElement public API.
16975 // --------------------
16977 VElement.prototype = {
16979 translate: function(tx, ty) {
16982 var transformAttr = this.attr('transform') || '',
16983 transform = parseTransformString(transformAttr);
16986 if (typeof tx === 'undefined') {
16987 return transform.translate;
16990 transformAttr = transformAttr.replace(/translate\([^\)]*\)/g, '').trim();
16992 var newTx = transform.translate.tx + tx,
16993 newTy = transform.translate.ty + ty,
16994 newTranslate = 'translate(' + newTx + ',' + newTy + ')';
16996 // Note that `translate()` is always the first transformation. This is
16997 // usually the desired case.
16998 this.attr('transform', (newTranslate + ' ' + transformAttr).trim());
17002 rotate: function(angle, cx, cy) {
17003 var transformAttr = this.attr('transform') || '',
17004 transform = parseTransformString(transformAttr);
17007 if (typeof angle === 'undefined') {
17008 return transform.rotate;
17011 transformAttr = transformAttr.replace(/rotate\([^\)]*\)/g, '').trim();
17013 var newAngle = transform.rotate.angle + angle % 360,
17014 newOrigin = (cx !== undefined && cy !== undefined) ? ',' + cx + ',' + cy : '';
17016 this.attr('transform', transformAttr + ' rotate(' + newAngle + newOrigin + ')');
17020 // Note that `scale` as the only transformation does not combine with previous values.
17021 scale: function(sx, sy) {
17022 sy = (typeof sy === 'undefined') ? sx : sy;
17024 var transformAttr = this.attr('transform') || '',
17025 transform = parseTransformString(transformAttr);
17028 if (typeof sx === 'undefined') {
17029 return transform.scale;
17032 transformAttr = transformAttr.replace(/scale\([^\)]*\)/g, '').trim();
17034 this.attr('transform', transformAttr + ' scale(' + sx + ',' + sy + ')');
17038 // Get SVGRect that contains coordinates and dimension of the real bounding box,
17039 // i.e. after transformations are applied.
17040 // If `target` is specified, bounding box will be computed relatively to `target` element.
17041 bbox: function(withoutTransformations, target) {
17043 // If the element is not in the live DOM, it does not have a bounding box defined and
17044 // so fall back to 'zero' dimension element.
17045 if (!this.node.ownerSVGElement) return { x: 0, y: 0, width: 0, height: 0 };
17050 box = this.node.getBBox();
17052 // Opera returns infinite values in some cases.
17053 // Note that Infinity | 0 produces 0 as opposed to Infinity || 0.
17054 // We also have to create new object as the standard says that you can't
17055 // modify the attributes of a bbox.
17056 box = { x: box.x | 0, y: box.y | 0, width: box.width | 0, height: box.height | 0};
17060 // Fallback for IE.
17062 x: this.node.clientLeft,
17063 y: this.node.clientTop,
17064 width: this.node.clientWidth,
17065 height: this.node.clientHeight
17069 if (withoutTransformations) {
17074 var matrix = this.node.getTransformToElement(target || this.node.ownerSVGElement);
17076 var point = this.node.ownerSVGElement.createSVGPoint();
17081 corners.push(point.matrixTransform(matrix));
17083 point.x = box.x + box.width;
17085 corners.push(point.matrixTransform(matrix));
17087 point.x = box.x + box.width;
17088 point.y = box.y + box.height;
17089 corners.push(point.matrixTransform(matrix));
17092 point.y = box.y + box.height;
17093 corners.push(point.matrixTransform(matrix));
17095 var minX = corners[0].x;
17097 var minY = corners[0].y;
17100 for (var i = 1, len = corners.length; i < len; i++) {
17102 var x = corners[i].x;
17103 var y = corners[i].y;
17107 } else if (x > maxX) {
17113 } else if (y > maxY) {
17121 width: maxX - minX,
17122 height: maxY - minY
17126 text: function(content) {
17127 var lines = content.split('\n'), i = 0,
17130 // `alignment-baseline` does not work in Firefox.
17131 // Setting `dominant-baseline` on the `<text>` element doesn't work in IE9.
17132 // In order to have the 0,0 coordinate of the `<text>` element (or the first `<tspan>`)
17133 // in the top left corner we translate the `<text>` element by `0.8em`.
17134 // See `http://www.w3.org/Graphics/SVG/WG/wiki/How_to_determine_dominant_baseline`.
17135 // See also `http://apike.ca/prog_svg_text_style.html`.
17136 this.attr('y', '0.8em');
17138 // An empty text gets rendered into the DOM in webkit-based browsers.
17139 // In order to unify this behaviour across all browsers
17140 // we rather hide the text element when it's empty.
17141 this.attr('display', content ? null : 'none');
17143 if (lines.length === 1) {
17144 this.node.textContent = content;
17147 // Easy way to erase all `<tspan>` children;
17148 this.node.textContent = '';
17150 for (; i < lines.length; i++) {
17152 // Shift all the <tspan> but first by one line (`1em`)
17153 tspan = V('tspan', { dy: (i == 0 ? '0em' : '1em'), x: this.attr('x') || 0});
17154 tspan.node.textContent = lines[i];
17156 this.append(tspan);
17161 attr: function(name, value) {
17163 if (typeof name === 'string' && typeof value === 'undefined') {
17164 return this.node.getAttribute(name);
17167 if (typeof name === 'object') {
17169 for (var attrName in name) {
17170 if (name.hasOwnProperty(attrName)) {
17171 setAttribute(this.node, attrName, name[attrName]);
17177 setAttribute(this.node, name, value);
17183 remove: function() {
17184 if (this.node.parentNode) {
17185 this.node.parentNode.removeChild(this.node);
17189 append: function(el) {
17193 if (Object.prototype.toString.call(el) !== '[object Array]') {
17198 for (var i = 0, len = els.length; i < len; i++) {
17200 this.node.appendChild(el instanceof VElement ? el.node : el);
17206 prepend: function(el) {
17207 this.node.insertBefore(el instanceof VElement ? el.node : el, this.node.firstChild);
17212 return this.node instanceof window.SVGSVGElement ? this : V(this.node.ownerSVGElement);
17217 var defs = this.svg().node.getElementsByTagName('defs');
17219 return (defs && defs.length) ? V(defs[0]) : undefined;
17222 clone: function() {
17223 var clone = V(this.node.cloneNode(true));
17224 // Note that clone inherits also ID. Therefore, we need to change it here.
17225 clone.node.id = uniqueId();
17229 findOne: function(selector) {
17231 var found = this.node.querySelector(selector);
17232 return found ? V(found) : undefined;
17235 find: function(selector) {
17237 var nodes = this.node.querySelectorAll(selector);
17239 // Map DOM elements to `VElement`s.
17240 for (var i = 0, len = nodes.length; i < len; i++) {
17241 nodes[i] = V(nodes[i]);
17246 // Convert global point into the coordinate space of this element.
17247 toLocalPoint: function(x, y) {
17249 var svg = this.svg().node;
17251 var p = svg.createSVGPoint();
17257 var globalPoint = p.matrixTransform(svg.getScreenCTM().inverse());
17258 var globalToLocalMatrix = this.node.getTransformToElement(svg).inverse();
17261 // IE9 throws an exception in odd cases. (`Unexpected call to method or property access`)
17262 // We have to make do with the original coordianates.
17266 return globalPoint.matrixTransform(globalToLocalMatrix);
17269 translateCenterToPoint: function(p) {
17271 var bbox = this.bbox();
17272 var center = g.rect(bbox).center();
17274 this.translate(p.x - center.x, p.y - center.y);
17277 // Efficiently auto-orient an element. This basically implements the orient=auto attribute
17278 // of markers. The easiest way of understanding on what this does is to imagine the element is an
17279 // arrowhead. Calling this method on the arrowhead makes it point to the `position` point while
17280 // being auto-oriented (properly rotated) towards the `reference` point.
17281 // `target` is the element relative to which the transformations are applied. Usually a viewport.
17282 translateAndAutoOrient: function(position, reference, target) {
17284 // Clean-up previously set transformations except the scale. If we didn't clean up the
17285 // previous transformations then they'd add up with the old ones. Scale is an exception as
17286 // it doesn't add up, consider: `this.scale(2).scale(2).scale(2)`. The result is that the
17287 // element is scaled by the factor 2, not 8.
17289 var s = this.scale();
17290 this.attr('transform', '');
17291 this.scale(s.sx, s.sy);
17293 var svg = this.svg().node;
17294 var bbox = this.bbox(false, target);
17296 // 1. Translate to origin.
17297 var translateToOrigin = svg.createSVGTransform();
17298 translateToOrigin.setTranslate(-bbox.x - bbox.width/2, -bbox.y - bbox.height/2);
17300 // 2. Rotate around origin.
17301 var rotateAroundOrigin = svg.createSVGTransform();
17302 var angle = g.point(position).changeInAngle(position.x - reference.x, position.y - reference.y, reference);
17303 rotateAroundOrigin.setRotate(angle, 0, 0);
17305 // 3. Translate to the `position` + the offset (half my width) towards the `reference` point.
17306 var translateFinal = svg.createSVGTransform();
17307 var finalPosition = g.point(position).move(reference, bbox.width/2);
17308 translateFinal.setTranslate(position.x + (position.x - finalPosition.x), position.y + (position.y - finalPosition.y));
17310 // 4. Apply transformations.
17311 var ctm = this.node.getTransformToElement(target);
17312 var transform = svg.createSVGTransform();
17313 transform.setMatrix(
17314 translateFinal.matrix.multiply(
17315 rotateAroundOrigin.matrix.multiply(
17316 translateToOrigin.matrix.multiply(
17320 // Instead of directly setting the `matrix()` transform on the element, first, decompose
17321 // the matrix into separate transforms. This allows us to use normal Vectorizer methods
17322 // as they don't work on matrices. An example of this is to retrieve a scale of an element.
17323 // this.node.transform.baseVal.initialize(transform);
17325 var decomposition = decomposeMatrix(transform.matrix);
17327 this.translate(decomposition.translateX, decomposition.translateY);
17328 this.rotate(decomposition.rotation);
17329 // Note that scale has been already applied, hence the following line stays commented. (it's here just for reference).
17330 //this.scale(decomposition.scaleX, decomposition.scaleY);
17335 animateAlongPath: function(attrs, path) {
17337 var animateMotion = V('animateMotion', attrs);
17338 var mpath = V('mpath', { 'xlink:href': '#' + V(path).node.id });
17340 animateMotion.append(mpath);
17342 this.append(animateMotion);
17344 animateMotion.node.beginElement();
17346 // Fallback for IE 9.
17347 // Run the animation programatically if FakeSmile (`http://leunen.me/fakesmile/`) present
17348 if (document.documentElement.getAttribute('smiling') === 'fake') {
17350 // Register the animation. (See `https://answers.launchpad.net/smil/+question/203333`)
17351 var animation = animateMotion.node;
17352 animation.animators = [];
17354 var animationID = animation.getAttribute('id');
17355 if (animationID) id2anim[animationID] = animation;
17357 var targets = getTargets(animation);
17358 for (var i = 0, len = targets.length; i < len; i++) {
17359 var target = targets[i];
17360 var animator = new Animator(animation, target, i);
17361 animators.push(animator);
17362 animation.animators[i] = animator;
17363 animator.register();
17369 hasClass: function(className) {
17371 return new RegExp('(\\s|^)' + className + '(\\s|$)').test(this.node.getAttribute('class'));
17374 addClass: function(className) {
17376 if (!this.hasClass(className)) {
17377 this.node.setAttribute('class', this.node.getAttribute('class') + ' ' + className);
17383 removeClass: function(className) {
17385 var removedClass = this.node.getAttribute('class').replace(new RegExp('(\\s|^)' + className + '(\\s|$)', 'g'), '$2');
17387 if (this.hasClass(className)) {
17388 this.node.setAttribute('class', removedClass);
17394 toggleClass: function(className, toAdd) {
17396 var toRemove = typeof toAdd === 'undefined' ? this.hasClass(className) : !toAdd;
17399 this.removeClass(className);
17401 this.addClass(className);
17408 // Convert a rectangle to SVG path commands. `r` is an object of the form:
17409 // `{ x: [number], y: [number], width: [number], height: [number], top-ry: [number], top-ry: [number], bottom-rx: [number], bottom-ry: [number] }`,
17410 // where `x, y, width, height` are the usual rectangle attributes and [top-/bottom-]rx/ry allows for
17411 // specifying radius of the rectangle for all its sides (as opposed to the built-in SVG rectangle
17412 // that has only `rx` and `ry` attributes).
17413 function rectToPath(r) {
17415 var topRx = r.rx || r['top-rx'] || 0;
17416 var bottomRx = r.rx || r['bottom-rx'] || 0;
17417 var topRy = r.ry || r['top-ry'] || 0;
17418 var bottomRy = r.ry || r['bottom-ry'] || 0;
17421 'M', r.x, r.y + topRy,
17422 'v', r.height - topRy - bottomRy,
17423 'a', bottomRx, bottomRy, 0, 0, 0, bottomRx, bottomRy,
17424 'h', r.width - 2 * bottomRx,
17425 'a', bottomRx, bottomRy, 0, 0, 0, bottomRx, -bottomRy,
17426 'v', -(r.height - bottomRy - topRy),
17427 'a', topRx, topRy, 0, 0, 0, -topRx, -topRy,
17428 'h', -(r.width - 2 * topRx),
17429 'a', topRx, topRy, 0, 0, 0, -topRx, topRy
17433 var V = createElement;
17435 V.decomposeMatrix = decomposeMatrix;
17436 V.rectToPath = rectToPath;
17438 var svgDocument = V('svg').node;
17440 V.createSVGMatrix = function(m) {
17442 var svgMatrix = svgDocument.createSVGMatrix();
17443 for (var component in m) {
17444 svgMatrix[component] = m[component];
17450 V.createSVGTransform = function() {
17452 return svgDocument.createSVGTransform();
17455 V.createSVGPoint = function(x, y) {
17457 var p = svgDocument.createSVGPoint();
17468 // Geometry library.
17469 // (c) 2011-2013 client IO
17472 (function(root, factory) {
17474 if (typeof define === 'function' && define.amd) {
17475 // AMD. Register as an anonymous module.
17476 define([], factory);
17478 } else if (typeof exports === 'object') {
17479 // Node. Does not work with strict CommonJS, but
17480 // only CommonJS-like environments that support module.exports,
17482 module.exports = factory();
17485 // Browser globals.
17486 root.g = factory();
17489 }(this, function() {
17492 // Declare shorthands to the most used math functions.
17494 var abs = math.abs;
17495 var cos = math.cos;
17496 var sin = math.sin;
17497 var sqrt = math.sqrt;
17498 var mmin = math.min;
17499 var mmax = math.max;
17500 var atan = math.atan;
17501 var atan2 = math.atan2;
17502 var acos = math.acos;
17503 var round = math.round;
17504 var floor = math.floor;
17506 var random = math.random;
17507 var toDeg = function(rad) { return (180*rad / PI) % 360; };
17508 var toRad = function(deg) { return (deg % 360) * PI / 180; };
17509 var snapToGrid = function(val, gridSize) { return gridSize * Math.round(val/gridSize); };
17510 var normalizeAngle = function(angle) { return (angle % 360) + (angle < 0 ? 360 : 0); };
17515 // Point is the most basic object consisting of x/y coordinate,.
17517 // Possible instantiations are:
17519 // * `point(10, 20)`
17520 // * `new point(10, 20)`
17521 // * `point('10 20')`
17522 // * `point(point(10, 20))`
17523 function point(x, y) {
17524 if (!(this instanceof point))
17525 return new point(x, y);
17527 if (y === undefined && Object(x) !== x) {
17528 xy = x.split(x.indexOf('@') === -1 ? ' ' : '@');
17529 this.x = parseInt(xy[0], 10);
17530 this.y = parseInt(xy[1], 10);
17531 } else if (Object(x) === x) {
17540 point.prototype = {
17541 toString: function() {
17542 return this.x + "@" + this.y;
17544 // If point lies outside rectangle `r`, return the nearest point on the boundary of rect `r`,
17545 // otherwise return point itself.
17546 // (see Squeak Smalltalk, Point>>adhereTo:)
17547 adhereToRect: function(r) {
17548 if (r.containsPoint(this)){
17551 this.x = mmin(mmax(this.x, r.x), r.x + r.width);
17552 this.y = mmin(mmax(this.y, r.y), r.y + r.height);
17555 // Compute the angle between me and `p` and the x axis.
17556 // (cartesian-to-polar coordinates conversion)
17557 // Return theta angle in degrees.
17558 theta: function(p) {
17560 // Invert the y-axis.
17561 var y = -(p.y - this.y);
17562 var x = p.x - this.x;
17563 // Makes sure that the comparison with zero takes rounding errors into account.
17564 var PRECISION = 10;
17565 // Note that `atan2` is not defined for `x`, `y` both equal zero.
17566 var rad = (y.toFixed(PRECISION) == 0 && x.toFixed(PRECISION) == 0) ? 0 : atan2(y, x);
17568 // Correction for III. and IV. quadrant.
17572 return 180*rad / PI;
17574 // Returns distance between me and point `p`.
17575 distance: function(p) {
17576 return line(this, p).length();
17578 // Returns a manhattan (taxi-cab) distance between me and point `p`.
17579 manhattanDistance: function(p) {
17580 return abs(p.x - this.x) + abs(p.y - this.y);
17582 // Offset me by the specified amount.
17583 offset: function(dx, dy) {
17588 magnitude: function() {
17589 return sqrt((this.x*this.x) + (this.y*this.y)) || 0.01;
17591 update: function(x, y) {
17596 round: function(decimals) {
17597 this.x = decimals ? this.x.toFixed(decimals) : round(this.x);
17598 this.y = decimals ? this.y.toFixed(decimals) : round(this.y);
17601 // Scale the line segment between (0,0) and me to have a length of len.
17602 normalize: function(len) {
17603 var s = (len || 1) / this.magnitude();
17604 this.x = s * this.x;
17605 this.y = s * this.y;
17608 difference: function(p) {
17609 return point(this.x - p.x, this.y - p.y);
17611 // Return the bearing between me and point `p`.
17612 bearing: function(p) {
17613 return line(this, p).bearing();
17615 // Converts rectangular to polar coordinates.
17616 // An origin can be specified, otherwise it's 0@0.
17617 toPolar: function(o) {
17618 o = (o && point(o)) || point(0,0);
17621 this.x = sqrt((x-o.x)*(x-o.x) + (y-o.y)*(y-o.y)); // r
17622 this.y = toRad(o.theta(point(x,y)));
17625 // Rotate point by angle around origin o.
17626 rotate: function(o, angle) {
17627 angle = (angle + 360) % 360;
17629 this.y += toRad(angle);
17630 var p = point.fromPolar(this.x, this.y, o);
17635 // Move point on line starting from ref ending at me by
17636 // distance distance.
17637 move: function(ref, distance) {
17638 var theta = toRad(point(ref).theta(this));
17639 return this.offset(cos(theta) * distance, -sin(theta) * distance);
17641 // Returns change in angle from my previous position (-dx, -dy) to my new position
17642 // relative to ref point.
17643 changeInAngle: function(dx, dy, ref) {
17644 // Revert the translation and measure the change in angle around x-axis.
17645 return point(this).offset(-dx, -dy).theta(ref) - this.theta(ref);
17647 equals: function(p) {
17648 return this.x === p.x && this.y === p.y;
17650 snapToGrid: function(gx, gy) {
17651 this.x = snapToGrid(this.x, gx)
17652 this.y = snapToGrid(this.y, gy || gx)
17656 // Alternative constructor, from polar coordinates.
17657 // @param {number} r Distance.
17658 // @param {number} angle Angle in radians.
17659 // @param {point} [optional] o Origin.
17660 point.fromPolar = function(r, angle, o) {
17661 o = (o && point(o)) || point(0,0);
17662 var x = abs(r * cos(angle));
17663 var y = abs(r * sin(angle));
17664 var deg = normalizeAngle(toDeg(angle));
17666 if (deg < 90) y = -y;
17667 else if (deg < 180) { x = -x; y = -y; }
17668 else if (deg < 270) x = -x;
17670 return point(o.x + x, o.y + y);
17673 // Create a point with random coordinates that fall into the range `[x1, x2]` and `[y1, y2]`.
17674 point.random = function(x1, x2, y1, y2) {
17675 return point(floor(random() * (x2 - x1 + 1) + x1), floor(random() * (y2 - y1 + 1) + y1));
17680 function line(p1, p2) {
17681 if (!(this instanceof line))
17682 return new line(p1, p2);
17683 this.start = point(p1);
17684 this.end = point(p2);
17688 toString: function() {
17689 return this.start.toString() + ' ' + this.end.toString();
17691 // @return {double} length of the line
17692 length: function() {
17693 return sqrt(this.squaredLength());
17695 // @return {integer} length without sqrt
17696 // @note for applications where the exact length is not necessary (e.g. compare only)
17697 squaredLength: function() {
17698 var x0 = this.start.x;
17699 var y0 = this.start.y;
17700 var x1 = this.end.x;
17701 var y1 = this.end.y;
17702 return (x0 -= x1)*x0 + (y0 -= y1)*y0;
17704 // @return {point} my midpoint
17705 midpoint: function() {
17706 return point((this.start.x + this.end.x) / 2,
17707 (this.start.y + this.end.y) / 2);
17709 // @return {point} Point where I'm intersecting l.
17710 // @see Squeak Smalltalk, LineSegment>>intersectionWith:
17711 intersection: function(l) {
17712 var pt1Dir = point(this.end.x - this.start.x, this.end.y - this.start.y);
17713 var pt2Dir = point(l.end.x - l.start.x, l.end.y - l.start.y);
17714 var det = (pt1Dir.x * pt2Dir.y) - (pt1Dir.y * pt2Dir.x);
17715 var deltaPt = point(l.start.x - this.start.x, l.start.y - this.start.y);
17716 var alpha = (deltaPt.x * pt2Dir.y) - (deltaPt.y * pt2Dir.x);
17717 var beta = (deltaPt.x * pt1Dir.y) - (deltaPt.y * pt1Dir.x);
17722 // No intersection found.
17726 if (alpha > det || beta > det){
17730 if (alpha < det || beta < det){
17734 return point(this.start.x + (alpha * pt1Dir.x / det),
17735 this.start.y + (alpha * pt1Dir.y / det));
17738 // @return the bearing (cardinal direction) of the line. For example N, W, or SE.
17739 // @returns {String} One of the following bearings : NE, E, SE, S, SW, W, NW, N.
17740 bearing: function() {
17742 var lat1 = toRad(this.start.y);
17743 var lat2 = toRad(this.end.y);
17744 var lon1 = this.start.x;
17745 var lon2 = this.end.x;
17746 var dLon = toRad(lon2 - lon1);
17747 var y = sin(dLon) * cos(lat2);
17748 var x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
17749 var brng = toDeg(atan2(y, x));
17751 var bearings = ['NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N'];
17753 var index = brng - 22.5;
17756 index = parseInt(index / 45);
17758 return bearings[index];
17764 function rect(x, y, w, h) {
17765 if (!(this instanceof rect))
17766 return new rect(x, y, w, h);
17767 if (y === undefined) {
17780 toString: function() {
17781 return this.origin().toString() + ' ' + this.corner().toString();
17783 origin: function() {
17784 return point(this.x, this.y);
17786 corner: function() {
17787 return point(this.x + this.width, this.y + this.height);
17789 topRight: function() {
17790 return point(this.x + this.width, this.y);
17792 bottomLeft: function() {
17793 return point(this.x, this.y + this.height);
17795 center: function() {
17796 return point(this.x + this.width/2, this.y + this.height/2);
17798 // @return {boolean} true if rectangles intersect
17799 intersect: function(r) {
17800 var myOrigin = this.origin();
17801 var myCorner = this.corner();
17802 var rOrigin = r.origin();
17803 var rCorner = r.corner();
17805 if (rCorner.x <= myOrigin.x ||
17806 rCorner.y <= myOrigin.y ||
17807 rOrigin.x >= myCorner.x ||
17808 rOrigin.y >= myCorner.y) return false;
17811 // @return {string} (left|right|top|bottom) side which is nearest to point
17812 // @see Squeak Smalltalk, Rectangle>>sideNearestTo:
17813 sideNearestToPoint: function(p) {
17815 var distToLeft = p.x - this.x;
17816 var distToRight = (this.x + this.width) - p.x;
17817 var distToTop = p.y - this.y;
17818 var distToBottom = (this.y + this.height) - p.y;
17819 var closest = distToLeft;
17822 if (distToRight < closest) {
17823 closest = distToRight;
17826 if (distToTop < closest) {
17827 closest = distToTop;
17830 if (distToBottom < closest) {
17831 closest = distToBottom;
17836 // @return {bool} true if point p is insight me
17837 containsPoint: function(p) {
17839 if (p.x >= this.x && p.x <= this.x + this.width &&
17840 p.y >= this.y && p.y <= this.y + this.height) {
17845 // Algorithm ported from java.awt.Rectangle from OpenJDK.
17846 // @return {bool} true if rectangle `r` is inside me.
17847 containsRect: function(r) {
17848 var nr = rect(r).normalize();
17853 var w = this.width;
17854 var h = this.height;
17855 if ((w | h | W | H) < 0) {
17856 // At least one of the dimensions is negative...
17859 // Note: if any dimension is zero, tests below must return false...
17862 if (X < x || Y < y) {
17868 // X+W overflowed or W was zero, return false if...
17869 // either original w or W was zero or
17870 // x+w did not overflow or
17871 // the overflowed x+w is smaller than the overflowed X+W
17872 if (w >= x || W > w) return false;
17874 // X+W did not overflow and W was not zero, return false if...
17875 // original w was zero or
17876 // x+w did not overflow and x+w is smaller than X+W
17877 if (w >= x && W > w) return false;
17882 if (h >= y || H > h) return false;
17884 if (h >= y && H > h) return false;
17888 // @return {point} a point on my boundary nearest to p
17889 // @see Squeak Smalltalk, Rectangle>>pointNearestTo:
17890 pointNearestToPoint: function(p) {
17892 if (this.containsPoint(p)) {
17893 var side = this.sideNearestToPoint(p);
17895 case "right": return point(this.x + this.width, p.y);
17896 case "left": return point(this.x, p.y);
17897 case "bottom": return point(p.x, this.y + this.height);
17898 case "top": return point(p.x, this.y);
17901 return p.adhereToRect(this);
17903 // Find point on my boundary where line starting
17904 // from my center ending in point p intersects me.
17905 // @param {number} angle If angle is specified, intersection with rotated rectangle is computed.
17906 intersectionWithLineFromCenterToPoint: function(p, angle) {
17908 var center = point(this.x + this.width/2, this.y + this.height/2);
17910 if (angle) p.rotate(center, angle);
17912 // (clockwise, starting from the top side)
17914 line(this.origin(), this.topRight()),
17915 line(this.topRight(), this.corner()),
17916 line(this.corner(), this.bottomLeft()),
17917 line(this.bottomLeft(), this.origin())
17919 var connector = line(center, p);
17921 for (var i = sides.length - 1; i >= 0; --i){
17922 var intersection = sides[i].intersection(connector);
17923 if (intersection !== null){
17924 result = intersection;
17928 if (result && angle) result.rotate(center, -angle);
17931 // Move and expand me.
17932 // @param r {rectangle} representing deltas
17933 moveAndExpand: function(r) {
17936 this.width += r.width;
17937 this.height += r.height;
17940 round: function(decimals) {
17941 this.x = decimals ? this.x.toFixed(decimals) : round(this.x);
17942 this.y = decimals ? this.y.toFixed(decimals) : round(this.y);
17943 this.width = decimals ? this.width.toFixed(decimals) : round(this.width);
17944 this.height = decimals ? this.height.toFixed(decimals) : round(this.height);
17947 // Normalize the rectangle; i.e., make it so that it has a non-negative width and height.
17948 // If width < 0 the function swaps the left and right corners,
17949 // and it swaps the top and bottom corners if height < 0
17950 // like in http://qt-project.org/doc/qt-4.8/qrectf.html#normalized
17951 normalize: function() {
17954 var newwidth = this.width;
17955 var newheight = this.height;
17956 if (this.width < 0) {
17957 newx = this.x + this.width;
17958 newwidth = -this.width;
17960 if (this.height < 0) {
17961 newy = this.y + this.height;
17962 newheight = -this.height;
17966 this.width = newwidth;
17967 this.height = newheight;
17974 function ellipse(c, a, b) {
17975 if (!(this instanceof ellipse))
17976 return new ellipse(c, a, b);
17984 ellipse.prototype = {
17985 toString: function() {
17986 return point(this.x, this.y).toString() + ' ' + this.a + ' ' + this.b;
17989 return rect(this.x - this.a, this.y - this.b, 2*this.a, 2*this.b);
17991 // Find point on me where line from my center to
17992 // point p intersects my boundary.
17993 // @param {number} angle If angle is specified, intersection with rotated ellipse is computed.
17994 intersectionWithLineFromCenterToPoint: function(p, angle) {
17996 if (angle) p.rotate(point(this.x, this.y), angle);
17997 var dx = p.x - this.x;
17998 var dy = p.y - this.y;
18001 result = this.bbox().pointNearestToPoint(p);
18002 if (angle) return result.rotate(point(this.x, this.y), -angle);
18006 var mSquared = m * m;
18007 var aSquared = this.a * this.a;
18008 var bSquared = this.b * this.b;
18009 var x = sqrt(1 / ((1 / aSquared) + (mSquared / bSquared)));
18011 x = dx < 0 ? -x : x;
18013 result = point(this.x + x, this.y + y);
18014 if (angle) return result.rotate(point(this.x, this.y), -angle);
18022 // Cubic Bezier curve path through points.
18023 // Ported from C# implementation by Oleg V. Polikarpotchkin and Peter Lee (http://www.codeproject.com/KB/graphics/BezierSpline.aspx).
18024 // @param {array} points Array of points through which the smooth line will go.
18025 // @return {array} SVG Path commands as an array
18026 curveThroughPoints: function(points) {
18027 var controlPoints = this.getCurveControlPoints(points);
18028 var path = ['M', points[0].x, points[0].y];
18030 for (var i = 0; i < controlPoints[0].length; i++) {
18031 path.push('C', controlPoints[0][i].x, controlPoints[0][i].y, controlPoints[1][i].x, controlPoints[1][i].y, points[i+1].x, points[i+1].y);
18036 // Get open-ended Bezier Spline Control Points.
18037 // @param knots Input Knot Bezier spline points (At least two points!).
18038 // @param firstControlPoints Output First Control points. Array of knots.length - 1 length.
18039 // @param secondControlPoints Output Second Control points. Array of knots.length - 1 length.
18040 getCurveControlPoints: function(knots) {
18041 var firstControlPoints = [];
18042 var secondControlPoints = [];
18043 var n = knots.length - 1;
18046 // Special case: Bezier curve should be a straight line.
18049 firstControlPoints[0] = point((2 * knots[0].x + knots[1].x) / 3,
18050 (2 * knots[0].y + knots[1].y) / 3);
18052 secondControlPoints[0] = point(2 * firstControlPoints[0].x - knots[0].x,
18053 2 * firstControlPoints[0].y - knots[0].y);
18054 return [firstControlPoints, secondControlPoints];
18057 // Calculate first Bezier control points.
18058 // Right hand side vector.
18061 // Set right hand side X values.
18062 for (i = 1; i < n - 1; i++) {
18063 rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
18065 rhs[0] = knots[0].x + 2 * knots[1].x;
18066 rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2.0;
18067 // Get first control points X-values.
18068 var x = this.getFirstControlPoints(rhs);
18070 // Set right hand side Y values.
18071 for (i = 1; i < n - 1; ++i) {
18072 rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
18074 rhs[0] = knots[0].y + 2 * knots[1].y;
18075 rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y) / 2.0;
18076 // Get first control points Y-values.
18077 var y = this.getFirstControlPoints(rhs);
18079 // Fill output arrays.
18080 for (i = 0; i < n; i++) {
18081 // First control point.
18082 firstControlPoints.push(point(x[i], y[i]));
18083 // Second control point.
18085 secondControlPoints.push(point(2 * knots [i + 1].x - x[i + 1],
18086 2 * knots[i + 1].y - y[i + 1]));
18088 secondControlPoints.push(point((knots[n].x + x[n - 1]) / 2,
18089 (knots[n].y + y[n - 1]) / 2));
18092 return [firstControlPoints, secondControlPoints];
18095 // Solves a tridiagonal system for one of coordinates (x or y) of first Bezier control points.
18096 // @param rhs Right hand side vector.
18097 // @return Solution vector.
18098 getFirstControlPoints: function(rhs) {
18099 var n = rhs.length;
18100 // `x` is a solution vector.
18106 // Decomposition and forward substitution.
18107 for (var i = 1; i < n; i++) {
18109 b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
18110 x[i] = (rhs[i] - x[i - 1]) / b;
18112 for (i = 1; i < n; i++) {
18113 // Backsubstitution.
18114 x[n - i - 1] -= tmp[n - i] * x[n - i];
18123 // Return the `value` from the `domain` interval scaled to the `range` interval.
18124 linear: function(domain, range, value) {
18126 var domainSpan = domain[1] - domain[0];
18127 var rangeSpan = range[1] - range[0];
18128 return (((value - domain[0]) / domainSpan) * rangeSpan + range[0]) || 0;
18136 snapToGrid: snapToGrid,
18137 normalizeAngle: normalizeAngle,
18147 // JointJS library.
18148 // (c) 2011-2013 client IO
18150 if (typeof exports === 'object') {
18152 var _ = require('lodash');
18156 // Global namespace.
18160 // `joint.dia` namespace.
18163 // `joint.ui` namespace.
18166 // `joint.layout` namespace.
18169 // `joint.shapes` namespace.
18172 // `joint.format` namespace.
18175 // `joint.connectors` namespace.
18178 // `joint.routers` namespace.
18183 // Return a simple hash code from a string. See http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/.
18184 hashCode: function(str) {
18187 if (str.length == 0) return hash;
18188 for (var i = 0; i < str.length; i++) {
18189 var c = str.charCodeAt(i);
18190 hash = ((hash << 5) - hash) + c;
18191 hash = hash & hash; // Convert to 32bit integer
18196 getByPath: function(obj, path, delim) {
18198 delim = delim || '.';
18199 var keys = path.split(delim);
18202 while (keys.length) {
18203 key = keys.shift();
18213 setByPath: function(obj, path, value, delim) {
18215 delim = delim || '.';
18217 var keys = path.split(delim);
18221 if (path.indexOf(delim) > -1) {
18223 for (var len = keys.length; i < len - 1; i++) {
18224 // diver creates an empty object if there is no nested object under such a key.
18225 // This means that one can populate an empty nested object with setByPath().
18226 diver = diver[keys[i]] || (diver[keys[i]] = {});
18228 diver[keys[len - 1]] = value;
18235 unsetByPath: function(obj, path, delim) {
18237 delim = delim || '.';
18239 // index of the last delimiter
18240 var i = path.lastIndexOf(delim);
18244 // unsetting a nested attribute
18245 var parent = joint.util.getByPath(obj, path.substr(0, i), delim);
18249 delete parent[path.slice(i + 1)];
18254 // unsetting a primitive attribute
18261 flattenObject: function(obj, delim, stop) {
18263 delim = delim || '.';
18266 for (var key in obj) {
18267 if (!obj.hasOwnProperty(key)) continue;
18269 var shouldGoDeeper = typeof obj[key] === 'object';
18270 if (shouldGoDeeper && stop && stop(obj[key])) {
18271 shouldGoDeeper = false;
18274 if (shouldGoDeeper) {
18275 var flatObject = this.flattenObject(obj[key], delim, stop);
18276 for (var flatKey in flatObject) {
18277 if (!flatObject.hasOwnProperty(flatKey)) continue;
18279 ret[key + delim + flatKey] = flatObject[flatKey];
18282 ret[key] = obj[key];
18290 // credit: http://stackoverflow.com/posts/2117523/revisions
18292 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
18293 var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
18294 return v.toString(16);
18298 // Generate global unique id for obj and store it as a property of the object.
18299 guid: function(obj) {
18301 this.guid.id = this.guid.id || 1;
18302 obj.id = (obj.id === undefined ? 'j_' + this.guid.id++ : obj.id);
18306 // Copy all the properties to the first argument from the following arguments.
18307 // All the properties will be overwritten by the properties from the following
18308 // arguments. Inherited properties are ignored.
18309 mixin: function() {
18311 var target = arguments[0];
18313 for (var i = 1, l = arguments.length; i < l; i++) {
18315 var extension = arguments[i];
18317 // Only functions and objects can be mixined.
18319 if ((Object(extension) !== extension) &&
18320 !_.isFunction(extension) &&
18321 (extension === null || extension === undefined)) {
18326 _.each(extension, function(copy, key) {
18328 if (this.mixin.deep && (Object(copy) === copy)) {
18330 if (!target[key]) {
18332 target[key] = _.isArray(copy) ? [] : {};
18335 this.mixin(target[key], copy);
18339 if (target[key] !== copy) {
18341 if (!this.mixin.supplement || !target.hasOwnProperty(key)) {
18343 target[key] = copy;
18354 // Copy all properties to the first argument from the following
18355 // arguments only in case if they don't exists in the first argument.
18356 // All the function propererties in the first argument will get
18357 // additional property base pointing to the extenders same named
18358 // property function's call method.
18359 supplement: function() {
18361 this.mixin.supplement = true;
18362 var ret = this.mixin.apply(this, arguments);
18363 this.mixin.supplement = false;
18367 // Same as `mixin()` but deep version.
18368 deepMixin: function() {
18370 this.mixin.deep = true;
18371 var ret = this.mixin.apply(this, arguments);
18372 this.mixin.deep = false;
18376 // Same as `supplement()` but deep version.
18377 deepSupplement: function() {
18379 this.mixin.deep = this.mixin.supplement = true;
18380 var ret = this.mixin.apply(this, arguments);
18381 this.mixin.deep = this.mixin.supplement = false;
18385 normalizeEvent: function(evt) {
18387 return (evt.originalEvent && evt.originalEvent.changedTouches && evt.originalEvent.changedTouches.length) ? evt.originalEvent.changedTouches[0] : evt;
18390 nextFrame:(function() {
18393 var client = typeof window != 'undefined';
18397 raf = window.requestAnimationFrame ||
18398 window.webkitRequestAnimationFrame ||
18399 window.mozRequestAnimationFrame ||
18400 window.oRequestAnimationFrame ||
18401 window.msRequestAnimationFrame;
18409 raf = function(callback) {
18411 var currTime = new Date().getTime();
18412 var timeToCall = Math.max(0, 16 - (currTime - lastTime));
18413 var id = setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
18414 lastTime = currTime + timeToCall;
18420 return client ? _.bind(raf, window) : raf;
18423 cancelFrame: (function() {
18426 var client = typeof window != 'undefined';
18430 caf = window.cancelAnimationFrame ||
18431 window.webkitCancelAnimationFrame ||
18432 window.webkitCancelRequestAnimationFrame ||
18433 window.msCancelAnimationFrame ||
18434 window.msCancelRequestAnimationFrame ||
18435 window.oCancelAnimationFrame ||
18436 window.oCancelRequestAnimationFrame ||
18437 window.mozCancelAnimationFrame ||
18438 window.mozCancelRequestAnimationFrame;
18442 caf = caf || clearTimeout;
18444 return client ? _.bind(caf, window) : caf;
18447 breakText: function(text, size, styles, opt) {
18451 var width = size.width;
18452 var height = size.height;
18454 var svgDocument = opt.svgDocument || V('svg').node;
18455 var textElement = V('<text><tspan></tspan></text>').attr(styles || {}).node;
18456 var textSpan = textElement.firstChild;
18457 var textNode = document.createTextNode('');
18459 textSpan.appendChild(textNode);
18461 svgDocument.appendChild(textElement);
18463 if (!opt.svgDocument) {
18465 document.body.appendChild(svgDocument);
18468 var words = text.split(' ');
18473 for (var i = 0, l = 0, len = words.length; i < len; i++) {
18475 var word = words[i];
18477 textNode.data = lines[l] ? lines[l] + ' ' + word : word;
18479 if (textSpan.getComputedTextLength() <= width) {
18481 // the current line fits
18482 lines[l] = textNode.data;
18485 // We were partitioning. Put rest of the word onto next line
18488 // cancel partitioning
18494 if (!lines[l] || p) {
18496 var partition = !!p;
18498 p = word.length - 1;
18500 if (partition || !p) {
18502 // word has only one character.
18507 // we won't fit this text within our rect
18513 // partitioning didn't help on the non-empty line
18514 // try again, but this time start with a new line
18516 // cancel partitions created
18517 words.splice(i,2, word + words[i+1]);
18519 // adjust word length
18528 // move last letter to the beginning of the next word
18529 words[i] = word.substring(0,p);
18530 words[i+1] = word.substring(p) + words[i+1];
18534 // We initiate partitioning
18535 // split the long word into two words
18536 words.splice(i, 1, word.substring(0,p), word.substring(p));
18538 // adjust words length
18541 if (l && !full[l-1]) {
18542 // if the previous line is not full, try to fit max part of
18543 // the current word there
18557 // if size.height is defined we have to check whether the height of the entire
18558 // text exceeds the rect height
18559 if (typeof height !== 'undefined') {
18561 // get line height as text height / 0.8 (as text height is approx. 0.8em
18562 // and line height is 1em. See vectorizer.text())
18563 var lh = lh || textElement.getBBox().height * 1.25;
18565 if (lh * lines.length > height) {
18567 // remove overflowing lines
18568 lines.splice(Math.floor(height / lh));
18575 if (opt.svgDocument) {
18577 // svg document was provided, remove the text element only
18578 svgDocument.removeChild(textElement);
18582 // clean svg document
18583 document.body.removeChild(svgDocument);
18586 return lines.join('\n');
18591 linear: function(t) {
18595 quad: function(t) {
18599 cubic: function(t) {
18603 inout: function(t) {
18604 if (t <= 0) return 0;
18605 if (t >= 1) return 1;
18606 var t2 = t * t, t3 = t2 * t;
18607 return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
18610 exponential: function(t) {
18611 return Math.pow(2, 10 * (t - 1));
18614 bounce: function(t) {
18615 for(var a = 0, b = 1; 1; a += b, b /= 2) {
18616 if (t >= (7 - 4 * a) / 11) {
18617 var q = (11 - 6 * a - 11 * t) / 4;
18618 return -q * q + b * b;
18623 reverse: function(f) {
18624 return function(t) {
18625 return 1 - f(1 - t)
18629 reflect: function(f) {
18630 return function(t) {
18631 return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
18635 clamp: function(f,n,x) {
18638 return function(t) {
18640 return r < n ? n : r > x ? x : r;
18644 back: function(s) {
18645 if (!s) s = 1.70158;
18646 return function(t) {
18647 return t * t * ((s + 1) * t - s);
18651 elastic: function(x) {
18653 return function(t) {
18654 return Math.pow(2, 10 * (t - 1)) * Math.cos(20*Math.PI*x/3*t);
18662 number: function(a, b) {
18664 return function(t) { return a + d * t; };
18667 object: function(a, b) {
18669 return function(t) {
18671 for (i = s.length - 1; i != -1; i--) {
18673 r[p] = a[p] + (b[p] - a[p]) * t;
18679 hexColor: function(a, b) {
18681 var ca = parseInt(a.slice(1), 16), cb = parseInt(b.slice(1), 16);
18683 var ra = ca & 0x0000ff, rd = (cb & 0x0000ff) - ra;
18684 var ga = ca & 0x00ff00, gd = (cb & 0x00ff00) - ga;
18685 var ba = ca & 0xff0000, bd = (cb & 0xff0000) - ba;
18687 return function(t) {
18688 var r = (ra + rd * t) & 0x000000ff;
18689 var g = (ga + gd * t) & 0x0000ff00;
18690 var b = (ba + bd * t) & 0x00ff0000;
18691 return '#' + (1 << 24 | r | g | b ).toString(16).slice(1);
18695 unit: function(a, b) {
18697 var r = /(-?[0-9]*.[0-9]*)(px|em|cm|mm|in|pt|pc|%)/;
18699 var ma = r.exec(a), mb = r.exec(b);
18700 var p = mb[1].indexOf('.'), f = p > 0 ? mb[1].length - p - 1 : 0;
18701 var a = +ma[1], d = +mb[1] - a, u = ma[2];
18703 return function(t) {
18704 return (a + d * t).toFixed(f) + u;
18712 // `x` ... horizontal blur
18713 // `y` ... vertical blur (optional)
18714 blur: function(args) {
18716 var x = _.isFinite(args.x) ? args.x : 2;
18718 return _.template('<filter><feGaussianBlur stdDeviation="${stdDeviation}"/></filter>', {
18719 stdDeviation: _.isFinite(args.y) ? [x, args.y] : x
18723 // `dx` ... horizontal shift
18724 // `dy` ... vertical shift
18726 // `color` ... color
18727 // `opacity` ... opacity
18728 dropShadow: function(args) {
18730 var tpl = 'SVGFEDropShadowElement' in window
18731 ? '<filter><feDropShadow stdDeviation="${blur}" dx="${dx}" dy="${dy}" flood-color="${color}" flood-opacity="${opacity}"/></filter>'
18732 : '<filter><feGaussianBlur in="SourceAlpha" stdDeviation="${blur}"/><feOffset dx="${dx}" dy="${dy}" result="offsetblur"/><feFlood flood-color="${color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="${opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge></filter>';
18734 return _.template(tpl, {
18737 opacity: _.isFinite(args.opacity) ? args.opacity : 1,
18738 color: args.color || 'black',
18739 blur: _.isFinite(args.blur) ? args.blur : 4
18743 // `amount` ... the proportion of the conversion. A value of 1 is completely grayscale. A value of 0 leaves the input unchanged.
18744 grayscale: function(args) {
18746 var amount = _.isFinite(args.amount) ? args.amount : 1;
18748 return _.template('<filter><feColorMatrix type="matrix" values="${a} ${b} ${c} 0 0 ${d} ${e} ${f} 0 0 ${g} ${b} ${h} 0 0 0 0 0 1 0"/></filter>', {
18749 a: 0.2126 + 0.7874 * (1 - amount),
18750 b: 0.7152 - 0.7152 * (1 - amount),
18751 c: 0.0722 - 0.0722 * (1 - amount),
18752 d: 0.2126 - 0.2126 * (1 - amount),
18753 e: 0.7152 + 0.2848 * (1 - amount),
18754 f: 0.0722 - 0.0722 * (1 - amount),
18755 g: 0.2126 - 0.2126 * (1 - amount),
18756 h: 0.0722 + 0.9278 * (1 - amount)
18760 // `amount` ... the proportion of the conversion. A value of 1 is completely sepia. A value of 0 leaves the input unchanged.
18761 sepia: function(args) {
18763 var amount = _.isFinite(args.amount) ? args.amount : 1;
18765 return _.template('<filter><feColorMatrix type="matrix" values="${a} ${b} ${c} 0 0 ${d} ${e} ${f} 0 0 ${g} ${h} ${i} 0 0 0 0 0 1 0"/></filter>', {
18766 a: 0.393 + 0.607 * (1 - amount),
18767 b: 0.769 - 0.769 * (1 - amount),
18768 c: 0.189 - 0.189 * (1 - amount),
18769 d: 0.349 - 0.349 * (1 - amount),
18770 e: 0.686 + 0.314 * (1 - amount),
18771 f: 0.168 - 0.168 * (1 - amount),
18772 g: 0.272 - 0.272 * (1 - amount),
18773 h: 0.534 - 0.534 * (1 - amount),
18774 i: 0.131 + 0.869 * (1 - amount)
18778 // `amount` ... the proportion of the conversion. A value of 0 is completely un-saturated. A value of 1 leaves the input unchanged.
18779 saturate: function(args) {
18781 var amount = _.isFinite(args.amount) ? args.amount : 1;
18783 return _.template('<filter><feColorMatrix type="saturate" values="${amount}"/></filter>', {
18788 // `angle` ... the number of degrees around the color circle the input samples will be adjusted.
18789 hueRotate: function(args) {
18791 return _.template('<filter><feColorMatrix type="hueRotate" values="${angle}"/></filter>', {
18792 angle: args.angle || 0
18796 // `amount` ... the proportion of the conversion. A value of 1 is completely inverted. A value of 0 leaves the input unchanged.
18797 invert: function(args) {
18799 var amount = _.isFinite(args.amount) ? args.amount : 1;
18801 return _.template('<filter><feComponentTransfer><feFuncR type="table" tableValues="${amount} ${amount2}"/><feFuncG type="table" tableValues="${amount} ${amount2}"/><feFuncB type="table" tableValues="${amount} ${amount2}"/></feComponentTransfer></filter>', {
18803 amount2: 1 - amount
18807 // `amount` ... proportion of the conversion. A value of 0 will create an image that is completely black. A value of 1 leaves the input unchanged.
18808 brightness: function(args) {
18810 return _.template('<filter><feComponentTransfer><feFuncR type="linear" slope="${amount}"/><feFuncG type="linear" slope="${amount}"/><feFuncB type="linear" slope="${amount}"/></feComponentTransfer></filter>', {
18811 amount: _.isFinite(args.amount) ? args.amount : 1
18815 // `amount` ... proportion of the conversion. A value of 0 will create an image that is completely black. A value of 1 leaves the input unchanged.
18816 contrast: function(args) {
18818 var amount = _.isFinite(args.amount) ? args.amount : 1;
18820 return _.template('<filter><feComponentTransfer><feFuncR type="linear" slope="${amount}" intercept="${amount2}"/><feFuncG type="linear" slope="${amount}" intercept="${amount2}"/><feFuncB type="linear" slope="${amount}" intercept="${amount2}"/></feComponentTransfer></filter>', {
18822 amount2: .5 - amount / 2
18829 // Formatting numbers via the Python Format Specification Mini-language.
18830 // See http://docs.python.org/release/3.1.3/library/string.html#format-specification-mini-language.
18831 // Heavilly inspired by the D3.js library implementation.
18832 number: function(specifier, value, locale) {
18834 locale = locale || {
18836 currency: ['$', ''],
18842 // See Python format specification mini-language: http://docs.python.org/release/3.1.3/library/string.html#format-specification-mini-language.
18843 // [[fill]align][sign][symbol][0][width][,][.precision][type]
18844 var re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
18846 var match = re.exec(specifier);
18847 var fill = match[1] || ' ';
18848 var align = match[2] || '>';
18849 var sign = match[3] || '';
18850 var symbol = match[4] || '';
18851 var zfill = match[5];
18852 var width = +match[6];
18853 var comma = match[7];
18854 var precision = match[8];
18855 var type = match[9];
18859 var integer = false;
18861 if (precision) precision = +precision.substring(1);
18863 if (zfill || fill === '0' && align === '=') {
18864 zfill = fill = '0';
18866 if (comma) width -= Math.floor((width - 1) / 4);
18870 case 'n': comma = true; type = 'g'; break;
18871 case '%': scale = 100; suffix = '%'; type = 'f'; break;
18872 case 'p': scale = 100; suffix = '%'; type = 'r'; break;
18876 case 'X': if (symbol === '#') prefix = '0' + type.toLowerCase();
18878 case 'd': integer = true; precision = 0; break;
18879 case 's': scale = -1; type = 'r'; break;
18882 if (symbol === '$') {
18883 prefix = locale.currency[0];
18884 suffix = locale.currency[1];
18887 // If no precision is specified for `'r'`, fallback to general notation.
18888 if (type == 'r' && !precision) type = 'g';
18890 // Ensure that the requested precision is in the supported range.
18891 if (precision != null) {
18892 if (type == 'g') precision = Math.max(1, Math.min(21, precision));
18893 else if (type == 'e' || type == 'f') precision = Math.max(0, Math.min(20, precision));
18896 var zcomma = zfill && comma;
18898 // Return the empty string for floats formatted as ints.
18899 if (integer && (value % 1)) return '';
18901 // Convert negative to positive, and record the sign prefix.
18902 var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, '-') : sign;
18904 var fullSuffix = suffix;
18906 // Apply the scale, computing it from the value's exponent for si format.
18907 // Preserve the existing suffix, if any, such as the currency symbol.
18909 var unit = this.prefix(value, precision);
18910 value = unit.scale(value);
18911 fullSuffix = unit.symbol + suffix;
18916 // Convert to the desired precision.
18917 value = this.convert(type, value, precision);
18919 // Break the value into the integer part (before) and decimal part (after).
18920 var i = value.lastIndexOf('.');
18921 var before = i < 0 ? value : value.substring(0, i);
18922 var after = i < 0 ? '' : locale.decimal + value.substring(i + 1);
18924 function formatGroup(value) {
18926 var i = value.length;
18929 var g = locale.grouping[0];
18930 while (i > 0 && g > 0) {
18931 t.push(value.substring(i -= g, i + g));
18932 g = locale.grouping[j = (j + 1) % locale.grouping.length];
18934 return t.reverse().join(locale.thousands);
18937 // If the fill character is not `'0'`, grouping is applied before padding.
18938 if (!zfill && comma && locale.grouping) {
18940 before = formatGroup(before);
18943 var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length);
18944 var padding = length < width ? new Array(length = width - length + 1).join(fill) : '';
18946 // If the fill character is `'0'`, grouping is applied after padding.
18947 if (zcomma) before = formatGroup(padding + before);
18950 negative += prefix;
18952 // Rejoin integer and decimal parts.
18953 value = before + after;
18955 return (align === '<' ? negative + value + padding
18956 : align === '>' ? padding + negative + value
18957 : align === '^' ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length)
18958 : negative + (zcomma ? value : padding + value)) + fullSuffix;
18961 convert: function(type, value, precision) {
18964 case 'b': return value.toString(2);
18965 case 'c': return String.fromCharCode(value);
18966 case 'o': return value.toString(8);
18967 case 'x': return value.toString(16);
18968 case 'X': return value.toString(16).toUpperCase();
18969 case 'g': return value.toPrecision(precision);
18970 case 'e': return value.toExponential(precision);
18971 case 'f': return value.toFixed(precision);
18972 case 'r': return (value = this.round(value, this.precision(value, precision))).toFixed(Math.max(0, Math.min(20, this.precision(value * (1 + 1e-15), precision))));
18973 default: return value + '';
18977 round: function(value, precision) {
18980 ? Math.round(value * (precision = Math.pow(10, precision))) / precision
18981 : Math.round(value);
18984 precision: function(value, precision) {
18986 return precision - (value ? Math.ceil(Math.log(value) / Math.LN10) : 1);
18989 prefix: function(value, precision) {
18991 var prefixes = _.map(['y','z','a','f','p','n','µ','m','','k','M','G','T','P','E','Z','Y'], function(d, i) {
18992 var k = Math.pow(10, abs(8 - i) * 3);
18994 scale: i > 8 ? function(d) { return d / k; } : function(d) { return d * k; },
19001 if (value < 0) value *= -1;
19002 if (precision) value = d3.round(value, this.precision(value, precision));
19003 i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
19004 i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
19006 return prefixes[8 + i / 3];
19012 if (typeof exports === 'object') {
19014 module.exports = joint;
19017 // JointJS, the JavaScript diagramming library.
19018 // (c) 2011-2013 client IO
19021 if (typeof exports === 'object') {
19025 Link: require('./joint.dia.link').Link,
19026 Element: require('./joint.dia.element').Element
19028 shapes: require('../plugins/shapes')
19030 var Backbone = require('backbone');
19031 var _ = require('lodash');
19032 var g = require('./geometry');
19037 joint.dia.GraphCells = Backbone.Collection.extend({
19039 initialize: function() {
19041 // Backbone automatically doesn't trigger re-sort if models attributes are changed later when
19042 // they're already in the collection. Therefore, we're triggering sort manually here.
19043 this.on('change:z', this.sort, this);
19046 model: function(attrs, options) {
19048 if (attrs.type === 'link') {
19050 return new joint.dia.Link(attrs, options);
19053 var module = attrs.type.split('.')[0];
19054 var entity = attrs.type.split('.')[1];
19056 if (joint.shapes[module] && joint.shapes[module][entity]) {
19058 return new joint.shapes[module][entity](attrs, options);
19061 return new joint.dia.Element(attrs, options);
19064 // `comparator` makes it easy to sort cells based on their `z` index.
19065 comparator: function(model) {
19067 return model.get('z') || 0;
19070 // Get all inbound and outbound links connected to the cell `model`.
19071 getConnectedLinks: function(model, opt) {
19075 if (_.isUndefined(opt.inbound) && _.isUndefined(opt.outbound)) {
19076 opt.inbound = opt.outbound = true;
19081 this.each(function(cell) {
19083 var source = cell.get('source');
19084 var target = cell.get('target');
19086 if (source && source.id === model.id && opt.outbound) {
19091 if (target && target.id === model.id && opt.inbound) {
19102 joint.dia.Graph = Backbone.Model.extend({
19104 initialize: function() {
19106 this.set('cells', new joint.dia.GraphCells);
19108 // Make all the events fired in the `cells` collection available.
19109 // to the outside world.
19110 this.get('cells').on('all', this.trigger, this);
19112 this.get('cells').on('remove', this.removeCell, this);
19115 toJSON: function() {
19117 // Backbone does not recursively call `toJSON()` on attributes that are themselves models/collections.
19118 // It just clones the attributes. Therefore, we must call `toJSON()` on the cells collection explicitely.
19119 var json = Backbone.Model.prototype.toJSON.apply(this, arguments);
19120 json.cells = this.get('cells').toJSON();
19124 fromJSON: function(json) {
19128 throw new Error('Graph JSON must contain cells array.');
19133 // Cells are the only attribute that is being set differently, using `cells.add()`.
19134 var cells = json.cells;
19135 delete attrs.cells;
19139 this.resetCells(cells);
19142 clear: function() {
19144 this.trigger('batch:start');
19145 this.get('cells').remove(this.get('cells').models);
19146 this.trigger('batch:stop');
19149 _prepareCell: function(cell) {
19151 if (cell instanceof Backbone.Model && _.isUndefined(cell.get('z'))) {
19153 cell.set('z', this.maxZIndex() + 1, { silent: true });
19155 } else if (_.isUndefined(cell.z)) {
19157 cell.z = this.maxZIndex() + 1;
19163 maxZIndex: function() {
19165 var lastCell = this.get('cells').last();
19166 return lastCell ? (lastCell.get('z') || 0) : 0;
19169 addCell: function(cell, options) {
19171 if (_.isArray(cell)) {
19173 return this.addCells(cell, options);
19176 this.get('cells').add(this._prepareCell(cell), options || {});
19181 addCells: function(cells, options) {
19183 _.each(cells, function(cell) { this.addCell(cell, options); }, this);
19188 // When adding a lot of cells, it is much more efficient to
19189 // reset the entire cells collection in one go.
19190 // Useful for bulk operations and optimizations.
19191 resetCells: function(cells) {
19193 this.get('cells').reset(_.map(cells, this._prepareCell, this));
19198 removeCell: function(cell, collection, options) {
19200 // Applications might provide a `disconnectLinks` option set to `true` in order to
19201 // disconnect links when a cell is removed rather then removing them. The default
19202 // is to remove all the associated links.
19203 if (options && options.disconnectLinks) {
19205 this.disconnectLinks(cell);
19209 this.removeLinks(cell);
19212 // Silently remove the cell from the cells collection. Silently, because
19213 // `joint.dia.Cell.prototype.remove` already triggers the `remove` event which is
19214 // then propagated to the graph model. If we didn't remove the cell silently, two `remove` events
19215 // would be triggered on the graph model.
19216 this.get('cells').remove(cell, { silent: true });
19219 // Get a cell by `id`.
19220 getCell: function(id) {
19222 return this.get('cells').get(id);
19225 getElements: function() {
19227 return this.get('cells').filter(function(cell) {
19229 return cell instanceof joint.dia.Element;
19233 getLinks: function() {
19235 return this.get('cells').filter(function(cell) {
19237 return cell instanceof joint.dia.Link;
19241 // Get all inbound and outbound links connected to the cell `model`.
19242 getConnectedLinks: function(model, opt) {
19244 return this.get('cells').getConnectedLinks(model, opt);
19247 getNeighbors: function(el) {
19249 var links = this.getConnectedLinks(el);
19250 var neighbors = [];
19251 var cells = this.get('cells');
19253 _.each(links, function(link) {
19255 var source = link.get('source');
19256 var target = link.get('target');
19258 // Discard if it is a point.
19260 var sourceElement = cells.get(source.id);
19261 if (sourceElement !== el) {
19263 neighbors.push(sourceElement);
19267 var targetElement = cells.get(target.id);
19268 if (targetElement !== el) {
19270 neighbors.push(targetElement);
19278 // Disconnect links connected to the cell `model`.
19279 disconnectLinks: function(model) {
19281 _.each(this.getConnectedLinks(model), function(link) {
19283 link.set(link.get('source').id === model.id ? 'source' : 'target', g.point(0, 0));
19287 // Remove links connected to the cell `model` completely.
19288 removeLinks: function(model) {
19290 _.invoke(this.getConnectedLinks(model), 'remove');
19293 // Find all views at given point
19294 findModelsFromPoint: function(p) {
19296 return _.filter(this.getElements(), function(el) {
19297 return el.getBBox().containsPoint(p);
19302 // Find all views in given area
19303 findModelsInArea: function(r) {
19305 return _.filter(this.getElements(), function(el) {
19306 return el.getBBox().intersect(r);
19313 if (typeof exports === 'object') {
19315 module.exports.Graph = joint.dia.Graph;
19318 // (c) 2011-2013 client IO
19321 if (typeof exports === 'object') {
19324 util: require('./core').util,
19326 Link: require('./joint.dia.link').Link
19329 var Backbone = require('backbone');
19330 var _ = require('lodash');
19334 // joint.dia.Cell base model.
19335 // --------------------------
19337 joint.dia.Cell = Backbone.Model.extend({
19339 // This is the same as Backbone.Model with the only difference that is uses _.merge
19340 // instead of just _.extend. The reason is that we want to mixin attributes set in upper classes.
19341 constructor: function(attributes, options) {
19344 var attrs = attributes || {};
19345 this.cid = _.uniqueId('c');
19346 this.attributes = {};
19347 if (options && options.collection) this.collection = options.collection;
19348 if (options && options.parse) attrs = this.parse(attrs, options) || {};
19349 if (defaults = _.result(this, 'defaults')) {
19351 // Replaced the call to _.defaults with _.merge.
19352 attrs = _.merge({}, defaults, attrs);
19355 this.set(attrs, options);
19357 this.initialize.apply(this, arguments);
19360 toJSON: function() {
19362 var defaultAttrs = this.constructor.prototype.defaults.attrs || {};
19363 var attrs = this.attributes.attrs;
19364 var finalAttrs = {};
19366 // Loop through all the attributes and
19367 // omit the default attributes as they are implicitly reconstructable by the cell 'type'.
19368 _.each(attrs, function(attr, selector) {
19370 var defaultAttr = defaultAttrs[selector];
19372 _.each(attr, function(value, name) {
19374 // attr is mainly flat though it might have one more level (consider the `style` attribute).
19375 // Check if the `value` is object and if yes, go one level deep.
19376 if (_.isObject(value) && !_.isArray(value)) {
19378 _.each(value, function(value2, name2) {
19380 if (!defaultAttr || !defaultAttr[name] || !_.isEqual(defaultAttr[name][name2], value2)) {
19382 finalAttrs[selector] = finalAttrs[selector] || {};
19383 (finalAttrs[selector][name] || (finalAttrs[selector][name] = {}))[name2] = value2;
19387 } else if (!defaultAttr || !_.isEqual(defaultAttr[name], value)) {
19388 // `value` is not an object, default attribute for such a selector does not exist
19389 // or it is different than the attribute value set on the model.
19391 finalAttrs[selector] = finalAttrs[selector] || {};
19392 finalAttrs[selector][name] = value;
19397 var attributes = _.cloneDeep(_.omit(this.attributes, 'attrs'));
19398 //var attributes = JSON.parse(JSON.stringify(_.omit(this.attributes, 'attrs')));
19399 attributes.attrs = finalAttrs;
19404 initialize: function(options) {
19406 if (!options || !options.id) {
19408 this.set('id', joint.util.uuid(), { silent: true });
19411 this._transitionIds = {};
19413 // Collect ports defined in `attrs` and keep collecting whenever `attrs` object changes.
19414 this.processPorts();
19415 this.on('change:attrs', this.processPorts, this);
19418 processPorts: function() {
19420 // Whenever `attrs` changes, we extract ports from the `attrs` object and store it
19421 // in a more accessible way. Also, if any port got removed and there were links that had `target`/`source`
19422 // set to that port, we remove those links as well (to follow the same behaviour as
19423 // with a removed element).
19425 var previousPorts = this.ports;
19427 // Collect ports from the `attrs` object.
19429 _.each(this.get('attrs'), function(attrs, selector) {
19431 if (attrs && attrs.port) {
19433 // `port` can either be directly an `id` or an object containing an `id` (and potentially other data).
19434 if (!_.isUndefined(attrs.port.id)) {
19435 ports[attrs.port.id] = attrs.port;
19437 ports[attrs.port] = { id: attrs.port };
19442 // Collect ports that have been removed (compared to the previous ports) - if any.
19443 // Use hash table for quick lookup.
19444 var removedPorts = {};
19445 _.each(previousPorts, function(port, id) {
19447 if (!ports[id]) removedPorts[id] = true;
19450 // Remove all the incoming/outgoing links that have source/target port set to any of the removed ports.
19451 if (this.collection && !_.isEmpty(removedPorts)) {
19453 var inboundLinks = this.collection.getConnectedLinks(this, { inbound: true });
19454 _.each(inboundLinks, function(link) {
19456 if (removedPorts[link.get('target').port]) link.remove();
19459 var outboundLinks = this.collection.getConnectedLinks(this, { outbound: true });
19460 _.each(outboundLinks, function(link) {
19462 if (removedPorts[link.get('source').port]) link.remove();
19466 // Update the `ports` object.
19467 this.ports = ports;
19470 remove: function(options) {
19472 var collection = this.collection;
19475 collection.trigger('batch:start');
19478 // First, unembed this cell from its parent cell if there is one.
19479 var parentCellId = this.get('parent');
19480 if (parentCellId) {
19482 var parentCell = this.collection && this.collection.get(parentCellId);
19483 parentCell.unembed(this);
19486 _.invoke(this.getEmbeddedCells(), 'remove', options);
19488 this.trigger('remove', this, this.collection, options);
19491 collection.trigger('batch:stop');
19495 toFront: function() {
19497 if (this.collection) {
19499 this.set('z', (this.collection.last().get('z') || 0) + 1);
19503 toBack: function() {
19505 if (this.collection) {
19507 this.set('z', (this.collection.first().get('z') || 0) - 1);
19511 embed: function(cell) {
19513 if (this.get('parent') == cell.id) {
19515 throw new Error('Recursive embedding not allowed.');
19519 this.trigger('batch:start');
19521 cell.set('parent', this.id);
19522 this.set('embeds', _.uniq((this.get('embeds') || []).concat([cell.id])));
19524 this.trigger('batch:stop');
19528 unembed: function(cell) {
19530 this.trigger('batch:start');
19532 var cellId = cell.id;
19533 cell.unset('parent');
19535 this.set('embeds', _.without(this.get('embeds'), cellId));
19537 this.trigger('batch:stop');
19540 getEmbeddedCells: function() {
19542 // Cell models can only be retrieved when this element is part of a collection.
19543 // There is no way this element knows about other cells otherwise.
19544 // This also means that calling e.g. `translate()` on an element with embeds before
19545 // adding it to a graph does not translate its embeds.
19546 if (this.collection) {
19548 return _.map(this.get('embeds') || [], function(cellId) {
19550 return this.collection.get(cellId);
19557 clone: function(opt) {
19561 var clone = Backbone.Model.prototype.clone.apply(this, arguments);
19563 // We don't want the clone to have the same ID as the original.
19564 clone.set('id', joint.util.uuid(), { silent: true });
19565 clone.set('embeds', '');
19567 if (!opt.deep) return clone;
19569 // The rest of the `clone()` method deals with embeds. If `deep` option is set to `true`,
19570 // the return value is an array of all the embedded clones created.
19572 var embeds = this.getEmbeddedCells();
19574 var clones = [clone];
19576 // This mapping stores cloned links under the `id`s of they originals.
19577 // This prevents cloning a link more then once. Consider a link 'self loop' for example.
19578 var linkCloneMapping = {};
19580 _.each(embeds, function(embed) {
19582 var embedClones = embed.clone({ deep: true });
19584 // Embed the first clone returned from `clone({ deep: true })` above. The first
19585 // cell is always the clone of the cell that called the `clone()` method, i.e. clone of `embed` in this case.
19586 clone.embed(embedClones[0]);
19588 _.each(embedClones, function(embedClone) {
19590 clones.push(embedClone);
19592 // Skip links. Inbound/outbound links are not relevant for them.
19593 if (embedClone instanceof joint.dia.Link) {
19598 // Collect all inbound links, clone them (if not done already) and set their target to the `embedClone.id`.
19599 var inboundLinks = this.collection.getConnectedLinks(embed, { inbound: true });
19601 _.each(inboundLinks, function(link) {
19603 var linkClone = linkCloneMapping[link.id] || link.clone();
19605 // Make sure we don't clone a link more then once.
19606 linkCloneMapping[link.id] = linkClone;
19608 var target = _.clone(linkClone.get('target'));
19609 target.id = embedClone.id;
19610 linkClone.set('target', target);
19613 // Collect all inbound links, clone them (if not done already) and set their source to the `embedClone.id`.
19614 var outboundLinks = this.collection.getConnectedLinks(embed, { outbound: true });
19616 _.each(outboundLinks, function(link) {
19618 var linkClone = linkCloneMapping[link.id] || link.clone();
19620 // Make sure we don't clone a link more then once.
19621 linkCloneMapping[link.id] = linkClone;
19623 var source = _.clone(linkClone.get('source'));
19624 source.id = embedClone.id;
19625 linkClone.set('source', source);
19632 // Add link clones to the array of all the new clones.
19633 clones = clones.concat(_.values(linkCloneMapping));
19638 // A convenient way to set nested attributes.
19639 attr: function(attrs, value, opt) {
19641 var currentAttrs = this.get('attrs');
19644 if (_.isString(attrs)) {
19645 // Get/set an attribute by a special path syntax that delimits
19646 // nested objects by the colon character.
19648 if (typeof value != 'undefined') {
19651 joint.util.setByPath(attr, attrs, value, delim);
19652 return this.set('attrs', _.merge({}, currentAttrs, attr), opt);
19656 return joint.util.getByPath(currentAttrs, attrs, delim);
19660 return this.set('attrs', _.merge({}, currentAttrs, attrs), value, opt);
19663 // A convenient way to unset nested attributes
19664 removeAttr: function(path, opt) {
19666 if (_.isArray(path)) {
19667 _.each(path, function(p) { this.removeAttr(p, opt); }, this);
19671 var attrs = joint.util.unsetByPath(_.merge({}, this.get('attrs')), path, '/');
19673 return this.set('attrs', attrs, _.extend({ dirty: true }, opt));
19676 transition: function(path, value, opt, delim) {
19678 delim = delim || '/';
19683 timingFunction: joint.util.timing.linear,
19684 valueFunction: joint.util.interpolate.number
19687 opt = _.extend(defaults, opt);
19689 var pathArray = path.split(delim);
19690 var property = pathArray[0];
19691 var isPropertyNested = pathArray.length > 1;
19692 var firstFrameTime = 0;
19693 var interpolatingFunction;
19695 var setter = _.bind(function(runtime) {
19697 var id, progress, propertyValue, status;
19699 firstFrameTime = firstFrameTime || runtime;
19700 runtime -= firstFrameTime;
19701 progress = runtime / opt.duration;
19703 if (progress < 1) {
19704 this._transitionIds[path] = id = joint.util.nextFrame(setter);
19707 delete this._transitionIds[path];
19710 propertyValue = interpolatingFunction(opt.timingFunction(progress));
19712 if (isPropertyNested) {
19713 var nestedPropertyValue = joint.util.setByPath({}, path, propertyValue, delim)[property];
19714 propertyValue = _.merge({}, this.get(property), nestedPropertyValue);
19717 opt.transitionId = id;
19719 this.set(property, propertyValue, opt);
19721 if (!id) this.trigger('transition:end', this, path);
19725 var initiator =_.bind(function(callback) {
19727 this.stopTransitions(path);
19729 interpolatingFunction = opt.valueFunction(joint.util.getByPath(this.attributes, path, delim), value);
19731 this._transitionIds[path] = joint.util.nextFrame(callback);
19733 this.trigger('transition:start', this, path);
19737 return _.delay(initiator, opt.delay, setter);
19740 getTransitions: function() {
19741 return _.keys(this._transitionIds);
19744 stopTransitions: function(path, delim) {
19746 delim = delim || '/';
19748 var pathArray = path && path.split(delim);
19750 _(this._transitionIds).keys().filter(pathArray && function(key) {
19752 return _.isEqual(pathArray, key.split(delim).slice(0, pathArray.length));
19754 }).each(function(key) {
19756 joint.util.cancelFrame(this._transitionIds[key]);
19758 delete this._transitionIds[key];
19760 this.trigger('transition:end', this, key);
19766 // joint.dia.CellView base view and controller.
19767 // --------------------------------------------
19769 // This is the base view and controller for `joint.dia.ElementView` and `joint.dia.LinkView`.
19771 joint.dia.CellView = Backbone.View.extend({
19775 attributes: function() {
19777 return { 'model-id': this.model.id }
19780 initialize: function() {
19782 _.bindAll(this, 'remove', 'update');
19784 // Store reference to this to the <g> DOM element so that the view is accessible through the DOM tree.
19785 this.$el.data('view', this);
19787 this.listenTo(this.model, 'remove', this.remove);
19788 this.listenTo(this.model, 'change:attrs', this.onChangeAttrs);
19791 onChangeAttrs: function(cell, attrs, opt) {
19795 // dirty flag could be set when a model attribute was removed and it needs to be cleared
19796 // also from the DOM element. See cell.removeAttr().
19797 return this.render();
19800 return this.update();
19803 _configure: function(options) {
19805 // Make sure a global unique id is assigned to this view. Store this id also to the properties object.
19806 // The global unique id makes sure that the same view can be rendered on e.g. different machines and
19807 // still be associated to the same object among all those clients. This is necessary for real-time
19808 // collaboration mechanism.
19809 options.id = options.id || joint.util.guid(this);
19811 Backbone.View.prototype._configure.apply(this, arguments);
19814 // Override the Backbone `_ensureElement()` method in order to create a `<g>` node that wraps
19815 // all the nodes of the Cell view.
19816 _ensureElement: function() {
19822 var attrs = _.extend({ id: this.id }, _.result(this, 'attributes'));
19823 if (this.className) attrs['class'] = _.result(this, 'className');
19824 el = V(_.result(this, 'tagName'), attrs).node;
19828 el = _.result(this, 'el')
19831 this.setElement(el, false);
19834 findBySelector: function(selector) {
19836 // These are either descendants of `this.$el` of `this.$el` itself.
19837 // `.` is a special selector used to select the wrapping `<g>` element.
19838 var $selected = selector === '.' ? this.$el : this.$el.find(selector);
19842 notify: function(evt) {
19846 var args = Array.prototype.slice.call(arguments, 1);
19848 // Trigger the event on both the element itself and also on the paper.
19849 this.trigger.apply(this, [evt].concat(args));
19851 // Paper event handlers receive the view object as the first argument.
19852 this.paper.trigger.apply(this.paper, [evt, this].concat(args));
19856 getStrokeBBox: function(el) {
19857 // Return a bounding box rectangle that takes into account stroke.
19858 // Note that this is a naive and ad-hoc implementation that does not
19859 // works only in certain cases and should be replaced as soon as browsers will
19860 // start supporting the getStrokeBBox() SVG method.
19861 // @TODO any better solution is very welcome!
19863 var isMagnet = !!el;
19865 el = el || this.el;
19866 var bbox = V(el).bbox(false, this.paper.viewport);
19871 strokeWidth = V(el).attr('stroke-width');
19875 strokeWidth = this.model.attr('rect/stroke-width') || this.model.attr('circle/stroke-width') || this.model.attr('ellipse/stroke-width') || this.model.attr('path/stroke-width');
19878 strokeWidth = parseFloat(strokeWidth) || 0;
19880 return g.rect(bbox).moveAndExpand({ x: -strokeWidth/2, y: -strokeWidth/2, width: strokeWidth, height: strokeWidth });
19883 getBBox: function() {
19885 return V(this.el).bbox();
19888 highlight: function(el) {
19890 el = !el ? this.el : this.$(el)[0] || this.el;
19892 V(el).addClass('highlighted');
19895 unhighlight: function(el) {
19897 el = !el ? this.el : this.$(el)[0] || this.el;
19899 V(el).removeClass('highlighted');
19902 // Find the closest element that has the `magnet` attribute set to `true`. If there was not such
19903 // an element found, return the root element of the cell view.
19904 findMagnet: function(el) {
19906 var $el = this.$(el);
19908 if ($el.length === 0 || $el[0] === this.el) {
19910 // If the overall cell has set `magnet === false`, then return `undefined` to
19911 // announce there is no magnet found for this cell.
19912 // This is especially useful to set on cells that have 'ports'. In this case,
19913 // only the ports have set `magnet === true` and the overall element has `magnet === false`.
19914 var attrs = this.model.get('attrs') || {};
19915 if (attrs['.'] && attrs['.']['magnet'] === false) {
19922 if ($el.attr('magnet')) {
19927 return this.findMagnet($el.parent());
19930 // `selector` is a CSS selector or `'.'`. `filter` must be in the special JointJS filter format:
19931 // `{ name: <name of the filter>, args: { <arguments>, ... }`.
19932 // An example is: `{ filter: { name: 'blur', args: { radius: 5 } } }`.
19933 applyFilter: function(selector, filter) {
19935 var $selected = this.findBySelector(selector);
19937 // Generate a hash code from the stringified filter definition. This gives us
19938 // a unique filter ID for different definitions.
19939 var filterId = filter.name + this.paper.svg.id + joint.util.hashCode(JSON.stringify(filter));
19941 // If the filter already exists in the document,
19942 // we're done and we can just use it (reference it using `url()`).
19943 // If not, create one.
19944 if (!this.paper.svg.getElementById(filterId)) {
19946 var filterSVGString = joint.util.filter[filter.name] && joint.util.filter[filter.name](filter.args || {});
19947 if (!filterSVGString) {
19948 throw new Error('Non-existing filter ' + filter.name);
19950 var filterElement = V(filterSVGString);
19951 filterElement.attr('filterUnits', 'userSpaceOnUse');
19952 if (filter.attrs) filterElement.attr(filter.attrs);
19953 filterElement.node.id = filterId;
19954 V(this.paper.svg).defs().append(filterElement);
19957 $selected.each(function() {
19959 V(this).attr('filter', 'url(#' + filterId + ')');
19963 // `selector` is a CSS selector or `'.'`. `attr` is either a `'fill'` or `'stroke'`.
19964 // `gradient` must be in the special JointJS gradient format:
19965 // `{ type: <linearGradient|radialGradient>, stops: [ { offset: <offset>, color: <color> }, ... ]`.
19966 // An example is: `{ fill: { type: 'linearGradient', stops: [ { offset: '10%', color: 'green' }, { offset: '50%', color: 'blue' } ] } }`.
19967 applyGradient: function(selector, attr, gradient) {
19969 var $selected = this.findBySelector(selector);
19971 // Generate a hash code from the stringified filter definition. This gives us
19972 // a unique filter ID for different definitions.
19973 var gradientId = gradient.type + this.paper.svg.id + joint.util.hashCode(JSON.stringify(gradient));
19975 // If the gradient already exists in the document,
19976 // we're done and we can just use it (reference it using `url()`).
19977 // If not, create one.
19978 if (!this.paper.svg.getElementById(gradientId)) {
19980 var gradientSVGString = [
19981 '<' + gradient.type + '>',
19982 _.map(gradient.stops, function(stop) {
19983 return '<stop offset="' + stop.offset + '" stop-color="' + stop.color + '" stop-opacity="' + (_.isFinite(stop.opacity) ? stop.opacity : 1) + '" />'
19985 '</' + gradient.type + '>'
19988 var gradientElement = V(gradientSVGString);
19989 if (gradient.attrs) { gradientElement.attr(gradient.attrs); }
19990 gradientElement.node.id = gradientId;
19991 V(this.paper.svg).defs().append(gradientElement);
19994 $selected.each(function() {
19996 V(this).attr(attr, 'url(#' + gradientId + ')');
20000 // Construct a unique selector for the `el` element within this view.
20001 // `selector` is being collected through the recursive call. No value for `selector` is expected when using this method.
20002 getSelector: function(el, selector) {
20004 if (el === this.el) {
20009 var index = $(el).index();
20011 selector = el.tagName + ':nth-child(' + (index + 1) + ')' + ' ' + (selector || '');
20013 return this.getSelector($(el).parent()[0], selector + ' ');
20016 // Interaction. The controller part.
20017 // ---------------------------------
20019 // Interaction is handled by the paper and delegated to the view in interest.
20020 // `x` & `y` parameters passed to these functions represent the coordinates already snapped to the paper grid.
20021 // If necessary, real coordinates can be obtained from the `evt` event object.
20023 // These functions are supposed to be overriden by the views that inherit from `joint.dia.Cell`,
20024 // i.e. `joint.dia.Element` and `joint.dia.Link`.
20026 pointerdblclick: function(evt, x, y) {
20028 this.notify('cell:pointerdblclick', evt, x, y);
20031 pointerclick: function(evt, x, y) {
20033 this.notify('cell:pointerclick', evt, x, y);
20036 pointerdown: function(evt, x, y) {
20038 if (this.model.collection) {
20039 this.model.trigger('batch:start');
20040 this._collection = this.model.collection;
20043 this.notify('cell:pointerdown', evt, x, y);
20046 pointermove: function(evt, x, y) {
20048 this.notify('cell:pointermove', evt, x, y);
20051 pointerup: function(evt, x, y) {
20053 this.notify('cell:pointerup', evt, x, y);
20055 if (this._collection) {
20056 // we don't want to trigger event on model as model doesn't
20057 // need to be member of collection anymore (remove)
20058 this._collection.trigger('batch:stop');
20059 delete this._collection;
20066 if (typeof exports === 'object') {
20068 module.exports.Cell = joint.dia.Cell;
20069 module.exports.CellView = joint.dia.CellView;
20072 // JointJS library.
20073 // (c) 2011-2013 client IO
20076 if (typeof exports === 'object') {
20079 util: require('./core').util,
20081 Cell: require('./joint.dia.cell').Cell,
20082 CellView: require('./joint.dia.cell').CellView
20085 var Backbone = require('backbone');
20086 var _ = require('lodash');
20090 // joint.dia.Element base model.
20091 // -----------------------------
20093 joint.dia.Element = joint.dia.Cell.extend({
20096 position: { x: 0, y: 0 },
20097 size: { width: 1, height: 1 },
20101 position: function(x, y) {
20103 this.set('position', { x: x, y: y });
20106 translate: function(tx, ty, opt) {
20110 if (tx === 0 && ty === 0) {
20111 // Like nothing has happened.
20115 var position = this.get('position') || { x: 0, y: 0 };
20116 var translatedPosition = { x: position.x + tx || 0, y: position.y + ty || 0 };
20118 if (opt && opt.transition) {
20120 if (!_.isObject(opt.transition)) opt.transition = {};
20122 this.transition('position', translatedPosition, _.extend({}, opt.transition, {
20123 valueFunction: joint.util.interpolate.object
20128 this.set('position', translatedPosition, opt);
20130 // Recursively call `translate()` on all the embeds cells.
20131 _.invoke(this.getEmbeddedCells(), 'translate', tx, ty, opt);
20137 resize: function(width, height) {
20139 this.trigger('batch:start');
20140 this.set('size', { width: width, height: height });
20141 this.trigger('batch:stop');
20146 rotate: function(angle, absolute) {
20148 return this.set('angle', absolute ? angle : ((this.get('angle') || 0) + angle) % 360);
20151 getBBox: function() {
20153 var position = this.get('position');
20154 var size = this.get('size');
20156 return g.rect(position.x, position.y, size.width, size.height);
20160 // joint.dia.Element base view and controller.
20161 // -------------------------------------------
20163 joint.dia.ElementView = joint.dia.CellView.extend({
20165 className: function() {
20166 return 'element ' + this.model.get('type').split('.').join(' ');
20169 initialize: function() {
20171 _.bindAll(this, 'translate', 'resize', 'rotate');
20173 joint.dia.CellView.prototype.initialize.apply(this, arguments);
20175 this.listenTo(this.model, 'change:position', this.translate);
20176 this.listenTo(this.model, 'change:size', this.resize);
20177 this.listenTo(this.model, 'change:angle', this.rotate);
20180 // Default is to process the `attrs` object and set attributes on subelements based on the selectors.
20181 update: function(cell, renderingOnlyAttrs) {
20183 var allAttrs = this.model.get('attrs');
20185 var rotatable = V(this.$('.rotatable')[0]);
20188 var rotation = rotatable.attr('transform');
20189 rotatable.attr('transform', '');
20192 var relativelyPositioned = [];
20194 _.each(renderingOnlyAttrs || allAttrs, function(attrs, selector) {
20196 // Elements that should be updated.
20197 var $selected = this.findBySelector(selector);
20199 // No element matched by the `selector` was found. We're done then.
20200 if ($selected.length === 0) return;
20202 // Special attributes are treated by JointJS, not by SVG.
20203 var specialAttributes = ['style', 'text', 'html', 'ref-x', 'ref-y', 'ref-dx', 'ref-dy', 'ref-width', 'ref-height', 'ref', 'x-alignment', 'y-alignment', 'port'];
20205 // If the `filter` attribute is an object, it is in the special JointJS filter format and so
20206 // it becomes a special attribute and is treated separately.
20207 if (_.isObject(attrs.filter)) {
20209 specialAttributes.push('filter');
20210 this.applyFilter(selector, attrs.filter);
20213 // If the `fill` or `stroke` attribute is an object, it is in the special JointJS gradient format and so
20214 // it becomes a special attribute and is treated separately.
20215 if (_.isObject(attrs.fill)) {
20217 specialAttributes.push('fill');
20218 this.applyGradient(selector, 'fill', attrs.fill);
20220 if (_.isObject(attrs.stroke)) {
20222 specialAttributes.push('stroke');
20223 this.applyGradient(selector, 'stroke', attrs.stroke);
20226 // Make special case for `text` attribute. So that we can set text content of the `<text>` element
20227 // via the `attrs` object as well.
20228 // Note that it's important to set text before applying the rest of the final attributes.
20229 // Vectorizer `text()` method sets on the element its own attributes and it has to be possible
20230 // to rewrite them, if needed. (i.e display: 'none')
20231 if (!_.isUndefined(attrs.text)) {
20233 $selected.each(function() {
20235 V(this).text(attrs.text + '');
20239 // Set regular attributes on the `$selected` subelement. Note that we cannot use the jQuery attr()
20240 // method as some of the attributes might be namespaced (e.g. xlink:href) which fails with jQuery attr().
20241 var finalAttributes = _.omit(attrs, specialAttributes);
20243 $selected.each(function() {
20245 V(this).attr(finalAttributes);
20248 // `port` attribute contains the `id` of the port that the underlying magnet represents.
20251 $selected.attr('port', _.isUndefined(attrs.port.id) ? attrs.port : attrs.port.id);
20254 // `style` attribute is special in the sense that it sets the CSS style of the subelement.
20257 $selected.css(attrs.style);
20260 if (!_.isUndefined(attrs.html)) {
20262 $selected.each(function() {
20264 $(this).html(attrs.html + '');
20268 // Special `ref-x` and `ref-y` attributes make it possible to set both absolute or
20269 // relative positioning of subelements.
20270 if (!_.isUndefined(attrs['ref-x']) ||
20271 !_.isUndefined(attrs['ref-y']) ||
20272 !_.isUndefined(attrs['ref-dx']) ||
20273 !_.isUndefined(attrs['ref-dy']) ||
20274 !_.isUndefined(attrs['x-alignment']) ||
20275 !_.isUndefined(attrs['y-alignment']) ||
20276 !_.isUndefined(attrs['ref-width']) ||
20277 !_.isUndefined(attrs['ref-height'])
20280 _.each($selected, function(el, index, list) {
20282 // copy original list selector to the element
20283 $el.selector = list.selector;
20284 relativelyPositioned.push($el);
20290 // We don't want the sub elements to affect the bounding box of the root element when
20291 // positioning the sub elements relatively to the bounding box.
20292 //_.invoke(relativelyPositioned, 'hide');
20293 //_.invoke(relativelyPositioned, 'show');
20295 // Note that we're using the bounding box without transformation because we are already inside
20296 // a transformed coordinate system.
20297 var bbox = this.el.getBBox();
20299 renderingOnlyAttrs = renderingOnlyAttrs || {};
20301 _.each(relativelyPositioned, function($el) {
20303 // if there was a special attribute affecting the position amongst renderingOnlyAttributes
20304 // we have to merge it with rest of the element's attributes as they are necessary
20305 // to update the position relatively (i.e `ref`)
20306 var renderingOnlyElAttrs = renderingOnlyAttrs[$el.selector];
20307 var elAttrs = renderingOnlyElAttrs
20308 ? _.merge({}, allAttrs[$el.selector], renderingOnlyElAttrs)
20309 : allAttrs[$el.selector];
20311 this.positionRelative($el, bbox, elAttrs);
20317 rotatable.attr('transform', rotation || '');
20321 positionRelative: function($el, bbox, elAttrs) {
20323 var ref = elAttrs['ref'];
20324 var refX = parseFloat(elAttrs['ref-x']);
20325 var refY = parseFloat(elAttrs['ref-y']);
20326 var refDx = parseFloat(elAttrs['ref-dx']);
20327 var refDy = parseFloat(elAttrs['ref-dy']);
20328 var yAlignment = elAttrs['y-alignment'];
20329 var xAlignment = elAttrs['x-alignment'];
20330 var refWidth = parseFloat(elAttrs['ref-width']);
20331 var refHeight = parseFloat(elAttrs['ref-height']);
20333 // `ref` is the selector of the reference element. If no `ref` is passed, reference
20334 // element is the root element.
20336 var isScalable = _.contains(_.pluck(_.pluck($el.parents('g'), 'className'), 'baseVal'), 'scalable');
20340 // Get the bounding box of the reference element relative to the root `<g>` element.
20341 bbox = V(this.findBySelector(ref)[0]).bbox(false, this.el);
20344 var vel = V($el[0]);
20346 // Remove the previous translate() from the transform attribute and translate the element
20347 // relative to the root bounding box following the `ref-x` and `ref-y` attributes.
20348 if (vel.attr('transform')) {
20350 vel.attr('transform', vel.attr('transform').replace(/translate\([^)]*\)/g, '') || '');
20353 function isDefined(x) {
20354 return _.isNumber(x) && !_.isNaN(x);
20357 // The final translation of the subelement.
20361 // 'ref-width'/'ref-height' defines the width/height of the subelement relatively to
20362 // the reference element size
20363 // val in 0..1 ref-width = 0.75 sets the width to 75% of the ref. el. width
20364 // val < 0 || val > 1 ref-height = -20 sets the height to the the ref. el. height shorter by 20
20366 if (isDefined(refWidth)) {
20368 if (refWidth >= 0 && refWidth <= 1) {
20370 vel.attr('width', refWidth * bbox.width);
20374 vel.attr('width', Math.max(refWidth + bbox.width, 0));
20378 if (isDefined(refHeight)) {
20380 if (refHeight >= 0 && refHeight <= 1) {
20382 vel.attr('height', refHeight * bbox.height);
20386 vel.attr('height', Math.max(refHeight + bbox.height, 0));
20390 // `ref-dx` and `ref-dy` define the offset of the subelement relative to the right and/or bottom
20391 // coordinate of the reference element.
20392 if (isDefined(refDx)) {
20396 // Compensate for the scale grid in case the elemnt is in the scalable group.
20397 var scale = V(this.$('.scalable')[0]).scale();
20398 tx = bbox.x + bbox.width + refDx / scale.sx;
20402 tx = bbox.x + bbox.width + refDx;
20405 if (isDefined(refDy)) {
20409 // Compensate for the scale grid in case the elemnt is in the scalable group.
20410 var scale = V(this.$('.scalable')[0]).scale();
20411 ty = bbox.y + bbox.height + refDy / scale.sy;
20414 ty = bbox.y + bbox.height + refDy;
20418 // if `refX` is in [0, 1] then `refX` is a fraction of bounding box width
20419 // if `refX` is < 0 then `refX`'s absolute values is the right coordinate of the bounding box
20420 // otherwise, `refX` is the left coordinate of the bounding box
20421 // Analogical rules apply for `refY`.
20422 if (isDefined(refX)) {
20424 if (refX > 0 && refX < 1) {
20426 tx = bbox.x + bbox.width * refX;
20428 } else if (isScalable) {
20430 // Compensate for the scale grid in case the elemnt is in the scalable group.
20431 var scale = V(this.$('.scalable')[0]).scale();
20432 tx = bbox.x + refX / scale.sx;
20436 tx = bbox.x + refX;
20439 if (isDefined(refY)) {
20441 if (refY > 0 && refY < 1) {
20443 ty = bbox.y + bbox.height * refY;
20445 } else if (isScalable) {
20447 // Compensate for the scale grid in case the elemnt is in the scalable group.
20448 var scale = V(this.$('.scalable')[0]).scale();
20449 ty = bbox.y + refY / scale.sy;
20453 ty = bbox.y + refY;
20457 var velbbox = vel.bbox(false, this.paper.viewport);
20458 // `y-alignment` when set to `middle` causes centering of the subelement around its new y coordinate.
20459 if (yAlignment === 'middle') {
20461 ty -= velbbox.height/2;
20463 } else if (isDefined(yAlignment)) {
20465 ty += (yAlignment > -1 && yAlignment < 1) ? velbbox.height * yAlignment : yAlignment;
20468 // `x-alignment` when set to `middle` causes centering of the subelement around its new x coordinate.
20469 if (xAlignment === 'middle') {
20471 tx -= velbbox.width/2;
20473 } else if (isDefined(xAlignment)) {
20475 tx += (xAlignment > -1 && xAlignment < 1) ? velbbox.width * xAlignment : xAlignment;
20478 vel.translate(tx, ty);
20481 // `prototype.markup` is rendered by default. Set the `markup` attribute on the model if the
20482 // default markup is not desirable.
20483 renderMarkup: function() {
20485 var markup = this.model.markup || this.model.get('markup');
20489 var nodes = V(markup);
20490 V(this.el).append(nodes);
20494 throw new Error('properties.markup is missing while the default render() implementation is used.');
20498 render: function() {
20502 this.renderMarkup();
20513 // Scale the whole `<g>` group. Note the difference between `scale()` and `resize()` here.
20514 // `resize()` doesn't scale the whole `<g>` group but rather adjusts the `box.sx`/`box.sy` only.
20515 // `update()` is then responsible for scaling only those elements that have the `follow-scale`
20516 // attribute set to `true`. This is desirable in elements that have e.g. a `<text>` subelement
20517 // that is not supposed to be scaled together with a surrounding `<rect>` element that IS supposed
20519 scale: function(sx, sy) {
20521 // TODO: take into account the origin coordinates `ox` and `oy`.
20522 V(this.el).scale(sx, sy);
20525 resize: function() {
20527 var size = this.model.get('size') || { width: 1, height: 1 };
20528 var angle = this.model.get('angle') || 0;
20530 var scalable = V(this.$('.scalable')[0]);
20532 // If there is no scalable elements, than there is nothing to resize.
20535 var scalableBbox = scalable.bbox(true);
20537 scalable.attr('transform', 'scale(' + (size.width / scalableBbox.width) + ',' + (size.height / scalableBbox.height) + ')');
20539 // Now the interesting part. The goal is to be able to store the object geometry via just `x`, `y`, `angle`, `width` and `height`
20540 // Order of transformations is significant but we want to reconstruct the object always in the order:
20541 // resize(), rotate(), translate() no matter of how the object was transformed. For that to work,
20542 // we must adjust the `x` and `y` coordinates of the object whenever we resize it (because the origin of the
20543 // rotation changes). The new `x` and `y` coordinates are computed by canceling the previous rotation
20544 // around the center of the resized object (which is a different origin then the origin of the previous rotation)
20545 // and getting the top-left corner of the resulting object. Then we clean up the rotation back to what it originally was.
20547 // Cancel the rotation but now around a different origin, which is the center of the scaled object.
20548 var rotatable = V(this.$('.rotatable')[0]);
20549 var rotation = rotatable && rotatable.attr('transform');
20550 if (rotation && rotation !== 'null') {
20552 rotatable.attr('transform', rotation + ' rotate(' + (-angle) + ',' + (size.width/2) + ',' + (size.height/2) + ')');
20553 var rotatableBbox = scalable.bbox(false, this.paper.viewport);
20555 // Store new x, y and perform rotate() again against the new rotation origin.
20556 this.model.set('position', { x: rotatableBbox.x, y: rotatableBbox.y });
20560 // Update must always be called on non-rotated element. Otherwise, relative positioning
20561 // would work with wrong (rotated) bounding boxes.
20565 translate: function(model, changes, opt) {
20567 var position = this.model.get('position') || { x: 0, y: 0 };
20569 V(this.el).attr('transform', 'translate(' + position.x + ',' + position.y + ')');
20572 rotate: function() {
20574 var rotatable = V(this.$('.rotatable')[0]);
20576 // If there is no rotatable elements, then there is nothing to rotate.
20580 var angle = this.model.get('angle') || 0;
20581 var size = this.model.get('size') || { width: 1, height: 1 };
20583 var ox = size.width/2;
20584 var oy = size.height/2;
20587 rotatable.attr('transform', 'rotate(' + angle + ',' + ox + ',' + oy + ')');
20590 // Interaction. The controller part.
20591 // ---------------------------------
20594 pointerdown: function(evt, x, y) {
20596 if ( // target is a valid magnet start linking
20597 evt.target.getAttribute('magnet') &&
20598 this.paper.options.validateMagnet.call(this.paper, this, evt.target)
20600 this.model.trigger('batch:start');
20602 var link = this.paper.getDefaultLink(this, evt.target);
20606 selector: this.getSelector(evt.target),
20607 port: $(evt.target).attr('port')
20609 target: { x: x, y: y }
20612 this.paper.model.addCell(link);
20614 this._linkView = this.paper.findViewByModel(link);
20615 this._linkView.startArrowheadMove('target');
20622 joint.dia.CellView.prototype.pointerdown.apply(this, arguments);
20626 pointermove: function(evt, x, y) {
20628 if (this._linkView) {
20630 // let the linkview deal with this event
20631 this._linkView.pointermove(evt, x, y);
20635 var grid = this.paper.options.gridSize;
20637 if (this.options.interactive !== false) {
20639 var position = this.model.get('position');
20641 // Make sure the new element's position always snaps to the current grid after
20642 // translate as the previous one could be calculated with a different grid size.
20643 this.model.translate(
20644 g.snapToGrid(position.x, grid) - position.x + g.snapToGrid(x - this._dx, grid),
20645 g.snapToGrid(position.y, grid) - position.y + g.snapToGrid(y - this._dy, grid)
20649 this._dx = g.snapToGrid(x, grid);
20650 this._dy = g.snapToGrid(y, grid);
20652 joint.dia.CellView.prototype.pointermove.apply(this, arguments);
20656 pointerup: function(evt, x, y) {
20658 if (this._linkView) {
20660 // let the linkview deal with this event
20661 this._linkView.pointerup(evt, x, y);
20663 delete this._linkView;
20665 this.model.trigger('batch:stop');
20669 joint.dia.CellView.prototype.pointerup.apply(this, arguments);
20675 if (typeof exports === 'object') {
20677 module.exports.Element = joint.dia.Element;
20678 module.exports.ElementView = joint.dia.ElementView;
20681 // JointJS diagramming library.
20682 // (c) 2011-2013 client IO
20685 if (typeof exports === 'object') {
20689 Cell: require('./joint.dia.cell').Cell,
20690 CellView: require('./joint.dia.cell').CellView
20693 var Backbone = require('backbone');
20694 var _ = require('lodash');
20695 var g = require('./geometry');
20700 // joint.dia.Link base model.
20701 // --------------------------
20702 joint.dia.Link = joint.dia.Cell.extend({
20704 // The default markup for links.
20706 '<path class="connection" stroke="black"/>',
20707 '<path class="marker-source" fill="black" stroke="black" />',
20708 '<path class="marker-target" fill="black" stroke="black" />',
20709 '<path class="connection-wrap"/>',
20710 '<g class="labels"/>',
20711 '<g class="marker-vertices"/>',
20712 '<g class="marker-arrowheads"/>',
20713 '<g class="link-tools"/>'
20717 '<g class="label">',
20724 '<g class="link-tool">',
20725 '<g class="tool-remove" event="remove">',
20726 '<circle r="11" />',
20727 '<path transform="scale(.8) translate(-16, -16)" d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z"/>',
20728 '<title>Remove link.</title>',
20730 '<g class="tool-options" event="link:options">',
20731 '<circle r="11" transform="translate(25)"/>',
20732 '<path fill="white" transform="scale(.55) translate(29, -16)" d="M31.229,17.736c0.064-0.571,0.104-1.148,0.104-1.736s-0.04-1.166-0.104-1.737l-4.377-1.557c-0.218-0.716-0.504-1.401-0.851-2.05l1.993-4.192c-0.725-0.91-1.549-1.734-2.458-2.459l-4.193,1.994c-0.647-0.347-1.334-0.632-2.049-0.849l-1.558-4.378C17.165,0.708,16.588,0.667,16,0.667s-1.166,0.041-1.737,0.105L12.707,5.15c-0.716,0.217-1.401,0.502-2.05,0.849L6.464,4.005C5.554,4.73,4.73,5.554,4.005,6.464l1.994,4.192c-0.347,0.648-0.632,1.334-0.849,2.05l-4.378,1.557C0.708,14.834,0.667,15.412,0.667,16s0.041,1.165,0.105,1.736l4.378,1.558c0.217,0.715,0.502,1.401,0.849,2.049l-1.994,4.193c0.725,0.909,1.549,1.733,2.459,2.458l4.192-1.993c0.648,0.347,1.334,0.633,2.05,0.851l1.557,4.377c0.571,0.064,1.148,0.104,1.737,0.104c0.588,0,1.165-0.04,1.736-0.104l1.558-4.377c0.715-0.218,1.399-0.504,2.049-0.851l4.193,1.993c0.909-0.725,1.733-1.549,2.458-2.458l-1.993-4.193c0.347-0.647,0.633-1.334,0.851-2.049L31.229,17.736zM16,20.871c-2.69,0-4.872-2.182-4.872-4.871c0-2.69,2.182-4.872,4.872-4.872c2.689,0,4.871,2.182,4.871,4.872C20.871,18.689,18.689,20.871,16,20.871z"/>',
20733 '<title>Link options.</title>',
20738 // The default markup for showing/removing vertices. These elements are the children of the .marker-vertices element (see `this.markup`).
20739 // Only .marker-vertex and .marker-vertex-remove element have special meaning. The former is used for
20740 // dragging vertices (changin their position). The latter is used for removing vertices.
20742 '<g class="marker-vertex-group" transform="translate(<%= x %>, <%= y %>)">',
20743 '<circle class="marker-vertex" idx="<%= idx %>" r="10" />',
20744 '<path class="marker-vertex-remove-area" idx="<%= idx %>" d="M16,5.333c-7.732,0-14,4.701-14,10.5c0,1.982,0.741,3.833,2.016,5.414L2,25.667l5.613-1.441c2.339,1.317,5.237,2.107,8.387,2.107c7.732,0,14-4.701,14-10.5C30,10.034,23.732,5.333,16,5.333z" transform="translate(5, -33)"/>',
20745 '<path class="marker-vertex-remove" idx="<%= idx %>" transform="scale(.8) translate(9.5, -37)" d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z">',
20746 '<title>Remove vertex.</title>',
20752 '<g class="marker-arrowhead-group marker-arrowhead-group-<%= end %>">',
20753 '<path class="marker-arrowhead" end="<%= end %>" d="M 26 0 L 0 13 L 26 26 z" />',
20762 disconnect: function() {
20764 return this.set({ source: g.point(0, 0), target: g.point(0, 0) });
20767 // A convenient way to set labels. Currently set values will be mixined with `value` if used as a setter.
20768 label: function(idx, value) {
20772 var labels = this.get('labels') || [];
20775 if (arguments.length === 0 || arguments.length === 1) {
20777 return labels[idx];
20780 var newValue = _.merge({}, labels[idx], value);
20782 var newLabels = labels.slice();
20783 newLabels[idx] = newValue;
20785 return this.set({ labels: newLabels });
20790 // joint.dia.Link base view and controller.
20791 // ----------------------------------------
20793 joint.dia.LinkView = joint.dia.CellView.extend({
20795 className: function() {
20796 return _.unique(this.model.get('type').split('.').concat('link')).join(' ');
20801 shortLinkLength: 100
20804 initialize: function() {
20806 joint.dia.CellView.prototype.initialize.apply(this, arguments);
20808 // create methods in prototype, so they can be accessed from any instance and
20809 // don't need to be create over and over
20810 if (typeof this.constructor.prototype.watchSource !== 'function') {
20811 this.constructor.prototype.watchSource = this._createWatcher('source');
20812 this.constructor.prototype.watchTarget = this._createWatcher('target');
20815 // `_.labelCache` is a mapping of indexes of labels in the `this.get('labels')` array to
20816 // `<g class="label">` nodes wrapped by Vectorizer. This allows for quick access to the
20817 // nodes in `updateLabelPosition()` in order to update the label positions.
20818 this._labelCache = {};
20820 // keeps markers bboxes and positions again for quicker access
20821 this._markerCache = {};
20824 this.startListening();
20827 startListening: function() {
20829 this.listenTo(this.model, 'change:markup', this.render);
20830 this.listenTo(this.model, 'change:smooth change:manhattan change:router change:connector', this.update);
20831 this.listenTo(this.model, 'change:toolMarkup', function() {
20832 this.renderTools().updateToolsPosition();
20834 this.listenTo(this.model, 'change:labels change:labelMarkup', function() {
20835 this.renderLabels().updateLabelPositions();
20837 this.listenTo(this.model, 'change:vertices change:vertexMarkup', function() {
20838 this.renderVertexMarkers().update();
20840 this.listenTo(this.model, 'change:source', function(cell, source) {
20841 this.watchSource(cell, source).update();
20843 this.listenTo(this.model, 'change:target', function(cell, target) {
20844 this.watchTarget(cell, target).update();
20851 render: function() {
20855 // A special markup can be given in the `properties.markup` property. This might be handy
20856 // if e.g. arrowhead markers should be `<image>` elements or any other element than `<path>`s.
20857 // `.connection`, `.connection-wrap`, `.marker-source` and `.marker-target` selectors
20858 // of elements with special meaning though. Therefore, those classes should be preserved in any
20859 // special markup passed in `properties.markup`.
20860 var children = V(this.model.get('markup') || this.model.markup);
20862 // custom markup may contain only one children
20863 if (!_.isArray(children)) children = [children];
20865 // Cache all children elements for quicker access.
20866 this._V = {}; // vectorized markup;
20867 _.each(children, function(child) {
20868 var c = child.attr('class');
20869 c && (this._V[$.camelCase(c)] = child);
20872 // Only the connection path is mandatory
20873 if (!this._V.connection) throw new Error('link: no connection path in the markup');
20875 // partial rendering
20876 this.renderTools();
20877 this.renderVertexMarkers();
20878 this.renderArrowheadMarkers();
20880 V(this.el).append(children);
20882 // rendering labels has to be run after the link is appended to DOM tree. (otherwise <Text> bbox
20883 // returns zero values)
20884 this.renderLabels();
20886 // start watching the ends of the link for changes
20887 this.watchSource(this.model, this.model.get('source'))
20888 .watchTarget(this.model, this.model.get('target'))
20894 renderLabels: function() {
20896 if (!this._V.labels) return this;
20898 this._labelCache = {};
20899 var $labels = $(this._V.labels.node).empty();
20901 var labels = this.model.get('labels') || [];
20902 if (!labels.length) return this;
20904 var labelTemplate = _.template(this.model.get('labelMarkup') || this.model.labelMarkup);
20905 // This is a prepared instance of a vectorized SVGDOM node for the label element resulting from
20906 // compilation of the labelTemplate. The purpose is that all labels will just `clone()` this
20907 // node to create a duplicate.
20908 var labelNodeInstance = V(labelTemplate());
20910 _.each(labels, function(label, idx) {
20912 var labelNode = labelNodeInstance.clone().node;
20913 // Cache label nodes so that the `updateLabels()` can just update the label node positions.
20914 this._labelCache[idx] = V(labelNode);
20916 var $text = $(labelNode).find('text');
20917 var $rect = $(labelNode).find('rect');
20919 // Text attributes with the default `text-anchor` and font-size set.
20920 var textAttributes = _.extend({ 'text-anchor': 'middle', 'font-size': 14 }, joint.util.getByPath(label, 'attrs/text', '/'));
20922 $text.attr(_.omit(textAttributes, 'text'));
20924 if (!_.isUndefined(textAttributes.text)) {
20926 V($text[0]).text(textAttributes.text + '');
20929 // Note that we first need to append the `<text>` element to the DOM in order to
20930 // get its bounding box.
20931 $labels.append(labelNode);
20933 // `y-alignment` - center the text element around its y coordinate.
20934 var textBbox = V($text[0]).bbox(true, $labels[0]);
20935 V($text[0]).translate(0, -textBbox.height/2);
20937 // Add default values.
20938 var rectAttributes = _.extend({
20944 }, joint.util.getByPath(label, 'attrs/rect', '/'));
20946 $rect.attr(_.extend(rectAttributes, {
20949 y: textBbox.y - textBbox.height/2, // Take into account the y-alignment translation.
20950 width: textBbox.width,
20951 height: textBbox.height
20959 renderTools: function() {
20961 if (!this._V.linkTools) return this;
20963 // Tools are a group of clickable elements that manipulate the whole link.
20964 // A good example of this is the remove tool that removes the whole link.
20965 // Tools appear after hovering the link close to the `source` element/point of the link
20966 // but are offset a bit so that they don't cover the `marker-arrowhead`.
20968 var $tools = $(this._V.linkTools.node).empty();
20969 var toolTemplate = _.template(this.model.get('toolMarkup') || this.model.toolMarkup);
20970 var tool = V(toolTemplate());
20972 $tools.append(tool.node);
20974 // Cache the tool node so that the `updateToolsPosition()` can update the tool position quickly.
20975 this._toolCache = tool;
20980 renderVertexMarkers: function() {
20982 if (!this._V.markerVertices) return this;
20984 var $markerVertices = $(this._V.markerVertices.node).empty();
20986 // A special markup can be given in the `properties.vertexMarkup` property. This might be handy
20987 // if default styling (elements) are not desired. This makes it possible to use any
20988 // SVG elements for .marker-vertex and .marker-vertex-remove tools.
20989 var markupTemplate = _.template(this.model.get('vertexMarkup') || this.model.vertexMarkup);
20991 _.each(this.model.get('vertices'), function(vertex, idx) {
20993 $markerVertices.append(V(markupTemplate(_.extend({ idx: idx }, vertex))).node);
20999 renderArrowheadMarkers: function() {
21001 // Custom markups might not have arrowhead markers. Therefore, jump of this function immediately if that's the case.
21002 if (!this._V.markerArrowheads) return this;
21004 var $markerArrowheads = $(this._V.markerArrowheads.node);
21006 $markerArrowheads.empty();
21008 // A special markup can be given in the `properties.vertexMarkup` property. This might be handy
21009 // if default styling (elements) are not desired. This makes it possible to use any
21010 // SVG elements for .marker-vertex and .marker-vertex-remove tools.
21011 var markupTemplate = _.template(this.model.get('arrowheadMarkup') || this.model.arrowheadMarkup);
21013 this._V.sourceArrowhead = V(markupTemplate({ end: 'source' }));
21014 this._V.targetArrowhead = V(markupTemplate({ end: 'target' }));
21016 $markerArrowheads.append(this._V.sourceArrowhead.node, this._V.targetArrowhead.node);
21024 // Default is to process the `attrs` object and set attributes on subelements based on the selectors.
21025 update: function() {
21027 // Update attributes.
21028 _.each(this.model.get('attrs'), function(attrs, selector) {
21030 // If the `filter` attribute is an object, it is in the special JointJS filter format and so
21031 // it becomes a special attribute and is treated separately.
21032 if (_.isObject(attrs.filter)) {
21034 this.findBySelector(selector).attr(_.omit(attrs, 'filter'));
21035 this.applyFilter(selector, attrs.filter);
21039 this.findBySelector(selector).attr(attrs);
21044 var vertices = this.route = this.findRoute(this.model.get('vertices') || []);
21046 // finds all the connection points taking new vertices into account
21047 this._findConnectionPoints(vertices);
21049 var pathData = this.getPathData(vertices);
21051 // The markup needs to contain a `.connection`
21052 this._V.connection.attr('d', pathData);
21053 this._V.connectionWrap && this._V.connectionWrap.attr('d', pathData);
21055 this._translateAndAutoOrientArrows(this._V.markerSource, this._V.markerTarget);
21058 this.updateLabelPositions();
21059 this.updateToolsPosition();
21060 this.updateArrowheadMarkers();
21062 delete this.options.perpendicular;
21067 _findConnectionPoints: function(vertices) {
21069 // cache source and target points
21070 var sourcePoint, targetPoint, sourceMarkerPoint, targetMarkerPoint;
21072 var firstVertex = _.first(vertices);
21074 sourcePoint = this.getConnectionPoint(
21075 'source', this.model.get('source'), firstVertex || this.model.get('target')
21078 var lastVertex = _.last(vertices);
21080 targetPoint = this.getConnectionPoint(
21081 'target', this.model.get('target'), lastVertex || sourcePoint
21084 // Move the source point by the width of the marker taking into account
21085 // its scale around x-axis. Note that scale is the only transform that
21086 // makes sense to be set in `.marker-source` attributes object
21087 // as all other transforms (translate/rotate) will be replaced
21088 // by the `translateAndAutoOrient()` function.
21089 var cache = this._markerCache;
21091 if (this._V.markerSource) {
21093 cache.sourceBBox = cache.sourceBBox || this._V.markerSource.bbox(true);
21095 sourceMarkerPoint = g.point(sourcePoint).move(
21096 firstVertex || targetPoint,
21097 cache.sourceBBox.width * this._V.markerSource.scale().sx * -1
21101 if (this._V.markerTarget) {
21103 cache.targetBBox = cache.targetBBox || this._V.markerTarget.bbox(true);
21105 targetMarkerPoint = g.point(targetPoint).move(
21106 lastVertex || sourcePoint,
21107 cache.targetBBox.width * this._V.markerTarget.scale().sx * -1
21111 // if there was no markup for the marker, use the connection point.
21112 cache.sourcePoint = sourceMarkerPoint || sourcePoint;
21113 cache.targetPoint = targetMarkerPoint || targetPoint;
21115 // make connection points public
21116 this.sourcePoint = sourcePoint;
21117 this.targetPoint = targetPoint;
21120 updateLabelPositions: function() {
21122 if (!this._V.labels) return this;
21124 // This method assumes all the label nodes are stored in the `this._labelCache` hash table
21125 // by their indexes in the `this.get('labels')` array. This is done in the `renderLabels()` method.
21127 var labels = this.model.get('labels') || [];
21128 if (!labels.length) return this;
21130 var connectionElement = this._V.connection.node;
21131 var connectionLength = connectionElement.getTotalLength();
21133 _.each(labels, function(label, idx) {
21135 var position = label.position;
21136 position = (position > connectionLength) ? connectionLength : position; // sanity check
21137 position = (position < 0) ? connectionLength + position : position;
21138 position = position > 1 ? position : connectionLength * position;
21140 var labelCoordinates = connectionElement.getPointAtLength(position);
21142 this._labelCache[idx].attr('transform', 'translate(' + labelCoordinates.x + ', ' + labelCoordinates.y + ')');
21150 updateToolsPosition: function() {
21152 if (!this._V.linkTools) return this;
21154 // Move the tools a bit to the target position but don't cover the `sourceArrowhead` marker.
21155 // Note that the offset is hardcoded here. The offset should be always
21156 // more than the `this.$('.marker-arrowhead[end="source"]')[0].bbox().width` but looking
21157 // this up all the time would be slow.
21162 // If the link is too short, make the tools half the size and the offset twice as low.
21163 if (this.getConnectionLength() < this.options.shortLinkLength) {
21164 scale = 'scale(.5)';
21168 var toolPosition = this.getPointAtLength(offset);
21170 this._toolCache.attr('transform', 'translate(' + toolPosition.x + ', ' + toolPosition.y + ') ' + scale);
21176 updateArrowheadMarkers: function() {
21178 if (!this._V.markerArrowheads) return this;
21180 // getting bbox of an element with `display="none"` in IE9 ends up with access violation
21181 if ($.css(this._V.markerArrowheads.node, 'display') === 'none') return this;
21183 var sx = this.getConnectionLength() < this.options.shortLinkLength ? .5 : 1;
21184 this._V.sourceArrowhead.scale(sx);
21185 this._V.targetArrowhead.scale(sx);
21187 this._translateAndAutoOrientArrows(this._V.sourceArrowhead, this._V.targetArrowhead);
21192 // Returns a function observing changes on an end of the link. If a change happens and new end is a new model,
21193 // it stops listening on the previous one and starts listening to the new one.
21194 _createWatcher: function(endType) {
21196 function watchEnd(link, end) {
21200 var previousEnd = link.previous(endType) || {};
21202 // Pick updateMethod this._sourceBboxUpdate or this._targetBboxUpdate.
21203 var updateEndFunction = this['_' + endType + 'BBoxUpdate'];
21205 if (this._isModel(previousEnd)) {
21206 this.stopListening(this.paper.getModelById(previousEnd.id), 'change', updateEndFunction);
21209 if (this._isModel(end)) {
21210 // If the observed model changes, it caches a new bbox and do the link update.
21211 this.listenTo(this.paper.getModelById(end.id), 'change', updateEndFunction);
21214 _.bind(updateEndFunction, this)({ cacheOnly: true });
21222 // It's important to keep both methods (sourceBboxUpdate and targetBboxUpdate) as unique methods
21223 // because of loop links. We have to be able to determine, which method we want to stop listen to.
21224 // ListenTo(model, event, handler) as model and event will be identical.
21225 _sourceBBoxUpdate: function(update) {
21227 // keep track which end had been changed very last
21228 this.lastEndChange = 'source';
21230 update = update || {};
21231 var end = this.model.get('source');
21233 if (this._isModel(end)) {
21235 var selector = this._makeSelector(end);
21236 var view = this.paper.findViewByModel(end.id);
21237 var magnetElement = this.paper.viewport.querySelector(selector);
21239 this.sourceBBox = view.getStrokeBBox(magnetElement);
21242 // the link end is a point ~ rect 1x1
21243 this.sourceBBox = g.rect(end.x, end.y, 1, 1);
21246 if (!update.cacheOnly) this.update();
21249 _targetBBoxUpdate: function(update) {
21251 // keep track which end had been changed very last
21252 this.lastEndChange = 'target';
21254 update = update || {};
21255 var end = this.model.get('target');
21257 if (this._isModel(end)) {
21259 var selector = this._makeSelector(end);
21260 var view = this.paper.findViewByModel(end.id);
21261 var magnetElement = this.paper.viewport.querySelector(selector);
21263 this.targetBBox = view.getStrokeBBox(magnetElement);
21266 // the link end is a point ~ rect 1x1
21267 this.targetBBox = g.rect(end.x, end.y, 1, 1);
21270 if (!update.cacheOnly) this.update();
21273 _translateAndAutoOrientArrows: function(sourceArrow, targetArrow) {
21275 // Make the markers "point" to their sticky points being auto-oriented towards
21276 // `targetPosition`/`sourcePosition`. And do so only if there is a markup for them.
21278 sourceArrow.translateAndAutoOrient(
21280 _.first(this.route) || this.targetPoint,
21281 this.paper.viewport
21286 targetArrow.translateAndAutoOrient(
21288 _.last(this.route) || this.sourcePoint,
21289 this.paper.viewport
21294 removeVertex: function(idx) {
21296 var vertices = _.clone(this.model.get('vertices'));
21298 if (vertices && vertices.length) {
21300 vertices.splice(idx, 1);
21301 this.model.set('vertices', vertices);
21307 // This method ads a new vertex to the `vertices` array of `.connection`. This method
21308 // uses a heuristic to find the index at which the new `vertex` should be placed at assuming
21309 // the new vertex is somewhere on the path.
21310 addVertex: function(vertex) {
21312 this.model.set('attrs', this.model.get('attrs') || {});
21313 var attrs = this.model.get('attrs');
21315 // As it is very hard to find a correct index of the newly created vertex,
21316 // a little heuristics is taking place here.
21317 // The heuristics checks if length of the newly created
21318 // path is lot more than length of the old path. If this is the case,
21319 // new vertex was probably put into a wrong index.
21320 // Try to put it into another index and repeat the heuristics again.
21322 var vertices = (this.model.get('vertices') || []).slice();
21323 // Store the original vertices for a later revert if needed.
21324 var originalVertices = vertices.slice();
21326 // A `<path>` element used to compute the length of the path during heuristics.
21327 var path = this._V.connection.node.cloneNode(false);
21329 // Length of the original path.
21330 var originalPathLength = path.getTotalLength();
21331 // Current path length.
21333 // Tolerance determines the highest possible difference between the length
21334 // of the old and new path. The number has been chosen heuristically.
21335 var pathLengthTolerance = 20;
21336 // Total number of vertices including source and target points.
21337 var idx = vertices.length + 1;
21339 // Loop through all possible indexes and check if the difference between
21340 // path lengths changes significantly. If not, the found index is
21341 // most probably the right one.
21344 vertices.splice(idx, 0, vertex);
21345 V(path).attr('d', this.getPathData(this.findRoute(vertices)));
21347 pathLength = path.getTotalLength();
21349 // Check if the path lengths changed significantly.
21350 if (pathLength - originalPathLength > pathLengthTolerance) {
21352 // Revert vertices to the original array. The path length has changed too much
21353 // so that the index was not found yet.
21354 vertices = originalVertices.slice();
21362 this.model.set('vertices', vertices);
21364 // In manhattan routing, if there are no vertices, the path length changes significantly
21365 // with the first vertex added. Shall we check vertices.length === 0? at beginning of addVertex()
21366 // in order to avoid the temporary path construction and other operations?
21367 return Math.max(idx, 0);
21371 findRoute: function(oldVertices) {
21373 var router = this.model.get('router');
21377 if (this.model.get('manhattan')) {
21378 // backwards compability
21379 router = { name: 'orthogonal' };
21382 return oldVertices;
21386 var fn = joint.routers[router.name];
21388 if (!_.isFunction(fn)) {
21390 throw 'unknown router: ' + router.name;
21393 var newVertices = fn.call(this, oldVertices || [], router.args || {}, this);
21395 return newVertices;
21398 // Return the `d` attribute value of the `<path>` element representing the link
21399 // between `source` and `target`.
21400 getPathData: function(vertices) {
21402 var connector = this.model.get('connector');
21406 // backwards compability
21407 connector = this.model.get('smooth') ? { name: 'smooth' } : { name: 'normal' };
21410 if (!_.isFunction(joint.connectors[connector.name])) {
21412 throw 'unknown connector: ' + connector.name;
21415 var pathData = joint.connectors[connector.name].call(
21417 this._markerCache.sourcePoint, // Note that the value is translated by the size
21418 this._markerCache.targetPoint, // of the marker. (We'r not using this.sourcePoint)
21419 vertices || (this.model.get('vertices') || {}),
21420 connector.args || {}, // options
21427 // Find a point that is the start of the connection.
21428 // If `selectorOrPoint` is a point, then we're done and that point is the start of the connection.
21429 // If the `selectorOrPoint` is an element however, we need to know a reference point (or element)
21430 // that the link leads to in order to determine the start of the connection on the original element.
21431 getConnectionPoint: function(end, selectorOrPoint, referenceSelectorOrPoint) {
21435 if (this._isPoint(selectorOrPoint)) {
21437 // If the source is a point, we don't need a reference point to find the sticky point of connection.
21438 spot = g.point(selectorOrPoint);
21442 // If the source is an element, we need to find a point on the element boundary that is closest
21443 // to the reference point (or reference element).
21444 // Get the bounding box of the spot relative to the paper viewport. This is necessary
21445 // in order to follow paper viewport transformations (scale/rotate).
21446 // `_sourceBbox` (`_targetBbox`) comes from `_sourceBboxUpdate` (`_sourceBboxUpdate`)
21447 // method, it exists since first render and are automatically updated
21448 var spotBbox = end === 'source' ? this.sourceBBox : this.targetBBox;
21452 if (this._isPoint(referenceSelectorOrPoint)) {
21454 // Reference was passed as a point, therefore, we're ready to find the sticky point of connection on the source element.
21455 reference = g.point(referenceSelectorOrPoint);
21459 // Reference was passed as an element, therefore we need to find a point on the reference
21460 // element boundary closest to the source element.
21461 // Get the bounding box of the spot relative to the paper viewport. This is necessary
21462 // in order to follow paper viewport transformations (scale/rotate).
21463 var referenceBbox = end === 'source' ? this.targetBBox : this.sourceBBox;
21465 reference = g.rect(referenceBbox).intersectionWithLineFromCenterToPoint(g.rect(spotBbox).center());
21466 reference = reference || g.rect(referenceBbox).center();
21469 // If `perpendicularLinks` flag is set on the paper and there are vertices
21470 // on the link, then try to find a connection point that makes the link perpendicular
21471 // even though the link won't point to the center of the targeted object.
21472 if (this.paper.options.perpendicularLinks || this.options.perpendicular) {
21474 var horizontalLineRect = g.rect(0, reference.y, this.paper.options.width, 1);
21475 var verticalLineRect = g.rect(reference.x, 0, 1, this.paper.options.height);
21478 if (horizontalLineRect.intersect(g.rect(spotBbox))) {
21480 nearestSide = g.rect(spotBbox).sideNearestToPoint(reference);
21481 switch (nearestSide) {
21483 spot = g.point(spotBbox.x, reference.y);
21486 spot = g.point(spotBbox.x + spotBbox.width, reference.y);
21489 spot = g.rect(spotBbox).center();
21493 } else if (verticalLineRect.intersect(g.rect(spotBbox))) {
21495 nearestSide = g.rect(spotBbox).sideNearestToPoint(reference);
21496 switch (nearestSide) {
21498 spot = g.point(reference.x, spotBbox.y);
21501 spot = g.point(reference.x, spotBbox.y + spotBbox.height);
21504 spot = g.rect(spotBbox).center();
21510 // If there is no intersection horizontally or vertically with the object bounding box,
21511 // then we fall back to the regular situation finding straight line (not perpendicular)
21512 // between the object and the reference point.
21514 spot = g.rect(spotBbox).intersectionWithLineFromCenterToPoint(reference);
21515 spot = spot || g.rect(spotBbox).center();
21520 spot = g.rect(spotBbox).intersectionWithLineFromCenterToPoint(reference);
21521 spot = spot || g.rect(spotBbox).center();
21528 _isModel: function(end) {
21530 return end && end.id;
21533 _isPoint: function(end) {
21535 return !this._isModel(end);
21538 _makeSelector: function(end) {
21540 var selector = '[model-id="' + end.id + '"]';
21541 // `port` has a higher precendence over `selector`. This is because the selector to the magnet
21542 // might change while the name of the port can stay the same.
21544 selector += ' [port="' + end.port + '"]';
21545 } else if (end.selector) {
21546 selector += ' ' + end.selector;
21555 getConnectionLength: function() {
21557 return this._V.connection.node.getTotalLength();
21560 getPointAtLength: function(length) {
21562 return this._V.connection.node.getPointAtLength(length);
21565 // Interaction. The controller part.
21566 // ---------------------------------
21568 _beforeArrowheadMove: function() {
21570 this.model.trigger('batch:start');
21572 this._z = this.model.get('z');
21573 this.model.set('z', Number.MAX_VALUE);
21575 // Let the pointer propagate throught the link view elements so that
21576 // the `evt.target` is another element under the pointer, not the link itself.
21577 this.el.style.pointerEvents = 'none';
21580 _afterArrowheadMove: function() {
21583 this.model.set('z', this._z);
21587 // Put `pointer-events` back to its original value. See `startArrowheadMove()` for explanation.
21588 // Value `auto` doesn't work in IE9. We force to use `visiblePainted` instead.
21589 // See `https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events`.
21590 this.el.style.pointerEvents = 'visiblePainted';
21592 this.model.trigger('batch:stop');
21595 _createValidateConnectionArgs: function(arrowhead) {
21596 // It makes sure the arguments for validateConnection have the following form:
21597 // (source view, source magnet, target view, target magnet and link view)
21600 args[4] = arrowhead;
21603 var oppositeArrowhead, i = 0, j = 0;
21605 if (arrowhead === 'source') {
21607 oppositeArrowhead = 'target';
21610 oppositeArrowhead = 'source';
21613 var end = this.model.get(oppositeArrowhead);
21616 args[i] = this.paper.findViewByModel(end.id);
21617 args[i+1] = end.selector && args[i].el.querySelector(end.selector);
21620 function validateConnectionArgs(cellView, magnet) {
21621 args[j] = cellView;
21622 args[j+1] = cellView.el === magnet ? undefined : magnet;
21626 return validateConnectionArgs;
21629 startArrowheadMove: function(end) {
21630 // Allow to delegate events from an another view to this linkView in order to trigger arrowhead
21631 // move without need to click on the actual arrowhead dom element.
21632 this._action = 'arrowhead-move';
21633 this._arrowhead = end;
21634 this._beforeArrowheadMove();
21635 this._validateConnectionArgs = this._createValidateConnectionArgs(this._arrowhead);
21638 pointerdown: function(evt, x, y) {
21640 joint.dia.CellView.prototype.pointerdown.apply(this, arguments);
21645 if (this.options.interactive === false) return;
21647 var className = evt.target.getAttribute('class');
21649 switch (className) {
21651 case 'marker-vertex':
21652 this._action = 'vertex-move';
21653 this._vertexIdx = evt.target.getAttribute('idx');
21656 case 'marker-vertex-remove':
21657 case 'marker-vertex-remove-area':
21658 this.removeVertex(evt.target.getAttribute('idx'));
21661 case 'marker-arrowhead':
21662 this.startArrowheadMove(evt.target.getAttribute('end'));
21667 var targetParentEvent = evt.target.parentNode.getAttribute('event');
21669 if (targetParentEvent) {
21671 // `remove` event is built-in. Other custom events are triggered on the paper.
21672 if (targetParentEvent === 'remove') {
21673 this.model.remove();
21675 this.paper.trigger(targetParentEvent, evt, this, x, y);
21680 // Store the index at which the new vertex has just been placed.
21681 // We'll be update the very same vertex position in `pointermove()`.
21682 this._vertexIdx = this.addVertex({ x: x, y: y });
21683 this._action = 'vertex-move';
21688 pointermove: function(evt, x, y) {
21690 joint.dia.CellView.prototype.pointermove.apply(this, arguments);
21692 switch (this._action) {
21694 case 'vertex-move':
21696 var vertices = _.clone(this.model.get('vertices'));
21697 vertices[this._vertexIdx] = { x: x, y: y };
21698 this.model.set('vertices', vertices);
21701 case 'arrowhead-move':
21703 if (this.paper.options.snapLinks) {
21705 // checking view in close area of the pointer
21707 var r = this.paper.options.snapLinks.radius || 50;
21708 var viewsInArea = this.paper.findViewsInArea({ x: x - r, y: y - r, width: 2 * r, height: 2 * r });
21710 this._closestView && this._closestView.unhighlight(this._closestEnd.selector);
21711 this._closestView = this._closestEnd = null;
21713 var pointer = g.point(x,y);
21714 var distance, minDistance = Number.MAX_VALUE;
21716 _.each(viewsInArea, function(view) {
21718 // skip connecting to the element in case '.': { magnet: false } attribute present
21719 if (view.el.getAttribute('magnet') !== 'false') {
21721 // find distance from the center of the model to pointer coordinates
21722 distance = view.model.getBBox().center().distance(pointer);
21724 // the connection is looked up in a circle area by `distance < r`
21725 if (distance < r && distance < minDistance) {
21727 if (this.paper.options.validateConnection.apply(
21728 this.paper, this._validateConnectionArgs(view, null)
21730 minDistance = distance;
21731 this._closestView = view;
21732 this._closestEnd = { id: view.model.id };
21737 view.$('[magnet]').each(_.bind(function(index, magnet) {
21739 var bbox = V(magnet).bbox(false, this.paper.viewport);
21741 distance = pointer.distance({
21742 x: bbox.x + bbox.width / 2,
21743 y: bbox.y + bbox.height / 2
21746 if (distance < r && distance < minDistance) {
21748 if (this.paper.options.validateConnection.apply(
21749 this.paper, this._validateConnectionArgs(view, magnet)
21751 minDistance = distance;
21752 this._closestView = view;
21753 this._closestEnd = {
21755 selector: view.getSelector(magnet),
21756 port: magnet.getAttribute('port')
21765 this._closestView && this._closestView.highlight(this._closestEnd.selector);
21767 this.model.set(this._arrowhead, this._closestEnd || { x: x, y: y });
21771 // checking views right under the pointer
21773 // Touchmove event's target is not reflecting the element under the coordinates as mousemove does.
21774 // It holds the element when a touchstart triggered.
21775 var target = (evt.type === 'mousemove')
21777 : document.elementFromPoint(evt.clientX, evt.clientY);
21779 if (this._targetEvent !== target) {
21780 // Unhighlight the previous view under pointer if there was one.
21781 this._magnetUnderPointer && this._viewUnderPointer.unhighlight(this._magnetUnderPointer);
21782 this._viewUnderPointer = this.paper.findView(target);
21783 if (this._viewUnderPointer) {
21784 // If we found a view that is under the pointer, we need to find the closest
21785 // magnet based on the real target element of the event.
21786 this._magnetUnderPointer = this._viewUnderPointer.findMagnet(target);
21788 if (this._magnetUnderPointer && this.paper.options.validateConnection.apply(
21790 this._validateConnectionArgs(this._viewUnderPointer, this._magnetUnderPointer)
21792 // If there was no magnet found, do not highlight anything and assume there
21793 // is no view under pointer we're interested in reconnecting to.
21794 // This can only happen if the overall element has the attribute `'.': { magnet: false }`.
21795 this._magnetUnderPointer && this._viewUnderPointer.highlight(this._magnetUnderPointer);
21797 // This type of connection is not valid. Disregard this magnet.
21798 this._magnetUnderPointer = null;
21801 // Make sure we'll delete previous magnet
21802 this._magnetUnderPointer = null;
21806 this._targetEvent = target;
21808 this.model.set(this._arrowhead, { x: x, y: y });
21818 pointerup: function(evt) {
21820 joint.dia.CellView.prototype.pointerup.apply(this, arguments);
21822 if (this._action === 'arrowhead-move') {
21824 if (this.paper.options.snapLinks) {
21826 this._closestView && this._closestView.unhighlight(this._closestEnd.selector);
21827 this._closestView = this._closestEnd = null;
21831 if (this._magnetUnderPointer) {
21832 this._viewUnderPointer.unhighlight(this._magnetUnderPointer);
21833 // Find a unique `selector` of the element under pointer that is a magnet. If the
21834 // `this._magnetUnderPointer` is the root element of the `this._viewUnderPointer` itself,
21835 // the returned `selector` will be `undefined`. That means we can directly pass it to the
21836 // `source`/`target` attribute of the link model below.
21837 this.model.set(this._arrowhead, {
21838 id: this._viewUnderPointer.model.id,
21839 selector: this._viewUnderPointer.getSelector(this._magnetUnderPointer),
21840 port: $(this._magnetUnderPointer).attr('port')
21844 delete this._viewUnderPointer;
21845 delete this._magnetUnderPointer;
21846 delete this._staticView;
21847 delete this._staticMagnet;
21850 this._afterArrowheadMove();
21853 delete this._action;
21858 if (typeof exports === 'object') {
21860 module.exports.Link = joint.dia.Link;
21861 module.exports.LinkView = joint.dia.LinkView;
21864 // JointJS library.
21865 // (c) 2011-2013 client IO
21868 joint.dia.Paper = Backbone.View.extend({
21875 perpendicularLinks: false,
21876 elementView: joint.dia.ElementView,
21877 linkView: joint.dia.LinkView,
21878 snapLinks: false, // false, true, { radius: value }
21880 // Defines what link model is added to the graph after an user clicks on an active magnet.
21881 // Value could be the Backbone.model or a function returning the Backbone.model
21882 // defaultLink: function(elementView, magnet) { return condition ? new customLink1() : new customLink2() }
21883 defaultLink: new joint.dia.Link,
21885 // Check whether to add a new link to the graph when user clicks on an a magnet.
21886 validateMagnet: function(cellView, magnet) {
21887 return magnet.getAttribute('magnet') !== 'passive';
21890 // Check whether to allow or disallow the link connection while an arrowhead end (source/target)
21892 validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {
21893 return (end === 'target' ? cellViewT : cellViewS) instanceof joint.dia.ElementView;
21899 'mousedown': 'pointerdown',
21900 'dblclick': 'mousedblclick',
21901 'click': 'mouseclick',
21902 'touchstart': 'pointerdown',
21903 'mousemove': 'pointermove',
21904 'touchmove': 'pointermove'
21907 initialize: function() {
21909 _.bindAll(this, 'addCell', 'sortCells', 'resetCells', 'pointerup');
21911 this.svg = V('svg').node;
21912 this.viewport = V('g').node;
21914 // Append `<defs>` element to the SVG document. This is useful for filters and gradients.
21915 V(this.svg).append(V('defs').node);
21917 V(this.viewport).attr({ 'class': 'viewport' });
21919 V(this.svg).append(this.viewport);
21921 this.$el.append(this.svg);
21923 this.setDimensions();
21925 this.listenTo(this.model, 'add', this.addCell);
21926 this.listenTo(this.model, 'reset', this.resetCells);
21927 this.listenTo(this.model, 'sort', this.sortCells);
21929 $(document).on('mouseup touchend', this.pointerup);
21931 // Hold the value when mouse has been moved: when mouse moved, no click event will be triggered.
21932 this._mousemoved = false;
21935 remove: function() {
21937 $(document).off('mouseup touchend', this.pointerup);
21939 Backbone.View.prototype.remove.call(this);
21942 setDimensions: function(width, height) {
21944 if (width) this.options.width = width;
21945 if (height) this.options.height = height;
21947 V(this.svg).attr('width', this.options.width);
21948 V(this.svg).attr('height', this.options.height);
21950 this.trigger('resize');
21953 // Expand/shrink the paper to fit the content. Snap the width/height to the grid
21954 // defined in `gridWidth`, `gridHeight`. `padding` adds to the resulting width/height of the paper.
21955 fitToContent: function(gridWidth, gridHeight, padding) {
21957 gridWidth = gridWidth || 1;
21958 gridHeight = gridHeight || 1;
21959 padding = padding || 0;
21961 // Calculate the paper size to accomodate all the graph's elements.
21962 var bbox = V(this.viewport).bbox(true, this.svg);
21964 var calcWidth = Math.ceil((bbox.width + bbox.x) / gridWidth) * gridWidth;
21965 var calcHeight = Math.ceil((bbox.height + bbox.y) / gridHeight) * gridHeight;
21967 calcWidth += padding;
21968 calcHeight += padding;
21970 // Change the dimensions only if there is a size discrepency
21971 if (calcWidth != this.options.width || calcHeight != this.options.height) {
21972 this.setDimensions(calcWidth || this.options.width , calcHeight || this.options.height);
21976 getContentBBox: function() {
21978 var crect = this.viewport.getBoundingClientRect();
21980 // Using Screen CTM was the only way to get the real viewport bounding box working in both
21981 // Google Chrome and Firefox.
21982 var ctm = this.viewport.getScreenCTM();
21984 var bbox = g.rect(Math.abs(crect.left - ctm.e), Math.abs(crect.top - ctm.f), crect.width, crect.height);
21989 createViewForModel: function(cell) {
21993 var type = cell.get('type');
21994 var module = type.split('.')[0];
21995 var entity = type.split('.')[1];
21997 // If there is a special view defined for this model, use that one instead of the default `elementView`/`linkView`.
21998 if (joint.shapes[module] && joint.shapes[module][entity + 'View']) {
22000 view = new joint.shapes[module][entity + 'View']({ model: cell, interactive: this.options.interactive });
22002 } else if (cell instanceof joint.dia.Element) {
22004 view = new this.options.elementView({ model: cell, interactive: this.options.interactive });
22008 view = new this.options.linkView({ model: cell, interactive: this.options.interactive });
22014 addCell: function(cell) {
22016 var view = this.createViewForModel(cell);
22018 V(this.viewport).append(view.el);
22022 // This is the only way to prevent image dragging in Firefox that works.
22023 // Setting -moz-user-select: none, draggable="false" attribute or user-drag: none didn't help.
22024 $(view.el).find('image').on('dragstart', function() { return false; });
22027 resetCells: function(cellsCollection) {
22029 $(this.viewport).empty();
22031 var cells = cellsCollection.models.slice();
22033 // Make sure links are always added AFTER elements.
22034 // They wouldn't find their sources/targets in the DOM otherwise.
22035 cells.sort(function(a, b) { return a instanceof joint.dia.Link ? 1 : -1; });
22037 _.each(cells, this.addCell, this);
22039 // Sort the cells in the DOM manually as we might have changed the order they
22040 // were added to the DOM (see above).
22044 sortCells: function() {
22046 // Run insertion sort algorithm in order to efficiently sort DOM elements according to their
22047 // associated model `z` attribute.
22049 var $cells = $(this.viewport).children('[model-id]');
22050 var cells = this.model.get('cells');
22052 this.sortElements($cells, function(a, b) {
22054 var cellA = cells.get($(a).attr('model-id'));
22055 var cellB = cells.get($(b).attr('model-id'));
22057 return (cellA.get('z') || 0) > (cellB.get('z') || 0) ? 1 : -1;
22061 // Highly inspired by the jquery.sortElements plugin by Padolsey.
22062 // See http://james.padolsey.com/javascript/sorting-elements-with-jquery/.
22063 sortElements: function(elements, comparator) {
22065 var $elements = $(elements);
22067 var placements = $elements.map(function() {
22069 var sortElement = this;
22070 var parentNode = sortElement.parentNode;
22072 // Since the element itself will change position, we have
22073 // to have some way of storing it's original position in
22074 // the DOM. The easiest way is to have a 'flag' node:
22075 var nextSibling = parentNode.insertBefore(
22076 document.createTextNode(''),
22077 sortElement.nextSibling
22080 return function() {
22082 if (parentNode === this) {
22084 "You can't sort elements if any one is a descendant of another."
22088 // Insert before flag:
22089 parentNode.insertBefore(this, nextSibling);
22091 parentNode.removeChild(nextSibling);
22096 return Array.prototype.sort.call($elements, comparator).each(function(i) {
22097 placements[i].call(this);
22101 scale: function(sx, sy, ox, oy) {
22109 // Remove previous transform so that the new scale is not affected by previous scales, especially
22110 // the old translate() does not affect the new translate if an origin is specified.
22111 V(this.viewport).attr('transform', '');
22113 // TODO: V.scale() doesn't support setting scale origin. #Fix
22115 V(this.viewport).translate(-ox * (sx - 1), -oy * (sy - 1));
22118 V(this.viewport).scale(sx, sy);
22120 this.trigger('scale', ox, oy);
22125 rotate: function(deg, ox, oy) {
22127 // If the origin is not set explicitely, rotate around the center. Note that
22128 // we must use the plain bounding box (`this.el.getBBox()` instead of the one that gives us
22129 // the real bounding box (`bbox()`) including transformations).
22130 if (_.isUndefined(ox)) {
22132 var bbox = this.viewport.getBBox();
22134 oy = bbox.height/2;
22137 V(this.viewport).rotate(deg, ox, oy);
22140 // Find the first view climbing up the DOM tree starting at element `el`. Note that `el` can also
22141 // be a selector or a jQuery object.
22142 findView: function(el) {
22144 var $el = this.$(el);
22146 if ($el.length === 0 || $el[0] === this.el) {
22151 if ($el.data('view')) {
22153 return $el.data('view');
22156 return this.findView($el.parent());
22159 // Find a view for a model `cell`. `cell` can also be a string representing a model `id`.
22160 findViewByModel: function(cell) {
22162 var id = _.isString(cell) ? cell : cell.id;
22164 var $view = this.$('[model-id="' + id + '"]');
22165 if ($view.length) {
22167 return $view.data('view');
22172 // Find all views at given point
22173 findViewsFromPoint: function(p) {
22177 var views = _.map(this.model.getElements(), this.findViewByModel);
22179 return _.filter(views, function(view) {
22180 return g.rect(V(view.el).bbox(false, this.viewport)).containsPoint(p);
22184 // Find all views in given area
22185 findViewsInArea: function(r) {
22189 var views = _.map(this.model.getElements(), this.findViewByModel);
22191 return _.filter(views, function(view) {
22192 return r.intersect(g.rect(V(view.el).bbox(false, this.viewport)));
22196 getModelById: function(id) {
22198 return this.model.getCell(id);
22201 snapToGrid: function(p) {
22203 // Convert global coordinates to the local ones of the `viewport`. Otherwise,
22204 // improper transformation would be applied when the viewport gets transformed (scaled/rotated).
22205 var localPoint = V(this.viewport).toLocalPoint(p.x, p.y);
22208 x: g.snapToGrid(localPoint.x, this.options.gridSize),
22209 y: g.snapToGrid(localPoint.y, this.options.gridSize)
22213 getDefaultLink: function(cellView, magnet) {
22215 return _.isFunction(this.options.defaultLink)
22216 // default link is a function producing link model
22217 ? this.options.defaultLink.call(this, cellView, magnet)
22218 // default link is the Backbone model
22219 : this.options.defaultLink.clone();
22225 mousedblclick: function(evt) {
22227 evt.preventDefault();
22228 evt = joint.util.normalizeEvent(evt);
22230 var view = this.findView(evt.target);
22231 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22235 view.pointerdblclick(evt, localPoint.x, localPoint.y);
22239 this.trigger('blank:pointerdblclick', evt, localPoint.x, localPoint.y);
22243 mouseclick: function(evt) {
22245 // Trigger event when mouse not moved.
22246 if (!this._mousemoved) {
22248 evt.preventDefault();
22249 evt = joint.util.normalizeEvent(evt);
22251 var view = this.findView(evt.target);
22252 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22256 view.pointerclick(evt, localPoint.x, localPoint.y);
22260 this.trigger('blank:pointerclick', evt, localPoint.x, localPoint.y);
22264 this._mousemoved = false;
22267 pointerdown: function(evt) {
22269 evt.preventDefault();
22270 evt = joint.util.normalizeEvent(evt);
22272 var view = this.findView(evt.target);
22274 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22278 this.sourceView = view;
22280 view.pointerdown(evt, localPoint.x, localPoint.y);
22284 this.trigger('blank:pointerdown', evt, localPoint.x, localPoint.y);
22288 pointermove: function(evt) {
22290 evt.preventDefault();
22291 evt = joint.util.normalizeEvent(evt);
22293 if (this.sourceView) {
22296 this._mousemoved = true;
22298 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22300 this.sourceView.pointermove(evt, localPoint.x, localPoint.y);
22304 pointerup: function(evt) {
22306 evt = joint.util.normalizeEvent(evt);
22308 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22310 if (this.sourceView) {
22312 this.sourceView.pointerup(evt, localPoint.x, localPoint.y);
22314 //"delete sourceView" occasionally throws an error in chrome (illegal access exception)
22315 this.sourceView = null;
22319 this.trigger('blank:pointerup', evt, localPoint.x, localPoint.y);
22325 // JointJS library.
22326 // (c) 2011-2013 client IO
22329 if (typeof exports === 'object') {
22332 util: require('../src/core').util,
22335 Element: require('../src/joint.dia.element').Element,
22336 ElementView: require('../src/joint.dia.element').ElementView
22339 var _ = require('lodash');
22343 joint.shapes.basic = {};
22346 joint.shapes.basic.Generic = joint.dia.Element.extend({
22348 defaults: joint.util.deepSupplement({
22350 type: 'basic.Generic',
22352 '.': { fill: '#FFFFFF', stroke: 'none' }
22355 }, joint.dia.Element.prototype.defaults)
22358 joint.shapes.basic.Rect = joint.shapes.basic.Generic.extend({
22360 markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',
22362 defaults: joint.util.deepSupplement({
22364 type: 'basic.Rect',
22366 'rect': { fill: '#FFFFFF', stroke: 'black', width: 100, height: 60 },
22367 'text': { 'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22370 }, joint.shapes.basic.Generic.prototype.defaults)
22373 joint.shapes.basic.Text = joint.shapes.basic.Generic.extend({
22375 markup: '<g class="rotatable"><g class="scalable"><text/></g></g>',
22377 defaults: joint.util.deepSupplement({
22379 type: 'basic.Text',
22381 'text': { 'font-size': 18, fill: 'black' }
22384 }, joint.shapes.basic.Generic.prototype.defaults)
22387 joint.shapes.basic.Circle = joint.shapes.basic.Generic.extend({
22389 markup: '<g class="rotatable"><g class="scalable"><circle/></g><text/></g>',
22391 defaults: joint.util.deepSupplement({
22393 type: 'basic.Circle',
22394 size: { width: 60, height: 60 },
22396 'circle': { fill: '#FFFFFF', stroke: 'black', r: 30, transform: 'translate(30, 30)' },
22397 'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-y': .5, ref: 'circle', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22399 }, joint.shapes.basic.Generic.prototype.defaults)
22402 joint.shapes.basic.Image = joint.shapes.basic.Generic.extend({
22404 markup: '<g class="rotatable"><g class="scalable"><image/></g><text/></g>',
22406 defaults: joint.util.deepSupplement({
22408 type: 'basic.Image',
22410 'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-dy': 20, ref: 'image', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22412 }, joint.shapes.basic.Generic.prototype.defaults)
22415 joint.shapes.basic.Path = joint.shapes.basic.Generic.extend({
22417 markup: '<g class="rotatable"><g class="scalable"><path/></g><text/></g>',
22419 defaults: joint.util.deepSupplement({
22421 type: 'basic.Path',
22422 size: { width: 60, height: 60 },
22424 'path': { fill: '#FFFFFF', stroke: 'black' },
22425 'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-dy': 20, ref: 'path', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22427 }, joint.shapes.basic.Generic.prototype.defaults)
22430 // PortsModelInterface is a common interface for shapes that have ports. This interface makes it easy
22431 // to create new shapes with ports functionality. It is assumed that the new shapes have
22432 // `inPorts` and `outPorts` array properties. Only these properties should be used to set ports.
22433 // In other words, using this interface, it is no longer recommended to set ports directly through the
22437 // joint.shapes.custom.MyElementWithPorts = joint.shapes.basic.Path.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
22438 // getPortAttrs: function(portName, index, total, selector, type) {
22440 // var portClass = 'port' + index;
22441 // var portSelector = selector + '>.' + portClass;
22442 // var portTextSelector = portSelector + '>text';
22443 // var portCircleSelector = portSelector + '>circle';
22445 // attrs[portTextSelector] = { text: portName };
22446 // attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
22447 // attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
22449 // if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
22454 joint.shapes.basic.PortsModelInterface = {
22456 initialize: function() {
22458 this.updatePortsAttrs();
22459 this.on('change:inPorts change:outPorts', this.updatePortsAttrs, this);
22461 // Call the `initialize()` of the parent.
22462 this.constructor.__super__.constructor.__super__.initialize.apply(this, arguments);
22465 updatePortsAttrs: function(eventName) {
22467 // Delete previously set attributes for ports.
22468 var currAttrs = this.get('attrs');
22469 _.each(this._portSelectors, function(selector) {
22470 if (currAttrs[selector]) delete currAttrs[selector];
22473 // This holds keys to the `attrs` object for all the port specific attribute that
22474 // we set in this method. This is necessary in order to remove previously set
22475 // attributes for previous ports.
22476 this._portSelectors = [];
22480 _.each(this.get('inPorts'), function(portName, index, ports) {
22481 var portAttributes = this.getPortAttrs(portName, index, ports.length, '.inPorts', 'in');
22482 this._portSelectors = this._portSelectors.concat(_.keys(portAttributes));
22483 _.extend(attrs, portAttributes);
22486 _.each(this.get('outPorts'), function(portName, index, ports) {
22487 var portAttributes = this.getPortAttrs(portName, index, ports.length, '.outPorts', 'out');
22488 this._portSelectors = this._portSelectors.concat(_.keys(portAttributes));
22489 _.extend(attrs, portAttributes);
22492 // Silently set `attrs` on the cell so that noone knows the attrs have changed. This makes sure
22493 // that, for example, command manager does not register `change:attrs` command but only
22494 // the important `change:inPorts`/`change:outPorts` command.
22495 this.attr(attrs, { silent: true });
22496 // Manually call the `processPorts()` method that is normally called on `change:attrs` (that we just made silent).
22497 this.processPorts();
22498 // Let the outside world (mainly the `ModelView`) know that we're done configuring the `attrs` object.
22499 this.trigger('process:ports');
22502 getPortSelector: function(name) {
22504 var selector = '.inPorts';
22505 var index = this.get('inPorts').indexOf(name);
22508 selector = '.outPorts';
22509 index = this.get('outPorts').indexOf(name);
22511 if (index < 0) throw new Error("getPortSelector(): Port doesn't exist.");
22514 return selector + '>g:nth-child(' + (index + 1) + ')>circle';
22518 joint.shapes.basic.PortsViewInterface = {
22520 initialize: function() {
22522 // `Model` emits the `process:ports` whenever it's done configuring the `attrs` object for ports.
22523 this.listenTo(this.model, 'process:ports', this.update);
22525 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
22528 update: function() {
22530 // First render ports so that `attrs` can be applied to those newly created DOM elements
22531 // in `ElementView.prototype.update()`.
22532 this.renderPorts();
22533 joint.dia.ElementView.prototype.update.apply(this, arguments);
22536 renderPorts: function() {
22538 var $inPorts = this.$('.inPorts').empty();
22539 var $outPorts = this.$('.outPorts').empty();
22541 var portTemplate = _.template(this.model.portMarkup);
22543 _.each(_.filter(this.model.ports, function(p) { return p.type === 'in' }), function(port, index) {
22545 $inPorts.append(V(portTemplate({ id: index, port: port })).node);
22547 _.each(_.filter(this.model.ports, function(p) { return p.type === 'out' }), function(port, index) {
22549 $outPorts.append(V(portTemplate({ id: index, port: port })).node);
22554 joint.shapes.basic.TextBlock = joint.shapes.basic.Generic.extend({
22556 markup: ['<g class="rotatable"><g class="scalable"><rect/></g><switch>',
22558 // if foreignObject supported
22560 '<foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" class="fobj">',
22561 '<body xmlns="http://www.w3.org/1999/xhtml"><div/></body>',
22562 '</foreignObject>',
22564 // else foreignObject is not supported (fallback for IE)
22565 '<text class="content"/>',
22567 '</switch></g>'].join(''),
22569 defaults: joint.util.deepSupplement({
22571 type: 'basic.TextBlock',
22573 // see joint.css for more element styles
22584 'font-family': 'Arial, helvetica, sans-serif'
22591 'y-alignment': 'middle',
22592 'x-alignment': 'middle'
22598 }, joint.shapes.basic.Generic.prototype.defaults),
22600 initialize: function() {
22602 if (typeof SVGForeignObjectElement !== 'undefined') {
22604 // foreignObject supported
22605 this.setForeignObjectSize(this, this.get('size'));
22606 this.setDivContent(this, this.get('content'));
22607 this.listenTo(this, 'change:size', this.setForeignObjectSize);
22608 this.listenTo(this, 'change:content', this.setDivContent);
22612 joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
22615 setForeignObjectSize: function(cell, size) {
22617 // Selector `foreignObject' doesn't work accross all browsers, we'r using class selector instead.
22618 // We have to clone size as we don't want attributes.div.style to be same object as attributes.size.
22620 '.fobj': _.clone(size),
22621 div: { style: _.clone(size) }
22625 setDivContent: function(cell, content) {
22627 // Append the content to div as html.
22628 cell.attr({ div : {
22635 // TextBlockView implements the fallback for IE when no foreignObject exists and
22636 // the text needs to be manually broken.
22637 joint.shapes.basic.TextBlockView = joint.dia.ElementView.extend({
22639 initialize: function() {
22641 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
22643 if (typeof SVGForeignObjectElement === 'undefined') {
22645 this.noSVGForeignObjectElement = true;
22647 this.listenTo(this.model, 'change:content', function(cell) {
22648 // avoiding pass of extra paramters
22649 this.updateContent(cell);
22654 update: function(cell, renderingOnlyAttrs) {
22656 if (this.noSVGForeignObjectElement) {
22658 var model = this.model;
22660 // Update everything but the content first.
22661 var noTextAttrs = _.omit(renderingOnlyAttrs || model.get('attrs'), '.content');
22662 joint.dia.ElementView.prototype.update.call(this, model, noTextAttrs);
22664 if (!renderingOnlyAttrs || _.has(renderingOnlyAttrs, '.content')) {
22665 // Update the content itself.
22666 this.updateContent(model, renderingOnlyAttrs);
22671 joint.dia.ElementView.prototype.update.call(this, model, renderingOnlyAttrs);
22675 updateContent: function(cell, renderingOnlyAttrs) {
22677 // Create copy of the text attributes
22678 var textAttrs = _.merge({}, (renderingOnlyAttrs || cell.get('attrs'))['.content']);
22680 delete textAttrs.text;
22682 // Break the content to fit the element size taking into account the attributes
22683 // set on the model.
22684 var text = joint.util.breakText(cell.get('content'), cell.get('size'), textAttrs, {
22685 // measuring sandbox svg document
22686 svgDocument: this.paper.svg
22689 // Create a new attrs with same structure as the model attrs { text: { *textAttributes* }}
22690 var attrs = joint.util.setByPath({}, '.content', textAttrs,'/');
22692 // Replace text attribute with the one we just processed.
22693 attrs['.content'].text = text;
22695 // Update the view using renderingOnlyAttributes parameter.
22696 joint.dia.ElementView.prototype.update.call(this, cell, attrs);
22700 if (typeof exports === 'object') {
22702 module.exports = joint.shapes.basic;
22705 joint.routers.orthogonal = function() {
22707 var sourceBBox, targetBBox;
22709 // Return the direction that one would have to take traveling from `p1` to `p2`.
22710 // This function assumes the line between `p1` and `p2` is orthogonal.
22711 function direction(p1, p2) {
22713 if (p1.y < p2.y && p1.x === p2.x) {
22715 } else if (p1.y > p2.y && p1.x === p2.x) {
22717 } else if (p1.x < p2.x && p1.y === p2.y) {
22723 function bestDirection(p1, p2, preferredDirection) {
22727 // This branching determines possible directions that one can take to travel
22728 // from `p1` to `p2`.
22731 if (p1.y > p2.y) { directions = ['up', 'right']; }
22732 else if (p1.y < p2.y) { directions = ['down', 'right']; }
22733 else { directions = ['right']; }
22735 } else if (p1.x > p2.x) {
22737 if (p1.y > p2.y) { directions = ['up', 'left']; }
22738 else if (p1.y < p2.y) { directions = ['down', 'left']; }
22739 else { directions = ['left']; }
22743 if (p1.y > p2.y) { directions = ['up']; }
22744 else { directions = ['down']; }
22747 if (_.contains(directions, preferredDirection)) {
22748 return preferredDirection;
22751 var direction = _.first(directions);
22753 // Should the direction be the exact opposite of the preferred direction,
22754 // try another one if such direction exists.
22755 switch (preferredDirection) {
22756 case 'down': if (direction === 'up') return _.last(directions); break;
22757 case 'up': if (direction === 'down') return _.last(directions); break;
22758 case 'left': if (direction === 'right') return _.last(directions); break;
22759 case 'right': if (direction === 'left') return _.last(directions); break;
22764 // Find a vertex in between the vertices `p1` and `p2` so that the route between those vertices
22765 // is orthogonal. Prefer going the direction determined by `preferredDirection`.
22766 function findMiddleVertex(p1, p2, preferredDirection) {
22768 var direction = bestDirection(p1, p2, preferredDirection);
22769 if (direction === 'down' || direction === 'up') {
22770 return { x: p1.x, y: p2.y, d: direction };
22772 return { x: p2.x, y: p1.y, d: direction };
22775 // Return points that one needs to draw a connection through in order to have a orthogonal link
22776 // routing from source to target going through `vertices`.
22777 function findOrthogonalRoute(vertices) {
22779 vertices = (vertices || []).slice();
22780 var orthogonalVertices = [];
22782 var sourceCenter = sourceBBox.center();
22783 var targetCenter = targetBBox.center();
22785 if (!vertices.length) {
22787 if (Math.abs(sourceCenter.x - targetCenter.x) < (sourceBBox.width / 2) ||
22788 Math.abs(sourceCenter.y - targetCenter.y) < (sourceBBox.height / 2)
22792 x: Math.min(sourceCenter.x, targetCenter.x) +
22793 Math.abs(sourceCenter.x - targetCenter.x) / 2,
22794 y: Math.min(sourceCenter.y, targetCenter.y) +
22795 Math.abs(sourceCenter.y - targetCenter.y) / 2
22800 vertices.unshift(sourceCenter);
22801 vertices.push(targetCenter);
22803 var orthogonalVertex;
22804 var lastOrthogonalVertex;
22808 // For all the pairs of link model vertices...
22809 for (var i = 0; i < vertices.length - 1; i++) {
22811 vertex = vertices[i];
22812 nextVertex = vertices[i + 1];
22813 lastOrthogonalVertex = _.last(orthogonalVertices);
22816 // Push all the link vertices to the orthogonal route.
22817 orthogonalVertex = vertex;
22818 // Determine a direction between the last vertex and the new one.
22819 // Therefore, each vertex contains the `d` property describing the direction that one
22820 // would have to take to travel to that vertex.
22821 orthogonalVertex.d = lastOrthogonalVertex
22822 ? direction(lastOrthogonalVertex, vertex)
22825 orthogonalVertices.push(orthogonalVertex);
22826 lastOrthogonalVertex = orthogonalVertex;
22829 // Make sure that we don't create a vertex that would go the opposite direction then
22830 // that of the previous one.
22831 // Othwerwise, a 'spike' segment would be created which is not desirable.
22832 // Find a dummy vertex to keep the link orthogonal. Preferably, take the same direction
22833 // as the previous one.
22834 var d = lastOrthogonalVertex && lastOrthogonalVertex.d;
22835 orthogonalVertex = findMiddleVertex(vertex, nextVertex, d);
22837 // Do not add a new vertex that is the same as one of the vertices already added.
22838 if (!g.point(orthogonalVertex).equals(g.point(vertex)) &&
22839 !g.point(orthogonalVertex).equals(g.point(nextVertex))) {
22841 orthogonalVertices.push(orthogonalVertex);
22844 return orthogonalVertices;
22847 return function(vertices) {
22849 sourceBBox = this.sourceBBox;
22850 targetBBox = this.targetBBox;
22852 return findOrthogonalRoute(vertices);
22857 joint.routers.manhattan = (function() {
22863 // size of the step to find a route
22866 // use of the perpendicular linkView option to connect center of element with first vertex
22867 perpendicular: true,
22869 // tells how to divide the paper when creating the elements map
22872 // should be source or target not to be consider as an obstacle
22873 excludeEnds: [], // 'source', 'target'
22875 // should be any element with a certain type not to be consider as an obstacle
22876 excludeTypes: ['basic.Text'],
22878 // if number of route finding loops exceed the maximum, stops searching and returns
22882 // possible starting directions from an element
22883 startDirections: ['left','right','top','bottom'],
22885 // possible ending directions to an element
22886 endDirections: ['left','right','top','bottom'],
22888 // specify directions above
22890 right: { x: 1, y: 0 },
22891 bottom: { x: 0, y: 1 },
22892 left: { x: -1, y: 0 },
22893 top: { x: 0, y: -1 }
22896 // maximum change of the direction
22897 maxAllowedDirectionChange: 1,
22899 // padding applied on the element bounding boxes
22900 paddingBox: function() {
22902 var step = this.step;
22912 // an array of directions to find next points on the route
22913 directions: function() {
22915 var step = this.step;
22918 { offsetX: step , offsetY: 0 , cost: step },
22919 { offsetX: 0 , offsetY: step , cost: step },
22920 { offsetX: -step , offsetY: 0 , cost: step },
22921 { offsetX: 0 , offsetY: -step , cost: step }
22925 // a penalty received for direction change
22926 penalties: function() {
22928 return [0, this.step / 2, this.step];
22931 // heurestic method to determine the distance between two points
22932 estimateCost: function(from, to) {
22934 return from.manhattanDistance(to);
22937 // a simple route used in situations, when main routing method fails
22938 // (exceed loops, inaccessible).
22939 fallbackRoute: function(from, to, opts) {
22941 // Find an orthogonal route ignoring obstacles.
22943 var prevDirIndexes = opts.prevDirIndexes || {};
22945 var point = (prevDirIndexes[from] || 0) % 2
22946 ? g.point(from.x, to.y)
22947 : g.point(to.x, from.y);
22949 return [point, to];
22952 // if a function is provided, it's used to route the link while dragging an end
22953 // i.e. function(from, to, opts) { return []; }
22954 draggingRoute: null
22957 // reconstructs a route by concating points with their parents
22958 function reconstructRoute(parents, point) {
22961 var prevDiff = { x: 0, y: 0 };
22962 var current = point;
22965 while ((parent = parents[current])) {
22967 var diff = parent.difference(current);
22969 if (!diff.equals(prevDiff)) {
22971 route.unshift(current);
22978 route.unshift(current);
22983 // find points around the rectangle taking given directions in the account
22984 function getRectPoints(bbox, directionList, opts) {
22986 var step = opts.step;
22988 var center = bbox.center();
22990 var startPoints = _.chain(opts.directionMap).pick(directionList).map(function(direction) {
22992 var x = direction.x * bbox.width / 2;
22993 var y = direction.y * bbox.height / 2;
22995 var point = g.point(center).offset(x,y).snapToGrid(step);
22997 if (bbox.containsPoint(point)) {
22999 point.offset(direction.x * step, direction.y * step);
23006 return startPoints;
23009 // returns a direction index from start point to end point
23010 function getDirection(start, end, dirLen) {
23012 var dirAngle = 360 / dirLen;
23014 var q = Math.floor(start.theta(end) / dirAngle);
23019 // finds the route between to points/rectangles implementing A* alghoritm
23020 function findRoute(start, end, map, opt) {
23022 var startDirections = opt.reversed ? opt.endDirections : opt.startDirections;
23023 var endDirections = opt.reversed ? opt.startDirections : opt.endDirections;
23025 // set of points we start pathfinding from
23026 var startSet = start instanceof g.rect
23027 ? getRectPoints(start, startDirections, opt)
23030 // set of points we want the pathfinding to finish at
23031 var endSet = end instanceof g.rect
23032 ? getRectPoints(end, endDirections, opt)
23035 var startCenter = startSet.length > 1 ? start.center() : startSet[0];
23036 var endCenter = endSet.length > 1 ? end.center() : endSet[0];
23038 // take into account only accessible end points
23039 var endPoints = _.filter(endSet, function(point) {
23041 var mapKey = g.point(point).snapToGrid(opt.mapGridSize).toString();
23043 var accesible = _.every(map[mapKey], function(obstacle) {
23044 return !obstacle.containsPoint(point);
23051 if (endPoints.length) {
23053 var step = opt.step;
23054 var penalties = opt.penalties;
23056 // choose the end point with the shortest estimated path cost
23057 var endPoint = _.chain(endPoints).invoke('snapToGrid', step).min(function(point) {
23059 return opt.estimateCost(startCenter, point);
23064 var costFromStart = {};
23065 var totalCost = {};
23068 var dirs = opt.directions;
23069 var dirLen = dirs.length;
23070 var dirHalfLen = dirLen / 2;
23071 var dirIndexes = opt.previousDirIndexes || {};
23073 // The set of point already evaluated.
23074 var closeHash = {}; // keeps only information whether a point was evaluated'
23076 // The set of tentative points to be evaluated, initially containing the start points
23077 var openHash = {}; // keeps only information whether a point is to be evaluated'
23078 var openSet = _.chain(startSet).invoke('snapToGrid', step).each(function(point) {
23080 var key = point.toString();
23082 costFromStart[key] = 0; // Cost from start along best known path.
23083 totalCost[key] = opt.estimateCost(point, endPoint);
23084 dirIndexes[key] = dirIndexes[key] || getDirection(startCenter, point, dirLen);
23085 openHash[key] = true;
23087 }).map(function(point) {
23089 return point.toString();
23091 }).sortBy(function(pointKey) {
23093 return totalCost[pointKey];
23097 var loopCounter = opt.maximumLoops;
23099 var maxAllowedDirectionChange = opt.maxAllowedDirectionChange;
23101 // main route finding loop
23102 while (openSet.length && loopCounter--) {
23104 var currentKey = openSet[0];
23105 var currentPoint = g.point(currentKey);
23107 if (endPoint.equals(currentPoint)) {
23109 opt.previousDirIndexes = _.pick(dirIndexes, currentKey);
23110 return reconstructRoute(parents, currentPoint);
23113 // remove current from the open list
23114 openSet.splice(0, 1);
23115 openHash[neighborKey] = null;
23117 // add current to the close list
23118 closeHash[neighborKey] = true;
23120 var currentDirIndex = dirIndexes[currentKey];
23121 var currentDist = costFromStart[currentKey];
23123 for (var dirIndex = 0; dirIndex < dirLen; dirIndex++) {
23125 var dirChange = Math.abs(dirIndex - currentDirIndex);
23127 if (dirChange > dirHalfLen) {
23129 dirChange = dirLen - dirChange;
23132 // if the direction changed rapidly don't use this point
23133 if (dirChange > maxAllowedDirectionChange) {
23138 var dir = dirs[dirIndex];
23140 var neighborPoint = g.point(currentPoint).offset(dir.offsetX, dir.offsetY);
23141 var neighborKey = neighborPoint.toString();
23143 if (closeHash[neighborKey]) {
23148 // is point accesible - no obstacle in the way
23150 var mapKey = g.point(neighborPoint).snapToGrid(opt.mapGridSize).toString();
23152 var isAccesible = _.every(map[mapKey], function(obstacle) {
23153 return !obstacle.containsPoint(neighborPoint);
23156 if (!isAccesible) {
23161 var inOpenSet = _.has(openHash, neighborKey);
23163 var costToNeighbor = currentDist + dir.cost;
23165 if (!inOpenSet || costToNeighbor < costFromStart[neighborKey]) {
23167 parents[neighborKey] = currentPoint;
23168 dirIndexes[neighborKey] = dirIndex;
23169 costFromStart[neighborKey] = costToNeighbor;
23171 totalCost[neighborKey] = costToNeighbor +
23172 opt.estimateCost(neighborPoint, endPoint) +
23173 penalties[dirChange];
23177 var openIndex = _.sortedIndex(openSet, neighborKey, function(openKey) {
23179 return totalCost[openKey];
23182 openSet.splice(openIndex, 0, neighborKey);
23183 openHash[neighborKey] = true;
23190 // no route found ('to' point wasn't either accessible or finding route took
23191 // way to much calculations)
23192 return opt.fallbackRoute(startCenter, endCenter, opt);
23195 // initiation of the route finding
23196 function router(oldVertices, opt) {
23198 // resolve some of the options
23199 opt.directions = _.result(opt, 'directions');
23200 opt.penalties = _.result(opt, 'penalties');
23201 opt.paddingBox = _.result(opt, 'paddingBox');
23203 // enable/disable linkView perpendicular option
23204 this.options.perpendicular = !!opt.perpendicular;
23206 // As route changes its shape rapidly when we start finding route from different point
23207 // it's necessary to start from the element that was not interacted with
23208 // (the position was changed) at very last.
23209 var reverseRouting = opt.reversed = (this.lastEndChange === 'source');
23211 var sourceBBox = reverseRouting ? g.rect(this.targetBBox) : g.rect(this.sourceBBox);
23212 var targetBBox = reverseRouting ? g.rect(this.sourceBBox) : g.rect(this.targetBBox);
23214 // expand boxes by specific padding
23215 sourceBBox.moveAndExpand(opt.paddingBox);
23216 targetBBox.moveAndExpand(opt.paddingBox);
23218 // building an elements map
23220 var link = this.model;
23221 var graph = this.paper.model;
23223 // source or target element could be excluded from set of obstacles
23224 var excludedEnds = _.chain(opt.excludeEnds)
23225 .map(link.get, link)
23227 .map(graph.getCell, graph).value();
23229 var mapGridSize = opt.mapGridSize;
23231 // builds a map of all elements for quicker obstacle queries (i.e. is a point contained
23232 // in any obstacle?) (a simplified grid search)
23233 // The paper is divided to smaller cells, where each of them holds an information which
23234 // elements belong to it. When we query whether a point is in an obstacle we don't need
23235 // to go through all obstacles, we check only those in a particular cell.
23236 var map = _.chain(graph.getElements())
23237 // remove source and target element if required
23238 .difference(excludedEnds)
23239 // remove all elements whose type is listed in excludedTypes array
23240 .reject(function(element) {
23241 return _.contains(opt.excludeTypes, element.get('type'));
23243 // change elements (models) to their bounding boxes
23245 // expand their boxes by specific padding
23246 .invoke('moveAndExpand', opt.paddingBox)
23248 .foldl(function(res, bbox) {
23250 var origin = bbox.origin().snapToGrid(mapGridSize);
23251 var corner = bbox.corner().snapToGrid(mapGridSize);
23253 for (var x = origin.x; x <= corner.x; x += mapGridSize) {
23254 for (var y = origin.y; y <= corner.y; y += mapGridSize) {
23256 var gridKey = x + '@' + y;
23258 res[gridKey] = res[gridKey] || [];
23259 res[gridKey].push(bbox);
23269 var newVertices = [];
23271 var points = _.map(oldVertices, g.point);
23273 var tailPoint = sourceBBox.center();
23275 // find a route by concating all partial routes (routes need to go through the vertices)
23276 // startElement -> vertex[1] -> ... -> vertex[n] -> endElement
23277 for (var i = 0, len = points.length; i <= len; i++) {
23279 var partialRoute = null;
23281 var from = to || sourceBBox;
23282 var to = points[i];
23288 // 'to' is not a vertex. If the target is a point (i.e. it's not an element), we
23289 // might use dragging route instead of main routing method if that is enabled.
23290 var endingAtPoint = !this.model.get('source').id || !this.model.get('target').id;
23292 if (endingAtPoint && _.isFunction(opt.draggingRoute)) {
23293 // Make sure we passing points only (not rects).
23294 var dragFrom = from instanceof g.rect ? from.center() : from;
23295 partialRoute = opt.draggingRoute(dragFrom, to.origin(), opt);
23299 // if partial route has not been calculated yet use the main routing method to find one
23300 partialRoute = partialRoute || findRoute(from, to, map, opt);
23302 var leadPoint = _.first(partialRoute);
23304 if (leadPoint && leadPoint.equals(tailPoint)) {
23306 // remove the first point if the previous partial route had the same point as last
23307 partialRoute.shift();
23310 tailPoint = _.last(partialRoute) || tailPoint;
23312 newVertices = newVertices.concat(partialRoute);
23315 // we might have to reverse the result if we swapped source and target at the beginning
23316 return reverseRouting ? newVertices.reverse() : newVertices;
23320 return function(vertices, opt, linkView) {
23322 return router.call(linkView, vertices, _.extend({}, config, opt));
23327 joint.routers.metro = (function() {
23329 if (!_.isFunction(joint.routers.manhattan)) {
23331 throw('Metro requires the manhattan router.');
23336 // cost of a diagonal step (calculated if not defined).
23337 diagonalCost: null,
23339 // an array of directions to find next points on the route
23340 directions: function() {
23342 var step = this.step;
23343 var diagonalCost = this.diagonalCost || Math.ceil(Math.sqrt(step * step << 1));
23346 { offsetX: step , offsetY: 0 , cost: step },
23347 { offsetX: step , offsetY: step , cost: diagonalCost },
23348 { offsetX: 0 , offsetY: step , cost: step },
23349 { offsetX: -step , offsetY: step , cost: diagonalCost },
23350 { offsetX: -step , offsetY: 0 , cost: step },
23351 { offsetX: -step , offsetY: -step , cost: diagonalCost },
23352 { offsetX: 0 , offsetY: -step , cost: step },
23353 { offsetX: step , offsetY: -step , cost: diagonalCost }
23357 // a simple route used in situations, when main routing method fails
23358 // (exceed loops, inaccessible).
23359 fallbackRoute: function(from, to, opts) {
23361 // Find a route which breaks by 45 degrees ignoring all obstacles.
23363 var theta = from.theta(to);
23365 var a = { x: to.x, y: from.y };
23366 var b = { x: from.x, y: to.y };
23368 if (theta % 180 > 90) {
23374 var p1 = (theta % 90) < 45 ? a : b;
23376 var l1 = g.line(from, p1);
23378 var alpha = 90 * Math.ceil(theta / 90);
23380 var p2 = g.point.fromPolar(l1.squaredLength(), g.toRad(alpha + 135), p1);
23382 var l2 = g.line(to, p2);
23384 var point = l1.intersection(l2);
23386 return point ? [point.round(), to] : [to];
23391 return function(vertices, opts, linkView) {
23393 return joint.routers.manhattan(vertices, _.extend({}, config, opts), linkView);
23398 joint.connectors.normal = function(sourcePoint, targetPoint, vertices) {
23400 // Construct the `d` attribute of the `<path>` element.
23401 var d = ['M', sourcePoint.x, sourcePoint.y];
23403 _.each(vertices, function(vertex) {
23405 d.push(vertex.x, vertex.y);
23408 d.push(targetPoint.x, targetPoint.y);
23410 return d.join(' ');
23413 joint.connectors.rounded = function(sourcePoint, targetPoint, vertices, opts) {
23415 var offset = opts.radius || 10;
23417 var c1, c2, d1, d2, prev, next;
23419 // Construct the `d` attribute of the `<path>` element.
23420 var d = ['M', sourcePoint.x, sourcePoint.y];
23422 _.each(vertices, function(vertex, index) {
23424 // the closest vertices
23425 prev = vertices[index-1] || sourcePoint;
23426 next = vertices[index+1] || targetPoint;
23428 // a half distance to the closest vertex
23429 d1 = d2 || g.point(vertex).distance(prev) / 2;
23430 d2 = g.point(vertex).distance(next) / 2;
23433 c1 = g.point(vertex).move(prev, -Math.min(offset, d1)).round();
23434 c2 = g.point(vertex).move(next, -Math.min(offset, d2)).round();
23436 d.push(c1.x, c1.y, 'S', vertex.x, vertex.y, c2.x, c2.y, 'L');
23439 d.push(targetPoint.x, targetPoint.y);
23441 return d.join(' ');
23444 joint.connectors.smooth = function(sourcePoint, targetPoint, vertices) {
23448 if (vertices.length) {
23450 d = g.bezier.curveThroughPoints([sourcePoint].concat(vertices).concat([targetPoint]));
23453 // if we have no vertices use a default cubic bezier curve, cubic bezier requires
23454 // two control points. The two control points are both defined with X as mid way
23455 // between the source and target points. SourceControlPoint Y is equal to sourcePoint Y
23456 // and targetControlPointY being equal to targetPointY. Handle situation were
23457 // sourcePointX is greater or less then targetPointX.
23458 var controlPointX = (sourcePoint.x < targetPoint.x)
23459 ? targetPoint.x - ((targetPoint.x - sourcePoint.x) / 2)
23460 : sourcePoint.x - ((sourcePoint.x - targetPoint.x) / 2);
23463 'M', sourcePoint.x, sourcePoint.y,
23464 'C', controlPointX, sourcePoint.y, controlPointX, targetPoint.y,
23465 targetPoint.x, targetPoint.y
23469 return d.join(' ');