����
������������������������������������
let currentRow;
let undoStack = [];
let hasUndone = false;
function triggerFileInput(dropArea) {
const fileInput = $(dropArea).siblings('input[type="file"]')[0];
fileInput.click();
}
function addRow() {
const row = `
|
|
Drag & Drop Image Here
Press Ctrl + V to paste images into the highlighted area.
|
|
`;
$('#imageTableBody').append(row);
}
function removeRow(button) {
const rows = $('#imageTableBody tr');
if (rows.length > 1) {
$(button).closest('tr').remove();
} else {
toastr.warning("The last row cannot be removed!");
}
}
function moveRow(button, direction) {
const row = $(button).closest('tr');
if (direction === 'up' && row.index() > 0) {
row.insertBefore(row.prev());
} else if (direction === 'down') {
row.insertAfter(row.next());
}
}
function previewImage(event, input) {
const imgPreview = $(input).siblings('.image-preview');
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = function (e) {
imgPreview.attr('src', e.target.result).show();
}
reader.readAsDataURL(input.files[0]);
}
}
function highlightDropArea(dropArea) {
$(dropArea).addClass('highlight');
}
function removeHighlight(dropArea) {
$(dropArea).removeClass('highlight');
}
function saveImages() {
const saveButton = $('#saveImagesButton');
saveButton.prop('disabled', true);
saveButton.text('Submitting...');
let formData = new FormData();
let pid = $('#pid').val();
let allImagesUploaded = true;
$('#imageTableBody tr').each(function () {
const fileInput = $(this).find('.image-file')[0].files[0];
const caption = $(this).find('input[type="text"]').val();
const imageSize = $(this).find('.image-size').val(); // Get image size
const pins = $(this).data('pins') || [];
const id = $(this).data('image-id');
const imageOrder = $(this).index();
if (!fileInput) {
allImagesUploaded = false;
return;
}
formData.append('images[]', fileInput);
formData.append('captions[]', caption);
formData.append('pins[]', JSON.stringify(pins));
formData.append('ids[]', id);
formData.append('pid', pid);
formData.append('imageOrder[]', imageOrder);
formData.append('imageSizes[]', imageSize); // Append image size
});
if (!allImagesUploaded) {
saveButton.prop('disabled', false);
saveButton.text('Submit');
toastr.error('Please upload all images.');
return;
}
$.ajax({
url: 'save_images.php',
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function (response) {
saveButton.text('Images Saved');
toastr.success('Images saved successfully! Please submit the form to view processed images.');
window.parent.postMessage({ action: 'submitForm' }, '*');
},
error: function (xhr, status, error) {
saveButton.prop('disabled', false);
saveButton.text('Save All Images');
toastr.error('Error saving images: ' + error);
}
});
}
$(document).ready(function () {
$(document).on('dragover', '.drag-drop-area', function (event) {
event.preventDefault();
highlightDropArea(this);
});
$(document).on('dragleave', '.drag-drop-area', function () {
removeHighlight(this);
});
$(document).on('drop', '.drag-drop-area', function (event) {
handleDrop(event, this);
});
$(document).on('paste', '.drag-drop-area', function (event) {
handlePaste(event, this);
});
});
function highlightDropArea(dropArea) {
// console.log('hit');
$(dropArea).addClass('highlight');
}
function removeHighlight(dropArea) {
$(dropArea).removeClass('highlight');
}
function handleDrop(event, dropArea) {
event.preventDefault();
removeHighlight(dropArea);
const files = event.originalEvent.dataTransfer.files;
if (files.length > 0) {
const input = $(dropArea).siblings('input[type="file"]')[0];
const dataTransfer = new DataTransfer();
dataTransfer.items.add(files[0]); // Simulate file input
input.files = dataTransfer.files;
previewImage(event, input);
}
}
function handlePaste(event, dropArea) {
const items = event.originalEvent.clipboardData.items;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.type.startsWith('image/')) {
event.preventDefault();
highlightDropArea(dropArea); // Highlight the area
const file = item.getAsFile();
const input = $(dropArea).siblings('input[type="file"]')[0];
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
input.files = dataTransfer.files; // Simulate file input
previewImage(event, input);
}
}
}
function previewImage(event, input) {
const imgPreview = $(input).siblings('.image-preview');
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = function (e) {
imgPreview.attr('src', e.target.result).show();
};
reader.readAsDataURL(input.files[0]);
}
}
let canvas = new fabric.Canvas('canvas');
let fabricImage = null;
let originalImageSrc = null;
function editImage(icon) {
currentRow = $(icon).closest('tr');
const imageSrc = currentRow.find('.image-preview').attr('src');
if (imageSrc) {
originalImageSrc = imageSrc;
$('#editImageModal').modal({
backdrop: 'static',
keyboard: false
});
loadFabricImage(imageSrc);
}
}
function loadFabricImage(src) {
fabric.Image.fromURL(src, function(img) {
// Get the original dimensions of the image
const originalWidth = img.width;
const originalHeight = img.height;
const maxWidth = 1000;
if (originalWidth > maxWidth) {
const aspectRatio = originalHeight / originalWidth;
canvas.setWidth(maxWidth);
canvas.setHeight(maxWidth * aspectRatio);
} else {
canvas.setWidth(originalWidth);
canvas.setHeight(originalHeight);
}
canvas.clear();
fabricImage = img;
// Set the properties of the image
img.set({
left: 0,
top: 0,
scaleX: canvas.width / originalWidth, // Scale to fit the canvas
scaleY: canvas.height / originalHeight, // Scale to fit the canvas
selectable: false,
evented: false
});
// Add the image to the canvas and send it to the back
canvas.add(fabricImage);
fabricImage.sendToBack();
// Render the canvas
canvas.renderAll();
});
}
function updateModalImage(event) {
const input = event.target;
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
loadFabricImage(e.target.result);
};
reader.readAsDataURL(input.files[0]);
}
}
let cropMode = false; // Tracks whether crop mode is active
let cropRect;
function cropImage() {
if (!cropMode) {
// First click - initialize crop mode and create crop rectangle
pushUndoState();
cropRect = new fabric.Rect({
left: 50, // Adjust as needed
top: 50,
width: 200,
height: 200,
fill: 'transparent',
stroke: 'red',
strokeWidth: 2,
selectable: false,
});
canvas.add(cropRect);
canvas.setActiveObject(cropRect);
canvas.renderAll();
cropMode = true; // Set crop mode active
} else {
// Second click - perform the crop
if (fabricImage && cropRect) {
const rect = cropRect.getBoundingRect();
const cropX = (rect.left - fabricImage.left) / fabricImage.scaleX;
const cropY = (rect.top - fabricImage.top) / fabricImage.scaleY;
const cropWidth = rect.width / fabricImage.scaleX;
const cropHeight = rect.height / fabricImage.scaleY;
const croppedCanvas = document.createElement('canvas');
croppedCanvas.width = cropWidth;
croppedCanvas.height = cropHeight;
const ctx = croppedCanvas.getContext('2d');
ctx.drawImage(
fabricImage.getElement(),
cropX, cropY, cropWidth, cropHeight,
0, 0, cropWidth, cropHeight
);
const croppedImageDataURL = croppedCanvas.toDataURL();
fabric.Image.fromURL(croppedImageDataURL, function (croppedImage) {
// Clear the canvas before adding the cropped image
canvas.clear();
// Ensure the cropped image width does not exceed 1000
let finalWidth = croppedImage.width;
let finalHeight = croppedImage.height;
const maxWidth = 1000;
if (finalWidth > maxWidth) {
const scaleFactor = maxWidth / finalWidth;
finalWidth = maxWidth;
finalHeight *= scaleFactor;
}
// Set the canvas dimensions to match the cropped image
canvas.setWidth(finalWidth);
canvas.setHeight(finalHeight);
// Set the cropped image properties
croppedImage.set({
left: 0,
top: 0,
scaleX: canvas.width / croppedImage.width,
scaleY: canvas.height / croppedImage.height,
selectable: false,
evented: false
});
// Add the cropped image to the canvas and render
canvas.add(croppedImage);
canvas.renderAll();
// Clean up: remove crop rectangle
canvas.remove(cropRect);
// Push the state to undo stack and update the fabric image
pushUndoState();
fabricImage = croppedImage;
// Reset crop mode
cropMode = false;
cropRect = null;
});
}
}
}
function flipImage() {
if (fabricImage) {
// console.log("Before flip: ", fabricImage);
// console.log("Before flip: ", fabricImage.flipX);
pushUndoState();
fabricImage.flipX = !fabricImage.flipX;
// console.log("After flip: ", fabricImage);
// console.log("After flip: ", fabricImage.flipX);
fabricImage.dirty = true;
canvas.renderAll();
}
}
function rotateImage() {
if (fabricImage) {
pushUndoState();
fabricImage.rotate((fabricImage.angle + 90) % 360);
canvas.renderAll();
}
}
function saveImageChanges() {
// Clear the pins from the canvas (temporarily)
const pins = [];
canvas.getObjects('image').forEach(function (obj) {
if (obj.pinData) {
pins.push(obj);
canvas.remove(obj);
}
});
const dataURL = canvas.toDataURL();
currentRow.find('.image-preview').attr('src', dataURL);
const fileInput = currentRow.find('input[type="file"]')[0];
const blob = dataURLtoBlob(dataURL);
const newFile = new File([blob], 'edited-image.png', { type: 'image/png' });
const dataTransfer = new DataTransfer();
dataTransfer.items.add(newFile);
fileInput.files = dataTransfer.files;
pins.forEach(pin => canvas.add(pin));
currentRow.data('pinsData', pinsData);
$('#editImageModal').modal('hide');
}
// Helper function to convert base64 to Blob
function dataURLtoBlob(dataURL) {
const byteString = atob(dataURL.split(',')[1]);
const mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
}
function toggleFreeDrawing() {
disableAllDrawingModes();
canvas.isDrawingMode = !canvas.isDrawingMode; // Toggle drawing mode
pushUndoState();
if (canvas.isDrawingMode) {
const selectedColor = $('#colorPicker').val();
canvas.freeDrawingBrush.color = selectedColor || 'red';
canvas.freeDrawingBrush.width = 5; // Set brush width
toastr.success('Free Drawing Mode Enabled Successfully!.')
} else {
toastr.success('Free Drawing Mode Disabled Successfully!.')
}
}
canvas.on('path:created', function () {
});
function addRectangle() {
pushUndoState();
disableAllDrawingModes();
const selectedColor = $('#colorPicker').val();
let rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'transparent',
width: 100,
height: 100,
stroke: selectedColor,
strokeWidth: 2,
selectable: true
});
canvas.add(rect);
canvas.renderAll();
}
// Add circle to the canvas
function addCircle() {
pushUndoState();
disableAllDrawingModes();
const selectedColor = $('#colorPicker').val();
let circle = new fabric.Circle({
left: 200,
top: 150,
radius: 50,
fill: 'transparent',
stroke: selectedColor,
strokeWidth: 2,
selectable: true
});
canvas.add(circle);
canvas.renderAll();
// Save the state after adding the circle
}
function addText() {
// console.log(undoStack);
pushUndoState();
// console.log(undoStack);
const text = prompt('Enter the text you want to add:');
if (text) {
const selectedColor = $('#colorPicker').val();
const textObj = new fabric.Text(text, {
left: canvas.width / 2 - 50, // Center the text horizontally
top: canvas.height / 2 - 10, // Center the text vertically
fill: selectedColor || 'red', // Default text color
fontSize: 24, // Default font size
fontFamily: 'Arial', // Default font family
});
// Add the text object to the canvas
canvas.add(textObj);
// Make the text selectable and draggable
canvas.setActiveObject(textObj);
canvas.renderAll();
}
}
let isLineDrawing = false;
let isDrawing = false;
let line = null;
// Toggle the drawing mode on or off
function toggleLineDrawing() {
isLineDrawing = !isLineDrawing;
if (isLineDrawing) {
canvas.isDrawingMode = false;
canvas.selection = false;
canvas.defaultCursor = 'crosshair';
// Reset the line and drawing flag
line = null;
isDrawing = false;
// Attach mouse event listeners
canvas.on('mouse:down', startDrawingLine);
canvas.on('mouse:move', continueDrawingLine);
canvas.on('mouse:up', finishDrawingLine);
} else {
// Detach mouse event listeners
canvas.off('mouse:down', startDrawingLine);
canvas.off('mouse:move', continueDrawingLine);
canvas.off('mouse:up', finishDrawingLine);
// Enable selection and reset cursor
canvas.selection = true;
canvas.defaultCursor = 'default';
}
}
// Start drawing the line
function startDrawingLine(o) {
if (!isLineDrawing || isDrawing) return; // Prevent drawing if already drawing
isDrawing = true;
const pointer = canvas.getPointer(o.e);
const points = [pointer.x, pointer.y, pointer.x, pointer.y];
// Get color from the color picker (or default to red)
const selectedColor = $('#colorPicker').val();
line = new fabric.Line(points, {
strokeWidth: 2,
stroke: selectedColor || 'red', // Default line color
selectable: false, // Line should not be selectable while drawing
evented: false, // Disable event handling while drawing
});
canvas.add(line);
}
// Continue drawing the line as the mouse moves
function continueDrawingLine(o) {
if (!isDrawing || !line) return; // Ensure line exists before continuing
const pointer = canvas.getPointer(o.e);
line.set({ x2: pointer.x, y2: pointer.y });
canvas.renderAll();
}
// Finish drawing the line when mouse button is released
function finishDrawingLine() {
if (!isDrawing || !line) return; // Ensure line exists before finishing
isDrawing = false;
line.setCoords(); // Set final coordinates of the line
pushUndoState(); // Optional, push to undo stack
// Finalize the line's drawing
canvas.renderAll();
// Reset the line object for the next drawing
line = null;
}
let pinsData = [];
function addPin() {
disableAllDrawingModes();
const url = prompt('Enter the URL for the pin:');
fabric.Image.fromURL('location-pin.png', function(pinIcon) {
pinIcon.scale(0.06);
pinIcon.set({
left: canvas.width / 2,
top: canvas.height / 2,
selectable: true,
hasControls: false,
hasBorders: false
});
pinIcon.on('mousedblclick', function() {
window.open(url, '_blank');
});
canvas.add(pinIcon);
canvas.renderAll();
let relativeLeft = (pinIcon.left / canvas.width) * 100;
let relativeTop = (pinIcon.top / canvas.height) * 100;
const pinData = {
url: url,
left: relativeLeft, // Store as percentage
top: relativeTop // Store as percentage
};
// Store pinData in the current row
const row = $(currentRow);
let pins = row.data('pins') || [];
pins.push(pinData);
row.data('pins', pins); // Update the row's pin data
// Update pin's position when it is moved
pinIcon.on('moving', function() {
// Convert new position to percentage
relativeLeft = (pinIcon.left / canvas.width) * 100;
relativeTop = (pinIcon.top / canvas.height) * 100;
pinData.left = relativeLeft;
pinData.top = relativeTop;
row.data('pins', pins);
});
pushUndoState();
});
}
function disableAllDrawingModes() {
// Disable free drawing mode
canvas.isDrawingMode = false;
// Disable line drawing mode
isLineDrawing = false;
canvas.off('mouse:down', startDrawingLine);
canvas.off('mouse:move', continueDrawingLine);
canvas.off('mouse:up', finishDrawingLine);
// Reset the canvas cursor and selection properties
canvas.selection = false; // Disable selection
canvas.defaultCursor = 'default'; // Set default cursor
// Ensure changes are reflected immediately
canvas.renderAll();
}
let isDropAreaSelected = false; // Track the selection state
$(document).on('click', '.select-area-btn', function() {
var currentRow = $(this).closest('tr');
var dropArea = currentRow.find('.drag-drop-area')[0];
var instructions = currentRow.find('.paste-instructions');
highlightDropArea(dropArea);
instructions.show();
$(document).off('paste');
$(document).on('paste', function(event) {
handlePaste(event, dropArea);
});
});
function pushUndoState() {
if (hasUndone) {
undoStack = undoStack.slice(0, undoStack.length);
hasUndone = false;
}
const canvasState = JSON.stringify(canvas.toJSON()); // Save canvas objects as JSON
const canvasWidth = canvas.getWidth(); // Get canvas width
const canvasHeight = canvas.getHeight(); // Get canvas height
undoStack.push({
state: canvasState, // Save the canvas state
width: canvasWidth, // Save the canvas width
height: canvasHeight // Save the canvas height
});
}
function undo() {
if (undoStack.length > 0) {
const lastState = undoStack.pop();
// console.log("Restoring canvas with width:", lastState.width);
// console.log("Restoring canvas with height:", lastState.height);
canvas.setWidth(lastState.width);
canvas.setHeight(lastState.height);
canvas.clear();
canvas.loadFromJSON(lastState.state, function() {
canvas.getObjects().forEach(function(obj) {
obj.set({
selectable: false,
hasControls: false,
evented: false,
});
fabricImage = obj;
});
canvas.renderAll();
});
hasUndone = true;
} else {
toastr.warning('No more actions to undo.');
}
}