UNPKG

vide

Version:

Easy as hell jQuery plugin for video backgrounds.

263 lines (211 loc) 5.72 kB
// Test for equality any JavaScript type. // Author: Philippe Rathé <prathe@gmail.com> QUnit.equiv = ( function() { // Stack to decide between skip/abort functions var callers = []; // Stack to avoiding loops from circular referencing var parents = []; var parentsB = []; var getProto = Object.getPrototypeOf || function( obj ) { /*jshint proto: true */ return obj.__proto__; }; function useStrictEquality( b, a ) { // To catch short annotation VS 'new' annotation of a declaration. e.g.: // `var i = 1;` // `var j = new Number(1);` if ( typeof a === "object" ) { a = a.valueOf(); } if ( typeof b === "object" ) { b = b.valueOf(); } return a === b; } function compareConstructors( a, b ) { var protoA = getProto( a ); var protoB = getProto( b ); // Comparing constructors is more strict than using `instanceof` if ( a.constructor === b.constructor ) { return true; } // Ref #851 // If the obj prototype descends from a null constructor, treat it // as a null prototype. if ( protoA && protoA.constructor === null ) { protoA = null; } if ( protoB && protoB.constructor === null ) { protoB = null; } // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if ( ( protoA === null && protoB === Object.prototype ) || ( protoB === null && protoA === Object.prototype ) ) { return true; } return false; } function getRegExpFlags( regexp ) { return "flags" in regexp ? regexp.flags : regexp.toString().match( /[gimuy]*$/ )[ 0 ]; } var callbacks = { "string": useStrictEquality, "boolean": useStrictEquality, "number": useStrictEquality, "null": useStrictEquality, "undefined": useStrictEquality, "symbol": useStrictEquality, "date": useStrictEquality, "nan": function() { return true; }, "regexp": function( b, a ) { return a.source === b.source && // Include flags in the comparison getRegExpFlags( a ) === getRegExpFlags( b ); }, // - skip when the property is a method of an instance (OOP) // - abort otherwise, // initial === would have catch identical references anyway "function": function() { var caller = callers[ callers.length - 1 ]; return caller !== Object && typeof caller !== "undefined"; }, "array": function( b, a ) { var i, j, len, loop, aCircular, bCircular; len = a.length; if ( len !== b.length ) { // Safe and faster return false; } // Track reference to avoid circular references parents.push( a ); parentsB.push( b ); for ( i = 0; i < len; i++ ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[ j ] === a[ i ]; bCircular = parentsB[ j ] === b[ i ]; if ( aCircular || bCircular ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) { loop = true; } else { parents.pop(); parentsB.pop(); return false; } } } if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { parents.pop(); parentsB.pop(); return false; } } parents.pop(); parentsB.pop(); return true; }, "set": function( b, a ) { var innerEq, outerEq = true; if ( a.size !== b.size ) { return false; } a.forEach( function( aVal ) { innerEq = false; b.forEach( function( bVal ) { if ( innerEquiv( bVal, aVal ) ) { innerEq = true; } } ); if ( !innerEq ) { outerEq = false; } } ); return outerEq; }, "map": function( b, a ) { var innerEq, outerEq = true; if ( a.size !== b.size ) { return false; } a.forEach( function( aVal, aKey ) { innerEq = false; b.forEach( function( bVal, bKey ) { if ( innerEquiv( [ bVal, bKey ], [ aVal, aKey ] ) ) { innerEq = true; } } ); if ( !innerEq ) { outerEq = false; } } ); return outerEq; }, "object": function( b, a ) { var i, j, loop, aCircular, bCircular; // Default to true var eq = true; var aProperties = []; var bProperties = []; if ( compareConstructors( a, b ) === false ) { return false; } // Stack constructor before traversing properties callers.push( a.constructor ); // Track reference to avoid circular references parents.push( a ); parentsB.push( b ); // Be strict: don't ensure hasOwnProperty and go deep for ( i in a ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[ j ] === a[ i ]; bCircular = parentsB[ j ] === b[ i ]; if ( aCircular || bCircular ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) { loop = true; } else { eq = false; break; } } } aProperties.push( i ); if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { eq = false; break; } } parents.pop(); parentsB.pop(); // Unstack, we are done callers.pop(); for ( i in b ) { // Collect b's properties bProperties.push( i ); } // Ensures identical properties name return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); } }; function typeEquiv( a, b ) { var type = QUnit.objectType( a ); return QUnit.objectType( b ) === type && callbacks[ type ]( b, a ); } // The real equiv function function innerEquiv( a, b ) { // We're done when there's nothing more to compare if ( arguments.length < 2 ) { return true; } // Require type-specific equality return ( a === b || typeEquiv( a, b ) ) && // ...across all consecutive argument pairs ( arguments.length === 2 || innerEquiv.apply( this, [].slice.call( arguments, 1 ) ) ); } return innerEquiv; }() );