(function($){ acf.fields.image_crop = acf.field.extend({ type: 'image_crop', $el: null, actions: { 'ready': 'initialize', 'append': 'initialize' }, events: { 'click a[data-name="add"]': 'add', 'click a[data-name="edit"]': 'edit', 'click a[data-name="remove"]': 'remove', 'change input[type="file"]': 'change' }, focus: function(){ // get elements this.$el = this.$field.find('.acf-image-uploader'); // get options this.o = acf.get_data( this.$el ); }, initialize: function(){ // add attribute to form if( this.o.uploader == 'basic' ) { this.$el.closest('form').attr('enctype', 'multipart/form-data'); } }, add: function() { // reference var self = this, $field = this.$field; // get repeater var $repeater = acf.get_closest_field( this.$field, 'repeater' ); // popup var frame = acf.media.popup({ title: acf._e('image', 'select'), mode: 'select', type: 'image', field: acf.get_field_key($field), multiple: $repeater.exists(), library: this.o.library, mime_types: this.o.mime_types, select: function( attachment, i ) { // select / add another image field? if( i > 0 ) { // vars var key = acf.get_field_key( $field ), $tr = $field.closest('.acf-row'); // reset field $field = false; // find next image field $tr.nextAll('.acf-row:visible').each(function(){ // get next $field $field = acf.get_field( key, $(this) ); // bail early if $next was not found if( !$field ) { return; } // bail early if next file uploader has value if( $field.find('.acf-image-uploader.has-value').exists() ) { $field = false; return; } // end loop if $next is found return false; }); // add extra row if next is not found if( !$field ) { $tr = acf.fields.repeater.doFocus( $repeater ).add(); // bail early if no $tr (maximum rows hit) if( !$tr ) { return false; } // get next $field $field = acf.get_field( key, $tr ); } } // focus self.doFocus( $field ); // render self.render( self.prepare(attachment) ); } }); }, prepare: function( attachment ) { // vars var image = { id: attachment.id, url: attachment.attributes.url }; // check for preview size if( acf.isset(attachment.attributes, 'sizes', this.o.preview_size, 'url') ) { image.url = attachment.attributes.sizes[ this.o.preview_size ].url; } // return return image; }, render: function( image ){ // set atts this.$el.find('[data-name="image"]').attr( 'src', image.url ); this.$el.find('[data-name="id"]').val( image.id ).trigger('change'); // set div class this.$el.addClass('has-value'); }, edit: function() { // reference var self = this; // vars //var id = this.$el.find('[data-name="id"]').val(); var id = this.$el.find('.acf-image-value').data('cropped-image'); if(!$.isNumeric(id)){ id = this.$el.find('.acf-image-value').data('original-image');; } // popup var frame = acf.media.popup({ title: acf._e('image', 'edit'), type: 'image', button: acf._e('image', 'update'), mode: 'edit', id: id, select: function( attachment, i ) { self.render( self.prepare(attachment) ); } }); }, remove: function() { // vars var attachment = { id: '', url: '' }; // add file to field this.render( attachment ); // remove class this.$el.removeClass('has-value'); }, change: function( e ){ this.$el.find('[data-name="id"]').val( e.$el.val() ); } }); function initialize_field( $el ) { var $field = $el, $options = $el.find('.acf-image-uploader'); $field.find('.acf-image-value').on('change', function(){ var originalImage = $(this).val(); if($(this).val()){ $field.removeClass('invalid'); $field.find('.init-crop-button').removeAttr('disabled'); $field.find('.acf-image-value').data('original-image', originalImage); $field.find('.acf-image-value').data('cropped-image', originalImage); $field.find('.acf-image-value').data('cropped', false); $.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) { if($field.find('img.crop-image').length == 0){ $field.find('.crop-action').append($('')); } $field.find('img.crop-image').attr('src', data['url']); $field.find('img.crop-image').data('width', data['width']); $field.find('img.crop-image').data('height', data['height']); var warnings = []; var valid = true; if($options.data('width') && data['width'] < $options.data('width')){ // changed for translation warnings.push( acf._e('image_crop', 'width_should_be') + $options.data('width') + 'px\n' + acf._e('image_crop', 'selected_width') + data['width'] + 'px'); // changed END valid = false; } if($options.data('height') && data['height'] < $options.data('height')){ // changed for translation warnings.push(acf._e('image_crop', 'height_should_be') + $options.data('height') + 'px\n' + acf._e('image_crop', 'selected_height') + data['height'] + 'px'); // changed END valid = false; } if(!valid){ $field.addClass('invalid'); $field.find('.init-crop-button').attr('disabled', 'disabled'); // changed for translation alert(acf._e('image_crop', 'size_warning') + '\n\n' + warnings.join('\n\n')); // changed END } else{ if($options.data('force_crop')){ initCrop($field); } } }, 'json'); updateFieldValue($field); } else{ //Do nothing } }); $field.find('.init-crop-button').click(function(e){ e.preventDefault(); initCrop($field); }); $field.find('.perform-crop-button').click(function(e){ e.preventDefault(); performCrop($field); }); $field.find('.cancel-crop-button').click(function(e){ e.preventDefault(); cancelCrop($field); }); // $field.find('[data-name=edit]').click(function(e){ // e.preventDefault(); // e.stopPropagation(); // var id = $field.find('.acf-image-value').data('cropped-image'); // if(!$.isNumeric(id)){ // id = $field.find('.acf-image-value').data('original-image');; // } // acf.media.popup({ // mode : 'edit', // title : acf._e('image', 'edit'), // button : acf._e('image', 'update'), // id : id // }); // }); } function initCrop($field){ var $options = $field.find('.acf-image-uploader'); var options = { handles: true, onSelectEnd: function (img, selection) { updateThumbnail($field, img, selection); updateCropData($field, img, selection); }, imageWidth:$options.find('.crop-stage img.crop-image').data('width'), imageHeight:$options.find('.crop-stage img.crop-image').data('height'), x1: 0, y1: 0 }; if($options.data('crop_type') == 'hard'){ options.aspectRatio = $options.data('width') + ':' + $options.data('height'); options.minWidth = $options.data('width'); options.minHeight = $options.data('height'); options.x2 = $options.data('width'); options.y2 = $options.data('height'); } else if($options.data('crop_type') == 'min'){ if($options.data('width')){ options.minWidth = $options.data('width'); options.x2 = $options.data('width'); } else{ options.x2 = options.imageWidth; } if($options.data('height')){ options.minHeight = $options.data('height'); options.y2 = $options.data('height'); } else{ options.y2 = options.imageHeight; } } // Center crop - disabled needs more testing // options.x1 = options.imageWidth/2 - (options.minWidth/2); // options.y1 = options.imageHeight/2 - (options.minHeight/2) // options.x2 = options.minWidth + options.x1; // options.y2 = options.minHeight + options.y1; //options.y1 = (options.imageHeight - options.minHeight) / 2; if(!$field.hasClass('invalid')){ toggleCropView($field); $field.find('.crop-stage img.crop-image').imgAreaSelect(options); updateCropData($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2}); updateThumbnail($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2}); } } function updateCropData($field, img, selection){ var $options = $field.find('.acf-image-uploader'); $options.data('x1', selection.x1); $options.data('x2', selection.x2); $options.data('y1', selection.y1); $options.data('y2', selection.y2); } function updateThumbnail($field, img, selection){ var $options = $field.find('.acf-image-uploader'); var div = $field.find('.crop-preview .preview'); var targetWidth = $field.find('.crop-preview .preview').width(); var factor = targetWidth / (selection.x2 - selection.x1); //image div.css('background-image', 'url(' + img.src + ')'); //width div.css('width', (selection.x2 - selection.x1) * factor); //height div.css('height', (selection.y2 - selection.y1) * factor); // Set offset - Fix by @christdg pos_x = 0-(selection.x1 * factor); pos_y = 0-(selection.y1 * factor); div.css('background-position', pos_x + 'px ' + pos_y + 'px'); 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'); } function generateCropJSON(originalImage, croppedImage){ var obj = { original_image: originalImage, cropped_image: croppedImage } return JSON.stringify(obj); } function performCrop($field){ if(!$field.find('.crop-stage').hasClass('loading')){ $field.find('.crop-stage').addClass('loading'); var $options = $field.find('.acf-image-uploader'); var targetWidth = $options.data('width'); var targetHeight = $options.data('height'); var saveToMediaLibrary = $options.data('save_to_media_library'); if($options.data('crop_type') == 'min'){ targetWidth = $options.data('x2') - $options.data('x1'); targetHeight = $options.data('y2') - $options.data('y1'); } var data = { action: 'acf_image_crop_perform_crop', id: $field.find('.acf-image-value').data('original-image'), x1: $options.data('x1'), x2: $options.data('x2'), y1: $options.data('y1'), y2: $options.data('y2'), target_width: targetWidth, target_height: targetHeight, preview_size: $options.data('preview_size'), save_to_media_library: saveToMediaLibrary } $.post(ajaxurl, data, function(data, textStatus, xhr) { if(data.success){ $field.find('[data-name=image]').attr('src', data.preview_url); $field.find('.acf-image-value').data('cropped-image', data.value); $field.find('.acf-image-value').data('cropped', true); updateFieldValue($field); } else{ $field.append('

' + acf._e('image_crop', 'crop_error') + '

' + data.error_message); } $field.find('.crop-stage').removeClass('loading'); cancelCrop($field); }, 'json'); } } function cancelCrop($field){ toggleCropView($field); $field.find('.crop-stage img.crop-image').imgAreaSelect({remove:true}); } function toggleCropView($field){ var $innerField = $field.find('.acf-image-crop'); if($innerField.hasClass('cropping')){ $('#acf-image-crop-overlay').remove(); } else{ $('body').append($('
')); } $innerField.toggleClass('cropping'); } function updateFieldValue($field){ var $input = $field.find('.acf-image-value'); $input.val(generateCropJSON($input.data('original-image'), $input.data('cropped-image'))); } function getFullImageUrl(id, callback){ $.post(ajaxurl, {images: []}, function(data, textStatus, xhr) { }, 'json'); } if( typeof acf.add_action !== 'undefined' ) { /* * ready append (ACF5) * * These are 2 events which are fired during the page load * ready = on page load similar to $(document).ready() * append = on new DOM elements appended via repeater field * * @type event * @date 20/07/13 * * @param $el (jQuery selection) the jQuery element which contains the ACF fields * @return n/a */ acf.add_action('ready append', function( $el ){ // search $el for fields of type 'image_crop' acf.get_fields({ type : 'image_crop'}, $el).each(function(){ initialize_field( $(this) ); }); }); } else { /* * acf/setup_fields (ACF4) * * This event is triggered when ACF adds any new elements to the DOM. * * @type function * @since 1.0.0 * @date 01/01/12 * * @param event e: an event object. This can be ignored * @param Element postbox: An element which contains the new HTML * * @return n/a */ $(document).live('acf/setup_fields', function(e, postbox){ $(postbox).find('.field[data-field_type="image_crop"]').each(function(){ initialize_field( $(this) ); }); }); } })(jQuery);