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 + ' × ' + ret.fh ); |
549 $( '#media-dims-' + postid ).html( response.data.fw + ' × ' + 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) ); |
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 ), |
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(), |
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; |