Advanced Custom Fields: Image Crop Add-on - Version 1.3

Version Description

  • Updated to be compatible with original image field changes as of ACF Pro 5.0.8. IMPORTANT: As this is a quick fix to ensure compatability with the newest ACF PRO version it is not backwards compatible. If you are using ACF Pro 5.0.7 and below, please use version 1.2 of this add-on.
Download this release

Release Info

Developer andersthorborg
Plugin Icon wp plugin Advanced Custom Fields: Image Crop Add-on
Version 1.3
Comparing to
See all releases

Code changes from version 1.2 to 1.3

acf-image-crop-v5.php CHANGED
@@ -320,7 +320,7 @@ class acf_field_image_crop extends acf_field_image {
320
  'type' => 'hidden',
321
  'name' => $field['name'],
322
  'value' => htmlspecialchars($field['value']),
323
- 'data-name' => 'value-id',
324
  'data-original-image' => $imageData->original_image,
325
  'data-cropped-image' => json_encode($imageData->cropped_image),
326
  'class' => 'acf-image-value'
@@ -339,10 +339,10 @@ class acf_field_image_crop extends acf_field_image {
339
  </div>
340
  <div class="view show-if-value acf-soh">
341
  <ul class="acf-hl acf-soh-target">
342
- <li><a class="acf-icon dark" data-name="edit-button" href="#"><i class="acf-sprite-edit"></i></a></li>
343
- <li><a class="acf-icon dark" data-name="remove-button" href="#"><i class="acf-sprite-delete"></i></a></li>
344
  </ul>
345
- <img data-name="value-url" src="<?php echo $url; ?>" alt=""/>
346
  <div class="crop-section">
347
  <div class="crop-stage">
348
  <div class="crop-action">
@@ -363,7 +363,7 @@ class acf_field_image_crop extends acf_field_image {
363
  </div>
364
  </div>
365
  <div class="view hide-if-value">
366
- <p><?php _e('No image selected','acf'); ?> <a data-name="add-button" class="acf-button" href="#"><?php _e('Add Image','acf'); ?></a></p>
367
  </div>
368
  </div>
369
  <?php
@@ -469,6 +469,7 @@ class acf_field_image_crop extends acf_field_image {
469
  // wp_enqueue_style('acf-input-image_crop');
470
 
471
  // register acf scripts
 
472
  wp_register_script('acf-input-image_crop', "{$dir}js/input.js", array('acf-input', 'imgareaselect'));
473
 
474
  wp_register_style('acf-input-image_crop', "{$dir}css/input.css", array('acf-input'));
320
  'type' => 'hidden',
321
  'name' => $field['name'],
322
  'value' => htmlspecialchars($field['value']),
323
+ 'data-name' => 'id',
324
  'data-original-image' => $imageData->original_image,
325
  'data-cropped-image' => json_encode($imageData->cropped_image),
326
  'class' => 'acf-image-value'
339
  </div>
340
  <div class="view show-if-value acf-soh">
341
  <ul class="acf-hl acf-soh-target">
342
+ <li><a class="acf-icon dark" data-name="edit" href="#"><i class="acf-sprite-edit"></i></a></li>
343
+ <li><a class="acf-icon dark" data-name="remove" href="#"><i class="acf-sprite-delete"></i></a></li>
344
  </ul>
345
+ <img data-name="image" src="<?php echo $url; ?>" alt=""/>
346
  <div class="crop-section">
347
  <div class="crop-stage">
348
  <div class="crop-action">
363
  </div>
364
  </div>
365
  <div class="view hide-if-value">
366
+ <p><?php _e('No image selected','acf'); ?> <a data-name="add" class="acf-button" href="#"><?php _e('Add Image','acf'); ?></a></p>
367
  </div>
368
  </div>
369
  <?php
469
  // wp_enqueue_style('acf-input-image_crop');
470
 
471
  // register acf scripts
472
+ //wp_register_script('acf-input-image', "{$dir}../advanced-custom-fields-pro/js/input/image.js");
473
  wp_register_script('acf-input-image_crop', "{$dir}js/input.js", array('acf-input', 'imgareaselect'));
474
 
475
  wp_register_style('acf-input-image_crop', "{$dir}css/input.css", array('acf-input'));
acf-image-crop.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Advanced Custom Fields: Image Crop Add-on
4
  Plugin URI: https://github.com/andersthorborg/ACF-Image-Crop
5
  Description: An image field making it possible/required for the user to crop the selected image to the specified image size or dimensions
6
- Version: 1.2
7
  Author: Anders Thorborg
8
  Author URI: http://thorb.org
9
  License: GPLv2 or later
3
  Plugin Name: Advanced Custom Fields: Image Crop Add-on
4
  Plugin URI: https://github.com/andersthorborg/ACF-Image-Crop
5
  Description: An image field making it possible/required for the user to crop the selected image to the specified image size or dimensions
6
+ Version: 1.3
7
  Author: Anders Thorborg
8
  Author URI: http://thorb.org
9
  License: GPLv2 or later
banner-772/303/227250.png ADDED
Binary file
icon-256x256.png ADDED
Binary file
js/input-old.js ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+
3
+
4
+ function initialize_field( $el ) {
5
+ var $field = $el, $options = $el.find('.acf-image-uploader');
6
+ $field.find('.acf-image-value').on('change', function(){
7
+ var originalImage = $(this).val();
8
+ if($(this).val()){
9
+ $field.removeClass('invalid');
10
+ $field.find('.init-crop-button').removeAttr('disabled');
11
+ $field.find('.acf-image-value').data('original-image', originalImage);
12
+ $field.find('.acf-image-value').data('cropped-image', originalImage);
13
+ $field.find('.acf-image-value').data('cropped', false);
14
+ $.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) {
15
+ if($field.find('img.crop-image').length == 0){
16
+ $field.find('.crop-action').append($('<img class="crop-image" src="#"/>'));
17
+ }
18
+ $field.find('img.crop-image').attr('src', data['url']);
19
+ $field.find('img.crop-image').data('width', data['width']);
20
+ $field.find('img.crop-image').data('height', data['height']);
21
+ var warnings = [];
22
+ var valid = true;
23
+ if($options.data('width') && data['width'] < $options.data('width')){
24
+ warnings.push('Width should be at least: ' + $options.data('width') + 'px (Selected image width: ' + data['width'] + 'px)');
25
+ valid = false;
26
+ }
27
+ if($options.data('height') && data['height'] < $options.data('height')){
28
+ warnings.push('Height should be at least: ' + $options.data('height') + 'px (Selected image height: ' + data['height'] + 'px)');
29
+ valid = false;
30
+ }
31
+ if(!valid){
32
+ $field.addClass('invalid');
33
+ $field.find('.init-crop-button').attr('disabled', 'disabled');
34
+ alert('Warning: The selected image is smaller than the required size:\n' + warnings.join('\n'));
35
+ }
36
+ else{
37
+ if($options.data('force_crop')){
38
+ initCrop($field);
39
+ }
40
+ }
41
+
42
+ }, 'json');
43
+ updateFieldValue($field);
44
+ }
45
+ else{
46
+ //Do nothing
47
+ }
48
+
49
+ });
50
+ $field.find('.init-crop-button').click(function(e){
51
+ e.preventDefault();
52
+ initCrop($field);
53
+ });
54
+ $field.find('.perform-crop-button').click(function(e){
55
+ e.preventDefault();
56
+ performCrop($field);
57
+ });
58
+ $field.find('.cancel-crop-button').click(function(e){
59
+ e.preventDefault();
60
+ cancelCrop($field);
61
+ });
62
+ $field.find('[data-name=edit]').click(function(e){
63
+ e.preventDefault();
64
+ e.stopPropagation();
65
+ var id = $field.find('.acf-image-value').data('cropped-image');
66
+ if(!$.isNumeric(id)){
67
+ id = $field.find('.acf-image-value').data('original-image');;
68
+ }
69
+ acf.media.popup({
70
+ mode : 'edit',
71
+ title : acf._e('image', 'edit'),
72
+ button : acf._e('image', 'update'),
73
+ id : id
74
+ });
75
+ });
76
+
77
+ }
78
+
79
+ function initCrop($field){
80
+ var $options = $field.find('.acf-image-uploader');
81
+ var options = {
82
+ handles: true,
83
+ onSelectEnd: function (img, selection) {
84
+ updateThumbnail($field, img, selection);
85
+ updateCropData($field, img, selection);
86
+ },
87
+ imageWidth:$options.find('.crop-stage img.crop-image').data('width'),
88
+ imageHeight:$options.find('.crop-stage img.crop-image').data('height'),
89
+ x1: 0,
90
+ y1: 0
91
+ };
92
+ if($options.data('crop_type') == 'hard'){
93
+ options.aspectRatio = $options.data('width') + ':' + $options.data('height');
94
+ options.minWidth = $options.data('width');
95
+ options.minHeight = $options.data('height');
96
+ options.x2 = $options.data('width');
97
+ options.y2 = $options.data('height');
98
+ }
99
+ else if($options.data('crop_type') == 'min'){
100
+ if($options.data('width')){
101
+ options.minWidth = $options.data('width');
102
+ options.x2 = $options.data('width');
103
+ }
104
+ else{
105
+ options.x2 = options.imageWidth;
106
+ }
107
+ if($options.data('height')){
108
+ options.minHeight = $options.data('height');
109
+ options.y2 = $options.data('height');
110
+ }
111
+ else{
112
+ options.y2 = options.imageHeight;
113
+ }
114
+ }
115
+ // Center crop - disabled needs more testing
116
+ // options.x1 = options.imageWidth/2 - (options.minWidth/2);
117
+ // options.y1 = options.imageHeight/2 - (options.minHeight/2)
118
+ // options.x2 = options.minWidth + options.x1;
119
+ // options.y2 = options.minHeight + options.y1;
120
+ //options.y1 = (options.imageHeight - options.minHeight) / 2;
121
+ if(!$field.hasClass('invalid')){
122
+ toggleCropView($field);
123
+ $field.find('.crop-stage img.crop-image').imgAreaSelect(options);
124
+ updateCropData($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
125
+ updateThumbnail($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
126
+ }
127
+ }
128
+
129
+ function updateCropData($field, img, selection){
130
+ var $options = $field.find('.acf-image-uploader');
131
+ $options.data('x1', selection.x1);
132
+ $options.data('x2', selection.x2);
133
+ $options.data('y1', selection.y1);
134
+ $options.data('y2', selection.y2);
135
+ }
136
+
137
+ function updateThumbnail($field, img, selection){
138
+ var $options = $field.find('.acf-image-uploader');
139
+ var div = $field.find('.crop-preview .preview');
140
+ var targetWidth = $field.find('.crop-preview .preview').width();
141
+ var factor = targetWidth / (selection.x2 - selection.x1);
142
+ //image
143
+ div.css('background-image', 'url(' + img.src + ')');
144
+ //width
145
+ div.css('width', (selection.x2 - selection.x1) * factor);
146
+ //height
147
+ div.css('height', (selection.y2 - selection.y1) * factor);
148
+ //x offset
149
+ div.css('background-position-x', 0-(selection.x1 * factor));
150
+ //y offset
151
+ div.css('background-position-y', 0-(selection.y1 * factor));
152
+ div.css('background-size', $options.find('.crop-stage img.crop-image').data('width') * factor + 'px' + ' ' + $options.find('.crop-stage img.crop-image').data('height') * factor + 'px');
153
+ }
154
+
155
+ function generateCropJSON(originalImage, croppedImage){
156
+ var obj = {
157
+ original_image: originalImage,
158
+ cropped_image: croppedImage
159
+ }
160
+ return JSON.stringify(obj);
161
+ }
162
+
163
+ function performCrop($field){
164
+ if(!$field.find('.crop-stage').hasClass('loading')){
165
+ $field.find('.crop-stage').addClass('loading');
166
+ var $options = $field.find('.acf-image-uploader');
167
+ var targetWidth = $options.data('width');
168
+ var targetHeight = $options.data('height');
169
+ var saveToMediaLibrary = $options.data('save_to_media_library');
170
+ if($options.data('crop_type') == 'min'){
171
+ targetWidth = $options.data('x2') - $options.data('x1');
172
+ targetHeight = $options.data('y2') - $options.data('y1');
173
+ }
174
+ var data = {
175
+ action: 'acf_image_crop_perform_crop',
176
+ id: $field.find('.acf-image-value').data('original-image'),
177
+ x1: $options.data('x1'),
178
+ x2: $options.data('x2'),
179
+ y1: $options.data('y1'),
180
+ y2: $options.data('y2'),
181
+ target_width: targetWidth,
182
+ target_height: targetHeight,
183
+ preview_size: $options.data('preview_size'),
184
+ save_to_media_library: saveToMediaLibrary
185
+ }
186
+ $.post(ajaxurl, data, function(data, textStatus, xhr) {
187
+ $field.find('[data-name=image]').attr('src', data.preview_url);
188
+ $field.find('.acf-image-value').data('cropped-image', data.value);
189
+ $field.find('.acf-image-value').data('cropped', true);
190
+ updateFieldValue($field);
191
+ $field.find('.crop-stage').removeClass('loading');
192
+ cancelCrop($field);
193
+ }, 'json');
194
+ }
195
+ }
196
+
197
+ function cancelCrop($field){
198
+ toggleCropView($field);
199
+ $field.find('.crop-stage img.crop-image').imgAreaSelect({remove:true});
200
+ }
201
+
202
+ function toggleCropView($field){
203
+ if($field.hasClass('cropping')){
204
+ $('#acf-image-crop-overlay').remove();
205
+ }
206
+ else{
207
+ $('body').append($('<div id="acf-image-crop-overlay"></div>'));
208
+ }
209
+ $field.toggleClass('cropping');
210
+
211
+ }
212
+
213
+ function updateFieldValue($field){
214
+ var $input = $field.find('.acf-image-value');
215
+ $input.val(generateCropJSON($input.data('original-image'), $input.data('cropped-image')));
216
+ }
217
+
218
+ function getFullImageUrl(id, callback){
219
+ $.post(ajaxurl, {images: []}, function(data, textStatus, xhr) {
220
+ }, 'json');
221
+ }
222
+
223
+
224
+ if( typeof acf.add_action !== 'undefined' ) {
225
+
226
+ /*
227
+ * ready append (ACF5)
228
+ *
229
+ * These are 2 events which are fired during the page load
230
+ * ready = on page load similar to $(document).ready()
231
+ * append = on new DOM elements appended via repeater field
232
+ *
233
+ * @type event
234
+ * @date 20/07/13
235
+ *
236
+ * @param $el (jQuery selection) the jQuery element which contains the ACF fields
237
+ * @return n/a
238
+ */
239
+
240
+ acf.add_action('ready append', function( $el ){
241
+
242
+ // search $el for fields of type 'image_crop'
243
+ acf.get_fields({ type : 'image_crop'}, $el).each(function(){
244
+
245
+ initialize_field( $(this) );
246
+
247
+ });
248
+
249
+ });
250
+
251
+
252
+ } else {
253
+
254
+
255
+ /*
256
+ * acf/setup_fields (ACF4)
257
+ *
258
+ * This event is triggered when ACF adds any new elements to the DOM.
259
+ *
260
+ * @type function
261
+ * @since 1.0.0
262
+ * @date 01/01/12
263
+ *
264
+ * @param event e: an event object. This can be ignored
265
+ * @param Element postbox: An element which contains the new HTML
266
+ *
267
+ * @return n/a
268
+ */
269
+
270
+ $(document).live('acf/setup_fields', function(e, postbox){
271
+
272
+ $(postbox).find('.field[data-field_type="image_crop"]').each(function(){
273
+
274
+ initialize_field( $(this) );
275
+
276
+ });
277
+
278
+ });
279
+
280
+
281
+ }
282
+
283
+
284
+ })(jQuery);
js/input.js CHANGED
@@ -1,141 +1,324 @@
1
  (function($){
 
2
 
 
 
3
 
4
- function initialize_field( $el ) {
5
- var $field = $el, $options = $el.find('.acf-image-uploader');
6
- $field.find('.acf-image-value').on('change', function(){
7
- var originalImage = $(this).val();
8
- if($(this).val()){
9
- $field.removeClass('invalid');
10
- $field.find('.init-crop-button').removeAttr('disabled');
11
- $field.find('.acf-image-value').data('original-image', originalImage);
12
- $field.find('.acf-image-value').data('cropped-image', originalImage);
13
- $field.find('.acf-image-value').data('cropped', false);
14
- $.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) {
15
- if($field.find('img.crop-image').length == 0){
16
- $field.find('.crop-action').append($('<img class="crop-image" src="#"/>'));
17
- }
18
- $field.find('img.crop-image').attr('src', data['url']);
19
- $field.find('img.crop-image').data('width', data['width']);
20
- $field.find('img.crop-image').data('height', data['height']);
21
- var warnings = [];
22
- var valid = true;
23
- if($options.data('width') && data['width'] < $options.data('width')){
24
- warnings.push('Width should be at least: ' + $options.data('width') + 'px (Selected image width: ' + data['width'] + 'px)');
25
- valid = false;
26
- }
27
- if($options.data('height') && data['height'] < $options.data('height')){
28
- warnings.push('Height should be at least: ' + $options.data('height') + 'px (Selected image height: ' + data['height'] + 'px)');
29
- valid = false;
30
- }
31
- if(!valid){
32
- $field.addClass('invalid');
33
- $field.find('.init-crop-button').attr('disabled', 'disabled');
34
- alert('Warning: The selected image is smaller than the required size:\n' + warnings.join('\n'));
35
- }
36
- else{
37
- if($options.data('force_crop')){
38
- initCrop($field);
39
- }
40
- }
41
-
42
- }, 'json');
43
- updateFieldValue($field);
44
- }
45
- else{
46
- //Do nothing
47
- }
48
-
49
- });
50
- $field.find('.init-crop-button').click(function(e){
51
- e.preventDefault();
52
- initCrop($field);
53
- });
54
- $field.find('.perform-crop-button').click(function(e){
55
- e.preventDefault();
56
- performCrop($field);
57
- });
58
- $field.find('.cancel-crop-button').click(function(e){
59
- e.preventDefault();
60
- cancelCrop($field);
61
- });
62
- $field.find('[data-name=edit-button]').click(function(e){
63
- e.preventDefault();
64
- e.stopPropagation();
65
- var id = $field.find('.acf-image-value').data('cropped-image');
66
- if(!$.isNumeric(id)){
67
- id = $field.find('.acf-image-value').data('original-image');;
68
- }
69
- acf.media.edit_popup({
70
- title : acf._e('image', 'edit'),
71
- button : acf._e('image', 'update'),
72
- id : id
73
- });
74
- });
75
-
76
- }
77
-
78
- function initCrop($field){
79
- var $options = $field.find('.acf-image-uploader');
80
- var options = {
81
- handles: true,
82
- onSelectEnd: function (img, selection) {
83
- updateThumbnail($field, img, selection);
84
- updateCropData($field, img, selection);
85
- },
86
- imageWidth:$options.find('.crop-stage img.crop-image').data('width'),
87
- imageHeight:$options.find('.crop-stage img.crop-image').data('height'),
88
- x1: 0,
89
- y1: 0
90
- };
91
- if($options.data('crop_type') == 'hard'){
92
- options.aspectRatio = $options.data('width') + ':' + $options.data('height');
93
- options.minWidth = $options.data('width');
94
- options.minHeight = $options.data('height');
95
- options.x2 = $options.data('width');
96
- options.y2 = $options.data('height');
97
- }
98
- else if($options.data('crop_type') == 'min'){
99
- if($options.data('width')){
100
- options.minWidth = $options.data('width');
101
- options.x2 = $options.data('width');
102
- }
103
- else{
104
- options.x2 = options.imageWidth;
105
- }
106
- if($options.data('height')){
107
- options.minHeight = $options.data('height');
108
- options.y2 = $options.data('height');
109
- }
110
- else{
111
- options.y2 = options.imageHeight;
112
- }
113
- }
114
- // Center crop - disabled needs more testing
115
- // options.x1 = options.imageWidth/2 - (options.minWidth/2);
116
- // options.y1 = options.imageHeight/2 - (options.minHeight/2)
117
- // options.x2 = options.minWidth + options.x1;
118
- // options.y2 = options.minHeight + options.y1;
119
- //options.y1 = (options.imageHeight - options.minHeight) / 2;
120
- if(!$field.hasClass('invalid')){
121
- toggleCropView($field);
122
- $field.find('.crop-stage img.crop-image').imgAreaSelect(options);
123
- updateCropData($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
124
- updateThumbnail($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
125
- }
126
- }
127
-
128
- function updateCropData($field, img, selection){
129
- var $options = $field.find('.acf-image-uploader');
130
- $options.data('x1', selection.x1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  $options.data('x2', selection.x2);
132
  $options.data('y1', selection.y1);
133
  $options.data('y2', selection.y2);
134
- }
135
 
136
- function updateThumbnail($field, img, selection){
137
- var $options = $field.find('.acf-image-uploader');
138
- var div = $field.find('.crop-preview .preview');
139
  var targetWidth = $field.find('.crop-preview .preview').width();
140
  var factor = targetWidth / (selection.x2 - selection.x1);
141
  //image
@@ -149,135 +332,135 @@
149
  //y offset
150
  div.css('background-position-y', 0-(selection.y1 * factor));
151
  div.css('background-size', $options.find('.crop-stage img.crop-image').data('width') * factor + 'px' + ' ' + $options.find('.crop-stage img.crop-image').data('height') * factor + 'px');
152
- }
153
-
154
- function generateCropJSON(originalImage, croppedImage){
155
- var obj = {
156
- original_image: originalImage,
157
- cropped_image: croppedImage
158
- }
159
- return JSON.stringify(obj);
160
- }
161
-
162
- function performCrop($field){
163
- if(!$field.find('.crop-stage').hasClass('loading')){
164
- $field.find('.crop-stage').addClass('loading');
165
- var $options = $field.find('.acf-image-uploader');
166
- var targetWidth = $options.data('width');
167
- var targetHeight = $options.data('height');
168
- var saveToMediaLibrary = $options.data('save_to_media_library');
169
- if($options.data('crop_type') == 'min'){
170
- targetWidth = $options.data('x2') - $options.data('x1');
171
- targetHeight = $options.data('y2') - $options.data('y1');
172
- }
173
- var data = {
174
- action: 'acf_image_crop_perform_crop',
175
- id: $field.find('.acf-image-value').data('original-image'),
176
- x1: $options.data('x1'),
177
- x2: $options.data('x2'),
178
- y1: $options.data('y1'),
179
- y2: $options.data('y2'),
180
- target_width: targetWidth,
181
- target_height: targetHeight,
182
- preview_size: $options.data('preview_size'),
183
- save_to_media_library: saveToMediaLibrary
184
- }
185
- $.post(ajaxurl, data, function(data, textStatus, xhr) {
186
- $field.find('[data-name=value-url]').attr('src', data.preview_url);
187
- $field.find('.acf-image-value').data('cropped-image', data.value);
188
- $field.find('.acf-image-value').data('cropped', true);
189
- updateFieldValue($field);
190
- $field.find('.crop-stage').removeClass('loading');
191
- cancelCrop($field);
192
- }, 'json');
193
- }
194
- }
195
-
196
- function cancelCrop($field){
197
- toggleCropView($field);
198
- $field.find('.crop-stage img.crop-image').imgAreaSelect({remove:true});
199
- }
200
-
201
- function toggleCropView($field){
202
- if($field.hasClass('cropping')){
203
- $('#acf-image-crop-overlay').remove();
204
- }
205
- else{
206
- $('body').append($('<div id="acf-image-crop-overlay"></div>'));
207
- }
208
- $field.toggleClass('cropping');
209
-
210
- }
211
-
212
- function updateFieldValue($field){
213
- var $input = $field.find('.acf-image-value');
214
- $input.val(generateCropJSON($input.data('original-image'), $input.data('cropped-image')));
215
- }
216
-
217
- function getFullImageUrl(id, callback){
218
- $.post(ajaxurl, {images: []}, function(data, textStatus, xhr) {
219
- }, 'json');
220
- }
221
-
222
-
223
- if( typeof acf.add_action !== 'undefined' ) {
224
-
225
- /*
226
- * ready append (ACF5)
227
- *
228
- * These are 2 events which are fired during the page load
229
- * ready = on page load similar to $(document).ready()
230
- * append = on new DOM elements appended via repeater field
231
- *
232
- * @type event
233
- * @date 20/07/13
234
- *
235
- * @param $el (jQuery selection) the jQuery element which contains the ACF fields
236
- * @return n/a
237
- */
238
-
239
- acf.add_action('ready append', function( $el ){
240
-
241
- // search $el for fields of type 'image_crop'
242
- acf.get_fields({ type : 'image_crop'}, $el).each(function(){
243
-
244
- initialize_field( $(this) );
245
-
246
- });
247
-
248
- });
249
-
250
-
251
- } else {
252
-
253
-
254
- /*
255
- * acf/setup_fields (ACF4)
256
- *
257
- * This event is triggered when ACF adds any new elements to the DOM.
258
- *
259
- * @type function
260
- * @since 1.0.0
261
- * @date 01/01/12
262
- *
263
- * @param event e: an event object. This can be ignored
264
- * @param Element postbox: An element which contains the new HTML
265
- *
266
- * @return n/a
267
- */
268
-
269
- $(document).live('acf/setup_fields', function(e, postbox){
270
-
271
- $(postbox).find('.field[data-field_type="image_crop"]').each(function(){
272
-
273
- initialize_field( $(this) );
274
-
275
- });
276
-
277
- });
278
-
279
-
280
- }
281
 
282
 
283
  })(jQuery);
1
  (function($){
2
+ acf.fields.image_crop = acf.field.extend({
3
 
4
+ type: 'image_crop',
5
+ $el: null,
6
 
7
+ events: {
8
+ 'click [data-name="add"]': 'add',
9
+ 'click [data-name="edit"]': 'edit',
10
+ 'click [data-name="remove"]': 'remove',
11
+ },
12
+
13
+ focus: function(){
14
+
15
+ this.$el = this.$field.find('.acf-image-uploader');
16
+
17
+ this.settings = acf.get_data( this.$el );
18
+
19
+ },
20
+
21
+ add: function() {
22
+
23
+ // reference
24
+ var self = this;
25
+
26
+
27
+ // vars
28
+ var field_key = acf.get_data( this.$field, 'key' );
29
+
30
+
31
+ // get repeater
32
+ var $repeater = acf.get_closest_field( this.$field, {type:'repeater'} );
33
+
34
+
35
+ // popup
36
+ var frame = acf.media.popup({
37
+ 'title' : acf._e('image', 'select'),
38
+ 'mode' : 'select',
39
+ 'type' : 'image',
40
+ 'multiple' : $repeater.exists(),
41
+ 'library' : this.settings.library,
42
+ 'select' : function( attachment, i ) {
43
+
44
+ // select / add another image field?
45
+ if( i > 0 ) {
46
+
47
+ // vars
48
+ var $tr = self.$field.parent(),
49
+ $next = false;
50
+
51
+
52
+ // find next image field
53
+ $tr.nextAll('.acf-row').not('.clone').each(function(){
54
+
55
+ // get next $field
56
+ $next = acf.get_field( field_key, $(this) );
57
+
58
+
59
+ // bail early if $next was not found
60
+ if( !$next ) {
61
+
62
+ return;
63
+
64
+ }
65
+
66
+
67
+ // bail early if next file uploader has value
68
+ if( $next.find('.acf-image-uploader.has-value').exists() ) {
69
+
70
+ $next = false;
71
+ return;
72
+
73
+ }
74
+
75
+
76
+ // end loop if $next is found
77
+ return false;
78
+
79
+ });
80
+
81
+
82
+ // add extra row if next is not found
83
+ if( !$next ) {
84
+
85
+ $tr = acf.fields.repeater.doFocus( $repeater ).add();
86
+
87
+
88
+ // bail early if no $tr (maximum rows hit)
89
+ if( !$tr ) {
90
+
91
+ return false;
92
+
93
+ }
94
+
95
+
96
+ // get next $field
97
+ $next = acf.get_field( field_key, $tr );
98
+
99
+ }
100
+
101
+
102
+ // update $el
103
+ self.doFocus( $next );
104
+
105
+ }
106
+
107
+
108
+ // add file to field
109
+ self.render( attachment );
110
+
111
+ }
112
+ });
113
+
114
+
115
+ },
116
+
117
+ render: function( attachment ){
118
+
119
+ // override url
120
+ if( acf.isset(attachment, 'attributes', 'sizes', this.settings.preview_size, 'url') ) {
121
+
122
+ attachment.url = attachment.attributes.sizes[ this.settings.preview_size ].url;
123
+
124
+ }
125
+
126
+
127
+ // set atts
128
+ this.$el.find('[data-name="image"]').attr( 'src', attachment.url );
129
+ this.$el.find('[data-name="id"]').val( attachment.id ).trigger('change');
130
+
131
+
132
+ // set div class
133
+ this.$el.addClass('has-value');
134
+
135
+ },
136
+
137
+ edit: function() {
138
+
139
+ // reference
140
+ var self = this;
141
+
142
+
143
+ // vars
144
+ var id = this.$el.find('[data-name="id"]').val();
145
+
146
+
147
+ // popup
148
+ var frame = acf.media.popup({
149
+
150
+ title: acf._e('image', 'edit'),
151
+ button: acf._e('image', 'update'),
152
+ mode: 'edit',
153
+ id: id,
154
+
155
+ select: function( attachment, i ) {
156
+
157
+ // add file to field
158
+ self.render( attachment );
159
+
160
+ }
161
+
162
+ });
163
+
164
+ },
165
+
166
+ remove: function() {
167
+
168
+ // vars
169
+ var attachment = {
170
+ id: '',
171
+ url: ''
172
+ };
173
+
174
+
175
+ // add file to field
176
+ this.render( attachment );
177
+
178
+
179
+ // remove class
180
+ this.$el.removeClass('has-value');
181
+
182
+ }
183
+
184
+ });
185
+
186
+ function initialize_field( $el ) {
187
+ var $field = $el, $options = $el.find('.acf-image-uploader');
188
+ $field.find('.acf-image-value').on('change', function(){
189
+ var originalImage = $(this).val();
190
+ if($(this).val()){
191
+ $field.removeClass('invalid');
192
+ $field.find('.init-crop-button').removeAttr('disabled');
193
+ $field.find('.acf-image-value').data('original-image', originalImage);
194
+ $field.find('.acf-image-value').data('cropped-image', originalImage);
195
+ $field.find('.acf-image-value').data('cropped', false);
196
+ $.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) {
197
+ if($field.find('img.crop-image').length == 0){
198
+ $field.find('.crop-action').append($('<img class="crop-image" src="#"/>'));
199
+ }
200
+ $field.find('img.crop-image').attr('src', data['url']);
201
+ $field.find('img.crop-image').data('width', data['width']);
202
+ $field.find('img.crop-image').data('height', data['height']);
203
+ var warnings = [];
204
+ var valid = true;
205
+ if($options.data('width') && data['width'] < $options.data('width')){
206
+ warnings.push('Width should be at least: ' + $options.data('width') + 'px (Selected image width: ' + data['width'] + 'px)');
207
+ valid = false;
208
+ }
209
+ if($options.data('height') && data['height'] < $options.data('height')){
210
+ warnings.push('Height should be at least: ' + $options.data('height') + 'px (Selected image height: ' + data['height'] + 'px)');
211
+ valid = false;
212
+ }
213
+ if(!valid){
214
+ $field.addClass('invalid');
215
+ $field.find('.init-crop-button').attr('disabled', 'disabled');
216
+ alert('Warning: The selected image is smaller than the required size:\n' + warnings.join('\n'));
217
+ }
218
+ else{
219
+ if($options.data('force_crop')){
220
+ initCrop($field);
221
+ }
222
+ }
223
+
224
+ }, 'json');
225
+ updateFieldValue($field);
226
+ }
227
+ else{
228
+ //Do nothing
229
+ }
230
+
231
+ });
232
+ $field.find('.init-crop-button').click(function(e){
233
+ e.preventDefault();
234
+ initCrop($field);
235
+ });
236
+ $field.find('.perform-crop-button').click(function(e){
237
+ e.preventDefault();
238
+ performCrop($field);
239
+ });
240
+ $field.find('.cancel-crop-button').click(function(e){
241
+ e.preventDefault();
242
+ cancelCrop($field);
243
+ });
244
+ $field.find('[data-name=edit]').click(function(e){
245
+ e.preventDefault();
246
+ e.stopPropagation();
247
+ var id = $field.find('.acf-image-value').data('cropped-image');
248
+ if(!$.isNumeric(id)){
249
+ id = $field.find('.acf-image-value').data('original-image');;
250
+ }
251
+ acf.media.popup({
252
+ mode : 'edit',
253
+ title : acf._e('image', 'edit'),
254
+ button : acf._e('image', 'update'),
255
+ id : id
256
+ });
257
+ });
258
+
259
+ }
260
+
261
+ function initCrop($field){
262
+ var $options = $field.find('.acf-image-uploader');
263
+ var options = {
264
+ handles: true,
265
+ onSelectEnd: function (img, selection) {
266
+ updateThumbnail($field, img, selection);
267
+ updateCropData($field, img, selection);
268
+ },
269
+ imageWidth:$options.find('.crop-stage img.crop-image').data('width'),
270
+ imageHeight:$options.find('.crop-stage img.crop-image').data('height'),
271
+ x1: 0,
272
+ y1: 0
273
+ };
274
+ if($options.data('crop_type') == 'hard'){
275
+ options.aspectRatio = $options.data('width') + ':' + $options.data('height');
276
+ options.minWidth = $options.data('width');
277
+ options.minHeight = $options.data('height');
278
+ options.x2 = $options.data('width');
279
+ options.y2 = $options.data('height');
280
+ }
281
+ else if($options.data('crop_type') == 'min'){
282
+ if($options.data('width')){
283
+ options.minWidth = $options.data('width');
284
+ options.x2 = $options.data('width');
285
+ }
286
+ else{
287
+ options.x2 = options.imageWidth;
288
+ }
289
+ if($options.data('height')){
290
+ options.minHeight = $options.data('height');
291
+ options.y2 = $options.data('height');
292
+ }
293
+ else{
294
+ options.y2 = options.imageHeight;
295
+ }
296
+ }
297
+ // Center crop - disabled needs more testing
298
+ // options.x1 = options.imageWidth/2 - (options.minWidth/2);
299
+ // options.y1 = options.imageHeight/2 - (options.minHeight/2)
300
+ // options.x2 = options.minWidth + options.x1;
301
+ // options.y2 = options.minHeight + options.y1;
302
+ //options.y1 = (options.imageHeight - options.minHeight) / 2;
303
+ if(!$field.hasClass('invalid')){
304
+ toggleCropView($field);
305
+ $field.find('.crop-stage img.crop-image').imgAreaSelect(options);
306
+ updateCropData($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
307
+ updateThumbnail($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
308
+ }
309
+ }
310
+
311
+ function updateCropData($field, img, selection){
312
+ var $options = $field.find('.acf-image-uploader');
313
+ $options.data('x1', selection.x1);
314
  $options.data('x2', selection.x2);
315
  $options.data('y1', selection.y1);
316
  $options.data('y2', selection.y2);
317
+ }
318
 
319
+ function updateThumbnail($field, img, selection){
320
+ var $options = $field.find('.acf-image-uploader');
321
+ var div = $field.find('.crop-preview .preview');
322
  var targetWidth = $field.find('.crop-preview .preview').width();
323
  var factor = targetWidth / (selection.x2 - selection.x1);
324
  //image
332
  //y offset
333
  div.css('background-position-y', 0-(selection.y1 * factor));
334
  div.css('background-size', $options.find('.crop-stage img.crop-image').data('width') * factor + 'px' + ' ' + $options.find('.crop-stage img.crop-image').data('height') * factor + 'px');
335
+ }
336
+
337
+ function generateCropJSON(originalImage, croppedImage){
338
+ var obj = {
339
+ original_image: originalImage,
340
+ cropped_image: croppedImage
341
+ }
342
+ return JSON.stringify(obj);
343
+ }
344
+
345
+ function performCrop($field){
346
+ if(!$field.find('.crop-stage').hasClass('loading')){
347
+ $field.find('.crop-stage').addClass('loading');
348
+ var $options = $field.find('.acf-image-uploader');
349
+ var targetWidth = $options.data('width');
350
+ var targetHeight = $options.data('height');
351
+ var saveToMediaLibrary = $options.data('save_to_media_library');
352
+ if($options.data('crop_type') == 'min'){
353
+ targetWidth = $options.data('x2') - $options.data('x1');
354
+ targetHeight = $options.data('y2') - $options.data('y1');
355
+ }
356
+ var data = {
357
+ action: 'acf_image_crop_perform_crop',
358
+ id: $field.find('.acf-image-value').data('original-image'),
359
+ x1: $options.data('x1'),
360
+ x2: $options.data('x2'),
361
+ y1: $options.data('y1'),
362
+ y2: $options.data('y2'),
363
+ target_width: targetWidth,
364
+ target_height: targetHeight,
365
+ preview_size: $options.data('preview_size'),
366
+ save_to_media_library: saveToMediaLibrary
367
+ }
368
+ $.post(ajaxurl, data, function(data, textStatus, xhr) {
369
+ $field.find('[data-name=image]').attr('src', data.preview_url);
370
+ $field.find('.acf-image-value').data('cropped-image', data.value);
371
+ $field.find('.acf-image-value').data('cropped', true);
372
+ updateFieldValue($field);
373
+ $field.find('.crop-stage').removeClass('loading');
374
+ cancelCrop($field);
375
+ }, 'json');
376
+ }
377
+ }
378
+
379
+ function cancelCrop($field){
380
+ toggleCropView($field);
381
+ $field.find('.crop-stage img.crop-image').imgAreaSelect({remove:true});
382
+ }
383
+
384
+ function toggleCropView($field){
385
+ if($field.hasClass('cropping')){
386
+ $('#acf-image-crop-overlay').remove();
387
+ }
388
+ else{
389
+ $('body').append($('<div id="acf-image-crop-overlay"></div>'));
390
+ }
391
+ $field.toggleClass('cropping');
392
+
393
+ }
394
+
395
+ function updateFieldValue($field){
396
+ var $input = $field.find('.acf-image-value');
397
+ $input.val(generateCropJSON($input.data('original-image'), $input.data('cropped-image')));
398
+ }
399
+
400
+ function getFullImageUrl(id, callback){
401
+ $.post(ajaxurl, {images: []}, function(data, textStatus, xhr) {
402
+ }, 'json');
403
+ }
404
+
405
+
406
+ if( typeof acf.add_action !== 'undefined' ) {
407
+
408
+ /*
409
+ * ready append (ACF5)
410
+ *
411
+ * These are 2 events which are fired during the page load
412
+ * ready = on page load similar to $(document).ready()
413
+ * append = on new DOM elements appended via repeater field
414
+ *
415
+ * @type event
416
+ * @date 20/07/13
417
+ *
418
+ * @param $el (jQuery selection) the jQuery element which contains the ACF fields
419
+ * @return n/a
420
+ */
421
+
422
+ acf.add_action('ready append', function( $el ){
423
+
424
+ // search $el for fields of type 'image_crop'
425
+ acf.get_fields({ type : 'image_crop'}, $el).each(function(){
426
+
427
+ initialize_field( $(this) );
428
+
429
+ });
430
+
431
+ });
432
+
433
+
434
+ } else {
435
+
436
+
437
+ /*
438
+ * acf/setup_fields (ACF4)
439
+ *
440
+ * This event is triggered when ACF adds any new elements to the DOM.
441
+ *
442
+ * @type function
443
+ * @since 1.0.0
444
+ * @date 01/01/12
445
+ *
446
+ * @param event e: an event object. This can be ignored
447
+ * @param Element postbox: An element which contains the new HTML
448
+ *
449
+ * @return n/a
450
+ */
451
+
452
+ $(document).live('acf/setup_fields', function(e, postbox){
453
+
454
+ $(postbox).find('.field[data-field_type="image_crop"]').each(function(){
455
+
456
+ initialize_field( $(this) );
457
+
458
+ });
459
+
460
+ });
461
+
462
+
463
+ }
464
 
465
 
466
  })(jQuery);
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: andersthorborg
3
  Tags: afc, advanced custom fields, image crop, image, crop
4
  Requires at least: 3.5
5
- Tested up to: 3.9.1
6
- Stable tag: 1.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -61,6 +61,9 @@ function my_register_fields()
61
 
62
  == Changelog ==
63
 
 
 
 
64
  = 1.2 =
65
  * Improved: Edit image is now working for most cropped image fields.
66
  * Fix: Wrong GUID for generated images that could cause issues when moving a site to a new location
2
  Contributors: andersthorborg
3
  Tags: afc, advanced custom fields, image crop, image, crop
4
  Requires at least: 3.5
5
+ Tested up to: 4.0
6
+ Stable tag: 1.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
61
 
62
  == Changelog ==
63
 
64
+ = 1.3 =
65
+ * Updated to be compatible with original image field changes as of ACF Pro 5.0.8. IMPORTANT: As this is a quick fix to ensure compatability with the newest ACF PRO version it is not backwards compatible. If you are using ACF Pro 5.0.7 and below, please use version 1.2 of this add-on.
66
+
67
  = 1.2 =
68
  * Improved: Edit image is now working for most cropped image fields.
69
  * Fix: Wrong GUID for generated images that could cause issues when moving a site to a new location