/*!
* Based on assets/js/acf-input.js from
* https://github.com/AdvancedCustomFields/acf by elliotcondon, licensed
* under GPLv2 or later
*/
import Cropper from 'cropperjs';
(function($) {
var field = null;
acf.fields.image_aspect_ratio_crop = acf.field.extend({
type: 'image_aspect_ratio_crop',
$el: null,
$input: null,
$img: 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',
'click a[data-name="crop"]': 'changeCrop',
},
/*
* focus
*
* This function will setup variables when focused on a field
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param n/a
* @return n/a
*/
focus: function() {
// vars
this.$el = this.$field.find('.acf-image-uploader-aspect-ratio-crop');
this.$input = this.$el.find('input[type="hidden"]');
this.$img = this.$el.find('img');
// options
this.o = acf.get_data(this.$el);
},
/*
* initialize
*
* This function is used to setup basic upload form attributes
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param n/a
* @return n/a
*/
initialize: function() {
this.isFirstCrop = null;
var self = this;
// add attribute to form
if (this.o.uploader == 'basic') {
this.$el.closest('form').attr('enctype', 'multipart/form-data');
}
$(document).on(
'click',
'.js-acf-image-aspect-ratio-crop-cancel',
function() {
if (self.isFirstCrop) {
// If it's the first time cropping an image, we don't want to
// leave the incorrect aspect ratio image in the field
acf.val(self.$input, '');
self.render({});
}
self.closeModal();
},
);
$(document)
.off('click', '.js-acf-image-aspect-ratio-crop-crop')
.on('click', '.js-acf-image-aspect-ratio-crop-crop', function() {
var cropData = self.cropper.getData(true);
$('.js-acf-image-aspect-ratio-crop-modal').css(
'max-width',
self.cropper.containerData.width,
);
var data = {
action: 'acf_image_aspect_ratio_crop_crop',
data: JSON.stringify({
id: $(this).data('id'),
aspectRatioHeight: $(this).data('aspect-ratio-height'),
aspectRatioWidth: $(this).data('aspect-ratio-width'),
x: cropData.x,
y: cropData.y,
width: cropData.width,
height: cropData.height,
}),
};
$('.js-acf-image-aspect-ratio-crop-crop').prop('disabled', true);
// prettier-ignore
var loading = '
' +
'
' +
'' +
'' +
'' +
'' +
'
' +
'
' +
aiarc_translations.cropping_in_progress +
'
' +
'
';
// prettier-ignore
var error = '
' +
'
' +
'' +
'' +
'' +
'' +
'
' +
'
' +
aiarc_translations.cropping_failed +
'
' +
'
';
$('.js-acf-image-aspect-ratio-crop-modal-footer-status').empty();
$('.js-acf-image-aspect-ratio-crop-modal-footer-status').html(
loading,
);
self.cropper.disable();
$.post(ajaxurl, data)
.done(function(data) {
self.cropComplete(data);
$('.js-acf-image-aspect-ratio-crop-crop').prop('disabled', false);
$('.js-acf-image-aspect-ratio-crop-modal-footer-status').empty();
})
.fail(function() {
self.cropper.enable();
$('.js-acf-image-aspect-ratio-crop-crop').prop('disabled', false);
$('.js-acf-image-aspect-ratio-crop-modal-footer-status').empty();
$('.js-acf-image-aspect-ratio-crop-modal-footer-status').html(
error,
);
});
});
},
/*
* prepare
*
* This function will prepare an object of attachment data
* selecting a library image vs embed an image via url return different data
* this function will keep the 2 consistent
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param attachment (object)
* @return data (object)
*/
prepare: function(attachment) {
// defaults
attachment = attachment || {};
// bail ealry if already valid
if (attachment._valid) return attachment;
// vars
var data = {
url: '',
alt: '',
title: '',
caption: '',
description: '',
width: 0,
height: 0,
};
// wp image
if (attachment.id) {
// update data
data = attachment.attributes;
// maybe get preview size
data.url = acf.maybe_get(
data,
'sizes.' + this.o.preview_size + '.url',
data.url,
);
}
// valid
data._valid = true;
// return
return data;
},
/*
* render
*
* This function will render the UI
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param attachment (obj)
* @return n/a
*/
render: function(data) {
// prepare
data = this.prepare(data);
// update image
this.$img.attr({
src: data.url,
alt: data.alt,
title: data.title,
});
// vars
var val = '';
// WP attachment
if (data.id) {
val = data.id;
}
// update val
acf.val(this.$input, val);
// update class
if (val) {
this.$el.addClass('has-value');
} else {
this.$el.removeClass('has-value');
}
},
/*
* add
*
* event listener
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param e (event)
* @return n/a
*/
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: $field.data('key'),
multiple: false,
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 = $field.data('key'),
$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-aspect-ratio-crop.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);
}
}
self.isFirstCrop = true;
// Add original id attribe to the image so we can recrop it right away without saving the post
$field
.find('.acf-image-uploader-aspect-ratio-crop')
.data('original-image-id', attachment.id)
.attr('data-original-image-id', attachment.id);
self.openModal({ attachment: attachment, field: $field });
// render
self.set('$field', $field).render(attachment);
},
});
},
changeCrop: function() {
this.isFirstCrop = false;
var originalImageId = $(this.$field)
.find('.acf-image-uploader-aspect-ratio-crop')
.data('original-image-id');
var attachment = new wp.media.model.Attachment.get(originalImageId);
var self = this;
attachment.fetch({
success: function(response) {
self.openModal({ attachment: response, field: self.$field });
},
});
},
/*
* edit
*
* event listener
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param e (event)
* @return n/a
*/
edit: function() {
// reference
var self = this,
$field = this.$field;
// vars
var val = null;
if (
this.$input.parent().attr('data-original-image-id') &&
window.aiarc_settings.modal_type === 'original'
) {
val = this.$input.parent().attr('data-original-image-id');
} else {
val = this.$input.val();
}
// bail early if no val
if (!val) return;
// popup
var frame = acf.media.popup({
title: acf._e('image', 'edit'),
button: acf._e('image', 'update'),
mode: 'edit',
attachment: val,
});
},
/*
* remove
*
* event listener
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param e (event)
* @return n/a
*/
remove: function() {
// vars
var attachment = {};
// add file to field
this.render(attachment);
},
/*
* change
*
* This function will update the hidden input when selecting a basic file to add basic validation
*
* @type function
* @date 12/04/2016
* @since 5.3.8
*
* @param e (event)
* @return n/a
*/
change: function(e) {
acf.fields.file.get_file_info(e.$el, this.$input);
},
openModal: function(data) {
var url = data.attachment.attributes.url;
var id = data.attachment.attributes.id;
field = data.field;
var aspectRatioWidth = $(field)
.find('.acf-image-uploader-aspect-ratio-crop')
.data('aspect_ratio_width');
var aspectRatioHeight = $(field)
.find('.acf-image-uploader-aspect-ratio-crop')
.data('aspect_ratio_height');
var options = {
aspectRatio: aspectRatioWidth / aspectRatioHeight,
viewMode: 1,
autoCropArea: 1,
zoomable: false,
checkCrossOrigin: false,
};
// prettier-ignore
$('body').append(
'
' +
'
' +
'
' +
'
' +
'
' + aiarc_translations.modal_title + '
' +
'' +
'
' +
'
' +
'' +
'
' +
'' +
'
' +
'
');
this.cropper = new Cropper(
$('.js-acf-image-aspect-ratio-crop-modal-image')[0],
options,
);
},
cropComplete: function(data) {
// Cropping successful, change image to cropped version
this.cropper.destroy();
$(field)
.find('input')
.val(data.id);
var attachment = new wp.media.model.Attachment.get(data.id);
var self = this;
attachment.fetch({
success: function(response) {
self.render(response);
},
});
this.closeModal();
},
closeModal: function() {
$('.acf-image-aspect-ratio-crop-backdrop').remove();
},
});
/**
* initialize_field
*
* This function will initialize the $field.
*
* @date 30/11/17
* @since 5.6.5
*
* @param n/a
* @return n/a
*/
function initialize_field($el) {
//$field.doStuff();
//var $field = $el, $options = $el.find('.acf-field-image-aspect-ratio-crop');
}
/*
* ready & append (ACF5)
*
* These two events are called when a field element is ready for initizliation.
* - ready: on page load similar to $(document).ready()
* - append: on new DOM elements appended via repeater field or other AJAX calls
*
* @param n/a
* @return n/a
*/
acf.add_action('ready_field/type=image_aspect_ratio_crop', initialize_field);
acf.add_action('append_field/type=image_aspect_ratio_crop', initialize_field);
})(jQuery);