diff --git a/.jscsrc b/.jscsrc index 81de6df1c..12beb8da6 100644 --- a/.jscsrc +++ b/.jscsrc @@ -8,5 +8,11 @@ "es3": true, // We want to output all errors - "maxErrors": 1000000 + "maxErrors": 1000000, + + "excludeFiles": [ + "dist/**/*", + "external/**/*", + "ui/vendor/**/*" + ] } diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 000000000..8026d53f7 --- /dev/null +++ b/.jshintignore @@ -0,0 +1,3 @@ +dist/**/* +external/**/* +ui/vendor/**/* diff --git a/Gruntfile.js b/Gruntfile.js index 78885382f..3e804cd64 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -252,6 +252,17 @@ grunt.initConfig( { }, bowercopy: { + inlineVendors: { + options: { + clean: true, + destPrefix: "ui/vendor" + }, + files: { + "jquery-color/jquery.color.js": "jquery-color/dist/jquery.color.js", + "jquery-color/LICENSE.txt": "jquery-color/LICENSE.txt" + } + }, + all: { options: { clean: true, @@ -422,8 +433,8 @@ grunt.initConfig( { "jquery-migrate-1.4.1/jquery-migrate.js": "jquery-migrate-1.4.1/dist/jquery-migrate.js", "jquery-migrate-1.4.1/LICENSE.txt": "jquery-migrate-1.4.1/LICENSE.txt", - "jquery-migrate-3.0.0/jquery-migrate.js": "jquery-migrate-3.0.0/dist/jquery-migrate.js", - "jquery-migrate-3.0.0/LICENSE.txt": "jquery-migrate-3.0.0/LICENSE.txt" + "jquery-migrate-3.3.0/jquery-migrate.js": "jquery-migrate-3.3.0/dist/jquery-migrate.js", + "jquery-migrate-3.3.0/LICENSE.txt": "jquery-migrate-3.3.0/LICENSE.txt" } } }, diff --git a/bower.json b/bower.json index 082e009ea..640de4315 100644 --- a/bower.json +++ b/bower.json @@ -12,8 +12,9 @@ "jquery": ">=1.6" }, "devDependencies": { + "jquery-color": "2.2.0", "jquery-mousewheel": "3.1.12", - "jquery-simulate": "1.0.0", + "jquery-simulate": "1.1.1", "jshint": "2.4.4", "qunit": "1.18.0", "qunit-assert-classes": "1.0.2", @@ -67,6 +68,6 @@ "jquery-3.4.0": "jquery#3.4.0", "jquery-3.4.1": "jquery#3.4.1", "jquery-migrate-1.4.1": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-1.4.1.tgz", - "jquery-migrate-3.0.0": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.0.0.tgz" + "jquery-migrate-3.3.0": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.3.0.tgz" } } diff --git a/external/jquery-migrate-3.1.0/LICENSE.txt b/external/jquery-migrate-3.3.0/LICENSE.txt similarity index 100% rename from external/jquery-migrate-3.1.0/LICENSE.txt rename to external/jquery-migrate-3.3.0/LICENSE.txt diff --git a/external/jquery-migrate-3.1.0/jquery-migrate.js b/external/jquery-migrate-3.3.0/jquery-migrate.js similarity index 70% rename from external/jquery-migrate-3.1.0/jquery-migrate.js rename to external/jquery-migrate-3.3.0/jquery-migrate.js index 31cf2f511..d0585ceb1 100644 --- a/external/jquery-migrate-3.1.0/jquery-migrate.js +++ b/external/jquery-migrate-3.3.0/jquery-migrate.js @@ -1,12 +1,14 @@ /*! - * jQuery Migrate - v3.1.0 - 2019-06-08 + * jQuery Migrate - v3.3.0 - 2020-05-05T01:57Z * Copyright OpenJS Foundation and other contributors */ -;( function( factory ) { +( function( factory ) { + "use strict"; + if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. - define( [ "jquery" ], function ( jQuery ) { + define( [ "jquery" ], function( jQuery ) { return factory( jQuery, window ); } ); } else if ( typeof module === "object" && module.exports ) { @@ -22,18 +24,16 @@ } )( function( jQuery, window ) { "use strict"; - -jQuery.migrateVersion = "3.1.0"; - -/* exported jQueryVersionSince, compareVersions */ +jQuery.migrateVersion = "3.3.0"; // Returns 0 if v1 == v2, -1 if v1 < v2, 1 if v1 > v2 function compareVersions( v1, v2 ) { - var rVersionParts = /^(\d+)\.(\d+)\.(\d+)/, + var i, + rVersionParts = /^(\d+)\.(\d+)\.(\d+)/, v1p = rVersionParts.exec( v1 ) || [ ], v2p = rVersionParts.exec( v2 ) || [ ]; - for ( var i = 1; i <= 3; i++ ) { + for ( i = 1; i <= 3; i++ ) { if ( +v1p[ i ] > +v2p[ i ] ) { return 1; } @@ -48,8 +48,6 @@ function jQueryVersionSince( version ) { return compareVersions( jQuery.fn.jquery, version ) >= 0; } -/* exported migrateWarn, migrateWarnFunc, migrateWarnProp */ - ( function() { // Support: IE9 only @@ -76,6 +74,9 @@ function jQueryVersionSince( version ) { var warnedAbout = {}; +// By default each warning is only reported once. +jQuery.migrateDeduplicateWarnings = true; + // List of warnings already given; public read only jQuery.migrateWarnings = []; @@ -92,7 +93,7 @@ jQuery.migrateReset = function() { function migrateWarn( msg ) { var console = window.console; - if ( !warnedAbout[ msg ] ) { + if ( !jQuery.migrateDeduplicateWarnings || !warnedAbout[ msg ] ) { warnedAbout[ msg ] = true; jQuery.migrateWarnings.push( msg ); if ( console && console.warn && !jQuery.migrateMute ) { @@ -132,12 +133,17 @@ if ( window.document.compatMode === "BackCompat" ) { migrateWarn( "jQuery is not compatible with Quirks Mode" ); } - -var oldInit = jQuery.fn.init, - oldIsNumeric = jQuery.isNumeric, +var findProp, + class2type = {}, + oldInit = jQuery.fn.init, oldFind = jQuery.find, + rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, - rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g; + rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; jQuery.fn.init = function( arg1 ) { var args = Array.prototype.slice.call( arguments ); @@ -187,7 +193,6 @@ jQuery.find = function( selector ) { }; // Copy properties attached to original jQuery.find method (e.g. .attr, .isXML) -var findProp; for ( findProp in oldFind ) { if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) { jQuery.find[ findProp ] = oldFind[ findProp ]; @@ -195,42 +200,15 @@ for ( findProp in oldFind ) { } // The number of elements contained in the matched element set -jQuery.fn.size = function() { - migrateWarn( "jQuery.fn.size() is deprecated and removed; use the .length property" ); +migrateWarnFunc( jQuery.fn, "size", function() { return this.length; -}; +}, +"jQuery.fn.size() is deprecated and removed; use the .length property" ); -jQuery.parseJSON = function() { - migrateWarn( "jQuery.parseJSON is deprecated; use JSON.parse" ); +migrateWarnFunc( jQuery, "parseJSON", function() { return JSON.parse.apply( null, arguments ); -}; - -jQuery.isNumeric = function( val ) { - - // The jQuery 2.2.3 implementation of isNumeric - function isNumeric2( obj ) { - var realStringObj = obj && obj.toString(); - return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; - } - - var newValue = oldIsNumeric( val ), - oldValue = isNumeric2( val ); - - if ( newValue !== oldValue ) { - migrateWarn( "jQuery.isNumeric() should not be called on constructed objects" ); - } - - return oldValue; -}; - -if ( jQueryVersionSince( "3.3.0" ) ) { - migrateWarnFunc( jQuery, "isWindow", - function( obj ) { - return obj != null && obj === obj.window; - }, - "jQuery.isWindow() is deprecated" - ); -} +}, +"jQuery.parseJSON is deprecated; use JSON.parse" ); migrateWarnFunc( jQuery, "holdReady", jQuery.holdReady, "jQuery.holdReady is deprecated" ); @@ -244,12 +222,81 @@ migrateWarnProp( jQuery.expr, "filters", jQuery.expr.pseudos, migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos" ); +// Prior to jQuery 3.1.1 there were internal refs so we don't warn there +if ( jQueryVersionSince( "3.1.1" ) ) { + migrateWarnFunc( jQuery, "trim", function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + "jQuery.trim is deprecated; use String.prototype.trim" ); +} + // Prior to jQuery 3.2 there were internal refs so we don't warn there if ( jQueryVersionSince( "3.2.0" ) ) { - migrateWarnFunc( jQuery, "nodeName", jQuery.nodeName, + migrateWarnFunc( jQuery, "nodeName", function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, "jQuery.nodeName is deprecated" ); } +if ( jQueryVersionSince( "3.3.0" ) ) { + + migrateWarnFunc( jQuery, "isNumeric", function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = typeof obj; + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, e.g. hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + "jQuery.isNumeric() is deprecated" + ); + + // Populate the class2type map + jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol". + split( " " ), + function( _, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + + migrateWarnFunc( jQuery, "type", function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ Object.prototype.toString.call( obj ) ] || "object" : + typeof obj; + }, + "jQuery.type is deprecated" ); + + migrateWarnFunc( jQuery, "isFunction", + function( obj ) { + return typeof obj === "function"; + }, + "jQuery.isFunction() is deprecated" ); + + migrateWarnFunc( jQuery, "isWindow", + function( obj ) { + return obj != null && obj === obj.window; + }, + "jQuery.isWindow() is deprecated" + ); + + migrateWarnFunc( jQuery, "isArray", Array.isArray, + "jQuery.isArray is deprecated; use Array.isArray" + ); +} + +// Support jQuery slim which excludes the ajax module +if ( jQuery.ajax ) { var oldAjax = jQuery.ajax; @@ -269,6 +316,7 @@ jQuery.ajax = function( ) { return jQXHR; }; +} var oldRemoveAttr = jQuery.fn.removeAttr, oldToggleClass = jQuery.fn.toggleClass, @@ -318,8 +366,38 @@ jQuery.fn.toggleClass = function( state ) { } ); }; +function camelCase( string ) { + return string.replace( /-([a-z])/g, function( _, letter ) { + return letter.toUpperCase(); + } ); +} -var internalSwapCall = false; +var oldFnCss, + internalSwapCall = false, + ralphaStart = /^[a-z]/, + + // The regex visualized: + // + // /----------\ + // | | /-------\ + // | / Top \ | | | + // /--- Border ---+-| Right |-+---+- Width -+---\ + // | | Bottom | | + // | \ Left / | + // | | + // | /----------\ | + // | /-------------\ | | |- END + // | | | | / Top \ | | + // | | / Margin \ | | | Right | | | + // |---------+-| |-+---+-| Bottom |-+----| + // | \ Padding / \ Left / | + // BEGIN -| | + // | /---------\ | + // | | | | + // | | / Min \ | / Width \ | + // \--------------+-| |-+---| |---/ + // \ Max / \ Height / + rautoPx = /^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/; // If this version of jQuery has .swap(), don't false-alarm on internal uses if ( jQuery.swap ) { @@ -363,17 +441,58 @@ jQuery.swap = function( elem, options, callback, args ) { return ret; }; +if ( jQueryVersionSince( "3.4.0" ) && typeof Proxy !== "undefined" ) { + + jQuery.cssProps = new Proxy( jQuery.cssProps || {}, { + set: function() { + migrateWarn( "JQMIGRATE: jQuery.cssProps is deprecated" ); + return Reflect.set.apply( this, arguments ); + } + } ); +} + +// Create a dummy jQuery.cssNumber if missing. It won't be used by jQuery but +// it will prevent code adding new keys to it unconditionally from crashing. +if ( !jQuery.cssNumber ) { + jQuery.cssNumber = {}; +} + +function isAutoPx( prop ) { + + // The first test is used to ensure that: + // 1. The prop starts with a lowercase letter (as we uppercase it for the second regex). + // 2. The prop is not empty. + return ralphaStart.test( prop ) && + rautoPx.test( prop[ 0 ].toUpperCase() + prop.slice( 1 ) ); +} + +oldFnCss = jQuery.fn.css; + +jQuery.fn.css = function( name, value ) { + var origThis = this; + if ( typeof name !== "string" ) { + jQuery.each( name, function( n, v ) { + jQuery.fn.css.call( origThis, n, v ); + } ); + } + if ( typeof value === "number" && !isAutoPx( camelCase( name ) ) ) { + migrateWarn( "Use of number-typed values is deprecated in jQuery.fn.css" ); + } + + return oldFnCss.apply( this, arguments ); +}; + var oldData = jQuery.data; jQuery.data = function( elem, name, value ) { - var curData; + var curData, sameKeys, key; // Name can be an object, and each entry in the object is meant to be set as data if ( name && typeof name === "object" && arguments.length === 2 ) { curData = jQuery.hasData( elem ) && oldData.call( this, elem ); - var sameKeys = {}; - for ( var key in name ) { - if ( key !== jQuery.camelCase( key ) ) { + sameKeys = {}; + for ( key in name ) { + if ( key !== camelCase( key ) ) { migrateWarn( "jQuery.data() always sets/gets camelCased names: " + key ); curData[ key ] = name[ key ]; } else { @@ -387,7 +506,7 @@ jQuery.data = function( elem, name, value ) { } // If the name is transformed, look for the un-transformed name in the data object - if ( name && typeof name === "string" && name !== jQuery.camelCase( name ) ) { + if ( name && typeof name === "string" && name !== camelCase( name ) ) { curData = jQuery.hasData( elem ) && oldData.call( this, elem ); if ( curData && name in curData ) { migrateWarn( "jQuery.data() always sets/gets camelCased names: " + name ); @@ -401,8 +520,12 @@ jQuery.data = function( elem, name, value ) { return oldData.apply( this, arguments ); }; -var oldTweenRun = jQuery.Tween.prototype.run; -var linearEasing = function( pct ) { +// Support jQuery slim which excludes the effects module +if ( jQuery.fx ) { + +var intervalValue, intervalMsg, + oldTweenRun = jQuery.Tween.prototype.run, + linearEasing = function( pct ) { return pct; }; @@ -418,8 +541,8 @@ jQuery.Tween.prototype.run = function( ) { oldTweenRun.apply( this, arguments ); }; -var intervalValue = jQuery.fx.interval || 13, - intervalMsg = "jQuery.fx.interval is deprecated"; +intervalValue = jQuery.fx.interval || 13; +intervalMsg = "jQuery.fx.interval is deprecated"; // Support: IE9, Android <=4.4 // Avoid false positives on browsers that lack rAF @@ -441,6 +564,8 @@ if ( window.requestAnimationFrame ) { } ); } +} + var oldLoad = jQuery.fn.load, oldEventAdd = jQuery.event.add, originalFix = jQuery.event.fix; @@ -571,28 +696,57 @@ jQuery.fn.extend( { } } ); +var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + origHtmlPrefilter = jQuery.htmlPrefilter, + makeMarkup = function( html ) { + var doc = window.document.implementation.createHTMLDocument( "" ); + doc.body.innerHTML = html; + return doc.body && doc.body.innerHTML; + }, + warnIfChanged = function( html ) { + var changed = html.replace( rxhtmlTag, "<$1>" ); + if ( changed !== html && makeMarkup( html ) !== makeMarkup( changed ) ) { + migrateWarn( "HTML tags must be properly nested and closed: " + html ); + } + }; + +jQuery.UNSAFE_restoreLegacyHtmlPrefilter = function() { + jQuery.htmlPrefilter = function( html ) { + warnIfChanged( html ); + return html.replace( rxhtmlTag, "<$1>" ); + }; +}; + +jQuery.htmlPrefilter = function( html ) { + warnIfChanged( html ); + return origHtmlPrefilter( html ); +}; var oldOffset = jQuery.fn.offset; jQuery.fn.offset = function() { var docElem, elem = this[ 0 ], - origin = { top: 0, left: 0 }; + bogus = { top: 0, left: 0 }; if ( !elem || !elem.nodeType ) { migrateWarn( "jQuery.fn.offset() requires a valid DOM element" ); - return origin; + return undefined; } docElem = ( elem.ownerDocument || window.document ).documentElement; if ( !jQuery.contains( docElem, elem ) ) { migrateWarn( "jQuery.fn.offset() requires an element connected to a document" ); - return origin; + return bogus; } return oldOffset.apply( this, arguments ); }; +// Support jQuery slim which excludes the ajax module +// The jQuery.param patch is about respecting `jQuery.ajaxSettings.traditional` +// so it doesn't make sense for the slim build. +if ( jQuery.ajax ) { var oldParam = jQuery.param; @@ -608,6 +762,8 @@ jQuery.param = function( data, traditional ) { return oldParam.call( this, data, traditional ); }; +} + var oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack; jQuery.fn.andSelf = function() { @@ -615,6 +771,8 @@ jQuery.fn.andSelf = function() { return oldSelf.apply( this, arguments ); }; +// Support jQuery slim which excludes the deferred module in jQuery 4.0+ +if ( jQuery.Deferred ) { var oldDeferred = jQuery.Deferred, tuples = [ @@ -639,14 +797,14 @@ jQuery.Deferred = function( func ) { return jQuery.Deferred( function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { - var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + var fn = typeof fns[ i ] === "function" && fns[ i ]; // Deferred.done(function() { bind to newDefer or newDefer.resolve }) // deferred.fail(function() { bind to newDefer or newDefer.reject }) // deferred.progress(function() { bind to newDefer or newDefer.notify }) deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { + if ( returned && typeof returned.promise === "function" ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) @@ -674,5 +832,7 @@ jQuery.Deferred = function( func ) { // Preserve handler of uncaught exceptions in promise chains jQuery.Deferred.exceptionHook = oldDeferred.exceptionHook; +} + return jQuery; } ); diff --git a/external/jquery-simulate/LICENSE.txt b/external/jquery-simulate/LICENSE.txt index 24cad742e..38d2ab8bd 100644 --- a/external/jquery-simulate/LICENSE.txt +++ b/external/jquery-simulate/LICENSE.txt @@ -1,5 +1,4 @@ -Copyright 2007, 2014 jQuery Foundation and other contributors, -https://jquery.org/ +Copyright jQuery Foundation and other contributors, https://jquery.org/ This software consists of voluntary contributions made by many individuals. For exact contribution history, see the revision history diff --git a/external/jquery-simulate/jquery.simulate.js b/external/jquery-simulate/jquery.simulate.js index 4a96cc310..8bcc2e479 100644 --- a/external/jquery-simulate/jquery.simulate.js +++ b/external/jquery-simulate/jquery.simulate.js @@ -1,19 +1,28 @@ /*! - * jQuery Simulate v1.0.0 - simulate browser mouse and keyboard events + * jQuery Simulate v1.1.1 - simulate browser mouse and keyboard events * https://github.com/jquery/jquery-simulate * - * Copyright 2012 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * - * Date: 2014-08-22 + * Date: 2020-05-06 */ ;(function( $, undefined ) { var rkeyEvent = /^key/, + rdashAlpha = /-([a-z])/g, rmouseEvent = /^(?:mouse|contextmenu)|click/; +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +function camelCase( string ) { + return string.replace( rdashAlpha, fcamelCase ); +} + $.fn.simulate = function( type, options ) { return this.each(function() { new $.simulate( this, type, options ); @@ -21,7 +30,7 @@ $.fn.simulate = function( type, options ) { }; $.simulate = function( elem, type, options ) { - var method = $.camelCase( "simulate-" + type ); + var method = camelCase( "simulate-" + type ); this.target = elem; this.options = options; @@ -201,10 +210,10 @@ $.extend( $.simulate.prototype, { }, dispatchEvent: function( elem, type, event ) { - if ( elem[ type ] ) { - elem[ type ](); - } else if ( elem.dispatchEvent ) { + if ( elem.dispatchEvent ) { elem.dispatchEvent( event ); + } else if ( type === "click" && elem.click && elem.nodeName.toLowerCase() === "input" ) { + elem.click(); } else if ( elem.fireEvent ) { elem.fireEvent( "on" + type, event ); } @@ -219,7 +228,7 @@ $.extend( $.simulate.prototype, { triggered = true; } - element.bind( "focus", trigger ); + element.on( "focus", trigger ); element[ 0 ].focus(); if ( !triggered ) { @@ -228,7 +237,7 @@ $.extend( $.simulate.prototype, { element.trigger( focusinEvent ); element.triggerHandler( "focus" ); } - element.unbind( "focus", trigger ); + element.off( "focus", trigger ); }, simulateBlur: function() { @@ -240,7 +249,7 @@ $.extend( $.simulate.prototype, { triggered = true; } - element.bind( "blur", trigger ); + element.on( "blur", trigger ); element[ 0 ].blur(); // blur events are async in IE @@ -258,7 +267,7 @@ $.extend( $.simulate.prototype, { element.trigger( focusoutEvent ); element.triggerHandler( "blur" ); } - element.unbind( "blur", trigger ); + element.off( "blur", trigger ); }, 1 ); } }); @@ -295,6 +304,7 @@ $.extend( $.simulate.prototype, { simulateDrag: function() { var i = 0, target = this.target, + eventDoc = target.ownerDocument, options = this.options, center = options.handle === "corner" ? findCorner( target ) : findCenter( target ), x = Math.floor( center.x ), @@ -315,14 +325,14 @@ $.extend( $.simulate.prototype, { clientY: Math.round( y ) }; - this.simulateEvent( target.ownerDocument, "mousemove", coord ); + this.simulateEvent( eventDoc, "mousemove", coord ); } - if ( $.contains( document, target ) ) { + if ( $.contains( eventDoc, target ) ) { this.simulateEvent( target, "mouseup", coord ); this.simulateEvent( target, "click", coord ); } else { - this.simulateEvent( document, "mouseup", coord ); + this.simulateEvent( eventDoc, "mouseup", coord ); } } }); diff --git a/tests/lib/bootstrap.js b/tests/lib/bootstrap.js index 0134d1d03..58710367c 100644 --- a/tests/lib/bootstrap.js +++ b/tests/lib/bootstrap.js @@ -120,7 +120,7 @@ function migrateUrl() { if ( jqueryVersion === "git" ) { url = "https://code.jquery.com/jquery-migrate-git"; } else if ( jqueryVersion[ 0 ] === "3" ) { - url = "../../../external/jquery-migrate-3.1.0/jquery-migrate"; + url = "../../../external/jquery-migrate-3.3.0/jquery-migrate"; } else if ( jqueryVersion[ 0 ] === "1" || jqueryVersion[ 0 ] === "2" ) { url = "../../../external/jquery-migrate-1.4.1/jquery-migrate"; } else if ( jqueryVersion === "custom" ) { diff --git a/ui/effect.js b/ui/effect.js index 417e83b08..401eba260 100644 --- a/ui/effect.js +++ b/ui/effect.js @@ -19,7 +19,11 @@ if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. - define( [ "jquery", "./version" ], factory ); + define( [ + "jquery", + "./vendor/jquery-color/jquery.color", + "./version" + ], factory ); } else { // Browser globals @@ -39,687 +43,6 @@ $.effects = { effect: {} }; -// jscs:disable - -/*! - * jQuery Color Animations v2.1.2 - * https://github.com/jquery/jquery-color - * - * Copyright 2014 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * Date: Wed Jan 16 08:47:09 2013 -0600 - */ -( function( jQuery, undefined ) { - - var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + - "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", - - // Plusequals test for += 100 -= 100 - rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, - - // A set of RE's that can match strings and generate color tuples. - stringParsers = [ { - re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ], - execResult[ 3 ], - execResult[ 4 ] - ]; - } - }, { - re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ] * 2.55, - execResult[ 2 ] * 2.55, - execResult[ 3 ] * 2.55, - execResult[ 4 ] - ]; - } - }, { - - // This regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ], 16 ) - ]; - } - }, { - - // This regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) - ]; - } - }, { - re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - space: "hsla", - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ] / 100, - execResult[ 3 ] / 100, - execResult[ 4 ] - ]; - } - } ], - - // JQuery.Color( ) - color = jQuery.Color = function( color, green, blue, alpha ) { - return new jQuery.Color.fn.parse( color, green, blue, alpha ); - }, - spaces = { - rgba: { - props: { - red: { - idx: 0, - type: "byte" - }, - green: { - idx: 1, - type: "byte" - }, - blue: { - idx: 2, - type: "byte" - } - } - }, - - hsla: { - props: { - hue: { - idx: 0, - type: "degrees" - }, - saturation: { - idx: 1, - type: "percent" - }, - lightness: { - idx: 2, - type: "percent" - } - } - } - }, - propTypes = { - "byte": { - floor: true, - max: 255 - }, - "percent": { - max: 1 - }, - "degrees": { - mod: 360, - floor: true - } - }, - support = color.support = {}, - - // Element for support tests - supportElem = jQuery( "

" )[ 0 ], - - // Colors = jQuery.Color.names - colors, - - // Local aliases of functions called often - each = jQuery.each; - -// Determine rgba support immediately -supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; -support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; - -// Define cache name and alpha properties -// for rgba and hsla spaces -each( spaces, function( spaceName, space ) { - space.cache = "_" + spaceName; - space.props.alpha = { - idx: 3, - type: "percent", - def: 1 - }; -} ); - -function clamp( value, prop, allowEmpty ) { - var type = propTypes[ prop.type ] || {}; - - if ( value == null ) { - return ( allowEmpty || !prop.def ) ? null : prop.def; - } - - // ~~ is an short way of doing floor for positive numbers - value = type.floor ? ~~value : parseFloat( value ); - - // IE will pass in empty strings as value for alpha, - // which will hit this case - if ( isNaN( value ) ) { - return prop.def; - } - - if ( type.mod ) { - - // We add mod before modding to make sure that negatives values - // get converted properly: -10 -> 350 - return ( value + type.mod ) % type.mod; - } - - // For now all property types without mod have min and max - return 0 > value ? 0 : type.max < value ? type.max : value; -} - -function stringParse( string ) { - var inst = color(), - rgba = inst._rgba = []; - - string = string.toLowerCase(); - - each( stringParsers, function( i, parser ) { - var parsed, - match = parser.re.exec( string ), - values = match && parser.parse( match ), - spaceName = parser.space || "rgba"; - - if ( values ) { - parsed = inst[ spaceName ]( values ); - - // If this was an rgba parse the assignment might happen twice - // oh well.... - inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; - rgba = inst._rgba = parsed._rgba; - - // Exit each( stringParsers ) here because we matched - return false; - } - } ); - - // Found a stringParser that handled it - if ( rgba.length ) { - - // If this came from a parsed string, force "transparent" when alpha is 0 - // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) - if ( rgba.join() === "0,0,0,0" ) { - jQuery.extend( rgba, colors.transparent ); - } - return inst; - } - - // Named colors - return colors[ string ]; -} - -color.fn = jQuery.extend( color.prototype, { - parse: function( red, green, blue, alpha ) { - if ( red === undefined ) { - this._rgba = [ null, null, null, null ]; - return this; - } - if ( red.jquery || red.nodeType ) { - red = jQuery( red ).css( green ); - green = undefined; - } - - var inst = this, - type = jQuery.type( red ), - rgba = this._rgba = []; - - // More than 1 argument specified - assume ( red, green, blue, alpha ) - if ( green !== undefined ) { - red = [ red, green, blue, alpha ]; - type = "array"; - } - - if ( type === "string" ) { - return this.parse( stringParse( red ) || colors._default ); - } - - if ( type === "array" ) { - each( spaces.rgba.props, function( key, prop ) { - rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); - } ); - return this; - } - - if ( type === "object" ) { - if ( red instanceof color ) { - each( spaces, function( spaceName, space ) { - if ( red[ space.cache ] ) { - inst[ space.cache ] = red[ space.cache ].slice(); - } - } ); - } else { - each( spaces, function( spaceName, space ) { - var cache = space.cache; - each( space.props, function( key, prop ) { - - // If the cache doesn't exist, and we know how to convert - if ( !inst[ cache ] && space.to ) { - - // If the value was null, we don't need to copy it - // if the key was alpha, we don't need to copy it either - if ( key === "alpha" || red[ key ] == null ) { - return; - } - inst[ cache ] = space.to( inst._rgba ); - } - - // This is the only case where we allow nulls for ALL properties. - // call clamp with alwaysAllowEmpty - inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); - } ); - - // Everything defined but alpha? - if ( inst[ cache ] && - jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { - - // Use the default of 1 - inst[ cache ][ 3 ] = 1; - if ( space.from ) { - inst._rgba = space.from( inst[ cache ] ); - } - } - } ); - } - return this; - } - }, - is: function( compare ) { - var is = color( compare ), - same = true, - inst = this; - - each( spaces, function( _, space ) { - var localCache, - isCache = is[ space.cache ]; - if ( isCache ) { - localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; - each( space.props, function( _, prop ) { - if ( isCache[ prop.idx ] != null ) { - same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); - return same; - } - } ); - } - return same; - } ); - return same; - }, - _space: function() { - var used = [], - inst = this; - each( spaces, function( spaceName, space ) { - if ( inst[ space.cache ] ) { - used.push( spaceName ); - } - } ); - return used.pop(); - }, - transition: function( other, distance ) { - var end = color( other ), - spaceName = end._space(), - space = spaces[ spaceName ], - startColor = this.alpha() === 0 ? color( "transparent" ) : this, - start = startColor[ space.cache ] || space.to( startColor._rgba ), - result = start.slice(); - - end = end[ space.cache ]; - each( space.props, function( key, prop ) { - var index = prop.idx, - startValue = start[ index ], - endValue = end[ index ], - type = propTypes[ prop.type ] || {}; - - // If null, don't override start value - if ( endValue === null ) { - return; - } - - // If null - use end - if ( startValue === null ) { - result[ index ] = endValue; - } else { - if ( type.mod ) { - if ( endValue - startValue > type.mod / 2 ) { - startValue += type.mod; - } else if ( startValue - endValue > type.mod / 2 ) { - startValue -= type.mod; - } - } - result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); - } - } ); - return this[ spaceName ]( result ); - }, - blend: function( opaque ) { - - // If we are already opaque - return ourself - if ( this._rgba[ 3 ] === 1 ) { - return this; - } - - var rgb = this._rgba.slice(), - a = rgb.pop(), - blend = color( opaque )._rgba; - - return color( jQuery.map( rgb, function( v, i ) { - return ( 1 - a ) * blend[ i ] + a * v; - } ) ); - }, - toRgbaString: function() { - var prefix = "rgba(", - rgba = jQuery.map( this._rgba, function( v, i ) { - return v == null ? ( i > 2 ? 1 : 0 ) : v; - } ); - - if ( rgba[ 3 ] === 1 ) { - rgba.pop(); - prefix = "rgb("; - } - - return prefix + rgba.join() + ")"; - }, - toHslaString: function() { - var prefix = "hsla(", - hsla = jQuery.map( this.hsla(), function( v, i ) { - if ( v == null ) { - v = i > 2 ? 1 : 0; - } - - // Catch 1 and 2 - if ( i && i < 3 ) { - v = Math.round( v * 100 ) + "%"; - } - return v; - } ); - - if ( hsla[ 3 ] === 1 ) { - hsla.pop(); - prefix = "hsl("; - } - return prefix + hsla.join() + ")"; - }, - toHexString: function( includeAlpha ) { - var rgba = this._rgba.slice(), - alpha = rgba.pop(); - - if ( includeAlpha ) { - rgba.push( ~~( alpha * 255 ) ); - } - - return "#" + jQuery.map( rgba, function( v ) { - - // Default to 0 when nulls exist - v = ( v || 0 ).toString( 16 ); - return v.length === 1 ? "0" + v : v; - } ).join( "" ); - }, - toString: function() { - return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); - } -} ); -color.fn.parse.prototype = color.fn; - -// Hsla conversions adapted from: -// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 - -function hue2rgb( p, q, h ) { - h = ( h + 1 ) % 1; - if ( h * 6 < 1 ) { - return p + ( q - p ) * h * 6; - } - if ( h * 2 < 1 ) { - return q; - } - if ( h * 3 < 2 ) { - return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; - } - return p; -} - -spaces.hsla.to = function( rgba ) { - if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { - return [ null, null, null, rgba[ 3 ] ]; - } - var r = rgba[ 0 ] / 255, - g = rgba[ 1 ] / 255, - b = rgba[ 2 ] / 255, - a = rgba[ 3 ], - max = Math.max( r, g, b ), - min = Math.min( r, g, b ), - diff = max - min, - add = max + min, - l = add * 0.5, - h, s; - - if ( min === max ) { - h = 0; - } else if ( r === max ) { - h = ( 60 * ( g - b ) / diff ) + 360; - } else if ( g === max ) { - h = ( 60 * ( b - r ) / diff ) + 120; - } else { - h = ( 60 * ( r - g ) / diff ) + 240; - } - - // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0% - // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) - if ( diff === 0 ) { - s = 0; - } else if ( l <= 0.5 ) { - s = diff / add; - } else { - s = diff / ( 2 - add ); - } - return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; -}; - -spaces.hsla.from = function( hsla ) { - if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { - return [ null, null, null, hsla[ 3 ] ]; - } - var h = hsla[ 0 ] / 360, - s = hsla[ 1 ], - l = hsla[ 2 ], - a = hsla[ 3 ], - q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, - p = 2 * l - q; - - return [ - Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), - Math.round( hue2rgb( p, q, h ) * 255 ), - Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), - a - ]; -}; - -each( spaces, function( spaceName, space ) { - var props = space.props, - cache = space.cache, - to = space.to, - from = space.from; - - // Makes rgba() and hsla() - color.fn[ spaceName ] = function( value ) { - - // Generate a cache for this space if it doesn't exist - if ( to && !this[ cache ] ) { - this[ cache ] = to( this._rgba ); - } - if ( value === undefined ) { - return this[ cache ].slice(); - } - - var ret, - type = jQuery.type( value ), - arr = ( type === "array" || type === "object" ) ? value : arguments, - local = this[ cache ].slice(); - - each( props, function( key, prop ) { - var val = arr[ type === "object" ? key : prop.idx ]; - if ( val == null ) { - val = local[ prop.idx ]; - } - local[ prop.idx ] = clamp( val, prop ); - } ); - - if ( from ) { - ret = color( from( local ) ); - ret[ cache ] = local; - return ret; - } else { - return color( local ); - } - }; - - // Makes red() green() blue() alpha() hue() saturation() lightness() - each( props, function( key, prop ) { - - // Alpha is included in more than one space - if ( color.fn[ key ] ) { - return; - } - color.fn[ key ] = function( value ) { - var vtype = jQuery.type( value ), - fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), - local = this[ fn ](), - cur = local[ prop.idx ], - match; - - if ( vtype === "undefined" ) { - return cur; - } - - if ( vtype === "function" ) { - value = value.call( this, cur ); - vtype = jQuery.type( value ); - } - if ( value == null && prop.empty ) { - return this; - } - if ( vtype === "string" ) { - match = rplusequals.exec( value ); - if ( match ) { - value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); - } - } - local[ prop.idx ] = value; - return this[ fn ]( local ); - }; - } ); -} ); - -// Add cssHook and .fx.step function for each named hook. -// accept a space separated string of properties -color.hook = function( hook ) { - var hooks = hook.split( " " ); - each( hooks, function( i, hook ) { - jQuery.cssHooks[ hook ] = { - set: function( elem, value ) { - var parsed, curElem, - backgroundColor = ""; - - if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || - ( parsed = stringParse( value ) ) ) ) { - value = color( parsed || value ); - if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { - curElem = hook === "backgroundColor" ? elem.parentNode : elem; - while ( - ( backgroundColor === "" || backgroundColor === "transparent" ) && - curElem && curElem.style - ) { - try { - backgroundColor = jQuery.css( curElem, "backgroundColor" ); - curElem = curElem.parentNode; - } catch ( e ) { - } - } - - value = value.blend( backgroundColor && backgroundColor !== "transparent" ? - backgroundColor : - "_default" ); - } - - value = value.toRgbaString(); - } - try { - elem.style[ hook ] = value; - } catch ( e ) { - - // Wrapped to prevent IE from throwing errors on "invalid" values like - // 'auto' or 'inherit' - } - } - }; - jQuery.fx.step[ hook ] = function( fx ) { - if ( !fx.colorInit ) { - fx.start = color( fx.elem, hook ); - fx.end = color( fx.end ); - fx.colorInit = true; - } - jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); - }; - } ); - -}; - -color.hook( stepHooks ); - -jQuery.cssHooks.borderColor = { - expand: function( value ) { - var expanded = {}; - - each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { - expanded[ "border" + part + "Color" ] = value; - } ); - return expanded; - } -}; - -// Basic color names only. -// Usage of any of the other color names requires adding yourself or including -// jquery.color.svg-names.js. -colors = jQuery.Color.names = { - - // 4.1. Basic color keywords - aqua: "#00ffff", - black: "#000000", - blue: "#0000ff", - fuchsia: "#ff00ff", - gray: "#808080", - green: "#008000", - lime: "#00ff00", - maroon: "#800000", - navy: "#000080", - olive: "#808000", - purple: "#800080", - red: "#ff0000", - silver: "#c0c0c0", - teal: "#008080", - white: "#ffffff", - yellow: "#ffff00", - - // 4.2.3. "transparent" color keyword - transparent: [ null, null, null, 0 ], - - _default: "#ffffff" -}; - -} )( jQuery ); - -// jscs:enable - /******************************************************************************/ /****************************** CLASS ANIMATIONS ******************************/ /******************************************************************************/ diff --git a/ui/vendor/jquery-color/LICENSE.txt b/ui/vendor/jquery-color/LICENSE.txt new file mode 100644 index 000000000..6a864b8ba --- /dev/null +++ b/ui/vendor/jquery-color/LICENSE.txt @@ -0,0 +1,43 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery-color + +The following license applies to all parts of jQuery Color except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the README. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/ui/vendor/jquery-color/jquery.color.js b/ui/vendor/jquery-color/jquery.color.js new file mode 100644 index 000000000..c291d96ae --- /dev/null +++ b/ui/vendor/jquery-color/jquery.color.js @@ -0,0 +1,722 @@ +/*! + * jQuery Color Animations v2.2.0 + * https://github.com/jquery/jquery-color + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Sun May 10 09:02:36 2020 +0200 + */ + +( function( root, factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery" ], factory ); + } else if ( typeof exports === "object" ) { + module.exports = factory( require( "jquery" ) ); + } else { + factory( root.jQuery ); + } +} )( this, function( jQuery, undefined ) { + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + + "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", + + class2type = {}, + toString = class2type.toString, + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + + // a set of RE's that can match strings and generate color tuples. + stringParsers = [ { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) : + 1 + ]; + } + }, { + + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 ) + .toFixed( 2 ) : + 1 + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + } ], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, + + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + support = color.support = {}, + + // element for support tests + supportElem = jQuery( "

" )[ 0 ], + + // colors = jQuery.Color.names + colors, + + // local aliases of functions called often + each = jQuery.each; + +// determine rgba support immediately +supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; +support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; + +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +} ); + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function getType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + return typeof obj === "object" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} + +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + + if ( value == null ) { + return ( allowEmpty || !prop.def ) ? null : prop.def; + } + + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); + + // IE will pass in empty strings as value for alpha, + // which will hit this case + if ( isNaN( value ) ) { + return prop.def; + } + + if ( type.mod ) { + + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return ( value + type.mod ) % type.mod; + } + + // for now all property types without mod have min and max + return Math.min( type.max, Math.max( 0, value ) ); +} + +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; + + string = string.toLowerCase(); + + each( stringParsers, function( _i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; + } + } ); + + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } + + // named colors + return colors[ string ]; +} + +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } + + var inst = this, + type = getType( red ), + rgba = this._rgba = []; + + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; + } + + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } + + if ( type === "array" ) { + each( spaces.rgba.props, function( _key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + } ); + return this; + } + + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( _spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + } ); + } else { + each( spaces, function( _spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { + + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + } ); + + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + + // use the default of 1 + if ( inst[ cache ][ 3 ] == null ) { + inst[ cache ][ 3 ] = 1; + } + + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + } ); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if ( isCache ) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + } ); + } + return same; + } ); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + } ); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( _key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + } ); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } + + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; + + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + } ) ); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + if ( v != null ) { + return v; + } + return i > 2 ? 1 : 0; + } ); + + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + + return prefix + rgba.join() + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } + + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + } ); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join() + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); + + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } + + return "#" + jQuery.map( rgba, function( v ) { + + // default to 0 when nulls exist + v = ( v || 0 ).toString( 16 ); + return v.length === 1 ? "0" + v : v; + } ).join( "" ); + }, + toString: function() { + return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); + } +} ); +color.fn.parse.prototype = color.fn; + +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 + +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + ( q - p ) * h * 6; + } + if ( h * 2 < 1 ) { + return q; + } + if ( h * 3 < 2 ) { + return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; + } + return p; +} + +spaces.hsla.to = function( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } + + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; +}; + +spaces.hsla.from = function( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; + + +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } + + var ret, + type = getType( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + } ); + + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; + + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var local, cur, match, fn, + vtype = getType( value ); + + if ( key === "alpha" ) { + fn = this._hsla ? "hsla" : "rgba"; + } else { + fn = spaceName; + } + local = this[ fn ](); + cur = local[ prop.idx ]; + + if ( vtype === "undefined" ) { + return cur; + } + + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = getType( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + } ); +} ); + +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( _i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + + if ( value !== "transparent" && ( getType( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + ( backgroundColor === "" || backgroundColor === "transparent" ) && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } + } + + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); + } + + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch ( e ) { + + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + } + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + } ); + +}; + +color.hook( stepHooks ); + +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; + + each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) { + expanded[ "border" + part + "Color" ] = value; + } ); + return expanded; + } +}; + +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" +}; + +} );