From edd4985b72402e37ad02dada48cbbe4c3177549d Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Wed, 8 Mar 2017 12:38:19 -0800 Subject: [PATCH] Remove support for jquery.placeholder shim Browser support according to MDN: * input placeholder: - Chrome 10 - Firefox 4 - IE 10 - Opera 11.00 - Safari 5.0 * textarea placeholder: - Chrome - Firefox 4 - IE 10 - Opera 11.50 - Safari 5.0 Bug: T159911 Change-Id: I388e99c5760681049abbe8d9c173b83af9121b02 --- resources/Resources.php | 4 +- resources/src/jquery/jquery.placeholder.js | 229 +----------------- resources/src/mediawiki/page/ready.js | 12 - .../jquery/jquery.placeholder.test.js | 138 ----------- 4 files changed, 11 insertions(+), 372 deletions(-) diff --git a/resources/Resources.php b/resources/Resources.php index d057572ea3..33bdcb98c5 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -300,6 +300,8 @@ return [ 'targets' => [ 'desktop', 'mobile' ], ], 'jquery.placeholder' => [ + 'deprecated' => 'Use of "jquery.placeholder" is deprecated since MediaWiki 1.29.0', + 'scripts' => 'resources/src/jquery/jquery.placeholder.js', 'targets' => [ 'desktop', 'mobile' ], ], @@ -1176,7 +1178,6 @@ return [ 'searchsuggest-containing', ], 'dependencies' => [ - 'jquery.placeholder', 'jquery.suggestions', 'jquery.getAttrs', 'mediawiki.api', @@ -1654,7 +1655,6 @@ return [ 'dependencies' => [ 'jquery.accessKeyLabel', 'jquery.checkboxShiftClick', - 'jquery.placeholder', 'jquery.mw-jump', ], 'targets' => [ 'desktop', 'mobile' ], diff --git a/resources/src/jquery/jquery.placeholder.js b/resources/src/jquery/jquery.placeholder.js index 12b0404b27..afb8837ff7 100644 --- a/resources/src/jquery/jquery.placeholder.js +++ b/resources/src/jquery/jquery.placeholder.js @@ -1,229 +1,18 @@ /*! - * HTML5 placeholder emulation for jQuery plugin - * - * This will automatically use the HTML5 placeholder attribute if supported, or emulate this behavior if not. - * - * This is a fork from Mathias Bynens' jquery.placeholder as of this commit - * https://github.com/mathiasbynens/jquery-placeholder/blob/47f05d400e2dd16b59d144141a2cf54a9a77c502/jquery.placeholder.js - * - * @author Mathias Bynens - * @author Trevor Parscal , 2012 - * @author Krinkle , 2012 - * @author Alex Ivanov , 2013 - * @version 2.1.0 - * @license MIT + * No-op for compatibility with code from before we used + * native placeholder in all supported browsers. */ ( function ( $ ) { + var placeholder; - var isInputSupported = 'placeholder' in document.createElement( 'input' ), - isTextareaSupported = 'placeholder' in document.createElement( 'textarea' ), - prototype = $.fn, - valHooks = $.valHooks, - propHooks = $.propHooks, - hooks, - placeholder; - - function safeActiveElement() { - // Avoid IE9 `document.activeElement` of death - // https://github.com/mathiasbynens/jquery-placeholder/pull/99 - try { - return document.activeElement; - } catch ( err ) {} - } - - function args( elem ) { - // Return an object of element attributes - var newAttrs = {}, - rinlinejQuery = /^jQuery\d+$/; - $.each( elem.attributes, function ( i, attr ) { - if ( attr.specified && !rinlinejQuery.test( attr.name ) ) { - newAttrs[ attr.name ] = attr.value; - } - } ); - return newAttrs; - } - - function clearPlaceholder( event, value ) { - var input = this, - $input = $( input ); - if ( input.value === $input.attr( 'placeholder' ) && $input.hasClass( 'placeholder' ) ) { - if ( $input.data( 'placeholder-password' ) ) { - $input = $input.hide().next().show().attr( 'id', $input.removeAttr( 'id' ).data( 'placeholder-id' ) ); - // If `clearPlaceholder` was called from `$.valHooks.input.set` - if ( event === true ) { - $input[ 0 ].value = value; - return value; - } - $input.focus(); - } else { - input.value = ''; - $input.removeClass( 'placeholder' ); - if ( input === safeActiveElement() ) { - input.select(); - } - } - } - } - - function setPlaceholder() { - var $replacement, - input = this, - $input = $( input ), - id = this.id; - if ( !input.value ) { - if ( input.type === 'password' ) { - if ( !$input.data( 'placeholder-textinput' ) ) { - try { - $replacement = $input.clone().attr( { type: 'text' } ); - } catch ( e ) { - $replacement = $( '' ).attr( $.extend( args( this ), { type: 'text' } ) ); - } - $replacement - .removeAttr( 'name' ) - .data( { - 'placeholder-password': $input, - 'placeholder-id': id - } ) - .on( 'focus.placeholder drop.placeholder', clearPlaceholder ); - $input - .data( { - 'placeholder-textinput': $replacement, - 'placeholder-id': id - } ) - .before( $replacement ); - } - $input = $input.removeAttr( 'id' ).hide().prev().attr( 'id', id ).show(); - // Note: `$input[0] != input` now! - } - $input.addClass( 'placeholder' ); - $input[ 0 ].value = $input.attr( 'placeholder' ); - } else { - $input.removeClass( 'placeholder' ); - } - } - - function changePlaceholder( text ) { - var hasArgs = arguments.length, - $input = this; - if ( hasArgs ) { - if ( $input.attr( 'placeholder' ) !== text ) { - $input.prop( 'placeholder', text ); - if ( $input.hasClass( 'placeholder' ) ) { - $input[ 0 ].value = text; - } - } - } - } - - if ( isInputSupported && isTextareaSupported ) { - - placeholder = prototype.placeholder = function ( text ) { - var hasArgs = arguments.length; - - if ( hasArgs ) { - changePlaceholder.call( this, text ); - } - - return this; - }; - - placeholder.input = placeholder.textarea = true; - - } else { - - placeholder = prototype.placeholder = function ( text ) { - var $this = this, - hasArgs = arguments.length; - - if ( hasArgs ) { - changePlaceholder.call( this, text ); - } - - $this - .filter( ( isInputSupported ? 'textarea' : ':input' ) + '[placeholder]' ) - .filter( function () { - return !$( this ).data( 'placeholder-enabled' ); - } ) - .on( { - 'focus.placeholder drop.placeholder': clearPlaceholder, - 'blur.placeholder': setPlaceholder - } ) - .data( 'placeholder-enabled', true ) - .trigger( 'blur.placeholder' ); - return $this; - }; - - placeholder.input = isInputSupported; - placeholder.textarea = isTextareaSupported; - - hooks = { - get: function ( element ) { - var $element = $( element ), - $passwordInput = $element.data( 'placeholder-password' ); - if ( $passwordInput ) { - return $passwordInput[ 0 ].value; - } - - return $element.data( 'placeholder-enabled' ) && $element.hasClass( 'placeholder' ) ? '' : element.value; - }, - set: function ( element, value ) { - var $element = $( element ), - $passwordInput = $element.data( 'placeholder-password' ); - if ( $passwordInput ) { - $passwordInput[ 0 ].value = value; - return value; - } - - if ( !$element.data( 'placeholder-enabled' ) ) { - element.value = value; - return value; - } - if ( !value ) { - element.value = value; - // Issue #56: Setting the placeholder causes problems if the element continues to have focus. - if ( element !== safeActiveElement() ) { - // We can't use `triggerHandler` here because of dummy text/password inputs :( - setPlaceholder.call( element ); - } - } else if ( $element.hasClass( 'placeholder' ) ) { - if ( !clearPlaceholder.call( element, true, value ) ) { - element.value = value; - } - } else { - element.value = value; - } - // `set` can not return `undefined`; see http://jsapi.info/jquery/1.7.1/val#L2363 - return $element; - } - }; - - if ( !isInputSupported ) { - valHooks.input = hooks; - propHooks.value = hooks; - } - if ( !isTextareaSupported ) { - valHooks.textarea = hooks; - propHooks.value = hooks; + placeholder = $.fn.placeholder = function ( text ) { + if ( arguments.length ) { + this.prop( 'placeholder', text ); } + return this; + }; - $( function () { - // Look for forms - $( document ).delegate( 'form', 'submit.placeholder', function () { - // Clear the placeholder values so they don't get submitted - var $inputs = $( '.placeholder', this ).each( clearPlaceholder ); - setTimeout( function () { - $inputs.each( setPlaceholder ); - }, 10 ); - } ); - } ); - - // Clear placeholder values upon page reload - $( window ).on( 'beforeunload.placeholder', function () { - $( '.placeholder' ).each( function () { - this.value = ''; - } ); - } ); + placeholder.input = placeholder.textarea = true; - } }( jQuery ) ); diff --git a/resources/src/mediawiki/page/ready.js b/resources/src/mediawiki/page/ready.js index f11bbde03e..d5a667e41a 100644 --- a/resources/src/mediawiki/page/ready.js +++ b/resources/src/mediawiki/page/ready.js @@ -1,6 +1,4 @@ ( function ( mw, $ ) { - var supportsPlaceholder = 'placeholder' in document.createElement( 'input' ); - // Break out of framesets if ( mw.config.get( 'wgBreakFrames' ) ) { // Note: In IE < 9 strict comparison to window is non-standard (the standard didn't exist yet) @@ -14,11 +12,6 @@ mw.hook( 'wikipage.content' ).add( function ( $content ) { var $sortable, $collapsible; - // Run jquery.placeholder polyfill if placeholder is not supported - if ( !supportsPlaceholder ) { - $content.find( 'input[placeholder]' ).placeholder(); - } - $collapsible = $content.find( '.mw-collapsible' ); if ( $collapsible.length ) { // Preloaded by Skin::getDefaultModules() @@ -43,11 +36,6 @@ $( function () { var $nodes; - if ( !supportsPlaceholder ) { - // Exclude content to avoid hitting it twice for the (first) wikipage content - $( 'input[placeholder]' ).not( '#mw-content-text input' ).placeholder(); - } - // Add accesskey hints to the tooltips $( '[accesskey]' ).updateTooltipAccessKeys(); diff --git a/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js b/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js index dd7666b651..ed2fbe69dd 100644 --- a/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js @@ -1,146 +1,8 @@ ( function ( $ ) { - var html, testElement; - QUnit.module( 'jquery.placeholder', QUnit.newMwEnvironment() ); QUnit.test( 'caches results of feature tests', function ( assert ) { assert.strictEqual( typeof $.fn.placeholder.input, 'boolean', '$.fn.placeholder.input' ); assert.strictEqual( typeof $.fn.placeholder.textarea, 'boolean', '$.fn.placeholder.textarea' ); } ); - - if ( $.fn.placeholder.input && $.fn.placeholder.textarea ) { - return; - } - - html = '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
'; - testElement = function ( $el, assert ) { - var el = $el[ 0 ], - placeholder = el.getAttribute( 'placeholder' ); - - assert.strictEqual( $el.placeholder(), $el, 'should be chainable' ); - - assert.strictEqual( el.value, placeholder, 'should set `placeholder` text as `value`' ); - assert.strictEqual( $el.prop( 'value' ), '', 'propHooks works properly' ); - assert.strictEqual( $el.val(), '', 'valHooks works properly' ); - assert.ok( $el.hasClass( 'placeholder' ), 'should have `placeholder` class' ); - - // test on focus - $el.focus(); - assert.strictEqual( el.value, '', '`value` should be the empty string on focus' ); - assert.strictEqual( $el.prop( 'value' ), '', 'propHooks works properly' ); - assert.strictEqual( $el.val(), '', 'valHooks works properly' ); - assert.ok( !$el.hasClass( 'placeholder' ), 'should not have `placeholder` class on focus' ); - - // and unfocus (blur) again - $el.blur(); - - assert.strictEqual( el.value, placeholder, 'should set `placeholder` text as `value`' ); - assert.strictEqual( $el.prop( 'value' ), '', 'propHooks works properly' ); - assert.strictEqual( $el.val(), '', 'valHooks works properly' ); - assert.ok( $el.hasClass( 'placeholder' ), 'should have `placeholder` class' ); - - // change the value - $el.val( 'lorem ipsum' ); - assert.strictEqual( $el.prop( 'value' ), 'lorem ipsum', '`$el.val(string)` should change the `value` property' ); - assert.strictEqual( el.value, 'lorem ipsum', '`$el.val(string)` should change the `value` attribute' ); - assert.ok( !$el.hasClass( 'placeholder' ), '`$el.val(string)` should remove `placeholder` class' ); - - // and clear it again - $el.val( '' ); - assert.strictEqual( $el.prop( 'value' ), '', '`$el.val("")` should change the `value` property' ); - assert.strictEqual( el.value, placeholder, '`$el.val("")` should change the `value` attribute' ); - assert.ok( $el.hasClass( 'placeholder' ), '`$el.val("")` should re-enable `placeholder` class' ); - - // make sure the placeholder property works as expected. - assert.strictEqual( $el.prop( 'placeholder' ), placeholder, '$el.prop(`placeholder`) should return the placeholder value' ); - $el.placeholder( 'new placeholder' ); - assert.strictEqual( el.getAttribute( 'placeholder' ), 'new placeholder', '$el.placeholder() should set the placeholder value' ); - assert.strictEqual( el.value, 'new placeholder', '$el.placeholder() should update the displayed placeholder value' ); - $el.placeholder( placeholder ); - }; - - QUnit.test( 'emulates placeholder for ', function ( assert ) { - $( '
' ).html( html ).appendTo( $( '#qunit-fixture' ) ); - testElement( $( '#input-type-text' ), assert ); - } ); - - QUnit.test( 'emulates placeholder for ', function ( assert ) { - $( '
' ).html( html ).appendTo( $( '#qunit-fixture' ) ); - testElement( $( '#input-type-search' ), assert ); - } ); - - QUnit.test( 'emulates placeholder for ', function ( assert ) { - $( '
' ).html( html ).appendTo( $( '#qunit-fixture' ) ); - testElement( $( '#input-type-email' ), assert ); - } ); - - QUnit.test( 'emulates placeholder for ', function ( assert ) { - $( '
' ).html( html ).appendTo( $( '#qunit-fixture' ) ); - testElement( $( '#input-type-url' ), assert ); - } ); - - QUnit.test( 'emulates placeholder for ', function ( assert ) { - $( '
' ).html( html ).appendTo( $( '#qunit-fixture' ) ); - testElement( $( '#input-type-tel' ), assert ); - } ); - - QUnit.test( 'emulates placeholder for ', function ( assert ) { - var $el, el, placeholder, selector = '#input-type-password'; - - $( '
' ).html( html ).appendTo( $( '#qunit-fixture' ) ); - - $el = $( selector ); - el = $el[ 0 ]; - placeholder = el.getAttribute( 'placeholder' ); - - assert.strictEqual( $el.placeholder(), $el, 'should be chainable' ); - - // Re-select the element, as it gets replaced by another one in some browsers - $el = $( selector ); - el = $el[ 0 ]; - - assert.strictEqual( el.value, placeholder, 'should set `placeholder` text as `value`' ); - assert.strictEqual( $el.prop( 'value' ), '', 'propHooks works properly' ); - assert.strictEqual( $el.val(), '', 'valHooks works properly' ); - assert.ok( $el.hasClass( 'placeholder' ), 'should have `placeholder` class' ); - - // test on focus - $el.focus(); - - // Re-select the element, as it gets replaced by another one in some browsers - $el = $( selector ); - el = $el[ 0 ]; - - assert.strictEqual( el.value, '', '`value` should be the empty string on focus' ); - assert.strictEqual( $el.prop( 'value' ), '', 'propHooks works properly' ); - assert.strictEqual( $el.val(), '', 'valHooks works properly' ); - assert.ok( !$el.hasClass( 'placeholder' ), 'should not have `placeholder` class on focus' ); - - // and unfocus (blur) again - $el.blur(); - - // Re-select the element, as it gets replaced by another one in some browsers - $el = $( selector ); - el = $el[ 0 ]; - - assert.strictEqual( el.value, placeholder, 'should set `placeholder` text as `value`' ); - assert.strictEqual( $el.prop( 'value' ), '', 'propHooks works properly' ); - assert.strictEqual( $el.val(), '', 'valHooks works properly' ); - assert.ok( $el.hasClass( 'placeholder' ), 'should have `placeholder` class' ); - - } ); - - QUnit.test( 'emulates placeholder for