image_hotspots-8.x-1.x-dev/js/image_hotspots.edit.js
js/image_hotspots.edit.js
/**
* @file
* Provides UI for making hotspots on image.
*/
'use strict';
(function ($, Drupal) {
Drupal.behaviors.imageHotspotsEdit = {
attach: function (context, settings) {
$(once('imageHotspotsEdit', '.image-hotspots-wrapper:not(.init-edit)', context)).each(function () {
var $wrapper = $(this);
// Main elements.
var divs = {
$wrapper: $wrapper,
$imageWrapper: $wrapper.find('.image-wrapper'),
$image: $wrapper.find('img'),
$labelsWrapper: $wrapper.find('.labels'),
$editForm: $wrapper.find('.edit-form-wrapper'),
$imageJcrop: null,
$jcropWrapper: null
};
// Main data.
var data = {
hotspotsTarget: {
fieldName: this.dataset.fieldName,
imageStyle: this.dataset.imageStyle,
fid: this.dataset.fid,
hotspotsStyle: this.dataset.hotspotsStyle,
langcode: this.dataset.langcode
},
hotspots: settings.image_hotspots[this.dataset.fieldName][this.dataset.fid][this.dataset.imageStyle][this.dataset.hotspotsStyle][this.dataset.langcode].hotspots || {}
};
// Editor state.
var state = {
currentLabel: null,
currentButton: null,
currentHid: null,
jcropApi: null
};
// Initialization.
$wrapper.find('.add-button').click(function () {
var $button = $(this);
unselectButton();
state.currentButton = $button;
editAction($button);
});
divs.$labelsWrapper.children().each(function () {
addEditorsToLabel($(this));
});
initEditForm();
$wrapper.addClass('.init-edit');
// Add edit and remove buttons to label.
function addEditorsToLabel($label) {
var $edit = $('<div />', {
class: 'action edit',
html: Drupal.t('Edit'),
title: Drupal.t('Edit this hotspot'),
on: {
click: function () {
var $button = $(this);
var $label = $button.parent().parent();
unselectButton();
state.currentButton = $button;
$button.addClass('selected');
editAction($label);
}
}
});
var $remove = $('<div />', {
class: 'action remove',
html: Drupal.t('Remove'),
title: Drupal.t('Delete this hotspot'),
on: {
click: function () {
unselectButton();
state.currentButton = null;
var $label = $(this).parent().parent();
removeAction($label);
}
}
});
var $box = $('<div />', {
class: 'label-editor',
'data-hid': $label.data('hid')
});
$box.append($edit, $remove);
$label.append($box);
}
// Action when user click on 'remove' button.
function removeAction($label) {
var hid = $label.data('hid');
var $button = $label.find('.remove');
var $throbber = $('<div />', {
class: 'ajax-progress-throbber',
html: '<div class="throbber"></div>'
});
$button.after($throbber);
$.post(drupalSettings.path.baseUrl + 'image-hotspots/' + hid + '/delete', {}, function (responseData) {
removeHotspotFromImage(hid);
hideJcrop();
hideEditForm();
deleteFromSettings(hid);
$label.fadeOut(100);
setTimeout(function () {
$label.remove();
}, 100)
})
.fail(function (responseData) {
alert(responseData.responseText)
})
.always(function () {
$throbber.remove();
});
}
// Action when user click on 'edit' button.
function editAction($label) {
var hid = $label.data('hid') || -1;
var hotspot_data = data.hotspots[hid] || {
'title': '',
'description': '',
'link': '',
'target': ''
};
var position = $label.position();
var dimensions = {
'width': $label.width(),
height: $label.height()
};
state.currentHid = hid;
state.currentLabel = $label;
showJcrop();
if (hotspot_data.x !== undefined) {
state.jcropApi.setSelect([
hotspot_data.x,
hotspot_data.y,
hotspot_data.x2,
hotspot_data.y2
]);
}
else {
state.jcropApi.release();
}
showEditForm(hotspot_data, position, dimensions);
}
// Calculates position of form and fills inputs.
function showEditForm(hotspot_data, position, dimensions) {
if (divs.$editForm.width() + position.left + dimensions.width > $(window).width()) {
position.left -= divs.$editForm.width();
}
divs.$editForm.css({
top: position.top + 10 + 'px',
left: position.left + 10 + 'px'
});
divs.$editForm.fadeIn(200);
divs.$editForm.find('input[name="hotspots-title"]').val(hotspot_data.title).focus();
divs.$editForm.find('textarea[name="hotspots-description"]').val(hotspot_data.description);
divs.$editForm.find('input[name="hotspots-link"]').val(hotspot_data.link);
if (hotspot_data.target === "_blank") {
divs.$editForm.find('input[type=checkbox][name=hotspots-target]').prop('checked', true);
}
}
// Hides edit form and clears messages.
function hideEditForm() {
divs.$editForm.fadeOut(200);
divs.$editForm.find('.form-messages').html('');
}
// Action when form is closed or successfully submited.
function closeFormAction() {
hideJcrop();
hideEditForm();
unselectButton();
}
// Action when user click on 'Save' button in edit form.
function saveFormAction() {
var hid, hotspotNewData;
var selection = state.jcropApi.tellSelect();
if (selection.h <= 0) {
divs.$editForm.find('.form-messages').html(Drupal.t('Please select an area on the image.'));
return false;
}
hid = state.currentHid;
hotspotNewData = {
title: divs.$editForm.find('input[name="hotspots-title"]').val(),
description: divs.$editForm.find('textarea[name="hotspots-description"]').val(),
link: divs.$editForm.find('input[name="hotspots-link"]').val(),
target: divs.$editForm.find('input[type=checkbox][name=hotspots-target]:checked').val(),
x: Math.round(selection.x),
y: Math.round(selection.y),
x2: Math.round(selection.x2),
y2: Math.round(selection.y2)
};
if (hotspotNewData.target === undefined) {
hotspotNewData.target = '_self';
}
var $throbber = $('<div />', {
class: 'ajax-progress-throbber',
html: '<div class="throbber"></div>'
});
if (hid !== -1) {
if (equalData(data.hotspots[hid], hotspotNewData)) {
closeFormAction();
return false;
}
divs.$editForm.find('button').after($throbber);
$.post(drupalSettings.path.baseUrl + 'image-hotspots/' + hid + '/update', hotspotNewData, function (responseData) {
hotspotNewData = responseData;
var $labelTitle = state.currentLabel.find('.label-title').children();
if (data.hotspots[hid].title !== hotspotNewData.title) {
$labelTitle.html(hotspotNewData.title);
}
if (data.hotspots[hid].link !== hotspotNewData.link) {
if ($labelTitle.is('a')) {
if (hotspotNewData.link === '') {
$labelTitle.replaceWith($('<span>' + $labelTitle.html() + '</span>'));
}
else {
$labelTitle.attr('href', hotspotNewData.link);
}
}
else {
$labelTitle.replaceWith($('<a href="' + hotspotNewData.link + '" target="_blank">' + $labelTitle.html() + '</a>'));
}
}
if (data.hotspots[hid].description !== hotspotNewData.description) {
$labelTitle.prevObject.prevObject[0].setAttribute('title', hotspotNewData.description);
}
data.hotspots[hid] = hotspotNewData;
hotspotNewData.hid = hid;
closeFormAction();
removeHotspotFromImage(hid);
Drupal.behaviors.imageHotspotView.createHotspotBox(divs.$imageWrapper, hotspotNewData);
})
.fail(function (responseData) {
divs.$editForm.find('.form-messages').html(responseData.responseText);
})
.always(function () {
$throbber.remove();
});
}
else {
hotspotNewData.image_style = data.hotspotsTarget.imageStyle;
hotspotNewData.field_name = data.hotspotsTarget.fieldName;
hotspotNewData.fid = data.hotspotsTarget.fid;
hotspotNewData.langcode = data.hotspotsTarget.langcode;
divs.$editForm.find('button').after($throbber);
if (hotspotNewData[target] === undefined) {
hotspotNewData[target] = '_self';
}
$.post(drupalSettings.path.baseUrl + 'image-hotspots/create', hotspotNewData, function (responseData) {
hotspotNewData = responseData;
data.hotspots[responseData.hid] = hotspotNewData;
var $newLabel = Drupal.behaviors.imageHotspotView.createHotspotLabel(divs.$labelsWrapper, hotspotNewData);
Drupal.behaviors.imageHotspotView.createHotspotBox(divs.$imageWrapper, hotspotNewData);
addEditorsToLabel($newLabel);
closeFormAction();
})
.fail(function (responseData) {
divs.$editForm.find('.form-messages').html(responseData.responseText);
})
.always(function () {
$throbber.remove();
});
}
}
// Sets up new options for Jcrop and shows it.
function showJcrop() {
var jcropSettings = {
trueSize: [divs.$image.attr('width'), divs.$image.attr('height')],
boxWidth: divs.$image.width(),
boxHeight: divs.$image.height()
};
if (state.jcropApi === null) {
initJcrop();
}
state.jcropApi.setOptions(jcropSettings);
divs.$imageWrapper.hide();
divs.$jcropWrapper.show();
}
// Releases Jcrop selection and hide it.
function hideJcrop() {
state.jcropApi && state.jcropApi.release();
divs.$jcropWrapper && divs.$jcropWrapper.hide();
divs.$imageWrapper.show();
}
// Remove existing box and overlays form image after successful deletion.
function removeHotspotFromImage(hid) {
divs.$imageWrapper.find('.overlay[data-hid="' + hid + '"]').remove();
divs.$imageWrapper.find('.hotspot-box[data-hid="' + hid + '"]').remove();
}
// Edit form initialization.
function initEditForm() {
divs.$editForm.find('.close-button').click(function () {
closeFormAction();
});
divs.$editForm.find('button').click(function () {
saveFormAction();
return false;
});
divs.$editForm.keyup(function (evt) {
evt = evt || window.event;
if ((evt.key && evt.key == 'Escape') || (evt.keyCode == 27)) {
closeFormAction();
}
});
}
// Creates image for jcrop and hide original.
function initJcrop() {
var jcropSettings = {
keySupport: false,
bgOpacity: 0.7
};
divs.$imageJcrop = divs.$image.clone();
divs.$imageWrapper.after(divs.$imageJcrop);
divs.$imageJcrop.Jcrop(jcropSettings, function () {
state.jcropApi = this;
divs.$jcropWrapper = divs.$wrapper.find('.jcrop-holder');
});
}
function equalData(oldD, newD) {
return (oldD.title == newD.title &&
oldD.description == newD.description &&
oldD.link == newD.link &&
oldD.target == newD.target &&
oldD.x == newD.x &&
oldD.y == newD.y &&
oldD.x2 == newD.x2 &&
oldD.y2 == newD.y2);
}
// Remove 'selected' class from last button.
function unselectButton() {
state.currentButton && state.currentButton.removeClass('selected');
}
// Remove deleted hotspots info from drupalSettings.
function deleteFromSettings(hid) {
var target = data.hotspotsTarget;
if (Object.hasOwn(settings.image_hotspots[target.fieldName][target.fid][target.imageStyle][target.hotspotsStyle][target.langcode]['hotspots'], "" + hid)) {
delete settings.image_hotspots[target.fieldName][target.fid][target.imageStyle][target.hotspotsStyle][target.langcode]['hotspots'][hid];
}
}
});
}
};
})(jQuery, Drupal);
