wp/wp-admin/js/image-edit.js
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     3  *
     3  *
     4  * @since 2.9.0
     4  * @since 2.9.0
     5  * @output wp-admin/js/image-edit.js
     5  * @output wp-admin/js/image-edit.js
     6  */
     6  */
     7 
     7 
     8  /* global imageEditL10n, ajaxurl, confirm */
     8  /* global ajaxurl, confirm */
     9 
     9 
    10 (function($) {
    10 (function($) {
       
    11 	var __ = wp.i18n.__;
    11 
    12 
    12 	/**
    13 	/**
    13 	 * Contains all the methods to initialise and control the image editor.
    14 	 * Contains all the methods to initialise and control the image editor.
    14 	 *
    15 	 *
    15 	 * @namespace imageEdit
    16 	 * @namespace imageEdit
    46 	},
    47 	},
    47 
    48 
    48 	/**
    49 	/**
    49 	 * Converts a value to an integer.
    50 	 * Converts a value to an integer.
    50 	 *
    51 	 *
    51 	 * @memberof imageEdit
    52 	 * @since 2.9.0
    52 	 * @since    2.9.0
    53 	 *
       
    54 	 * @memberof imageEdit
    53 	 *
    55 	 *
    54 	 * @param {number} f The float value that should be converted.
    56 	 * @param {number} f The float value that should be converted.
    55 	 *
    57 	 *
    56 	 * @return {number} The integer representation from the float value.
    58 	 * @return {number} The integer representation from the float value.
    57 	 */
    59 	 */
    64 	},
    66 	},
    65 
    67 
    66 	/**
    68 	/**
    67 	 * Adds the disabled attribute and class to a single form element or a field set.
    69 	 * Adds the disabled attribute and class to a single form element or a field set.
    68 	 *
    70 	 *
    69 	 * @memberof imageEdit
    71 	 * @since 2.9.0
    70 	 * @since    2.9.0
    72 	 *
       
    73 	 * @memberof imageEdit
    71 	 *
    74 	 *
    72 	 * @param {jQuery}         el The element that should be modified.
    75 	 * @param {jQuery}         el The element that should be modified.
    73 	 * @param {bool|number}    s  The state for the element. If set to true
    76 	 * @param {boolean|number} s  The state for the element. If set to true
    74 	 *                            the element is disabled,
    77 	 *                            the element is disabled,
    75 	 *                            otherwise the element is enabled.
    78 	 *                            otherwise the element is enabled.
    76 	 *                            The function is sometimes called with a 0 or 1
    79 	 *                            The function is sometimes called with a 0 or 1
    77 	 *                            instead of true or false.
    80 	 *                            instead of true or false.
    78 	 *
    81 	 *
    79 	 * @returns {void}
    82 	 * @return {void}
    80 	 */
    83 	 */
    81 	setDisabled : function( el, s ) {
    84 	setDisabled : function( el, s ) {
    82 		/*
    85 		/*
    83 		 * `el` can be a single form element or a fieldset. Before #28864, the disabled state on
    86 		 * `el` can be a single form element or a fieldset. Before #28864, the disabled state on
    84 		 * some text fields  was handled targeting $('input', el). Now we need to handle the
    87 		 * some text fields  was handled targeting $('input', el). Now we need to handle the
    93 	},
    96 	},
    94 
    97 
    95 	/**
    98 	/**
    96 	 * Initializes the image editor.
    99 	 * Initializes the image editor.
    97 	 *
   100 	 *
    98 	 * @memberof imageEdit
   101 	 * @since 2.9.0
    99 	 * @since    2.9.0
   102 	 *
   100 	 *
   103 	 * @memberof imageEdit
   101 	 * @param {number} postid The post id.
   104 	 *
   102 	 *
   105 	 * @param {number} postid The post ID.
   103 	 * @returns {void}
   106 	 *
       
   107 	 * @return {void}
   104 	 */
   108 	 */
   105 	init : function(postid) {
   109 	init : function(postid) {
   106 		var t = this, old = $('#image-editor-' + t.postid),
   110 		var t = this, old = $('#image-editor-' + t.postid),
   107 			x = t.intval( $('#imgedit-x-' + postid).val() ),
   111 			x = t.intval( $('#imgedit-x-' + postid).val() ),
   108 			y = t.intval( $('#imgedit-y-' + postid).val() );
   112 			y = t.intval( $('#imgedit-y-' + postid).val() );
   119 		$('#imgedit-response-' + postid).empty();
   123 		$('#imgedit-response-' + postid).empty();
   120 
   124 
   121 		$('input[type="text"]', '#imgedit-panel-' + postid).keypress(function(e) {
   125 		$('input[type="text"]', '#imgedit-panel-' + postid).keypress(function(e) {
   122 			var k = e.keyCode;
   126 			var k = e.keyCode;
   123 
   127 
   124 			// Key codes 37 thru 40 are the arrow keys.
   128 			// Key codes 37 through 40 are the arrow keys.
   125 			if ( 36 < k && k < 41 ) {
   129 			if ( 36 < k && k < 41 ) {
   126 				$(this).blur();
   130 				$(this).blur();
   127 			}
   131 			}
   128 
   132 
   129 			// The key code 13 is the enter key.
   133 			// The key code 13 is the Enter key.
   130 			if ( 13 === k ) {
   134 			if ( 13 === k ) {
   131 				e.preventDefault();
   135 				e.preventDefault();
   132 				e.stopPropagation();
   136 				e.stopPropagation();
   133 				return false;
   137 				return false;
   134 			}
   138 			}
   135 		});
   139 		});
       
   140 
       
   141 		$( document ).on( 'image-editor-ui-ready', this.focusManager );
   136 	},
   142 	},
   137 
   143 
   138 	/**
   144 	/**
   139 	 * Toggles the wait/load icon in the editor.
   145 	 * Toggles the wait/load icon in the editor.
   140 	 *
   146 	 *
   141 	 * @memberof imageEdit
   147 	 * @since 2.9.0
   142 	 * @since    2.9.0
   148 	 * @since 5.5.0 Added the triggerUIReady parameter.
   143 	 *
   149 	 *
   144 	 * @param {number} postid The post id.
   150 	 * @memberof imageEdit
   145 	 * @param {number} toggle Is 0 or 1, fades the icon in then 1 and out when 0.
   151 	 *
   146 	 *
   152 	 * @param {number}  postid         The post ID.
   147 	 * @returns {void}
   153 	 * @param {number}  toggle         Is 0 or 1, fades the icon in when 1 and out when 0.
   148 	 */
   154 	 * @param {boolean} triggerUIReady Whether to trigger a custom event when the UI is ready. Default false.
   149 	toggleEditor : function(postid, toggle) {
   155 	 *
       
   156 	 * @return {void}
       
   157 	 */
       
   158 	toggleEditor: function( postid, toggle, triggerUIReady ) {
   150 		var wait = $('#imgedit-wait-' + postid);
   159 		var wait = $('#imgedit-wait-' + postid);
   151 
   160 
   152 		if ( toggle ) {
   161 		if ( toggle ) {
   153 			wait.fadeIn( 'fast' );
   162 			wait.fadeIn( 'fast' );
   154 		} else {
   163 		} else {
   155 			wait.fadeOut('fast');
   164 			wait.fadeOut( 'fast', function() {
       
   165 				if ( triggerUIReady ) {
       
   166 					$( document ).trigger( 'image-editor-ui-ready' );
       
   167 				}
       
   168 			} );
   156 		}
   169 		}
   157 	},
   170 	},
   158 
   171 
   159 	/**
   172 	/**
   160 	 * Shows or hides the image edit help box.
   173 	 * Shows or hides the image edit help box.
   161 	 *
   174 	 *
   162 	 * @memberof imageEdit
   175 	 * @since 2.9.0
   163 	 * @since    2.9.0
   176 	 *
       
   177 	 * @memberof imageEdit
   164 	 *
   178 	 *
   165 	 * @param {HTMLElement} el The element to create the help window in.
   179 	 * @param {HTMLElement} el The element to create the help window in.
   166 	 *
   180 	 *
   167 	 * @returns {boolean} Always returns false.
   181 	 * @return {boolean} Always returns false.
   168 	 */
   182 	 */
   169 	toggleHelp : function(el) {
   183 	toggleHelp : function(el) {
   170 		var $el = $( el );
   184 		var $el = $( el );
   171 		$el
   185 		$el
   172 			.attr( 'aria-expanded', 'false' === $el.attr( 'aria-expanded' ) ? 'true' : 'false' )
   186 			.attr( 'aria-expanded', 'false' === $el.attr( 'aria-expanded' ) ? 'true' : 'false' )
   179 	 * Gets the value from the image edit target.
   193 	 * Gets the value from the image edit target.
   180 	 *
   194 	 *
   181 	 * The image edit target contains the image sizes where the (possible) changes
   195 	 * The image edit target contains the image sizes where the (possible) changes
   182 	 * have to be applied to.
   196 	 * have to be applied to.
   183 	 *
   197 	 *
   184 	 * @memberof imageEdit
   198 	 * @since 2.9.0
   185 	 * @since    2.9.0
   199 	 *
   186 	 *
   200 	 * @memberof imageEdit
   187 	 * @param {number} postid The post id.
   201 	 *
   188 	 *
   202 	 * @param {number} postid The post ID.
   189 	 * @returns {string} The value from the imagedit-save-target input field when available,
   203 	 *
   190 	 *                   or 'full' when not available.
   204 	 * @return {string} The value from the imagedit-save-target input field when available,
       
   205 	 *                  or 'full' when not available.
   191 	 */
   206 	 */
   192 	getTarget : function(postid) {
   207 	getTarget : function(postid) {
   193 		return $('input[name="imgedit-target-' + postid + '"]:checked', '#imgedit-save-target-' + postid).val() || 'full';
   208 		return $('input[name="imgedit-target-' + postid + '"]:checked', '#imgedit-save-target-' + postid).val() || 'full';
   194 	},
   209 	},
   195 
   210 
   196 	/**
   211 	/**
   197 	 * Recalculates the height or width and keeps the original aspect ratio.
   212 	 * Recalculates the height or width and keeps the original aspect ratio.
   198 	 *
   213 	 *
   199 	 * If the original image size is exceeded a red exclamation mark is shown.
   214 	 * If the original image size is exceeded a red exclamation mark is shown.
   200 	 *
   215 	 *
   201 	 * @memberof imageEdit
   216 	 * @since 2.9.0
   202 	 * @since    2.9.0
   217 	 *
   203 	 *
   218 	 * @memberof imageEdit
   204 	 * @param {number}         postid The current post id.
   219 	 *
       
   220 	 * @param {number}         postid The current post ID.
   205 	 * @param {number}         x      Is 0 when it applies the y-axis
   221 	 * @param {number}         x      Is 0 when it applies the y-axis
   206 	 *                                and 1 when applicable for the x-axis.
   222 	 *                                and 1 when applicable for the x-axis.
   207 	 * @param {jQuery}         el     Element.
   223 	 * @param {jQuery}         el     Element.
   208 	 *
   224 	 *
   209 	 * @returns {void}
   225 	 * @return {void}
   210 	 */
   226 	 */
   211 	scaleChanged : function( postid, x, el ) {
   227 	scaleChanged : function( postid, x, el ) {
   212 		var w = $('#imgedit-scale-width-' + postid), h = $('#imgedit-scale-height-' + postid),
   228 		var w = $('#imgedit-scale-width-' + postid), h = $('#imgedit-scale-height-' + postid),
   213 		warn = $('#imgedit-scale-warn-' + postid), w1 = '', h1 = '';
   229 		warn = $('#imgedit-scale-warn-' + postid), w1 = '', h1 = '';
   214 
   230 
   232 	},
   248 	},
   233 
   249 
   234 	/**
   250 	/**
   235 	 * Gets the selected aspect ratio.
   251 	 * Gets the selected aspect ratio.
   236 	 *
   252 	 *
   237 	 * @memberof imageEdit
   253 	 * @since 2.9.0
   238 	 * @since    2.9.0
   254 	 *
   239 	 *
   255 	 * @memberof imageEdit
   240 	 * @param {number} postid The post id.
   256 	 *
   241 	 *
   257 	 * @param {number} postid The post ID.
   242 	 * @returns {string} The aspect ratio.
   258 	 *
       
   259 	 * @return {string} The aspect ratio.
   243 	 */
   260 	 */
   244 	getSelRatio : function(postid) {
   261 	getSelRatio : function(postid) {
   245 		var x = this.hold.w, y = this.hold.h,
   262 		var x = this.hold.w, y = this.hold.h,
   246 			X = this.intval( $('#imgedit-crop-width-' + postid).val() ),
   263 			X = this.intval( $('#imgedit-crop-width-' + postid).val() ),
   247 			Y = this.intval( $('#imgedit-crop-height-' + postid).val() );
   264 			Y = this.intval( $('#imgedit-crop-height-' + postid).val() );
   259 
   276 
   260 	/**
   277 	/**
   261 	 * Removes the last action from the image edit history.
   278 	 * Removes the last action from the image edit history.
   262 	 * The history consist of (edit) actions performed on the image.
   279 	 * The history consist of (edit) actions performed on the image.
   263 	 *
   280 	 *
   264 	 * @memberof imageEdit
   281 	 * @since 2.9.0
   265 	 * @since    2.9.0
   282 	 *
   266 	 *
   283 	 * @memberof imageEdit
   267 	 * @param {number} postid  The post id.
   284 	 *
       
   285 	 * @param {number} postid  The post ID.
   268 	 * @param {number} setSize 0 or 1, when 1 the image resets to its original size.
   286 	 * @param {number} setSize 0 or 1, when 1 the image resets to its original size.
   269 	 *
   287 	 *
   270 	 * @returns {string} JSON string containing the history or an empty string if no history exists.
   288 	 * @return {string} JSON string containing the history or an empty string if no history exists.
   271 	 */
   289 	 */
   272 	filterHistory : function(postid, setSize) {
   290 	filterHistory : function(postid, setSize) {
   273 		// Apply undo state to history.
   291 		// Apply undo state to history.
   274 		var history = $('#imgedit-history-' + postid).val(), pop, n, o, i, op = [];
   292 		var history = $('#imgedit-history-' + postid).val(), pop, n, o, i, op = [];
   275 
   293 
   293 				}
   311 				}
   294 
   312 
   295 				// Restore original 'o'.
   313 				// Restore original 'o'.
   296 				o = history[history.length - 1];
   314 				o = history[history.length - 1];
   297 
   315 
   298 				// c = 'crop', r = 'rotate', f = 'flip'
   316 				// c = 'crop', r = 'rotate', f = 'flip'.
   299 				o = o.c || o.r || o.f || false;
   317 				o = o.c || o.r || o.f || false;
   300 
   318 
   301 				if ( o ) {
   319 				if ( o ) {
   302 					// fw = Full image width
   320 					// fw = Full image width.
   303 					this.hold.w = o.fw;
   321 					this.hold.w = o.fw;
   304 					// fh = Full image height
   322 					// fh = Full image height.
   305 					this.hold.h = o.fh;
   323 					this.hold.h = o.fh;
   306 				}
   324 				}
   307 			}
   325 			}
   308 
   326 
   309 			// Filter the last step/action from the history.
   327 			// Filter the last step/action from the history.
   324 	/**
   342 	/**
   325 	 * Binds the necessary events to the image.
   343 	 * Binds the necessary events to the image.
   326 	 *
   344 	 *
   327 	 * When the image source is reloaded the image will be reloaded.
   345 	 * When the image source is reloaded the image will be reloaded.
   328 	 *
   346 	 *
   329 	 * @memberof imageEdit
   347 	 * @since 2.9.0
   330 	 * @since    2.9.0
   348 	 *
   331 	 *
   349 	 * @memberof imageEdit
   332 	 * @param {number}   postid   The post id.
   350 	 *
       
   351 	 * @param {number}   postid   The post ID.
   333 	 * @param {string}   nonce    The nonce to verify the request.
   352 	 * @param {string}   nonce    The nonce to verify the request.
   334 	 * @param {function} callback Function to execute when the image is loaded.
   353 	 * @param {function} callback Function to execute when the image is loaded.
   335 	 *
   354 	 *
   336 	 * @returns {void}
   355 	 * @return {void}
   337 	 */
   356 	 */
   338 	refreshEditor : function(postid, nonce, callback) {
   357 	refreshEditor : function(postid, nonce, callback) {
   339 		var t = this, data, img;
   358 		var t = this, data, img;
   340 
   359 
   341 		t.toggleEditor(postid, 1);
   360 		t.toggleEditor(postid, 1);
   369 					}
   388 					}
   370 				}
   389 				}
   371 
   390 
   372 				parent.empty().append(img);
   391 				parent.empty().append(img);
   373 
   392 
   374 				// w, h are the new full size dims
   393 				// w, h are the new full size dimensions.
   375 				max1 = Math.max( t.hold.w, t.hold.h );
   394 				max1 = Math.max( t.hold.w, t.hold.h );
   376 				max2 = Math.max( $(img).width(), $(img).height() );
   395 				max2 = Math.max( $(img).width(), $(img).height() );
   377 				t.hold.sizer = max1 > max2 ? max2 / max1 : 1;
   396 				t.hold.sizer = max1 > max2 ? max2 / max1 : 1;
   378 
   397 
   379 				t.initCrop(postid, img, parent);
   398 				t.initCrop(postid, img, parent);
   388 					$('input.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', true);
   407 					$('input.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', true);
   389 				}
   408 				}
   390 
   409 
   391 				t.toggleEditor(postid, 0);
   410 				t.toggleEditor(postid, 0);
   392 			})
   411 			})
   393 			.on('error', function() {
   412 			.on( 'error', function() {
   394 				$('#imgedit-crop-' + postid).empty().append('<div class="error"><p>' + imageEditL10n.error + '</p></div>');
   413 				var errorMessage = __( 'Could not load the preview image. Please reload the page and try again.' );
   395 				t.toggleEditor(postid, 0);
   414 
   396 			})
   415 				$( '#imgedit-crop-' + postid )
       
   416 					.empty()
       
   417 					.append( '<div class="notice notice-error" tabindex="-1" role="alert"><p>' + errorMessage + '</p></div>' );
       
   418 
       
   419 				t.toggleEditor( postid, 0, true );
       
   420 				wp.a11y.speak( errorMessage, 'assertive' );
       
   421 			} )
   397 			.attr('src', ajaxurl + '?' + $.param(data));
   422 			.attr('src', ajaxurl + '?' + $.param(data));
   398 	},
   423 	},
   399 	/**
   424 	/**
   400 	 * Performs an image edit action.
   425 	 * Performs an image edit action.
   401 	 *
   426 	 *
   402 	 * @memberof imageEdit
   427 	 * @since 2.9.0
   403 	 * @since    2.9.0
   428 	 *
   404 	 *
   429 	 * @memberof imageEdit
   405 	 * @param  {number}  postid The post id.
   430 	 *
   406 	 * @param  {string}  nonce  The nonce to verify the request.
   431 	 * @param {number} postid The post ID.
   407 	 * @param  {string}  action The action to perform on the image.
   432 	 * @param {string} nonce  The nonce to verify the request.
   408 	 *                          The possible actions are: "scale" and "restore".
   433 	 * @param {string} action The action to perform on the image.
   409 	 *
   434 	 *                        The possible actions are: "scale" and "restore".
   410 	 * @returns {boolean|void} Executes a post request that refreshes the page
   435 	 *
   411 	 *                         when the action is performed.
   436 	 * @return {boolean|void} Executes a post request that refreshes the page
   412 	 *                         Returns false if a invalid action is given,
   437 	 *                        when the action is performed.
   413 	 *                         or when the action cannot be performed.
   438 	 *                        Returns false if a invalid action is given,
       
   439 	 *                        or when the action cannot be performed.
   414 	 */
   440 	 */
   415 	action : function(postid, nonce, action) {
   441 	action : function(postid, nonce, action) {
   416 		var t = this, data, w, h, fw, fh;
   442 		var t = this, data, w, h, fw, fh;
   417 
   443 
   418 		if ( t.notsaved(postid) ) {
   444 		if ( t.notsaved(postid) ) {
   451 		} else {
   477 		} else {
   452 			return false;
   478 			return false;
   453 		}
   479 		}
   454 
   480 
   455 		t.toggleEditor(postid, 1);
   481 		t.toggleEditor(postid, 1);
   456 		$.post(ajaxurl, data, function(r) {
   482 		$.post( ajaxurl, data, function( response ) {
   457 			$('#image-editor-' + postid).empty().append(r);
   483 			$( '#image-editor-' + postid ).empty().append( response.data.html );
   458 			t.toggleEditor(postid, 0);
   484 			t.toggleEditor( postid, 0, true );
   459 			// refresh the attachment model so that changes propagate
   485 			// Refresh the attachment model so that changes propagate.
   460 			if ( t._view ) {
   486 			if ( t._view ) {
   461 				t._view.refresh();
   487 				t._view.refresh();
   462 			}
   488 			}
   463 		});
   489 		} ).done( function( response ) {
       
   490 			// Whether the executed action was `scale` or `restore`, the response does have a message.
       
   491 			if ( response && response.data.message.msg ) {
       
   492 				wp.a11y.speak( response.data.message.msg );
       
   493 				return;
       
   494 			}
       
   495 
       
   496 			if ( response && response.data.message.error ) {
       
   497 				wp.a11y.speak( response.data.message.error );
       
   498 			}
       
   499 		} );
   464 	},
   500 	},
   465 
   501 
   466 	/**
   502 	/**
   467 	 * Stores the changes that are made to the image.
   503 	 * Stores the changes that are made to the image.
   468 	 *
   504 	 *
   469 	 * @memberof imageEdit
   505 	 * @since 2.9.0
   470 	 * @since    2.9.0
   506 	 *
   471 	 *
   507 	 * @memberof imageEdit
   472 	 * @param {number}  postid   The post id to get the image from the database.
   508 	 *
       
   509 	 * @param {number}  postid   The post ID to get the image from the database.
   473 	 * @param {string}  nonce    The nonce to verify the request.
   510 	 * @param {string}  nonce    The nonce to verify the request.
   474 	 *
   511 	 *
   475 	 * @returns {boolean|void}  If the actions are successfully saved a response message is shown.
   512 	 * @return {boolean|void}  If the actions are successfully saved a response message is shown.
   476 	 *                          Returns false if there is no image editing history,
   513 	 *                         Returns false if there is no image editing history,
   477 	 *                          thus there are not edit-actions performed on the image.
   514 	 *                         thus there are not edit-actions performed on the image.
   478 	 */
   515 	 */
   479 	save : function(postid, nonce) {
   516 	save : function(postid, nonce) {
   480 		var data,
   517 		var data,
   481 			target = this.getTarget(postid),
   518 			target = this.getTarget(postid),
   482 			history = this.filterHistory(postid, 0),
   519 			history = this.filterHistory(postid, 0),
   495 			'target': target,
   532 			'target': target,
   496 			'context': $('#image-edit-context').length ? $('#image-edit-context').val() : null,
   533 			'context': $('#image-edit-context').length ? $('#image-edit-context').val() : null,
   497 			'do': 'save'
   534 			'do': 'save'
   498 		};
   535 		};
   499 		// Post the image edit data to the backend.
   536 		// Post the image edit data to the backend.
   500 		$.post(ajaxurl, data, function(r) {
   537 		$.post( ajaxurl, data, function( response ) {
   501 			// Read the response.
       
   502 			var ret = JSON.parse(r);
       
   503 
       
   504 			// If a response is returned, close the editor and show an error.
   538 			// If a response is returned, close the editor and show an error.
   505 			if ( ret.error ) {
   539 			if ( response.data.error ) {
   506 				$('#imgedit-response-' + postid).html('<div class="error"><p>' + ret.error + '</p></div>');
   540 				$( '#imgedit-response-' + postid )
       
   541 					.html( '<div class="notice notice-error" tabindex="-1" role="alert"><p>' + response.data.error + '</p></div>' );
       
   542 
   507 				imageEdit.close(postid);
   543 				imageEdit.close(postid);
       
   544 				wp.a11y.speak( response.data.error );
   508 				return;
   545 				return;
   509 			}
   546 			}
   510 
   547 
   511 			if ( ret.fw && ret.fh ) {
   548 			if ( response.data.fw && response.data.fh ) {
   512 				$('#media-dims-' + postid).html( ret.fw + ' &times; ' + ret.fh );
   549 				$( '#media-dims-' + postid ).html( response.data.fw + ' &times; ' + response.data.fh );
   513 			}
   550 			}
   514 
   551 
   515 			if ( ret.thumbnail ) {
   552 			if ( response.data.thumbnail ) {
   516 				$('.thumbnail', '#thumbnail-head-' + postid).attr('src', ''+ret.thumbnail);
   553 				$( '.thumbnail', '#thumbnail-head-' + postid ).attr( 'src', '' + response.data.thumbnail );
   517 			}
   554 			}
   518 
   555 
   519 			if ( ret.msg ) {
   556 			if ( response.data.msg ) {
   520 				$('#imgedit-response-' + postid).html('<div class="updated"><p>' + ret.msg + '</p></div>');
   557 				$( '#imgedit-response-' + postid )
       
   558 					.html( '<div class="notice notice-success" tabindex="-1" role="alert"><p>' + response.data.msg + '</p></div>' );
       
   559 
       
   560 				wp.a11y.speak( response.data.msg );
   521 			}
   561 			}
   522 
   562 
   523 			if ( self._view ) {
   563 			if ( self._view ) {
   524 				self._view.save();
   564 				self._view.save();
   525 			} else {
   565 			} else {
   529 	},
   569 	},
   530 
   570 
   531 	/**
   571 	/**
   532 	 * Creates the image edit window.
   572 	 * Creates the image edit window.
   533 	 *
   573 	 *
   534 	 * @memberof imageEdit
   574 	 * @since 2.9.0
   535 	 * @since    2.9.0
   575 	 *
   536 	 *
   576 	 * @memberof imageEdit
   537 	 * @param {number} postid   The post id for the image.
   577 	 *
       
   578 	 * @param {number} postid   The post ID for the image.
   538 	 * @param {string} nonce    The nonce to verify the request.
   579 	 * @param {string} nonce    The nonce to verify the request.
   539 	 * @param {object} view     The image editor view to be used for the editing.
   580 	 * @param {Object} view     The image editor view to be used for the editing.
   540 	 *
   581 	 *
   541 	 * @returns {void|promise} Either returns void if the button was already activated
   582 	 * @return {void|promise} Either returns void if the button was already activated
   542 	 *                         or returns an instance of the image editor, wrapped in a promise.
   583 	 *                        or returns an instance of the image editor, wrapped in a promise.
   543 	 */
   584 	 */
   544 	open : function( postid, nonce, view ) {
   585 	open : function( postid, nonce, view ) {
   545 		this._view = view;
   586 		this._view = view;
   546 
   587 
   547 		var dfd, data, elem = $('#image-editor-' + postid), head = $('#media-head-' + postid),
   588 		var dfd, data,
   548 			btn = $('#imgedit-open-btn-' + postid), spin = btn.siblings('.spinner');
   589 			elem = $( '#image-editor-' + postid ),
       
   590 			head = $( '#media-head-' + postid ),
       
   591 			btn = $( '#imgedit-open-btn-' + postid ),
       
   592 			spin = btn.siblings( '.spinner' );
   549 
   593 
   550 		/*
   594 		/*
   551 		 * Instead of disabling the button, which causes a focus loss and makes screen
   595 		 * Instead of disabling the button, which causes a focus loss and makes screen
   552 		 * readers announce "unavailable", return if the button was already clicked.
   596 		 * readers announce "unavailable", return if the button was already clicked.
   553 		 */
   597 		 */
   562 			'_ajax_nonce': nonce,
   606 			'_ajax_nonce': nonce,
   563 			'postid': postid,
   607 			'postid': postid,
   564 			'do': 'open'
   608 			'do': 'open'
   565 		};
   609 		};
   566 
   610 
   567 		dfd = $.ajax({
   611 		dfd = $.ajax( {
   568 			url:  ajaxurl,
   612 			url:  ajaxurl,
   569 			type: 'post',
   613 			type: 'post',
   570 			data: data,
   614 			data: data,
   571 			beforeSend: function() {
   615 			beforeSend: function() {
   572 				btn.addClass( 'button-activated' );
   616 				btn.addClass( 'button-activated' );
   573 			}
   617 			}
   574 		}).done(function( html ) {
   618 		} ).done( function( response ) {
   575 			elem.html( html );
   619 			var errorMessage;
   576 			head.fadeOut('fast', function(){
   620 
   577 				elem.fadeIn('fast');
   621 			if ( '-1' === response ) {
       
   622 				errorMessage = __( 'Could not load the preview image.' );
       
   623 				elem.html( '<div class="notice notice-error" tabindex="-1" role="alert"><p>' + errorMessage + '</p></div>' );
       
   624 			}
       
   625 
       
   626 			if ( response.data && response.data.html ) {
       
   627 				elem.html( response.data.html );
       
   628 			}
       
   629 
       
   630 			head.fadeOut( 'fast', function() {
       
   631 				elem.fadeIn( 'fast', function() {
       
   632 					if ( errorMessage ) {
       
   633 						$( document ).trigger( 'image-editor-ui-ready' );
       
   634 					}
       
   635 				} );
   578 				btn.removeClass( 'button-activated' );
   636 				btn.removeClass( 'button-activated' );
   579 				spin.removeClass( 'is-active' );
   637 				spin.removeClass( 'is-active' );
   580 			});
   638 			} );
   581 			// Initialise the Image Editor now that everything is ready.
   639 			// Initialise the Image Editor now that everything is ready.
   582 			imageEdit.init( postid );
   640 			imageEdit.init( postid );
   583 		});
   641 		} );
   584 
   642 
   585 		return dfd;
   643 		return dfd;
   586 	},
   644 	},
   587 
   645 
   588 	/**
   646 	/**
   589 	 * Initializes the cropping tool and sets a default cropping selection.
   647 	 * Initializes the cropping tool and sets a default cropping selection.
   590 	 *
   648 	 *
   591 	 * @memberof imageEdit
   649 	 * @since 2.9.0
   592 	 * @since    2.9.0
   650 	 *
   593 	 *
   651 	 * @memberof imageEdit
   594 	 * @param {number} postid The post id.
   652 	 *
   595 	 *
   653 	 * @param {number} postid The post ID.
   596 	 * @returns {void}
   654 	 *
       
   655 	 * @return {void}
   597 	 */
   656 	 */
   598 	imgLoaded : function(postid) {
   657 	imgLoaded : function(postid) {
   599 		var img = $('#image-preview-' + postid), parent = $('#imgedit-crop-' + postid);
   658 		var img = $('#image-preview-' + postid), parent = $('#imgedit-crop-' + postid);
   600 
   659 
   601 		// Ensure init has run even when directly loaded.
   660 		// Ensure init has run even when directly loaded.
   604 		}
   663 		}
   605 
   664 
   606 		this.initCrop(postid, img, parent);
   665 		this.initCrop(postid, img, parent);
   607 		this.setCropSelection( postid, { 'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0, 'width': img.innerWidth(), 'height': img.innerHeight() } );
   666 		this.setCropSelection( postid, { 'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0, 'width': img.innerWidth(), 'height': img.innerHeight() } );
   608 
   667 
   609 		this.toggleEditor(postid, 0);
   668 		this.toggleEditor( postid, 0, true );
   610 		// Editor is ready, move focus to the first focusable element.
   669 	},
   611 		$( '.imgedit-wrap .imgedit-help-toggle' ).eq( 0 ).focus();
   670 
       
   671 	/**
       
   672 	 * Manages keyboard focus in the Image Editor user interface.
       
   673 	 *
       
   674 	 * @since 5.5.0
       
   675 	 *
       
   676 	 * @return {void}
       
   677 	 */
       
   678 	focusManager: function() {
       
   679 		/*
       
   680 		 * Editor is ready. Move focus to one of the admin alert notices displayed
       
   681 		 * after a user action or to the first focusable element. Since the DOM
       
   682 		 * update is pretty large, the timeout helps browsers update their
       
   683 		 * accessibility tree to better support assistive technologies.
       
   684 		 */
       
   685 		setTimeout( function() {
       
   686 			var elementToSetFocusTo = $( '.notice[role="alert"]' );
       
   687 
       
   688 			if ( ! elementToSetFocusTo.length ) {
       
   689 				elementToSetFocusTo = $( '.imgedit-wrap' ).find( ':tabbable:first' );
       
   690 			}
       
   691 
       
   692 			elementToSetFocusTo.focus();
       
   693 		}, 100 );
   612 	},
   694 	},
   613 
   695 
   614 	/**
   696 	/**
   615 	 * Initializes the cropping tool.
   697 	 * Initializes the cropping tool.
   616 	 *
   698 	 *
   617 	 * @memberof imageEdit
   699 	 * @since 2.9.0
   618 	 * @since    2.9.0
   700 	 *
   619 	 *
   701 	 * @memberof imageEdit
   620 	 * @param {number}      postid The post id.
   702 	 *
       
   703 	 * @param {number}      postid The post ID.
   621 	 * @param {HTMLElement} image  The preview image.
   704 	 * @param {HTMLElement} image  The preview image.
   622 	 * @param {HTMLElement} parent The preview image container.
   705 	 * @param {HTMLElement} parent The preview image container.
   623 	 *
   706 	 *
   624 	 * @returns {void}
   707 	 * @return {void}
   625 	 */
   708 	 */
   626 	initCrop : function(postid, image, parent) {
   709 	initCrop : function(postid, image, parent) {
   627 		var t = this,
   710 		var t = this,
   628 			selW = $('#imgedit-sel-width-' + postid),
   711 			selW = $('#imgedit-sel-width-' + postid),
   629 			selH = $('#imgedit-sel-height-' + postid),
   712 			selH = $('#imgedit-sel-height-' + postid),
       
   713 			$image = $( image ),
   630 			$img;
   714 			$img;
   631 
   715 
   632 		t.iasapi = $(image).imgAreaSelect({
   716 		// Already initialized?
       
   717 		if ( $image.data( 'imgAreaSelect' ) ) {
       
   718 			return;
       
   719 		}
       
   720 
       
   721 		t.iasapi = $image.imgAreaSelect({
   633 			parent: parent,
   722 			parent: parent,
   634 			instance: true,
   723 			instance: true,
   635 			handles: true,
   724 			handles: true,
   636 			keys: true,
   725 			keys: true,
   637 			minWidth: 3,
   726 			minWidth: 3,
   643 			 * @ignore
   732 			 * @ignore
   644 			 *
   733 			 *
   645 			 * @param {jQuery} img The preview image.
   734 			 * @param {jQuery} img The preview image.
   646 			 */
   735 			 */
   647 			onInit: function( img ) {
   736 			onInit: function( img ) {
   648 				// Ensure that the imgAreaSelect wrapper elements are position:absolute.
   737 				// Ensure that the imgAreaSelect wrapper elements are position:absolute
   649 				// (even if we're in a position:fixed modal)
   738 				// (even if we're in a position:fixed modal).
   650 				$img = $( img );
   739 				$img = $( img );
   651 				$img.next().css( 'position', 'absolute' )
   740 				$img.next().css( 'position', 'absolute' )
   652 					.nextAll( '.imgareaselect-outer' ).css( 'position', 'absolute' );
   741 					.nextAll( '.imgareaselect-outer' ).css( 'position', 'absolute' );
   653 				/**
   742 				/**
   654 				 * Binds mouse down event to the cropping container.
   743 				 * Binds mouse down event to the cropping container.
   655 				 *
   744 				 *
   656 				 * @returns {void}
   745 				 * @return {void}
   657 				 */
   746 				 */
   658 				parent.children().on( 'mousedown, touchstart', function(e){
   747 				parent.children().on( 'mousedown, touchstart', function(e){
   659 					var ratio = false, sel, defRatio;
   748 					var ratio = false, sel, defRatio;
   660 
   749 
   661 					if ( e.shiftKey ) {
   750 					if ( e.shiftKey ) {
   673 			/**
   762 			/**
   674 			 * Event triggered when starting a selection.
   763 			 * Event triggered when starting a selection.
   675 			 *
   764 			 *
   676 			 * @ignore
   765 			 * @ignore
   677 			 *
   766 			 *
   678 			 * @returns {void}
   767 			 * @return {void}
   679 			 */
   768 			 */
   680 			onSelectStart: function() {
   769 			onSelectStart: function() {
   681 				imageEdit.setDisabled($('#imgedit-crop-sel-' + postid), 1);
   770 				imageEdit.setDisabled($('#imgedit-crop-sel-' + postid), 1);
   682 			},
   771 			},
   683 			/**
   772 			/**
   684 			 * Event triggered when the selection is ended.
   773 			 * Event triggered when the selection is ended.
   685 			 *
   774 			 *
   686 			 * @ignore
   775 			 * @ignore
   687 			 *
   776 			 *
   688 			 * @param {object} img jQuery object representing the image.
   777 			 * @param {Object} img jQuery object representing the image.
   689 			 * @param {object} c   The selection.
   778 			 * @param {Object} c   The selection.
   690 			 *
   779 			 *
   691 			 * @returns {object}
   780 			 * @return {Object}
   692 			 */
   781 			 */
   693 			onSelectEnd: function(img, c) {
   782 			onSelectEnd: function(img, c) {
   694 				imageEdit.setCropSelection(postid, c);
   783 				imageEdit.setCropSelection(postid, c);
   695 			},
   784 			},
   696 
   785 
   697 			/**
   786 			/**
   698 			 * Event triggered when the selection changes.
   787 			 * Event triggered when the selection changes.
   699 			 *
   788 			 *
   700 			 * @ignore
   789 			 * @ignore
   701 			 *
   790 			 *
   702 			 * @param {object} img jQuery object representing the image.
   791 			 * @param {Object} img jQuery object representing the image.
   703 			 * @param {object} c   The selection.
   792 			 * @param {Object} c   The selection.
   704 			 *
   793 			 *
   705 			 * @returns {void}
   794 			 * @return {void}
   706 			 */
   795 			 */
   707 			onSelectChange: function(img, c) {
   796 			onSelectChange: function(img, c) {
   708 				var sizer = imageEdit.hold.sizer;
   797 				var sizer = imageEdit.hold.sizer;
   709 				selW.val( imageEdit.round(c.width / sizer) );
   798 				selW.val( imageEdit.round(c.width / sizer) );
   710 				selH.val( imageEdit.round(c.height / sizer) );
   799 				selH.val( imageEdit.round(c.height / sizer) );
   713 	},
   802 	},
   714 
   803 
   715 	/**
   804 	/**
   716 	 * Stores the current crop selection.
   805 	 * Stores the current crop selection.
   717 	 *
   806 	 *
   718 	 * @memberof imageEdit
   807 	 * @since 2.9.0
   719 	 * @since    2.9.0
   808 	 *
   720 	 *
   809 	 * @memberof imageEdit
   721 	 * @param {number} postid The post id.
   810 	 *
   722 	 * @param {object} c      The selection.
   811 	 * @param {number} postid The post ID.
   723 	 *
   812 	 * @param {Object} c      The selection.
   724 	 * @returns {boolean}
   813 	 *
       
   814 	 * @return {boolean}
   725 	 */
   815 	 */
   726 	setCropSelection : function(postid, c) {
   816 	setCropSelection : function(postid, c) {
   727 		var sel;
   817 		var sel;
   728 
   818 
   729 		c = c || 0;
   819 		c = c || 0;
   744 
   834 
   745 
   835 
   746 	/**
   836 	/**
   747 	 * Closes the image editor.
   837 	 * Closes the image editor.
   748 	 *
   838 	 *
   749 	 * @memberof imageEdit
   839 	 * @since 2.9.0
   750 	 * @since    2.9.0
   840 	 *
   751 	 *
   841 	 * @memberof imageEdit
   752 	 * @param {number}  postid The post id.
   842 	 *
   753 	 * @param {bool}    warn   Warning message.
   843 	 * @param {number}  postid The post ID.
   754 	 *
   844 	 * @param {boolean} warn   Warning message.
   755 	 * @returns {void|bool} Returns false if there is a warning.
   845 	 *
       
   846 	 * @return {void|boolean} Returns false if there is a warning.
   756 	 */
   847 	 */
   757 	close : function(postid, warn) {
   848 	close : function(postid, warn) {
   758 		warn = warn || false;
   849 		warn = warn || false;
   759 
   850 
   760 		if ( warn && this.notsaved(postid) ) {
   851 		if ( warn && this.notsaved(postid) ) {
   762 		}
   853 		}
   763 
   854 
   764 		this.iasapi = {};
   855 		this.iasapi = {};
   765 		this.hold = {};
   856 		this.hold = {};
   766 
   857 
   767 		// If we've loaded the editor in the context of a Media Modal, then switch to the previous view,
   858 		// If we've loaded the editor in the context of a Media Modal,
   768 		// whatever that might have been.
   859 		// then switch to the previous view, whatever that might have been.
   769 		if ( this._view ){
   860 		if ( this._view ){
   770 			this._view.back();
   861 			this._view.back();
   771 		}
   862 		}
   772 
   863 
   773 		// In case we are not accessing the image editor in the context of a View, close the editor the old-skool way
   864 		// In case we are not accessing the image editor in the context of a View,
       
   865 		// close the editor the old-school way.
   774 		else {
   866 		else {
   775 			$('#image-editor-' + postid).fadeOut('fast', function() {
   867 			$('#image-editor-' + postid).fadeOut('fast', function() {
   776 				$( '#media-head-' + postid ).fadeIn( 'fast', function() {
   868 				$( '#media-head-' + postid ).fadeIn( 'fast', function() {
   777 					// Move focus back to the Edit Image button. Runs also when saving.
   869 					// Move focus back to the Edit Image button. Runs also when saving.
   778 					$( '#imgedit-open-btn-' + postid ).focus();
   870 					$( '#imgedit-open-btn-' + postid ).focus();
   785 	},
   877 	},
   786 
   878 
   787 	/**
   879 	/**
   788 	 * Checks if the image edit history is saved.
   880 	 * Checks if the image edit history is saved.
   789 	 *
   881 	 *
   790 	 * @memberof imageEdit
   882 	 * @since 2.9.0
   791 	 * @since    2.9.0
   883 	 *
   792 	 *
   884 	 * @memberof imageEdit
   793 	 * @param {number} postid The post id.
   885 	 *
   794 	 *
   886 	 * @param {number} postid The post ID.
   795 	 * @returns {boolean} Returns true if the history is not saved.
   887 	 *
       
   888 	 * @return {boolean} Returns true if the history is not saved.
   796 	 */
   889 	 */
   797 	notsaved : function(postid) {
   890 	notsaved : function(postid) {
   798 		var h = $('#imgedit-history-' + postid).val(),
   891 		var h = $('#imgedit-history-' + postid).val(),
   799 			history = ( h !== '' ) ? JSON.parse(h) : [],
   892 			history = ( h !== '' ) ? JSON.parse(h) : [],
   800 			pop = this.intval( $('#imgedit-undone-' + postid).val() );
   893 			pop = this.intval( $('#imgedit-undone-' + postid).val() );
   809 	},
   902 	},
   810 
   903 
   811 	/**
   904 	/**
   812 	 * Adds an image edit action to the history.
   905 	 * Adds an image edit action to the history.
   813 	 *
   906 	 *
   814 	 * @memberof imageEdit
   907 	 * @since 2.9.0
   815 	 * @since    2.9.0
   908 	 *
   816 	 *
   909 	 * @memberof imageEdit
   817 	 * @param {object} op     The original position.
   910 	 *
   818 	 * @param {number} postid The post id.
   911 	 * @param {Object} op     The original position.
       
   912 	 * @param {number} postid The post ID.
   819 	 * @param {string} nonce  The nonce.
   913 	 * @param {string} nonce  The nonce.
   820 	 *
   914 	 *
   821 	 * @returns {void}
   915 	 * @return {void}
   822 	 */
   916 	 */
   823 	addStep : function(op, postid, nonce) {
   917 	addStep : function(op, postid, nonce) {
   824 		var t = this, elem = $('#imgedit-history-' + postid),
   918 		var t = this, elem = $('#imgedit-history-' + postid),
   825 			history = ( elem.val() !== '' ) ? JSON.parse( elem.val() ) : [],
   919 			history = ( elem.val() !== '' ) ? JSON.parse( elem.val() ) : [],
   826 			undone = $( '#imgedit-undone-' + postid ),
   920 			undone = $( '#imgedit-undone-' + postid ),
   828 
   922 
   829 		while ( pop > 0 ) {
   923 		while ( pop > 0 ) {
   830 			history.pop();
   924 			history.pop();
   831 			pop--;
   925 			pop--;
   832 		}
   926 		}
   833 		undone.val(0); // reset
   927 		undone.val(0); // Reset.
   834 
   928 
   835 		history.push(op);
   929 		history.push(op);
   836 		elem.val( JSON.stringify(history) );
   930 		elem.val( JSON.stringify(history) );
   837 
   931 
   838 		t.refreshEditor(postid, nonce, function() {
   932 		t.refreshEditor(postid, nonce, function() {
   842 	},
   936 	},
   843 
   937 
   844 	/**
   938 	/**
   845 	 * Rotates the image.
   939 	 * Rotates the image.
   846 	 *
   940 	 *
   847 	 * @memberof imageEdit
   941 	 * @since 2.9.0
   848 	 * @since    2.9.0
   942 	 *
       
   943 	 * @memberof imageEdit
   849 	 *
   944 	 *
   850 	 * @param {string} angle  The angle the image is rotated with.
   945 	 * @param {string} angle  The angle the image is rotated with.
   851 	 * @param {number} postid The post id.
   946 	 * @param {number} postid The post ID.
   852 	 * @param {string} nonce  The nonce.
   947 	 * @param {string} nonce  The nonce.
   853 	 * @param {object} t      The target element.
   948 	 * @param {Object} t      The target element.
   854 	 *
   949 	 *
   855 	 * @returns {boolean}
   950 	 * @return {boolean}
   856 	 */
   951 	 */
   857 	rotate : function(angle, postid, nonce, t) {
   952 	rotate : function(angle, postid, nonce, t) {
   858 		if ( $(t).hasClass('disabled') ) {
   953 		if ( $(t).hasClass('disabled') ) {
   859 			return false;
   954 			return false;
   860 		}
   955 		}
   863 	},
   958 	},
   864 
   959 
   865 	/**
   960 	/**
   866 	 * Flips the image.
   961 	 * Flips the image.
   867 	 *
   962 	 *
   868 	 * @memberof imageEdit
   963 	 * @since 2.9.0
   869 	 * @since    2.9.0
   964 	 *
       
   965 	 * @memberof imageEdit
   870 	 *
   966 	 *
   871 	 * @param {number} axis   The axle the image is flipped on.
   967 	 * @param {number} axis   The axle the image is flipped on.
   872 	 * @param {number} postid The post id.
   968 	 * @param {number} postid The post ID.
   873 	 * @param {string} nonce  The nonce.
   969 	 * @param {string} nonce  The nonce.
   874 	 * @param {object} t      The target element.
   970 	 * @param {Object} t      The target element.
   875 	 *
   971 	 *
   876 	 * @returns {boolean}
   972 	 * @return {boolean}
   877 	 */
   973 	 */
   878 	flip : function (axis, postid, nonce, t) {
   974 	flip : function (axis, postid, nonce, t) {
   879 		if ( $(t).hasClass('disabled') ) {
   975 		if ( $(t).hasClass('disabled') ) {
   880 			return false;
   976 			return false;
   881 		}
   977 		}
   884 	},
   980 	},
   885 
   981 
   886 	/**
   982 	/**
   887 	 * Crops the image.
   983 	 * Crops the image.
   888 	 *
   984 	 *
   889 	 * @memberof imageEdit
   985 	 * @since 2.9.0
   890 	 * @since    2.9.0
   986 	 *
   891 	 *
   987 	 * @memberof imageEdit
   892 	 * @param {number} postid The post id.
   988 	 *
       
   989 	 * @param {number} postid The post ID.
   893 	 * @param {string} nonce  The nonce.
   990 	 * @param {string} nonce  The nonce.
   894 	 * @param {object} t      The target object.
   991 	 * @param {Object} t      The target object.
   895 	 *
   992 	 *
   896 	 * @returns {void|boolean} Returns false if the crop button is disabled.
   993 	 * @return {void|boolean} Returns false if the crop button is disabled.
   897 	 */
   994 	 */
   898 	crop : function (postid, nonce, t) {
   995 	crop : function (postid, nonce, t) {
   899 		var sel = $('#imgedit-selection-' + postid).val(),
   996 		var sel = $('#imgedit-selection-' + postid).val(),
   900 			w = this.intval( $('#imgedit-sel-width-' + postid).val() ),
   997 			w = this.intval( $('#imgedit-sel-width-' + postid).val() ),
   901 			h = this.intval( $('#imgedit-sel-height-' + postid).val() );
   998 			h = this.intval( $('#imgedit-sel-height-' + postid).val() );
   913 	},
  1010 	},
   914 
  1011 
   915 	/**
  1012 	/**
   916 	 * Undoes an image edit action.
  1013 	 * Undoes an image edit action.
   917 	 *
  1014 	 *
   918 	 * @memberof imageEdit
  1015 	 * @since 2.9.0
   919 	 * @since    2.9.0
  1016 	 *
   920 	 *
  1017 	 * @memberof imageEdit
   921 	 * @param {number} postid   The post id.
  1018 	 *
       
  1019 	 * @param {number} postid   The post ID.
   922 	 * @param {string} nonce    The nonce.
  1020 	 * @param {string} nonce    The nonce.
   923 	 *
  1021 	 *
   924 	 * @returns {void|false} Returns false if the undo button is disabled.
  1022 	 * @return {void|false} Returns false if the undo button is disabled.
   925 	 */
  1023 	 */
   926 	undo : function (postid, nonce) {
  1024 	undo : function (postid, nonce) {
   927 		var t = this, button = $('#image-undo-' + postid), elem = $('#imgedit-undone-' + postid),
  1025 		var t = this, button = $('#image-undo-' + postid), elem = $('#imgedit-undone-' + postid),
   928 			pop = t.intval( elem.val() ) + 1;
  1026 			pop = t.intval( elem.val() ) + 1;
   929 
  1027 
   946 	},
  1044 	},
   947 
  1045 
   948 	/**
  1046 	/**
   949 	 * Reverts a undo action.
  1047 	 * Reverts a undo action.
   950 	 *
  1048 	 *
   951 	 * @memberof imageEdit
  1049 	 * @since 2.9.0
   952 	 * @since    2.9.0
  1050 	 *
   953 	 *
  1051 	 * @memberof imageEdit
   954 	 * @param {number} postid The post id.
  1052 	 *
       
  1053 	 * @param {number} postid The post ID.
   955 	 * @param {string} nonce  The nonce.
  1054 	 * @param {string} nonce  The nonce.
   956 	 *
  1055 	 *
   957 	 * @returns {void}
  1056 	 * @return {void}
   958 	 */
  1057 	 */
   959 	redo : function(postid, nonce) {
  1058 	redo : function(postid, nonce) {
   960 		var t = this, button = $('#image-redo-' + postid), elem = $('#imgedit-undone-' + postid),
  1059 		var t = this, button = $('#image-redo-' + postid), elem = $('#imgedit-undone-' + postid),
   961 			pop = t.intval( elem.val() ) - 1;
  1060 			pop = t.intval( elem.val() ) - 1;
   962 
  1061 
   976 	},
  1075 	},
   977 
  1076 
   978 	/**
  1077 	/**
   979 	 * Sets the selection for the height and width in pixels.
  1078 	 * Sets the selection for the height and width in pixels.
   980 	 *
  1079 	 *
   981 	 * @memberof imageEdit
  1080 	 * @since 2.9.0
   982 	 * @since    2.9.0
  1081 	 *
   983 	 *
  1082 	 * @memberof imageEdit
   984 	 * @param {number} postid The post id.
  1083 	 *
       
  1084 	 * @param {number} postid The post ID.
   985 	 * @param {jQuery} el     The element containing the values.
  1085 	 * @param {jQuery} el     The element containing the values.
   986 	 *
  1086 	 *
   987 	 * @returns {void|boolean} Returns false when the x or y value is lower than 1,
  1087 	 * @return {void|boolean} Returns false when the x or y value is lower than 1,
   988 	 *                         void when the value is not numeric or when the operation
  1088 	 *                        void when the value is not numeric or when the operation
   989 	 *                         is successful.
  1089 	 *                        is successful.
   990 	 */
  1090 	 */
   991 	setNumSelection : function( postid, el ) {
  1091 	setNumSelection : function( postid, el ) {
   992 		var sel, elX = $('#imgedit-sel-width-' + postid), elY = $('#imgedit-sel-height-' + postid),
  1092 		var sel, elX = $('#imgedit-sel-width-' + postid), elY = $('#imgedit-sel-height-' + postid),
   993 			x = this.intval( elX.val() ), y = this.intval( elY.val() ),
  1093 			x = this.intval( elX.val() ), y = this.intval( elY.val() ),
   994 			img = $('#image-preview-' + postid), imgh = img.height(), imgw = img.width(),
  1094 			img = $('#image-preview-' + postid), imgh = img.height(), imgw = img.width(),
  1033 	},
  1133 	},
  1034 
  1134 
  1035 	/**
  1135 	/**
  1036 	 * Rounds a number to a whole.
  1136 	 * Rounds a number to a whole.
  1037 	 *
  1137 	 *
  1038 	 * @memberof imageEdit
  1138 	 * @since 2.9.0
  1039 	 * @since    2.9.0
  1139 	 *
       
  1140 	 * @memberof imageEdit
  1040 	 *
  1141 	 *
  1041 	 * @param {number} num The number.
  1142 	 * @param {number} num The number.
  1042 	 *
  1143 	 *
  1043 	 * @returns {number} The number rounded to a whole number.
  1144 	 * @return {number} The number rounded to a whole number.
  1044 	 */
  1145 	 */
  1045 	round : function(num) {
  1146 	round : function(num) {
  1046 		var s;
  1147 		var s;
  1047 		num = Math.round(num);
  1148 		num = Math.round(num);
  1048 
  1149 
  1062 	},
  1163 	},
  1063 
  1164 
  1064 	/**
  1165 	/**
  1065 	 * Sets a locked aspect ratio for the selection.
  1166 	 * Sets a locked aspect ratio for the selection.
  1066 	 *
  1167 	 *
  1067 	 * @memberof imageEdit
  1168 	 * @since 2.9.0
  1068 	 * @since    2.9.0
  1169 	 *
  1069 	 *
  1170 	 * @memberof imageEdit
  1070 	 * @param {number} postid     The post id.
  1171 	 *
       
  1172 	 * @param {number} postid     The post ID.
  1071 	 * @param {number} n          The ratio to set.
  1173 	 * @param {number} n          The ratio to set.
  1072 	 * @param {jQuery} el         The element containing the values.
  1174 	 * @param {jQuery} el         The element containing the values.
  1073 	 *
  1175 	 *
  1074 	 * @returns {void}
  1176 	 * @return {void}
  1075 	 */
  1177 	 */
  1076 	setRatioSelection : function(postid, n, el) {
  1178 	setRatioSelection : function(postid, n, el) {
  1077 		var sel, r, x = this.intval( $('#imgedit-crop-width-' + postid).val() ),
  1179 		var sel, r, x = this.intval( $('#imgedit-crop-width-' + postid).val() ),
  1078 			y = this.intval( $('#imgedit-crop-height-' + postid).val() ),
  1180 			y = this.intval( $('#imgedit-crop-height-' + postid).val() ),
  1079 			h = $('#image-preview-' + postid).height();
  1181 			h = $('#image-preview-' + postid).height();
  1080 
  1182 
  1081 		if ( false === this.validateNumeric( el ) ) {
  1183 		if ( false === this.validateNumeric( el ) ) {
       
  1184 			this.iasapi.setOptions({
       
  1185 				aspectRatio: null
       
  1186 			});
       
  1187 
  1082 			return;
  1188 			return;
  1083 		}
  1189 		}
  1084 
  1190 
  1085 		if ( x && y ) {
  1191 		if ( x && y ) {
  1086 			this.iasapi.setOptions({
  1192 			this.iasapi.setOptions({
  1106 	},
  1212 	},
  1107 
  1213 
  1108 	/**
  1214 	/**
  1109 	 * Validates if a value in a jQuery.HTMLElement is numeric.
  1215 	 * Validates if a value in a jQuery.HTMLElement is numeric.
  1110 	 *
  1216 	 *
  1111 	 * @memberof imageEdit
  1217 	 * @since 4.6.0
  1112 	 * @since    4.6
  1218 	 *
       
  1219 	 * @memberof imageEdit
  1113 	 *
  1220 	 *
  1114 	 * @param {jQuery} el The html element.
  1221 	 * @param {jQuery} el The html element.
  1115 	 *
  1222 	 *
  1116 	 * @returns {void|boolean} Returns false if the value is not numeric,
  1223 	 * @return {void|boolean} Returns false if the value is not numeric,
  1117 	 *                         void when it is.
  1224 	 *                        void when it is.
  1118 	 */
  1225 	 */
  1119 	validateNumeric: function( el ) {
  1226 	validateNumeric: function( el ) {
  1120 		if ( ! this.intval( $( el ).val() ) ) {
  1227 		if ( ! this.intval( $( el ).val() ) ) {
  1121 			$( el ).val( '' );
  1228 			$( el ).val( '' );
  1122 			return false;
  1229 			return false;