User:Majr/inputCounter.js

$( function { 'use strict';

var events = [ 'keypress', 'change', 'mouseenter', 'mouseup', 'cut', 'paste', 'focus', 'blur' ].join( '.inputCounter ' ) + '.inputCounter';

// Display the amount of chars left on inputs that have a maxlength parameter $( '#mw-content-text' ).on( events, 'input', function {	var $input = $( this );	if ( $input.prop( 'type' ) !== 'text' ) {		return;	};	var max = $input.data( 'maxlength' ) || $input.attr( 'maxLength' );	if ( !max ) {		return;	}	mw.loader.using( 'jquery.byteLength', function { var $number = $input.parent.children( '.chars' ); if ( !$number.length ) { // Get rid of the jQuery.byteLimit on the summary preventing extra characters being entered $( '#wpSummary' ).off( '.byteLimit' ); var refocus = $input.is( ':focus' ); var display = $input.css( 'display' ); if ( display !== 'block' ) { display = 'inline-block'; }			var width = $input.outerWidth; $input .removeAttr( 'maxLength' ) .data( 'maxlength', max ) .css( {					width: width,					'-moz-box-sizing': 'border-box',					boxSizing: 'border-box',					// Set soon to be lost native styling					paddingTop: $input.css( 'padding-top' ),					paddingBottom: $input.css( 'padding-bottom' ),					paddingLeft: $input.css( 'padding-left' ),					paddingRight: $input.css( 'padding-right' )				} ) .wrap( $( ' ' )					.addClass( 'input-counter' )					.css( { position: 'relative', display: display } )				)				.parent.width( width ); $number = $( ' ' ) .addClass( 'chars' ) .css( {					position: 'absolute',					top: $input.css( 'border-top-width' ),					right: $input.css( 'border-right-width' ),					paddingTop: parseFloat( $input.css( 'padding-top' ) ) || 1,					paddingRight: parseFloat( $input.css( 'padding-right' ) ) || 1,					lineHeight: $input.css( 'line-height' )				} ) .insertAfter( $input ); }		// Timeout allows the text as just entered to be retrieved, rather than the text just before setTimeout( function {			var length = $.byteLength( $input.val ),				delta = max - length;			// Take into account the predefined reason length			var $reasonList = $( '#wpDeleteReasonList, #wpProtectReasonSelection' );			if ( $reasonList.length && $reasonList.val !== 'other' ) {				delta -= $.byteLength( $reasonList.val ) + 2;			}			$number.text( delta );			if ( delta < 0 ) {				$number.addClass( 'extra-chars' ).css( 'color', '#F00' );			} else {				$number.removeClass( 'extra-chars' ).css( 'color', '#AAA' );			}			// Prevent entered text from overlapping the number			$input.css( 'padding-right', $number.innerWidth + 5 );			// Reset focus if it was lost			if ( refocus && !$input.is( ':focus' ) ) {				$input.focus;			}		}, 0 ); } ); } );

// Update char count when changing a pre-defined reason select box $( '#wpDeleteReasonList, #wpProtectReasonSelection' ).change( function {	$( '#wpReason, #mwProtect-reason' ).focus; } );

// Prevent forms from submitting that have inputs with too many characters $( '#mw-content-text' ).on( 'submit', 'form', function( e ) {	var $extraChars = $( this ).find( '.extra-chars' );	if ( !$extraChars.length ) {		return;	}	e.preventDefault;	// Scroll the first input field with too many chars into view if needed	if ( $extraChars.first.offset.top < $( window ).scrollTop + 40 ) {		$( window ).scrollTop( $extraChars.first.offset.top - 40 );	}	// Flash the numbers to draw attention to them	var flashes = 0, flash = setInterval( function { if ( $extraChars.data( 'flash' ) ) { $extraChars.data( 'flash', 0 ).css( {				backgroundColor: '',				color: '#F00'			} ); flashes++; } else { $extraChars.data( 'flash', 1 ).css( {				backgroundColor: '#F00',				color: '#FFF'			} ); }		if ( flashes === 4 ) { clearInterval( flash ); if ( !$extraChars.hasClass( 'extra-chars' ) ) { $extraChars.css( 'color', '#AAA' ); }		}	}, 500 ); } );

} );