wp/wp-admin/js/user-profile.js
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
     1 /**
     1 /**
     2  * @output wp-admin/js/user-profile.js
     2  * @output wp-admin/js/user-profile.js
     3  */
     3  */
     4 
     4 
     5 /* global ajaxurl, pwsL10n */
     5 /* global ajaxurl, pwsL10n, userProfileL10n */
     6 (function($) {
     6 (function($) {
     7 	var updateLock = false,
     7 	var updateLock = false,
     8 		__ = wp.i18n.__,
     8 		__ = wp.i18n.__,
     9 		$pass1Row,
     9 		$pass1Row,
    10 		$pass1,
    10 		$pass1,
    12 		$weakRow,
    12 		$weakRow,
    13 		$weakCheckbox,
    13 		$weakCheckbox,
    14 		$toggleButton,
    14 		$toggleButton,
    15 		$submitButtons,
    15 		$submitButtons,
    16 		$submitButton,
    16 		$submitButton,
    17 		currentPass;
    17 		currentPass,
       
    18 		$passwordWrapper;
    18 
    19 
    19 	function generatePassword() {
    20 	function generatePassword() {
    20 		if ( typeof zxcvbn !== 'function' ) {
    21 		if ( typeof zxcvbn !== 'function' ) {
    21 			setTimeout( generatePassword, 50 );
    22 			setTimeout( generatePassword, 50 );
    22 			return;
    23 			return;
    23 		} else if ( ! $pass1.val() ) {
    24 		} else if ( ! $pass1.val() || $passwordWrapper.hasClass( 'is-open' ) ) {
    24 			// zxcvbn loaded before user entered password.
    25 			// zxcvbn loaded before user entered password, or generating new password.
    25 			$pass1.val( $pass1.data( 'pw' ) );
    26 			$pass1.val( $pass1.data( 'pw' ) );
    26 			$pass1.trigger( 'pwupdate' );
    27 			$pass1.trigger( 'pwupdate' );
    27 			showOrHideWeakPasswordCheckbox();
    28 			showOrHideWeakPasswordCheckbox();
    28 		}
    29 		} else {
    29 		else {
       
    30 			// zxcvbn loaded after the user entered password, check strength.
    30 			// zxcvbn loaded after the user entered password, check strength.
    31 			check_pass_strength();
    31 			check_pass_strength();
    32 			showOrHideWeakPasswordCheckbox();
    32 			showOrHideWeakPasswordCheckbox();
    33 		}
    33 		}
    34 
    34 
       
    35 		// Install screen.
    35 		if ( 1 !== parseInt( $toggleButton.data( 'start-masked' ), 10 ) ) {
    36 		if ( 1 !== parseInt( $toggleButton.data( 'start-masked' ), 10 ) ) {
       
    37 			// Show the password not masked if admin_password hasn't been posted yet.
    36 			$pass1.attr( 'type', 'text' );
    38 			$pass1.attr( 'type', 'text' );
    37 		} else {
    39 		} else {
       
    40 			// Otherwise, mask the password.
    38 			$toggleButton.trigger( 'click' );
    41 			$toggleButton.trigger( 'click' );
    39 		}
    42 		}
    40 
    43 
    41 		// Once zxcvbn loads, passwords strength is known.
    44 		// Once zxcvbn loads, passwords strength is known.
    42 		$( '#pw-weak-text-label' ).text( __( 'Confirm use of weak password' ) );
    45 		$( '#pw-weak-text-label' ).text( __( 'Confirm use of weak password' ) );
    54 				return;
    57 				return;
    55 			}
    58 			}
    56 
    59 
    57 			currentPass = $pass1.val();
    60 			currentPass = $pass1.val();
    58 
    61 
       
    62 			// Refresh password strength area.
    59 			$pass1.removeClass( 'short bad good strong' );
    63 			$pass1.removeClass( 'short bad good strong' );
    60 			showOrHideWeakPasswordCheckbox();
    64 			showOrHideWeakPasswordCheckbox();
    61 		} );
    65 		} );
    62 	}
    66 	}
    63 
    67 
    82 				resetToggle( false );
    86 				resetToggle( false );
    83 			} else {
    87 			} else {
    84 				$pass1.attr( 'type', 'password' );
    88 				$pass1.attr( 'type', 'password' );
    85 				resetToggle( true );
    89 				resetToggle( true );
    86 			}
    90 			}
    87 
    91 		});
    88 			$pass1.focus();
    92 	}
    89 
    93 
    90 			if ( ! _.isUndefined( $pass1[0].setSelectionRange ) ) {
    94 	/**
    91 				$pass1[0].setSelectionRange( 0, 100 );
    95 	 * Handle the password reset button. Sets up an ajax callback to trigger sending
    92 			}
    96 	 * a password reset email.
    93 		});
    97 	 */
       
    98 	function bindPasswordRestLink() {
       
    99 		$( '#generate-reset-link' ).on( 'click', function() {
       
   100 			var $this  = $(this),
       
   101 				data = {
       
   102 					'user_id': userProfileL10n.user_id, // The user to send a reset to.
       
   103 					'nonce':   userProfileL10n.nonce    // Nonce to validate the action.
       
   104 				};
       
   105 
       
   106 				// Remove any previous error messages.
       
   107 				$this.parent().find( '.notice-error' ).remove();
       
   108 
       
   109 				// Send the reset request.
       
   110 				var resetAction =  wp.ajax.post( 'send-password-reset', data );
       
   111 
       
   112 				// Handle reset success.
       
   113 				resetAction.done( function( response ) {
       
   114 					addInlineNotice( $this, true, response );
       
   115 				} );
       
   116 
       
   117 				// Handle reset failure.
       
   118 				resetAction.fail( function( response ) {
       
   119 					addInlineNotice( $this, false, response );
       
   120 				} );
       
   121 
       
   122 		});
       
   123 
       
   124 	}
       
   125 
       
   126 	/**
       
   127 	 * Helper function to insert an inline notice of success or failure.
       
   128 	 *
       
   129 	 * @param {jQuery Object} $this   The button element: the message will be inserted
       
   130 	 *                                above this button
       
   131 	 * @param {bool}          success Whether the message is a success message.
       
   132 	 * @param {string}        message The message to insert.
       
   133 	 */
       
   134 	function addInlineNotice( $this, success, message ) {
       
   135 		var resultDiv = $( '<div />' );
       
   136 
       
   137 		// Set up the notice div.
       
   138 		resultDiv.addClass( 'notice inline' );
       
   139 
       
   140 		// Add a class indicating success or failure.
       
   141 		resultDiv.addClass( 'notice-' + ( success ? 'success' : 'error' ) );
       
   142 
       
   143 		// Add the message, wrapping in a p tag, with a fadein to highlight each message.
       
   144 		resultDiv.text( $( $.parseHTML( message ) ).text() ).wrapInner( '<p />');
       
   145 
       
   146 		// Disable the button when the callback has succeeded.
       
   147 		$this.prop( 'disabled', success );
       
   148 
       
   149 		// Remove any previous notices.
       
   150 		$this.siblings( '.notice' ).remove();
       
   151 
       
   152 		// Insert the notice.
       
   153 		$this.before( resultDiv );
    94 	}
   154 	}
    95 
   155 
    96 	function bindPasswordForm() {
   156 	function bindPasswordForm() {
    97 		var $passwordWrapper,
   157 		var $generateButton,
    98 			$generateButton,
       
    99 			$cancelButton;
   158 			$cancelButton;
   100 
   159 
   101 		$pass1Row = $( '.user-pass1-wrap, .user-pass-wrap' );
   160 		$pass1Row = $( '.user-pass1-wrap, .user-pass-wrap, .reset-pass-submit' );
   102 
   161 
   103 		// Hide the confirm password field when JavaScript support is enabled.
   162 		// Hide the confirm password field when JavaScript support is enabled.
   104 		$('.user-pass2-wrap').hide();
   163 		$('.user-pass2-wrap').hide();
   105 
   164 
   106 		$submitButton = $( '#submit, #wp-submit' ).on( 'click', function () {
   165 		$submitButton = $( '#submit, #wp-submit' ).on( 'click', function () {
   109 
   168 
   110 		$submitButtons = $submitButton.add( ' #createusersub' );
   169 		$submitButtons = $submitButton.add( ' #createusersub' );
   111 
   170 
   112 		$weakRow = $( '.pw-weak' );
   171 		$weakRow = $( '.pw-weak' );
   113 		$weakCheckbox = $weakRow.find( '.pw-checkbox' );
   172 		$weakCheckbox = $weakRow.find( '.pw-checkbox' );
   114 		$weakCheckbox.change( function() {
   173 		$weakCheckbox.on( 'change', function() {
   115 			$submitButtons.prop( 'disabled', ! $weakCheckbox.prop( 'checked' ) );
   174 			$submitButtons.prop( 'disabled', ! $weakCheckbox.prop( 'checked' ) );
   116 		} );
   175 		} );
   117 
   176 
   118 		$pass1 = $('#pass1');
   177 		$pass1 = $('#pass1');
   119 		if ( $pass1.length ) {
   178 		if ( $pass1.length ) {
   121 		} else {
   180 		} else {
   122 			// Password field for the login form.
   181 			// Password field for the login form.
   123 			$pass1 = $( '#user_pass' );
   182 			$pass1 = $( '#user_pass' );
   124 		}
   183 		}
   125 
   184 
   126 		/**
   185 		/*
   127 		 * Fix a LastPass mismatch issue, LastPass only changes pass2.
   186 		 * Fix a LastPass mismatch issue, LastPass only changes pass2.
   128 		 *
   187 		 *
   129 		 * This fixes the issue by copying any changes from the hidden
   188 		 * This fixes the issue by copying any changes from the hidden
   130 		 * pass2 field to the pass1 field, then running check_pass_strength.
   189 		 * pass2 field to the pass1 field, then running check_pass_strength.
   131 		 */
   190 		 */
   147 		$passwordWrapper = $pass1Row.find( '.wp-pwd' );
   206 		$passwordWrapper = $pass1Row.find( '.wp-pwd' );
   148 		$generateButton  = $pass1Row.find( 'button.wp-generate-pw' );
   207 		$generateButton  = $pass1Row.find( 'button.wp-generate-pw' );
   149 
   208 
   150 		bindToggleButton();
   209 		bindToggleButton();
   151 
   210 
   152 		if ( $generateButton.length ) {
       
   153 			$passwordWrapper.hide();
       
   154 		}
       
   155 
       
   156 		$generateButton.show();
   211 		$generateButton.show();
   157 		$generateButton.on( 'click', function () {
   212 		$generateButton.on( 'click', function () {
   158 			updateLock = true;
   213 			updateLock = true;
   159 
   214 
   160 			$generateButton.hide();
   215 			// Make sure the password fields are shown.
   161 			$passwordWrapper.show();
   216 			$generateButton.attr( 'aria-expanded', 'true' );
       
   217 			$passwordWrapper
       
   218 				.show()
       
   219 				.addClass( 'is-open' );
   162 
   220 
   163 			// Enable the inputs when showing.
   221 			// Enable the inputs when showing.
   164 			$pass1.attr( 'disabled', false );
   222 			$pass1.attr( 'disabled', false );
   165 			$pass2.attr( 'disabled', false );
   223 			$pass2.attr( 'disabled', false );
   166 
   224 
   167 			if ( $pass1.val().length === 0 ) {
   225 			// Set the password to the generated value.
   168 				generatePassword();
   226 			generatePassword();
   169 			}
   227 
   170 		} );
   228 			// Show generated password in plaintext by default.
   171 
   229 			resetToggle ( false );
   172 		$cancelButton = $pass1Row.find( 'button.wp-cancel-pw' );
   230 
   173 		$cancelButton.on( 'click', function () {
   231 			// Generate the next password and cache.
   174 			updateLock = false;
       
   175 
       
   176 			// Clear any entered password.
       
   177 			$pass1.val( '' );
       
   178 
       
   179 			// Generate a new password.
       
   180 			wp.ajax.post( 'generate-password' )
   232 			wp.ajax.post( 'generate-password' )
   181 				.done( function( data ) {
   233 				.done( function( data ) {
   182 					$pass1.data( 'pw', data );
   234 					$pass1.data( 'pw', data );
   183 				} );
   235 				} );
   184 
   236 		} );
   185 			$generateButton.show().focus();
   237 
   186 			$passwordWrapper.hide();
   238 		$cancelButton = $pass1Row.find( 'button.wp-cancel-pw' );
   187 
   239 		$cancelButton.on( 'click', function () {
   188 			$weakRow.hide( 0, function () {
   240 			updateLock = false;
   189 				$weakCheckbox.removeProp( 'checked' );
       
   190 			} );
       
   191 
   241 
   192 			// Disable the inputs when hiding to prevent autofill and submission.
   242 			// Disable the inputs when hiding to prevent autofill and submission.
   193 			$pass1.prop( 'disabled', true );
   243 			$pass1.prop( 'disabled', true );
   194 			$pass2.prop( 'disabled', true );
   244 			$pass2.prop( 'disabled', true );
   195 
   245 
       
   246 			// Clear password field and update the UI.
       
   247 			$pass1.val( '' ).trigger( 'pwupdate' );
   196 			resetToggle( false );
   248 			resetToggle( false );
   197 
   249 
   198 			if ( $pass1Row.closest( 'form' ).is( '#your-profile' ) ) {
   250 			// Hide password controls.
   199 				// Clear password field to prevent update.
   251 			$passwordWrapper
   200 				$pass1.val( '' ).trigger( 'pwupdate' );
   252 				.hide()
   201 				$submitButtons.prop( 'disabled', false );
   253 				.removeClass( 'is-open' );
   202 			}
   254 
       
   255 			// Stop an empty password from being submitted as a change.
       
   256 			$submitButtons.prop( 'disabled', false );
   203 		} );
   257 		} );
   204 
   258 
   205 		$pass1Row.closest( 'form' ).on( 'submit', function () {
   259 		$pass1Row.closest( 'form' ).on( 'submit', function () {
   206 			updateLock = false;
   260 			updateLock = false;
   207 
   261 
   213 
   267 
   214 	function check_pass_strength() {
   268 	function check_pass_strength() {
   215 		var pass1 = $('#pass1').val(), strength;
   269 		var pass1 = $('#pass1').val(), strength;
   216 
   270 
   217 		$('#pass-strength-result').removeClass('short bad good strong empty');
   271 		$('#pass-strength-result').removeClass('short bad good strong empty');
   218 		if ( ! pass1 ) {
   272 		if ( ! pass1 || '' ===  pass1.trim() ) {
   219 			$( '#pass-strength-result' ).addClass( 'empty' ).html( '&nbsp;' );
   273 			$( '#pass-strength-result' ).addClass( 'empty' ).html( '&nbsp;' );
   220 			return;
   274 			return;
   221 		}
   275 		}
   222 
   276 
   223 		strength = wp.passwordStrength.meter( pass1, wp.passwordStrength.userInputDisallowedList(), pass1 );
   277 		strength = wp.passwordStrength.meter( pass1, wp.passwordStrength.userInputDisallowedList(), pass1 );
   263 				$weakRow.hide();
   317 				$weakRow.hide();
   264 			}
   318 			}
   265 		}
   319 		}
   266 	}
   320 	}
   267 
   321 
   268 	$(document).ready( function() {
   322 	$( function() {
   269 		var $colorpicker, $stylesheet, user_id, current_user_id,
   323 		var $colorpicker, $stylesheet, user_id, current_user_id,
   270 			select       = $( '#display_name' ),
   324 			select       = $( '#display_name' ),
   271 			current_name = select.val(),
   325 			current_name = select.val(),
   272 			greeting     = $( '#wp-admin-bar-my-account' ).find( '.display-name' );
   326 			greeting     = $( '#wp-admin-bar-my-account' ).find( '.display-name' );
   273 
   327 
   274 		$( '#pass1' ).val( '' ).on( 'input' + ' pwupdate', check_pass_strength );
   328 		$( '#pass1' ).val( '' ).on( 'input' + ' pwupdate', check_pass_strength );
   275 		$('#pass-strength-result').show();
   329 		$('#pass-strength-result').show();
   276 		$('.color-palette').click( function() {
   330 		$('.color-palette').on( 'click', function() {
   277 			$(this).siblings('input[name="admin_color"]').prop('checked', true);
   331 			$(this).siblings('input[name="admin_color"]').prop('checked', true);
   278 		});
   332 		});
   279 
   333 
   280 		if ( select.length ) {
   334 		if ( select.length ) {
   281 			$('#first_name, #last_name, #nickname').bind( 'blur.user_profile', function() {
   335 			$('#first_name, #last_name, #nickname').on( 'blur.user_profile', function() {
   282 				var dub = [],
   336 				var dub = [],
   283 					inputs = {
   337 					inputs = {
   284 						display_nickname  : $('#nickname').val() || '',
   338 						display_nickname  : $('#nickname').val() || '',
   285 						display_username  : $('#user_login').val() || '',
   339 						display_username  : $('#user_login').val() || '',
   286 						display_firstname : $('#first_name').val() || '',
   340 						display_firstname : $('#first_name').val() || '',
   318 			select.on( 'change', function() {
   372 			select.on( 'change', function() {
   319 				if ( user_id !== current_user_id ) {
   373 				if ( user_id !== current_user_id ) {
   320 					return;
   374 					return;
   321 				}
   375 				}
   322 
   376 
   323 				var display_name = $.trim( this.value ) || current_name;
   377 				var display_name = this.value.trim() || current_name;
   324 
   378 
   325 				greeting.text( display_name );
   379 				greeting.text( display_name );
   326 			} );
   380 			} );
   327 		}
   381 		}
   328 
   382 
   352 				$stylesheet.attr( 'href', $this.children( '.css_url' ).val() );
   406 				$stylesheet.attr( 'href', $this.children( '.css_url' ).val() );
   353 
   407 
   354 				// Repaint icons.
   408 				// Repaint icons.
   355 				if ( typeof wp !== 'undefined' && wp.svgPainter ) {
   409 				if ( typeof wp !== 'undefined' && wp.svgPainter ) {
   356 					try {
   410 					try {
   357 						colors = $.parseJSON( $this.children( '.icon_colors' ).val() );
   411 						colors = JSON.parse( $this.children( '.icon_colors' ).val() );
   358 					} catch ( error ) {}
   412 					} catch ( error ) {}
   359 
   413 
   360 					if ( colors ) {
   414 					if ( colors ) {
   361 						wp.svgPainter.setColors( colors );
   415 						wp.svgPainter.setColors( colors );
   362 						wp.svgPainter.paint();
   416 						wp.svgPainter.paint();
   375 				});
   429 				});
   376 			}
   430 			}
   377 		});
   431 		});
   378 
   432 
   379 		bindPasswordForm();
   433 		bindPasswordForm();
       
   434 		bindPasswordRestLink();
   380 	});
   435 	});
   381 
   436 
   382 	$( '#destroy-sessions' ).on( 'click', function( e ) {
   437 	$( '#destroy-sessions' ).on( 'click', function( e ) {
   383 		var $this = $(this);
   438 		var $this = $(this);
   384 
   439 
   397 		e.preventDefault();
   452 		e.preventDefault();
   398 	});
   453 	});
   399 
   454 
   400 	window.generatePassword = generatePassword;
   455 	window.generatePassword = generatePassword;
   401 
   456 
   402 	/* Warn the user if password was generated but not saved */
   457 	// Warn the user if password was generated but not saved.
   403 	$( window ).on( 'beforeunload', function () {
   458 	$( window ).on( 'beforeunload', function () {
   404 		if ( true === updateLock ) {
   459 		if ( true === updateLock ) {
   405 			return __( 'Your new password has not been saved.' );
   460 			return __( 'Your new password has not been saved.' );
   406 		}
   461 		}
   407 	} );
   462 	} );
   408 
   463 
       
   464 	/*
       
   465 	 * We need to generate a password as soon as the Reset Password page is loaded,
       
   466 	 * to avoid double clicking the button to retrieve the first generated password.
       
   467 	 * See ticket #39638.
       
   468 	 */
       
   469 	$( function() {
       
   470 		if ( $( '.reset-pass-submit' ).length ) {
       
   471 			$( '.reset-pass-submit button.wp-generate-pw' ).trigger( 'click' );
       
   472 		}
       
   473 	});
       
   474 
   409 })(jQuery);
   475 })(jQuery);