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;
16995 // Note that `translate()` is always the first transformation. This is
16996 // usually the desired case.
16997 this.attr('transform', 'translate(' + newTx + ',' + newTy + ') ' + transformAttr);
17001 rotate: function(angle, cx, cy) {
17002 var transformAttr = this.attr('transform') || '',
17003 transform = parseTransformString(transformAttr);
17006 if (typeof angle === 'undefined') {
17007 return transform.rotate;
17010 transformAttr = transformAttr.replace(/rotate\([^\)]*\)/g, '').trim();
17012 var newAngle = transform.rotate.angle + angle % 360,
17013 newOrigin = (cx !== undefined && cy !== undefined) ? ',' + cx + ',' + cy : '';
17015 this.attr('transform', transformAttr + ' rotate(' + newAngle + newOrigin + ')');
17019 // Note that `scale` as the only transformation does not combine with previous values.
17020 scale: function(sx, sy) {
17021 sy = (typeof sy === 'undefined') ? sx : sy;
17023 var transformAttr = this.attr('transform') || '',
17024 transform = parseTransformString(transformAttr);
17027 if (typeof sx === 'undefined') {
17028 return transform.scale;
17031 transformAttr = transformAttr.replace(/scale\([^\)]*\)/g, '').trim();
17033 this.attr('transform', transformAttr + ' scale(' + sx + ',' + sy + ')');
17037 // Get SVGRect that contains coordinates and dimension of the real bounding box,
17038 // i.e. after transformations are applied.
17039 // If `target` is specified, bounding box will be computed relatively to `target` element.
17040 bbox: function(withoutTransformations, target) {
17042 // If the element is not in the live DOM, it does not have a bounding box defined and
17043 // so fall back to 'zero' dimension element.
17044 if (!this.node.ownerSVGElement) return { x: 0, y: 0, width: 0, height: 0 };
17049 box = this.node.getBBox();
17051 // Opera returns infinite values in some cases.
17052 // Note that Infinity | 0 produces 0 as opposed to Infinity || 0.
17053 // We also have to create new object as the standard says that you can't
17054 // modify the attributes of a bbox.
17055 box = { x: box.x | 0, y: box.y | 0, width: box.width | 0, height: box.height | 0};
17059 // Fallback for IE.
17061 x: this.node.clientLeft,
17062 y: this.node.clientTop,
17063 width: this.node.clientWidth,
17064 height: this.node.clientHeight
17068 if (withoutTransformations) {
17073 var matrix = this.node.getTransformToElement(target || this.node.ownerSVGElement);
17075 var point = this.node.ownerSVGElement.createSVGPoint();
17080 corners.push(point.matrixTransform(matrix));
17082 point.x = box.x + box.width;
17084 corners.push(point.matrixTransform(matrix));
17086 point.x = box.x + box.width;
17087 point.y = box.y + box.height;
17088 corners.push(point.matrixTransform(matrix));
17091 point.y = box.y + box.height;
17092 corners.push(point.matrixTransform(matrix));
17094 var minX = corners[0].x;
17096 var minY = corners[0].y;
17099 for (var i = 1, len = corners.length; i < len; i++) {
17101 var x = corners[i].x;
17102 var y = corners[i].y;
17106 } else if (x > maxX) {
17112 } else if (y > maxY) {
17120 width: maxX - minX,
17121 height: maxY - minY
17125 text: function(content) {
17126 var lines = content.split('\n'), i = 0,
17129 // `alignment-baseline` does not work in Firefox.
17130 // Setting `dominant-baseline` on the `<text>` element doesn't work in IE9.
17131 // In order to have the 0,0 coordinate of the `<text>` element (or the first `<tspan>`)
17132 // in the top left corner we translate the `<text>` element by `0.8em`.
17133 // See `http://www.w3.org/Graphics/SVG/WG/wiki/How_to_determine_dominant_baseline`.
17134 // See also `http://apike.ca/prog_svg_text_style.html`.
17135 this.attr('y', '0.8em');
17137 // An empty text gets rendered into the DOM in webkit-based browsers.
17138 // In order to unify this behaviour across all browsers
17139 // we rather hide the text element when it's empty.
17140 this.attr('display', content ? null : 'none');
17142 if (lines.length === 1) {
17143 this.node.textContent = content;
17146 // Easy way to erase all `<tspan>` children;
17147 this.node.textContent = '';
17149 for (; i < lines.length; i++) {
17151 // Shift all the <tspan> but first by one line (`1em`)
17152 tspan = V('tspan', { dy: (i == 0 ? '0em' : '1em'), x: this.attr('x') || 0});
17153 tspan.node.textContent = lines[i];
17155 this.append(tspan);
17160 attr: function(name, value) {
17162 if (typeof name === 'string' && typeof value === 'undefined') {
17163 return this.node.getAttribute(name);
17166 if (typeof name === 'object') {
17168 for (var attrName in name) {
17169 if (name.hasOwnProperty(attrName)) {
17170 setAttribute(this.node, attrName, name[attrName]);
17176 setAttribute(this.node, name, value);
17182 remove: function() {
17183 if (this.node.parentNode) {
17184 this.node.parentNode.removeChild(this.node);
17188 append: function(el) {
17192 if (Object.prototype.toString.call(el) !== '[object Array]') {
17197 for (var i = 0, len = els.length; i < len; i++) {
17199 this.node.appendChild(el instanceof VElement ? el.node : el);
17205 prepend: function(el) {
17206 this.node.insertBefore(el instanceof VElement ? el.node : el, this.node.firstChild);
17211 return this.node instanceof window.SVGSVGElement ? this : V(this.node.ownerSVGElement);
17216 var defs = this.svg().node.getElementsByTagName('defs');
17218 return (defs && defs.length) ? V(defs[0]) : undefined;
17221 clone: function() {
17222 var clone = V(this.node.cloneNode(true));
17223 // Note that clone inherits also ID. Therefore, we need to change it here.
17224 clone.node.id = uniqueId();
17228 findOne: function(selector) {
17230 var found = this.node.querySelector(selector);
17231 return found ? V(found) : undefined;
17234 find: function(selector) {
17236 var nodes = this.node.querySelectorAll(selector);
17238 // Map DOM elements to `VElement`s.
17239 for (var i = 0, len = nodes.length; i < len; i++) {
17240 nodes[i] = V(nodes[i]);
17245 // Convert global point into the coordinate space of this element.
17246 toLocalPoint: function(x, y) {
17248 var svg = this.svg().node;
17250 var p = svg.createSVGPoint();
17256 var globalPoint = p.matrixTransform(svg.getScreenCTM().inverse());
17257 var globalToLocalMatrix = this.node.getTransformToElement(svg).inverse();
17260 // IE9 throws an exception in odd cases. (`Unexpected call to method or property access`)
17261 // We have to make do with the original coordianates.
17265 return globalPoint.matrixTransform(globalToLocalMatrix);
17268 translateCenterToPoint: function(p) {
17270 var bbox = this.bbox();
17271 var center = g.rect(bbox).center();
17273 this.translate(p.x - center.x, p.y - center.y);
17276 // Efficiently auto-orient an element. This basically implements the orient=auto attribute
17277 // of markers. The easiest way of understanding on what this does is to imagine the element is an
17278 // arrowhead. Calling this method on the arrowhead makes it point to the `position` point while
17279 // being auto-oriented (properly rotated) towards the `reference` point.
17280 // `target` is the element relative to which the transformations are applied. Usually a viewport.
17281 translateAndAutoOrient: function(position, reference, target) {
17283 // Clean-up previously set transformations except the scale. If we didn't clean up the
17284 // previous transformations then they'd add up with the old ones. Scale is an exception as
17285 // it doesn't add up, consider: `this.scale(2).scale(2).scale(2)`. The result is that the
17286 // element is scaled by the factor 2, not 8.
17288 var s = this.scale();
17289 this.attr('transform', '');
17290 this.scale(s.sx, s.sy);
17292 var svg = this.svg().node;
17293 var bbox = this.bbox(false, target);
17295 // 1. Translate to origin.
17296 var translateToOrigin = svg.createSVGTransform();
17297 translateToOrigin.setTranslate(-bbox.x - bbox.width/2, -bbox.y - bbox.height/2);
17299 // 2. Rotate around origin.
17300 var rotateAroundOrigin = svg.createSVGTransform();
17301 var angle = g.point(position).changeInAngle(position.x - reference.x, position.y - reference.y, reference);
17302 rotateAroundOrigin.setRotate(angle, 0, 0);
17304 // 3. Translate to the `position` + the offset (half my width) towards the `reference` point.
17305 var translateFinal = svg.createSVGTransform();
17306 var finalPosition = g.point(position).move(reference, bbox.width/2);
17307 translateFinal.setTranslate(position.x + (position.x - finalPosition.x), position.y + (position.y - finalPosition.y));
17309 // 4. Apply transformations.
17310 var ctm = this.node.getTransformToElement(target);
17311 var transform = svg.createSVGTransform();
17312 transform.setMatrix(
17313 translateFinal.matrix.multiply(
17314 rotateAroundOrigin.matrix.multiply(
17315 translateToOrigin.matrix.multiply(
17319 // Instead of directly setting the `matrix()` transform on the element, first, decompose
17320 // the matrix into separate transforms. This allows us to use normal Vectorizer methods
17321 // as they don't work on matrices. An example of this is to retrieve a scale of an element.
17322 // this.node.transform.baseVal.initialize(transform);
17324 var decomposition = decomposeMatrix(transform.matrix);
17326 this.translate(decomposition.translateX, decomposition.translateY);
17327 this.rotate(decomposition.rotation);
17328 // Note that scale has been already applied, hence the following line stays commented. (it's here just for reference).
17329 //this.scale(decomposition.scaleX, decomposition.scaleY);
17334 animateAlongPath: function(attrs, path) {
17336 var animateMotion = V('animateMotion', attrs);
17337 var mpath = V('mpath', { 'xlink:href': '#' + V(path).node.id });
17339 animateMotion.append(mpath);
17341 this.append(animateMotion);
17343 animateMotion.node.beginElement();
17345 // Fallback for IE 9.
17346 // Run the animation programatically if FakeSmile (`http://leunen.me/fakesmile/`) present
17347 if (document.documentElement.getAttribute('smiling') === 'fake') {
17349 // Register the animation. (See `https://answers.launchpad.net/smil/+question/203333`)
17350 var animation = animateMotion.node;
17351 animation.animators = [];
17353 var animationID = animation.getAttribute('id');
17354 if (animationID) id2anim[animationID] = animation;
17356 var targets = getTargets(animation);
17357 for (var i = 0, len = targets.length; i < len; i++) {
17358 var target = targets[i];
17359 var animator = new Animator(animation, target, i);
17360 animators.push(animator);
17361 animation.animators[i] = animator;
17362 animator.register();
17368 hasClass: function(className) {
17370 return new RegExp('(\\s|^)' + className + '(\\s|$)').test(this.node.getAttribute('class'));
17373 addClass: function(className) {
17375 if (!this.hasClass(className)) {
17376 this.node.setAttribute('class', this.node.getAttribute('class') + ' ' + className);
17382 removeClass: function(className) {
17384 var removedClass = this.node.getAttribute('class').replace(new RegExp('(\\s|^)' + className + '(\\s|$)', 'g'), '$2');
17386 if (this.hasClass(className)) {
17387 this.node.setAttribute('class', removedClass);
17393 toggleClass: function(className, toAdd) {
17395 var toRemove = typeof toAdd === 'undefined' ? this.hasClass(className) : !toAdd;
17398 this.removeClass(className);
17400 this.addClass(className);
17407 // Convert a rectangle to SVG path commands. `r` is an object of the form:
17408 // `{ x: [number], y: [number], width: [number], height: [number], top-ry: [number], top-ry: [number], bottom-rx: [number], bottom-ry: [number] }`,
17409 // where `x, y, width, height` are the usual rectangle attributes and [top-/bottom-]rx/ry allows for
17410 // specifying radius of the rectangle for all its sides (as opposed to the built-in SVG rectangle
17411 // that has only `rx` and `ry` attributes).
17412 function rectToPath(r) {
17414 var topRx = r.rx || r['top-rx'] || 0;
17415 var bottomRx = r.rx || r['bottom-rx'] || 0;
17416 var topRy = r.ry || r['top-ry'] || 0;
17417 var bottomRy = r.ry || r['bottom-ry'] || 0;
17420 'M', r.x, r.y + topRy,
17421 'v', r.height - topRy - bottomRy,
17422 'a', bottomRx, bottomRy, 0, 0, 0, bottomRx, bottomRy,
17423 'h', r.width - 2 * bottomRx,
17424 'a', bottomRx, bottomRy, 0, 0, 0, bottomRx, -bottomRy,
17425 'v', -(r.height - bottomRy - topRy),
17426 'a', topRx, topRy, 0, 0, 0, -topRx, -topRy,
17427 'h', -(r.width - 2 * topRx),
17428 'a', topRx, topRy, 0, 0, 0, -topRx, topRy
17432 var V = createElement;
17434 V.decomposeMatrix = decomposeMatrix;
17435 V.rectToPath = rectToPath;
17437 var svgDocument = V('svg').node;
17439 V.createSVGMatrix = function(m) {
17441 var svgMatrix = svgDocument.createSVGMatrix();
17442 for (var component in m) {
17443 svgMatrix[component] = m[component];
17449 V.createSVGTransform = function() {
17451 return svgDocument.createSVGTransform();
17454 V.createSVGPoint = function(x, y) {
17456 var p = svgDocument.createSVGPoint();
17467 // Geometry library.
17468 // (c) 2011-2013 client IO
17471 (function(root, factory) {
17473 if (typeof define === 'function' && define.amd) {
17474 // AMD. Register as an anonymous module.
17475 define([], factory);
17477 } else if (typeof exports === 'object') {
17478 // Node. Does not work with strict CommonJS, but
17479 // only CommonJS-like environments that support module.exports,
17481 module.exports = factory();
17484 // Browser globals.
17485 root.g = factory();
17488 }(this, function() {
17491 // Declare shorthands to the most used math functions.
17493 var abs = math.abs;
17494 var cos = math.cos;
17495 var sin = math.sin;
17496 var sqrt = math.sqrt;
17497 var mmin = math.min;
17498 var mmax = math.max;
17499 var atan = math.atan;
17500 var atan2 = math.atan2;
17501 var acos = math.acos;
17502 var round = math.round;
17503 var floor = math.floor;
17505 var random = math.random;
17506 var toDeg = function(rad) { return (180*rad / PI) % 360; };
17507 var toRad = function(deg) { return (deg % 360) * PI / 180; };
17508 var snapToGrid = function(val, gridSize) { return gridSize * Math.round(val/gridSize); };
17509 var normalizeAngle = function(angle) { return (angle % 360) + (angle < 0 ? 360 : 0); };
17514 // Point is the most basic object consisting of x/y coordinate,.
17516 // Possible instantiations are:
17518 // * `point(10, 20)`
17519 // * `new point(10, 20)`
17520 // * `point('10 20')`
17521 // * `point(point(10, 20))`
17522 function point(x, y) {
17523 if (!(this instanceof point))
17524 return new point(x, y);
17526 if (y === undefined && Object(x) !== x) {
17527 xy = x.split(x.indexOf('@') === -1 ? ' ' : '@');
17528 this.x = parseInt(xy[0], 10);
17529 this.y = parseInt(xy[1], 10);
17530 } else if (Object(x) === x) {
17539 point.prototype = {
17540 toString: function() {
17541 return this.x + "@" + this.y;
17543 // If point lies outside rectangle `r`, return the nearest point on the boundary of rect `r`,
17544 // otherwise return point itself.
17545 // (see Squeak Smalltalk, Point>>adhereTo:)
17546 adhereToRect: function(r) {
17547 if (r.containsPoint(this)){
17550 this.x = mmin(mmax(this.x, r.x), r.x + r.width);
17551 this.y = mmin(mmax(this.y, r.y), r.y + r.height);
17554 // Compute the angle between me and `p` and the x axis.
17555 // (cartesian-to-polar coordinates conversion)
17556 // Return theta angle in degrees.
17557 theta: function(p) {
17559 // Invert the y-axis.
17560 var y = -(p.y - this.y);
17561 var x = p.x - this.x;
17562 // Makes sure that the comparison with zero takes rounding errors into account.
17563 var PRECISION = 10;
17564 // Note that `atan2` is not defined for `x`, `y` both equal zero.
17565 var rad = (y.toFixed(PRECISION) == 0 && x.toFixed(PRECISION) == 0) ? 0 : atan2(y, x);
17567 // Correction for III. and IV. quadrant.
17571 return 180*rad / PI;
17573 // Returns distance between me and point `p`.
17574 distance: function(p) {
17575 return line(this, p).length();
17577 // Returns a manhattan (taxi-cab) distance between me and point `p`.
17578 manhattanDistance: function(p) {
17579 return abs(p.x - this.x) + abs(p.y - this.y);
17581 // Offset me by the specified amount.
17582 offset: function(dx, dy) {
17587 magnitude: function() {
17588 return sqrt((this.x*this.x) + (this.y*this.y)) || 0.01;
17590 update: function(x, y) {
17595 round: function(decimals) {
17596 this.x = decimals ? this.x.toFixed(decimals) : round(this.x);
17597 this.y = decimals ? this.y.toFixed(decimals) : round(this.y);
17600 // Scale the line segment between (0,0) and me to have a length of len.
17601 normalize: function(len) {
17602 var s = (len || 1) / this.magnitude();
17603 this.x = s * this.x;
17604 this.y = s * this.y;
17607 difference: function(p) {
17608 return point(this.x - p.x, this.y - p.y);
17610 // Return the bearing between me and point `p`.
17611 bearing: function(p) {
17612 return line(this, p).bearing();
17614 // Converts rectangular to polar coordinates.
17615 // An origin can be specified, otherwise it's 0@0.
17616 toPolar: function(o) {
17617 o = (o && point(o)) || point(0,0);
17620 this.x = sqrt((x-o.x)*(x-o.x) + (y-o.y)*(y-o.y)); // r
17621 this.y = toRad(o.theta(point(x,y)));
17624 // Rotate point by angle around origin o.
17625 rotate: function(o, angle) {
17626 angle = (angle + 360) % 360;
17628 this.y += toRad(angle);
17629 var p = point.fromPolar(this.x, this.y, o);
17634 // Move point on line starting from ref ending at me by
17635 // distance distance.
17636 move: function(ref, distance) {
17637 var theta = toRad(point(ref).theta(this));
17638 return this.offset(cos(theta) * distance, -sin(theta) * distance);
17640 // Returns change in angle from my previous position (-dx, -dy) to my new position
17641 // relative to ref point.
17642 changeInAngle: function(dx, dy, ref) {
17643 // Revert the translation and measure the change in angle around x-axis.
17644 return point(this).offset(-dx, -dy).theta(ref) - this.theta(ref);
17646 equals: function(p) {
17647 return this.x === p.x && this.y === p.y;
17649 snapToGrid: function(gx, gy) {
17650 this.x = snapToGrid(this.x, gx)
17651 this.y = snapToGrid(this.y, gy || gx)
17655 // Alternative constructor, from polar coordinates.
17656 // @param {number} r Distance.
17657 // @param {number} angle Angle in radians.
17658 // @param {point} [optional] o Origin.
17659 point.fromPolar = function(r, angle, o) {
17660 o = (o && point(o)) || point(0,0);
17661 var x = abs(r * cos(angle));
17662 var y = abs(r * sin(angle));
17663 var deg = normalizeAngle(toDeg(angle));
17665 if (deg < 90) y = -y;
17666 else if (deg < 180) { x = -x; y = -y; }
17667 else if (deg < 270) x = -x;
17669 return point(o.x + x, o.y + y);
17672 // Create a point with random coordinates that fall into the range `[x1, x2]` and `[y1, y2]`.
17673 point.random = function(x1, x2, y1, y2) {
17674 return point(floor(random() * (x2 - x1 + 1) + x1), floor(random() * (y2 - y1 + 1) + y1));
17679 function line(p1, p2) {
17680 if (!(this instanceof line))
17681 return new line(p1, p2);
17682 this.start = point(p1);
17683 this.end = point(p2);
17687 toString: function() {
17688 return this.start.toString() + ' ' + this.end.toString();
17690 // @return {double} length of the line
17691 length: function() {
17692 return sqrt(this.squaredLength());
17694 // @return {integer} length without sqrt
17695 // @note for applications where the exact length is not necessary (e.g. compare only)
17696 squaredLength: function() {
17697 var x0 = this.start.x;
17698 var y0 = this.start.y;
17699 var x1 = this.end.x;
17700 var y1 = this.end.y;
17701 return (x0 -= x1)*x0 + (y0 -= y1)*y0;
17703 // @return {point} my midpoint
17704 midpoint: function() {
17705 return point((this.start.x + this.end.x) / 2,
17706 (this.start.y + this.end.y) / 2);
17708 // @return {point} Point where I'm intersecting l.
17709 // @see Squeak Smalltalk, LineSegment>>intersectionWith:
17710 intersection: function(l) {
17711 var pt1Dir = point(this.end.x - this.start.x, this.end.y - this.start.y);
17712 var pt2Dir = point(l.end.x - l.start.x, l.end.y - l.start.y);
17713 var det = (pt1Dir.x * pt2Dir.y) - (pt1Dir.y * pt2Dir.x);
17714 var deltaPt = point(l.start.x - this.start.x, l.start.y - this.start.y);
17715 var alpha = (deltaPt.x * pt2Dir.y) - (deltaPt.y * pt2Dir.x);
17716 var beta = (deltaPt.x * pt1Dir.y) - (deltaPt.y * pt1Dir.x);
17721 // No intersection found.
17725 if (alpha > det || beta > det){
17729 if (alpha < det || beta < det){
17733 return point(this.start.x + (alpha * pt1Dir.x / det),
17734 this.start.y + (alpha * pt1Dir.y / det));
17737 // @return the bearing (cardinal direction) of the line. For example N, W, or SE.
17738 // @returns {String} One of the following bearings : NE, E, SE, S, SW, W, NW, N.
17739 bearing: function() {
17741 var lat1 = toRad(this.start.y);
17742 var lat2 = toRad(this.end.y);
17743 var lon1 = this.start.x;
17744 var lon2 = this.end.x;
17745 var dLon = toRad(lon2 - lon1);
17746 var y = sin(dLon) * cos(lat2);
17747 var x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
17748 var brng = toDeg(atan2(y, x));
17750 var bearings = ['NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N'];
17752 var index = brng - 22.5;
17755 index = parseInt(index / 45);
17757 return bearings[index];
17763 function rect(x, y, w, h) {
17764 if (!(this instanceof rect))
17765 return new rect(x, y, w, h);
17766 if (y === undefined) {
17779 toString: function() {
17780 return this.origin().toString() + ' ' + this.corner().toString();
17782 origin: function() {
17783 return point(this.x, this.y);
17785 corner: function() {
17786 return point(this.x + this.width, this.y + this.height);
17788 topRight: function() {
17789 return point(this.x + this.width, this.y);
17791 bottomLeft: function() {
17792 return point(this.x, this.y + this.height);
17794 center: function() {
17795 return point(this.x + this.width/2, this.y + this.height/2);
17797 // @return {boolean} true if rectangles intersect
17798 intersect: function(r) {
17799 var myOrigin = this.origin();
17800 var myCorner = this.corner();
17801 var rOrigin = r.origin();
17802 var rCorner = r.corner();
17804 if (rCorner.x <= myOrigin.x ||
17805 rCorner.y <= myOrigin.y ||
17806 rOrigin.x >= myCorner.x ||
17807 rOrigin.y >= myCorner.y) return false;
17810 // @return {string} (left|right|top|bottom) side which is nearest to point
17811 // @see Squeak Smalltalk, Rectangle>>sideNearestTo:
17812 sideNearestToPoint: function(p) {
17814 var distToLeft = p.x - this.x;
17815 var distToRight = (this.x + this.width) - p.x;
17816 var distToTop = p.y - this.y;
17817 var distToBottom = (this.y + this.height) - p.y;
17818 var closest = distToLeft;
17821 if (distToRight < closest) {
17822 closest = distToRight;
17825 if (distToTop < closest) {
17826 closest = distToTop;
17829 if (distToBottom < closest) {
17830 closest = distToBottom;
17835 // @return {bool} true if point p is insight me
17836 containsPoint: function(p) {
17838 if (p.x >= this.x && p.x <= this.x + this.width &&
17839 p.y >= this.y && p.y <= this.y + this.height) {
17844 // Algorithm ported from java.awt.Rectangle from OpenJDK.
17845 // @return {bool} true if rectangle `r` is inside me.
17846 containsRect: function(r) {
17847 var nr = rect(r).normalize();
17852 var w = this.width;
17853 var h = this.height;
17854 if ((w | h | W | H) < 0) {
17855 // At least one of the dimensions is negative...
17858 // Note: if any dimension is zero, tests below must return false...
17861 if (X < x || Y < y) {
17867 // X+W overflowed or W was zero, return false if...
17868 // either original w or W was zero or
17869 // x+w did not overflow or
17870 // the overflowed x+w is smaller than the overflowed X+W
17871 if (w >= x || W > w) return false;
17873 // X+W did not overflow and W was not zero, return false if...
17874 // original w was zero or
17875 // x+w did not overflow and x+w is smaller than X+W
17876 if (w >= x && W > w) return false;
17881 if (h >= y || H > h) return false;
17883 if (h >= y && H > h) return false;
17887 // @return {point} a point on my boundary nearest to p
17888 // @see Squeak Smalltalk, Rectangle>>pointNearestTo:
17889 pointNearestToPoint: function(p) {
17891 if (this.containsPoint(p)) {
17892 var side = this.sideNearestToPoint(p);
17894 case "right": return point(this.x + this.width, p.y);
17895 case "left": return point(this.x, p.y);
17896 case "bottom": return point(p.x, this.y + this.height);
17897 case "top": return point(p.x, this.y);
17900 return p.adhereToRect(this);
17902 // Find point on my boundary where line starting
17903 // from my center ending in point p intersects me.
17904 // @param {number} angle If angle is specified, intersection with rotated rectangle is computed.
17905 intersectionWithLineFromCenterToPoint: function(p, angle) {
17907 var center = point(this.x + this.width/2, this.y + this.height/2);
17909 if (angle) p.rotate(center, angle);
17911 // (clockwise, starting from the top side)
17913 line(this.origin(), this.topRight()),
17914 line(this.topRight(), this.corner()),
17915 line(this.corner(), this.bottomLeft()),
17916 line(this.bottomLeft(), this.origin())
17918 var connector = line(center, p);
17920 for (var i = sides.length - 1; i >= 0; --i){
17921 var intersection = sides[i].intersection(connector);
17922 if (intersection !== null){
17923 result = intersection;
17927 if (result && angle) result.rotate(center, -angle);
17930 // Move and expand me.
17931 // @param r {rectangle} representing deltas
17932 moveAndExpand: function(r) {
17935 this.width += r.width;
17936 this.height += r.height;
17939 round: function(decimals) {
17940 this.x = decimals ? this.x.toFixed(decimals) : round(this.x);
17941 this.y = decimals ? this.y.toFixed(decimals) : round(this.y);
17942 this.width = decimals ? this.width.toFixed(decimals) : round(this.width);
17943 this.height = decimals ? this.height.toFixed(decimals) : round(this.height);
17946 // Normalize the rectangle; i.e., make it so that it has a non-negative width and height.
17947 // If width < 0 the function swaps the left and right corners,
17948 // and it swaps the top and bottom corners if height < 0
17949 // like in http://qt-project.org/doc/qt-4.8/qrectf.html#normalized
17950 normalize: function() {
17953 var newwidth = this.width;
17954 var newheight = this.height;
17955 if (this.width < 0) {
17956 newx = this.x + this.width;
17957 newwidth = -this.width;
17959 if (this.height < 0) {
17960 newy = this.y + this.height;
17961 newheight = -this.height;
17965 this.width = newwidth;
17966 this.height = newheight;
17973 function ellipse(c, a, b) {
17974 if (!(this instanceof ellipse))
17975 return new ellipse(c, a, b);
17983 ellipse.prototype = {
17984 toString: function() {
17985 return point(this.x, this.y).toString() + ' ' + this.a + ' ' + this.b;
17988 return rect(this.x - this.a, this.y - this.b, 2*this.a, 2*this.b);
17990 // Find point on me where line from my center to
17991 // point p intersects my boundary.
17992 // @param {number} angle If angle is specified, intersection with rotated ellipse is computed.
17993 intersectionWithLineFromCenterToPoint: function(p, angle) {
17995 if (angle) p.rotate(point(this.x, this.y), angle);
17996 var dx = p.x - this.x;
17997 var dy = p.y - this.y;
18000 result = this.bbox().pointNearestToPoint(p);
18001 if (angle) return result.rotate(point(this.x, this.y), -angle);
18005 var mSquared = m * m;
18006 var aSquared = this.a * this.a;
18007 var bSquared = this.b * this.b;
18008 var x = sqrt(1 / ((1 / aSquared) + (mSquared / bSquared)));
18010 x = dx < 0 ? -x : x;
18012 result = point(this.x + x, this.y + y);
18013 if (angle) return result.rotate(point(this.x, this.y), -angle);
18021 // Cubic Bezier curve path through points.
18022 // Ported from C# implementation by Oleg V. Polikarpotchkin and Peter Lee (http://www.codeproject.com/KB/graphics/BezierSpline.aspx).
18023 // @param {array} points Array of points through which the smooth line will go.
18024 // @return {array} SVG Path commands as an array
18025 curveThroughPoints: function(points) {
18026 var controlPoints = this.getCurveControlPoints(points);
18027 var path = ['M', points[0].x, points[0].y];
18029 for (var i = 0; i < controlPoints[0].length; i++) {
18030 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);
18035 // Get open-ended Bezier Spline Control Points.
18036 // @param knots Input Knot Bezier spline points (At least two points!).
18037 // @param firstControlPoints Output First Control points. Array of knots.length - 1 length.
18038 // @param secondControlPoints Output Second Control points. Array of knots.length - 1 length.
18039 getCurveControlPoints: function(knots) {
18040 var firstControlPoints = [];
18041 var secondControlPoints = [];
18042 var n = knots.length - 1;
18045 // Special case: Bezier curve should be a straight line.
18048 firstControlPoints[0] = point((2 * knots[0].x + knots[1].x) / 3,
18049 (2 * knots[0].y + knots[1].y) / 3);
18051 secondControlPoints[0] = point(2 * firstControlPoints[0].x - knots[0].x,
18052 2 * firstControlPoints[0].y - knots[0].y);
18053 return [firstControlPoints, secondControlPoints];
18056 // Calculate first Bezier control points.
18057 // Right hand side vector.
18060 // Set right hand side X values.
18061 for (i = 1; i < n - 1; i++) {
18062 rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
18064 rhs[0] = knots[0].x + 2 * knots[1].x;
18065 rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2.0;
18066 // Get first control points X-values.
18067 var x = this.getFirstControlPoints(rhs);
18069 // Set right hand side Y values.
18070 for (i = 1; i < n - 1; ++i) {
18071 rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
18073 rhs[0] = knots[0].y + 2 * knots[1].y;
18074 rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y) / 2.0;
18075 // Get first control points Y-values.
18076 var y = this.getFirstControlPoints(rhs);
18078 // Fill output arrays.
18079 for (i = 0; i < n; i++) {
18080 // First control point.
18081 firstControlPoints.push(point(x[i], y[i]));
18082 // Second control point.
18084 secondControlPoints.push(point(2 * knots [i + 1].x - x[i + 1],
18085 2 * knots[i + 1].y - y[i + 1]));
18087 secondControlPoints.push(point((knots[n].x + x[n - 1]) / 2,
18088 (knots[n].y + y[n - 1]) / 2));
18091 return [firstControlPoints, secondControlPoints];
18094 // Solves a tridiagonal system for one of coordinates (x or y) of first Bezier control points.
18095 // @param rhs Right hand side vector.
18096 // @return Solution vector.
18097 getFirstControlPoints: function(rhs) {
18098 var n = rhs.length;
18099 // `x` is a solution vector.
18105 // Decomposition and forward substitution.
18106 for (var i = 1; i < n; i++) {
18108 b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
18109 x[i] = (rhs[i] - x[i - 1]) / b;
18111 for (i = 1; i < n; i++) {
18112 // Backsubstitution.
18113 x[n - i - 1] -= tmp[n - i] * x[n - i];
18122 // Return the `value` from the `domain` interval scaled to the `range` interval.
18123 linear: function(domain, range, value) {
18125 var domainSpan = domain[1] - domain[0];
18126 var rangeSpan = range[1] - range[0];
18127 return (((value - domain[0]) / domainSpan) * rangeSpan + range[0]) || 0;
18135 snapToGrid: snapToGrid,
18136 normalizeAngle: normalizeAngle,
18146 // JointJS library.
18147 // (c) 2011-2013 client IO
18149 if (typeof exports === 'object') {
18151 var _ = require('lodash');
18155 // Global namespace.
18159 // `joint.dia` namespace.
18162 // `joint.ui` namespace.
18165 // `joint.layout` namespace.
18168 // `joint.shapes` namespace.
18171 // `joint.format` namespace.
18174 // `joint.connectors` namespace.
18177 // `joint.routers` namespace.
18182 // Return a simple hash code from a string. See http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/.
18183 hashCode: function(str) {
18186 if (str.length == 0) return hash;
18187 for (var i = 0; i < str.length; i++) {
18188 var c = str.charCodeAt(i);
18189 hash = ((hash << 5) - hash) + c;
18190 hash = hash & hash; // Convert to 32bit integer
18195 getByPath: function(obj, path, delim) {
18197 delim = delim || '.';
18198 var keys = path.split(delim);
18201 while (keys.length) {
18202 key = keys.shift();
18212 setByPath: function(obj, path, value, delim) {
18214 delim = delim || '.';
18216 var keys = path.split(delim);
18220 if (path.indexOf(delim) > -1) {
18222 for (var len = keys.length; i < len - 1; i++) {
18223 // diver creates an empty object if there is no nested object under such a key.
18224 // This means that one can populate an empty nested object with setByPath().
18225 diver = diver[keys[i]] || (diver[keys[i]] = {});
18227 diver[keys[len - 1]] = value;
18234 unsetByPath: function(obj, path, delim) {
18236 delim = delim || '.';
18238 // index of the last delimiter
18239 var i = path.lastIndexOf(delim);
18243 // unsetting a nested attribute
18244 var parent = joint.util.getByPath(obj, path.substr(0, i), delim);
18248 delete parent[path.slice(i + 1)];
18253 // unsetting a primitive attribute
18260 flattenObject: function(obj, delim, stop) {
18262 delim = delim || '.';
18265 for (var key in obj) {
18266 if (!obj.hasOwnProperty(key)) continue;
18268 var shouldGoDeeper = typeof obj[key] === 'object';
18269 if (shouldGoDeeper && stop && stop(obj[key])) {
18270 shouldGoDeeper = false;
18273 if (shouldGoDeeper) {
18274 var flatObject = this.flattenObject(obj[key], delim, stop);
18275 for (var flatKey in flatObject) {
18276 if (!flatObject.hasOwnProperty(flatKey)) continue;
18278 ret[key + delim + flatKey] = flatObject[flatKey];
18281 ret[key] = obj[key];
18289 // credit: http://stackoverflow.com/posts/2117523/revisions
18291 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
18292 var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
18293 return v.toString(16);
18297 // Generate global unique id for obj and store it as a property of the object.
18298 guid: function(obj) {
18300 this.guid.id = this.guid.id || 1;
18301 obj.id = (obj.id === undefined ? 'j_' + this.guid.id++ : obj.id);
18305 // Copy all the properties to the first argument from the following arguments.
18306 // All the properties will be overwritten by the properties from the following
18307 // arguments. Inherited properties are ignored.
18308 mixin: function() {
18310 var target = arguments[0];
18312 for (var i = 1, l = arguments.length; i < l; i++) {
18314 var extension = arguments[i];
18316 // Only functions and objects can be mixined.
18318 if ((Object(extension) !== extension) &&
18319 !_.isFunction(extension) &&
18320 (extension === null || extension === undefined)) {
18325 _.each(extension, function(copy, key) {
18327 if (this.mixin.deep && (Object(copy) === copy)) {
18329 if (!target[key]) {
18331 target[key] = _.isArray(copy) ? [] : {};
18334 this.mixin(target[key], copy);
18338 if (target[key] !== copy) {
18340 if (!this.mixin.supplement || !target.hasOwnProperty(key)) {
18342 target[key] = copy;
18353 // Copy all properties to the first argument from the following
18354 // arguments only in case if they don't exists in the first argument.
18355 // All the function propererties in the first argument will get
18356 // additional property base pointing to the extenders same named
18357 // property function's call method.
18358 supplement: function() {
18360 this.mixin.supplement = true;
18361 var ret = this.mixin.apply(this, arguments);
18362 this.mixin.supplement = false;
18366 // Same as `mixin()` but deep version.
18367 deepMixin: function() {
18369 this.mixin.deep = true;
18370 var ret = this.mixin.apply(this, arguments);
18371 this.mixin.deep = false;
18375 // Same as `supplement()` but deep version.
18376 deepSupplement: function() {
18378 this.mixin.deep = this.mixin.supplement = true;
18379 var ret = this.mixin.apply(this, arguments);
18380 this.mixin.deep = this.mixin.supplement = false;
18384 normalizeEvent: function(evt) {
18386 return (evt.originalEvent && evt.originalEvent.changedTouches && evt.originalEvent.changedTouches.length) ? evt.originalEvent.changedTouches[0] : evt;
18389 nextFrame:(function() {
18392 var client = typeof window != 'undefined';
18396 raf = window.requestAnimationFrame ||
18397 window.webkitRequestAnimationFrame ||
18398 window.mozRequestAnimationFrame ||
18399 window.oRequestAnimationFrame ||
18400 window.msRequestAnimationFrame;
18408 raf = function(callback) {
18410 var currTime = new Date().getTime();
18411 var timeToCall = Math.max(0, 16 - (currTime - lastTime));
18412 var id = setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
18413 lastTime = currTime + timeToCall;
18419 return client ? _.bind(raf, window) : raf;
18422 cancelFrame: (function() {
18425 var client = typeof window != 'undefined';
18429 caf = window.cancelAnimationFrame ||
18430 window.webkitCancelAnimationFrame ||
18431 window.webkitCancelRequestAnimationFrame ||
18432 window.msCancelAnimationFrame ||
18433 window.msCancelRequestAnimationFrame ||
18434 window.oCancelAnimationFrame ||
18435 window.oCancelRequestAnimationFrame ||
18436 window.mozCancelAnimationFrame ||
18437 window.mozCancelRequestAnimationFrame;
18441 caf = caf || clearTimeout;
18443 return client ? _.bind(caf, window) : caf;
18446 breakText: function(text, size, styles, opt) {
18450 var width = size.width;
18451 var height = size.height;
18453 var svgDocument = opt.svgDocument || V('svg').node;
18454 var textElement = V('<text><tspan></tspan></text>').attr(styles || {}).node;
18455 var textSpan = textElement.firstChild;
18456 var textNode = document.createTextNode('');
18458 textSpan.appendChild(textNode);
18460 svgDocument.appendChild(textElement);
18462 if (!opt.svgDocument) {
18464 document.body.appendChild(svgDocument);
18467 var words = text.split(' ');
18472 for (var i = 0, l = 0, len = words.length; i < len; i++) {
18474 var word = words[i];
18476 textNode.data = lines[l] ? lines[l] + ' ' + word : word;
18478 if (textSpan.getComputedTextLength() <= width) {
18480 // the current line fits
18481 lines[l] = textNode.data;
18484 // We were partitioning. Put rest of the word onto next line
18487 // cancel partitioning
18493 if (!lines[l] || p) {
18495 var partition = !!p;
18497 p = word.length - 1;
18499 if (partition || !p) {
18501 // word has only one character.
18506 // we won't fit this text within our rect
18512 // partitioning didn't help on the non-empty line
18513 // try again, but this time start with a new line
18515 // cancel partitions created
18516 words.splice(i,2, word + words[i+1]);
18518 // adjust word length
18527 // move last letter to the beginning of the next word
18528 words[i] = word.substring(0,p);
18529 words[i+1] = word.substring(p) + words[i+1];
18533 // We initiate partitioning
18534 // split the long word into two words
18535 words.splice(i, 1, word.substring(0,p), word.substring(p));
18537 // adjust words length
18540 if (l && !full[l-1]) {
18541 // if the previous line is not full, try to fit max part of
18542 // the current word there
18556 // if size.height is defined we have to check whether the height of the entire
18557 // text exceeds the rect height
18558 if (typeof height !== 'undefined') {
18560 // get line height as text height / 0.8 (as text height is approx. 0.8em
18561 // and line height is 1em. See vectorizer.text())
18562 var lh = lh || textElement.getBBox().height * 1.25;
18564 if (lh * lines.length > height) {
18566 // remove overflowing lines
18567 lines.splice(Math.floor(height / lh));
18574 if (opt.svgDocument) {
18576 // svg document was provided, remove the text element only
18577 svgDocument.removeChild(textElement);
18581 // clean svg document
18582 document.body.removeChild(svgDocument);
18585 return lines.join('\n');
18590 linear: function(t) {
18594 quad: function(t) {
18598 cubic: function(t) {
18602 inout: function(t) {
18603 if (t <= 0) return 0;
18604 if (t >= 1) return 1;
18605 var t2 = t * t, t3 = t2 * t;
18606 return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
18609 exponential: function(t) {
18610 return Math.pow(2, 10 * (t - 1));
18613 bounce: function(t) {
18614 for(var a = 0, b = 1; 1; a += b, b /= 2) {
18615 if (t >= (7 - 4 * a) / 11) {
18616 var q = (11 - 6 * a - 11 * t) / 4;
18617 return -q * q + b * b;
18622 reverse: function(f) {
18623 return function(t) {
18624 return 1 - f(1 - t)
18628 reflect: function(f) {
18629 return function(t) {
18630 return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
18634 clamp: function(f,n,x) {
18637 return function(t) {
18639 return r < n ? n : r > x ? x : r;
18643 back: function(s) {
18644 if (!s) s = 1.70158;
18645 return function(t) {
18646 return t * t * ((s + 1) * t - s);
18650 elastic: function(x) {
18652 return function(t) {
18653 return Math.pow(2, 10 * (t - 1)) * Math.cos(20*Math.PI*x/3*t);
18661 number: function(a, b) {
18663 return function(t) { return a + d * t; };
18666 object: function(a, b) {
18668 return function(t) {
18670 for (i = s.length - 1; i != -1; i--) {
18672 r[p] = a[p] + (b[p] - a[p]) * t;
18678 hexColor: function(a, b) {
18680 var ca = parseInt(a.slice(1), 16), cb = parseInt(b.slice(1), 16);
18682 var ra = ca & 0x0000ff, rd = (cb & 0x0000ff) - ra;
18683 var ga = ca & 0x00ff00, gd = (cb & 0x00ff00) - ga;
18684 var ba = ca & 0xff0000, bd = (cb & 0xff0000) - ba;
18686 return function(t) {
18687 var r = (ra + rd * t) & 0x000000ff;
18688 var g = (ga + gd * t) & 0x0000ff00;
18689 var b = (ba + bd * t) & 0x00ff0000;
18690 return '#' + (1 << 24 | r | g | b ).toString(16).slice(1);
18694 unit: function(a, b) {
18696 var r = /(-?[0-9]*.[0-9]*)(px|em|cm|mm|in|pt|pc|%)/;
18698 var ma = r.exec(a), mb = r.exec(b);
18699 var p = mb[1].indexOf('.'), f = p > 0 ? mb[1].length - p - 1 : 0;
18700 var a = +ma[1], d = +mb[1] - a, u = ma[2];
18702 return function(t) {
18703 return (a + d * t).toFixed(f) + u;
18711 // `x` ... horizontal blur
18712 // `y` ... vertical blur (optional)
18713 blur: function(args) {
18715 var x = _.isFinite(args.x) ? args.x : 2;
18717 return _.template('<filter><feGaussianBlur stdDeviation="${stdDeviation}"/></filter>', {
18718 stdDeviation: _.isFinite(args.y) ? [x, args.y] : x
18722 // `dx` ... horizontal shift
18723 // `dy` ... vertical shift
18725 // `color` ... color
18726 // `opacity` ... opacity
18727 dropShadow: function(args) {
18729 var tpl = 'SVGFEDropShadowElement' in window
18730 ? '<filter><feDropShadow stdDeviation="${blur}" dx="${dx}" dy="${dy}" flood-color="${color}" flood-opacity="${opacity}"/></filter>'
18731 : '<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>';
18733 return _.template(tpl, {
18736 opacity: _.isFinite(args.opacity) ? args.opacity : 1,
18737 color: args.color || 'black',
18738 blur: _.isFinite(args.blur) ? args.blur : 4
18742 // `amount` ... the proportion of the conversion. A value of 1 is completely grayscale. A value of 0 leaves the input unchanged.
18743 grayscale: function(args) {
18745 var amount = _.isFinite(args.amount) ? args.amount : 1;
18747 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>', {
18748 a: 0.2126 + 0.7874 * (1 - amount),
18749 b: 0.7152 - 0.7152 * (1 - amount),
18750 c: 0.0722 - 0.0722 * (1 - amount),
18751 d: 0.2126 - 0.2126 * (1 - amount),
18752 e: 0.7152 + 0.2848 * (1 - amount),
18753 f: 0.0722 - 0.0722 * (1 - amount),
18754 g: 0.2126 - 0.2126 * (1 - amount),
18755 h: 0.0722 + 0.9278 * (1 - amount)
18759 // `amount` ... the proportion of the conversion. A value of 1 is completely sepia. A value of 0 leaves the input unchanged.
18760 sepia: function(args) {
18762 var amount = _.isFinite(args.amount) ? args.amount : 1;
18764 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>', {
18765 a: 0.393 + 0.607 * (1 - amount),
18766 b: 0.769 - 0.769 * (1 - amount),
18767 c: 0.189 - 0.189 * (1 - amount),
18768 d: 0.349 - 0.349 * (1 - amount),
18769 e: 0.686 + 0.314 * (1 - amount),
18770 f: 0.168 - 0.168 * (1 - amount),
18771 g: 0.272 - 0.272 * (1 - amount),
18772 h: 0.534 - 0.534 * (1 - amount),
18773 i: 0.131 + 0.869 * (1 - amount)
18777 // `amount` ... the proportion of the conversion. A value of 0 is completely un-saturated. A value of 1 leaves the input unchanged.
18778 saturate: function(args) {
18780 var amount = _.isFinite(args.amount) ? args.amount : 1;
18782 return _.template('<filter><feColorMatrix type="saturate" values="${amount}"/></filter>', {
18787 // `angle` ... the number of degrees around the color circle the input samples will be adjusted.
18788 hueRotate: function(args) {
18790 return _.template('<filter><feColorMatrix type="hueRotate" values="${angle}"/></filter>', {
18791 angle: args.angle || 0
18795 // `amount` ... the proportion of the conversion. A value of 1 is completely inverted. A value of 0 leaves the input unchanged.
18796 invert: function(args) {
18798 var amount = _.isFinite(args.amount) ? args.amount : 1;
18800 return _.template('<filter><feComponentTransfer><feFuncR type="table" tableValues="${amount} ${amount2}"/><feFuncG type="table" tableValues="${amount} ${amount2}"/><feFuncB type="table" tableValues="${amount} ${amount2}"/></feComponentTransfer></filter>', {
18802 amount2: 1 - amount
18806 // `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.
18807 brightness: function(args) {
18809 return _.template('<filter><feComponentTransfer><feFuncR type="linear" slope="${amount}"/><feFuncG type="linear" slope="${amount}"/><feFuncB type="linear" slope="${amount}"/></feComponentTransfer></filter>', {
18810 amount: _.isFinite(args.amount) ? args.amount : 1
18814 // `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.
18815 contrast: function(args) {
18817 var amount = _.isFinite(args.amount) ? args.amount : 1;
18819 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>', {
18821 amount2: .5 - amount / 2
18828 // Formatting numbers via the Python Format Specification Mini-language.
18829 // See http://docs.python.org/release/3.1.3/library/string.html#format-specification-mini-language.
18830 // Heavilly inspired by the D3.js library implementation.
18831 number: function(specifier, value, locale) {
18833 locale = locale || {
18835 currency: ['$', ''],
18841 // See Python format specification mini-language: http://docs.python.org/release/3.1.3/library/string.html#format-specification-mini-language.
18842 // [[fill]align][sign][symbol][0][width][,][.precision][type]
18843 var re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
18845 var match = re.exec(specifier);
18846 var fill = match[1] || ' ';
18847 var align = match[2] || '>';
18848 var sign = match[3] || '';
18849 var symbol = match[4] || '';
18850 var zfill = match[5];
18851 var width = +match[6];
18852 var comma = match[7];
18853 var precision = match[8];
18854 var type = match[9];
18858 var integer = false;
18860 if (precision) precision = +precision.substring(1);
18862 if (zfill || fill === '0' && align === '=') {
18863 zfill = fill = '0';
18865 if (comma) width -= Math.floor((width - 1) / 4);
18869 case 'n': comma = true; type = 'g'; break;
18870 case '%': scale = 100; suffix = '%'; type = 'f'; break;
18871 case 'p': scale = 100; suffix = '%'; type = 'r'; break;
18875 case 'X': if (symbol === '#') prefix = '0' + type.toLowerCase();
18877 case 'd': integer = true; precision = 0; break;
18878 case 's': scale = -1; type = 'r'; break;
18881 if (symbol === '$') {
18882 prefix = locale.currency[0];
18883 suffix = locale.currency[1];
18886 // If no precision is specified for `'r'`, fallback to general notation.
18887 if (type == 'r' && !precision) type = 'g';
18889 // Ensure that the requested precision is in the supported range.
18890 if (precision != null) {
18891 if (type == 'g') precision = Math.max(1, Math.min(21, precision));
18892 else if (type == 'e' || type == 'f') precision = Math.max(0, Math.min(20, precision));
18895 var zcomma = zfill && comma;
18897 // Return the empty string for floats formatted as ints.
18898 if (integer && (value % 1)) return '';
18900 // Convert negative to positive, and record the sign prefix.
18901 var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, '-') : sign;
18903 var fullSuffix = suffix;
18905 // Apply the scale, computing it from the value's exponent for si format.
18906 // Preserve the existing suffix, if any, such as the currency symbol.
18908 var unit = this.prefix(value, precision);
18909 value = unit.scale(value);
18910 fullSuffix = unit.symbol + suffix;
18915 // Convert to the desired precision.
18916 value = this.convert(type, value, precision);
18918 // Break the value into the integer part (before) and decimal part (after).
18919 var i = value.lastIndexOf('.');
18920 var before = i < 0 ? value : value.substring(0, i);
18921 var after = i < 0 ? '' : locale.decimal + value.substring(i + 1);
18923 function formatGroup(value) {
18925 var i = value.length;
18928 var g = locale.grouping[0];
18929 while (i > 0 && g > 0) {
18930 t.push(value.substring(i -= g, i + g));
18931 g = locale.grouping[j = (j + 1) % locale.grouping.length];
18933 return t.reverse().join(locale.thousands);
18936 // If the fill character is not `'0'`, grouping is applied before padding.
18937 if (!zfill && comma && locale.grouping) {
18939 before = formatGroup(before);
18942 var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length);
18943 var padding = length < width ? new Array(length = width - length + 1).join(fill) : '';
18945 // If the fill character is `'0'`, grouping is applied after padding.
18946 if (zcomma) before = formatGroup(padding + before);
18949 negative += prefix;
18951 // Rejoin integer and decimal parts.
18952 value = before + after;
18954 return (align === '<' ? negative + value + padding
18955 : align === '>' ? padding + negative + value
18956 : align === '^' ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length)
18957 : negative + (zcomma ? value : padding + value)) + fullSuffix;
18960 convert: function(type, value, precision) {
18963 case 'b': return value.toString(2);
18964 case 'c': return String.fromCharCode(value);
18965 case 'o': return value.toString(8);
18966 case 'x': return value.toString(16);
18967 case 'X': return value.toString(16).toUpperCase();
18968 case 'g': return value.toPrecision(precision);
18969 case 'e': return value.toExponential(precision);
18970 case 'f': return value.toFixed(precision);
18971 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))));
18972 default: return value + '';
18976 round: function(value, precision) {
18979 ? Math.round(value * (precision = Math.pow(10, precision))) / precision
18980 : Math.round(value);
18983 precision: function(value, precision) {
18985 return precision - (value ? Math.ceil(Math.log(value) / Math.LN10) : 1);
18988 prefix: function(value, precision) {
18990 var prefixes = _.map(['y','z','a','f','p','n','µ','m','','k','M','G','T','P','E','Z','Y'], function(d, i) {
18991 var k = Math.pow(10, abs(8 - i) * 3);
18993 scale: i > 8 ? function(d) { return d / k; } : function(d) { return d * k; },
19000 if (value < 0) value *= -1;
19001 if (precision) value = d3.round(value, this.precision(value, precision));
19002 i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
19003 i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
19005 return prefixes[8 + i / 3];
19011 if (typeof exports === 'object') {
19013 module.exports = joint;
19016 // JointJS, the JavaScript diagramming library.
19017 // (c) 2011-2013 client IO
19020 if (typeof exports === 'object') {
19024 Link: require('./joint.dia.link').Link,
19025 Element: require('./joint.dia.element').Element
19027 shapes: require('../plugins/shapes')
19029 var Backbone = require('backbone');
19030 var _ = require('lodash');
19031 var g = require('./geometry');
19036 joint.dia.GraphCells = Backbone.Collection.extend({
19038 initialize: function() {
19040 // Backbone automatically doesn't trigger re-sort if models attributes are changed later when
19041 // they're already in the collection. Therefore, we're triggering sort manually here.
19042 this.on('change:z', this.sort, this);
19045 model: function(attrs, options) {
19047 if (attrs.type === 'link') {
19049 return new joint.dia.Link(attrs, options);
19052 var module = attrs.type.split('.')[0];
19053 var entity = attrs.type.split('.')[1];
19055 if (joint.shapes[module] && joint.shapes[module][entity]) {
19057 return new joint.shapes[module][entity](attrs, options);
19060 return new joint.dia.Element(attrs, options);
19063 // `comparator` makes it easy to sort cells based on their `z` index.
19064 comparator: function(model) {
19066 return model.get('z') || 0;
19069 // Get all inbound and outbound links connected to the cell `model`.
19070 getConnectedLinks: function(model, opt) {
19074 if (_.isUndefined(opt.inbound) && _.isUndefined(opt.outbound)) {
19075 opt.inbound = opt.outbound = true;
19080 this.each(function(cell) {
19082 var source = cell.get('source');
19083 var target = cell.get('target');
19085 if (source && source.id === model.id && opt.outbound) {
19090 if (target && target.id === model.id && opt.inbound) {
19101 joint.dia.Graph = Backbone.Model.extend({
19103 initialize: function() {
19105 this.set('cells', new joint.dia.GraphCells);
19107 // Make all the events fired in the `cells` collection available.
19108 // to the outside world.
19109 this.get('cells').on('all', this.trigger, this);
19111 this.get('cells').on('remove', this.removeCell, this);
19114 toJSON: function() {
19116 // Backbone does not recursively call `toJSON()` on attributes that are themselves models/collections.
19117 // It just clones the attributes. Therefore, we must call `toJSON()` on the cells collection explicitely.
19118 var json = Backbone.Model.prototype.toJSON.apply(this, arguments);
19119 json.cells = this.get('cells').toJSON();
19123 fromJSON: function(json) {
19127 throw new Error('Graph JSON must contain cells array.');
19132 // Cells are the only attribute that is being set differently, using `cells.add()`.
19133 var cells = json.cells;
19134 delete attrs.cells;
19138 this.resetCells(cells);
19141 clear: function() {
19143 this.trigger('batch:start');
19144 this.get('cells').remove(this.get('cells').models);
19145 this.trigger('batch:stop');
19148 _prepareCell: function(cell) {
19150 if (cell instanceof Backbone.Model && _.isUndefined(cell.get('z'))) {
19152 cell.set('z', this.maxZIndex() + 1, { silent: true });
19154 } else if (_.isUndefined(cell.z)) {
19156 cell.z = this.maxZIndex() + 1;
19162 maxZIndex: function() {
19164 var lastCell = this.get('cells').last();
19165 return lastCell ? (lastCell.get('z') || 0) : 0;
19168 addCell: function(cell, options) {
19170 if (_.isArray(cell)) {
19172 return this.addCells(cell, options);
19175 this.get('cells').add(this._prepareCell(cell), options || {});
19180 addCells: function(cells, options) {
19182 _.each(cells, function(cell) { this.addCell(cell, options); }, this);
19187 // When adding a lot of cells, it is much more efficient to
19188 // reset the entire cells collection in one go.
19189 // Useful for bulk operations and optimizations.
19190 resetCells: function(cells) {
19192 this.get('cells').reset(_.map(cells, this._prepareCell, this));
19197 removeCell: function(cell, collection, options) {
19199 // Applications might provide a `disconnectLinks` option set to `true` in order to
19200 // disconnect links when a cell is removed rather then removing them. The default
19201 // is to remove all the associated links.
19202 if (options && options.disconnectLinks) {
19204 this.disconnectLinks(cell);
19208 this.removeLinks(cell);
19211 // Silently remove the cell from the cells collection. Silently, because
19212 // `joint.dia.Cell.prototype.remove` already triggers the `remove` event which is
19213 // then propagated to the graph model. If we didn't remove the cell silently, two `remove` events
19214 // would be triggered on the graph model.
19215 this.get('cells').remove(cell, { silent: true });
19218 // Get a cell by `id`.
19219 getCell: function(id) {
19221 return this.get('cells').get(id);
19224 getElements: function() {
19226 return this.get('cells').filter(function(cell) {
19228 return cell instanceof joint.dia.Element;
19232 getLinks: function() {
19234 return this.get('cells').filter(function(cell) {
19236 return cell instanceof joint.dia.Link;
19240 // Get all inbound and outbound links connected to the cell `model`.
19241 getConnectedLinks: function(model, opt) {
19243 return this.get('cells').getConnectedLinks(model, opt);
19246 getNeighbors: function(el) {
19248 var links = this.getConnectedLinks(el);
19249 var neighbors = [];
19250 var cells = this.get('cells');
19252 _.each(links, function(link) {
19254 var source = link.get('source');
19255 var target = link.get('target');
19257 // Discard if it is a point.
19259 var sourceElement = cells.get(source.id);
19260 if (sourceElement !== el) {
19262 neighbors.push(sourceElement);
19266 var targetElement = cells.get(target.id);
19267 if (targetElement !== el) {
19269 neighbors.push(targetElement);
19277 // Disconnect links connected to the cell `model`.
19278 disconnectLinks: function(model) {
19280 _.each(this.getConnectedLinks(model), function(link) {
19282 link.set(link.get('source').id === model.id ? 'source' : 'target', g.point(0, 0));
19286 // Remove links connected to the cell `model` completely.
19287 removeLinks: function(model) {
19289 _.invoke(this.getConnectedLinks(model), 'remove');
19292 // Find all views at given point
19293 findModelsFromPoint: function(p) {
19295 return _.filter(this.getElements(), function(el) {
19296 return el.getBBox().containsPoint(p);
19301 // Find all views in given area
19302 findModelsInArea: function(r) {
19304 return _.filter(this.getElements(), function(el) {
19305 return el.getBBox().intersect(r);
19312 if (typeof exports === 'object') {
19314 module.exports.Graph = joint.dia.Graph;
19317 // (c) 2011-2013 client IO
19320 if (typeof exports === 'object') {
19323 util: require('./core').util,
19325 Link: require('./joint.dia.link').Link
19328 var Backbone = require('backbone');
19329 var _ = require('lodash');
19333 // joint.dia.Cell base model.
19334 // --------------------------
19336 joint.dia.Cell = Backbone.Model.extend({
19338 // This is the same as Backbone.Model with the only difference that is uses _.merge
19339 // instead of just _.extend. The reason is that we want to mixin attributes set in upper classes.
19340 constructor: function(attributes, options) {
19343 var attrs = attributes || {};
19344 this.cid = _.uniqueId('c');
19345 this.attributes = {};
19346 if (options && options.collection) this.collection = options.collection;
19347 if (options && options.parse) attrs = this.parse(attrs, options) || {};
19348 if (defaults = _.result(this, 'defaults')) {
19350 // Replaced the call to _.defaults with _.merge.
19351 attrs = _.merge({}, defaults, attrs);
19354 this.set(attrs, options);
19356 this.initialize.apply(this, arguments);
19359 toJSON: function() {
19361 var defaultAttrs = this.constructor.prototype.defaults.attrs || {};
19362 var attrs = this.attributes.attrs;
19363 var finalAttrs = {};
19365 // Loop through all the attributes and
19366 // omit the default attributes as they are implicitly reconstructable by the cell 'type'.
19367 _.each(attrs, function(attr, selector) {
19369 var defaultAttr = defaultAttrs[selector];
19371 _.each(attr, function(value, name) {
19373 // attr is mainly flat though it might have one more level (consider the `style` attribute).
19374 // Check if the `value` is object and if yes, go one level deep.
19375 if (_.isObject(value) && !_.isArray(value)) {
19377 _.each(value, function(value2, name2) {
19379 if (!defaultAttr || !defaultAttr[name] || !_.isEqual(defaultAttr[name][name2], value2)) {
19381 finalAttrs[selector] = finalAttrs[selector] || {};
19382 (finalAttrs[selector][name] || (finalAttrs[selector][name] = {}))[name2] = value2;
19386 } else if (!defaultAttr || !_.isEqual(defaultAttr[name], value)) {
19387 // `value` is not an object, default attribute for such a selector does not exist
19388 // or it is different than the attribute value set on the model.
19390 finalAttrs[selector] = finalAttrs[selector] || {};
19391 finalAttrs[selector][name] = value;
19396 var attributes = _.cloneDeep(_.omit(this.attributes, 'attrs'));
19397 //var attributes = JSON.parse(JSON.stringify(_.omit(this.attributes, 'attrs')));
19398 attributes.attrs = finalAttrs;
19403 initialize: function(options) {
19405 if (!options || !options.id) {
19407 this.set('id', joint.util.uuid(), { silent: true });
19410 this._transitionIds = {};
19412 // Collect ports defined in `attrs` and keep collecting whenever `attrs` object changes.
19413 this.processPorts();
19414 this.on('change:attrs', this.processPorts, this);
19417 processPorts: function() {
19419 // Whenever `attrs` changes, we extract ports from the `attrs` object and store it
19420 // in a more accessible way. Also, if any port got removed and there were links that had `target`/`source`
19421 // set to that port, we remove those links as well (to follow the same behaviour as
19422 // with a removed element).
19424 var previousPorts = this.ports;
19426 // Collect ports from the `attrs` object.
19428 _.each(this.get('attrs'), function(attrs, selector) {
19430 if (attrs && attrs.port) {
19432 // `port` can either be directly an `id` or an object containing an `id` (and potentially other data).
19433 if (!_.isUndefined(attrs.port.id)) {
19434 ports[attrs.port.id] = attrs.port;
19436 ports[attrs.port] = { id: attrs.port };
19441 // Collect ports that have been removed (compared to the previous ports) - if any.
19442 // Use hash table for quick lookup.
19443 var removedPorts = {};
19444 _.each(previousPorts, function(port, id) {
19446 if (!ports[id]) removedPorts[id] = true;
19449 // Remove all the incoming/outgoing links that have source/target port set to any of the removed ports.
19450 if (this.collection && !_.isEmpty(removedPorts)) {
19452 var inboundLinks = this.collection.getConnectedLinks(this, { inbound: true });
19453 _.each(inboundLinks, function(link) {
19455 if (removedPorts[link.get('target').port]) link.remove();
19458 var outboundLinks = this.collection.getConnectedLinks(this, { outbound: true });
19459 _.each(outboundLinks, function(link) {
19461 if (removedPorts[link.get('source').port]) link.remove();
19465 // Update the `ports` object.
19466 this.ports = ports;
19469 remove: function(options) {
19471 var collection = this.collection;
19474 collection.trigger('batch:start');
19477 // First, unembed this cell from its parent cell if there is one.
19478 var parentCellId = this.get('parent');
19479 if (parentCellId) {
19481 var parentCell = this.collection && this.collection.get(parentCellId);
19482 parentCell.unembed(this);
19485 _.invoke(this.getEmbeddedCells(), 'remove', options);
19487 this.trigger('remove', this, this.collection, options);
19490 collection.trigger('batch:stop');
19494 toFront: function() {
19496 if (this.collection) {
19498 this.set('z', (this.collection.last().get('z') || 0) + 1);
19502 toBack: function() {
19504 if (this.collection) {
19506 this.set('z', (this.collection.first().get('z') || 0) - 1);
19510 embed: function(cell) {
19512 if (this.get('parent') == cell.id) {
19514 throw new Error('Recursive embedding not allowed.');
19518 this.trigger('batch:start');
19520 cell.set('parent', this.id);
19521 this.set('embeds', _.uniq((this.get('embeds') || []).concat([cell.id])));
19523 this.trigger('batch:stop');
19527 unembed: function(cell) {
19529 this.trigger('batch:start');
19531 var cellId = cell.id;
19532 cell.unset('parent');
19534 this.set('embeds', _.without(this.get('embeds'), cellId));
19536 this.trigger('batch:stop');
19539 getEmbeddedCells: function() {
19541 // Cell models can only be retrieved when this element is part of a collection.
19542 // There is no way this element knows about other cells otherwise.
19543 // This also means that calling e.g. `translate()` on an element with embeds before
19544 // adding it to a graph does not translate its embeds.
19545 if (this.collection) {
19547 return _.map(this.get('embeds') || [], function(cellId) {
19549 return this.collection.get(cellId);
19556 clone: function(opt) {
19560 var clone = Backbone.Model.prototype.clone.apply(this, arguments);
19562 // We don't want the clone to have the same ID as the original.
19563 clone.set('id', joint.util.uuid(), { silent: true });
19564 clone.set('embeds', '');
19566 if (!opt.deep) return clone;
19568 // The rest of the `clone()` method deals with embeds. If `deep` option is set to `true`,
19569 // the return value is an array of all the embedded clones created.
19571 var embeds = this.getEmbeddedCells();
19573 var clones = [clone];
19575 // This mapping stores cloned links under the `id`s of they originals.
19576 // This prevents cloning a link more then once. Consider a link 'self loop' for example.
19577 var linkCloneMapping = {};
19579 _.each(embeds, function(embed) {
19581 var embedClones = embed.clone({ deep: true });
19583 // Embed the first clone returned from `clone({ deep: true })` above. The first
19584 // cell is always the clone of the cell that called the `clone()` method, i.e. clone of `embed` in this case.
19585 clone.embed(embedClones[0]);
19587 _.each(embedClones, function(embedClone) {
19589 clones.push(embedClone);
19591 // Skip links. Inbound/outbound links are not relevant for them.
19592 if (embedClone instanceof joint.dia.Link) {
19597 // Collect all inbound links, clone them (if not done already) and set their target to the `embedClone.id`.
19598 var inboundLinks = this.collection.getConnectedLinks(embed, { inbound: true });
19600 _.each(inboundLinks, function(link) {
19602 var linkClone = linkCloneMapping[link.id] || link.clone();
19604 // Make sure we don't clone a link more then once.
19605 linkCloneMapping[link.id] = linkClone;
19607 var target = _.clone(linkClone.get('target'));
19608 target.id = embedClone.id;
19609 linkClone.set('target', target);
19612 // Collect all inbound links, clone them (if not done already) and set their source to the `embedClone.id`.
19613 var outboundLinks = this.collection.getConnectedLinks(embed, { outbound: true });
19615 _.each(outboundLinks, function(link) {
19617 var linkClone = linkCloneMapping[link.id] || link.clone();
19619 // Make sure we don't clone a link more then once.
19620 linkCloneMapping[link.id] = linkClone;
19622 var source = _.clone(linkClone.get('source'));
19623 source.id = embedClone.id;
19624 linkClone.set('source', source);
19631 // Add link clones to the array of all the new clones.
19632 clones = clones.concat(_.values(linkCloneMapping));
19637 // A convenient way to set nested attributes.
19638 attr: function(attrs, value, opt) {
19640 var currentAttrs = this.get('attrs');
19643 if (_.isString(attrs)) {
19644 // Get/set an attribute by a special path syntax that delimits
19645 // nested objects by the colon character.
19647 if (typeof value != 'undefined') {
19650 joint.util.setByPath(attr, attrs, value, delim);
19651 return this.set('attrs', _.merge({}, currentAttrs, attr), opt);
19655 return joint.util.getByPath(currentAttrs, attrs, delim);
19659 return this.set('attrs', _.merge({}, currentAttrs, attrs), value, opt);
19662 // A convenient way to unset nested attributes
19663 removeAttr: function(path, opt) {
19665 if (_.isArray(path)) {
19666 _.each(path, function(p) { this.removeAttr(p, opt); }, this);
19670 var attrs = joint.util.unsetByPath(_.merge({}, this.get('attrs')), path, '/');
19672 return this.set('attrs', attrs, _.extend({ dirty: true }, opt));
19675 transition: function(path, value, opt, delim) {
19677 delim = delim || '/';
19682 timingFunction: joint.util.timing.linear,
19683 valueFunction: joint.util.interpolate.number
19686 opt = _.extend(defaults, opt);
19688 var pathArray = path.split(delim);
19689 var property = pathArray[0];
19690 var isPropertyNested = pathArray.length > 1;
19691 var firstFrameTime = 0;
19692 var interpolatingFunction;
19694 var setter = _.bind(function(runtime) {
19696 var id, progress, propertyValue, status;
19698 firstFrameTime = firstFrameTime || runtime;
19699 runtime -= firstFrameTime;
19700 progress = runtime / opt.duration;
19702 if (progress < 1) {
19703 this._transitionIds[path] = id = joint.util.nextFrame(setter);
19706 delete this._transitionIds[path];
19709 propertyValue = interpolatingFunction(opt.timingFunction(progress));
19711 if (isPropertyNested) {
19712 var nestedPropertyValue = joint.util.setByPath({}, path, propertyValue, delim)[property];
19713 propertyValue = _.merge({}, this.get(property), nestedPropertyValue);
19716 opt.transitionId = id;
19718 this.set(property, propertyValue, opt);
19720 if (!id) this.trigger('transition:end', this, path);
19724 var initiator =_.bind(function(callback) {
19726 this.stopTransitions(path);
19728 interpolatingFunction = opt.valueFunction(joint.util.getByPath(this.attributes, path, delim), value);
19730 this._transitionIds[path] = joint.util.nextFrame(callback);
19732 this.trigger('transition:start', this, path);
19736 return _.delay(initiator, opt.delay, setter);
19739 getTransitions: function() {
19740 return _.keys(this._transitionIds);
19743 stopTransitions: function(path, delim) {
19745 delim = delim || '/';
19747 var pathArray = path && path.split(delim);
19749 _(this._transitionIds).keys().filter(pathArray && function(key) {
19751 return _.isEqual(pathArray, key.split(delim).slice(0, pathArray.length));
19753 }).each(function(key) {
19755 joint.util.cancelFrame(this._transitionIds[key]);
19757 delete this._transitionIds[key];
19759 this.trigger('transition:end', this, key);
19765 // joint.dia.CellView base view and controller.
19766 // --------------------------------------------
19768 // This is the base view and controller for `joint.dia.ElementView` and `joint.dia.LinkView`.
19770 joint.dia.CellView = Backbone.View.extend({
19774 attributes: function() {
19776 return { 'model-id': this.model.id }
19779 initialize: function() {
19781 _.bindAll(this, 'remove', 'update');
19783 // Store reference to this to the <g> DOM element so that the view is accessible through the DOM tree.
19784 this.$el.data('view', this);
19786 this.listenTo(this.model, 'remove', this.remove);
19787 this.listenTo(this.model, 'change:attrs', this.onChangeAttrs);
19790 onChangeAttrs: function(cell, attrs, opt) {
19794 // dirty flag could be set when a model attribute was removed and it needs to be cleared
19795 // also from the DOM element. See cell.removeAttr().
19796 return this.render();
19799 return this.update();
19802 _configure: function(options) {
19804 // Make sure a global unique id is assigned to this view. Store this id also to the properties object.
19805 // The global unique id makes sure that the same view can be rendered on e.g. different machines and
19806 // still be associated to the same object among all those clients. This is necessary for real-time
19807 // collaboration mechanism.
19808 options.id = options.id || joint.util.guid(this);
19810 Backbone.View.prototype._configure.apply(this, arguments);
19813 // Override the Backbone `_ensureElement()` method in order to create a `<g>` node that wraps
19814 // all the nodes of the Cell view.
19815 _ensureElement: function() {
19821 var attrs = _.extend({ id: this.id }, _.result(this, 'attributes'));
19822 if (this.className) attrs['class'] = _.result(this, 'className');
19823 el = V(_.result(this, 'tagName'), attrs).node;
19827 el = _.result(this, 'el')
19830 this.setElement(el, false);
19833 findBySelector: function(selector) {
19835 // These are either descendants of `this.$el` of `this.$el` itself.
19836 // `.` is a special selector used to select the wrapping `<g>` element.
19837 var $selected = selector === '.' ? this.$el : this.$el.find(selector);
19841 notify: function(evt) {
19845 var args = Array.prototype.slice.call(arguments, 1);
19847 // Trigger the event on both the element itself and also on the paper.
19848 this.trigger.apply(this, [evt].concat(args));
19850 // Paper event handlers receive the view object as the first argument.
19851 this.paper.trigger.apply(this.paper, [evt, this].concat(args));
19855 getStrokeBBox: function(el) {
19856 // Return a bounding box rectangle that takes into account stroke.
19857 // Note that this is a naive and ad-hoc implementation that does not
19858 // works only in certain cases and should be replaced as soon as browsers will
19859 // start supporting the getStrokeBBox() SVG method.
19860 // @TODO any better solution is very welcome!
19862 var isMagnet = !!el;
19864 el = el || this.el;
19865 var bbox = V(el).bbox(false, this.paper.viewport);
19870 strokeWidth = V(el).attr('stroke-width');
19874 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');
19877 strokeWidth = parseFloat(strokeWidth) || 0;
19879 return g.rect(bbox).moveAndExpand({ x: -strokeWidth/2, y: -strokeWidth/2, width: strokeWidth, height: strokeWidth });
19882 getBBox: function() {
19884 return V(this.el).bbox();
19887 highlight: function(el) {
19889 el = !el ? this.el : this.$(el)[0] || this.el;
19891 V(el).addClass('highlighted');
19894 unhighlight: function(el) {
19896 el = !el ? this.el : this.$(el)[0] || this.el;
19898 V(el).removeClass('highlighted');
19901 // Find the closest element that has the `magnet` attribute set to `true`. If there was not such
19902 // an element found, return the root element of the cell view.
19903 findMagnet: function(el) {
19905 var $el = this.$(el);
19907 if ($el.length === 0 || $el[0] === this.el) {
19909 // If the overall cell has set `magnet === false`, then return `undefined` to
19910 // announce there is no magnet found for this cell.
19911 // This is especially useful to set on cells that have 'ports'. In this case,
19912 // only the ports have set `magnet === true` and the overall element has `magnet === false`.
19913 var attrs = this.model.get('attrs') || {};
19914 if (attrs['.'] && attrs['.']['magnet'] === false) {
19921 if ($el.attr('magnet')) {
19926 return this.findMagnet($el.parent());
19929 // `selector` is a CSS selector or `'.'`. `filter` must be in the special JointJS filter format:
19930 // `{ name: <name of the filter>, args: { <arguments>, ... }`.
19931 // An example is: `{ filter: { name: 'blur', args: { radius: 5 } } }`.
19932 applyFilter: function(selector, filter) {
19934 var $selected = this.findBySelector(selector);
19936 // Generate a hash code from the stringified filter definition. This gives us
19937 // a unique filter ID for different definitions.
19938 var filterId = filter.name + this.paper.svg.id + joint.util.hashCode(JSON.stringify(filter));
19940 // If the filter already exists in the document,
19941 // we're done and we can just use it (reference it using `url()`).
19942 // If not, create one.
19943 if (!this.paper.svg.getElementById(filterId)) {
19945 var filterSVGString = joint.util.filter[filter.name] && joint.util.filter[filter.name](filter.args || {});
19946 if (!filterSVGString) {
19947 throw new Error('Non-existing filter ' + filter.name);
19949 var filterElement = V(filterSVGString);
19950 filterElement.attr('filterUnits', 'userSpaceOnUse');
19951 if (filter.attrs) filterElement.attr(filter.attrs);
19952 filterElement.node.id = filterId;
19953 V(this.paper.svg).defs().append(filterElement);
19956 $selected.each(function() {
19958 V(this).attr('filter', 'url(#' + filterId + ')');
19962 // `selector` is a CSS selector or `'.'`. `attr` is either a `'fill'` or `'stroke'`.
19963 // `gradient` must be in the special JointJS gradient format:
19964 // `{ type: <linearGradient|radialGradient>, stops: [ { offset: <offset>, color: <color> }, ... ]`.
19965 // An example is: `{ fill: { type: 'linearGradient', stops: [ { offset: '10%', color: 'green' }, { offset: '50%', color: 'blue' } ] } }`.
19966 applyGradient: function(selector, attr, gradient) {
19968 var $selected = this.findBySelector(selector);
19970 // Generate a hash code from the stringified filter definition. This gives us
19971 // a unique filter ID for different definitions.
19972 var gradientId = gradient.type + this.paper.svg.id + joint.util.hashCode(JSON.stringify(gradient));
19974 // If the gradient already exists in the document,
19975 // we're done and we can just use it (reference it using `url()`).
19976 // If not, create one.
19977 if (!this.paper.svg.getElementById(gradientId)) {
19979 var gradientSVGString = [
19980 '<' + gradient.type + '>',
19981 _.map(gradient.stops, function(stop) {
19982 return '<stop offset="' + stop.offset + '" stop-color="' + stop.color + '" stop-opacity="' + (_.isFinite(stop.opacity) ? stop.opacity : 1) + '" />'
19984 '</' + gradient.type + '>'
19987 var gradientElement = V(gradientSVGString);
19988 if (gradient.attrs) { gradientElement.attr(gradient.attrs); }
19989 gradientElement.node.id = gradientId;
19990 V(this.paper.svg).defs().append(gradientElement);
19993 $selected.each(function() {
19995 V(this).attr(attr, 'url(#' + gradientId + ')');
19999 // Construct a unique selector for the `el` element within this view.
20000 // `selector` is being collected through the recursive call. No value for `selector` is expected when using this method.
20001 getSelector: function(el, selector) {
20003 if (el === this.el) {
20008 var index = $(el).index();
20010 selector = el.tagName + ':nth-child(' + (index + 1) + ')' + ' ' + (selector || '');
20012 return this.getSelector($(el).parent()[0], selector + ' ');
20015 // Interaction. The controller part.
20016 // ---------------------------------
20018 // Interaction is handled by the paper and delegated to the view in interest.
20019 // `x` & `y` parameters passed to these functions represent the coordinates already snapped to the paper grid.
20020 // If necessary, real coordinates can be obtained from the `evt` event object.
20022 // These functions are supposed to be overriden by the views that inherit from `joint.dia.Cell`,
20023 // i.e. `joint.dia.Element` and `joint.dia.Link`.
20025 pointerdblclick: function(evt, x, y) {
20027 this.notify('cell:pointerdblclick', evt, x, y);
20030 pointerclick: function(evt, x, y) {
20032 this.notify('cell:pointerclick', evt, x, y);
20035 pointerdown: function(evt, x, y) {
20037 if (this.model.collection) {
20038 this.model.trigger('batch:start');
20039 this._collection = this.model.collection;
20042 this.notify('cell:pointerdown', evt, x, y);
20045 pointermove: function(evt, x, y) {
20047 this.notify('cell:pointermove', evt, x, y);
20050 pointerup: function(evt, x, y) {
20052 this.notify('cell:pointerup', evt, x, y);
20054 if (this._collection) {
20055 // we don't want to trigger event on model as model doesn't
20056 // need to be member of collection anymore (remove)
20057 this._collection.trigger('batch:stop');
20058 delete this._collection;
20065 if (typeof exports === 'object') {
20067 module.exports.Cell = joint.dia.Cell;
20068 module.exports.CellView = joint.dia.CellView;
20071 // JointJS library.
20072 // (c) 2011-2013 client IO
20075 if (typeof exports === 'object') {
20078 util: require('./core').util,
20080 Cell: require('./joint.dia.cell').Cell,
20081 CellView: require('./joint.dia.cell').CellView
20084 var Backbone = require('backbone');
20085 var _ = require('lodash');
20089 // joint.dia.Element base model.
20090 // -----------------------------
20092 joint.dia.Element = joint.dia.Cell.extend({
20095 position: { x: 0, y: 0 },
20096 size: { width: 1, height: 1 },
20100 position: function(x, y) {
20102 this.set('position', { x: x, y: y });
20105 translate: function(tx, ty, opt) {
20109 if (tx === 0 && ty === 0) {
20110 // Like nothing has happened.
20114 var position = this.get('position') || { x: 0, y: 0 };
20115 var translatedPosition = { x: position.x + tx || 0, y: position.y + ty || 0 };
20117 if (opt && opt.transition) {
20119 if (!_.isObject(opt.transition)) opt.transition = {};
20121 this.transition('position', translatedPosition, _.extend({}, opt.transition, {
20122 valueFunction: joint.util.interpolate.object
20127 this.set('position', translatedPosition, opt);
20129 // Recursively call `translate()` on all the embeds cells.
20130 _.invoke(this.getEmbeddedCells(), 'translate', tx, ty, opt);
20136 resize: function(width, height) {
20138 this.trigger('batch:start');
20139 this.set('size', { width: width, height: height });
20140 this.trigger('batch:stop');
20145 rotate: function(angle, absolute) {
20147 return this.set('angle', absolute ? angle : ((this.get('angle') || 0) + angle) % 360);
20150 getBBox: function() {
20152 var position = this.get('position');
20153 var size = this.get('size');
20155 return g.rect(position.x, position.y, size.width, size.height);
20159 // joint.dia.Element base view and controller.
20160 // -------------------------------------------
20162 joint.dia.ElementView = joint.dia.CellView.extend({
20164 className: function() {
20165 return 'element ' + this.model.get('type').split('.').join(' ');
20168 initialize: function() {
20170 _.bindAll(this, 'translate', 'resize', 'rotate');
20172 joint.dia.CellView.prototype.initialize.apply(this, arguments);
20174 this.listenTo(this.model, 'change:position', this.translate);
20175 this.listenTo(this.model, 'change:size', this.resize);
20176 this.listenTo(this.model, 'change:angle', this.rotate);
20179 // Default is to process the `attrs` object and set attributes on subelements based on the selectors.
20180 update: function(cell, renderingOnlyAttrs) {
20182 var allAttrs = this.model.get('attrs');
20184 var rotatable = V(this.$('.rotatable')[0]);
20187 var rotation = rotatable.attr('transform');
20188 rotatable.attr('transform', '');
20191 var relativelyPositioned = [];
20193 _.each(renderingOnlyAttrs || allAttrs, function(attrs, selector) {
20195 // Elements that should be updated.
20196 var $selected = this.findBySelector(selector);
20198 // No element matched by the `selector` was found. We're done then.
20199 if ($selected.length === 0) return;
20201 // Special attributes are treated by JointJS, not by SVG.
20202 var specialAttributes = ['style', 'text', 'html', 'ref-x', 'ref-y', 'ref-dx', 'ref-dy', 'ref-width', 'ref-height', 'ref', 'x-alignment', 'y-alignment', 'port'];
20204 // If the `filter` attribute is an object, it is in the special JointJS filter format and so
20205 // it becomes a special attribute and is treated separately.
20206 if (_.isObject(attrs.filter)) {
20208 specialAttributes.push('filter');
20209 this.applyFilter(selector, attrs.filter);
20212 // If the `fill` or `stroke` attribute is an object, it is in the special JointJS gradient format and so
20213 // it becomes a special attribute and is treated separately.
20214 if (_.isObject(attrs.fill)) {
20216 specialAttributes.push('fill');
20217 this.applyGradient(selector, 'fill', attrs.fill);
20219 if (_.isObject(attrs.stroke)) {
20221 specialAttributes.push('stroke');
20222 this.applyGradient(selector, 'stroke', attrs.stroke);
20225 // Make special case for `text` attribute. So that we can set text content of the `<text>` element
20226 // via the `attrs` object as well.
20227 // Note that it's important to set text before applying the rest of the final attributes.
20228 // Vectorizer `text()` method sets on the element its own attributes and it has to be possible
20229 // to rewrite them, if needed. (i.e display: 'none')
20230 if (!_.isUndefined(attrs.text)) {
20232 $selected.each(function() {
20234 V(this).text(attrs.text + '');
20238 // Set regular attributes on the `$selected` subelement. Note that we cannot use the jQuery attr()
20239 // method as some of the attributes might be namespaced (e.g. xlink:href) which fails with jQuery attr().
20240 var finalAttributes = _.omit(attrs, specialAttributes);
20242 $selected.each(function() {
20244 V(this).attr(finalAttributes);
20247 // `port` attribute contains the `id` of the port that the underlying magnet represents.
20250 $selected.attr('port', _.isUndefined(attrs.port.id) ? attrs.port : attrs.port.id);
20253 // `style` attribute is special in the sense that it sets the CSS style of the subelement.
20256 $selected.css(attrs.style);
20259 if (!_.isUndefined(attrs.html)) {
20261 $selected.each(function() {
20263 $(this).html(attrs.html + '');
20267 // Special `ref-x` and `ref-y` attributes make it possible to set both absolute or
20268 // relative positioning of subelements.
20269 if (!_.isUndefined(attrs['ref-x']) ||
20270 !_.isUndefined(attrs['ref-y']) ||
20271 !_.isUndefined(attrs['ref-dx']) ||
20272 !_.isUndefined(attrs['ref-dy']) ||
20273 !_.isUndefined(attrs['x-alignment']) ||
20274 !_.isUndefined(attrs['y-alignment']) ||
20275 !_.isUndefined(attrs['ref-width']) ||
20276 !_.isUndefined(attrs['ref-height'])
20279 _.each($selected, function(el, index, list) {
20281 // copy original list selector to the element
20282 $el.selector = list.selector;
20283 relativelyPositioned.push($el);
20289 // We don't want the sub elements to affect the bounding box of the root element when
20290 // positioning the sub elements relatively to the bounding box.
20291 //_.invoke(relativelyPositioned, 'hide');
20292 //_.invoke(relativelyPositioned, 'show');
20294 // Note that we're using the bounding box without transformation because we are already inside
20295 // a transformed coordinate system.
20296 var bbox = this.el.getBBox();
20298 renderingOnlyAttrs = renderingOnlyAttrs || {};
20300 _.each(relativelyPositioned, function($el) {
20302 // if there was a special attribute affecting the position amongst renderingOnlyAttributes
20303 // we have to merge it with rest of the element's attributes as they are necessary
20304 // to update the position relatively (i.e `ref`)
20305 var renderingOnlyElAttrs = renderingOnlyAttrs[$el.selector];
20306 var elAttrs = renderingOnlyElAttrs
20307 ? _.merge({}, allAttrs[$el.selector], renderingOnlyElAttrs)
20308 : allAttrs[$el.selector];
20310 this.positionRelative($el, bbox, elAttrs);
20316 rotatable.attr('transform', rotation || '');
20320 positionRelative: function($el, bbox, elAttrs) {
20322 var ref = elAttrs['ref'];
20323 var refX = parseFloat(elAttrs['ref-x']);
20324 var refY = parseFloat(elAttrs['ref-y']);
20325 var refDx = parseFloat(elAttrs['ref-dx']);
20326 var refDy = parseFloat(elAttrs['ref-dy']);
20327 var yAlignment = elAttrs['y-alignment'];
20328 var xAlignment = elAttrs['x-alignment'];
20329 var refWidth = parseFloat(elAttrs['ref-width']);
20330 var refHeight = parseFloat(elAttrs['ref-height']);
20332 // `ref` is the selector of the reference element. If no `ref` is passed, reference
20333 // element is the root element.
20335 var isScalable = _.contains(_.pluck(_.pluck($el.parents('g'), 'className'), 'baseVal'), 'scalable');
20339 // Get the bounding box of the reference element relative to the root `<g>` element.
20340 bbox = V(this.findBySelector(ref)[0]).bbox(false, this.el);
20343 var vel = V($el[0]);
20345 // Remove the previous translate() from the transform attribute and translate the element
20346 // relative to the root bounding box following the `ref-x` and `ref-y` attributes.
20347 if (vel.attr('transform')) {
20349 vel.attr('transform', vel.attr('transform').replace(/translate\([^)]*\)/g, '') || '');
20352 function isDefined(x) {
20353 return _.isNumber(x) && !_.isNaN(x);
20356 // The final translation of the subelement.
20360 // 'ref-width'/'ref-height' defines the width/height of the subelement relatively to
20361 // the reference element size
20362 // val in 0..1 ref-width = 0.75 sets the width to 75% of the ref. el. width
20363 // val < 0 || val > 1 ref-height = -20 sets the height to the the ref. el. height shorter by 20
20365 if (isDefined(refWidth)) {
20367 if (refWidth >= 0 && refWidth <= 1) {
20369 vel.attr('width', refWidth * bbox.width);
20373 vel.attr('width', Math.max(refWidth + bbox.width, 0));
20377 if (isDefined(refHeight)) {
20379 if (refHeight >= 0 && refHeight <= 1) {
20381 vel.attr('height', refHeight * bbox.height);
20385 vel.attr('height', Math.max(refHeight + bbox.height, 0));
20389 // `ref-dx` and `ref-dy` define the offset of the subelement relative to the right and/or bottom
20390 // coordinate of the reference element.
20391 if (isDefined(refDx)) {
20395 // Compensate for the scale grid in case the elemnt is in the scalable group.
20396 var scale = V(this.$('.scalable')[0]).scale();
20397 tx = bbox.x + bbox.width + refDx / scale.sx;
20401 tx = bbox.x + bbox.width + refDx;
20404 if (isDefined(refDy)) {
20408 // Compensate for the scale grid in case the elemnt is in the scalable group.
20409 var scale = V(this.$('.scalable')[0]).scale();
20410 ty = bbox.y + bbox.height + refDy / scale.sy;
20413 ty = bbox.y + bbox.height + refDy;
20417 // if `refX` is in [0, 1] then `refX` is a fraction of bounding box width
20418 // if `refX` is < 0 then `refX`'s absolute values is the right coordinate of the bounding box
20419 // otherwise, `refX` is the left coordinate of the bounding box
20420 // Analogical rules apply for `refY`.
20421 if (isDefined(refX)) {
20423 if (refX > 0 && refX < 1) {
20425 tx = bbox.x + bbox.width * refX;
20427 } else if (isScalable) {
20429 // Compensate for the scale grid in case the elemnt is in the scalable group.
20430 var scale = V(this.$('.scalable')[0]).scale();
20431 tx = bbox.x + refX / scale.sx;
20435 tx = bbox.x + refX;
20438 if (isDefined(refY)) {
20440 if (refY > 0 && refY < 1) {
20442 ty = bbox.y + bbox.height * refY;
20444 } else if (isScalable) {
20446 // Compensate for the scale grid in case the elemnt is in the scalable group.
20447 var scale = V(this.$('.scalable')[0]).scale();
20448 ty = bbox.y + refY / scale.sy;
20452 ty = bbox.y + refY;
20456 var velbbox = vel.bbox(false, this.paper.viewport);
20457 // `y-alignment` when set to `middle` causes centering of the subelement around its new y coordinate.
20458 if (yAlignment === 'middle') {
20460 ty -= velbbox.height/2;
20462 } else if (isDefined(yAlignment)) {
20464 ty += (yAlignment > -1 && yAlignment < 1) ? velbbox.height * yAlignment : yAlignment;
20467 // `x-alignment` when set to `middle` causes centering of the subelement around its new x coordinate.
20468 if (xAlignment === 'middle') {
20470 tx -= velbbox.width/2;
20472 } else if (isDefined(xAlignment)) {
20474 tx += (xAlignment > -1 && xAlignment < 1) ? velbbox.width * xAlignment : xAlignment;
20477 vel.translate(tx, ty);
20480 // `prototype.markup` is rendered by default. Set the `markup` attribute on the model if the
20481 // default markup is not desirable.
20482 renderMarkup: function() {
20484 var markup = this.model.markup || this.model.get('markup');
20488 var nodes = V(markup);
20489 V(this.el).append(nodes);
20493 throw new Error('properties.markup is missing while the default render() implementation is used.');
20497 render: function() {
20501 this.renderMarkup();
20512 // Scale the whole `<g>` group. Note the difference between `scale()` and `resize()` here.
20513 // `resize()` doesn't scale the whole `<g>` group but rather adjusts the `box.sx`/`box.sy` only.
20514 // `update()` is then responsible for scaling only those elements that have the `follow-scale`
20515 // attribute set to `true`. This is desirable in elements that have e.g. a `<text>` subelement
20516 // that is not supposed to be scaled together with a surrounding `<rect>` element that IS supposed
20518 scale: function(sx, sy) {
20520 // TODO: take into account the origin coordinates `ox` and `oy`.
20521 V(this.el).scale(sx, sy);
20524 resize: function() {
20526 var size = this.model.get('size') || { width: 1, height: 1 };
20527 var angle = this.model.get('angle') || 0;
20529 var scalable = V(this.$('.scalable')[0]);
20531 // If there is no scalable elements, than there is nothing to resize.
20534 var scalableBbox = scalable.bbox(true);
20536 scalable.attr('transform', 'scale(' + (size.width / scalableBbox.width) + ',' + (size.height / scalableBbox.height) + ')');
20538 // Now the interesting part. The goal is to be able to store the object geometry via just `x`, `y`, `angle`, `width` and `height`
20539 // Order of transformations is significant but we want to reconstruct the object always in the order:
20540 // resize(), rotate(), translate() no matter of how the object was transformed. For that to work,
20541 // we must adjust the `x` and `y` coordinates of the object whenever we resize it (because the origin of the
20542 // rotation changes). The new `x` and `y` coordinates are computed by canceling the previous rotation
20543 // around the center of the resized object (which is a different origin then the origin of the previous rotation)
20544 // and getting the top-left corner of the resulting object. Then we clean up the rotation back to what it originally was.
20546 // Cancel the rotation but now around a different origin, which is the center of the scaled object.
20547 var rotatable = V(this.$('.rotatable')[0]);
20548 var rotation = rotatable && rotatable.attr('transform');
20549 if (rotation && rotation !== 'null') {
20551 rotatable.attr('transform', rotation + ' rotate(' + (-angle) + ',' + (size.width/2) + ',' + (size.height/2) + ')');
20552 var rotatableBbox = scalable.bbox(false, this.paper.viewport);
20554 // Store new x, y and perform rotate() again against the new rotation origin.
20555 this.model.set('position', { x: rotatableBbox.x, y: rotatableBbox.y });
20559 // Update must always be called on non-rotated element. Otherwise, relative positioning
20560 // would work with wrong (rotated) bounding boxes.
20564 translate: function(model, changes, opt) {
20566 var position = this.model.get('position') || { x: 0, y: 0 };
20568 V(this.el).attr('transform', 'translate(' + position.x + ',' + position.y + ')');
20571 rotate: function() {
20573 var rotatable = V(this.$('.rotatable')[0]);
20575 // If there is no rotatable elements, then there is nothing to rotate.
20579 var angle = this.model.get('angle') || 0;
20580 var size = this.model.get('size') || { width: 1, height: 1 };
20582 var ox = size.width/2;
20583 var oy = size.height/2;
20586 rotatable.attr('transform', 'rotate(' + angle + ',' + ox + ',' + oy + ')');
20589 // Interaction. The controller part.
20590 // ---------------------------------
20593 pointerdown: function(evt, x, y) {
20595 if ( // target is a valid magnet start linking
20596 evt.target.getAttribute('magnet') &&
20597 this.paper.options.validateMagnet.call(this.paper, this, evt.target)
20599 this.model.trigger('batch:start');
20601 var link = this.paper.getDefaultLink(this, evt.target);
20605 selector: this.getSelector(evt.target),
20606 port: $(evt.target).attr('port')
20608 target: { x: x, y: y }
20611 this.paper.model.addCell(link);
20613 this._linkView = this.paper.findViewByModel(link);
20614 this._linkView.startArrowheadMove('target');
20621 joint.dia.CellView.prototype.pointerdown.apply(this, arguments);
20625 pointermove: function(evt, x, y) {
20627 if (this._linkView) {
20629 // let the linkview deal with this event
20630 this._linkView.pointermove(evt, x, y);
20634 var grid = this.paper.options.gridSize;
20636 if (this.options.interactive !== false) {
20638 var position = this.model.get('position');
20640 // Make sure the new element's position always snaps to the current grid after
20641 // translate as the previous one could be calculated with a different grid size.
20642 this.model.translate(
20643 g.snapToGrid(position.x, grid) - position.x + g.snapToGrid(x - this._dx, grid),
20644 g.snapToGrid(position.y, grid) - position.y + g.snapToGrid(y - this._dy, grid)
20648 this._dx = g.snapToGrid(x, grid);
20649 this._dy = g.snapToGrid(y, grid);
20651 joint.dia.CellView.prototype.pointermove.apply(this, arguments);
20655 pointerup: function(evt, x, y) {
20657 if (this._linkView) {
20659 // let the linkview deal with this event
20660 this._linkView.pointerup(evt, x, y);
20662 delete this._linkView;
20664 this.model.trigger('batch:stop');
20668 joint.dia.CellView.prototype.pointerup.apply(this, arguments);
20674 if (typeof exports === 'object') {
20676 module.exports.Element = joint.dia.Element;
20677 module.exports.ElementView = joint.dia.ElementView;
20680 // JointJS diagramming library.
20681 // (c) 2011-2013 client IO
20684 if (typeof exports === 'object') {
20688 Cell: require('./joint.dia.cell').Cell,
20689 CellView: require('./joint.dia.cell').CellView
20692 var Backbone = require('backbone');
20693 var _ = require('lodash');
20694 var g = require('./geometry');
20699 // joint.dia.Link base model.
20700 // --------------------------
20701 joint.dia.Link = joint.dia.Cell.extend({
20703 // The default markup for links.
20705 '<path class="connection" stroke="black"/>',
20706 '<path class="marker-source" fill="black" stroke="black" />',
20707 '<path class="marker-target" fill="black" stroke="black" />',
20708 '<path class="connection-wrap"/>',
20709 '<g class="labels"/>',
20710 '<g class="marker-vertices"/>',
20711 '<g class="marker-arrowheads"/>',
20712 '<g class="link-tools"/>'
20716 '<g class="label">',
20723 '<g class="link-tool">',
20724 '<g class="tool-remove" event="remove">',
20725 '<circle r="11" />',
20726 '<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"/>',
20727 '<title>Remove link.</title>',
20729 '<g class="tool-options" event="link:options">',
20730 '<circle r="11" transform="translate(25)"/>',
20731 '<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"/>',
20732 '<title>Link options.</title>',
20737 // The default markup for showing/removing vertices. These elements are the children of the .marker-vertices element (see `this.markup`).
20738 // Only .marker-vertex and .marker-vertex-remove element have special meaning. The former is used for
20739 // dragging vertices (changin their position). The latter is used for removing vertices.
20741 '<g class="marker-vertex-group" transform="translate(<%= x %>, <%= y %>)">',
20742 '<circle class="marker-vertex" idx="<%= idx %>" r="10" />',
20743 '<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)"/>',
20744 '<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">',
20745 '<title>Remove vertex.</title>',
20751 '<g class="marker-arrowhead-group marker-arrowhead-group-<%= end %>">',
20752 '<path class="marker-arrowhead" end="<%= end %>" d="M 26 0 L 0 13 L 26 26 z" />',
20761 disconnect: function() {
20763 return this.set({ source: g.point(0, 0), target: g.point(0, 0) });
20766 // A convenient way to set labels. Currently set values will be mixined with `value` if used as a setter.
20767 label: function(idx, value) {
20771 var labels = this.get('labels') || [];
20774 if (arguments.length === 0 || arguments.length === 1) {
20776 return labels[idx];
20779 var newValue = _.merge({}, labels[idx], value);
20781 var newLabels = labels.slice();
20782 newLabels[idx] = newValue;
20784 return this.set({ labels: newLabels });
20789 // joint.dia.Link base view and controller.
20790 // ----------------------------------------
20792 joint.dia.LinkView = joint.dia.CellView.extend({
20794 className: function() {
20795 return _.unique(this.model.get('type').split('.').concat('link')).join(' ');
20800 shortLinkLength: 100
20803 initialize: function() {
20805 joint.dia.CellView.prototype.initialize.apply(this, arguments);
20807 // create methods in prototype, so they can be accessed from any instance and
20808 // don't need to be create over and over
20809 if (typeof this.constructor.prototype.watchSource !== 'function') {
20810 this.constructor.prototype.watchSource = this._createWatcher('source');
20811 this.constructor.prototype.watchTarget = this._createWatcher('target');
20814 // `_.labelCache` is a mapping of indexes of labels in the `this.get('labels')` array to
20815 // `<g class="label">` nodes wrapped by Vectorizer. This allows for quick access to the
20816 // nodes in `updateLabelPosition()` in order to update the label positions.
20817 this._labelCache = {};
20819 // keeps markers bboxes and positions again for quicker access
20820 this._markerCache = {};
20823 this.startListening();
20826 startListening: function() {
20828 this.listenTo(this.model, 'change:markup', this.render);
20829 this.listenTo(this.model, 'change:smooth change:manhattan change:router change:connector', this.update);
20830 this.listenTo(this.model, 'change:toolMarkup', function() {
20831 this.renderTools().updateToolsPosition();
20833 this.listenTo(this.model, 'change:labels change:labelMarkup', function() {
20834 this.renderLabels().updateLabelPositions();
20836 this.listenTo(this.model, 'change:vertices change:vertexMarkup', function() {
20837 this.renderVertexMarkers().update();
20839 this.listenTo(this.model, 'change:source', function(cell, source) {
20840 this.watchSource(cell, source).update();
20842 this.listenTo(this.model, 'change:target', function(cell, target) {
20843 this.watchTarget(cell, target).update();
20850 render: function() {
20854 // A special markup can be given in the `properties.markup` property. This might be handy
20855 // if e.g. arrowhead markers should be `<image>` elements or any other element than `<path>`s.
20856 // `.connection`, `.connection-wrap`, `.marker-source` and `.marker-target` selectors
20857 // of elements with special meaning though. Therefore, those classes should be preserved in any
20858 // special markup passed in `properties.markup`.
20859 var children = V(this.model.get('markup') || this.model.markup);
20861 // custom markup may contain only one children
20862 if (!_.isArray(children)) children = [children];
20864 // Cache all children elements for quicker access.
20865 this._V = {}; // vectorized markup;
20866 _.each(children, function(child) {
20867 var c = child.attr('class');
20868 c && (this._V[$.camelCase(c)] = child);
20871 // Only the connection path is mandatory
20872 if (!this._V.connection) throw new Error('link: no connection path in the markup');
20874 // partial rendering
20875 this.renderTools();
20876 this.renderVertexMarkers();
20877 this.renderArrowheadMarkers();
20879 V(this.el).append(children);
20881 // rendering labels has to be run after the link is appended to DOM tree. (otherwise <Text> bbox
20882 // returns zero values)
20883 this.renderLabels();
20885 // start watching the ends of the link for changes
20886 this.watchSource(this.model, this.model.get('source'))
20887 .watchTarget(this.model, this.model.get('target'))
20893 renderLabels: function() {
20895 if (!this._V.labels) return this;
20897 this._labelCache = {};
20898 var $labels = $(this._V.labels.node).empty();
20900 var labels = this.model.get('labels') || [];
20901 if (!labels.length) return this;
20903 var labelTemplate = _.template(this.model.get('labelMarkup') || this.model.labelMarkup);
20904 // This is a prepared instance of a vectorized SVGDOM node for the label element resulting from
20905 // compilation of the labelTemplate. The purpose is that all labels will just `clone()` this
20906 // node to create a duplicate.
20907 var labelNodeInstance = V(labelTemplate());
20909 _.each(labels, function(label, idx) {
20911 var labelNode = labelNodeInstance.clone().node;
20912 // Cache label nodes so that the `updateLabels()` can just update the label node positions.
20913 this._labelCache[idx] = V(labelNode);
20915 var $text = $(labelNode).find('text');
20916 var $rect = $(labelNode).find('rect');
20918 // Text attributes with the default `text-anchor` and font-size set.
20919 var textAttributes = _.extend({ 'text-anchor': 'middle', 'font-size': 14 }, joint.util.getByPath(label, 'attrs/text', '/'));
20921 $text.attr(_.omit(textAttributes, 'text'));
20923 if (!_.isUndefined(textAttributes.text)) {
20925 V($text[0]).text(textAttributes.text + '');
20928 // Note that we first need to append the `<text>` element to the DOM in order to
20929 // get its bounding box.
20930 $labels.append(labelNode);
20932 // `y-alignment` - center the text element around its y coordinate.
20933 var textBbox = V($text[0]).bbox(true, $labels[0]);
20934 V($text[0]).translate(0, -textBbox.height/2);
20936 // Add default values.
20937 var rectAttributes = _.extend({
20943 }, joint.util.getByPath(label, 'attrs/rect', '/'));
20945 $rect.attr(_.extend(rectAttributes, {
20948 y: textBbox.y - textBbox.height/2, // Take into account the y-alignment translation.
20949 width: textBbox.width,
20950 height: textBbox.height
20958 renderTools: function() {
20960 if (!this._V.linkTools) return this;
20962 // Tools are a group of clickable elements that manipulate the whole link.
20963 // A good example of this is the remove tool that removes the whole link.
20964 // Tools appear after hovering the link close to the `source` element/point of the link
20965 // but are offset a bit so that they don't cover the `marker-arrowhead`.
20967 var $tools = $(this._V.linkTools.node).empty();
20968 var toolTemplate = _.template(this.model.get('toolMarkup') || this.model.toolMarkup);
20969 var tool = V(toolTemplate());
20971 $tools.append(tool.node);
20973 // Cache the tool node so that the `updateToolsPosition()` can update the tool position quickly.
20974 this._toolCache = tool;
20979 renderVertexMarkers: function() {
20981 if (!this._V.markerVertices) return this;
20983 var $markerVertices = $(this._V.markerVertices.node).empty();
20985 // A special markup can be given in the `properties.vertexMarkup` property. This might be handy
20986 // if default styling (elements) are not desired. This makes it possible to use any
20987 // SVG elements for .marker-vertex and .marker-vertex-remove tools.
20988 var markupTemplate = _.template(this.model.get('vertexMarkup') || this.model.vertexMarkup);
20990 _.each(this.model.get('vertices'), function(vertex, idx) {
20992 $markerVertices.append(V(markupTemplate(_.extend({ idx: idx }, vertex))).node);
20998 renderArrowheadMarkers: function() {
21000 // Custom markups might not have arrowhead markers. Therefore, jump of this function immediately if that's the case.
21001 if (!this._V.markerArrowheads) return this;
21003 var $markerArrowheads = $(this._V.markerArrowheads.node);
21005 $markerArrowheads.empty();
21007 // A special markup can be given in the `properties.vertexMarkup` property. This might be handy
21008 // if default styling (elements) are not desired. This makes it possible to use any
21009 // SVG elements for .marker-vertex and .marker-vertex-remove tools.
21010 var markupTemplate = _.template(this.model.get('arrowheadMarkup') || this.model.arrowheadMarkup);
21012 this._V.sourceArrowhead = V(markupTemplate({ end: 'source' }));
21013 this._V.targetArrowhead = V(markupTemplate({ end: 'target' }));
21015 $markerArrowheads.append(this._V.sourceArrowhead.node, this._V.targetArrowhead.node);
21023 // Default is to process the `attrs` object and set attributes on subelements based on the selectors.
21024 update: function() {
21026 // Update attributes.
21027 _.each(this.model.get('attrs'), function(attrs, selector) {
21029 // If the `filter` attribute is an object, it is in the special JointJS filter format and so
21030 // it becomes a special attribute and is treated separately.
21031 if (_.isObject(attrs.filter)) {
21033 this.findBySelector(selector).attr(_.omit(attrs, 'filter'));
21034 this.applyFilter(selector, attrs.filter);
21038 this.findBySelector(selector).attr(attrs);
21043 var vertices = this.route = this.findRoute(this.model.get('vertices') || []);
21045 // finds all the connection points taking new vertices into account
21046 this._findConnectionPoints(vertices);
21048 var pathData = this.getPathData(vertices);
21050 // The markup needs to contain a `.connection`
21051 this._V.connection.attr('d', pathData);
21052 this._V.connectionWrap && this._V.connectionWrap.attr('d', pathData);
21054 this._translateAndAutoOrientArrows(this._V.markerSource, this._V.markerTarget);
21057 this.updateLabelPositions();
21058 this.updateToolsPosition();
21059 this.updateArrowheadMarkers();
21061 delete this.options.perpendicular;
21066 _findConnectionPoints: function(vertices) {
21068 // cache source and target points
21069 var sourcePoint, targetPoint, sourceMarkerPoint, targetMarkerPoint;
21071 var firstVertex = _.first(vertices);
21073 sourcePoint = this.getConnectionPoint(
21074 'source', this.model.get('source'), firstVertex || this.model.get('target')
21077 var lastVertex = _.last(vertices);
21079 targetPoint = this.getConnectionPoint(
21080 'target', this.model.get('target'), lastVertex || sourcePoint
21083 // Move the source point by the width of the marker taking into account
21084 // its scale around x-axis. Note that scale is the only transform that
21085 // makes sense to be set in `.marker-source` attributes object
21086 // as all other transforms (translate/rotate) will be replaced
21087 // by the `translateAndAutoOrient()` function.
21088 var cache = this._markerCache;
21090 if (this._V.markerSource) {
21092 cache.sourceBBox = cache.sourceBBox || this._V.markerSource.bbox(true);
21094 sourceMarkerPoint = g.point(sourcePoint).move(
21095 firstVertex || targetPoint,
21096 cache.sourceBBox.width * this._V.markerSource.scale().sx * -1
21100 if (this._V.markerTarget) {
21102 cache.targetBBox = cache.targetBBox || this._V.markerTarget.bbox(true);
21104 targetMarkerPoint = g.point(targetPoint).move(
21105 lastVertex || sourcePoint,
21106 cache.targetBBox.width * this._V.markerTarget.scale().sx * -1
21110 // if there was no markup for the marker, use the connection point.
21111 cache.sourcePoint = sourceMarkerPoint || sourcePoint;
21112 cache.targetPoint = targetMarkerPoint || targetPoint;
21114 // make connection points public
21115 this.sourcePoint = sourcePoint;
21116 this.targetPoint = targetPoint;
21119 updateLabelPositions: function() {
21121 if (!this._V.labels) return this;
21123 // This method assumes all the label nodes are stored in the `this._labelCache` hash table
21124 // by their indexes in the `this.get('labels')` array. This is done in the `renderLabels()` method.
21126 var labels = this.model.get('labels') || [];
21127 if (!labels.length) return this;
21129 var connectionElement = this._V.connection.node;
21130 var connectionLength = connectionElement.getTotalLength();
21132 _.each(labels, function(label, idx) {
21134 var position = label.position;
21135 position = (position > connectionLength) ? connectionLength : position; // sanity check
21136 position = (position < 0) ? connectionLength + position : position;
21137 position = position > 1 ? position : connectionLength * position;
21139 var labelCoordinates = connectionElement.getPointAtLength(position);
21141 this._labelCache[idx].attr('transform', 'translate(' + labelCoordinates.x + ', ' + labelCoordinates.y + ')');
21149 updateToolsPosition: function() {
21151 if (!this._V.linkTools) return this;
21153 // Move the tools a bit to the target position but don't cover the `sourceArrowhead` marker.
21154 // Note that the offset is hardcoded here. The offset should be always
21155 // more than the `this.$('.marker-arrowhead[end="source"]')[0].bbox().width` but looking
21156 // this up all the time would be slow.
21161 // If the link is too short, make the tools half the size and the offset twice as low.
21162 if (this.getConnectionLength() < this.options.shortLinkLength) {
21163 scale = 'scale(.5)';
21167 var toolPosition = this.getPointAtLength(offset);
21169 this._toolCache.attr('transform', 'translate(' + toolPosition.x + ', ' + toolPosition.y + ') ' + scale);
21175 updateArrowheadMarkers: function() {
21177 if (!this._V.markerArrowheads) return this;
21179 // getting bbox of an element with `display="none"` in IE9 ends up with access violation
21180 if ($.css(this._V.markerArrowheads.node, 'display') === 'none') return this;
21182 var sx = this.getConnectionLength() < this.options.shortLinkLength ? .5 : 1;
21183 this._V.sourceArrowhead.scale(sx);
21184 this._V.targetArrowhead.scale(sx);
21186 this._translateAndAutoOrientArrows(this._V.sourceArrowhead, this._V.targetArrowhead);
21191 // Returns a function observing changes on an end of the link. If a change happens and new end is a new model,
21192 // it stops listening on the previous one and starts listening to the new one.
21193 _createWatcher: function(endType) {
21195 function watchEnd(link, end) {
21199 var previousEnd = link.previous(endType) || {};
21201 // Pick updateMethod this._sourceBboxUpdate or this._targetBboxUpdate.
21202 var updateEndFunction = this['_' + endType + 'BBoxUpdate'];
21204 if (this._isModel(previousEnd)) {
21205 this.stopListening(this.paper.getModelById(previousEnd.id), 'change', updateEndFunction);
21208 if (this._isModel(end)) {
21209 // If the observed model changes, it caches a new bbox and do the link update.
21210 this.listenTo(this.paper.getModelById(end.id), 'change', updateEndFunction);
21213 _.bind(updateEndFunction, this)({ cacheOnly: true });
21221 // It's important to keep both methods (sourceBboxUpdate and targetBboxUpdate) as unique methods
21222 // because of loop links. We have to be able to determine, which method we want to stop listen to.
21223 // ListenTo(model, event, handler) as model and event will be identical.
21224 _sourceBBoxUpdate: function(update) {
21226 // keep track which end had been changed very last
21227 this.lastEndChange = 'source';
21229 update = update || {};
21230 var end = this.model.get('source');
21232 if (this._isModel(end)) {
21234 var selector = this._makeSelector(end);
21235 var view = this.paper.findViewByModel(end.id);
21236 var magnetElement = this.paper.viewport.querySelector(selector);
21238 this.sourceBBox = view.getStrokeBBox(magnetElement);
21241 // the link end is a point ~ rect 1x1
21242 this.sourceBBox = g.rect(end.x, end.y, 1, 1);
21245 if (!update.cacheOnly) this.update();
21248 _targetBBoxUpdate: function(update) {
21250 // keep track which end had been changed very last
21251 this.lastEndChange = 'target';
21253 update = update || {};
21254 var end = this.model.get('target');
21256 if (this._isModel(end)) {
21258 var selector = this._makeSelector(end);
21259 var view = this.paper.findViewByModel(end.id);
21260 var magnetElement = this.paper.viewport.querySelector(selector);
21262 this.targetBBox = view.getStrokeBBox(magnetElement);
21265 // the link end is a point ~ rect 1x1
21266 this.targetBBox = g.rect(end.x, end.y, 1, 1);
21269 if (!update.cacheOnly) this.update();
21272 _translateAndAutoOrientArrows: function(sourceArrow, targetArrow) {
21274 // Make the markers "point" to their sticky points being auto-oriented towards
21275 // `targetPosition`/`sourcePosition`. And do so only if there is a markup for them.
21277 sourceArrow.translateAndAutoOrient(
21279 _.first(this.route) || this.targetPoint,
21280 this.paper.viewport
21285 targetArrow.translateAndAutoOrient(
21287 _.last(this.route) || this.sourcePoint,
21288 this.paper.viewport
21293 removeVertex: function(idx) {
21295 var vertices = _.clone(this.model.get('vertices'));
21297 if (vertices && vertices.length) {
21299 vertices.splice(idx, 1);
21300 this.model.set('vertices', vertices);
21306 // This method ads a new vertex to the `vertices` array of `.connection`. This method
21307 // uses a heuristic to find the index at which the new `vertex` should be placed at assuming
21308 // the new vertex is somewhere on the path.
21309 addVertex: function(vertex) {
21311 this.model.set('attrs', this.model.get('attrs') || {});
21312 var attrs = this.model.get('attrs');
21314 // As it is very hard to find a correct index of the newly created vertex,
21315 // a little heuristics is taking place here.
21316 // The heuristics checks if length of the newly created
21317 // path is lot more than length of the old path. If this is the case,
21318 // new vertex was probably put into a wrong index.
21319 // Try to put it into another index and repeat the heuristics again.
21321 var vertices = (this.model.get('vertices') || []).slice();
21322 // Store the original vertices for a later revert if needed.
21323 var originalVertices = vertices.slice();
21325 // A `<path>` element used to compute the length of the path during heuristics.
21326 var path = this._V.connection.node.cloneNode(false);
21328 // Length of the original path.
21329 var originalPathLength = path.getTotalLength();
21330 // Current path length.
21332 // Tolerance determines the highest possible difference between the length
21333 // of the old and new path. The number has been chosen heuristically.
21334 var pathLengthTolerance = 20;
21335 // Total number of vertices including source and target points.
21336 var idx = vertices.length + 1;
21338 // Loop through all possible indexes and check if the difference between
21339 // path lengths changes significantly. If not, the found index is
21340 // most probably the right one.
21343 vertices.splice(idx, 0, vertex);
21344 V(path).attr('d', this.getPathData(this.findRoute(vertices)));
21346 pathLength = path.getTotalLength();
21348 // Check if the path lengths changed significantly.
21349 if (pathLength - originalPathLength > pathLengthTolerance) {
21351 // Revert vertices to the original array. The path length has changed too much
21352 // so that the index was not found yet.
21353 vertices = originalVertices.slice();
21361 this.model.set('vertices', vertices);
21363 // In manhattan routing, if there are no vertices, the path length changes significantly
21364 // with the first vertex added. Shall we check vertices.length === 0? at beginning of addVertex()
21365 // in order to avoid the temporary path construction and other operations?
21366 return Math.max(idx, 0);
21370 findRoute: function(oldVertices) {
21372 var router = this.model.get('router');
21376 if (this.model.get('manhattan')) {
21377 // backwards compability
21378 router = { name: 'orthogonal' };
21381 return oldVertices;
21385 var fn = joint.routers[router.name];
21387 if (!_.isFunction(fn)) {
21389 throw 'unknown router: ' + router.name;
21392 var newVertices = fn.call(this, oldVertices || [], router.args || {}, this);
21394 return newVertices;
21397 // Return the `d` attribute value of the `<path>` element representing the link
21398 // between `source` and `target`.
21399 getPathData: function(vertices) {
21401 var connector = this.model.get('connector');
21405 // backwards compability
21406 connector = this.model.get('smooth') ? { name: 'smooth' } : { name: 'normal' };
21409 if (!_.isFunction(joint.connectors[connector.name])) {
21411 throw 'unknown connector: ' + connector.name;
21414 var pathData = joint.connectors[connector.name].call(
21416 this._markerCache.sourcePoint, // Note that the value is translated by the size
21417 this._markerCache.targetPoint, // of the marker. (We'r not using this.sourcePoint)
21418 vertices || (this.model.get('vertices') || {}),
21419 connector.args || {}, // options
21426 // Find a point that is the start of the connection.
21427 // If `selectorOrPoint` is a point, then we're done and that point is the start of the connection.
21428 // If the `selectorOrPoint` is an element however, we need to know a reference point (or element)
21429 // that the link leads to in order to determine the start of the connection on the original element.
21430 getConnectionPoint: function(end, selectorOrPoint, referenceSelectorOrPoint) {
21434 if (this._isPoint(selectorOrPoint)) {
21436 // If the source is a point, we don't need a reference point to find the sticky point of connection.
21437 spot = g.point(selectorOrPoint);
21441 // If the source is an element, we need to find a point on the element boundary that is closest
21442 // to the reference point (or reference element).
21443 // Get the bounding box of the spot relative to the paper viewport. This is necessary
21444 // in order to follow paper viewport transformations (scale/rotate).
21445 // `_sourceBbox` (`_targetBbox`) comes from `_sourceBboxUpdate` (`_sourceBboxUpdate`)
21446 // method, it exists since first render and are automatically updated
21447 var spotBbox = end === 'source' ? this.sourceBBox : this.targetBBox;
21451 if (this._isPoint(referenceSelectorOrPoint)) {
21453 // Reference was passed as a point, therefore, we're ready to find the sticky point of connection on the source element.
21454 reference = g.point(referenceSelectorOrPoint);
21458 // Reference was passed as an element, therefore we need to find a point on the reference
21459 // element boundary closest to the source element.
21460 // Get the bounding box of the spot relative to the paper viewport. This is necessary
21461 // in order to follow paper viewport transformations (scale/rotate).
21462 var referenceBbox = end === 'source' ? this.targetBBox : this.sourceBBox;
21464 reference = g.rect(referenceBbox).intersectionWithLineFromCenterToPoint(g.rect(spotBbox).center());
21465 reference = reference || g.rect(referenceBbox).center();
21468 // If `perpendicularLinks` flag is set on the paper and there are vertices
21469 // on the link, then try to find a connection point that makes the link perpendicular
21470 // even though the link won't point to the center of the targeted object.
21471 if (this.paper.options.perpendicularLinks || this.options.perpendicular) {
21473 var horizontalLineRect = g.rect(0, reference.y, this.paper.options.width, 1);
21474 var verticalLineRect = g.rect(reference.x, 0, 1, this.paper.options.height);
21477 if (horizontalLineRect.intersect(g.rect(spotBbox))) {
21479 nearestSide = g.rect(spotBbox).sideNearestToPoint(reference);
21480 switch (nearestSide) {
21482 spot = g.point(spotBbox.x, reference.y);
21485 spot = g.point(spotBbox.x + spotBbox.width, reference.y);
21488 spot = g.rect(spotBbox).center();
21492 } else if (verticalLineRect.intersect(g.rect(spotBbox))) {
21494 nearestSide = g.rect(spotBbox).sideNearestToPoint(reference);
21495 switch (nearestSide) {
21497 spot = g.point(reference.x, spotBbox.y);
21500 spot = g.point(reference.x, spotBbox.y + spotBbox.height);
21503 spot = g.rect(spotBbox).center();
21509 // If there is no intersection horizontally or vertically with the object bounding box,
21510 // then we fall back to the regular situation finding straight line (not perpendicular)
21511 // between the object and the reference point.
21513 spot = g.rect(spotBbox).intersectionWithLineFromCenterToPoint(reference);
21514 spot = spot || g.rect(spotBbox).center();
21519 spot = g.rect(spotBbox).intersectionWithLineFromCenterToPoint(reference);
21520 spot = spot || g.rect(spotBbox).center();
21527 _isModel: function(end) {
21529 return end && end.id;
21532 _isPoint: function(end) {
21534 return !this._isModel(end);
21537 _makeSelector: function(end) {
21539 var selector = '[model-id="' + end.id + '"]';
21540 // `port` has a higher precendence over `selector`. This is because the selector to the magnet
21541 // might change while the name of the port can stay the same.
21543 selector += ' [port="' + end.port + '"]';
21544 } else if (end.selector) {
21545 selector += ' ' + end.selector;
21554 getConnectionLength: function() {
21556 return this._V.connection.node.getTotalLength();
21559 getPointAtLength: function(length) {
21561 return this._V.connection.node.getPointAtLength(length);
21564 // Interaction. The controller part.
21565 // ---------------------------------
21567 _beforeArrowheadMove: function() {
21569 this.model.trigger('batch:start');
21571 this._z = this.model.get('z');
21572 this.model.set('z', Number.MAX_VALUE);
21574 // Let the pointer propagate throught the link view elements so that
21575 // the `evt.target` is another element under the pointer, not the link itself.
21576 this.el.style.pointerEvents = 'none';
21579 _afterArrowheadMove: function() {
21582 this.model.set('z', this._z);
21586 // Put `pointer-events` back to its original value. See `startArrowheadMove()` for explanation.
21587 // Value `auto` doesn't work in IE9. We force to use `visiblePainted` instead.
21588 // See `https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events`.
21589 this.el.style.pointerEvents = 'visiblePainted';
21591 this.model.trigger('batch:stop');
21594 _createValidateConnectionArgs: function(arrowhead) {
21595 // It makes sure the arguments for validateConnection have the following form:
21596 // (source view, source magnet, target view, target magnet and link view)
21599 args[4] = arrowhead;
21602 var oppositeArrowhead, i = 0, j = 0;
21604 if (arrowhead === 'source') {
21606 oppositeArrowhead = 'target';
21609 oppositeArrowhead = 'source';
21612 var end = this.model.get(oppositeArrowhead);
21615 args[i] = this.paper.findViewByModel(end.id);
21616 args[i+1] = end.selector && args[i].el.querySelector(end.selector);
21619 function validateConnectionArgs(cellView, magnet) {
21620 args[j] = cellView;
21621 args[j+1] = cellView.el === magnet ? undefined : magnet;
21625 return validateConnectionArgs;
21628 startArrowheadMove: function(end) {
21629 // Allow to delegate events from an another view to this linkView in order to trigger arrowhead
21630 // move without need to click on the actual arrowhead dom element.
21631 this._action = 'arrowhead-move';
21632 this._arrowhead = end;
21633 this._beforeArrowheadMove();
21634 this._validateConnectionArgs = this._createValidateConnectionArgs(this._arrowhead);
21637 pointerdown: function(evt, x, y) {
21639 joint.dia.CellView.prototype.pointerdown.apply(this, arguments);
21644 if (this.options.interactive === false) return;
21646 var className = evt.target.getAttribute('class');
21648 switch (className) {
21650 case 'marker-vertex':
21651 this._action = 'vertex-move';
21652 this._vertexIdx = evt.target.getAttribute('idx');
21655 case 'marker-vertex-remove':
21656 case 'marker-vertex-remove-area':
21657 this.removeVertex(evt.target.getAttribute('idx'));
21660 case 'marker-arrowhead':
21661 this.startArrowheadMove(evt.target.getAttribute('end'));
21666 var targetParentEvent = evt.target.parentNode.getAttribute('event');
21668 if (targetParentEvent) {
21670 // `remove` event is built-in. Other custom events are triggered on the paper.
21671 if (targetParentEvent === 'remove') {
21672 this.model.remove();
21674 this.paper.trigger(targetParentEvent, evt, this, x, y);
21679 // Store the index at which the new vertex has just been placed.
21680 // We'll be update the very same vertex position in `pointermove()`.
21681 this._vertexIdx = this.addVertex({ x: x, y: y });
21682 this._action = 'vertex-move';
21687 pointermove: function(evt, x, y) {
21689 joint.dia.CellView.prototype.pointermove.apply(this, arguments);
21691 switch (this._action) {
21693 case 'vertex-move':
21695 var vertices = _.clone(this.model.get('vertices'));
21696 vertices[this._vertexIdx] = { x: x, y: y };
21697 this.model.set('vertices', vertices);
21700 case 'arrowhead-move':
21702 if (this.paper.options.snapLinks) {
21704 // checking view in close area of the pointer
21706 var r = this.paper.options.snapLinks.radius || 50;
21707 var viewsInArea = this.paper.findViewsInArea({ x: x - r, y: y - r, width: 2 * r, height: 2 * r });
21709 this._closestView && this._closestView.unhighlight(this._closestEnd.selector);
21710 this._closestView = this._closestEnd = null;
21712 var pointer = g.point(x,y);
21713 var distance, minDistance = Number.MAX_VALUE;
21715 _.each(viewsInArea, function(view) {
21717 // skip connecting to the element in case '.': { magnet: false } attribute present
21718 if (view.el.getAttribute('magnet') !== 'false') {
21720 // find distance from the center of the model to pointer coordinates
21721 distance = view.model.getBBox().center().distance(pointer);
21723 // the connection is looked up in a circle area by `distance < r`
21724 if (distance < r && distance < minDistance) {
21726 if (this.paper.options.validateConnection.apply(
21727 this.paper, this._validateConnectionArgs(view, null)
21729 minDistance = distance;
21730 this._closestView = view;
21731 this._closestEnd = { id: view.model.id };
21736 view.$('[magnet]').each(_.bind(function(index, magnet) {
21738 var bbox = V(magnet).bbox(false, this.paper.viewport);
21740 distance = pointer.distance({
21741 x: bbox.x + bbox.width / 2,
21742 y: bbox.y + bbox.height / 2
21745 if (distance < r && distance < minDistance) {
21747 if (this.paper.options.validateConnection.apply(
21748 this.paper, this._validateConnectionArgs(view, magnet)
21750 minDistance = distance;
21751 this._closestView = view;
21752 this._closestEnd = {
21754 selector: view.getSelector(magnet),
21755 port: magnet.getAttribute('port')
21764 this._closestView && this._closestView.highlight(this._closestEnd.selector);
21766 this.model.set(this._arrowhead, this._closestEnd || { x: x, y: y });
21770 // checking views right under the pointer
21772 // Touchmove event's target is not reflecting the element under the coordinates as mousemove does.
21773 // It holds the element when a touchstart triggered.
21774 var target = (evt.type === 'mousemove')
21776 : document.elementFromPoint(evt.clientX, evt.clientY);
21778 if (this._targetEvent !== target) {
21779 // Unhighlight the previous view under pointer if there was one.
21780 this._magnetUnderPointer && this._viewUnderPointer.unhighlight(this._magnetUnderPointer);
21781 this._viewUnderPointer = this.paper.findView(target);
21782 if (this._viewUnderPointer) {
21783 // If we found a view that is under the pointer, we need to find the closest
21784 // magnet based on the real target element of the event.
21785 this._magnetUnderPointer = this._viewUnderPointer.findMagnet(target);
21787 if (this._magnetUnderPointer && this.paper.options.validateConnection.apply(
21789 this._validateConnectionArgs(this._viewUnderPointer, this._magnetUnderPointer)
21791 // If there was no magnet found, do not highlight anything and assume there
21792 // is no view under pointer we're interested in reconnecting to.
21793 // This can only happen if the overall element has the attribute `'.': { magnet: false }`.
21794 this._magnetUnderPointer && this._viewUnderPointer.highlight(this._magnetUnderPointer);
21796 // This type of connection is not valid. Disregard this magnet.
21797 this._magnetUnderPointer = null;
21800 // Make sure we'll delete previous magnet
21801 this._magnetUnderPointer = null;
21805 this._targetEvent = target;
21807 this.model.set(this._arrowhead, { x: x, y: y });
21817 pointerup: function(evt) {
21819 joint.dia.CellView.prototype.pointerup.apply(this, arguments);
21821 if (this._action === 'arrowhead-move') {
21823 if (this.paper.options.snapLinks) {
21825 this._closestView && this._closestView.unhighlight(this._closestEnd.selector);
21826 this._closestView = this._closestEnd = null;
21830 if (this._magnetUnderPointer) {
21831 this._viewUnderPointer.unhighlight(this._magnetUnderPointer);
21832 // Find a unique `selector` of the element under pointer that is a magnet. If the
21833 // `this._magnetUnderPointer` is the root element of the `this._viewUnderPointer` itself,
21834 // the returned `selector` will be `undefined`. That means we can directly pass it to the
21835 // `source`/`target` attribute of the link model below.
21836 this.model.set(this._arrowhead, {
21837 id: this._viewUnderPointer.model.id,
21838 selector: this._viewUnderPointer.getSelector(this._magnetUnderPointer),
21839 port: $(this._magnetUnderPointer).attr('port')
21843 delete this._viewUnderPointer;
21844 delete this._magnetUnderPointer;
21845 delete this._staticView;
21846 delete this._staticMagnet;
21849 this._afterArrowheadMove();
21852 delete this._action;
21857 if (typeof exports === 'object') {
21859 module.exports.Link = joint.dia.Link;
21860 module.exports.LinkView = joint.dia.LinkView;
21863 // JointJS library.
21864 // (c) 2011-2013 client IO
21867 joint.dia.Paper = Backbone.View.extend({
21874 perpendicularLinks: false,
21875 elementView: joint.dia.ElementView,
21876 linkView: joint.dia.LinkView,
21877 snapLinks: false, // false, true, { radius: value }
21879 // Defines what link model is added to the graph after an user clicks on an active magnet.
21880 // Value could be the Backbone.model or a function returning the Backbone.model
21881 // defaultLink: function(elementView, magnet) { return condition ? new customLink1() : new customLink2() }
21882 defaultLink: new joint.dia.Link,
21884 // Check whether to add a new link to the graph when user clicks on an a magnet.
21885 validateMagnet: function(cellView, magnet) {
21886 return magnet.getAttribute('magnet') !== 'passive';
21889 // Check whether to allow or disallow the link connection while an arrowhead end (source/target)
21891 validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {
21892 return (end === 'target' ? cellViewT : cellViewS) instanceof joint.dia.ElementView;
21898 'mousedown': 'pointerdown',
21899 'dblclick': 'mousedblclick',
21900 'click': 'mouseclick',
21901 'touchstart': 'pointerdown',
21902 'mousemove': 'pointermove',
21903 'touchmove': 'pointermove'
21906 initialize: function() {
21908 _.bindAll(this, 'addCell', 'sortCells', 'resetCells', 'pointerup');
21910 this.svg = V('svg').node;
21911 this.viewport = V('g').node;
21913 // Append `<defs>` element to the SVG document. This is useful for filters and gradients.
21914 V(this.svg).append(V('defs').node);
21916 V(this.viewport).attr({ 'class': 'viewport' });
21918 V(this.svg).append(this.viewport);
21920 this.$el.append(this.svg);
21922 this.setDimensions();
21924 this.listenTo(this.model, 'add', this.addCell);
21925 this.listenTo(this.model, 'reset', this.resetCells);
21926 this.listenTo(this.model, 'sort', this.sortCells);
21928 $(document).on('mouseup touchend', this.pointerup);
21930 // Hold the value when mouse has been moved: when mouse moved, no click event will be triggered.
21931 this._mousemoved = false;
21934 remove: function() {
21936 $(document).off('mouseup touchend', this.pointerup);
21938 Backbone.View.prototype.remove.call(this);
21941 setDimensions: function(width, height) {
21943 if (width) this.options.width = width;
21944 if (height) this.options.height = height;
21946 V(this.svg).attr('width', this.options.width);
21947 V(this.svg).attr('height', this.options.height);
21949 this.trigger('resize');
21952 // Expand/shrink the paper to fit the content. Snap the width/height to the grid
21953 // defined in `gridWidth`, `gridHeight`. `padding` adds to the resulting width/height of the paper.
21954 fitToContent: function(gridWidth, gridHeight, padding) {
21956 gridWidth = gridWidth || 1;
21957 gridHeight = gridHeight || 1;
21958 padding = padding || 0;
21960 // Calculate the paper size to accomodate all the graph's elements.
21961 var bbox = V(this.viewport).bbox(true, this.svg);
21963 var calcWidth = Math.ceil((bbox.width + bbox.x) / gridWidth) * gridWidth;
21964 var calcHeight = Math.ceil((bbox.height + bbox.y) / gridHeight) * gridHeight;
21966 calcWidth += padding;
21967 calcHeight += padding;
21969 // Change the dimensions only if there is a size discrepency
21970 if (calcWidth != this.options.width || calcHeight != this.options.height) {
21971 this.setDimensions(calcWidth || this.options.width , calcHeight || this.options.height);
21975 getContentBBox: function() {
21977 var crect = this.viewport.getBoundingClientRect();
21979 // Using Screen CTM was the only way to get the real viewport bounding box working in both
21980 // Google Chrome and Firefox.
21981 var ctm = this.viewport.getScreenCTM();
21983 var bbox = g.rect(Math.abs(crect.left - ctm.e), Math.abs(crect.top - ctm.f), crect.width, crect.height);
21988 createViewForModel: function(cell) {
21992 var type = cell.get('type');
21993 var module = type.split('.')[0];
21994 var entity = type.split('.')[1];
21996 // If there is a special view defined for this model, use that one instead of the default `elementView`/`linkView`.
21997 if (joint.shapes[module] && joint.shapes[module][entity + 'View']) {
21999 view = new joint.shapes[module][entity + 'View']({ model: cell, interactive: this.options.interactive });
22001 } else if (cell instanceof joint.dia.Element) {
22003 view = new this.options.elementView({ model: cell, interactive: this.options.interactive });
22007 view = new this.options.linkView({ model: cell, interactive: this.options.interactive });
22013 addCell: function(cell) {
22015 var view = this.createViewForModel(cell);
22017 V(this.viewport).append(view.el);
22021 // This is the only way to prevent image dragging in Firefox that works.
22022 // Setting -moz-user-select: none, draggable="false" attribute or user-drag: none didn't help.
22023 $(view.el).find('image').on('dragstart', function() { return false; });
22026 resetCells: function(cellsCollection) {
22028 $(this.viewport).empty();
22030 var cells = cellsCollection.models.slice();
22032 // Make sure links are always added AFTER elements.
22033 // They wouldn't find their sources/targets in the DOM otherwise.
22034 cells.sort(function(a, b) { return a instanceof joint.dia.Link ? 1 : -1; });
22036 _.each(cells, this.addCell, this);
22038 // Sort the cells in the DOM manually as we might have changed the order they
22039 // were added to the DOM (see above).
22043 sortCells: function() {
22045 // Run insertion sort algorithm in order to efficiently sort DOM elements according to their
22046 // associated model `z` attribute.
22048 var $cells = $(this.viewport).children('[model-id]');
22049 var cells = this.model.get('cells');
22051 this.sortElements($cells, function(a, b) {
22053 var cellA = cells.get($(a).attr('model-id'));
22054 var cellB = cells.get($(b).attr('model-id'));
22056 return (cellA.get('z') || 0) > (cellB.get('z') || 0) ? 1 : -1;
22060 // Highly inspired by the jquery.sortElements plugin by Padolsey.
22061 // See http://james.padolsey.com/javascript/sorting-elements-with-jquery/.
22062 sortElements: function(elements, comparator) {
22064 var $elements = $(elements);
22066 var placements = $elements.map(function() {
22068 var sortElement = this;
22069 var parentNode = sortElement.parentNode;
22071 // Since the element itself will change position, we have
22072 // to have some way of storing it's original position in
22073 // the DOM. The easiest way is to have a 'flag' node:
22074 var nextSibling = parentNode.insertBefore(
22075 document.createTextNode(''),
22076 sortElement.nextSibling
22079 return function() {
22081 if (parentNode === this) {
22083 "You can't sort elements if any one is a descendant of another."
22087 // Insert before flag:
22088 parentNode.insertBefore(this, nextSibling);
22090 parentNode.removeChild(nextSibling);
22095 return Array.prototype.sort.call($elements, comparator).each(function(i) {
22096 placements[i].call(this);
22100 scale: function(sx, sy, ox, oy) {
22108 // Remove previous transform so that the new scale is not affected by previous scales, especially
22109 // the old translate() does not affect the new translate if an origin is specified.
22110 V(this.viewport).attr('transform', '');
22112 // TODO: V.scale() doesn't support setting scale origin. #Fix
22114 V(this.viewport).translate(-ox * (sx - 1), -oy * (sy - 1));
22117 V(this.viewport).scale(sx, sy);
22119 this.trigger('scale', ox, oy);
22124 rotate: function(deg, ox, oy) {
22126 // If the origin is not set explicitely, rotate around the center. Note that
22127 // we must use the plain bounding box (`this.el.getBBox()` instead of the one that gives us
22128 // the real bounding box (`bbox()`) including transformations).
22129 if (_.isUndefined(ox)) {
22131 var bbox = this.viewport.getBBox();
22133 oy = bbox.height/2;
22136 V(this.viewport).rotate(deg, ox, oy);
22139 // Find the first view climbing up the DOM tree starting at element `el`. Note that `el` can also
22140 // be a selector or a jQuery object.
22141 findView: function(el) {
22143 var $el = this.$(el);
22145 if ($el.length === 0 || $el[0] === this.el) {
22150 if ($el.data('view')) {
22152 return $el.data('view');
22155 return this.findView($el.parent());
22158 // Find a view for a model `cell`. `cell` can also be a string representing a model `id`.
22159 findViewByModel: function(cell) {
22161 var id = _.isString(cell) ? cell : cell.id;
22163 var $view = this.$('[model-id="' + id + '"]');
22164 if ($view.length) {
22166 return $view.data('view');
22171 // Find all views at given point
22172 findViewsFromPoint: function(p) {
22176 var views = _.map(this.model.getElements(), this.findViewByModel);
22178 return _.filter(views, function(view) {
22179 return g.rect(V(view.el).bbox(false, this.viewport)).containsPoint(p);
22183 // Find all views in given area
22184 findViewsInArea: function(r) {
22188 var views = _.map(this.model.getElements(), this.findViewByModel);
22190 return _.filter(views, function(view) {
22191 return r.intersect(g.rect(V(view.el).bbox(false, this.viewport)));
22195 getModelById: function(id) {
22197 return this.model.getCell(id);
22200 snapToGrid: function(p) {
22202 // Convert global coordinates to the local ones of the `viewport`. Otherwise,
22203 // improper transformation would be applied when the viewport gets transformed (scaled/rotated).
22204 var localPoint = V(this.viewport).toLocalPoint(p.x, p.y);
22207 x: g.snapToGrid(localPoint.x, this.options.gridSize),
22208 y: g.snapToGrid(localPoint.y, this.options.gridSize)
22212 getDefaultLink: function(cellView, magnet) {
22214 return _.isFunction(this.options.defaultLink)
22215 // default link is a function producing link model
22216 ? this.options.defaultLink.call(this, cellView, magnet)
22217 // default link is the Backbone model
22218 : this.options.defaultLink.clone();
22224 mousedblclick: function(evt) {
22226 evt.preventDefault();
22227 evt = joint.util.normalizeEvent(evt);
22229 var view = this.findView(evt.target);
22230 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22234 view.pointerdblclick(evt, localPoint.x, localPoint.y);
22238 this.trigger('blank:pointerdblclick', evt, localPoint.x, localPoint.y);
22242 mouseclick: function(evt) {
22244 // Trigger event when mouse not moved.
22245 if (!this._mousemoved) {
22247 evt.preventDefault();
22248 evt = joint.util.normalizeEvent(evt);
22250 var view = this.findView(evt.target);
22251 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22255 view.pointerclick(evt, localPoint.x, localPoint.y);
22259 this.trigger('blank:pointerclick', evt, localPoint.x, localPoint.y);
22263 this._mousemoved = false;
22266 pointerdown: function(evt) {
22268 evt.preventDefault();
22269 evt = joint.util.normalizeEvent(evt);
22271 var view = this.findView(evt.target);
22273 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22277 this.sourceView = view;
22279 view.pointerdown(evt, localPoint.x, localPoint.y);
22283 this.trigger('blank:pointerdown', evt, localPoint.x, localPoint.y);
22287 pointermove: function(evt) {
22289 evt.preventDefault();
22290 evt = joint.util.normalizeEvent(evt);
22292 if (this.sourceView) {
22295 this._mousemoved = true;
22297 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22299 this.sourceView.pointermove(evt, localPoint.x, localPoint.y);
22303 pointerup: function(evt) {
22305 evt = joint.util.normalizeEvent(evt);
22307 var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22309 if (this.sourceView) {
22311 this.sourceView.pointerup(evt, localPoint.x, localPoint.y);
22313 //"delete sourceView" occasionally throws an error in chrome (illegal access exception)
22314 this.sourceView = null;
22318 this.trigger('blank:pointerup', evt, localPoint.x, localPoint.y);
22324 // JointJS library.
22325 // (c) 2011-2013 client IO
22328 if (typeof exports === 'object') {
22331 util: require('../src/core').util,
22334 Element: require('../src/joint.dia.element').Element,
22335 ElementView: require('../src/joint.dia.element').ElementView
22338 var _ = require('lodash');
22342 joint.shapes.basic = {};
22345 joint.shapes.basic.Generic = joint.dia.Element.extend({
22347 defaults: joint.util.deepSupplement({
22349 type: 'basic.Generic',
22351 '.': { fill: '#FFFFFF', stroke: 'none' }
22354 }, joint.dia.Element.prototype.defaults)
22357 joint.shapes.basic.Rect = joint.shapes.basic.Generic.extend({
22359 markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',
22361 defaults: joint.util.deepSupplement({
22363 type: 'basic.Rect',
22365 'rect': { fill: '#FFFFFF', stroke: 'black', width: 100, height: 60 },
22366 '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' }
22369 }, joint.shapes.basic.Generic.prototype.defaults)
22372 joint.shapes.basic.Text = joint.shapes.basic.Generic.extend({
22374 markup: '<g class="rotatable"><g class="scalable"><text/></g></g>',
22376 defaults: joint.util.deepSupplement({
22378 type: 'basic.Text',
22380 'text': { 'font-size': 18, fill: 'black' }
22383 }, joint.shapes.basic.Generic.prototype.defaults)
22386 joint.shapes.basic.Circle = joint.shapes.basic.Generic.extend({
22388 markup: '<g class="rotatable"><g class="scalable"><circle/></g><text/></g>',
22390 defaults: joint.util.deepSupplement({
22392 type: 'basic.Circle',
22393 size: { width: 60, height: 60 },
22395 'circle': { fill: '#FFFFFF', stroke: 'black', r: 30, transform: 'translate(30, 30)' },
22396 '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' }
22398 }, joint.shapes.basic.Generic.prototype.defaults)
22401 joint.shapes.basic.Image = joint.shapes.basic.Generic.extend({
22403 markup: '<g class="rotatable"><g class="scalable"><image/></g><text/></g>',
22405 defaults: joint.util.deepSupplement({
22407 type: 'basic.Image',
22409 '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' }
22411 }, joint.shapes.basic.Generic.prototype.defaults)
22414 joint.shapes.basic.Path = joint.shapes.basic.Generic.extend({
22416 markup: '<g class="rotatable"><g class="scalable"><path/></g><text/></g>',
22418 defaults: joint.util.deepSupplement({
22420 type: 'basic.Path',
22421 size: { width: 60, height: 60 },
22423 'path': { fill: '#FFFFFF', stroke: 'black' },
22424 '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' }
22426 }, joint.shapes.basic.Generic.prototype.defaults)
22429 // PortsModelInterface is a common interface for shapes that have ports. This interface makes it easy
22430 // to create new shapes with ports functionality. It is assumed that the new shapes have
22431 // `inPorts` and `outPorts` array properties. Only these properties should be used to set ports.
22432 // In other words, using this interface, it is no longer recommended to set ports directly through the
22436 // joint.shapes.custom.MyElementWithPorts = joint.shapes.basic.Path.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
22437 // getPortAttrs: function(portName, index, total, selector, type) {
22439 // var portClass = 'port' + index;
22440 // var portSelector = selector + '>.' + portClass;
22441 // var portTextSelector = portSelector + '>text';
22442 // var portCircleSelector = portSelector + '>circle';
22444 // attrs[portTextSelector] = { text: portName };
22445 // attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
22446 // attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
22448 // if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
22453 joint.shapes.basic.PortsModelInterface = {
22455 initialize: function() {
22457 this.updatePortsAttrs();
22458 this.on('change:inPorts change:outPorts', this.updatePortsAttrs, this);
22460 // Call the `initialize()` of the parent.
22461 this.constructor.__super__.constructor.__super__.initialize.apply(this, arguments);
22464 updatePortsAttrs: function(eventName) {
22466 // Delete previously set attributes for ports.
22467 var currAttrs = this.get('attrs');
22468 _.each(this._portSelectors, function(selector) {
22469 if (currAttrs[selector]) delete currAttrs[selector];
22472 // This holds keys to the `attrs` object for all the port specific attribute that
22473 // we set in this method. This is necessary in order to remove previously set
22474 // attributes for previous ports.
22475 this._portSelectors = [];
22479 _.each(this.get('inPorts'), function(portName, index, ports) {
22480 var portAttributes = this.getPortAttrs(portName, index, ports.length, '.inPorts', 'in');
22481 this._portSelectors = this._portSelectors.concat(_.keys(portAttributes));
22482 _.extend(attrs, portAttributes);
22485 _.each(this.get('outPorts'), function(portName, index, ports) {
22486 var portAttributes = this.getPortAttrs(portName, index, ports.length, '.outPorts', 'out');
22487 this._portSelectors = this._portSelectors.concat(_.keys(portAttributes));
22488 _.extend(attrs, portAttributes);
22491 // Silently set `attrs` on the cell so that noone knows the attrs have changed. This makes sure
22492 // that, for example, command manager does not register `change:attrs` command but only
22493 // the important `change:inPorts`/`change:outPorts` command.
22494 this.attr(attrs, { silent: true });
22495 // Manually call the `processPorts()` method that is normally called on `change:attrs` (that we just made silent).
22496 this.processPorts();
22497 // Let the outside world (mainly the `ModelView`) know that we're done configuring the `attrs` object.
22498 this.trigger('process:ports');
22501 getPortSelector: function(name) {
22503 var selector = '.inPorts';
22504 var index = this.get('inPorts').indexOf(name);
22507 selector = '.outPorts';
22508 index = this.get('outPorts').indexOf(name);
22510 if (index < 0) throw new Error("getPortSelector(): Port doesn't exist.");
22513 return selector + '>g:nth-child(' + (index + 1) + ')>circle';
22517 joint.shapes.basic.PortsViewInterface = {
22519 initialize: function() {
22521 // `Model` emits the `process:ports` whenever it's done configuring the `attrs` object for ports.
22522 this.listenTo(this.model, 'process:ports', this.update);
22524 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
22527 update: function() {
22529 // First render ports so that `attrs` can be applied to those newly created DOM elements
22530 // in `ElementView.prototype.update()`.
22531 this.renderPorts();
22532 joint.dia.ElementView.prototype.update.apply(this, arguments);
22535 renderPorts: function() {
22537 var $inPorts = this.$('.inPorts').empty();
22538 var $outPorts = this.$('.outPorts').empty();
22540 var portTemplate = _.template(this.model.portMarkup);
22542 _.each(_.filter(this.model.ports, function(p) { return p.type === 'in' }), function(port, index) {
22544 $inPorts.append(V(portTemplate({ id: index, port: port })).node);
22546 _.each(_.filter(this.model.ports, function(p) { return p.type === 'out' }), function(port, index) {
22548 $outPorts.append(V(portTemplate({ id: index, port: port })).node);
22553 joint.shapes.basic.TextBlock = joint.shapes.basic.Generic.extend({
22555 markup: ['<g class="rotatable"><g class="scalable"><rect/></g><switch>',
22557 // if foreignObject supported
22559 '<foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" class="fobj">',
22560 '<body xmlns="http://www.w3.org/1999/xhtml"><div/></body>',
22561 '</foreignObject>',
22563 // else foreignObject is not supported (fallback for IE)
22564 '<text class="content"/>',
22566 '</switch></g>'].join(''),
22568 defaults: joint.util.deepSupplement({
22570 type: 'basic.TextBlock',
22572 // see joint.css for more element styles
22583 'font-family': 'Arial, helvetica, sans-serif'
22590 'y-alignment': 'middle',
22591 'x-alignment': 'middle'
22597 }, joint.shapes.basic.Generic.prototype.defaults),
22599 initialize: function() {
22601 if (typeof SVGForeignObjectElement !== 'undefined') {
22603 // foreignObject supported
22604 this.setForeignObjectSize(this, this.get('size'));
22605 this.setDivContent(this, this.get('content'));
22606 this.listenTo(this, 'change:size', this.setForeignObjectSize);
22607 this.listenTo(this, 'change:content', this.setDivContent);
22611 joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
22614 setForeignObjectSize: function(cell, size) {
22616 // Selector `foreignObject' doesn't work accross all browsers, we'r using class selector instead.
22617 // We have to clone size as we don't want attributes.div.style to be same object as attributes.size.
22619 '.fobj': _.clone(size),
22620 div: { style: _.clone(size) }
22624 setDivContent: function(cell, content) {
22626 // Append the content to div as html.
22627 cell.attr({ div : {
22634 // TextBlockView implements the fallback for IE when no foreignObject exists and
22635 // the text needs to be manually broken.
22636 joint.shapes.basic.TextBlockView = joint.dia.ElementView.extend({
22638 initialize: function() {
22640 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
22642 if (typeof SVGForeignObjectElement === 'undefined') {
22644 this.noSVGForeignObjectElement = true;
22646 this.listenTo(this.model, 'change:content', function(cell) {
22647 // avoiding pass of extra paramters
22648 this.updateContent(cell);
22653 update: function(cell, renderingOnlyAttrs) {
22655 if (this.noSVGForeignObjectElement) {
22657 var model = this.model;
22659 // Update everything but the content first.
22660 var noTextAttrs = _.omit(renderingOnlyAttrs || model.get('attrs'), '.content');
22661 joint.dia.ElementView.prototype.update.call(this, model, noTextAttrs);
22663 if (!renderingOnlyAttrs || _.has(renderingOnlyAttrs, '.content')) {
22664 // Update the content itself.
22665 this.updateContent(model, renderingOnlyAttrs);
22670 joint.dia.ElementView.prototype.update.call(this, model, renderingOnlyAttrs);
22674 updateContent: function(cell, renderingOnlyAttrs) {
22676 // Create copy of the text attributes
22677 var textAttrs = _.merge({}, (renderingOnlyAttrs || cell.get('attrs'))['.content']);
22679 delete textAttrs.text;
22681 // Break the content to fit the element size taking into account the attributes
22682 // set on the model.
22683 var text = joint.util.breakText(cell.get('content'), cell.get('size'), textAttrs, {
22684 // measuring sandbox svg document
22685 svgDocument: this.paper.svg
22688 // Create a new attrs with same structure as the model attrs { text: { *textAttributes* }}
22689 var attrs = joint.util.setByPath({}, '.content', textAttrs,'/');
22691 // Replace text attribute with the one we just processed.
22692 attrs['.content'].text = text;
22694 // Update the view using renderingOnlyAttributes parameter.
22695 joint.dia.ElementView.prototype.update.call(this, cell, attrs);
22699 if (typeof exports === 'object') {
22701 module.exports = joint.shapes.basic;
22704 joint.routers.orthogonal = function() {
22706 var sourceBBox, targetBBox;
22708 // Return the direction that one would have to take traveling from `p1` to `p2`.
22709 // This function assumes the line between `p1` and `p2` is orthogonal.
22710 function direction(p1, p2) {
22712 if (p1.y < p2.y && p1.x === p2.x) {
22714 } else if (p1.y > p2.y && p1.x === p2.x) {
22716 } else if (p1.x < p2.x && p1.y === p2.y) {
22722 function bestDirection(p1, p2, preferredDirection) {
22726 // This branching determines possible directions that one can take to travel
22727 // from `p1` to `p2`.
22730 if (p1.y > p2.y) { directions = ['up', 'right']; }
22731 else if (p1.y < p2.y) { directions = ['down', 'right']; }
22732 else { directions = ['right']; }
22734 } else if (p1.x > p2.x) {
22736 if (p1.y > p2.y) { directions = ['up', 'left']; }
22737 else if (p1.y < p2.y) { directions = ['down', 'left']; }
22738 else { directions = ['left']; }
22742 if (p1.y > p2.y) { directions = ['up']; }
22743 else { directions = ['down']; }
22746 if (_.contains(directions, preferredDirection)) {
22747 return preferredDirection;
22750 var direction = _.first(directions);
22752 // Should the direction be the exact opposite of the preferred direction,
22753 // try another one if such direction exists.
22754 switch (preferredDirection) {
22755 case 'down': if (direction === 'up') return _.last(directions); break;
22756 case 'up': if (direction === 'down') return _.last(directions); break;
22757 case 'left': if (direction === 'right') return _.last(directions); break;
22758 case 'right': if (direction === 'left') return _.last(directions); break;
22763 // Find a vertex in between the vertices `p1` and `p2` so that the route between those vertices
22764 // is orthogonal. Prefer going the direction determined by `preferredDirection`.
22765 function findMiddleVertex(p1, p2, preferredDirection) {
22767 var direction = bestDirection(p1, p2, preferredDirection);
22768 if (direction === 'down' || direction === 'up') {
22769 return { x: p1.x, y: p2.y, d: direction };
22771 return { x: p2.x, y: p1.y, d: direction };
22774 // Return points that one needs to draw a connection through in order to have a orthogonal link
22775 // routing from source to target going through `vertices`.
22776 function findOrthogonalRoute(vertices) {
22778 vertices = (vertices || []).slice();
22779 var orthogonalVertices = [];
22781 var sourceCenter = sourceBBox.center();
22782 var targetCenter = targetBBox.center();
22784 if (!vertices.length) {
22786 if (Math.abs(sourceCenter.x - targetCenter.x) < (sourceBBox.width / 2) ||
22787 Math.abs(sourceCenter.y - targetCenter.y) < (sourceBBox.height / 2)
22791 x: Math.min(sourceCenter.x, targetCenter.x) +
22792 Math.abs(sourceCenter.x - targetCenter.x) / 2,
22793 y: Math.min(sourceCenter.y, targetCenter.y) +
22794 Math.abs(sourceCenter.y - targetCenter.y) / 2
22799 vertices.unshift(sourceCenter);
22800 vertices.push(targetCenter);
22802 var orthogonalVertex;
22803 var lastOrthogonalVertex;
22807 // For all the pairs of link model vertices...
22808 for (var i = 0; i < vertices.length - 1; i++) {
22810 vertex = vertices[i];
22811 nextVertex = vertices[i + 1];
22812 lastOrthogonalVertex = _.last(orthogonalVertices);
22815 // Push all the link vertices to the orthogonal route.
22816 orthogonalVertex = vertex;
22817 // Determine a direction between the last vertex and the new one.
22818 // Therefore, each vertex contains the `d` property describing the direction that one
22819 // would have to take to travel to that vertex.
22820 orthogonalVertex.d = lastOrthogonalVertex
22821 ? direction(lastOrthogonalVertex, vertex)
22824 orthogonalVertices.push(orthogonalVertex);
22825 lastOrthogonalVertex = orthogonalVertex;
22828 // Make sure that we don't create a vertex that would go the opposite direction then
22829 // that of the previous one.
22830 // Othwerwise, a 'spike' segment would be created which is not desirable.
22831 // Find a dummy vertex to keep the link orthogonal. Preferably, take the same direction
22832 // as the previous one.
22833 var d = lastOrthogonalVertex && lastOrthogonalVertex.d;
22834 orthogonalVertex = findMiddleVertex(vertex, nextVertex, d);
22836 // Do not add a new vertex that is the same as one of the vertices already added.
22837 if (!g.point(orthogonalVertex).equals(g.point(vertex)) &&
22838 !g.point(orthogonalVertex).equals(g.point(nextVertex))) {
22840 orthogonalVertices.push(orthogonalVertex);
22843 return orthogonalVertices;
22846 return function(vertices) {
22848 sourceBBox = this.sourceBBox;
22849 targetBBox = this.targetBBox;
22851 return findOrthogonalRoute(vertices);
22856 joint.routers.manhattan = (function() {
22862 // size of the step to find a route
22865 // use of the perpendicular linkView option to connect center of element with first vertex
22866 perpendicular: true,
22868 // tells how to divide the paper when creating the elements map
22871 // should be source or target not to be consider as an obstacle
22872 excludeEnds: [], // 'source', 'target'
22874 // should be any element with a certain type not to be consider as an obstacle
22875 excludeTypes: ['basic.Text'],
22877 // if number of route finding loops exceed the maximum, stops searching and returns
22881 // possible starting directions from an element
22882 startDirections: ['left','right','top','bottom'],
22884 // possible ending directions to an element
22885 endDirections: ['left','right','top','bottom'],
22887 // specify directions above
22889 right: { x: 1, y: 0 },
22890 bottom: { x: 0, y: 1 },
22891 left: { x: -1, y: 0 },
22892 top: { x: 0, y: -1 }
22895 // maximum change of the direction
22896 maxAllowedDirectionChange: 1,
22898 // padding applied on the element bounding boxes
22899 paddingBox: function() {
22901 var step = this.step;
22911 // an array of directions to find next points on the route
22912 directions: function() {
22914 var step = this.step;
22917 { offsetX: step , offsetY: 0 , cost: step },
22918 { offsetX: 0 , offsetY: step , cost: step },
22919 { offsetX: -step , offsetY: 0 , cost: step },
22920 { offsetX: 0 , offsetY: -step , cost: step }
22924 // a penalty received for direction change
22925 penalties: function() {
22927 return [0, this.step / 2, this.step];
22930 // heurestic method to determine the distance between two points
22931 estimateCost: function(from, to) {
22933 return from.manhattanDistance(to);
22936 // a simple route used in situations, when main routing method fails
22937 // (exceed loops, inaccessible).
22938 fallbackRoute: function(from, to, opts) {
22940 // Find an orthogonal route ignoring obstacles.
22942 var prevDirIndexes = opts.prevDirIndexes || {};
22944 var point = (prevDirIndexes[from] || 0) % 2
22945 ? g.point(from.x, to.y)
22946 : g.point(to.x, from.y);
22948 return [point, to];
22951 // if a function is provided, it's used to route the link while dragging an end
22952 // i.e. function(from, to, opts) { return []; }
22953 draggingRoute: null
22956 // reconstructs a route by concating points with their parents
22957 function reconstructRoute(parents, point) {
22960 var prevDiff = { x: 0, y: 0 };
22961 var current = point;
22964 while ((parent = parents[current])) {
22966 var diff = parent.difference(current);
22968 if (!diff.equals(prevDiff)) {
22970 route.unshift(current);
22977 route.unshift(current);
22982 // find points around the rectangle taking given directions in the account
22983 function getRectPoints(bbox, directionList, opts) {
22985 var step = opts.step;
22987 var center = bbox.center();
22989 var startPoints = _.chain(opts.directionMap).pick(directionList).map(function(direction) {
22991 var x = direction.x * bbox.width / 2;
22992 var y = direction.y * bbox.height / 2;
22994 var point = g.point(center).offset(x,y).snapToGrid(step);
22996 if (bbox.containsPoint(point)) {
22998 point.offset(direction.x * step, direction.y * step);
23005 return startPoints;
23008 // returns a direction index from start point to end point
23009 function getDirection(start, end, dirLen) {
23011 var dirAngle = 360 / dirLen;
23013 var q = Math.floor(start.theta(end) / dirAngle);
23018 // finds the route between to points/rectangles implementing A* alghoritm
23019 function findRoute(start, end, map, opt) {
23021 var startDirections = opt.reversed ? opt.endDirections : opt.startDirections;
23022 var endDirections = opt.reversed ? opt.startDirections : opt.endDirections;
23024 // set of points we start pathfinding from
23025 var startSet = start instanceof g.rect
23026 ? getRectPoints(start, startDirections, opt)
23029 // set of points we want the pathfinding to finish at
23030 var endSet = end instanceof g.rect
23031 ? getRectPoints(end, endDirections, opt)
23034 var startCenter = startSet.length > 1 ? start.center() : startSet[0];
23035 var endCenter = endSet.length > 1 ? end.center() : endSet[0];
23037 // take into account only accessible end points
23038 var endPoints = _.filter(endSet, function(point) {
23040 var mapKey = g.point(point).snapToGrid(opt.mapGridSize).toString();
23042 var accesible = _.every(map[mapKey], function(obstacle) {
23043 return !obstacle.containsPoint(point);
23050 if (endPoints.length) {
23052 var step = opt.step;
23053 var penalties = opt.penalties;
23055 // choose the end point with the shortest estimated path cost
23056 var endPoint = _.chain(endPoints).invoke('snapToGrid', step).min(function(point) {
23058 return opt.estimateCost(startCenter, point);
23063 var costFromStart = {};
23064 var totalCost = {};
23067 var dirs = opt.directions;
23068 var dirLen = dirs.length;
23069 var dirHalfLen = dirLen / 2;
23070 var dirIndexes = opt.previousDirIndexes || {};
23072 // The set of point already evaluated.
23073 var closeHash = {}; // keeps only information whether a point was evaluated'
23075 // The set of tentative points to be evaluated, initially containing the start points
23076 var openHash = {}; // keeps only information whether a point is to be evaluated'
23077 var openSet = _.chain(startSet).invoke('snapToGrid', step).each(function(point) {
23079 var key = point.toString();
23081 costFromStart[key] = 0; // Cost from start along best known path.
23082 totalCost[key] = opt.estimateCost(point, endPoint);
23083 dirIndexes[key] = dirIndexes[key] || getDirection(startCenter, point, dirLen);
23084 openHash[key] = true;
23086 }).map(function(point) {
23088 return point.toString();
23090 }).sortBy(function(pointKey) {
23092 return totalCost[pointKey];
23096 var loopCounter = opt.maximumLoops;
23098 var maxAllowedDirectionChange = opt.maxAllowedDirectionChange;
23100 // main route finding loop
23101 while (openSet.length && loopCounter--) {
23103 var currentKey = openSet[0];
23104 var currentPoint = g.point(currentKey);
23106 if (endPoint.equals(currentPoint)) {
23108 opt.previousDirIndexes = _.pick(dirIndexes, currentKey);
23109 return reconstructRoute(parents, currentPoint);
23112 // remove current from the open list
23113 openSet.splice(0, 1);
23114 openHash[neighborKey] = null;
23116 // add current to the close list
23117 closeHash[neighborKey] = true;
23119 var currentDirIndex = dirIndexes[currentKey];
23120 var currentDist = costFromStart[currentKey];
23122 for (var dirIndex = 0; dirIndex < dirLen; dirIndex++) {
23124 var dirChange = Math.abs(dirIndex - currentDirIndex);
23126 if (dirChange > dirHalfLen) {
23128 dirChange = dirLen - dirChange;
23131 // if the direction changed rapidly don't use this point
23132 if (dirChange > maxAllowedDirectionChange) {
23137 var dir = dirs[dirIndex];
23139 var neighborPoint = g.point(currentPoint).offset(dir.offsetX, dir.offsetY);
23140 var neighborKey = neighborPoint.toString();
23142 if (closeHash[neighborKey]) {
23147 // is point accesible - no obstacle in the way
23149 var mapKey = g.point(neighborPoint).snapToGrid(opt.mapGridSize).toString();
23151 var isAccesible = _.every(map[mapKey], function(obstacle) {
23152 return !obstacle.containsPoint(neighborPoint);
23155 if (!isAccesible) {
23160 var inOpenSet = _.has(openHash, neighborKey);
23162 var costToNeighbor = currentDist + dir.cost;
23164 if (!inOpenSet || costToNeighbor < costFromStart[neighborKey]) {
23166 parents[neighborKey] = currentPoint;
23167 dirIndexes[neighborKey] = dirIndex;
23168 costFromStart[neighborKey] = costToNeighbor;
23170 totalCost[neighborKey] = costToNeighbor +
23171 opt.estimateCost(neighborPoint, endPoint) +
23172 penalties[dirChange];
23176 var openIndex = _.sortedIndex(openSet, neighborKey, function(openKey) {
23178 return totalCost[openKey];
23181 openSet.splice(openIndex, 0, neighborKey);
23182 openHash[neighborKey] = true;
23189 // no route found ('to' point wasn't either accessible or finding route took
23190 // way to much calculations)
23191 return opt.fallbackRoute(startCenter, endCenter, opt);
23194 // initiation of the route finding
23195 function router(oldVertices, opt) {
23197 // resolve some of the options
23198 opt.directions = _.result(opt, 'directions');
23199 opt.penalties = _.result(opt, 'penalties');
23200 opt.paddingBox = _.result(opt, 'paddingBox');
23202 // enable/disable linkView perpendicular option
23203 this.options.perpendicular = !!opt.perpendicular;
23205 // As route changes its shape rapidly when we start finding route from different point
23206 // it's necessary to start from the element that was not interacted with
23207 // (the position was changed) at very last.
23208 var reverseRouting = opt.reversed = (this.lastEndChange === 'source');
23210 var sourceBBox = reverseRouting ? g.rect(this.targetBBox) : g.rect(this.sourceBBox);
23211 var targetBBox = reverseRouting ? g.rect(this.sourceBBox) : g.rect(this.targetBBox);
23213 // expand boxes by specific padding
23214 sourceBBox.moveAndExpand(opt.paddingBox);
23215 targetBBox.moveAndExpand(opt.paddingBox);
23217 // building an elements map
23219 var link = this.model;
23220 var graph = this.paper.model;
23222 // source or target element could be excluded from set of obstacles
23223 var excludedEnds = _.chain(opt.excludeEnds)
23224 .map(link.get, link)
23226 .map(graph.getCell, graph).value();
23228 var mapGridSize = opt.mapGridSize;
23230 // builds a map of all elements for quicker obstacle queries (i.e. is a point contained
23231 // in any obstacle?) (a simplified grid search)
23232 // The paper is divided to smaller cells, where each of them holds an information which
23233 // elements belong to it. When we query whether a point is in an obstacle we don't need
23234 // to go through all obstacles, we check only those in a particular cell.
23235 var map = _.chain(graph.getElements())
23236 // remove source and target element if required
23237 .difference(excludedEnds)
23238 // remove all elements whose type is listed in excludedTypes array
23239 .reject(function(element) {
23240 return _.contains(opt.excludeTypes, element.get('type'));
23242 // change elements (models) to their bounding boxes
23244 // expand their boxes by specific padding
23245 .invoke('moveAndExpand', opt.paddingBox)
23247 .foldl(function(res, bbox) {
23249 var origin = bbox.origin().snapToGrid(mapGridSize);
23250 var corner = bbox.corner().snapToGrid(mapGridSize);
23252 for (var x = origin.x; x <= corner.x; x += mapGridSize) {
23253 for (var y = origin.y; y <= corner.y; y += mapGridSize) {
23255 var gridKey = x + '@' + y;
23257 res[gridKey] = res[gridKey] || [];
23258 res[gridKey].push(bbox);
23268 var newVertices = [];
23270 var points = _.map(oldVertices, g.point);
23272 var tailPoint = sourceBBox.center();
23274 // find a route by concating all partial routes (routes need to go through the vertices)
23275 // startElement -> vertex[1] -> ... -> vertex[n] -> endElement
23276 for (var i = 0, len = points.length; i <= len; i++) {
23278 var partialRoute = null;
23280 var from = to || sourceBBox;
23281 var to = points[i];
23287 // 'to' is not a vertex. If the target is a point (i.e. it's not an element), we
23288 // might use dragging route instead of main routing method if that is enabled.
23289 var endingAtPoint = !this.model.get('source').id || !this.model.get('target').id;
23291 if (endingAtPoint && _.isFunction(opt.draggingRoute)) {
23292 // Make sure we passing points only (not rects).
23293 var dragFrom = from instanceof g.rect ? from.center() : from;
23294 partialRoute = opt.draggingRoute(dragFrom, to.origin(), opt);
23298 // if partial route has not been calculated yet use the main routing method to find one
23299 partialRoute = partialRoute || findRoute(from, to, map, opt);
23301 var leadPoint = _.first(partialRoute);
23303 if (leadPoint && leadPoint.equals(tailPoint)) {
23305 // remove the first point if the previous partial route had the same point as last
23306 partialRoute.shift();
23309 tailPoint = _.last(partialRoute) || tailPoint;
23311 newVertices = newVertices.concat(partialRoute);
23314 // we might have to reverse the result if we swapped source and target at the beginning
23315 return reverseRouting ? newVertices.reverse() : newVertices;
23319 return function(vertices, opt, linkView) {
23321 return router.call(linkView, vertices, _.extend({}, config, opt));
23326 joint.routers.metro = (function() {
23328 if (!_.isFunction(joint.routers.manhattan)) {
23330 throw('Metro requires the manhattan router.');
23335 // cost of a diagonal step (calculated if not defined).
23336 diagonalCost: null,
23338 // an array of directions to find next points on the route
23339 directions: function() {
23341 var step = this.step;
23342 var diagonalCost = this.diagonalCost || Math.ceil(Math.sqrt(step * step << 1));
23345 { offsetX: step , offsetY: 0 , cost: step },
23346 { offsetX: step , offsetY: step , cost: diagonalCost },
23347 { offsetX: 0 , offsetY: step , cost: step },
23348 { offsetX: -step , offsetY: step , cost: diagonalCost },
23349 { offsetX: -step , offsetY: 0 , cost: step },
23350 { offsetX: -step , offsetY: -step , cost: diagonalCost },
23351 { offsetX: 0 , offsetY: -step , cost: step },
23352 { offsetX: step , offsetY: -step , cost: diagonalCost }
23356 // a simple route used in situations, when main routing method fails
23357 // (exceed loops, inaccessible).
23358 fallbackRoute: function(from, to, opts) {
23360 // Find a route which breaks by 45 degrees ignoring all obstacles.
23362 var theta = from.theta(to);
23364 var a = { x: to.x, y: from.y };
23365 var b = { x: from.x, y: to.y };
23367 if (theta % 180 > 90) {
23373 var p1 = (theta % 90) < 45 ? a : b;
23375 var l1 = g.line(from, p1);
23377 var alpha = 90 * Math.ceil(theta / 90);
23379 var p2 = g.point.fromPolar(l1.squaredLength(), g.toRad(alpha + 135), p1);
23381 var l2 = g.line(to, p2);
23383 var point = l1.intersection(l2);
23385 return point ? [point.round(), to] : [to];
23390 return function(vertices, opts, linkView) {
23392 return joint.routers.manhattan(vertices, _.extend({}, config, opts), linkView);
23397 joint.connectors.normal = function(sourcePoint, targetPoint, vertices) {
23399 // Construct the `d` attribute of the `<path>` element.
23400 var d = ['M', sourcePoint.x, sourcePoint.y];
23402 _.each(vertices, function(vertex) {
23404 d.push(vertex.x, vertex.y);
23407 d.push(targetPoint.x, targetPoint.y);
23409 return d.join(' ');
23412 joint.connectors.rounded = function(sourcePoint, targetPoint, vertices, opts) {
23414 var offset = opts.radius || 10;
23416 var c1, c2, d1, d2, prev, next;
23418 // Construct the `d` attribute of the `<path>` element.
23419 var d = ['M', sourcePoint.x, sourcePoint.y];
23421 _.each(vertices, function(vertex, index) {
23423 // the closest vertices
23424 prev = vertices[index-1] || sourcePoint;
23425 next = vertices[index+1] || targetPoint;
23427 // a half distance to the closest vertex
23428 d1 = d2 || g.point(vertex).distance(prev) / 2;
23429 d2 = g.point(vertex).distance(next) / 2;
23432 c1 = g.point(vertex).move(prev, -Math.min(offset, d1)).round();
23433 c2 = g.point(vertex).move(next, -Math.min(offset, d2)).round();
23435 d.push(c1.x, c1.y, 'S', vertex.x, vertex.y, c2.x, c2.y, 'L');
23438 d.push(targetPoint.x, targetPoint.y);
23440 return d.join(' ');
23443 joint.connectors.smooth = function(sourcePoint, targetPoint, vertices) {
23447 if (vertices.length) {
23449 d = g.bezier.curveThroughPoints([sourcePoint].concat(vertices).concat([targetPoint]));
23452 // if we have no vertices use a default cubic bezier curve, cubic bezier requires
23453 // two control points. The two control points are both defined with X as mid way
23454 // between the source and target points. SourceControlPoint Y is equal to sourcePoint Y
23455 // and targetControlPointY being equal to targetPointY. Handle situation were
23456 // sourcePointX is greater or less then targetPointX.
23457 var controlPointX = (sourcePoint.x < targetPoint.x)
23458 ? targetPoint.x - ((targetPoint.x - sourcePoint.x) / 2)
23459 : sourcePoint.x - ((sourcePoint.x - targetPoint.x) / 2);
23462 'M', sourcePoint.x, sourcePoint.y,
23463 'C', controlPointX, sourcePoint.y, controlPointX, targetPoint.y,
23464 targetPoint.x, targetPoint.y
23468 return d.join(' ');
23471 if (typeof exports === 'object') {
23474 util: require('../src/core').util,
23477 Element: require('../src/joint.dia.element').Element,
23478 Link: require('../src/joint.dia.link').Link
23484 joint.shapes.erd = {};
23486 joint.shapes.erd.Entity = joint.dia.Element.extend({
23488 markup: '<g class="rotatable"><g class="scalable"><polygon class="outer"/><polygon class="inner"/></g><text/></g>',
23490 defaults: joint.util.deepSupplement({
23492 type: 'erd.Entity',
23493 size: { width: 150, height: 60 },
23496 fill: '#2ECC71', stroke: '#27AE60', 'stroke-width': 2,
23497 points: '100,0 100,60 0,60 0,0'
23500 fill: '#2ECC71', stroke: '#27AE60', 'stroke-width': 2,
23501 points: '95,5 95,55 5,55 5,5',
23506 'font-family': 'Arial', 'font-size': 14,
23507 ref: '.outer', 'ref-x': .5, 'ref-y': .5,
23508 'x-alignment': 'middle', 'y-alignment': 'middle'
23512 }, joint.dia.Element.prototype.defaults)
23515 joint.shapes.erd.WeakEntity = joint.shapes.erd.Entity.extend({
23517 defaults: joint.util.deepSupplement({
23519 type: 'erd.WeakEntity',
23522 '.inner' : { display: 'auto' },
23523 text: { text: 'Weak Entity' }
23526 }, joint.shapes.erd.Entity.prototype.defaults)
23529 joint.shapes.erd.Relationship = joint.dia.Element.extend({
23531 markup: '<g class="rotatable"><g class="scalable"><polygon class="outer"/><polygon class="inner"/></g><text/></g>',
23533 defaults: joint.util.deepSupplement({
23535 type: 'erd.Relationship',
23536 size: { width: 80, height: 80 },
23539 fill: '#3498DB', stroke: '#2980B9', 'stroke-width': 2,
23540 points: '40,0 80,40 40,80 0,40'
23543 fill: '#3498DB', stroke: '#2980B9', 'stroke-width': 2,
23544 points: '40,5 75,40 40,75 5,40',
23548 text: 'Relationship',
23549 'font-family': 'Arial', 'font-size': 12,
23550 ref: '.', 'ref-x': .5, 'ref-y': .5,
23551 'x-alignment': 'middle', 'y-alignment': 'middle'
23555 }, joint.dia.Element.prototype.defaults)
23558 joint.shapes.erd.IdentifyingRelationship = joint.shapes.erd.Relationship.extend({
23560 defaults: joint.util.deepSupplement({
23562 type: 'erd.IdentifyingRelationship',
23565 '.inner': { display: 'auto' },
23566 text: { text: 'Identifying' }
23569 }, joint.shapes.erd.Relationship.prototype.defaults)
23572 joint.shapes.erd.Attribute = joint.dia.Element.extend({
23574 markup: '<g class="rotatable"><g class="scalable"><ellipse class="outer"/><ellipse class="inner"/></g><text/></g>',
23576 defaults: joint.util.deepSupplement({
23578 type: 'erd.Attribute',
23579 size: { width: 100, height: 50 },
23582 transform: 'translate(50, 25)'
23585 stroke: '#D35400', 'stroke-width': 2,
23586 cx: 0, cy: 0, rx: 50, ry: 25,
23590 stroke: '#D35400', 'stroke-width': 2,
23591 cx: 0, cy: 0, rx: 45, ry: 20,
23592 fill: 'transparent', display: 'none'
23595 'font-family': 'Arial', 'font-size': 14,
23596 ref: '.', 'ref-x': .5, 'ref-y': .5,
23597 'x-alignment': 'middle', 'y-alignment': 'middle'
23601 }, joint.dia.Element.prototype.defaults)
23605 joint.shapes.erd.Multivalued = joint.shapes.erd.Attribute.extend({
23607 defaults: joint.util.deepSupplement({
23609 type: 'erd.Multivalued',
23612 '.inner': { display: 'block' },
23613 text: { text: 'multivalued' }
23615 }, joint.shapes.erd.Attribute.prototype.defaults)
23618 joint.shapes.erd.Derived = joint.shapes.erd.Attribute.extend({
23620 defaults: joint.util.deepSupplement({
23622 type: 'erd.Derived',
23625 '.outer': { 'stroke-dasharray': '3,5' },
23626 text: { text: 'derived' }
23629 }, joint.shapes.erd.Attribute.prototype.defaults)
23632 joint.shapes.erd.Key = joint.shapes.erd.Attribute.extend({
23634 defaults: joint.util.deepSupplement({
23639 ellipse: { 'stroke-width': 4 },
23640 text: { text: 'key', 'font-weight': 'bold', 'text-decoration': 'underline' }
23642 }, joint.shapes.erd.Attribute.prototype.defaults)
23645 joint.shapes.erd.Normal = joint.shapes.erd.Attribute.extend({
23647 defaults: joint.util.deepSupplement({
23649 type: 'erd.Normal',
23651 attrs: { text: { text: 'Normal' }}
23653 }, joint.shapes.erd.Attribute.prototype.defaults)
23656 joint.shapes.erd.ISA = joint.dia.Element.extend({
23658 markup: '<g class="rotatable"><g class="scalable"><polygon/></g><text/></g>',
23660 defaults: joint.util.deepSupplement({
23663 size: { width: 100, height: 50 },
23666 points: '0,0 50,50 100,0',
23667 fill: '#F1C40F', stroke: '#F39C12', 'stroke-width': 2
23671 ref: '.', 'ref-x': .5, 'ref-y': .3,
23672 'x-alignment': 'middle', 'y-alignment': 'middle'
23676 }, joint.dia.Element.prototype.defaults)
23680 joint.shapes.erd.Line = joint.dia.Link.extend({
23682 defaults: { type: "erd.Line" },
23684 cardinality: function(value) {
23685 this.set('labels', [{ position: -20, attrs: { text: { dy: -8, text: value }}}]);
23689 if (typeof exports === 'object') {
23691 module.exports = joint.shapes.erd;
23694 if (typeof exports === 'object') {
23697 util: require('../src/core').util,
23699 basic: require('./joint.shapes.basic')
23702 Element: require('../src/joint.dia.element').Element,
23703 Link: require('../src/joint.dia.link').Link
23708 joint.shapes.fsa = {};
23710 joint.shapes.fsa.State = joint.shapes.basic.Circle.extend({
23711 defaults: joint.util.deepSupplement({
23714 circle: { 'stroke-width': 3 },
23715 text: { 'font-weight': 'bold' }
23717 }, joint.shapes.basic.Circle.prototype.defaults)
23720 joint.shapes.fsa.StartState = joint.dia.Element.extend({
23722 markup: '<g class="rotatable"><g class="scalable"><circle/></g></g>',
23724 defaults: joint.util.deepSupplement({
23726 type: 'fsa.StartState',
23727 size: { width: 20, height: 20 },
23730 transform: 'translate(10, 10)',
23736 }, joint.dia.Element.prototype.defaults)
23739 joint.shapes.fsa.EndState = joint.dia.Element.extend({
23741 markup: '<g class="rotatable"><g class="scalable"><circle class="outer"/><circle class="inner"/></g></g>',
23743 defaults: joint.util.deepSupplement({
23745 type: 'fsa.EndState',
23746 size: { width: 20, height: 20 },
23749 transform: 'translate(10, 10)',
23756 transform: 'translate(10, 10)',
23762 }, joint.dia.Element.prototype.defaults)
23765 joint.shapes.fsa.Arrow = joint.dia.Link.extend({
23767 defaults: joint.util.deepSupplement({
23769 attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' }},
23771 }, joint.dia.Link.prototype.defaults)
23774 if (typeof exports === 'object') {
23776 module.exports = joint.shapes.fsa;
23779 if (typeof exports === 'object') {
23782 util: require('../src/core').util,
23785 Element: require('../src/joint.dia.element').Element,
23786 Link: require('../src/joint.dia.link').Link
23791 joint.shapes.org = {};
23793 joint.shapes.org.Member = joint.dia.Element.extend({
23795 markup: '<g class="rotatable"><g class="scalable"><rect class="card"/><image/></g><text class="rank"/><text class="name"/></g>',
23797 defaults: joint.util.deepSupplement({
23799 type: 'org.Member',
23800 size: { width: 180, height: 70 },
23803 rect: { width: 170, height: 60 },
23806 fill: '#FFFFFF', stroke: '#000000', 'stroke-width': 2,
23807 'pointer-events': 'visiblePainted', rx: 10, ry: 10
23811 width: 48, height: 48,
23812 ref: '.card', 'ref-x': 10, 'ref-y': 5
23816 'text-decoration': 'underline',
23817 ref: '.card', 'ref-x': 0.9, 'ref-y': 0.2,
23818 'font-family': 'Courier New', 'font-size': 14,
23819 'text-anchor': 'end'
23823 'font-weight': 'bold',
23824 ref: '.card', 'ref-x': 0.9, 'ref-y': 0.6,
23825 'font-family': 'Courier New', 'font-size': 14,
23826 'text-anchor': 'end'
23829 }, joint.dia.Element.prototype.defaults)
23832 joint.shapes.org.Arrow = joint.dia.Link.extend({
23836 source: { selector: '.card' }, target: { selector: '.card' },
23837 attrs: { '.connection': { stroke: '#585858', 'stroke-width': 3 }},
23843 if (typeof exports === 'object') {
23845 module.exports = joint.shapes.org;
23848 if (typeof exports === 'object') {
23851 util: require('../src/core').util,
23853 basic: require('./joint.shapes.basic')
23859 joint.shapes.chess = {};
23861 joint.shapes.chess.KingWhite = joint.shapes.basic.Generic.extend({
23863 markup: '<g class="rotatable"><g class="scalable"><g style="fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"><path d="M 22.5,11.63 L 22.5,6" style="fill:none; stroke:#000000; stroke-linejoin:miter;" /> <path d="M 20,8 L 25,8" style="fill:none; stroke:#000000; stroke-linejoin:miter;" /> <path d="M 22.5,25 C 22.5,25 27,17.5 25.5,14.5 C 25.5,14.5 24.5,12 22.5,12 C 20.5,12 19.5,14.5 19.5,14.5 C 18,17.5 22.5,25 22.5,25" style="fill:#ffffff; stroke:#000000; stroke-linecap:butt; stroke-linejoin:miter;" /> <path d="M 11.5,37 C 17,40.5 27,40.5 32.5,37 L 32.5,30 C 32.5,30 41.5,25.5 38.5,19.5 C 34.5,13 25,16 22.5,23.5 L 22.5,27 L 22.5,23.5 C 19,16 9.5,13 6.5,19.5 C 3.5,25.5 11.5,29.5 11.5,29.5 L 11.5,37 z " style="fill:#ffffff; stroke:#000000;" /> <path d="M 11.5,30 C 17,27 27,27 32.5,30" style="fill:none; stroke:#000000;" /> <path d="M 11.5,33.5 C 17,30.5 27,30.5 32.5,33.5" style="fill:none; stroke:#000000;" /> <path d="M 11.5,37 C 17,34 27,34 32.5,37" style="fill:none; stroke:#000000;" /> </g></g></g>',
23865 defaults: joint.util.deepSupplement({
23867 type: 'chess.KingWhite',
23868 size: { width: 42, height: 38 }
23870 }, joint.shapes.basic.Generic.prototype.defaults)
23873 joint.shapes.chess.KingBlack = joint.shapes.basic.Generic.extend({
23875 markup: '<g class="rotatable"><g class="scalable"><g style="fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <path d="M 22.5,11.63 L 22.5,6" style="fill:none; stroke:#000000; stroke-linejoin:miter;" id="path6570" /> <path d="M 22.5,25 C 22.5,25 27,17.5 25.5,14.5 C 25.5,14.5 24.5,12 22.5,12 C 20.5,12 19.5,14.5 19.5,14.5 C 18,17.5 22.5,25 22.5,25" style="fill:#000000;fill-opacity:1; stroke-linecap:butt; stroke-linejoin:miter;" /> <path d="M 11.5,37 C 17,40.5 27,40.5 32.5,37 L 32.5,30 C 32.5,30 41.5,25.5 38.5,19.5 C 34.5,13 25,16 22.5,23.5 L 22.5,27 L 22.5,23.5 C 19,16 9.5,13 6.5,19.5 C 3.5,25.5 11.5,29.5 11.5,29.5 L 11.5,37 z " style="fill:#000000; stroke:#000000;" /> <path d="M 20,8 L 25,8" style="fill:none; stroke:#000000; stroke-linejoin:miter;" /> <path d="M 32,29.5 C 32,29.5 40.5,25.5 38.03,19.85 C 34.15,14 25,18 22.5,24.5 L 22.51,26.6 L 22.5,24.5 C 20,18 9.906,14 6.997,19.85 C 4.5,25.5 11.85,28.85 11.85,28.85" style="fill:none; stroke:#ffffff;" /> <path d="M 11.5,30 C 17,27 27,27 32.5,30 M 11.5,33.5 C 17,30.5 27,30.5 32.5,33.5 M 11.5,37 C 17,34 27,34 32.5,37" style="fill:none; stroke:#ffffff;" /> </g></g></g>',
23877 defaults: joint.util.deepSupplement({
23879 type: 'chess.KingBlack',
23880 size: { width: 42, height: 38 }
23882 }, joint.shapes.basic.Generic.prototype.defaults)
23885 joint.shapes.chess.QueenWhite = joint.shapes.basic.Generic.extend({
23887 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#ffffff; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <path d="M 9 13 A 2 2 0 1 1 5,13 A 2 2 0 1 1 9 13 z" transform="translate(-1,-1)" /> <path d="M 9 13 A 2 2 0 1 1 5,13 A 2 2 0 1 1 9 13 z" transform="translate(15.5,-5.5)" /> <path d="M 9 13 A 2 2 0 1 1 5,13 A 2 2 0 1 1 9 13 z" transform="translate(32,-1)" /> <path d="M 9 13 A 2 2 0 1 1 5,13 A 2 2 0 1 1 9 13 z" transform="translate(7,-4.5)" /> <path d="M 9 13 A 2 2 0 1 1 5,13 A 2 2 0 1 1 9 13 z" transform="translate(24,-4)" /> <path d="M 9,26 C 17.5,24.5 30,24.5 36,26 L 38,14 L 31,25 L 31,11 L 25.5,24.5 L 22.5,9.5 L 19.5,24.5 L 14,10.5 L 14,25 L 7,14 L 9,26 z " style="stroke-linecap:butt;" /> <path d="M 9,26 C 9,28 10.5,28 11.5,30 C 12.5,31.5 12.5,31 12,33.5 C 10.5,34.5 10.5,36 10.5,36 C 9,37.5 11,38.5 11,38.5 C 17.5,39.5 27.5,39.5 34,38.5 C 34,38.5 35.5,37.5 34,36 C 34,36 34.5,34.5 33,33.5 C 32.5,31 32.5,31.5 33.5,30 C 34.5,28 36,28 36,26 C 27.5,24.5 17.5,24.5 9,26 z " style="stroke-linecap:butt;" /> <path d="M 11.5,30 C 15,29 30,29 33.5,30" style="fill:none;" /> <path d="M 12,33.5 C 18,32.5 27,32.5 33,33.5" style="fill:none;" /> </g></g></g>',
23889 defaults: joint.util.deepSupplement({
23891 type: 'chess.QueenWhite',
23892 size: { width: 42, height: 38 }
23894 }, joint.shapes.basic.Generic.prototype.defaults)
23897 joint.shapes.chess.QueenBlack = joint.shapes.basic.Generic.extend({
23899 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#000000; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <g style="fill:#000000; stroke:none;"> <circle cx="6" cy="12" r="2.75" /> <circle cx="14" cy="9" r="2.75" /> <circle cx="22.5" cy="8" r="2.75" /> <circle cx="31" cy="9" r="2.75" /> <circle cx="39" cy="12" r="2.75" /> </g> <path d="M 9,26 C 17.5,24.5 30,24.5 36,26 L 38.5,13.5 L 31,25 L 30.7,10.9 L 25.5,24.5 L 22.5,10 L 19.5,24.5 L 14.3,10.9 L 14,25 L 6.5,13.5 L 9,26 z" style="stroke-linecap:butt; stroke:#000000;" /> <path d="M 9,26 C 9,28 10.5,28 11.5,30 C 12.5,31.5 12.5,31 12,33.5 C 10.5,34.5 10.5,36 10.5,36 C 9,37.5 11,38.5 11,38.5 C 17.5,39.5 27.5,39.5 34,38.5 C 34,38.5 35.5,37.5 34,36 C 34,36 34.5,34.5 33,33.5 C 32.5,31 32.5,31.5 33.5,30 C 34.5,28 36,28 36,26 C 27.5,24.5 17.5,24.5 9,26 z" style="stroke-linecap:butt;" /> <path d="M 11,38.5 A 35,35 1 0 0 34,38.5" style="fill:none; stroke:#000000; stroke-linecap:butt;" /> <path d="M 11,29 A 35,35 1 0 1 34,29" style="fill:none; stroke:#ffffff;" /> <path d="M 12.5,31.5 L 32.5,31.5" style="fill:none; stroke:#ffffff;" /> <path d="M 11.5,34.5 A 35,35 1 0 0 33.5,34.5" style="fill:none; stroke:#ffffff;" /> <path d="M 10.5,37.5 A 35,35 1 0 0 34.5,37.5" style="fill:none; stroke:#ffffff;" /> </g></g></g>',
23901 defaults: joint.util.deepSupplement({
23903 type: 'chess.QueenBlack',
23904 size: { width: 42, height: 38 }
23906 }, joint.shapes.basic.Generic.prototype.defaults)
23909 joint.shapes.chess.RookWhite = joint.shapes.basic.Generic.extend({
23911 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#ffffff; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <path d="M 9,39 L 36,39 L 36,36 L 9,36 L 9,39 z " style="stroke-linecap:butt;" /> <path d="M 12,36 L 12,32 L 33,32 L 33,36 L 12,36 z " style="stroke-linecap:butt;" /> <path d="M 11,14 L 11,9 L 15,9 L 15,11 L 20,11 L 20,9 L 25,9 L 25,11 L 30,11 L 30,9 L 34,9 L 34,14" style="stroke-linecap:butt;" /> <path d="M 34,14 L 31,17 L 14,17 L 11,14" /> <path d="M 31,17 L 31,29.5 L 14,29.5 L 14,17" style="stroke-linecap:butt; stroke-linejoin:miter;" /> <path d="M 31,29.5 L 32.5,32 L 12.5,32 L 14,29.5" /> <path d="M 11,14 L 34,14" style="fill:none; stroke:#000000; stroke-linejoin:miter;" /> </g></g></g>',
23913 defaults: joint.util.deepSupplement({
23915 type: 'chess.RookWhite',
23916 size: { width: 32, height: 34 }
23918 }, joint.shapes.basic.Generic.prototype.defaults)
23921 joint.shapes.chess.RookBlack = joint.shapes.basic.Generic.extend({
23923 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#000000; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <path d="M 9,39 L 36,39 L 36,36 L 9,36 L 9,39 z " style="stroke-linecap:butt;" /> <path d="M 12.5,32 L 14,29.5 L 31,29.5 L 32.5,32 L 12.5,32 z " style="stroke-linecap:butt;" /> <path d="M 12,36 L 12,32 L 33,32 L 33,36 L 12,36 z " style="stroke-linecap:butt;" /> <path d="M 14,29.5 L 14,16.5 L 31,16.5 L 31,29.5 L 14,29.5 z " style="stroke-linecap:butt;stroke-linejoin:miter;" /> <path d="M 14,16.5 L 11,14 L 34,14 L 31,16.5 L 14,16.5 z " style="stroke-linecap:butt;" /> <path d="M 11,14 L 11,9 L 15,9 L 15,11 L 20,11 L 20,9 L 25,9 L 25,11 L 30,11 L 30,9 L 34,9 L 34,14 L 11,14 z " style="stroke-linecap:butt;" /> <path d="M 12,35.5 L 33,35.5 L 33,35.5" style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" /> <path d="M 13,31.5 L 32,31.5" style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" /> <path d="M 14,29.5 L 31,29.5" style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" /> <path d="M 14,16.5 L 31,16.5" style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" /> <path d="M 11,14 L 34,14" style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" /> </g></g></g>',
23925 defaults: joint.util.deepSupplement({
23927 type: 'chess.RookBlack',
23928 size: { width: 32, height: 34 }
23930 }, joint.shapes.basic.Generic.prototype.defaults)
23933 joint.shapes.chess.BishopWhite = joint.shapes.basic.Generic.extend({
23935 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-rule:evenodd; fill-opacity:1; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <g style="fill:#ffffff; stroke:#000000; stroke-linecap:butt;"> <path d="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38 C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.646,38.99 6.677,38.97 6,38 C 7.354,36.06 9,36 9,36 z" /> <path d="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5 22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z" /> <path d="M 25 8 A 2.5 2.5 0 1 1 20,8 A 2.5 2.5 0 1 1 25 8 z" /> </g> <path d="M 17.5,26 L 27.5,26 M 15,30 L 30,30 M 22.5,15.5 L 22.5,20.5 M 20,18 L 25,18" style="fill:none; stroke:#000000; stroke-linejoin:miter;" /> </g></g></g>',
23937 defaults: joint.util.deepSupplement({
23939 type: 'chess.BishopWhite',
23940 size: { width: 38, height: 38 }
23942 }, joint.shapes.basic.Generic.prototype.defaults)
23945 joint.shapes.chess.BishopBlack = joint.shapes.basic.Generic.extend({
23947 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-rule:evenodd; fill-opacity:1; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <g style="fill:#000000; stroke:#000000; stroke-linecap:butt;"> <path d="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38 C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.646,38.99 6.677,38.97 6,38 C 7.354,36.06 9,36 9,36 z" /> <path d="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5 22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z" /> <path d="M 25 8 A 2.5 2.5 0 1 1 20,8 A 2.5 2.5 0 1 1 25 8 z" /> </g> <path d="M 17.5,26 L 27.5,26 M 15,30 L 30,30 M 22.5,15.5 L 22.5,20.5 M 20,18 L 25,18" style="fill:none; stroke:#ffffff; stroke-linejoin:miter;" /> </g></g></g>',
23949 defaults: joint.util.deepSupplement({
23951 type: 'chess.BishopBlack',
23952 size: { width: 38, height: 38 }
23954 }, joint.shapes.basic.Generic.prototype.defaults)
23957 joint.shapes.chess.KnightWhite = joint.shapes.basic.Generic.extend({
23959 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <path d="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18" style="fill:#ffffff; stroke:#000000;" /> <path d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L 18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10" style="fill:#ffffff; stroke:#000000;" /> <path d="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z" style="fill:#000000; stroke:#000000;" /> <path d="M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z" transform="matrix(0.866,0.5,-0.5,0.866,9.693,-5.173)" style="fill:#000000; stroke:#000000;" /> </g></g></g>',
23961 defaults: joint.util.deepSupplement({
23963 type: 'chess.KnightWhite',
23964 size: { width: 38, height: 37 }
23966 }, joint.shapes.basic.Generic.prototype.defaults)
23969 joint.shapes.chess.KnightBlack = joint.shapes.basic.Generic.extend({
23971 markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"> <path d="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18" style="fill:#000000; stroke:#000000;" /> <path d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L 18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10" style="fill:#000000; stroke:#000000;" /> <path d="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z" style="fill:#ffffff; stroke:#ffffff;" /> <path d="M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z" transform="matrix(0.866,0.5,-0.5,0.866,9.693,-5.173)" style="fill:#ffffff; stroke:#ffffff;" /> <path d="M 24.55,10.4 L 24.1,11.85 L 24.6,12 C 27.75,13 30.25,14.49 32.5,18.75 C 34.75,23.01 35.75,29.06 35.25,39 L 35.2,39.5 L 37.45,39.5 L 37.5,39 C 38,28.94 36.62,22.15 34.25,17.66 C 31.88,13.17 28.46,11.02 25.06,10.5 L 24.55,10.4 z " style="fill:#ffffff; stroke:none;" /> </g></g></g>',
23973 defaults: joint.util.deepSupplement({
23975 type: 'chess.KnightBlack',
23976 size: { width: 38, height: 37 }
23978 }, joint.shapes.basic.Generic.prototype.defaults)
23981 joint.shapes.chess.PawnWhite = joint.shapes.basic.Generic.extend({
23983 markup: '<g class="rotatable"><g class="scalable"><path d="M 22,9 C 19.79,9 18,10.79 18,13 C 18,13.89 18.29,14.71 18.78,15.38 C 16.83,16.5 15.5,18.59 15.5,21 C 15.5,23.03 16.44,24.84 17.91,26.03 C 14.91,27.09 10.5,31.58 10.5,39.5 L 33.5,39.5 C 33.5,31.58 29.09,27.09 26.09,26.03 C 27.56,24.84 28.5,23.03 28.5,21 C 28.5,18.59 27.17,16.5 25.22,15.38 C 25.71,14.71 26,13.89 26,13 C 26,10.79 24.21,9 22,9 z " style="opacity:1; fill:#ffffff; fill-opacity:1; fill-rule:nonzero; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:miter; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;" /></g></g>',
23985 defaults: joint.util.deepSupplement({
23987 type: 'chess.PawnWhite',
23988 size: { width: 28, height: 33 }
23990 }, joint.shapes.basic.Generic.prototype.defaults)
23993 joint.shapes.chess.PawnBlack = joint.shapes.basic.Generic.extend({
23995 markup: '<g class="rotatable"><g class="scalable"><path d="M 22,9 C 19.79,9 18,10.79 18,13 C 18,13.89 18.29,14.71 18.78,15.38 C 16.83,16.5 15.5,18.59 15.5,21 C 15.5,23.03 16.44,24.84 17.91,26.03 C 14.91,27.09 10.5,31.58 10.5,39.5 L 33.5,39.5 C 33.5,31.58 29.09,27.09 26.09,26.03 C 27.56,24.84 28.5,23.03 28.5,21 C 28.5,18.59 27.17,16.5 25.22,15.38 C 25.71,14.71 26,13.89 26,13 C 26,10.79 24.21,9 22,9 z " style="opacity:1; fill:#000000; fill-opacity:1; fill-rule:nonzero; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:miter; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;" /></g></g>',
23997 defaults: joint.util.deepSupplement({
23999 type: 'chess.PawnBlack',
24000 size: { width: 28, height: 33 }
24002 }, joint.shapes.basic.Generic.prototype.defaults)
24005 if (typeof exports === 'object') {
24007 module.exports = joint.shapes.chess;
24010 if (typeof exports === 'object') {
24013 util: require('../src/core').util,
24015 basic: require('./joint.shapes.basic')
24018 ElementView: require('../src/joint.dia.element').ElementView,
24019 Link: require('../src/joint.dia.link').Link
24024 joint.shapes.pn = {};
24026 joint.shapes.pn.Place = joint.shapes.basic.Generic.extend({
24028 markup: '<g class="rotatable"><g class="scalable"><circle class="root"/><g class="tokens" /></g><text class="label"/></g>',
24030 defaults: joint.util.deepSupplement({
24033 size: { width: 50, height: 50 },
24039 transform: 'translate(25, 25)'
24042 'text-anchor': 'middle',
24049 '.tokens > circle': {
24053 '.tokens.one > circle': { transform: 'translate(25, 25)' },
24055 '.tokens.two > circle:nth-child(1)': { transform: 'translate(19, 25)' },
24056 '.tokens.two > circle:nth-child(2)': { transform: 'translate(31, 25)' },
24058 '.tokens.three > circle:nth-child(1)': { transform: 'translate(18, 29)' },
24059 '.tokens.three > circle:nth-child(2)': { transform: 'translate(25, 19)' },
24060 '.tokens.three > circle:nth-child(3)': { transform: 'translate(32, 29)' },
24062 '.tokens.alot > text': {
24063 transform: 'translate(25, 18)',
24064 'text-anchor': 'middle',
24069 }, joint.shapes.basic.Generic.prototype.defaults)
24073 joint.shapes.pn.PlaceView = joint.dia.ElementView.extend({
24075 initialize: function() {
24077 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
24079 this.model.on('change:tokens', function() {
24081 this.renderTokens();
24087 render: function() {
24089 joint.dia.ElementView.prototype.render.apply(this, arguments);
24091 this.renderTokens();
24095 renderTokens: function() {
24097 var $tokens = this.$('.tokens').empty();
24098 $tokens[0].className.baseVal = 'tokens';
24100 var tokens = this.model.get('tokens');
24102 if (!tokens) return;
24107 $tokens[0].className.baseVal += ' one';
24108 $tokens.append(V('<circle/>').node);
24112 $tokens[0].className.baseVal += ' two';
24113 $tokens.append(V('<circle/>').node, V('<circle/>').node);
24117 $tokens[0].className.baseVal += ' three';
24118 $tokens.append(V('<circle/>').node, V('<circle/>').node, V('<circle/>').node);
24122 $tokens[0].className.baseVal += ' alot';
24123 $tokens.append(V('<text/>').text(tokens + '' ).node);
24130 joint.shapes.pn.Transition = joint.shapes.basic.Generic.extend({
24132 markup: '<g class="rotatable"><g class="scalable"><rect class="root"/></g></g><text class="label"/>',
24134 defaults: joint.util.deepSupplement({
24136 type: 'pn.Transition',
24137 size: { width: 12, height: 50 },
24146 'text-anchor': 'middle',
24155 }, joint.shapes.basic.Generic.prototype.defaults)
24158 joint.shapes.pn.Link = joint.dia.Link.extend({
24160 defaults: joint.util.deepSupplement({
24162 attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' }}
24164 }, joint.dia.Link.prototype.defaults)
24167 if (typeof exports === 'object') {
24169 module.exports = joint.shapes.pn;
24172 if (typeof exports === 'object') {
24175 util: require('../src/core').util,
24177 basic: require('./joint.shapes.basic')
24180 ElementView: require('../src/joint.dia.element').ElementView,
24181 Link: require('../src/joint.dia.link').Link
24184 var _ = require('lodash');
24187 joint.shapes.devs = {};
24189 joint.shapes.devs.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
24191 markup: '<g class="rotatable"><g class="scalable"><rect/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
24192 portMarkup: '<g class="port<%= id %>"><circle/><text/></g>',
24194 defaults: joint.util.deepSupplement({
24196 type: 'devs.Model',
24197 size: { width: 1, height: 1 },
24203 '.': { magnet: false },
24205 width: 150, height: 250,
24215 'pointer-events': 'none'
24217 '.label': { text: 'Model', 'ref-x': .3, 'ref-y': .2 },
24218 '.inPorts text': { x:-15, dy: 4, 'text-anchor': 'end' },
24219 '.outPorts text':{ x: 15, dy: 4 }
24222 }, joint.shapes.basic.Generic.prototype.defaults),
24224 getPortAttrs: function(portName, index, total, selector, type) {
24228 var portClass = 'port' + index;
24229 var portSelector = selector + '>.' + portClass;
24230 var portTextSelector = portSelector + '>text';
24231 var portCircleSelector = portSelector + '>circle';
24233 attrs[portTextSelector] = { text: portName };
24234 attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
24235 attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
24237 if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
24244 joint.shapes.devs.Atomic = joint.shapes.devs.Model.extend({
24246 defaults: joint.util.deepSupplement({
24248 type: 'devs.Atomic',
24249 size: { width: 80, height: 80 },
24251 rect: { fill: 'salmon' },
24252 '.label': { text: 'Atomic' },
24253 '.inPorts circle': { fill: 'PaleGreen' },
24254 '.outPorts circle': { fill: 'Tomato' }
24257 }, joint.shapes.devs.Model.prototype.defaults)
24261 joint.shapes.devs.Coupled = joint.shapes.devs.Model.extend({
24263 defaults: joint.util.deepSupplement({
24265 type: 'devs.Coupled',
24266 size: { width: 200, height: 300 },
24268 rect: { fill: 'seaGreen' },
24269 '.label': { text: 'Coupled' },
24270 '.inPorts circle': { fill: 'PaleGreen' },
24271 '.outPorts circle': { fill: 'Tomato' }
24274 }, joint.shapes.devs.Model.prototype.defaults)
24277 joint.shapes.devs.Link = joint.dia.Link.extend({
24281 attrs: { '.connection' : { 'stroke-width' : 2 }}
24285 joint.shapes.devs.ModelView = joint.dia.ElementView.extend(joint.shapes.basic.PortsViewInterface);
24286 joint.shapes.devs.AtomicView = joint.shapes.devs.ModelView;
24287 joint.shapes.devs.CoupledView = joint.shapes.devs.ModelView;
24290 if (typeof exports === 'object') {
24292 module.exports = joint.shapes.devs;
24295 if (typeof exports === 'object') {
24298 util: require('../src/core').util,
24300 basic: require('./joint.shapes.basic')
24303 ElementView: require('../src/joint.dia.element').ElementView,
24304 Link: require('../src/joint.dia.link').Link
24307 var _ = require('lodash');
24310 joint.shapes.uml = {}
24312 joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
24315 '<g class="rotatable">',
24316 '<g class="scalable">',
24317 '<rect class="uml-class-name-rect"/><rect class="uml-class-attrs-rect"/><rect class="uml-class-methods-rect"/>',
24319 '<text class="uml-class-name-text"/><text class="uml-class-attrs-text"/><text class="uml-class-methods-text"/>',
24323 defaults: joint.util.deepSupplement({
24328 rect: { 'width': 200 },
24330 '.uml-class-name-rect': { 'stroke': 'black', 'stroke-width': 2, 'fill': '#3498db' },
24331 '.uml-class-attrs-rect': { 'stroke': 'black', 'stroke-width': 2, 'fill': '#2980b9' },
24332 '.uml-class-methods-rect': { 'stroke': 'black', 'stroke-width': 2, 'fill': '#2980b9' },
24334 '.uml-class-name-text': {
24335 'ref': '.uml-class-name-rect', 'ref-y': .5, 'ref-x': .5, 'text-anchor': 'middle', 'y-alignment': 'middle', 'font-weight': 'bold',
24336 'fill': 'black', 'font-size': 12, 'font-family': 'Times New Roman'
24338 '.uml-class-attrs-text': {
24339 'ref': '.uml-class-attrs-rect', 'ref-y': 5, 'ref-x': 5,
24340 'fill': 'black', 'font-size': 12, 'font-family': 'Times New Roman'
24342 '.uml-class-methods-text': {
24343 'ref': '.uml-class-methods-rect', 'ref-y': 5, 'ref-x': 5,
24344 'fill': 'black', 'font-size': 12, 'font-family': 'Times New Roman'
24352 }, joint.shapes.basic.Generic.prototype.defaults),
24354 initialize: function() {
24356 _.bindAll(this, 'updateRectangles');
24358 this.on('change:name change:attributes change:methods', function() {
24359 this.updateRectangles();
24360 this.trigger('uml-update');
24363 this.updateRectangles();
24365 joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
24368 getClassName: function() {
24369 return this.get('name');
24372 updateRectangles: function() {
24374 var attrs = this.get('attrs');
24377 { type: 'name', text: this.getClassName() },
24378 { type: 'attrs', text: this.get('attributes') },
24379 { type: 'methods', text: this.get('methods') }
24384 _.each(rects, function(rect) {
24386 var lines = _.isArray(rect.text) ? rect.text : [rect.text];
24387 var rectHeight = lines.length * 20 + 20;
24389 attrs['.uml-class-' + rect.type + '-text'].text = lines.join('\n');
24390 attrs['.uml-class-' + rect.type + '-rect'].height = rectHeight;
24391 attrs['.uml-class-' + rect.type + '-rect'].transform = 'translate(0,'+ offsetY + ')';
24393 offsetY += rectHeight;
24399 joint.shapes.uml.ClassView = joint.dia.ElementView.extend({
24401 initialize: function() {
24403 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
24405 this.model.on('uml-update', _.bind(function() {
24412 joint.shapes.uml.Abstract = joint.shapes.uml.Class.extend({
24414 defaults: joint.util.deepSupplement({
24415 type: 'uml.Abstract',
24417 '.uml-class-name-rect': { fill : '#e74c3c' },
24418 '.uml-class-attrs-rect': { fill : '#c0392b' },
24419 '.uml-class-methods-rect': { fill : '#c0392b' }
24421 }, joint.shapes.uml.Class.prototype.defaults),
24423 getClassName: function() {
24424 return ['<<Abstract>>', this.get('name')];
24428 joint.shapes.uml.AbstractView = joint.shapes.uml.ClassView;
24430 joint.shapes.uml.Interface = joint.shapes.uml.Class.extend({
24432 defaults: joint.util.deepSupplement({
24433 type: 'uml.Interface',
24435 '.uml-class-name-rect': { fill : '#f1c40f' },
24436 '.uml-class-attrs-rect': { fill : '#f39c12' },
24437 '.uml-class-methods-rect': { fill : '#f39c12' }
24439 }, joint.shapes.uml.Class.prototype.defaults),
24441 getClassName: function() {
24442 return ['<<Interface>>', this.get('name')];
24446 joint.shapes.uml.InterfaceView = joint.shapes.uml.ClassView;
24448 joint.shapes.uml.Generalization = joint.dia.Link.extend({
24450 type: 'uml.Generalization',
24451 attrs: { '.marker-target': { d: 'M 20 0 L 0 10 L 20 20 z', fill: 'white' }}
24455 joint.shapes.uml.Implementation = joint.dia.Link.extend({
24457 type: 'uml.Implementation',
24459 '.marker-target': { d: 'M 20 0 L 0 10 L 20 20 z', fill: 'white' },
24460 '.connection': { 'stroke-dasharray': '3,3' }
24465 joint.shapes.uml.Aggregation = joint.dia.Link.extend({
24467 type: 'uml.Aggregation',
24468 attrs: { '.marker-target': { d: 'M 40 10 L 20 20 L 0 10 L 20 0 z', fill: 'white' }}
24472 joint.shapes.uml.Composition = joint.dia.Link.extend({
24474 type: 'uml.Composition',
24475 attrs: { '.marker-target': { d: 'M 40 10 L 20 20 L 0 10 L 20 0 z', fill: 'black' }}
24479 joint.shapes.uml.Association = joint.dia.Link.extend({
24480 defaults: { type: 'uml.Association' }
24485 joint.shapes.uml.State = joint.shapes.basic.Generic.extend({
24488 '<g class="rotatable">',
24489 '<g class="scalable">',
24492 '<path/><text class="uml-state-name"/><text class="uml-state-events"/>',
24496 defaults: joint.util.deepSupplement({
24501 rect: { 'width': 200, 'height': 200, 'fill': '#ecf0f1', 'stroke': '#bdc3c7', 'stroke-width': 3, 'rx': 10, 'ry': 10 },
24502 path: { 'd': 'M 0 20 L 200 20', 'stroke': '#bdc3c7', 'stroke-width': 2 },
24503 '.uml-state-name': {
24504 'ref': 'rect', 'ref-x': .5, 'ref-y': 5, 'text-anchor': 'middle',
24505 'font-family': 'Courier New', 'font-size': 14, fill: '#000000'
24507 '.uml-state-events': {
24508 'ref': 'path', 'ref-x': 5, 'ref-y': 5,
24509 'font-family': 'Courier New', 'font-size': 14, fill: '#000000'
24516 }, joint.shapes.basic.Generic.prototype.defaults),
24518 initialize: function() {
24520 _.bindAll(this, 'updateEvents', 'updatePath');
24523 'change:name': function() { this.updateName(); this.trigger('change:attrs'); },
24524 'change:events': function() { this.updateEvents(); this.trigger('change:attrs'); },
24525 'change:size': this.updatePath
24529 this.updateEvents();
24532 joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
24535 updateName: function() {
24536 this.get('attrs')['.uml-state-name'].text = this.get('name');
24539 updateEvents: function() {
24540 this.get('attrs')['.uml-state-events'].text = this.get('events').join('\n');
24543 updatePath: function() {
24544 this.get('attrs')['path'].d = 'M 0 20 L ' + this.get('size').width + ' 20';
24549 joint.shapes.uml.StartState = joint.shapes.basic.Circle.extend({
24551 defaults: joint.util.deepSupplement({
24553 type: 'uml.StartState',
24554 attrs: { circle: { 'fill': '#34495e', 'stroke': '#2c3e50', 'stroke-width': 2, 'rx': 1 }}
24556 }, joint.shapes.basic.Circle.prototype.defaults)
24560 joint.shapes.uml.EndState = joint.shapes.basic.Generic.extend({
24562 markup: '<g class="rotatable"><g class="scalable"><circle class="outer"/><circle class="inner"/></g></g>',
24564 defaults: joint.util.deepSupplement({
24566 type: 'uml.EndState',
24567 size: { width: 20, height: 20 },
24570 transform: 'translate(10, 10)',
24577 transform: 'translate(10, 10)',
24583 }, joint.shapes.basic.Generic.prototype.defaults)
24587 joint.shapes.uml.Transition = joint.dia.Link.extend({
24589 type: 'uml.Transition',
24591 '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z', fill: '#34495e', stroke: '#2c3e50' },
24592 '.connection': { stroke: '#2c3e50' }
24597 if (typeof exports === 'object') {
24599 module.exports = joint.shapes.uml;
24602 ;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
24603 var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
24605 * Copyright (c) 2012-2013 Chris Pettitt
24607 * Permission is hereby granted, free of charge, to any person obtaining a copy
24608 * of this software and associated documentation files (the "Software"), to deal
24609 * in the Software without restriction, including without limitation the rights
24610 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24611 * copies of the Software, and to permit persons to whom the Software is
24612 * furnished to do so, subject to the following conditions:
24614 * The above copyright notice and this permission notice shall be included in
24615 * all copies or substantial portions of the Software.
24617 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24618 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24619 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24620 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24621 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24622 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24625 global.dagre = require("./index");
24627 },{"./index":2}],2:[function(require,module,exports){
24629 Copyright (c) 2012-2013 Chris Pettitt
24631 Permission is hereby granted, free of charge, to any person obtaining a copy
24632 of this software and associated documentation files (the "Software"), to deal
24633 in the Software without restriction, including without limitation the rights
24634 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24635 copies of the Software, and to permit persons to whom the Software is
24636 furnished to do so, subject to the following conditions:
24638 The above copyright notice and this permission notice shall be included in
24639 all copies or substantial portions of the Software.
24641 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24642 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24643 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24644 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24645 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24646 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24649 exports.Digraph = require("graphlib").Digraph;
24650 exports.Graph = require("graphlib").Graph;
24651 exports.layout = require("./lib/layout");
24652 exports.version = require("./lib/version");
24654 },{"./lib/layout":3,"./lib/version":18,"graphlib":24}],3:[function(require,module,exports){
24655 var util = require('./util'),
24656 rank = require('./rank'),
24657 order = require('./order'),
24658 CGraph = require('graphlib').CGraph,
24659 CDigraph = require('graphlib').CDigraph;
24661 module.exports = function() {
24662 // External configuration
24664 // How much debug information to include?
24666 // Max number of sweeps to perform in order phase
24667 orderMaxSweeps: order.DEFAULT_MAX_SWEEPS,
24668 // Use network simplex algorithm in ranking
24669 rankSimplex: false,
24670 // Rank direction. Valid values are (TB, LR)
24675 var position = require('./position')();
24677 // This layout object
24680 self.orderIters = util.propertyAccessor(self, config, 'orderMaxSweeps');
24682 self.rankSimplex = util.propertyAccessor(self, config, 'rankSimplex');
24684 self.nodeSep = delegateProperty(position.nodeSep);
24685 self.edgeSep = delegateProperty(position.edgeSep);
24686 self.universalSep = delegateProperty(position.universalSep);
24687 self.rankSep = delegateProperty(position.rankSep);
24688 self.rankDir = util.propertyAccessor(self, config, 'rankDir');
24689 self.debugAlignment = delegateProperty(position.debugAlignment);
24691 self.debugLevel = util.propertyAccessor(self, config, 'debugLevel', function(x) {
24692 util.log.level = x;
24693 position.debugLevel(x);
24696 self.run = util.time('Total layout', run);
24698 self._normalize = normalize;
24703 * Constructs an adjacency graph using the nodes and edges specified through
24704 * config. For each node and edge we add a property `dagre` that contains an
24705 * object that will hold intermediate and final layout information. Some of
24706 * the contents include:
24708 * 1) A generated ID that uniquely identifies the object.
24709 * 2) Dimension information for nodes (copied from the source node).
24710 * 3) Optional dimension information for edges.
24712 * After the adjacency graph is constructed the code no longer needs to use
24713 * the original nodes and edges passed in via config.
24715 function initLayoutGraph(inputGraph) {
24716 var g = new CDigraph();
24718 inputGraph.eachNode(function(u, value) {
24719 if (value === undefined) value = {};
24721 width: value.width,
24722 height: value.height
24724 if (value.hasOwnProperty('rank')) {
24725 g.node(u).prefRank = value.rank;
24729 // Set up subgraphs
24730 if (inputGraph.parent) {
24731 inputGraph.nodes().forEach(function(u) {
24732 g.parent(u, inputGraph.parent(u));
24736 inputGraph.eachEdge(function(e, u, v, value) {
24737 if (value === undefined) value = {};
24740 minLen: value.minLen || 1,
24741 width: value.width || 0,
24742 height: value.height || 0,
24746 g.addEdge(null, u, v, newValue);
24749 // Initial graph attributes
24750 var graphValue = inputGraph.graph() || {};
24752 rankDir: graphValue.rankDir || config.rankDir,
24753 orderRestarts: graphValue.orderRestarts
24759 function run(inputGraph) {
24760 var rankSep = self.rankSep();
24763 // Build internal graph
24764 g = util.time('initLayoutGraph', initLayoutGraph)(inputGraph);
24766 if (g.order() === 0) {
24770 // Make space for edge labels
24771 g.eachEdge(function(e, s, t, a) {
24774 self.rankSep(rankSep / 2);
24776 // Determine the rank for each node. Nodes with a lower rank will appear
24777 // above nodes of higher rank.
24778 util.time('rank.run', rank.run)(g, config.rankSimplex);
24780 // Normalize the graph by ensuring that every edge is proper (each edge has
24781 // a length of 1). We achieve this by adding dummy nodes to long edges,
24782 // thus shortening them.
24783 util.time('normalize', normalize)(g);
24785 // Order the nodes so that edge crossings are minimized.
24786 util.time('order', order)(g, config.orderMaxSweeps);
24788 // Find the x and y coordinates for every node in the graph.
24789 util.time('position', position.run)(g);
24791 // De-normalize the graph by removing dummy nodes and augmenting the
24792 // original long edges with coordinate information.
24793 util.time('undoNormalize', undoNormalize)(g);
24795 // Reverses points for edges that are in a reversed state.
24796 util.time('fixupEdgePoints', fixupEdgePoints)(g);
24798 // Restore delete edges and reverse edges that were reversed in the rank
24800 util.time('rank.restoreEdges', rank.restoreEdges)(g);
24802 // Construct final result graph and return it
24803 return util.time('createFinalGraph', createFinalGraph)(g, inputGraph.isDirected());
24805 self.rankSep(rankSep);
24810 * This function is responsible for 'normalizing' the graph. The process of
24811 * normalization ensures that no edge in the graph has spans more than one
24812 * rank. To do this it inserts dummy nodes as needed and links them by adding
24813 * dummy edges. This function keeps enough information in the dummy nodes and
24814 * edges to ensure that the original graph can be reconstructed later.
24816 * This method assumes that the input graph is cycle free.
24818 function normalize(g) {
24819 var dummyCount = 0;
24820 g.eachEdge(function(e, s, t, a) {
24821 var sourceRank = g.node(s).rank;
24822 var targetRank = g.node(t).rank;
24823 if (sourceRank + 1 < targetRank) {
24824 for (var u = s, rank = sourceRank + 1, i = 0; rank < targetRank; ++rank, ++i) {
24825 var v = '_D' + (++dummyCount);
24829 edge: { id: e, source: s, target: t, attrs: a },
24834 // If this node represents a bend then we will use it as a control
24835 // point. For edges with 2 segments this will be the center dummy
24836 // node. For edges with more than two segments, this will be the
24837 // first and last dummy node.
24838 if (i === 0) node.index = 0;
24839 else if (rank + 1 === targetRank) node.index = 1;
24841 g.addNode(v, node);
24842 g.addEdge(null, u, v, {});
24845 g.addEdge(null, u, t, {});
24852 * Reconstructs the graph as it was before normalization. The positions of
24853 * dummy nodes are used to build an array of points for the original 'long'
24854 * edge. Dummy nodes and edges are removed.
24856 function undoNormalize(g) {
24857 g.eachNode(function(u, a) {
24859 if ('index' in a) {
24861 if (!g.hasEdge(edge.id)) {
24862 g.addEdge(edge.id, edge.source, edge.target, edge.attrs);
24864 var points = g.edge(edge.id).points;
24865 points[a.index] = { x: a.x, y: a.y, ul: a.ul, ur: a.ur, dl: a.dl, dr: a.dr };
24873 * For each edge that was reversed during the `acyclic` step, reverse its
24876 function fixupEdgePoints(g) {
24877 g.eachEdge(function(e, s, t, a) { if (a.reversed) a.points.reverse(); });
24880 function createFinalGraph(g, isDirected) {
24881 var out = isDirected ? new CDigraph() : new CGraph();
24882 out.graph(g.graph());
24883 g.eachNode(function(u, value) { out.addNode(u, value); });
24884 g.eachNode(function(u) { out.parent(u, g.parent(u)); });
24885 g.eachEdge(function(e, u, v, value) {
24886 out.addEdge(value.e, u, v, value);
24889 // Attach bounding box information
24890 var maxX = 0, maxY = 0;
24891 g.eachNode(function(u, value) {
24892 if (!g.children(u).length) {
24893 maxX = Math.max(maxX, value.x + value.width / 2);
24894 maxY = Math.max(maxY, value.y + value.height / 2);
24897 g.eachEdge(function(e, u, v, value) {
24898 var maxXPoints = Math.max.apply(Math, value.points.map(function(p) { return p.x; }));
24899 var maxYPoints = Math.max.apply(Math, value.points.map(function(p) { return p.y; }));
24900 maxX = Math.max(maxX, maxXPoints + value.width / 2);
24901 maxY = Math.max(maxY, maxYPoints + value.height / 2);
24903 out.graph().width = maxX;
24904 out.graph().height = maxY;
24910 * Given a function, a new function is returned that invokes the given
24911 * function. The return value from the function is always the `self` object.
24913 function delegateProperty(f) {
24914 return function() {
24915 if (!arguments.length) return f();
24916 f.apply(null, arguments);
24923 },{"./order":4,"./position":9,"./rank":10,"./util":17,"graphlib":24}],4:[function(require,module,exports){
24924 var util = require('./util'),
24925 crossCount = require('./order/crossCount'),
24926 initLayerGraphs = require('./order/initLayerGraphs'),
24927 initOrder = require('./order/initOrder'),
24928 sortLayer = require('./order/sortLayer');
24930 module.exports = order;
24932 // The maximum number of sweeps to perform before finishing the order phase.
24933 var DEFAULT_MAX_SWEEPS = 24;
24934 order.DEFAULT_MAX_SWEEPS = DEFAULT_MAX_SWEEPS;
24937 * Runs the order phase with the specified `graph, `maxSweeps`, and
24938 * `debugLevel`. If `maxSweeps` is not specified we use `DEFAULT_MAX_SWEEPS`.
24939 * If `debugLevel` is not set we assume 0.
24941 function order(g, maxSweeps) {
24942 if (arguments.length < 2) {
24943 maxSweeps = DEFAULT_MAX_SWEEPS;
24946 var restarts = g.graph().orderRestarts || 0;
24948 var layerGraphs = initLayerGraphs(g);
24949 // TODO: remove this when we add back support for ordering clusters
24950 layerGraphs.forEach(function(lg) {
24951 lg = lg.filterNodes(function(u) { return !g.children(u).length; });
24956 allTimeBestCC = Number.MAX_VALUE,
24959 function saveAllTimeBest() {
24960 g.eachNode(function(u, value) { allTimeBest[u] = value.order; });
24963 for (var j = 0; j < Number(restarts) + 1 && allTimeBestCC !== 0; ++j) {
24964 currentBestCC = Number.MAX_VALUE;
24965 initOrder(g, restarts > 0);
24967 util.log(2, 'Order phase start cross count: ' + g.graph().orderInitCC);
24969 var i, lastBest, cc;
24970 for (i = 0, lastBest = 0; lastBest < 4 && i < maxSweeps && currentBestCC > 0; ++i, ++lastBest, ++iters) {
24971 sweep(g, layerGraphs, i);
24972 cc = crossCount(g);
24973 if (cc < currentBestCC) {
24975 currentBestCC = cc;
24976 if (cc < allTimeBestCC) {
24978 allTimeBestCC = cc;
24981 util.log(3, 'Order phase start ' + j + ' iter ' + i + ' cross count: ' + cc);
24985 Object.keys(allTimeBest).forEach(function(u) {
24986 if (!g.children || !g.children(u).length) {
24987 g.node(u).order = allTimeBest[u];
24990 g.graph().orderCC = allTimeBestCC;
24992 util.log(2, 'Order iterations: ' + iters);
24993 util.log(2, 'Order phase best cross count: ' + g.graph().orderCC);
24996 function predecessorWeights(g, nodes) {
24998 nodes.forEach(function(u) {
24999 weights[u] = g.inEdges(u).map(function(e) {
25000 return g.node(g.source(e)).order;
25006 function successorWeights(g, nodes) {
25008 nodes.forEach(function(u) {
25009 weights[u] = g.outEdges(u).map(function(e) {
25010 return g.node(g.target(e)).order;
25016 function sweep(g, layerGraphs, iter) {
25017 if (iter % 2 === 0) {
25018 sweepDown(g, layerGraphs, iter);
25020 sweepUp(g, layerGraphs, iter);
25024 function sweepDown(g, layerGraphs) {
25026 for (i = 1; i < layerGraphs.length; ++i) {
25027 cg = sortLayer(layerGraphs[i], cg, predecessorWeights(g, layerGraphs[i].nodes()));
25031 function sweepUp(g, layerGraphs) {
25033 for (i = layerGraphs.length - 2; i >= 0; --i) {
25034 sortLayer(layerGraphs[i], cg, successorWeights(g, layerGraphs[i].nodes()));
25038 },{"./order/crossCount":5,"./order/initLayerGraphs":6,"./order/initOrder":7,"./order/sortLayer":8,"./util":17}],5:[function(require,module,exports){
25039 var util = require('../util');
25041 module.exports = crossCount;
25044 * Returns the cross count for the given graph.
25046 function crossCount(g) {
25048 var ordering = util.ordering(g);
25049 for (var i = 1; i < ordering.length; ++i) {
25050 cc += twoLayerCrossCount(g, ordering[i-1], ordering[i]);
25056 * This function searches through a ranked and ordered graph and counts the
25057 * number of edges that cross. This algorithm is derived from:
25059 * W. Barth et al., Bilayer Cross Counting, JGAA, 8(2) 179–194 (2004)
25061 function twoLayerCrossCount(g, layer1, layer2) {
25063 layer1.forEach(function(u) {
25064 var nodeIndices = [];
25065 g.outEdges(u).forEach(function(e) { nodeIndices.push(g.node(g.target(e)).order); });
25066 nodeIndices.sort(function(x, y) { return x - y; });
25067 indices = indices.concat(nodeIndices);
25070 var firstIndex = 1;
25071 while (firstIndex < layer2.length) firstIndex <<= 1;
25073 var treeSize = 2 * firstIndex - 1;
25077 for (var i = 0; i < treeSize; ++i) { tree[i] = 0; }
25080 indices.forEach(function(i) {
25081 var treeIndex = i + firstIndex;
25083 while (treeIndex > 0) {
25084 if (treeIndex % 2) {
25085 cc += tree[treeIndex + 1];
25087 treeIndex = (treeIndex - 1) >> 1;
25095 },{"../util":17}],6:[function(require,module,exports){
25096 var nodesFromList = require('graphlib').filter.nodesFromList,
25098 Set = require('cp-data').Set;
25100 module.exports = initLayerGraphs;
25103 * This function takes a compound layered graph, g, and produces an array of
25104 * layer graphs. Each entry in the array represents a subgraph of nodes
25105 * relevant for performing crossing reduction on that layer.
25107 function initLayerGraphs(g) {
25112 g.children(u).forEach(function(v) { dfs(v); });
25116 var value = g.node(u);
25117 value.minRank = ('rank' in value) ? value.rank : Number.MAX_VALUE;
25118 value.maxRank = ('rank' in value) ? value.rank : Number.MIN_VALUE;
25119 var uRanks = new Set();
25120 g.children(u).forEach(function(v) {
25122 uRanks = Set.union([uRanks, rs]);
25123 value.minRank = Math.min(value.minRank, g.node(v).minRank);
25124 value.maxRank = Math.max(value.maxRank, g.node(v).maxRank);
25127 if ('rank' in value) uRanks.add(value.rank);
25129 uRanks.keys().forEach(function(r) {
25130 if (!(r in ranks)) ranks[r] = [];
25138 var layerGraphs = [];
25139 ranks.forEach(function(us, rank) {
25140 layerGraphs[rank] = g.filterNodes(nodesFromList(us));
25143 return layerGraphs;
25146 },{"cp-data":19,"graphlib":24}],7:[function(require,module,exports){
25147 var crossCount = require('./crossCount'),
25148 util = require('../util');
25150 module.exports = initOrder;
25153 * Given a graph with a set of layered nodes (i.e. nodes that have a `rank`
25154 * attribute) this function attaches an `order` attribute that uniquely
25155 * arranges each node of each rank. If no constraint graph is provided the
25156 * order of the nodes in each rank is entirely arbitrary.
25158 function initOrder(g, random) {
25161 g.eachNode(function(u, value) {
25162 var layer = layers[value.rank];
25163 if (g.children && g.children(u).length > 0) return;
25165 layer = layers[value.rank] = [];
25170 layers.forEach(function(layer) {
25172 util.shuffle(layer);
25174 layer.forEach(function(u, i) {
25175 g.node(u).order = i;
25179 var cc = crossCount(g);
25180 g.graph().orderInitCC = cc;
25181 g.graph().orderCC = Number.MAX_VALUE;
25184 },{"../util":17,"./crossCount":5}],8:[function(require,module,exports){
25185 var util = require('../util');
25187 Digraph = require('graphlib').Digraph,
25188 topsort = require('graphlib').alg.topsort,
25189 nodesFromList = require('graphlib').filter.nodesFromList;
25192 module.exports = sortLayer;
25195 function sortLayer(g, cg, weights) {
25196 var result = sortLayerSubgraph(g, null, cg, weights);
25197 result.list.forEach(function(u, i) {
25198 g.node(u).order = i;
25200 return result.constraintGraph;
25204 function sortLayer(g, cg, weights) {
25207 g.eachNode(function(u, value) {
25208 ordering[value.order] = u;
25209 var ws = weights[u];
25211 bs[u] = util.sum(ws) / ws.length;
25215 var toSort = g.nodes().filter(function(u) { return bs[u] !== undefined; });
25216 toSort.sort(function(x, y) {
25217 return bs[x] - bs[y] || g.node(x).order - g.node(y).order;
25220 for (var i = 0, j = 0, jl = toSort.length; j < jl; ++i) {
25221 if (bs[ordering[i]] !== undefined) {
25222 g.node(toSort[j++]).order = i;
25227 // TOOD: re-enable constrained sorting once we have a strategy for handling
25228 // undefined barycenters.
25230 function sortLayerSubgraph(g, sg, cg, weights) {
25231 cg = cg ? cg.filterNodes(nodesFromList(g.children(sg))) : new Digraph();
25234 g.children(sg).forEach(function(u) {
25235 if (g.children(u).length) {
25236 nodeData[u] = sortLayerSubgraph(g, u, cg, weights);
25237 nodeData[u].firstSG = u;
25238 nodeData[u].lastSG = u;
25240 var ws = weights[u];
25243 barycenter: ws.length > 0 ? util.sum(ws) / ws.length : 0,
25249 resolveViolatedConstraints(g, cg, nodeData);
25251 var keys = Object.keys(nodeData);
25252 keys.sort(function(x, y) {
25253 return nodeData[x].barycenter - nodeData[y].barycenter;
25256 var result = keys.map(function(u) { return nodeData[u]; })
25257 .reduce(function(lhs, rhs) { return mergeNodeData(g, lhs, rhs); });
25262 function mergeNodeData(g, lhs, rhs) {
25263 var cg = mergeDigraphs(lhs.constraintGraph, rhs.constraintGraph);
25265 if (lhs.lastSG !== undefined && rhs.firstSG !== undefined) {
25266 if (cg === undefined) {
25267 cg = new Digraph();
25269 if (!cg.hasNode(lhs.lastSG)) { cg.addNode(lhs.lastSG); }
25270 cg.addNode(rhs.firstSG);
25271 cg.addEdge(null, lhs.lastSG, rhs.firstSG);
25275 degree: lhs.degree + rhs.degree,
25276 barycenter: (lhs.barycenter * lhs.degree + rhs.barycenter * rhs.degree) /
25277 (lhs.degree + rhs.degree),
25278 list: lhs.list.concat(rhs.list),
25279 firstSG: lhs.firstSG !== undefined ? lhs.firstSG : rhs.firstSG,
25280 lastSG: rhs.lastSG !== undefined ? rhs.lastSG : lhs.lastSG,
25281 constraintGraph: cg
25285 function mergeDigraphs(lhs, rhs) {
25286 if (lhs === undefined) return rhs;
25287 if (rhs === undefined) return lhs;
25290 rhs.nodes().forEach(function(u) { lhs.addNode(u); });
25291 rhs.edges().forEach(function(e, u, v) { lhs.addEdge(null, u, v); });
25295 function resolveViolatedConstraints(g, cg, nodeData) {
25296 // Removes nodes `u` and `v` from `cg` and makes any edges incident on them
25297 // incident on `w` instead.
25298 function collapseNodes(u, v, w) {
25299 // TODO original paper removes self loops, but it is not obvious when this would happen
25300 cg.inEdges(u).forEach(function(e) {
25302 cg.addEdge(null, cg.source(e), w);
25305 cg.outEdges(v).forEach(function(e) {
25307 cg.addEdge(null, w, cg.target(e));
25315 while ((violated = findViolatedConstraint(cg, nodeData)) !== undefined) {
25316 var source = cg.source(violated),
25317 target = cg.target(violated);
25320 while ((v = cg.addNode(null)) && g.hasNode(v)) {
25324 // Collapse barycenter and list
25325 nodeData[v] = mergeNodeData(g, nodeData[source], nodeData[target]);
25326 delete nodeData[source];
25327 delete nodeData[target];
25329 collapseNodes(source, target, v);
25330 if (cg.incidentEdges(v).length === 0) { cg.delNode(v); }
25334 function findViolatedConstraint(cg, nodeData) {
25335 var us = topsort(cg);
25336 for (var i = 0; i < us.length; ++i) {
25338 var inEdges = cg.inEdges(u);
25339 for (var j = 0; j < inEdges.length; ++j) {
25340 var e = inEdges[j];
25341 if (nodeData[cg.source(e)].barycenter >= nodeData[u].barycenter) {
25349 },{"../util":17}],9:[function(require,module,exports){
25350 var util = require('./util');
25353 * The algorithms here are based on Brandes and Köpf, "Fast and Simple
25354 * Horizontal Coordinate Assignment".
25356 module.exports = function() {
25357 // External configuration
25361 universalSep: null,
25367 self.nodeSep = util.propertyAccessor(self, config, 'nodeSep');
25368 self.edgeSep = util.propertyAccessor(self, config, 'edgeSep');
25369 // If not null this separation value is used for all nodes and edges
25370 // regardless of their widths. `nodeSep` and `edgeSep` are ignored with this
25372 self.universalSep = util.propertyAccessor(self, config, 'universalSep');
25373 self.rankSep = util.propertyAccessor(self, config, 'rankSep');
25374 self.debugLevel = util.propertyAccessor(self, config, 'debugLevel');
25381 g = g.filterNodes(util.filterNonSubgraphs(g));
25383 var layering = util.ordering(g);
25385 var conflicts = findConflicts(g, layering);
25388 ['u', 'd'].forEach(function(vertDir) {
25389 if (vertDir === 'd') layering.reverse();
25391 ['l', 'r'].forEach(function(horizDir) {
25392 if (horizDir === 'r') reverseInnerOrder(layering);
25394 var dir = vertDir + horizDir;
25395 var align = verticalAlignment(g, layering, conflicts, vertDir === 'u' ? 'predecessors' : 'successors');
25396 xss[dir]= horizontalCompaction(g, layering, align.pos, align.root, align.align);
25398 if (config.debugLevel >= 3)
25399 debugPositioning(vertDir + horizDir, g, layering, xss[dir]);
25401 if (horizDir === 'r') flipHorizontally(xss[dir]);
25403 if (horizDir === 'r') reverseInnerOrder(layering);
25406 if (vertDir === 'd') layering.reverse();
25409 balance(g, layering, xss);
25411 g.eachNode(function(v) {
25413 for (var alignment in xss) {
25414 var alignmentX = xss[alignment][v];
25415 posXDebug(alignment, g, v, alignmentX);
25416 xs.push(alignmentX);
25418 xs.sort(function(x, y) { return x - y; });
25419 posX(g, v, (xs[1] + xs[2]) / 2);
25422 // Align y coordinates with ranks
25423 var y = 0, reverseY = g.graph().rankDir === 'BT' || g.graph().rankDir === 'RL';
25424 layering.forEach(function(layer) {
25425 var maxHeight = util.max(layer.map(function(u) { return height(g, u); }));
25426 y += maxHeight / 2;
25427 layer.forEach(function(u) {
25428 posY(g, u, reverseY ? -y : y);
25430 y += maxHeight / 2 + config.rankSep;
25433 // Translate layout so that top left corner of bounding rectangle has
25434 // coordinate (0, 0).
25435 var minX = util.min(g.nodes().map(function(u) { return posX(g, u) - width(g, u) / 2; }));
25436 var minY = util.min(g.nodes().map(function(u) { return posY(g, u) - height(g, u) / 2; }));
25437 g.eachNode(function(u) {
25438 posX(g, u, posX(g, u) - minX);
25439 posY(g, u, posY(g, u) - minY);
25444 * Generate an ID that can be used to represent any undirected edge that is
25445 * incident on `u` and `v`.
25447 function undirEdgeId(u, v) {
25449 ? u.toString().length + ':' + u + '-' + v
25450 : v.toString().length + ':' + v + '-' + u;
25453 function findConflicts(g, layering) {
25454 var conflicts = {}, // Set of conflicting edge ids
25455 pos = {}, // Position of node in its layer
25458 k0, // Position of the last inner segment in the previous layer
25459 l, // Current position in the current layer (for iteration up to `l1`)
25460 k1; // Position of the next inner segment in the previous layer or
25461 // the position of the last element in the previous layer
25463 if (layering.length <= 2) return conflicts;
25465 function updateConflicts(v) {
25467 if (k < k0 || k > k1) {
25468 conflicts[undirEdgeId(currLayer[l], v)] = true;
25472 layering[1].forEach(function(u, i) { pos[u] = i; });
25473 for (var i = 1; i < layering.length - 1; ++i) {
25474 prevLayer = layering[i];
25475 currLayer = layering[i+1];
25479 // Scan current layer for next node that is incident to an inner segement
25480 // between layering[i+1] and layering[i].
25481 for (var l1 = 0; l1 < currLayer.length; ++l1) {
25482 var u = currLayer[l1]; // Next inner segment in the current layer or
25483 // last node in the current layer
25487 if (g.node(u).dummy) {
25488 var uPred = g.predecessors(u)[0];
25489 // Note: In the case of self loops and sideways edges it is possible
25490 // for a dummy not to have a predecessor.
25491 if (uPred !== undefined && g.node(uPred).dummy)
25494 if (k1 === undefined && l1 === currLayer.length - 1)
25495 k1 = prevLayer.length - 1;
25497 if (k1 !== undefined) {
25498 for (; l <= l1; ++l) {
25499 g.predecessors(currLayer[l]).forEach(updateConflicts);
25509 function verticalAlignment(g, layering, conflicts, relationship) {
25510 var pos = {}, // Position for a node in its layer
25511 root = {}, // Root of the block that the node participates in
25512 align = {}; // Points to the next node in the block or, if the last
25513 // element in the block, points to the first block's root
25515 layering.forEach(function(layer) {
25516 layer.forEach(function(u, i) {
25523 layering.forEach(function(layer) {
25525 layer.forEach(function(v) {
25526 var related = g[relationship](v), // Adjacent nodes from the previous layer
25527 mid; // The mid point in the related array
25529 if (related.length > 0) {
25530 related.sort(function(x, y) { return pos[x] - pos[y]; });
25531 mid = (related.length - 1) / 2;
25532 related.slice(Math.floor(mid), Math.ceil(mid) + 1).forEach(function(u) {
25533 if (align[v] === v) {
25534 if (!conflicts[undirEdgeId(u, v)] && prevIdx < pos[u]) {
25536 align[v] = root[v] = root[u];
25545 return { pos: pos, root: root, align: align };
25548 // This function deviates from the standard BK algorithm in two ways. First
25549 // it takes into account the size of the nodes. Second it includes a fix to
25550 // the original algorithm that is described in Carstens, "Node and Label
25551 // Placement in a Layered Layout Algorithm".
25552 function horizontalCompaction(g, layering, pos, root, align) {
25553 var sink = {}, // Mapping of node id -> sink node id for class
25554 maybeShift = {}, // Mapping of sink node id -> { class node id, min shift }
25555 shift = {}, // Mapping of sink node id -> shift
25556 pred = {}, // Mapping of node id -> predecessor node (or null)
25557 xs = {}; // Calculated X positions
25559 layering.forEach(function(layer) {
25560 layer.forEach(function(u, i) {
25562 maybeShift[u] = {};
25564 pred[u] = layer[i - 1];
25568 function updateShift(toShift, neighbor, delta) {
25569 if (!(neighbor in maybeShift[toShift])) {
25570 maybeShift[toShift][neighbor] = delta;
25572 maybeShift[toShift][neighbor] = Math.min(maybeShift[toShift][neighbor], delta);
25576 function placeBlock(v) {
25582 var u = root[pred[w]];
25584 if (sink[v] === v) {
25587 var delta = sep(g, pred[w]) + sep(g, w);
25588 if (sink[v] !== sink[u]) {
25589 updateShift(sink[u], sink[v], xs[v] - xs[u] - delta);
25591 xs[v] = Math.max(xs[v], xs[u] + delta);
25599 // Root coordinates relative to sink
25600 util.values(root).forEach(function(v) {
25604 // Absolute coordinates
25605 // There is an assumption here that we've resolved shifts for any classes
25606 // that begin at an earlier layer. We guarantee this by visiting layers in
25608 layering.forEach(function(layer) {
25609 layer.forEach(function(v) {
25610 xs[v] = xs[root[v]];
25611 if (v === root[v] && v === sink[v]) {
25613 if (v in maybeShift && Object.keys(maybeShift[v]).length > 0) {
25614 minShift = util.min(Object.keys(maybeShift[v])
25616 return maybeShift[v][u] + (u in shift ? shift[u] : 0);
25620 shift[v] = minShift;
25625 layering.forEach(function(layer) {
25626 layer.forEach(function(v) {
25627 xs[v] += shift[sink[root[v]]] || 0;
25634 function findMinCoord(g, layering, xs) {
25635 return util.min(layering.map(function(layer) {
25641 function findMaxCoord(g, layering, xs) {
25642 return util.max(layering.map(function(layer) {
25643 var u = layer[layer.length - 1];
25648 function balance(g, layering, xss) {
25649 var min = {}, // Min coordinate for the alignment
25650 max = {}, // Max coordinate for the alginment
25652 shift = {}; // Amount to shift a given alignment
25654 function updateAlignment(v) {
25655 xss[alignment][v] += shift[alignment];
25658 var smallest = Number.POSITIVE_INFINITY;
25659 for (var alignment in xss) {
25660 var xs = xss[alignment];
25661 min[alignment] = findMinCoord(g, layering, xs);
25662 max[alignment] = findMaxCoord(g, layering, xs);
25663 var w = max[alignment] - min[alignment];
25664 if (w < smallest) {
25666 smallestAlignment = alignment;
25670 // Determine how much to adjust positioning for each alignment
25671 ['u', 'd'].forEach(function(vertDir) {
25672 ['l', 'r'].forEach(function(horizDir) {
25673 var alignment = vertDir + horizDir;
25674 shift[alignment] = horizDir === 'l'
25675 ? min[smallestAlignment] - min[alignment]
25676 : max[smallestAlignment] - max[alignment];
25680 // Find average of medians for xss array
25681 for (alignment in xss) {
25682 g.eachNode(updateAlignment);
25686 function flipHorizontally(xs) {
25687 for (var u in xs) {
25692 function reverseInnerOrder(layering) {
25693 layering.forEach(function(layer) {
25698 function width(g, u) {
25699 switch (g.graph().rankDir) {
25700 case 'LR': return g.node(u).height;
25701 case 'RL': return g.node(u).height;
25702 default: return g.node(u).width;
25706 function height(g, u) {
25707 switch(g.graph().rankDir) {
25708 case 'LR': return g.node(u).width;
25709 case 'RL': return g.node(u).width;
25710 default: return g.node(u).height;
25714 function sep(g, u) {
25715 if (config.universalSep !== null) {
25716 return config.universalSep;
25718 var w = width(g, u);
25719 var s = g.node(u).dummy ? config.edgeSep : config.nodeSep;
25720 return (w + s) / 2;
25723 function posX(g, u, x) {
25724 if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') {
25725 if (arguments.length < 3) {
25726 return g.node(u).y;
25731 if (arguments.length < 3) {
25732 return g.node(u).x;
25739 function posXDebug(name, g, u, x) {
25740 if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') {
25741 if (arguments.length < 3) {
25742 return g.node(u)[name];
25744 g.node(u)[name] = x;
25747 if (arguments.length < 3) {
25748 return g.node(u)[name];
25750 g.node(u)[name] = x;
25755 function posY(g, u, y) {
25756 if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') {
25757 if (arguments.length < 3) {
25758 return g.node(u).x;
25763 if (arguments.length < 3) {
25764 return g.node(u).y;
25771 function debugPositioning(align, g, layering, xs) {
25772 layering.forEach(function(l, li) {
25774 l.forEach(function(v) {
25777 var s = sep(g, u) + sep(g, v);
25779 console.log('Position phase: sep violation. Align: ' + align + '. Layer: ' + li + '. ' +
25780 'U: ' + u + ' V: ' + v + '. Actual sep: ' + (xV - xU) + ' Expected sep: ' + s);
25789 },{"./util":17}],10:[function(require,module,exports){
25790 var util = require('./util'),
25791 acyclic = require('./rank/acyclic'),
25792 initRank = require('./rank/initRank'),
25793 feasibleTree = require('./rank/feasibleTree'),
25794 constraints = require('./rank/constraints'),
25795 simplex = require('./rank/simplex'),
25796 components = require('graphlib').alg.components,
25797 filter = require('graphlib').filter;
25800 exports.restoreEdges = restoreEdges;
25803 * Heuristic function that assigns a rank to each node of the input graph with
25804 * the intent of minimizing edge lengths, while respecting the `minLen`
25805 * attribute of incident edges.
25809 * * Each edge in the input graph must have an assigned 'minLen' attribute
25811 function run(g, useSimplex) {
25812 expandSelfLoops(g);
25814 // If there are rank constraints on nodes, then build a new graph that
25815 // encodes the constraints.
25816 util.time('constraints.apply', constraints.apply)(g);
25818 expandSidewaysEdges(g);
25820 // Reverse edges to get an acyclic graph, we keep the graph in an acyclic
25821 // state until the very end.
25822 util.time('acyclic', acyclic)(g);
25824 // Convert the graph into a flat graph for ranking
25825 var flatGraph = g.filterNodes(util.filterNonSubgraphs(g));
25827 // Assign an initial ranking using DFS.
25828 initRank(flatGraph);
25830 // For each component improve the assigned ranks.
25831 components(flatGraph).forEach(function(cmpt) {
25832 var subgraph = flatGraph.filterNodes(filter.nodesFromList(cmpt));
25833 rankComponent(subgraph, useSimplex);
25836 // Relax original constraints
25837 util.time('constraints.relax', constraints.relax(g));
25839 // When handling nodes with constrained ranks it is possible to end up with
25840 // edges that point to previous ranks. Most of the subsequent algorithms assume
25841 // that edges are pointing to successive ranks only. Here we reverse any "back
25842 // edges" and mark them as such. The acyclic algorithm will reverse them as a
25843 // post processing step.
25844 util.time('reorientEdges', reorientEdges)(g);
25847 function restoreEdges(g) {
25852 * Expand self loops into three dummy nodes. One will sit above the incident
25853 * node, one will be at the same level, and one below. The result looks like:
25859 * Dummy nodes x, y, z give us the shape of a loop and node y is where we place
25862 * TODO: consolidate knowledge of dummy node construction.
25863 * TODO: support minLen = 2
25865 function expandSelfLoops(g) {
25866 g.eachEdge(function(e, u, v, a) {
25868 var x = addDummyNode(g, e, u, v, a, 0, false),
25869 y = addDummyNode(g, e, u, v, a, 1, true),
25870 z = addDummyNode(g, e, u, v, a, 2, false);
25871 g.addEdge(null, x, u, {minLen: 1, selfLoop: true});
25872 g.addEdge(null, x, y, {minLen: 1, selfLoop: true});
25873 g.addEdge(null, u, z, {minLen: 1, selfLoop: true});
25874 g.addEdge(null, y, z, {minLen: 1, selfLoop: true});
25880 function expandSidewaysEdges(g) {
25881 g.eachEdge(function(e, u, v, a) {
25883 var origEdge = a.originalEdge,
25884 dummy = addDummyNode(g, origEdge.e, origEdge.u, origEdge.v, origEdge.value, 0, true);
25885 g.addEdge(null, u, dummy, {minLen: 1});
25886 g.addEdge(null, dummy, v, {minLen: 1});
25892 function addDummyNode(g, e, u, v, a, index, isLabel) {
25893 return g.addNode(null, {
25894 width: isLabel ? a.width : 0,
25895 height: isLabel ? a.height : 0,
25896 edge: { id: e, source: u, target: v, attrs: a },
25902 function reorientEdges(g) {
25903 g.eachEdge(function(e, u, v, value) {
25904 if (g.node(u).rank > g.node(v).rank) {
25906 value.reversed = true;
25907 g.addEdge(e, v, u, value);
25912 function rankComponent(subgraph, useSimplex) {
25913 var spanningTree = feasibleTree(subgraph);
25916 util.log(1, 'Using network simplex for ranking');
25917 simplex(subgraph, spanningTree);
25919 normalize(subgraph);
25922 function normalize(g) {
25923 var m = util.min(g.nodes().map(function(u) { return g.node(u).rank; }));
25924 g.eachNode(function(u, node) { node.rank -= m; });
25927 },{"./rank/acyclic":11,"./rank/constraints":12,"./rank/feasibleTree":13,"./rank/initRank":14,"./rank/simplex":16,"./util":17,"graphlib":24}],11:[function(require,module,exports){
25928 var util = require('../util');
25930 module.exports = acyclic;
25931 module.exports.undo = undo;
25934 * This function takes a directed graph that may have cycles and reverses edges
25935 * as appropriate to break these cycles. Each reversed edge is assigned a
25936 * `reversed` attribute with the value `true`.
25938 * There should be no self loops in the graph.
25940 function acyclic(g) {
25946 if (u in visited) return;
25947 visited[u] = onStack[u] = true;
25948 g.outEdges(u).forEach(function(e) {
25949 var t = g.target(e),
25953 console.error('Warning: found self loop "' + e + '" for node "' + u + '"');
25954 } else if (t in onStack) {
25957 value.reversed = true;
25959 g.addEdge(e, t, u, value);
25968 g.eachNode(function(u) { dfs(u); });
25970 util.log(2, 'Acyclic Phase: reversed ' + reverseCount + ' edge(s)');
25972 return reverseCount;
25976 * Given a graph that has had the acyclic operation applied, this function
25977 * undoes that operation. More specifically, any edge with the `reversed`
25978 * attribute is again reversed to restore the original direction of the edge.
25981 g.eachEdge(function(e, s, t, a) {
25985 g.addEdge(e, t, s, a);
25990 },{"../util":17}],12:[function(require,module,exports){
25991 exports.apply = function(g) {
25994 g.children(sg).forEach(function(u) {
25995 if (g.children(u).length) {
26000 var value = g.node(u),
26001 prefRank = value.prefRank;
26002 if (prefRank !== undefined) {
26003 if (!checkSupportedPrefRank(prefRank)) { return; }
26005 if (!(prefRank in rankSets)) {
26006 rankSets.prefRank = [u];
26008 rankSets.prefRank.push(u);
26011 var newU = rankSets[prefRank];
26012 if (newU === undefined) {
26013 newU = rankSets[prefRank] = g.addNode(null, { originalNodes: [] });
26014 g.parent(newU, sg);
26017 redirectInEdges(g, u, newU, prefRank === 'min');
26018 redirectOutEdges(g, u, newU, prefRank === 'max');
26020 // Save original node and remove it from reduced graph
26021 g.node(newU).originalNodes.push({ u: u, value: value, parent: sg });
26026 addLightEdgesFromMinNode(g, sg, rankSets.min);
26027 addLightEdgesToMaxNode(g, sg, rankSets.max);
26033 function checkSupportedPrefRank(prefRank) {
26034 if (prefRank !== 'min' && prefRank !== 'max' && prefRank.indexOf('same_') !== 0) {
26035 console.error('Unsupported rank type: ' + prefRank);
26041 function redirectInEdges(g, u, newU, reverse) {
26042 g.inEdges(u).forEach(function(e) {
26043 var origValue = g.edge(e),
26045 if (origValue.originalEdge) {
26049 originalEdge: { e: e, u: g.source(e), v: g.target(e), value: origValue },
26050 minLen: g.edge(e).minLen
26054 // Do not reverse edges for self-loops.
26055 if (origValue.selfLoop) {
26060 // Ensure that all edges to min are reversed
26061 g.addEdge(null, newU, g.source(e), value);
26062 value.reversed = true;
26064 g.addEdge(null, g.source(e), newU, value);
26069 function redirectOutEdges(g, u, newU, reverse) {
26070 g.outEdges(u).forEach(function(e) {
26071 var origValue = g.edge(e),
26073 if (origValue.originalEdge) {
26077 originalEdge: { e: e, u: g.source(e), v: g.target(e), value: origValue },
26078 minLen: g.edge(e).minLen
26082 // Do not reverse edges for self-loops.
26083 if (origValue.selfLoop) {
26088 // Ensure that all edges from max are reversed
26089 g.addEdge(null, g.target(e), newU, value);
26090 value.reversed = true;
26092 g.addEdge(null, newU, g.target(e), value);
26097 function addLightEdgesFromMinNode(g, sg, minNode) {
26098 if (minNode !== undefined) {
26099 g.children(sg).forEach(function(u) {
26100 // The dummy check ensures we don't add an edge if the node is involved
26101 // in a self loop or sideways edge.
26102 if (u !== minNode && !g.outEdges(minNode, u).length && !g.node(u).dummy) {
26103 g.addEdge(null, minNode, u, { minLen: 0 });
26109 function addLightEdgesToMaxNode(g, sg, maxNode) {
26110 if (maxNode !== undefined) {
26111 g.children(sg).forEach(function(u) {
26112 // The dummy check ensures we don't add an edge if the node is involved
26113 // in a self loop or sideways edge.
26114 if (u !== maxNode && !g.outEdges(u, maxNode).length && !g.node(u).dummy) {
26115 g.addEdge(null, u, maxNode, { minLen: 0 });
26122 * This function "relaxes" the constraints applied previously by the "apply"
26123 * function. It expands any nodes that were collapsed and assigns the rank of
26124 * the collapsed node to each of the expanded nodes. It also restores the
26125 * original edges and removes any dummy edges pointing at the collapsed nodes.
26127 * Note that the process of removing collapsed nodes also removes dummy edges
26130 exports.relax = function(g) {
26131 // Save original edges
26132 var originalEdges = [];
26133 g.eachEdge(function(e, u, v, value) {
26134 var originalEdge = value.originalEdge;
26135 if (originalEdge) {
26136 originalEdges.push(originalEdge);
26140 // Expand collapsed nodes
26141 g.eachNode(function(u, value) {
26142 var originalNodes = value.originalNodes;
26143 if (originalNodes) {
26144 originalNodes.forEach(function(originalNode) {
26145 originalNode.value.rank = value.rank;
26146 g.addNode(originalNode.u, originalNode.value);
26147 g.parent(originalNode.u, originalNode.parent);
26153 // Restore original edges
26154 originalEdges.forEach(function(edge) {
26155 g.addEdge(edge.e, edge.u, edge.v, edge.value);
26159 },{}],13:[function(require,module,exports){
26161 var Set = require('cp-data').Set,
26163 Digraph = require('graphlib').Digraph,
26164 util = require('../util');
26166 module.exports = feasibleTree;
26169 * Given an acyclic graph with each node assigned a `rank` attribute, this
26170 * function constructs and returns a spanning tree. This function may reduce
26171 * the length of some edges from the initial rank assignment while maintaining
26172 * the `minLen` specified by each edge.
26176 * * The input graph is acyclic
26177 * * Each node in the input graph has an assigned `rank` attribute
26178 * * Each edge in the input graph has an assigned `minLen` attribute
26182 * A feasible spanning tree for the input graph (i.e. a spanning tree that
26183 * respects each graph edge's `minLen` attribute) represented as a Digraph with
26184 * a `root` attribute on graph.
26186 * Nodes have the same id and value as that in the input graph.
26188 * Edges in the tree have arbitrarily assigned ids. The attributes for edges
26189 * include `reversed`. `reversed` indicates that the edge is a
26190 * back edge in the input graph.
26192 function feasibleTree(g) {
26193 var remaining = new Set(g.nodes()),
26194 tree = new Digraph();
26196 if (remaining.size() === 1) {
26197 var root = g.nodes()[0];
26198 tree.addNode(root, {});
26199 tree.graph({ root: root });
26203 function addTightEdges(v) {
26204 var continueToScan = true;
26205 g.predecessors(v).forEach(function(u) {
26206 if (remaining.has(u) && !slack(g, u, v)) {
26207 if (remaining.has(v)) {
26208 tree.addNode(v, {});
26209 remaining.remove(v);
26210 tree.graph({ root: v });
26213 tree.addNode(u, {});
26214 tree.addEdge(null, u, v, { reversed: true });
26215 remaining.remove(u);
26217 continueToScan = false;
26221 g.successors(v).forEach(function(w) {
26222 if (remaining.has(w) && !slack(g, v, w)) {
26223 if (remaining.has(v)) {
26224 tree.addNode(v, {});
26225 remaining.remove(v);
26226 tree.graph({ root: v });
26229 tree.addNode(w, {});
26230 tree.addEdge(null, v, w, {});
26231 remaining.remove(w);
26233 continueToScan = false;
26236 return continueToScan;
26239 function createTightEdge() {
26240 var minSlack = Number.MAX_VALUE;
26241 remaining.keys().forEach(function(v) {
26242 g.predecessors(v).forEach(function(u) {
26243 if (!remaining.has(u)) {
26244 var edgeSlack = slack(g, u, v);
26245 if (Math.abs(edgeSlack) < Math.abs(minSlack)) {
26246 minSlack = -edgeSlack;
26251 g.successors(v).forEach(function(w) {
26252 if (!remaining.has(w)) {
26253 var edgeSlack = slack(g, v, w);
26254 if (Math.abs(edgeSlack) < Math.abs(minSlack)) {
26255 minSlack = edgeSlack;
26261 tree.eachNode(function(u) { g.node(u).rank -= minSlack; });
26264 while (remaining.size()) {
26265 var nodesToSearch = !tree.order() ? remaining.keys() : tree.nodes();
26266 for (var i = 0, il = nodesToSearch.length;
26267 i < il && addTightEdges(nodesToSearch[i]);
26269 if (remaining.size()) {
26277 function slack(g, u, v) {
26278 var rankDiff = g.node(v).rank - g.node(u).rank;
26279 var maxMinLen = util.max(g.outEdges(u, v)
26280 .map(function(e) { return g.edge(e).minLen; }));
26281 return rankDiff - maxMinLen;
26284 },{"../util":17,"cp-data":19,"graphlib":24}],14:[function(require,module,exports){
26285 var util = require('../util'),
26286 topsort = require('graphlib').alg.topsort;
26288 module.exports = initRank;
26291 * Assigns a `rank` attribute to each node in the input graph and ensures that
26292 * this rank respects the `minLen` attribute of incident edges.
26296 * * The input graph must be acyclic
26297 * * Each edge in the input graph must have an assigned 'minLen' attribute
26299 function initRank(g) {
26300 var sorted = topsort(g);
26302 sorted.forEach(function(u) {
26303 var inEdges = g.inEdges(u);
26304 if (inEdges.length === 0) {
26305 g.node(u).rank = 0;
26309 var minLens = inEdges.map(function(e) {
26310 return g.node(g.source(e)).rank + g.edge(e).minLen;
26312 g.node(u).rank = util.max(minLens);
26316 },{"../util":17,"graphlib":24}],15:[function(require,module,exports){
26322 * A helper to calculate the slack between two nodes (`u` and `v`) given a
26323 * `minLen` constraint. The slack represents how much the distance between `u`
26324 * and `v` could shrink while maintaining the `minLen` constraint. If the value
26325 * is negative then the constraint is currently violated.
26327 This function requires that `u` and `v` are in `graph` and they both have a
26330 function slack(graph, u, v, minLen) {
26331 return Math.abs(graph.node(u).rank - graph.node(v).rank) - minLen;
26334 },{}],16:[function(require,module,exports){
26335 var util = require('../util'),
26336 rankUtil = require('./rankUtil');
26338 module.exports = simplex;
26340 function simplex(graph, spanningTree) {
26341 // The network simplex algorithm repeatedly replaces edges of
26342 // the spanning tree with negative cut values until no such
26344 initCutValues(graph, spanningTree);
26346 var e = leaveEdge(spanningTree);
26347 if (e === null) break;
26348 var f = enterEdge(graph, spanningTree, e);
26349 exchange(graph, spanningTree, e, f);
26354 * Set the cut values of edges in the spanning tree by a depth-first
26355 * postorder traversal. The cut value corresponds to the cost, in
26356 * terms of a ranking's edge length sum, of lengthening an edge.
26357 * Negative cut values typically indicate edges that would yield a
26358 * smaller edge length sum if they were lengthened.
26360 function initCutValues(graph, spanningTree) {
26361 computeLowLim(spanningTree);
26363 spanningTree.eachEdge(function(id, u, v, treeValue) {
26364 treeValue.cutValue = 0;
26367 // Propagate cut values up the tree.
26369 var children = spanningTree.successors(n);
26370 for (var c in children) {
26371 var child = children[c];
26374 if (n !== spanningTree.graph().root) {
26375 setCutValue(graph, spanningTree, n);
26378 dfs(spanningTree.graph().root);
26382 * Perform a DFS postorder traversal, labeling each node v with
26383 * its traversal order 'lim(v)' and the minimum traversal number
26384 * of any of its descendants 'low(v)'. This provides an efficient
26385 * way to test whether u is an ancestor of v since
26386 * low(u) <= lim(v) <= lim(u) if and only if u is an ancestor.
26388 function computeLowLim(tree) {
26389 var postOrderNum = 0;
26392 var children = tree.successors(n);
26393 var low = postOrderNum;
26394 for (var c in children) {
26395 var child = children[c];
26397 low = Math.min(low, tree.node(child).low);
26399 tree.node(n).low = low;
26400 tree.node(n).lim = postOrderNum++;
26403 dfs(tree.graph().root);
26407 * To compute the cut value of the edge parent -> child, we consider
26408 * it and any other graph edges to or from the child.
26415 function setCutValue(graph, tree, child) {
26416 var parentEdge = tree.inEdges(child)[0];
26418 // List of child's children in the spanning tree.
26419 var grandchildren = [];
26420 var grandchildEdges = tree.outEdges(child);
26421 for (var gce in grandchildEdges) {
26422 grandchildren.push(tree.target(grandchildEdges[gce]));
26427 // TODO: Replace unit increment/decrement with edge weights.
26428 var E = 0; // Edges from child to grandchild's subtree.
26429 var F = 0; // Edges to child from grandchild's subtree.
26430 var G = 0; // Edges from child to nodes outside of child's subtree.
26431 var H = 0; // Edges from nodes outside of child's subtree to child.
26433 // Consider all graph edges from child.
26434 var outEdges = graph.outEdges(child);
26436 for (var oe in outEdges) {
26437 var succ = graph.target(outEdges[oe]);
26438 for (gc in grandchildren) {
26439 if (inSubtree(tree, succ, grandchildren[gc])) {
26443 if (!inSubtree(tree, succ, child)) {
26448 // Consider all graph edges to child.
26449 var inEdges = graph.inEdges(child);
26450 for (var ie in inEdges) {
26451 var pred = graph.source(inEdges[ie]);
26452 for (gc in grandchildren) {
26453 if (inSubtree(tree, pred, grandchildren[gc])) {
26457 if (!inSubtree(tree, pred, child)) {
26462 // Contributions depend on the alignment of the parent -> child edge
26463 // and the child -> u or v edges.
26464 var grandchildCutSum = 0;
26465 for (gc in grandchildren) {
26466 var cv = tree.edge(grandchildEdges[gc]).cutValue;
26467 if (!tree.edge(grandchildEdges[gc]).reversed) {
26468 grandchildCutSum += cv;
26470 grandchildCutSum -= cv;
26474 if (!tree.edge(parentEdge).reversed) {
26475 cutValue += grandchildCutSum - E + F - G + H;
26477 cutValue -= grandchildCutSum - E + F - G + H;
26480 tree.edge(parentEdge).cutValue = cutValue;
26484 * Return whether n is a node in the subtree with the given
26487 function inSubtree(tree, n, root) {
26488 return (tree.node(root).low <= tree.node(n).lim &&
26489 tree.node(n).lim <= tree.node(root).lim);
26493 * Return an edge from the tree with a negative cut value, or null if there
26496 function leaveEdge(tree) {
26497 var edges = tree.edges();
26498 for (var n in edges) {
26500 var treeValue = tree.edge(e);
26501 if (treeValue.cutValue < 0) {
26509 * The edge e should be an edge in the tree, with an underlying edge
26510 * in the graph, with a negative cut value. Of the two nodes incident
26511 * on the edge, take the lower one. enterEdge returns an edge with
26512 * minimum slack going from outside of that node's subtree to inside
26513 * of that node's subtree.
26515 function enterEdge(graph, tree, e) {
26516 var source = tree.source(e);
26517 var target = tree.target(e);
26518 var lower = tree.node(target).lim < tree.node(source).lim ? target : source;
26520 // Is the tree edge aligned with the graph edge?
26521 var aligned = !tree.edge(e).reversed;
26523 var minSlack = Number.POSITIVE_INFINITY;
26526 graph.eachEdge(function(id, u, v, value) {
26527 if (id !== e && inSubtree(tree, u, lower) && !inSubtree(tree, v, lower)) {
26528 var slack = rankUtil.slack(graph, u, v, value.minLen);
26529 if (slack < minSlack) {
26536 graph.eachEdge(function(id, u, v, value) {
26537 if (id !== e && !inSubtree(tree, u, lower) && inSubtree(tree, v, lower)) {
26538 var slack = rankUtil.slack(graph, u, v, value.minLen);
26539 if (slack < minSlack) {
26547 if (minSlackEdge === undefined) {
26550 graph.eachNode(function(id) {
26551 if (!inSubtree(tree, id, lower)) {
26557 throw new Error('No edge found from outside of tree to inside');
26560 return minSlackEdge;
26564 * Replace edge e with edge f in the tree, recalculating the tree root,
26565 * the nodes' low and lim properties and the edges' cut values.
26567 function exchange(graph, tree, e, f) {
26569 var source = graph.source(f);
26570 var target = graph.target(f);
26572 // Redirect edges so that target is the root of its subtree.
26573 function redirect(v) {
26574 var edges = tree.inEdges(v);
26575 for (var i in edges) {
26577 var u = tree.source(e);
26578 var value = tree.edge(e);
26581 value.reversed = !value.reversed;
26582 tree.addEdge(e, v, u, value);
26589 var edges = tree.inEdges(root);
26590 while (edges.length > 0) {
26591 root = tree.source(edges[0]);
26592 edges = tree.inEdges(root);
26595 tree.graph().root = root;
26597 tree.addEdge(null, source, target, {cutValue: 0});
26599 initCutValues(graph, tree);
26601 adjustRanks(graph, tree);
26605 * Reset the ranks of all nodes based on the current spanning tree.
26606 * The rank of the tree's root remains unchanged, while all other
26607 * nodes are set to the sum of minimum length constraints along
26608 * the path from the root.
26610 function adjustRanks(graph, tree) {
26612 var children = tree.successors(p);
26613 children.forEach(function(c) {
26614 var minLen = minimumLength(graph, p, c);
26615 graph.node(c).rank = graph.node(p).rank + minLen;
26620 dfs(tree.graph().root);
26624 * If u and v are connected by some edges in the graph, return the
26625 * minimum length of those edges, as a positive number if v succeeds
26626 * u and as a negative number if v precedes u.
26628 function minimumLength(graph, u, v) {
26629 var outEdges = graph.outEdges(u, v);
26630 if (outEdges.length > 0) {
26631 return util.max(outEdges.map(function(e) {
26632 return graph.edge(e).minLen;
26636 var inEdges = graph.inEdges(u, v);
26637 if (inEdges.length > 0) {
26638 return -util.max(inEdges.map(function(e) {
26639 return graph.edge(e).minLen;
26644 },{"../util":17,"./rankUtil":15}],17:[function(require,module,exports){
26646 * Returns the smallest value in the array.
26648 exports.min = function(values) {
26649 return Math.min.apply(Math, values);
26653 * Returns the largest value in the array.
26655 exports.max = function(values) {
26656 return Math.max.apply(Math, values);
26660 * Returns `true` only if `f(x)` is `true` for all `x` in `xs`. Otherwise
26661 * returns `false`. This function will return immediately if it finds a
26662 * case where `f(x)` does not hold.
26664 exports.all = function(xs, f) {
26665 for (var i = 0; i < xs.length; ++i) {
26674 * Accumulates the sum of elements in the given array using the `+` operator.
26676 exports.sum = function(values) {
26677 return values.reduce(function(acc, x) { return acc + x; }, 0);
26681 * Returns an array of all values in the given object.
26683 exports.values = function(obj) {
26684 return Object.keys(obj).map(function(k) { return obj[k]; });
26687 exports.shuffle = function(array) {
26688 for (i = array.length - 1; i > 0; --i) {
26689 var j = Math.floor(Math.random() * (i + 1));
26691 array[j] = array[i];
26696 exports.propertyAccessor = function(self, config, field, setHook) {
26697 return function(x) {
26698 if (!arguments.length) return config[field];
26700 if (setHook) setHook(x);
26706 * Given a layered, directed graph with `rank` and `order` node attributes,
26707 * this function returns an array of ordered ranks. Each rank contains an array
26708 * of the ids of the nodes in that rank in the order specified by the `order`
26711 exports.ordering = function(g) {
26713 g.eachNode(function(u, value) {
26714 var rank = ordering[value.rank] || (ordering[value.rank] = []);
26715 rank[value.order] = u;
26721 * A filter that can be used with `filterNodes` to get a graph that only
26722 * includes nodes that do not contain others nodes.
26724 exports.filterNonSubgraphs = function(g) {
26725 return function(u) {
26726 return g.children(u).length === 0;
26731 * Returns a new function that wraps `func` with a timer. The wrapper logs the
26732 * time it takes to execute the function.
26734 * The timer will be enabled provided `log.level >= 1`.
26736 function time(name, func) {
26737 return function() {
26738 var start = new Date().getTime();
26740 return func.apply(null, arguments);
26742 log(1, name + ' time: ' + (new Date().getTime() - start) + 'ms');
26746 time.enabled = false;
26748 exports.time = time;
26751 * A global logger with the specification `log(level, message, ...)` that
26752 * will log a message to the console if `log.level >= level`.
26754 function log(level) {
26755 if (log.level >= level) {
26756 console.log.apply(console, Array.prototype.slice.call(arguments, 1));
26763 },{}],18:[function(require,module,exports){
26764 module.exports = '0.4.5';
26766 },{}],19:[function(require,module,exports){
26767 exports.Set = require('./lib/Set');
26768 exports.PriorityQueue = require('./lib/PriorityQueue');
26769 exports.version = require('./lib/version');
26771 },{"./lib/PriorityQueue":20,"./lib/Set":21,"./lib/version":23}],20:[function(require,module,exports){
26772 module.exports = PriorityQueue;
26775 * A min-priority queue data structure. This algorithm is derived from Cormen,
26776 * et al., "Introduction to Algorithms". The basic idea of a min-priority
26777 * queue is that you can efficiently (in O(1) time) get the smallest key in
26778 * the queue. Adding and removing elements takes O(log n) time. A key can
26779 * have its priority decreased in O(log n) time.
26781 function PriorityQueue() {
26783 this._keyIndices = {};
26787 * Returns the number of elements in the queue. Takes `O(1)` time.
26789 PriorityQueue.prototype.size = function() {
26790 return this._arr.length;
26794 * Returns the keys that are in the queue. Takes `O(n)` time.
26796 PriorityQueue.prototype.keys = function() {
26797 return this._arr.map(function(x) { return x.key; });
26801 * Returns `true` if **key** is in the queue and `false` if not.
26803 PriorityQueue.prototype.has = function(key) {
26804 return key in this._keyIndices;
26808 * Returns the priority for **key**. If **key** is not present in the queue
26809 * then this function returns `undefined`. Takes `O(1)` time.
26811 * @param {Object} key
26813 PriorityQueue.prototype.priority = function(key) {
26814 var index = this._keyIndices[key];
26815 if (index !== undefined) {
26816 return this._arr[index].priority;
26821 * Returns the key for the minimum element in this queue. If the queue is
26822 * empty this function throws an Error. Takes `O(1)` time.
26824 PriorityQueue.prototype.min = function() {
26825 if (this.size() === 0) {
26826 throw new Error("Queue underflow");
26828 return this._arr[0].key;
26832 * Inserts a new key into the priority queue. If the key already exists in
26833 * the queue this function returns `false`; otherwise it will return `true`.
26834 * Takes `O(n)` time.
26836 * @param {Object} key the key to add
26837 * @param {Number} priority the initial priority for the key
26839 PriorityQueue.prototype.add = function(key, priority) {
26840 var keyIndices = this._keyIndices;
26841 if (!(key in keyIndices)) {
26842 var arr = this._arr;
26843 var index = arr.length;
26844 keyIndices[key] = index;
26845 arr.push({key: key, priority: priority});
26846 this._decrease(index);
26853 * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
26855 PriorityQueue.prototype.removeMin = function() {
26856 this._swap(0, this._arr.length - 1);
26857 var min = this._arr.pop();
26858 delete this._keyIndices[min.key];
26864 * Decreases the priority for **key** to **priority**. If the new priority is
26865 * greater than the previous priority, this function will throw an Error.
26867 * @param {Object} key the key for which to raise priority
26868 * @param {Number} priority the new priority for the key
26870 PriorityQueue.prototype.decrease = function(key, priority) {
26871 var index = this._keyIndices[key];
26872 if (priority > this._arr[index].priority) {
26873 throw new Error("New priority is greater than current priority. " +
26874 "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
26876 this._arr[index].priority = priority;
26877 this._decrease(index);
26880 PriorityQueue.prototype._heapify = function(i) {
26881 var arr = this._arr;
26885 if (l < arr.length) {
26886 largest = arr[l].priority < arr[largest].priority ? l : largest;
26887 if (r < arr.length) {
26888 largest = arr[r].priority < arr[largest].priority ? r : largest;
26890 if (largest !== i) {
26891 this._swap(i, largest);
26892 this._heapify(largest);
26897 PriorityQueue.prototype._decrease = function(index) {
26898 var arr = this._arr;
26899 var priority = arr[index].priority;
26901 while (index !== 0) {
26902 parent = index >> 1;
26903 if (arr[parent].priority < priority) {
26906 this._swap(index, parent);
26911 PriorityQueue.prototype._swap = function(i, j) {
26912 var arr = this._arr;
26913 var keyIndices = this._keyIndices;
26914 var origArrI = arr[i];
26915 var origArrJ = arr[j];
26918 keyIndices[origArrJ.key] = i;
26919 keyIndices[origArrI.key] = j;
26922 },{}],21:[function(require,module,exports){
26923 var util = require('./util');
26925 module.exports = Set;
26928 * Constructs a new Set with an optional set of `initialKeys`.
26930 * It is important to note that keys are coerced to String for most purposes
26931 * with this object, similar to the behavior of JavaScript's Object. For
26932 * example, the following will add only one key:
26934 * var s = new Set();
26938 * However, the type of the key is preserved internally so that `keys` returns
26939 * the original key set uncoerced. For the above example, `keys` would return
26942 function Set(initialKeys) {
26947 for (var i = 0, il = initialKeys.length; i < il; ++i) {
26948 this.add(initialKeys[i]);
26954 * Returns a new Set that represents the set intersection of the array of given
26957 Set.intersect = function(sets) {
26958 if (sets.length === 0) {
26962 var result = new Set(!util.isArray(sets[0]) ? sets[0].keys() : sets[0]);
26963 for (var i = 1, il = sets.length; i < il; ++i) {
26964 var resultKeys = result.keys(),
26965 other = !util.isArray(sets[i]) ? sets[i] : new Set(sets[i]);
26966 for (var j = 0, jl = resultKeys.length; j < jl; ++j) {
26967 var key = resultKeys[j];
26968 if (!other.has(key)) {
26969 result.remove(key);
26978 * Returns a new Set that represents the set union of the array of given sets.
26980 Set.union = function(sets) {
26981 var totalElems = util.reduce(sets, function(lhs, rhs) {
26982 return lhs + (rhs.size ? rhs.size() : rhs.length);
26984 var arr = new Array(totalElems);
26987 for (var i = 0, il = sets.length; i < il; ++i) {
26989 keys = !util.isArray(cur) ? cur.keys() : cur;
26990 for (var j = 0, jl = keys.length; j < jl; ++j) {
26991 arr[k++] = keys[j];
26995 return new Set(arr);
26999 * Returns the size of this set in `O(1)` time.
27001 Set.prototype.size = function() {
27006 * Returns the keys in this set. Takes `O(n)` time.
27008 Set.prototype.keys = function() {
27009 return values(this._keys);
27013 * Tests if a key is present in this Set. Returns `true` if it is and `false`
27014 * if not. Takes `O(1)` time.
27016 Set.prototype.has = function(key) {
27017 return key in this._keys;
27021 * Adds a new key to this Set if it is not already present. Returns `true` if
27022 * the key was added and `false` if it was already present. Takes `O(1)` time.
27024 Set.prototype.add = function(key) {
27025 if (!(key in this._keys)) {
27026 this._keys[key] = key;
27034 * Removes a key from this Set. If the key was removed this function returns
27035 * `true`. If not, it returns `false`. Takes `O(1)` time.
27037 Set.prototype.remove = function(key) {
27038 if (key in this._keys) {
27039 delete this._keys[key];
27047 * Returns an array of all values for properties of **o**.
27049 function values(o) {
27050 var ks = Object.keys(o),
27052 result = new Array(len),
27054 for (i = 0; i < len; ++i) {
27055 result[i] = o[ks[i]];
27060 },{"./util":22}],22:[function(require,module,exports){
27062 * This polyfill comes from
27063 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
27065 if(!Array.isArray) {
27066 exports.isArray = function (vArg) {
27067 return Object.prototype.toString.call(vArg) === '[object Array]';
27070 exports.isArray = Array.isArray;
27074 * Slightly adapted polyfill from
27075 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
27077 if ('function' !== typeof Array.prototype.reduce) {
27078 exports.reduce = function(array, callback, opt_initialValue) {
27080 if (null === array || 'undefined' === typeof array) {
27081 // At the moment all modern browsers, that support strict mode, have
27082 // native implementation of Array.prototype.reduce. For instance, IE8
27083 // does not support strict mode, so this check is actually useless.
27084 throw new TypeError(
27085 'Array.prototype.reduce called on null or undefined');
27087 if ('function' !== typeof callback) {
27088 throw new TypeError(callback + ' is not a function');
27091 length = array.length >>> 0,
27092 isValueSet = false;
27093 if (1 < arguments.length) {
27094 value = opt_initialValue;
27097 for (index = 0; length > index; ++index) {
27098 if (array.hasOwnProperty(index)) {
27100 value = callback(value, array[index], index, array);
27103 value = array[index];
27109 throw new TypeError('Reduce of empty array with no initial value');
27114 exports.reduce = function(array, callback, opt_initialValue) {
27115 return array.reduce(callback, opt_initialValue);
27119 },{}],23:[function(require,module,exports){
27120 module.exports = '1.1.3';
27122 },{}],24:[function(require,module,exports){
27123 exports.Graph = require("./lib/Graph");
27124 exports.Digraph = require("./lib/Digraph");
27125 exports.CGraph = require("./lib/CGraph");
27126 exports.CDigraph = require("./lib/CDigraph");
27127 require("./lib/graph-converters");
27130 isAcyclic: require("./lib/alg/isAcyclic"),
27131 components: require("./lib/alg/components"),
27132 dijkstra: require("./lib/alg/dijkstra"),
27133 dijkstraAll: require("./lib/alg/dijkstraAll"),
27134 findCycles: require("./lib/alg/findCycles"),
27135 floydWarshall: require("./lib/alg/floydWarshall"),
27136 postorder: require("./lib/alg/postorder"),
27137 preorder: require("./lib/alg/preorder"),
27138 prim: require("./lib/alg/prim"),
27139 tarjan: require("./lib/alg/tarjan"),
27140 topsort: require("./lib/alg/topsort")
27143 exports.converter = {
27144 json: require("./lib/converter/json.js")
27147 var filter = require("./lib/filter");
27150 nodesFromList: filter.nodesFromList
27153 exports.version = require("./lib/version");
27155 },{"./lib/CDigraph":26,"./lib/CGraph":27,"./lib/Digraph":28,"./lib/Graph":29,"./lib/alg/components":30,"./lib/alg/dijkstra":31,"./lib/alg/dijkstraAll":32,"./lib/alg/findCycles":33,"./lib/alg/floydWarshall":34,"./lib/alg/isAcyclic":35,"./lib/alg/postorder":36,"./lib/alg/preorder":37,"./lib/alg/prim":38,"./lib/alg/tarjan":39,"./lib/alg/topsort":40,"./lib/converter/json.js":42,"./lib/filter":43,"./lib/graph-converters":44,"./lib/version":46}],25:[function(require,module,exports){
27157 var Set = require("cp-data").Set;
27160 module.exports = BaseGraph;
27162 function BaseGraph() {
27163 // The value assigned to the graph itself.
27164 this._value = undefined;
27166 // Map of node id -> { id, value }
27169 // Map of edge id -> { id, u, v, value }
27172 // Used to generate a unique id in the graph
27177 BaseGraph.prototype.order = function() {
27178 return Object.keys(this._nodes).length;
27182 BaseGraph.prototype.size = function() {
27183 return Object.keys(this._edges).length;
27186 // Accessor for graph level value
27187 BaseGraph.prototype.graph = function(value) {
27188 if (arguments.length === 0) {
27189 return this._value;
27191 this._value = value;
27194 BaseGraph.prototype.hasNode = function(u) {
27195 return u in this._nodes;
27198 BaseGraph.prototype.node = function(u, value) {
27199 var node = this._strictGetNode(u);
27200 if (arguments.length === 1) {
27203 node.value = value;
27206 BaseGraph.prototype.nodes = function() {
27208 this.eachNode(function(id) { nodes.push(id); });
27212 BaseGraph.prototype.eachNode = function(func) {
27213 for (var k in this._nodes) {
27214 var node = this._nodes[k];
27215 func(node.id, node.value);
27219 BaseGraph.prototype.hasEdge = function(e) {
27220 return e in this._edges;
27223 BaseGraph.prototype.edge = function(e, value) {
27224 var edge = this._strictGetEdge(e);
27225 if (arguments.length === 1) {
27228 edge.value = value;
27231 BaseGraph.prototype.edges = function() {
27233 this.eachEdge(function(id) { es.push(id); });
27237 BaseGraph.prototype.eachEdge = function(func) {
27238 for (var k in this._edges) {
27239 var edge = this._edges[k];
27240 func(edge.id, edge.u, edge.v, edge.value);
27244 BaseGraph.prototype.incidentNodes = function(e) {
27245 var edge = this._strictGetEdge(e);
27246 return [edge.u, edge.v];
27249 BaseGraph.prototype.addNode = function(u, value) {
27250 if (u === undefined || u === null) {
27252 u = "_" + (++this._nextId);
27253 } while (this.hasNode(u));
27254 } else if (this.hasNode(u)) {
27255 throw new Error("Graph already has node '" + u + "'");
27257 this._nodes[u] = { id: u, value: value };
27261 BaseGraph.prototype.delNode = function(u) {
27262 this._strictGetNode(u);
27263 this.incidentEdges(u).forEach(function(e) { this.delEdge(e); }, this);
27264 delete this._nodes[u];
27267 // inMap and outMap are opposite sides of an incidence map. For example, for
27268 // Graph these would both come from the _incidentEdges map, while for Digraph
27269 // they would come from _inEdges and _outEdges.
27270 BaseGraph.prototype._addEdge = function(e, u, v, value, inMap, outMap) {
27271 this._strictGetNode(u);
27272 this._strictGetNode(v);
27274 if (e === undefined || e === null) {
27276 e = "_" + (++this._nextId);
27277 } while (this.hasEdge(e));
27279 else if (this.hasEdge(e)) {
27280 throw new Error("Graph already has edge '" + e + "'");
27283 this._edges[e] = { id: e, u: u, v: v, value: value };
27284 addEdgeToMap(inMap[v], u, e);
27285 addEdgeToMap(outMap[u], v, e);
27290 // See note for _addEdge regarding inMap and outMap.
27291 BaseGraph.prototype._delEdge = function(e, inMap, outMap) {
27292 var edge = this._strictGetEdge(e);
27293 delEdgeFromMap(inMap[edge.v], edge.u, e);
27294 delEdgeFromMap(outMap[edge.u], edge.v, e);
27295 delete this._edges[e];
27298 BaseGraph.prototype.copy = function() {
27299 var copy = new this.constructor();
27300 copy.graph(this.graph());
27301 this.eachNode(function(u, value) { copy.addNode(u, value); });
27302 this.eachEdge(function(e, u, v, value) { copy.addEdge(e, u, v, value); });
27303 copy._nextId = this._nextId;
27307 BaseGraph.prototype.filterNodes = function(filter) {
27308 var copy = new this.constructor();
27309 copy.graph(this.graph());
27310 this.eachNode(function(u, value) {
27312 copy.addNode(u, value);
27315 this.eachEdge(function(e, u, v, value) {
27316 if (copy.hasNode(u) && copy.hasNode(v)) {
27317 copy.addEdge(e, u, v, value);
27323 BaseGraph.prototype._strictGetNode = function(u) {
27324 var node = this._nodes[u];
27325 if (node === undefined) {
27326 throw new Error("Node '" + u + "' is not in graph");
27331 BaseGraph.prototype._strictGetEdge = function(e) {
27332 var edge = this._edges[e];
27333 if (edge === undefined) {
27334 throw new Error("Edge '" + e + "' is not in graph");
27339 function addEdgeToMap(map, v, e) {
27340 (map[v] || (map[v] = new Set())).add(e);
27343 function delEdgeFromMap(map, v, e) {
27344 var vEntry = map[v];
27346 if (vEntry.size() === 0) {
27352 },{"cp-data":19}],26:[function(require,module,exports){
27353 var Digraph = require("./Digraph"),
27354 compoundify = require("./compoundify");
27356 var CDigraph = compoundify(Digraph);
27358 module.exports = CDigraph;
27360 CDigraph.fromDigraph = function(src) {
27361 var g = new CDigraph(),
27362 graphValue = src.graph();
27364 if (graphValue !== undefined) {
27365 g.graph(graphValue);
27368 src.eachNode(function(u, value) {
27369 if (value === undefined) {
27372 g.addNode(u, value);
27375 src.eachEdge(function(e, u, v, value) {
27376 if (value === undefined) {
27377 g.addEdge(null, u, v);
27379 g.addEdge(null, u, v, value);
27385 CDigraph.prototype.toString = function() {
27386 return "CDigraph " + JSON.stringify(this, null, 2);
27389 },{"./Digraph":28,"./compoundify":41}],27:[function(require,module,exports){
27390 var Graph = require("./Graph"),
27391 compoundify = require("./compoundify");
27393 var CGraph = compoundify(Graph);
27395 module.exports = CGraph;
27397 CGraph.fromGraph = function(src) {
27398 var g = new CGraph(),
27399 graphValue = src.graph();
27401 if (graphValue !== undefined) {
27402 g.graph(graphValue);
27405 src.eachNode(function(u, value) {
27406 if (value === undefined) {
27409 g.addNode(u, value);
27412 src.eachEdge(function(e, u, v, value) {
27413 if (value === undefined) {
27414 g.addEdge(null, u, v);
27416 g.addEdge(null, u, v, value);
27422 CGraph.prototype.toString = function() {
27423 return "CGraph " + JSON.stringify(this, null, 2);
27426 },{"./Graph":29,"./compoundify":41}],28:[function(require,module,exports){
27428 * This file is organized with in the following order:
27431 * Graph constructors
27432 * Graph queries (e.g. nodes(), edges()
27437 var util = require("./util"),
27438 BaseGraph = require("./BaseGraph"),
27440 Set = require("cp-data").Set;
27443 module.exports = Digraph;
27446 * Constructor to create a new directed multi-graph.
27448 function Digraph() {
27449 BaseGraph.call(this);
27451 /*! Map of sourceId -> {targetId -> Set of edge ids} */
27452 this._inEdges = {};
27454 /*! Map of targetId -> {sourceId -> Set of edge ids} */
27455 this._outEdges = {};
27458 Digraph.prototype = new BaseGraph();
27459 Digraph.prototype.constructor = Digraph;
27462 * Always returns `true`.
27464 Digraph.prototype.isDirected = function() {
27469 * Returns all successors of the node with the id `u`. That is, all nodes
27470 * that have the node `u` as their source are returned.
27472 * If no node `u` exists in the graph this function throws an Error.
27474 * @param {String} u a node id
27476 Digraph.prototype.successors = function(u) {
27477 this._strictGetNode(u);
27478 return Object.keys(this._outEdges[u])
27479 .map(function(v) { return this._nodes[v].id; }, this);
27483 * Returns all predecessors of the node with the id `u`. That is, all nodes
27484 * that have the node `u` as their target are returned.
27486 * If no node `u` exists in the graph this function throws an Error.
27488 * @param {String} u a node id
27490 Digraph.prototype.predecessors = function(u) {
27491 this._strictGetNode(u);
27492 return Object.keys(this._inEdges[u])
27493 .map(function(v) { return this._nodes[v].id; }, this);
27497 * Returns all nodes that are adjacent to the node with the id `u`. In other
27498 * words, this function returns the set of all successors and predecessors of
27501 * @param {String} u a node id
27503 Digraph.prototype.neighbors = function(u) {
27504 return Set.union([this.successors(u), this.predecessors(u)]).keys();
27508 * Returns all nodes in the graph that have no in-edges.
27510 Digraph.prototype.sources = function() {
27512 return this._filterNodes(function(u) {
27513 // This could have better space characteristics if we had an inDegree function.
27514 return self.inEdges(u).length === 0;
27519 * Returns all nodes in the graph that have no out-edges.
27521 Digraph.prototype.sinks = function() {
27523 return this._filterNodes(function(u) {
27524 // This could have better space characteristics if we have an outDegree function.
27525 return self.outEdges(u).length === 0;
27530 * Returns the source node incident on the edge identified by the id `e`. If no
27531 * such edge exists in the graph this function throws an Error.
27533 * @param {String} e an edge id
27535 Digraph.prototype.source = function(e) {
27536 return this._strictGetEdge(e).u;
27540 * Returns the target node incident on the edge identified by the id `e`. If no
27541 * such edge exists in the graph this function throws an Error.
27543 * @param {String} e an edge id
27545 Digraph.prototype.target = function(e) {
27546 return this._strictGetEdge(e).v;
27550 * Returns an array of ids for all edges in the graph that have the node
27551 * `target` as their target. If the node `target` is not in the graph this
27552 * function raises an Error.
27554 * Optionally a `source` node can also be specified. This causes the results
27555 * to be filtered such that only edges from `source` to `target` are included.
27556 * If the node `source` is specified but is not in the graph then this function
27559 * @param {String} target the target node id
27560 * @param {String} [source] an optional source node id
27562 Digraph.prototype.inEdges = function(target, source) {
27563 this._strictGetNode(target);
27564 var results = Set.union(util.values(this._inEdges[target])).keys();
27565 if (arguments.length > 1) {
27566 this._strictGetNode(source);
27567 results = results.filter(function(e) { return this.source(e) === source; }, this);
27573 * Returns an array of ids for all edges in the graph that have the node
27574 * `source` as their source. If the node `source` is not in the graph this
27575 * function raises an Error.
27577 * Optionally a `target` node may also be specified. This causes the results
27578 * to be filtered such that only edges from `source` to `target` are included.
27579 * If the node `target` is specified but is not in the graph then this function
27582 * @param {String} source the source node id
27583 * @param {String} [target] an optional target node id
27585 Digraph.prototype.outEdges = function(source, target) {
27586 this._strictGetNode(source);
27587 var results = Set.union(util.values(this._outEdges[source])).keys();
27588 if (arguments.length > 1) {
27589 this._strictGetNode(target);
27590 results = results.filter(function(e) { return this.target(e) === target; }, this);
27596 * Returns an array of ids for all edges in the graph that have the `u` as
27597 * their source or their target. If the node `u` is not in the graph this
27598 * function raises an Error.
27600 * Optionally a `v` node may also be specified. This causes the results to be
27601 * filtered such that only edges between `u` and `v` - in either direction -
27602 * are included. IF the node `v` is specified but not in the graph then this
27603 * function raises an Error.
27605 * @param {String} u the node for which to find incident edges
27606 * @param {String} [v] option node that must be adjacent to `u`
27608 Digraph.prototype.incidentEdges = function(u, v) {
27609 if (arguments.length > 1) {
27610 return Set.union([this.outEdges(u, v), this.outEdges(v, u)]).keys();
27612 return Set.union([this.inEdges(u), this.outEdges(u)]).keys();
27617 * Returns a string representation of this graph.
27619 Digraph.prototype.toString = function() {
27620 return "Digraph " + JSON.stringify(this, null, 2);
27624 * Adds a new node with the id `u` to the graph and assigns it the value
27625 * `value`. If a node with the id is already a part of the graph this function
27628 * @param {String} u a node id
27629 * @param {Object} [value] an optional value to attach to the node
27631 Digraph.prototype.addNode = function(u, value) {
27632 u = BaseGraph.prototype.addNode.call(this, u, value);
27633 this._inEdges[u] = {};
27634 this._outEdges[u] = {};
27639 * Removes a node from the graph that has the id `u`. Any edges incident on the
27640 * node are also removed. If the graph does not contain a node with the id this
27641 * function will throw an Error.
27643 * @param {String} u a node id
27645 Digraph.prototype.delNode = function(u) {
27646 BaseGraph.prototype.delNode.call(this, u);
27647 delete this._inEdges[u];
27648 delete this._outEdges[u];
27652 * Adds a new edge to the graph with the id `e` from a node with the id `source`
27653 * to a node with an id `target` and assigns it the value `value`. This graph
27654 * allows more than one edge from `source` to `target` as long as the id `e`
27655 * is unique in the set of edges. If `e` is `null` the graph will assign a
27656 * unique identifier to the edge.
27658 * If `source` or `target` are not present in the graph this function will
27661 * @param {String} [e] an edge id
27662 * @param {String} source the source node id
27663 * @param {String} target the target node id
27664 * @param {Object} [value] an optional value to attach to the edge
27666 Digraph.prototype.addEdge = function(e, source, target, value) {
27667 return BaseGraph.prototype._addEdge.call(this, e, source, target, value,
27668 this._inEdges, this._outEdges);
27672 * Removes an edge in the graph with the id `e`. If no edge in the graph has
27673 * the id `e` this function will throw an Error.
27675 * @param {String} e an edge id
27677 Digraph.prototype.delEdge = function(e) {
27678 BaseGraph.prototype._delEdge.call(this, e, this._inEdges, this._outEdges);
27681 // Unlike BaseGraph.filterNodes, this helper just returns nodes that
27682 // satisfy a predicate.
27683 Digraph.prototype._filterNodes = function(pred) {
27685 this.eachNode(function(u) {
27694 },{"./BaseGraph":25,"./util":45,"cp-data":19}],29:[function(require,module,exports){
27696 * This file is organized with in the following order:
27699 * Graph constructors
27700 * Graph queries (e.g. nodes(), edges()
27705 var util = require("./util"),
27706 BaseGraph = require("./BaseGraph"),
27708 Set = require("cp-data").Set;
27711 module.exports = Graph;
27714 * Constructor to create a new undirected multi-graph.
27717 BaseGraph.call(this);
27719 /*! Map of nodeId -> { otherNodeId -> Set of edge ids } */
27720 this._incidentEdges = {};
27723 Graph.prototype = new BaseGraph();
27724 Graph.prototype.constructor = Graph;
27727 * Always returns `false`.
27729 Graph.prototype.isDirected = function() {
27734 * Returns all nodes that are adjacent to the node with the id `u`.
27736 * @param {String} u a node id
27738 Graph.prototype.neighbors = function(u) {
27739 this._strictGetNode(u);
27740 return Object.keys(this._incidentEdges[u])
27741 .map(function(v) { return this._nodes[v].id; }, this);
27745 * Returns an array of ids for all edges in the graph that are incident on `u`.
27746 * If the node `u` is not in the graph this function raises an Error.
27748 * Optionally a `v` node may also be specified. This causes the results to be
27749 * filtered such that only edges between `u` and `v` are included. If the node
27750 * `v` is specified but not in the graph then this function raises an Error.
27752 * @param {String} u the node for which to find incident edges
27753 * @param {String} [v] option node that must be adjacent to `u`
27755 Graph.prototype.incidentEdges = function(u, v) {
27756 this._strictGetNode(u);
27757 if (arguments.length > 1) {
27758 this._strictGetNode(v);
27759 return v in this._incidentEdges[u] ? this._incidentEdges[u][v].keys() : [];
27761 return Set.union(util.values(this._incidentEdges[u])).keys();
27766 * Returns a string representation of this graph.
27768 Graph.prototype.toString = function() {
27769 return "Graph " + JSON.stringify(this, null, 2);
27773 * Adds a new node with the id `u` to the graph and assigns it the value
27774 * `value`. If a node with the id is already a part of the graph this function
27777 * @param {String} u a node id
27778 * @param {Object} [value] an optional value to attach to the node
27780 Graph.prototype.addNode = function(u, value) {
27781 u = BaseGraph.prototype.addNode.call(this, u, value);
27782 this._incidentEdges[u] = {};
27787 * Removes a node from the graph that has the id `u`. Any edges incident on the
27788 * node are also removed. If the graph does not contain a node with the id this
27789 * function will throw an Error.
27791 * @param {String} u a node id
27793 Graph.prototype.delNode = function(u) {
27794 BaseGraph.prototype.delNode.call(this, u);
27795 delete this._incidentEdges[u];
27799 * Adds a new edge to the graph with the id `e` between a node with the id `u`
27800 * and a node with an id `v` and assigns it the value `value`. This graph
27801 * allows more than one edge between `u` and `v` as long as the id `e`
27802 * is unique in the set of edges. If `e` is `null` the graph will assign a
27803 * unique identifier to the edge.
27805 * If `u` or `v` are not present in the graph this function will throw an
27808 * @param {String} [e] an edge id
27809 * @param {String} u the node id of one of the adjacent nodes
27810 * @param {String} v the node id of the other adjacent node
27811 * @param {Object} [value] an optional value to attach to the edge
27813 Graph.prototype.addEdge = function(e, u, v, value) {
27814 return BaseGraph.prototype._addEdge.call(this, e, u, v, value,
27815 this._incidentEdges, this._incidentEdges);
27819 * Removes an edge in the graph with the id `e`. If no edge in the graph has
27820 * the id `e` this function will throw an Error.
27822 * @param {String} e an edge id
27824 Graph.prototype.delEdge = function(e) {
27825 BaseGraph.prototype._delEdge.call(this, e, this._incidentEdges, this._incidentEdges);
27829 },{"./BaseGraph":25,"./util":45,"cp-data":19}],30:[function(require,module,exports){
27831 var Set = require("cp-data").Set;
27834 module.exports = components;
27837 * Finds all [connected components][] in a graph and returns an array of these
27838 * components. Each component is itself an array that contains the ids of nodes
27839 * in the component.
27841 * This function only works with undirected Graphs.
27843 * [connected components]: http://en.wikipedia.org/wiki/Connected_component_(graph_theory)
27845 * @param {Graph} g the graph to search for components
27847 function components(g) {
27849 var visited = new Set();
27851 function dfs(v, component) {
27852 if (!visited.has(v)) {
27855 g.neighbors(v).forEach(function(w) {
27861 g.nodes().forEach(function(v) {
27862 var component = [];
27864 if (component.length > 0) {
27865 results.push(component);
27872 },{"cp-data":19}],31:[function(require,module,exports){
27873 var PriorityQueue = require("cp-data").PriorityQueue;
27875 module.exports = dijkstra;
27878 * This function is an implementation of [Dijkstra's algorithm][] which finds
27879 * the shortest path from **source** to all other nodes in **g**. This
27880 * function returns a map of `u -> { distance, predecessor }`. The distance
27881 * property holds the sum of the weights from **source** to `u` along the
27882 * shortest path or `Number.POSITIVE_INFINITY` if there is no path from
27883 * **source**. The predecessor property can be used to walk the individual
27884 * elements of the path from **source** to **u** in reverse order.
27886 * This function takes an optional `weightFunc(e)` which returns the
27887 * weight of the edge `e`. If no weightFunc is supplied then each edge is
27888 * assumed to have a weight of 1. This function throws an Error if any of
27889 * the traversed edges have a negative edge weight.
27891 * This function takes an optional `incidentFunc(u)` which returns the ids of
27892 * all edges incident to the node `u` for the purposes of shortest path
27893 * traversal. By default this function uses the `g.outEdges` for Digraphs and
27894 * `g.incidentEdges` for Graphs.
27896 * This function takes `O((|E| + |V|) * log |V|)` time.
27898 * [Dijkstra's algorithm]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
27900 * @param {Graph} g the graph to search for shortest paths from **source**
27901 * @param {Object} source the source from which to start the search
27902 * @param {Function} [weightFunc] optional weight function
27903 * @param {Function} [incidentFunc] optional incident function
27905 function dijkstra(g, source, weightFunc, incidentFunc) {
27907 pq = new PriorityQueue();
27909 function updateNeighbors(e) {
27910 var incidentNodes = g.incidentNodes(e),
27911 v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1],
27912 vEntry = results[v],
27913 weight = weightFunc(e),
27914 distance = uEntry.distance + weight;
27917 throw new Error("dijkstra does not allow negative edge weights. Bad edge: " + e + " Weight: " + weight);
27920 if (distance < vEntry.distance) {
27921 vEntry.distance = distance;
27922 vEntry.predecessor = u;
27923 pq.decrease(v, distance);
27927 weightFunc = weightFunc || function() { return 1; };
27928 incidentFunc = incidentFunc || (g.isDirected()
27929 ? function(u) { return g.outEdges(u); }
27930 : function(u) { return g.incidentEdges(u); });
27932 g.eachNode(function(u) {
27933 var distance = u === source ? 0 : Number.POSITIVE_INFINITY;
27934 results[u] = { distance: distance };
27935 pq.add(u, distance);
27939 while (pq.size() > 0) {
27940 u = pq.removeMin();
27941 uEntry = results[u];
27942 if (uEntry.distance === Number.POSITIVE_INFINITY) {
27946 incidentFunc(u).forEach(updateNeighbors);
27952 },{"cp-data":19}],32:[function(require,module,exports){
27953 var dijkstra = require("./dijkstra");
27955 module.exports = dijkstraAll;
27958 * This function finds the shortest path from each node to every other
27959 * reachable node in the graph. It is similar to [alg.dijkstra][], but
27960 * instead of returning a single-source array, it returns a mapping of
27961 * of `source -> alg.dijksta(g, source, weightFunc, incidentFunc)`.
27963 * This function takes an optional `weightFunc(e)` which returns the
27964 * weight of the edge `e`. If no weightFunc is supplied then each edge is
27965 * assumed to have a weight of 1. This function throws an Error if any of
27966 * the traversed edges have a negative edge weight.
27968 * This function takes an optional `incidentFunc(u)` which returns the ids of
27969 * all edges incident to the node `u` for the purposes of shortest path
27970 * traversal. By default this function uses the `outEdges` function on the
27973 * This function takes `O(|V| * (|E| + |V|) * log |V|)` time.
27975 * [alg.dijkstra]: dijkstra.js.html#dijkstra
27977 * @param {Graph} g the graph to search for shortest paths from **source**
27978 * @param {Function} [weightFunc] optional weight function
27979 * @param {Function} [incidentFunc] optional incident function
27981 function dijkstraAll(g, weightFunc, incidentFunc) {
27983 g.eachNode(function(u) {
27984 results[u] = dijkstra(g, u, weightFunc, incidentFunc);
27989 },{"./dijkstra":31}],33:[function(require,module,exports){
27990 var tarjan = require("./tarjan");
27992 module.exports = findCycles;
27995 * Given a Digraph **g** this function returns all nodes that are part of a
27996 * cycle. Since there may be more than one cycle in a graph this function
27997 * returns an array of these cycles, where each cycle is itself represented
27998 * by an array of ids for each node involved in that cycle.
28000 * [alg.isAcyclic][] is more efficient if you only need to determine whether
28001 * a graph has a cycle or not.
28003 * [alg.isAcyclic]: isAcyclic.js.html#isAcyclic
28005 * @param {Digraph} g the graph to search for cycles.
28007 function findCycles(g) {
28008 return tarjan(g).filter(function(cmpt) { return cmpt.length > 1; });
28011 },{"./tarjan":39}],34:[function(require,module,exports){
28012 module.exports = floydWarshall;
28015 * This function is an implementation of the [Floyd-Warshall algorithm][],
28016 * which finds the shortest path from each node to every other reachable node
28017 * in the graph. It is similar to [alg.dijkstraAll][], but it handles negative
28018 * edge weights and is more efficient for some types of graphs. This function
28019 * returns a map of `source -> { target -> { distance, predecessor }`. The
28020 * distance property holds the sum of the weights from `source` to `target`
28021 * along the shortest path of `Number.POSITIVE_INFINITY` if there is no path
28022 * from `source`. The predecessor property can be used to walk the individual
28023 * elements of the path from `source` to `target` in reverse order.
28025 * This function takes an optional `weightFunc(e)` which returns the
28026 * weight of the edge `e`. If no weightFunc is supplied then each edge is
28027 * assumed to have a weight of 1.
28029 * This function takes an optional `incidentFunc(u)` which returns the ids of
28030 * all edges incident to the node `u` for the purposes of shortest path
28031 * traversal. By default this function uses the `outEdges` function on the
28034 * This algorithm takes O(|V|^3) time.
28036 * [Floyd-Warshall algorithm]: https://en.wikipedia.org/wiki/Floyd-Warshall_algorithm
28037 * [alg.dijkstraAll]: dijkstraAll.js.html#dijkstraAll
28039 * @param {Graph} g the graph to search for shortest paths from **source**
28040 * @param {Function} [weightFunc] optional weight function
28041 * @param {Function} [incidentFunc] optional incident function
28043 function floydWarshall(g, weightFunc, incidentFunc) {
28047 weightFunc = weightFunc || function() { return 1; };
28048 incidentFunc = incidentFunc || (g.isDirected()
28049 ? function(u) { return g.outEdges(u); }
28050 : function(u) { return g.incidentEdges(u); });
28052 nodes.forEach(function(u) {
28054 results[u][u] = { distance: 0 };
28055 nodes.forEach(function(v) {
28057 results[u][v] = { distance: Number.POSITIVE_INFINITY };
28060 incidentFunc(u).forEach(function(e) {
28061 var incidentNodes = g.incidentNodes(e),
28062 v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1],
28064 if (d < results[u][v].distance) {
28065 results[u][v] = { distance: d, predecessor: u };
28070 nodes.forEach(function(k) {
28071 var rowK = results[k];
28072 nodes.forEach(function(i) {
28073 var rowI = results[i];
28074 nodes.forEach(function(j) {
28078 var altDistance = ik.distance + kj.distance;
28079 if (altDistance < ij.distance) {
28080 ij.distance = altDistance;
28081 ij.predecessor = kj.predecessor;
28090 },{}],35:[function(require,module,exports){
28091 var topsort = require("./topsort");
28093 module.exports = isAcyclic;
28096 * Given a Digraph **g** this function returns `true` if the graph has no
28097 * cycles and returns `false` if it does. This algorithm returns as soon as it
28098 * detects the first cycle.
28100 * Use [alg.findCycles][] if you need the actual list of cycles in a graph.
28102 * [alg.findCycles]: findCycles.js.html#findCycles
28104 * @param {Digraph} g the graph to test for cycles
28106 function isAcyclic(g) {
28110 if (e instanceof topsort.CycleException) return false;
28116 },{"./topsort":40}],36:[function(require,module,exports){
28118 var Set = require("cp-data").Set;
28121 module.exports = postorder;
28123 // Postorder traversal of g, calling f for each visited node. Assumes the graph
28125 function postorder(g, root, f) {
28126 var visited = new Set();
28127 if (g.isDirected()) {
28128 throw new Error("This function only works for undirected graphs");
28130 function dfs(u, prev) {
28131 if (visited.has(u)) {
28132 throw new Error("The input graph is not a tree: " + g);
28135 g.neighbors(u).forEach(function(v) {
28136 if (v !== prev) dfs(v, u);
28143 },{"cp-data":19}],37:[function(require,module,exports){
28145 var Set = require("cp-data").Set;
28148 module.exports = preorder;
28150 // Preorder traversal of g, calling f for each visited node. Assumes the graph
28152 function preorder(g, root, f) {
28153 var visited = new Set();
28154 if (g.isDirected()) {
28155 throw new Error("This function only works for undirected graphs");
28157 function dfs(u, prev) {
28158 if (visited.has(u)) {
28159 throw new Error("The input graph is not a tree: " + g);
28163 g.neighbors(u).forEach(function(v) {
28164 if (v !== prev) dfs(v, u);
28170 },{"cp-data":19}],38:[function(require,module,exports){
28171 var Graph = require("../Graph"),
28172 PriorityQueue = require("cp-data").PriorityQueue;
28174 module.exports = prim;
28177 * [Prim's algorithm][] takes a connected undirected graph and generates a
28178 * [minimum spanning tree][]. This function returns the minimum spanning
28179 * tree as an undirected graph. This algorithm is derived from the description
28180 * in "Introduction to Algorithms", Third Edition, Cormen, et al., Pg 634.
28182 * This function takes a `weightFunc(e)` which returns the weight of the edge
28183 * `e`. It throws an Error if the graph is not connected.
28185 * This function takes `O(|E| log |V|)` time.
28187 * [Prim's algorithm]: https://en.wikipedia.org/wiki/Prim's_algorithm
28188 * [minimum spanning tree]: https://en.wikipedia.org/wiki/Minimum_spanning_tree
28190 * @param {Graph} g the graph used to generate the minimum spanning tree
28191 * @param {Function} weightFunc the weight function to use
28193 function prim(g, weightFunc) {
28194 var result = new Graph(),
28196 pq = new PriorityQueue(),
28199 function updateNeighbors(e) {
28200 var incidentNodes = g.incidentNodes(e),
28201 v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1],
28202 pri = pq.priority(v);
28203 if (pri !== undefined) {
28204 var edgeWeight = weightFunc(e);
28205 if (edgeWeight < pri) {
28207 pq.decrease(v, edgeWeight);
28212 if (g.order() === 0) {
28216 g.eachNode(function(u) {
28217 pq.add(u, Number.POSITIVE_INFINITY);
28221 // Start from an arbitrary node
28222 pq.decrease(g.nodes()[0], 0);
28225 while (pq.size() > 0) {
28226 u = pq.removeMin();
28227 if (u in parents) {
28228 result.addEdge(null, u, parents[u]);
28230 throw new Error("Input graph is not connected: " + g);
28235 g.incidentEdges(u).forEach(updateNeighbors);
28241 },{"../Graph":29,"cp-data":19}],39:[function(require,module,exports){
28242 module.exports = tarjan;
28245 * This function is an implementation of [Tarjan's algorithm][] which finds
28246 * all [strongly connected components][] in the directed graph **g**. Each
28247 * strongly connected component is composed of nodes that can reach all other
28248 * nodes in the component via directed edges. A strongly connected component
28249 * can consist of a single node if that node cannot both reach and be reached
28250 * by any other specific node in the graph. Components of more than one node
28251 * are guaranteed to have at least one cycle.
28253 * This function returns an array of components. Each component is itself an
28254 * array that contains the ids of all nodes in the component.
28256 * [Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
28257 * [strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component
28259 * @param {Digraph} g the graph to search for strongly connected components
28261 function tarjan(g) {
28262 if (!g.isDirected()) {
28263 throw new Error("tarjan can only be applied to a directed graph. Bad input: " + g);
28268 visited = {}, // node id -> { onStack, lowlink, index }
28272 var entry = visited[u] = {
28279 g.successors(u).forEach(function(v) {
28280 if (!(v in visited)) {
28282 entry.lowlink = Math.min(entry.lowlink, visited[v].lowlink);
28283 } else if (visited[v].onStack) {
28284 entry.lowlink = Math.min(entry.lowlink, visited[v].index);
28288 if (entry.lowlink === entry.index) {
28293 visited[v].onStack = false;
28296 results.push(cmpt);
28300 g.nodes().forEach(function(u) {
28301 if (!(u in visited)) {
28309 },{}],40:[function(require,module,exports){
28310 module.exports = topsort;
28311 topsort.CycleException = CycleException;
28314 * Given a graph **g**, this function returns an ordered list of nodes such
28315 * that for each edge `u -> v`, `u` appears before `v` in the list. If the
28316 * graph has a cycle it is impossible to generate such a list and
28317 * **CycleException** is thrown.
28319 * See [topological sorting](https://en.wikipedia.org/wiki/Topological_sorting)
28320 * for more details about how this algorithm works.
28322 * @param {Digraph} g the graph to sort
28324 function topsort(g) {
28325 if (!g.isDirected()) {
28326 throw new Error("topsort can only be applied to a directed graph. Bad input: " + g);
28333 function visit(node) {
28334 if (node in stack) {
28335 throw new CycleException();
28338 if (!(node in visited)) {
28339 stack[node] = true;
28340 visited[node] = true;
28341 g.predecessors(node).forEach(function(pred) {
28344 delete stack[node];
28345 results.push(node);
28349 var sinks = g.sinks();
28350 if (g.order() !== 0 && sinks.length === 0) {
28351 throw new CycleException();
28354 g.sinks().forEach(function(sink) {
28361 function CycleException() {}
28363 CycleException.prototype.toString = function() {
28364 return "Graph has at least one cycle";
28367 },{}],41:[function(require,module,exports){
28368 // This file provides a helper function that mixes-in Dot behavior to an
28369 // existing graph prototype.
28372 var Set = require("cp-data").Set;
28375 module.exports = compoundify;
28377 // Extends the given SuperConstructor with the ability for nodes to contain
28378 // other nodes. A special node id `null` is used to indicate the root graph.
28379 function compoundify(SuperConstructor) {
28380 function Constructor() {
28381 SuperConstructor.call(this);
28383 // Map of object id -> parent id (or null for root graph)
28384 this._parents = {};
28386 // Map of id (or null) -> children set
28387 this._children = {};
28388 this._children[null] = new Set();
28391 Constructor.prototype = new SuperConstructor();
28392 Constructor.prototype.constructor = Constructor;
28394 Constructor.prototype.parent = function(u, parent) {
28395 this._strictGetNode(u);
28397 if (arguments.length < 2) {
28398 return this._parents[u];
28401 if (u === parent) {
28402 throw new Error("Cannot make " + u + " a parent of itself");
28404 if (parent !== null) {
28405 this._strictGetNode(parent);
28408 this._children[this._parents[u]].remove(u);
28409 this._parents[u] = parent;
28410 this._children[parent].add(u);
28413 Constructor.prototype.children = function(u) {
28415 this._strictGetNode(u);
28417 return this._children[u].keys();
28420 Constructor.prototype.addNode = function(u, value) {
28421 u = SuperConstructor.prototype.addNode.call(this, u, value);
28422 this._parents[u] = null;
28423 this._children[u] = new Set();
28424 this._children[null].add(u);
28428 Constructor.prototype.delNode = function(u) {
28429 // Promote all children to the parent of the subgraph
28430 var parent = this.parent(u);
28431 this._children[u].keys().forEach(function(child) {
28432 this.parent(child, parent);
28435 this._children[parent].remove(u);
28436 delete this._parents[u];
28437 delete this._children[u];
28439 return SuperConstructor.prototype.delNode.call(this, u);
28442 Constructor.prototype.copy = function() {
28443 var copy = SuperConstructor.prototype.copy.call(this);
28444 this.nodes().forEach(function(u) {
28445 copy.parent(u, this.parent(u));
28450 Constructor.prototype.filterNodes = function(filter) {
28452 copy = SuperConstructor.prototype.filterNodes.call(this, filter);
28455 function findParent(u) {
28456 var parent = self.parent(u);
28457 if (parent === null || copy.hasNode(parent)) {
28458 parents[u] = parent;
28460 } else if (parent in parents) {
28461 return parents[parent];
28463 return findParent(parent);
28467 copy.eachNode(function(u) { copy.parent(u, findParent(u)); });
28472 return Constructor;
28475 },{"cp-data":19}],42:[function(require,module,exports){
28476 var Graph = require("../Graph"),
28477 Digraph = require("../Digraph"),
28478 CGraph = require("../CGraph"),
28479 CDigraph = require("../CDigraph");
28481 exports.decode = function(nodes, edges, Ctor) {
28482 Ctor = Ctor || Digraph;
28484 if (typeOf(nodes) !== "Array") {
28485 throw new Error("nodes is not an Array");
28488 if (typeOf(edges) !== "Array") {
28489 throw new Error("edges is not an Array");
28492 if (typeof Ctor === "string") {
28494 case "graph": Ctor = Graph; break;
28495 case "digraph": Ctor = Digraph; break;
28496 case "cgraph": Ctor = CGraph; break;
28497 case "cdigraph": Ctor = CDigraph; break;
28498 default: throw new Error("Unrecognized graph type: " + Ctor);
28502 var graph = new Ctor();
28504 nodes.forEach(function(u) {
28505 graph.addNode(u.id, u.value);
28508 // If the graph is compound, set up children...
28509 if (graph.parent) {
28510 nodes.forEach(function(u) {
28512 u.children.forEach(function(v) {
28513 graph.parent(v, u.id);
28519 edges.forEach(function(e) {
28520 graph.addEdge(e.id, e.u, e.v, e.value);
28526 exports.encode = function(graph) {
28530 graph.eachNode(function(u, value) {
28531 var node = {id: u, value: value};
28532 if (graph.children) {
28533 var children = graph.children(u);
28534 if (children.length) {
28535 node.children = children;
28541 graph.eachEdge(function(e, u, v, value) {
28542 edges.push({id: e, u: u, v: v, value: value});
28546 if (graph instanceof CDigraph) {
28548 } else if (graph instanceof CGraph) {
28550 } else if (graph instanceof Digraph) {
28552 } else if (graph instanceof Graph) {
28555 throw new Error("Couldn't determine type of graph: " + graph);
28558 return { nodes: nodes, edges: edges, type: type };
28561 function typeOf(obj) {
28562 return Object.prototype.toString.call(obj).slice(8, -1);
28565 },{"../CDigraph":26,"../CGraph":27,"../Digraph":28,"../Graph":29}],43:[function(require,module,exports){
28567 var Set = require("cp-data").Set;
28570 exports.all = function() {
28571 return function() { return true; };
28574 exports.nodesFromList = function(nodes) {
28575 var set = new Set(nodes);
28576 return function(u) {
28581 },{"cp-data":19}],44:[function(require,module,exports){
28582 var Graph = require("./Graph"),
28583 Digraph = require("./Digraph");
28585 // Side-effect based changes are lousy, but node doesn't seem to resolve the
28589 * Returns a new directed graph using the nodes and edges from this graph. The
28590 * new graph will have the same nodes, but will have twice the number of edges:
28591 * each edge is split into two edges with opposite directions. Edge ids,
28592 * consequently, are not preserved by this transformation.
28594 Graph.prototype.toDigraph =
28595 Graph.prototype.asDirected = function() {
28596 var g = new Digraph();
28597 this.eachNode(function(u, value) { g.addNode(u, value); });
28598 this.eachEdge(function(e, u, v, value) {
28599 g.addEdge(null, u, v, value);
28600 g.addEdge(null, v, u, value);
28606 * Returns a new undirected graph using the nodes and edges from this graph.
28607 * The new graph will have the same nodes, but the edges will be made
28608 * undirected. Edge ids are preserved in this transformation.
28610 Digraph.prototype.toGraph =
28611 Digraph.prototype.asUndirected = function() {
28612 var g = new Graph();
28613 this.eachNode(function(u, value) { g.addNode(u, value); });
28614 this.eachEdge(function(e, u, v, value) {
28615 g.addEdge(e, u, v, value);
28620 },{"./Digraph":28,"./Graph":29}],45:[function(require,module,exports){
28621 // Returns an array of all values for properties of **o**.
28622 exports.values = function(o) {
28623 var ks = Object.keys(o),
28625 result = new Array(len),
28627 for (i = 0; i < len; ++i) {
28628 result[i] = o[ks[i]];
28633 },{}],46:[function(require,module,exports){
28634 module.exports = '0.7.4';
28638 joint.layout.DirectedGraph = {
28640 layout: function(graph, opt) {
28644 var inputGraph = this._prepareData(graph);
28645 var runner = dagre.layout();
28647 if (opt.debugLevel) { runner.debugLevel(opt.debugLevel); }
28648 if (opt.rankDir) { runner.rankDir(opt.rankDir); }
28649 if (opt.rankSep) { runner.rankSep(opt.rankSep); }
28650 if (opt.edgeSep) { runner.edgeSep(opt.edgeSep); }
28651 if (opt.nodeSep) { runner.nodeSep(opt.nodeSep); }
28653 var layoutGraph = runner.run(inputGraph);
28655 layoutGraph.eachNode(function(u, value) {
28656 if (!value.dummy) {
28657 graph.get('cells').get(u).set('position', {
28658 x: value.x - value.width/2,
28659 y: value.y - value.height/2
28664 if (opt.setLinkVertices) {
28666 layoutGraph.eachEdge(function(e, u, v, value) {
28667 var link = graph.get('cells').get(e);
28669 graph.get('cells').get(e).set('vertices', value.points);
28674 return { width: layoutGraph.graph().width, height: layoutGraph.graph().height };
28677 _prepareData: function(graph) {
28679 var dagreGraph = new dagre.Digraph();
28681 // For each element.
28682 _.each(graph.getElements(), function(cell) {
28684 if (dagreGraph.hasNode(cell.id)) return;
28686 dagreGraph.addNode(cell.id, {
28687 width: cell.get('size').width,
28688 height: cell.get('size').height,
28689 rank: cell.get('rank')
28694 _.each(graph.getLinks(), function(cell) {
28696 if (dagreGraph.hasEdge(cell.id)) return;
28698 var sourceId = cell.get('source').id;
28699 var targetId = cell.get('target').id;
28701 dagreGraph.addEdge(cell.id, sourceId, targetId, { minLen: cell.get('minLen') || 1 });