wp/wp-admin/js/image-edit.js
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
     9 
     9 
    10 (function($) {
    10 (function($) {
    11 	var __ = wp.i18n.__;
    11 	var __ = wp.i18n.__;
    12 
    12 
    13 	/**
    13 	/**
    14 	 * Contains all the methods to initialise and control the image editor.
    14 	 * Contains all the methods to initialize and control the image editor.
    15 	 *
    15 	 *
    16 	 * @namespace imageEdit
    16 	 * @namespace imageEdit
    17 	 */
    17 	 */
    18 	var imageEdit = window.imageEdit = {
    18 	var imageEdit = window.imageEdit = {
    19 	iasapi : {},
    19 	iasapi : {},
    20 	hold : {},
    20 	hold : {},
    21 	postid : '',
    21 	postid : '',
    22 	_view : false,
    22 	_view : false,
    23 
    23 
    24 	/**
    24 	/**
    25 	 * Handle crop tool clicks.
    25 	 * Enable crop tool.
    26 	 */
    26 	 */
    27 	handleCropToolClick: function( postid, nonce, cropButton ) {
    27 	toggleCropTool: function( postid, nonce, cropButton ) {
    28 		var img = $( '#image-preview-' + postid ),
    28 		var img = $( '#image-preview-' + postid ),
    29 			selection = this.iasapi.getSelection();
    29 			selection = this.iasapi.getSelection();
    30 
    30 
    31 		// Ensure selection is available, otherwise reset to full image.
    31 		imageEdit.toggleControls( cropButton );
    32 		if ( isNaN( selection.x1 ) ) {
    32 		var $el = $( cropButton );
    33 			this.setCropSelection( postid, { 'x1': 0, 'y1': 0, 'x2': img.innerWidth(), 'y2': img.innerHeight(), 'width': img.innerWidth(), 'height': img.innerHeight() } );
    33 		var state = ( $el.attr( 'aria-expanded' ) === 'true' ) ? 'true' : 'false';
    34 			selection = this.iasapi.getSelection();
    34 		// Crop tools have been closed.
    35 		}
    35 		if ( 'false' === state ) {
    36 
    36 			// Cancel selection, but do not unset inputs.
    37 		// If we don't already have a selection, select the entire image.
    37 			this.iasapi.cancelSelection();
    38 		if ( 0 === selection.x1 && 0 === selection.y1 && 0 === selection.x2 && 0 === selection.y2 ) {
    38 			imageEdit.setDisabled($('.imgedit-crop-clear'), 0);
    39 			this.iasapi.setSelection( 0, 0, img.innerWidth(), img.innerHeight(), true );
       
    40 			this.iasapi.setOptions( { show: true } );
       
    41 			this.iasapi.update();
       
    42 		} else {
    39 		} else {
    43 
    40 			imageEdit.setDisabled($('.imgedit-crop-clear'), 1);
       
    41 			// Get values from inputs to restore previous selection.
       
    42 			var startX = ( $( '#imgedit-start-x-' + postid ).val() ) ? $('#imgedit-start-x-' + postid).val() : 0;
       
    43 			var startY = ( $( '#imgedit-start-y-' + postid ).val() ) ? $('#imgedit-start-y-' + postid).val() : 0;
       
    44 			var width = ( $( '#imgedit-sel-width-' + postid ).val() ) ? $('#imgedit-sel-width-' + postid).val() : img.innerWidth();
       
    45 			var height = ( $( '#imgedit-sel-height-' + postid ).val() ) ? $('#imgedit-sel-height-' + postid).val() : img.innerHeight();
       
    46 			// Ensure selection is available, otherwise reset to full image.
       
    47 			if ( isNaN( selection.x1 ) ) {
       
    48 				this.setCropSelection( postid, { 'x1': startX, 'y1': startY, 'x2': width, 'y2': height, 'width': width, 'height': height } );
       
    49 				selection = this.iasapi.getSelection();
       
    50 			}
       
    51 
       
    52 			// If we don't already have a selection, select the entire image.
       
    53 			if ( 0 === selection.x1 && 0 === selection.y1 && 0 === selection.x2 && 0 === selection.y2 ) {
       
    54 				this.iasapi.setSelection( 0, 0, img.innerWidth(), img.innerHeight(), true );
       
    55 				this.iasapi.setOptions( { show: true } );
       
    56 				this.iasapi.update();
       
    57 			} else {
       
    58 				this.iasapi.setSelection( startX, startY, width, height, true );
       
    59 				this.iasapi.setOptions( { show: true } );
       
    60 				this.iasapi.update();
       
    61 			}
       
    62 		}
       
    63 	},
       
    64 
       
    65 	/**
       
    66 	 * Handle crop tool clicks.
       
    67 	 */
       
    68 	handleCropToolClick: function( postid, nonce, cropButton ) {
       
    69 
       
    70 		if ( cropButton.classList.contains( 'imgedit-crop-clear' ) ) {
       
    71 			this.iasapi.cancelSelection();
       
    72 			imageEdit.setDisabled($('.imgedit-crop-apply'), 0);
       
    73 
       
    74 			$('#imgedit-sel-width-' + postid).val('');
       
    75 			$('#imgedit-sel-height-' + postid).val('');
       
    76 			$('#imgedit-start-x-' + postid).val('0');
       
    77 			$('#imgedit-start-y-' + postid).val('0');
       
    78 			$('#imgedit-selection-' + postid).val('');
       
    79 		} else {
    44 			// Otherwise, perform the crop.
    80 			// Otherwise, perform the crop.
    45 			imageEdit.crop( postid, nonce , cropButton );
    81 			imageEdit.crop( postid, nonce , cropButton );
    46 		}
    82 		}
    47 	},
    83 	},
    48 
    84 
   120 		t.hold.xy_ratio = x / y;
   156 		t.hold.xy_ratio = x / y;
   121 		t.hold.sizer = parseFloat( $('#imgedit-sizer-' + postid).val() );
   157 		t.hold.sizer = parseFloat( $('#imgedit-sizer-' + postid).val() );
   122 		t.postid = postid;
   158 		t.postid = postid;
   123 		$('#imgedit-response-' + postid).empty();
   159 		$('#imgedit-response-' + postid).empty();
   124 
   160 
       
   161 		$('#imgedit-panel-' + postid).on( 'keypress', function(e) {
       
   162 			var nonce = $( '#imgedit-nonce-' + postid ).val();
       
   163 			if ( e.which === 26 && e.ctrlKey ) {
       
   164 				imageEdit.undo( postid, nonce );
       
   165 			}
       
   166 
       
   167 			if ( e.which === 25 && e.ctrlKey ) {
       
   168 				imageEdit.redo( postid, nonce );
       
   169 			}
       
   170 		});
       
   171 
   125 		$('#imgedit-panel-' + postid).on( 'keypress', 'input[type="text"]', function(e) {
   172 		$('#imgedit-panel-' + postid).on( 'keypress', 'input[type="text"]', function(e) {
   126 			var k = e.keyCode;
   173 			var k = e.keyCode;
   127 
   174 
   128 			// Key codes 37 through 40 are the arrow keys.
   175 			// Key codes 37 through 40 are the arrow keys.
   129 			if ( 36 < k && k < 41 ) {
   176 			if ( 36 < k && k < 41 ) {
   168 			} );
   215 			} );
   169 		}
   216 		}
   170 	},
   217 	},
   171 
   218 
   172 	/**
   219 	/**
       
   220 	 * Shows or hides image menu popup.
       
   221 	 *
       
   222 	 * @since 6.3.0
       
   223 	 *
       
   224 	 * @memberof imageEdit
       
   225 	 *
       
   226 	 * @param {HTMLElement} el The activated control element.
       
   227 	 *
       
   228 	 * @return {boolean} Always returns false.
       
   229 	 */
       
   230 	togglePopup : function(el) {
       
   231 		var $el = $( el );
       
   232 		var $targetEl = $( el ).attr( 'aria-controls' );
       
   233 		var $target = $( '#' + $targetEl );
       
   234 		$el
       
   235 			.attr( 'aria-expanded', 'false' === $el.attr( 'aria-expanded' ) ? 'true' : 'false' );
       
   236 		// Open menu and set z-index to appear above image crop area if it is enabled.
       
   237 		$target
       
   238 			.toggleClass( 'imgedit-popup-menu-open' ).slideToggle( 'fast' ).css( { 'z-index' : 200000 } );
       
   239 		// Move focus to first item in menu when opening menu.
       
   240 		if ( 'true' === $el.attr( 'aria-expanded' ) ) {
       
   241 			$target.find( 'button' ).first().trigger( 'focus' );
       
   242 		}
       
   243 
       
   244 		return false;
       
   245 	},
       
   246 
       
   247 	/**
       
   248 	 * Observes whether the popup should remain open based on focus position.
       
   249 	 *
       
   250 	 * @since 6.4.0
       
   251 	 *
       
   252 	 * @memberof imageEdit
       
   253 	 *
       
   254 	 * @param {HTMLElement} el The activated control element.
       
   255 	 *
       
   256 	 * @return {boolean} Always returns false.
       
   257 	 */
       
   258 	monitorPopup : function() {
       
   259 		var $parent = document.querySelector( '.imgedit-rotate-menu-container' );
       
   260 		var $toggle = document.querySelector( '.imgedit-rotate-menu-container .imgedit-rotate' );
       
   261 
       
   262 		setTimeout( function() {
       
   263 			var $focused = document.activeElement;
       
   264 			var $contains = $parent.contains( $focused );
       
   265 
       
   266 			// If $focused is defined and not inside the menu container, close the popup.
       
   267 			if ( $focused && ! $contains ) {
       
   268 				if ( 'true' === $toggle.getAttribute( 'aria-expanded' ) ) {
       
   269 					imageEdit.togglePopup( $toggle );
       
   270 				}
       
   271 			}
       
   272 		}, 100 );
       
   273 
       
   274 		return false;
       
   275 	},
       
   276 
       
   277 	/**
       
   278 	 * Navigate popup menu by arrow keys.
       
   279 	 *
       
   280 	 * @since 6.3.0
       
   281 	 *
       
   282 	 * @memberof imageEdit
       
   283 	 *
       
   284 	 * @param {HTMLElement} el The current element.
       
   285 	 *
       
   286 	 * @return {boolean} Always returns false.
       
   287 	 */
       
   288 	browsePopup : function(el) {
       
   289 		var $el = $( el );
       
   290 		var $collection = $( el ).parent( '.imgedit-popup-menu' ).find( 'button' );
       
   291 		var $index = $collection.index( $el );
       
   292 		var $prev = $index - 1;
       
   293 		var $next = $index + 1;
       
   294 		var $last = $collection.length;
       
   295 		if ( $prev < 0 ) {
       
   296 			$prev = $last - 1;
       
   297 		}
       
   298 		if ( $next === $last ) {
       
   299 			$next = 0;
       
   300 		}
       
   301 		var $target = false;
       
   302 		if ( event.keyCode === 40 ) {
       
   303 			$target = $collection.get( $next );
       
   304 		} else if ( event.keyCode === 38 ) {
       
   305 			$target = $collection.get( $prev );
       
   306 		}
       
   307 		if ( $target ) {
       
   308 			$target.focus();
       
   309 			event.preventDefault();
       
   310 		}
       
   311 
       
   312 		return false;
       
   313 	},
       
   314 
       
   315 	/**
       
   316 	 * Close popup menu and reset focus on feature activation.
       
   317 	 *
       
   318 	 * @since 6.3.0
       
   319 	 *
       
   320 	 * @memberof imageEdit
       
   321 	 *
       
   322 	 * @param {HTMLElement} el The current element.
       
   323 	 *
       
   324 	 * @return {boolean} Always returns false.
       
   325 	 */
       
   326 	closePopup : function(el) {
       
   327 		var $parent = $(el).parent( '.imgedit-popup-menu' );
       
   328 		var $controlledID = $parent.attr( 'id' );
       
   329 		var $target = $( 'button[aria-controls="' + $controlledID + '"]' );
       
   330 		$target
       
   331 			.attr( 'aria-expanded', 'false' ).trigger( 'focus' );
       
   332 		$parent
       
   333 			.toggleClass( 'imgedit-popup-menu-open' ).slideToggle( 'fast' );
       
   334 
       
   335 		return false;
       
   336 	},
       
   337 
       
   338 	/**
   173 	 * Shows or hides the image edit help box.
   339 	 * Shows or hides the image edit help box.
   174 	 *
   340 	 *
   175 	 * @since 2.9.0
   341 	 * @since 2.9.0
   176 	 *
   342 	 *
   177 	 * @memberof imageEdit
   343 	 * @memberof imageEdit
   188 
   354 
   189 		return false;
   355 		return false;
   190 	},
   356 	},
   191 
   357 
   192 	/**
   358 	/**
       
   359 	 * Shows or hides image edit input fields when enabled.
       
   360 	 *
       
   361 	 * @since 6.3.0
       
   362 	 *
       
   363 	 * @memberof imageEdit
       
   364 	 *
       
   365 	 * @param {HTMLElement} el The element to trigger the edit panel.
       
   366 	 *
       
   367 	 * @return {boolean} Always returns false.
       
   368 	 */
       
   369 	toggleControls : function(el) {
       
   370 		var $el = $( el );
       
   371 		var $target = $( '#' + $el.attr( 'aria-controls' ) );
       
   372 		$el
       
   373 			.attr( 'aria-expanded', 'false' === $el.attr( 'aria-expanded' ) ? 'true' : 'false' );
       
   374 		$target
       
   375 			.parent( '.imgedit-group' ).toggleClass( 'imgedit-panel-active' );
       
   376 
       
   377 		return false;
       
   378 	},
       
   379 
       
   380 	/**
   193 	 * Gets the value from the image edit target.
   381 	 * Gets the value from the image edit target.
   194 	 *
   382 	 *
   195 	 * The image edit target contains the image sizes where the (possible) changes
   383 	 * The image edit target contains the image sizes where the (possible) changes
   196 	 * have to be applied to.
   384 	 * have to be applied to.
   197 	 *
   385 	 *
   200 	 * @memberof imageEdit
   388 	 * @memberof imageEdit
   201 	 *
   389 	 *
   202 	 * @param {number} postid The post ID.
   390 	 * @param {number} postid The post ID.
   203 	 *
   391 	 *
   204 	 * @return {string} The value from the imagedit-save-target input field when available,
   392 	 * @return {string} The value from the imagedit-save-target input field when available,
   205 	 *                  or 'full' when not available.
   393 	 *                  'full' when not selected, or 'all' if it doesn't exist.
   206 	 */
   394 	 */
   207 	getTarget : function(postid) {
   395 	getTarget : function( postid ) {
   208 		return $('input[name="imgedit-target-' + postid + '"]:checked', '#imgedit-save-target-' + postid).val() || 'full';
   396 		var element = $( '#imgedit-save-target-' + postid );
       
   397 
       
   398 		if ( element.length ) {
       
   399 			return element.find( 'input[name="imgedit-target-' + postid + '"]:checked' ).val() || 'full';
       
   400 		}
       
   401 
       
   402 		return 'all';
   209 	},
   403 	},
   210 
   404 
   211 	/**
   405 	/**
   212 	 * Recalculates the height or width and keeps the original aspect ratio.
   406 	 * Recalculates the height or width and keeps the original aspect ratio.
   213 	 *
   407 	 *
   224 	 *
   418 	 *
   225 	 * @return {void}
   419 	 * @return {void}
   226 	 */
   420 	 */
   227 	scaleChanged : function( postid, x, el ) {
   421 	scaleChanged : function( postid, x, el ) {
   228 		var w = $('#imgedit-scale-width-' + postid), h = $('#imgedit-scale-height-' + postid),
   422 		var w = $('#imgedit-scale-width-' + postid), h = $('#imgedit-scale-height-' + postid),
   229 		warn = $('#imgedit-scale-warn-' + postid), w1 = '', h1 = '';
   423 		warn = $('#imgedit-scale-warn-' + postid), w1 = '', h1 = '',
       
   424 		scaleBtn = $('#imgedit-scale-button');
   230 
   425 
   231 		if ( false === this.validateNumeric( el ) ) {
   426 		if ( false === this.validateNumeric( el ) ) {
   232 			return;
   427 			return;
   233 		}
   428 		}
   234 
   429 
   240 			w.val( w1 );
   435 			w.val( w1 );
   241 		}
   436 		}
   242 
   437 
   243 		if ( ( h1 && h1 > this.hold.oh ) || ( w1 && w1 > this.hold.ow ) ) {
   438 		if ( ( h1 && h1 > this.hold.oh ) || ( w1 && w1 > this.hold.ow ) ) {
   244 			warn.css('visibility', 'visible');
   439 			warn.css('visibility', 'visible');
       
   440 			scaleBtn.prop('disabled', true);
   245 		} else {
   441 		} else {
   246 			warn.css('visibility', 'hidden');
   442 			warn.css('visibility', 'hidden');
       
   443 			scaleBtn.prop('disabled', false);
   247 		}
   444 		}
   248 	},
   445 	},
   249 
   446 
   250 	/**
   447 	/**
   251 	 * Gets the selected aspect ratio.
   448 	 * Gets the selected aspect ratio.
   400 				if ( (typeof callback !== 'undefined') && callback !== null ) {
   597 				if ( (typeof callback !== 'undefined') && callback !== null ) {
   401 					callback();
   598 					callback();
   402 				}
   599 				}
   403 
   600 
   404 				if ( $('#imgedit-history-' + postid).val() && $('#imgedit-undone-' + postid).val() === '0' ) {
   601 				if ( $('#imgedit-history-' + postid).val() && $('#imgedit-undone-' + postid).val() === '0' ) {
   405 					$('input.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', false);
   602 					$('button.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', false);
   406 				} else {
   603 				} else {
   407 					$('input.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', true);
   604 					$('button.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', true);
   408 				}
   605 				}
       
   606 				var successMessage = __( 'Image updated.' );
   409 
   607 
   410 				t.toggleEditor(postid, 0);
   608 				t.toggleEditor(postid, 0);
       
   609 				wp.a11y.speak( successMessage, 'assertive' );
   411 			})
   610 			})
   412 			.on( 'error', function() {
   611 			.on( 'error', function() {
   413 				var errorMessage = __( 'Could not load the preview image. Please reload the page and try again.' );
   612 				var errorMessage = __( 'Could not load the preview image. Please reload the page and try again.' );
   414 
   613 
   415 				$( '#imgedit-crop-' + postid )
   614 				$( '#imgedit-crop-' + postid )
   433 	 * @param {string} action The action to perform on the image.
   632 	 * @param {string} action The action to perform on the image.
   434 	 *                        The possible actions are: "scale" and "restore".
   633 	 *                        The possible actions are: "scale" and "restore".
   435 	 *
   634 	 *
   436 	 * @return {boolean|void} Executes a post request that refreshes the page
   635 	 * @return {boolean|void} Executes a post request that refreshes the page
   437 	 *                        when the action is performed.
   636 	 *                        when the action is performed.
   438 	 *                        Returns false if a invalid action is given,
   637 	 *                        Returns false if an invalid action is given,
   439 	 *                        or when the action cannot be performed.
   638 	 *                        or when the action cannot be performed.
   440 	 */
   639 	 */
   441 	action : function(postid, nonce, action) {
   640 	action : function(postid, nonce, action) {
   442 		var t = this, data, w, h, fw, fh;
   641 		var t = this, data, w, h, fw, fh;
   443 
   642 
   634 					}
   833 					}
   635 				} );
   834 				} );
   636 				btn.removeClass( 'button-activated' );
   835 				btn.removeClass( 'button-activated' );
   637 				spin.removeClass( 'is-active' );
   836 				spin.removeClass( 'is-active' );
   638 			} );
   837 			} );
   639 			// Initialise the Image Editor now that everything is ready.
   838 			// Initialize the Image Editor now that everything is ready.
   640 			imageEdit.init( postid );
   839 			imageEdit.init( postid );
   641 		} );
   840 		} );
   642 
   841 
   643 		return dfd;
   842 		return dfd;
   644 	},
   843 	},
   687 
   886 
   688 			if ( ! elementToSetFocusTo.length ) {
   887 			if ( ! elementToSetFocusTo.length ) {
   689 				elementToSetFocusTo = $( '.imgedit-wrap' ).find( ':tabbable:first' );
   888 				elementToSetFocusTo = $( '.imgedit-wrap' ).find( ':tabbable:first' );
   690 			}
   889 			}
   691 
   890 
   692 			elementToSetFocusTo.trigger( 'focus' );
   891 			elementToSetFocusTo.attr( 'tabindex', '-1' ).trigger( 'focus' );
   693 		}, 100 );
   892 		}, 100 );
   694 	},
   893 	},
   695 
   894 
   696 	/**
   895 	/**
   697 	 * Initializes the cropping tool.
   896 	 * Initializes the cropping tool.
   708 	 */
   907 	 */
   709 	initCrop : function(postid, image, parent) {
   908 	initCrop : function(postid, image, parent) {
   710 		var t = this,
   909 		var t = this,
   711 			selW = $('#imgedit-sel-width-' + postid),
   910 			selW = $('#imgedit-sel-width-' + postid),
   712 			selH = $('#imgedit-sel-height-' + postid),
   911 			selH = $('#imgedit-sel-height-' + postid),
       
   912 			selX = $('#imgedit-start-x-' + postid),
       
   913 			selY = $('#imgedit-start-y-' + postid),
   713 			$image = $( image ),
   914 			$image = $( image ),
   714 			$img;
   915 			$img;
   715 
   916 
   716 		// Already initialized?
   917 		// Already initialized?
   717 		if ( $image.data( 'imgAreaSelect' ) ) {
   918 		if ( $image.data( 'imgAreaSelect' ) ) {
   766 			 *
   967 			 *
   767 			 * @return {void}
   968 			 * @return {void}
   768 			 */
   969 			 */
   769 			onSelectStart: function() {
   970 			onSelectStart: function() {
   770 				imageEdit.setDisabled($('#imgedit-crop-sel-' + postid), 1);
   971 				imageEdit.setDisabled($('#imgedit-crop-sel-' + postid), 1);
       
   972 				imageEdit.setDisabled($('.imgedit-crop-clear'), 1);
       
   973 				imageEdit.setDisabled($('.imgedit-crop-apply'), 1);
   771 			},
   974 			},
   772 			/**
   975 			/**
   773 			 * Event triggered when the selection is ended.
   976 			 * Event triggered when the selection is ended.
   774 			 *
   977 			 *
   775 			 * @ignore
   978 			 * @ignore
   779 			 *
   982 			 *
   780 			 * @return {Object}
   983 			 * @return {Object}
   781 			 */
   984 			 */
   782 			onSelectEnd: function(img, c) {
   985 			onSelectEnd: function(img, c) {
   783 				imageEdit.setCropSelection(postid, c);
   986 				imageEdit.setCropSelection(postid, c);
       
   987 				if ( ! $('#imgedit-crop > *').is(':visible') ) {
       
   988 					imageEdit.toggleControls($('.imgedit-crop.button'));
       
   989 				}
   784 			},
   990 			},
   785 
   991 
   786 			/**
   992 			/**
   787 			 * Event triggered when the selection changes.
   993 			 * Event triggered when the selection changes.
   788 			 *
   994 			 *
   795 			 */
  1001 			 */
   796 			onSelectChange: function(img, c) {
  1002 			onSelectChange: function(img, c) {
   797 				var sizer = imageEdit.hold.sizer;
  1003 				var sizer = imageEdit.hold.sizer;
   798 				selW.val( imageEdit.round(c.width / sizer) );
  1004 				selW.val( imageEdit.round(c.width / sizer) );
   799 				selH.val( imageEdit.round(c.height / sizer) );
  1005 				selH.val( imageEdit.round(c.height / sizer) );
       
  1006 				selX.val( imageEdit.round(c.x1 / sizer) );
       
  1007 				selY.val( imageEdit.round(c.y1 / sizer) );
   800 			}
  1008 			}
   801 		});
  1009 		});
   802 	},
  1010 	},
   803 
  1011 
   804 	/**
  1012 	/**
   821 		if ( !c || ( c.width < 3 && c.height < 3 ) ) {
  1029 		if ( !c || ( c.width < 3 && c.height < 3 ) ) {
   822 			this.setDisabled( $( '.imgedit-crop', '#imgedit-panel-' + postid ), 1 );
  1030 			this.setDisabled( $( '.imgedit-crop', '#imgedit-panel-' + postid ), 1 );
   823 			this.setDisabled( $( '#imgedit-crop-sel-' + postid ), 1 );
  1031 			this.setDisabled( $( '#imgedit-crop-sel-' + postid ), 1 );
   824 			$('#imgedit-sel-width-' + postid).val('');
  1032 			$('#imgedit-sel-width-' + postid).val('');
   825 			$('#imgedit-sel-height-' + postid).val('');
  1033 			$('#imgedit-sel-height-' + postid).val('');
       
  1034 			$('#imgedit-start-x-' + postid).val('0');
       
  1035 			$('#imgedit-start-y-' + postid).val('0');
   826 			$('#imgedit-selection-' + postid).val('');
  1036 			$('#imgedit-selection-' + postid).val('');
   827 			return false;
  1037 			return false;
   828 		}
  1038 		}
   829 
  1039 
   830 		sel = { 'x': c.x1, 'y': c.y1, 'w': c.width, 'h': c.height };
  1040 		sel = { 'x': c.x1, 'y': c.y1, 'w': c.width, 'h': c.height };
   951 	 */
  1161 	 */
   952 	rotate : function(angle, postid, nonce, t) {
  1162 	rotate : function(angle, postid, nonce, t) {
   953 		if ( $(t).hasClass('disabled') ) {
  1163 		if ( $(t).hasClass('disabled') ) {
   954 			return false;
  1164 			return false;
   955 		}
  1165 		}
   956 
  1166 		this.closePopup(t);
   957 		this.addStep({ 'r': { 'r': angle, 'fw': this.hold.h, 'fh': this.hold.w }}, postid, nonce);
  1167 		this.addStep({ 'r': { 'r': angle, 'fw': this.hold.h, 'fh': this.hold.w }}, postid, nonce);
   958 	},
  1168 	},
   959 
  1169 
   960 	/**
  1170 	/**
   961 	 * Flips the image.
  1171 	 * Flips the image.
   973 	 */
  1183 	 */
   974 	flip : function (axis, postid, nonce, t) {
  1184 	flip : function (axis, postid, nonce, t) {
   975 		if ( $(t).hasClass('disabled') ) {
  1185 		if ( $(t).hasClass('disabled') ) {
   976 			return false;
  1186 			return false;
   977 		}
  1187 		}
   978 
  1188 		this.closePopup(t);
   979 		this.addStep({ 'f': { 'f': axis, 'fw': this.hold.w, 'fh': this.hold.h }}, postid, nonce);
  1189 		this.addStep({ 'f': { 'f': axis, 'fw': this.hold.w, 'fh': this.hold.h }}, postid, nonce);
   980 	},
  1190 	},
   981 
  1191 
   982 	/**
  1192 	/**
   983 	 * Crops the image.
  1193 	 * Crops the image.
  1009 		}
  1219 		}
  1010 
  1220 
  1011 		// Clear the selection fields after cropping.
  1221 		// Clear the selection fields after cropping.
  1012 		$('#imgedit-sel-width-' + postid).val('');
  1222 		$('#imgedit-sel-width-' + postid).val('');
  1013 		$('#imgedit-sel-height-' + postid).val('');
  1223 		$('#imgedit-sel-height-' + postid).val('');
       
  1224 		$('#imgedit-start-x-' + postid).val('0');
       
  1225 		$('#imgedit-start-y-' + postid).val('0');
  1014 	},
  1226 	},
  1015 
  1227 
  1016 	/**
  1228 	/**
  1017 	 * Undoes an image edit action.
  1229 	 * Undoes an image edit action.
  1018 	 *
  1230 	 *
  1092 	 *                        void when the value is not numeric or when the operation
  1304 	 *                        void when the value is not numeric or when the operation
  1093 	 *                        is successful.
  1305 	 *                        is successful.
  1094 	 */
  1306 	 */
  1095 	setNumSelection : function( postid, el ) {
  1307 	setNumSelection : function( postid, el ) {
  1096 		var sel, elX = $('#imgedit-sel-width-' + postid), elY = $('#imgedit-sel-height-' + postid),
  1308 		var sel, elX = $('#imgedit-sel-width-' + postid), elY = $('#imgedit-sel-height-' + postid),
       
  1309 			elX1 = $('#imgedit-start-x-' + postid), elY1 = $('#imgedit-start-y-' + postid),
       
  1310 			xS = this.intval( elX1.val() ), yS = this.intval( elY1.val() ),
  1097 			x = this.intval( elX.val() ), y = this.intval( elY.val() ),
  1311 			x = this.intval( elX.val() ), y = this.intval( elY.val() ),
  1098 			img = $('#image-preview-' + postid), imgh = img.height(), imgw = img.width(),
  1312 			img = $('#image-preview-' + postid), imgh = img.height(), imgw = img.width(),
  1099 			sizer = this.hold.sizer, x1, y1, x2, y2, ias = this.iasapi;
  1313 			sizer = this.hold.sizer, x1, y1, x2, y2, ias = this.iasapi;
  1100 
  1314 
  1101 		if ( false === this.validateNumeric( el ) ) {
  1315 		if ( false === this.validateNumeric( el ) ) {
  1110 		if ( y < 1 ) {
  1324 		if ( y < 1 ) {
  1111 			elY.val('');
  1325 			elY.val('');
  1112 			return false;
  1326 			return false;
  1113 		}
  1327 		}
  1114 
  1328 
  1115 		if ( x && y && ( sel = ias.getSelection() ) ) {
  1329 		if ( ( ( x && y ) || ( xS && yS ) ) && ( sel = ias.getSelection() ) ) {
  1116 			x2 = sel.x1 + Math.round( x * sizer );
  1330 			x2 = sel.x1 + Math.round( x * sizer );
  1117 			y2 = sel.y1 + Math.round( y * sizer );
  1331 			y2 = sel.y1 + Math.round( y * sizer );
  1118 			x1 = sel.x1;
  1332 			x1 = ( xS === sel.x1 ) ? sel.x1 : Math.round( xS * sizer );
  1119 			y1 = sel.y1;
  1333 			y1 = ( yS === sel.y1 ) ? sel.y1 : Math.round( yS * sizer );
  1120 
  1334 
  1121 			if ( x2 > imgw ) {
  1335 			if ( x2 > imgw ) {
  1122 				x1 = 0;
  1336 				x1 = 0;
  1123 				x2 = imgw;
  1337 				x2 = imgw;
  1124 				elX.val( Math.round( x2 / sizer ) );
  1338 				elX.val( Math.round( x2 / sizer ) );
  1200 			if ( sel = this.iasapi.getSelection(true) ) {
  1414 			if ( sel = this.iasapi.getSelection(true) ) {
  1201 				r = Math.ceil( sel.y1 + ( ( sel.x2 - sel.x1 ) / ( x / y ) ) );
  1415 				r = Math.ceil( sel.y1 + ( ( sel.x2 - sel.x1 ) / ( x / y ) ) );
  1202 
  1416 
  1203 				if ( r > h ) {
  1417 				if ( r > h ) {
  1204 					r = h;
  1418 					r = h;
       
  1419 					var errorMessage = __( 'Selected crop ratio exceeds the boundaries of the image. Try a different ratio.' );
       
  1420 
       
  1421 					$( '#imgedit-crop-' + postid )
       
  1422 						.prepend( '<div class="notice notice-error" tabindex="-1" role="alert"><p>' + errorMessage + '</p></div>' );
       
  1423 
       
  1424 					wp.a11y.speak( errorMessage, 'assertive' );
  1205 					if ( n ) {
  1425 					if ( n ) {
  1206 						$('#imgedit-crop-height-' + postid).val('');
  1426 						$('#imgedit-crop-height-' + postid).val( '' );
  1207 					} else {
  1427 					} else {
  1208 						$('#imgedit-crop-width-' + postid).val('');
  1428 						$('#imgedit-crop-width-' + postid).val( '');
       
  1429 					}
       
  1430 				} else {
       
  1431 					var error = $( '#imgedit-crop-' + postid ).find( '.notice-error' );
       
  1432 					if ( 'undefined' !== typeof( error ) ) {
       
  1433 						error.remove();
  1209 					}
  1434 					}
  1210 				}
  1435 				}
  1211 
  1436 
  1212 				this.iasapi.setSelection( sel.x1, sel.y1, sel.x2, r );
  1437 				this.iasapi.setSelection( sel.x1, sel.y1, sel.x2, r );
  1213 				this.iasapi.update();
  1438 				this.iasapi.update();
  1226 	 *
  1451 	 *
  1227 	 * @return {void|boolean} Returns false if the value is not numeric,
  1452 	 * @return {void|boolean} Returns false if the value is not numeric,
  1228 	 *                        void when it is.
  1453 	 *                        void when it is.
  1229 	 */
  1454 	 */
  1230 	validateNumeric: function( el ) {
  1455 	validateNumeric: function( el ) {
  1231 		if ( ! this.intval( $( el ).val() ) ) {
  1456 		if ( false === this.intval( $( el ).val() ) ) {
  1232 			$( el ).val( '' );
  1457 			$( el ).val( '' );
  1233 			return false;
  1458 			return false;
  1234 		}
  1459 		}
  1235 	}
  1460 	}
  1236 };
  1461 };