From ef2e9bab92ae898311baa295590cd487d9071319 Mon Sep 17 00:00:00 2001 From: Scott González Date: Wed, 16 Nov 2016 14:42:34 -0500 Subject: Widget: Improve `remove` event bindings for `classes` options Fixes #15078 Fixes #15082 Fixes #15095 Fixes #15136 Fixes #15152 Closes gh-1769 --- ui/widget.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'ui/widget.js') diff --git a/ui/widget.js b/ui/widget.js index 726f70735..f87675712 100644 --- a/ui/widget.js +++ b/ui/widget.js @@ -493,11 +493,29 @@ $.Widget.prototype = { classes: this.options.classes || {} }, options ); + function bindRemoveEvent() { + options.element.each( function( _, element ) { + var isTracked = $.map( that.classesElementLookup, function( elements ) { + return elements; + } ) + .some( function( elements ) { + return elements.is( element ); + } ); + + if ( !isTracked ) { + that._on( $( element ), { + remove: "_untrackClassesElement" + } ); + } + } ); + } + function processClassString( classes, checkOption ) { var current, i; for ( i = 0; i < classes.length; i++ ) { current = that.classesElementLookup[ classes[ i ] ] || $(); if ( options.add ) { + bindRemoveEvent(); current = $( $.unique( current.get().concat( options.element.get() ) ) ); } else { current = $( current.not( options.element ).get() ); @@ -510,10 +528,6 @@ $.Widget.prototype = { } } - this._on( options.element, { - "remove": "_untrackClassesElement" - } ); - if ( options.keys ) { processClassString( options.keys.match( /\S+/g ) || [], true ); } @@ -531,6 +545,8 @@ $.Widget.prototype = { that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); } } ); + + this._off( $( event.target ) ); }, _removeClass: function( element, keys, extra ) { @@ -611,7 +627,7 @@ $.Widget.prototype = { _off: function( element, eventName ) { eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.off( eventName ).off( eventName ); + element.off( eventName ); // Clear the stack to avoid memory leaks (#10056) this.bindings = $( this.bindings.not( element ).get() ); -- cgit v1.2.3 From b3c0a7f71d0b351755b97858ad47de4e9a373606 Mon Sep 17 00:00:00 2001 From: Scott González Date: Fri, 21 Apr 2017 14:49:52 -0400 Subject: Widget: Handle `Object.create(null)` for options objects Fixes #15179 Closes gh-1809 --- tests/unit/widget/extend.js | 7 ++++++- ui/widget.js | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'ui/widget.js') diff --git a/tests/unit/widget/extend.js b/tests/unit/widget/extend.js index 36575200b..b27d925f0 100644 --- a/tests/unit/widget/extend.js +++ b/tests/unit/widget/extend.js @@ -5,7 +5,7 @@ define( [ ], function( QUnit, $ ) { QUnit.test( "$.widget.extend()", function( assert ) { - assert.expect( 27 ); + assert.expect( 28 ); var ret, empty, optionsWithLength, optionsWithDate, myKlass, customObject, optionsWithCustomObject, nullUndef, target, recursive, obj, input, output, @@ -108,6 +108,11 @@ QUnit.test( "$.widget.extend()", function( assert ) { assert.deepEqual( input, output, "don't clone arrays" ); input.key[ 0 ] = 10; assert.deepEqual( input, output, "don't clone arrays" ); + + input = Object.create( null ); + input.foo = "f"; + output = $.widget.extend( {}, input ); + assert.deepEqual( input, output, "Object with no prototype" ); } ); } ); diff --git a/ui/widget.js b/ui/widget.js index f87675712..011396811 100644 --- a/ui/widget.js +++ b/ui/widget.js @@ -26,6 +26,7 @@ }( function( $ ) { var widgetUuid = 0; +var widgetHasOwnProperty = Array.prototype.hasOwnProperty; var widgetSlice = Array.prototype.slice; $.cleanData = ( function( orig ) { @@ -183,7 +184,7 @@ $.widget.extend = function( target ) { for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) { // Clone objects if ( $.isPlainObject( value ) ) { -- cgit v1.2.3 From 0b7246b6eeadfa9e2696e22f3230f6452f8129dc Mon Sep 17 00:00:00 2001 From: Eirik Sletteberg Date: Fri, 2 Dec 2016 14:41:30 +0100 Subject: Core: Fix JQMIGRATE warning about `jQuery.expr[":"]` This commit polyfills `jQuery.expr.pseudos` for old versions of jQuery. Fixes #15185 Closes gh-1773 --- ui/data.js | 2 +- ui/focusable.js | 2 +- ui/jquery-1-7.js | 14 +++++++++++++- ui/tabbable.js | 2 +- ui/widget.js | 4 ++-- ui/widgets/controlgroup.js | 2 +- ui/widgets/tabs.js | 2 +- 7 files changed, 20 insertions(+), 8 deletions(-) (limited to 'ui/widget.js') diff --git a/ui/data.js b/ui/data.js index d0417b8f9..c02e7ffde 100644 --- a/ui/data.js +++ b/ui/data.js @@ -23,7 +23,7 @@ factory( jQuery ); } } ( function( $ ) { -return $.extend( $.expr[ ":" ], { +return $.extend( $.expr.pseudos, { data: $.expr.createPseudo ? $.expr.createPseudo( function( dataName ) { return function( elem ) { diff --git a/ui/focusable.js b/ui/focusable.js index cf4f728b8..b1a7b61e2 100644 --- a/ui/focusable.js +++ b/ui/focusable.js @@ -73,7 +73,7 @@ function visible( element ) { return visibility !== "hidden"; } -$.extend( $.expr[ ":" ], { +$.extend( $.expr.pseudos, { focusable: function( element ) { return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); } diff --git a/ui/jquery-1-7.js b/ui/jquery-1-7.js index bd40e332f..5e7907a15 100644 --- a/ui/jquery-1-7.js +++ b/ui/jquery-1-7.js @@ -1,5 +1,5 @@ /*! - * jQuery UI Support for jQuery core 1.7.x @VERSION + * jQuery UI Support for jQuery core 1.7.x and newer @VERSION * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -86,4 +86,16 @@ if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) { }; } +// Support: jQuery 1.9.x or older +// $.expr[ ":" ] is deprecated. +if ( !$.expr.pseudos ) { + $.expr.pseudos = $.expr[ ":" ]; +} + +// Support: jQuery 1.11.x or older +// $.unique has been renamed to $.uniqueSort +if ( !$.uniqueSort ) { + $.uniqueSort = $.unique; +} + } ) ); diff --git a/ui/tabbable.js b/ui/tabbable.js index 3baa641ce..bb79466e8 100644 --- a/ui/tabbable.js +++ b/ui/tabbable.js @@ -24,7 +24,7 @@ } } ( function( $ ) { -return $.extend( $.expr[ ":" ], { +return $.extend( $.expr.pseudos, { tabbable: function( element ) { var tabIndex = $.attr( element, "tabindex" ), hasTabindex = tabIndex != null; diff --git a/ui/widget.js b/ui/widget.js index 011396811..c101e59d4 100644 --- a/ui/widget.js +++ b/ui/widget.js @@ -65,7 +65,7 @@ $.widget = function( name, base, prototype ) { } // Create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; @@ -517,7 +517,7 @@ $.Widget.prototype = { current = that.classesElementLookup[ classes[ i ] ] || $(); if ( options.add ) { bindRemoveEvent(); - current = $( $.unique( current.get().concat( options.element.get() ) ) ); + current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) ); } else { current = $( current.not( options.element ).get() ); } diff --git a/ui/widgets/controlgroup.js b/ui/widgets/controlgroup.js index 6f357948d..c79f3fcaf 100644 --- a/ui/widgets/controlgroup.js +++ b/ui/widgets/controlgroup.js @@ -150,7 +150,7 @@ return $.widget( "ui.controlgroup", { } ); } ); - this.childWidgets = $( $.unique( childWidgets ) ); + this.childWidgets = $( $.uniqueSort( childWidgets ) ); this._addClass( this.childWidgets, "ui-controlgroup-item" ); }, diff --git a/ui/widgets/tabs.js b/ui/widgets/tabs.js index 58a65ebe8..14f94ae83 100644 --- a/ui/widgets/tabs.js +++ b/ui/widgets/tabs.js @@ -96,7 +96,7 @@ $.widget( "ui.tabs", { // Take disabling tabs via class attribute from HTML // into account and update option properly. if ( $.isArray( options.disabled ) ) { - options.disabled = $.unique( options.disabled.concat( + options.disabled = $.uniqueSort( options.disabled.concat( $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { return that.tabs.index( li ); } ) -- cgit v1.2.3