Compare commits
No commits in common. "21f80966369ea6193a177aa027e65327026b0620" and "2ddcf21572ef37e99641728e495a77efbd50f1fe" have entirely different histories.
21f8096636
...
2ddcf21572
|
|
@ -23,6 +23,20 @@ function gallery_app_init($hook) {
|
||||||
// Wordpress Media Library Dialog
|
// Wordpress Media Library Dialog
|
||||||
wp_enqueue_media();
|
wp_enqueue_media();
|
||||||
|
|
||||||
|
// Image Cropping Library
|
||||||
|
/*wp_enqueue_style(
|
||||||
|
'cropper-css',
|
||||||
|
'https://unpkg.com/cropperjs@2.1.0/dist/cropper.css',
|
||||||
|
array(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
wp_enqueue_script(
|
||||||
|
'cropper-js',
|
||||||
|
'https://unpkg.com/cropperjs@2.1.0/dist/cropper.js',
|
||||||
|
array(),
|
||||||
|
null
|
||||||
|
);*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Own scripts
|
* Own scripts
|
||||||
*/
|
*/
|
||||||
|
|
@ -37,12 +51,6 @@ function gallery_app_init($hook) {
|
||||||
array( 'jquery', 'jcrop' )
|
array( 'jquery', 'jcrop' )
|
||||||
);
|
);
|
||||||
|
|
||||||
wp_localize_script( 'theatergf-gallery-admin-js', 'wpAPISettings', array(
|
|
||||||
'root' => esc_url_raw( rest_url() ),
|
|
||||||
'nonce' => wp_create_nonce( 'wp_rest' )
|
|
||||||
));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
add_action('admin_enqueue_scripts', 'TheaterGF\Gallery\Admin\gallery_app_init');
|
add_action('admin_enqueue_scripts', 'TheaterGF\Gallery\Admin\gallery_app_init');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ function admin_gallery_html($args) {
|
||||||
<div class="theatergf gallery_app">
|
<div class="theatergf gallery_app">
|
||||||
|
|
||||||
<div id="theatergf-editor" class="theatergf image-editor">
|
<div id="theatergf-editor" class="theatergf image-editor">
|
||||||
<img class="editor-image">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="editor-button-row">
|
|
||||||
<button id="theatergf-select-image" class="button button-primary">Select image</button>
|
<button id="theatergf-select-image" class="button button-primary">Select image</button>
|
||||||
<button id="theatergf-edit-save" class="button button-primary">Save</button
|
|
||||||
|
<div style="height: 15px"></div>
|
||||||
|
|
||||||
|
<div class="theatergf image-edit-wrap">
|
||||||
|
<canvas id="theatergf-image-editor"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,116 @@
|
||||||
|
|
||||||
const devicePixelRatio = window.devicePixelRatio || 1;
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
function clamp(n, min, max) {
|
class ImageCropper {
|
||||||
return Math.max(Math.min(n, max), min)
|
|
||||||
}
|
|
||||||
function round(n, base = 10) {
|
|
||||||
return Math.round(n / base) * base;
|
|
||||||
}
|
|
||||||
function floor(n, base = 10) {
|
|
||||||
return Math.floor(n / base) * base;
|
|
||||||
}
|
|
||||||
function ceil(n, base = 10) {
|
|
||||||
return Math.ceil(n / base) * base;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRelativeClientRect(element) {
|
constructor(canvas) {
|
||||||
const element_bounds = element.getBoundingClientRect();
|
if (!(canvas instanceof HTMLCanvasElement)) {
|
||||||
const parents_bounds = element.parentElement.getBoundingClientRect();
|
throw TypeError('canvas must be a HTMLCanvasElement');
|
||||||
return new DOMRect(
|
|
||||||
element_bounds.x - parents_bounds.x,
|
|
||||||
element_bounds.y - parents_bounds.y,
|
|
||||||
element_bounds.width,
|
|
||||||
element_bounds.height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResizableBox {
|
|
||||||
constructor(parent, bounding, resolution, aspectRatio = null) {
|
|
||||||
|
|
||||||
this.DIRECTIONS = {
|
|
||||||
nw: { sign: { x: -1, y: -1 }, anchor: 'se' },
|
|
||||||
ne: { sign: { x: +1, y: -1 }, anchor: 'sw' },
|
|
||||||
sw: { sign: { x: -1, y: +1 }, anchor: 'ne' },
|
|
||||||
se: { sign: { x: +1, y: +1 }, anchor: 'nw' }
|
|
||||||
}
|
}
|
||||||
this.bounding = bounding;
|
this._preview = canvas;
|
||||||
this.resolution = resolution;
|
this._preview_ctx = canvas.getContext('2d');
|
||||||
this.aspectRatio = aspectRatio;
|
this._preview_ctx.reset();
|
||||||
|
|
||||||
this.mouseStart = { x: 0, y: 0 };
|
const dimensions = this._preview.getBoundingClientRect();
|
||||||
this.maxDelta = { x: 0, y: 0 };
|
console.log(dimensions);
|
||||||
this.minDelta = { x: 0, y: 0 };
|
console.log(this._preview.width, this._preview.height);
|
||||||
|
|
||||||
this.elemStart = new DOMRect();
|
this._preview.width = dimensions.width * devicePixelRatio;
|
||||||
this.direction = undefined;
|
this._preview.height = dimensions.height * devicePixelRatio;
|
||||||
|
this._preview_ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
this._constructElement(parent);
|
showImage(image_src) {
|
||||||
|
this._image = new Image();
|
||||||
|
this._image.src = image_src;
|
||||||
|
|
||||||
this.res_scale = {
|
this._image.addEventListener('load', (e) => {
|
||||||
x: resolution.x / bounding.width,
|
|
||||||
y: resolution.y / bounding.height
|
const dimensions = this._preview.getBoundingClientRect();
|
||||||
|
|
||||||
|
const scale = {
|
||||||
|
x: dimensions.width / this._image.naturalWidth,
|
||||||
|
y: dimensions.height / this._image.naturalHeight
|
||||||
|
}
|
||||||
|
const ratio = Math.min(scale.x, scale.y);
|
||||||
|
|
||||||
|
const position = {
|
||||||
|
x: (dimensions.width - this._image.naturalWidth * ratio) / 2,
|
||||||
|
y: (dimensions.height - this._image.naturalHeight * ratio) / 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this._preview_ctx.drawImage(this._image, position.x, position.y, this._image.naturalWidth * ratio, this._image.naturalHeight * ratio);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
doCrop() {
|
||||||
|
this._shadow = document.createElement('canvas');
|
||||||
|
this._shadow.style.display = 'none';
|
||||||
|
this._shadow_ctx = canvas.getContext('2d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*jQuery(document).ready( ($) => {
|
||||||
|
|
||||||
|
let wp_file_selector_frame;
|
||||||
|
let image_cropper;
|
||||||
|
|
||||||
|
$('#theatergf-select-image').on('click', (event) => {
|
||||||
|
|
||||||
|
// don't open browser file select
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (wp_file_selector_frame) {
|
||||||
|
wp_file_selector_frame.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_file_selector_frame = wp.media({
|
||||||
|
title: 'Select Image',
|
||||||
|
button: {
|
||||||
|
text: 'Use Image'
|
||||||
|
},
|
||||||
|
multiple: false
|
||||||
|
});
|
||||||
|
|
||||||
|
wp_file_selector_frame.on('select', () => {
|
||||||
|
const file = wp_file_selector_frame.state().get('selection').first().toJSON();
|
||||||
|
|
||||||
|
image_cropper = new ImageCropper(document.getElementById('theatergf-image-editor'));
|
||||||
|
//image_cropper.showImage('http://localhost:8000/wp-content/uploads/2026/03/Kishon002.jpg');
|
||||||
|
|
||||||
|
image_cropper.showImage(file.url);
|
||||||
|
//document.getElementById('theatergf-image-preview').src = file.url;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
wp_file_selector_frame.open();
|
||||||
|
});
|
||||||
|
});*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ResizableBox {
|
||||||
|
constructor(element, aspectRatio = null) {
|
||||||
|
this.element = element;
|
||||||
|
this.aspectRatio = aspectRatio;
|
||||||
|
|
||||||
|
this.mouseStart = {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
this.elemStart = {
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: element.style.width,
|
||||||
|
height: element.style.height,
|
||||||
|
corner_pos: {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.direction = undefined;
|
||||||
|
|
||||||
const dragMouseMove = (event) => {
|
const dragMouseMove = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -61,113 +120,78 @@ class ResizableBox {
|
||||||
y: event.clientY - this.mouseStart.y
|
y: event.clientY - this.mouseStart.y
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.direction) {
|
const delta = {...offset};
|
||||||
this.resize(offset, this.direction, this.aspectRatio);
|
|
||||||
} else {
|
|
||||||
this.move(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dragMouseUp = (_) => {
|
if (this.direction && aspectRatio) {
|
||||||
this.element.classList.remove("moving");
|
|
||||||
|
|
||||||
this.direction = undefined;
|
|
||||||
|
|
||||||
document.removeEventListener('mousemove', dragMouseMove);
|
|
||||||
document.removeEventListener('mouseup', dragMouseUp);
|
|
||||||
};
|
|
||||||
|
|
||||||
const dragMouseDown = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.mouseStart.x = event.clientX;
|
|
||||||
this.mouseStart.y = event.clientY;
|
|
||||||
|
|
||||||
this.elemStart = getRelativeClientRect(this.element)
|
|
||||||
|
|
||||||
this.direction = [...event.target.classList].find(c => ["nw","ne","sw","se"].includes(c));
|
|
||||||
|
|
||||||
if (this.direction) {
|
|
||||||
const handle_size = getRelativeClientRect(this.element.querySelector(".handle"));
|
|
||||||
this.minDelta.x = -1 * (this.elemStart.width - 2*handle_size.width);
|
|
||||||
this.minDelta.y = -1 * (this.elemStart.height - 2*handle_size.height);
|
|
||||||
|
|
||||||
|
const {anchor, sign} = (() => {
|
||||||
switch (this.direction) {
|
switch (this.direction) {
|
||||||
case 'nw':
|
case 'nw':
|
||||||
this.maxDelta.x = this.elemStart.left - this.bounding.left;
|
return {
|
||||||
this.maxDelta.y = this.elemStart.top - this.bounding.top;
|
anchor: {
|
||||||
break;
|
x: this.elemStart.left + this.elemStart.width,
|
||||||
|
y: this.elemStart.top + this.elemStart.height
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
x: -1,
|
||||||
|
y: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'ne':
|
case 'ne':
|
||||||
this.maxDelta.x = this.bounding.right - this.elemStart.right;
|
return {
|
||||||
this.maxDelta.y = this.elemStart.top - this.bounding.top;
|
anchor: {
|
||||||
break;
|
x: this.elemStart.left,
|
||||||
|
y: this.elemStart.top + this.elemStart.height
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
x: +1,
|
||||||
|
y: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'sw':
|
case 'sw':
|
||||||
this.maxDelta.x = this.elemStart.left - this.bounding.left;
|
return {
|
||||||
this.maxDelta.y = this.bounding.bottom - this.elemStart.bottom;
|
anchor: {
|
||||||
break;
|
x: this.elemStart.left + this.elemStart.width,
|
||||||
|
y: this.elemStart.top
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
x: -1,
|
||||||
|
y: +1
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'se':
|
case 'se':
|
||||||
this.maxDelta.x = this.bounding.right - this.elemStart.right;
|
return {
|
||||||
this.maxDelta.y = this.bounding.bottom - this.elemStart.bottom;
|
anchor: {
|
||||||
break;
|
x: this.elemStart.left,
|
||||||
|
y: this.elemStart.top
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
x: +1,
|
||||||
|
y: +1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.element.classList.add('moving');
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', dragMouseMove);
|
|
||||||
document.addEventListener('mouseup', dragMouseUp);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.element.addEventListener('mousedown', dragMouseDown);
|
|
||||||
}
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
move(delta) {
|
const px = this.elemStart.corner_pos.x + offset.x
|
||||||
this.element.style.left = clamp(this.elemStart.left + delta.x, this.bounding.left, this.bounding.right - this.elemStart.width) + "px";
|
const py = this.elemStart.corner_pos.y + offset.y
|
||||||
this.element.style.top = clamp(this.elemStart.top + delta.y, this.bounding.top, this.bounding.bottom - this.elemStart.height) + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
resize(delta, direction, handle_aspect_ratio = true) {
|
const dx = sign.x * (px - anchor.x)
|
||||||
|
const dy = sign.y * (py - anchor.y)
|
||||||
|
|
||||||
console.log(delta)
|
const sh = dx/this.elemStart.width
|
||||||
|
const sv = dy/this.elemStart.height
|
||||||
|
|
||||||
const sign = this.DIRECTIONS[direction].sign;
|
const dv = Math.abs(dx - this.elemStart.width)
|
||||||
|
const dh = Math.abs(dy - this.elemStart.height)
|
||||||
|
|
||||||
const normalized = {
|
const s = (dv > dh) ? sv : sh
|
||||||
x: delta.x * sign.x,
|
|
||||||
y: delta.y * sign.y
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(normalized)
|
delta.x = sign.x * (s * this.elemStart.width - this.elemStart.width)
|
||||||
console.log(this.minDelta)
|
delta.y = sign.y * (s * this.elemStart.height - this.elemStart.height)
|
||||||
console.log(this.maxDelta);
|
|
||||||
|
|
||||||
if (handle_aspect_ratio) {
|
|
||||||
//delta = this._applyAspectRatio(delta.x, delta.y, direction)
|
|
||||||
|
|
||||||
if (Math.abs(normalized.x) > Math.abs(normalized.y * this.aspectRatio)) {
|
|
||||||
normalized.x = clamp(normalized.x,
|
|
||||||
Math.max(this.minDelta.x, this.minDelta.y * this.aspectRatio),
|
|
||||||
Math.min(this.maxDelta.x, this.maxDelta.y * this.aspectRatio));
|
|
||||||
normalized.y = normalized.x / this.aspectRatio;
|
|
||||||
} else {
|
|
||||||
normalized.y = clamp(normalized.y,
|
|
||||||
Math.max(this.minDelta.y, this.minDelta.x / this.aspectRatio),
|
|
||||||
Math.min(this.maxDelta.y, this.maxDelta.x / this.aspectRatio));
|
|
||||||
normalized.x = normalized.y * this.aspectRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
normalized.x = clamp(normalized.x, this.minDelta.x, this.maxDelta.x);
|
|
||||||
normalized.y = clamp(normalized.y, this.minDelta.y, this.maxDelta.y);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delta.x = normalized.x * sign.x;
|
|
||||||
delta.y = normalized.y * sign.y;
|
|
||||||
|
|
||||||
console.log(delta)
|
|
||||||
|
|
||||||
switch(this.direction) {
|
switch(this.direction) {
|
||||||
case 'nw':
|
case 'nw':
|
||||||
this.element.style.left = (this.elemStart.left + delta.x) + "px";
|
this.element.style.left = (this.elemStart.left + delta.x) + "px";
|
||||||
|
|
@ -189,36 +213,69 @@ class ResizableBox {
|
||||||
this.element.style.width = (this.elemStart.width + delta.x) + "px";
|
this.element.style.width = (this.elemStart.width + delta.x) + "px";
|
||||||
this.element.style.height = (this.elemStart.height + delta.y) + "px";
|
this.element.style.height = (this.elemStart.height + delta.y) + "px";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// moving is the default
|
||||||
|
default:
|
||||||
|
this.element.style.left = (this.elemStart.left + offset.x) + "px";
|
||||||
|
this.element.style.top = (this.elemStart.top + offset.y) + "px";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_constructElement(parent) {
|
|
||||||
parent.querySelector('.selector')?.remove();
|
|
||||||
|
|
||||||
this.element = document.createElement('div');
|
const dragMouseUp = (_) => {
|
||||||
this.element.classList.add('selector');
|
this.element.classList.remove("moving");
|
||||||
|
this.direction = undefined
|
||||||
|
document.removeEventListener('mousemove', dragMouseMove);
|
||||||
|
document.removeEventListener('mouseup', dragMouseUp);
|
||||||
|
};
|
||||||
|
|
||||||
if (this.aspectRatio) {
|
const dragMouseDown = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.bounding.width > this.bounding.height * this.aspectRatio) {
|
this.mouseStart.x = event.clientX;
|
||||||
this.element.style.width = (this.bounding.height * this.aspectRatio - 2) + "px";
|
this.mouseStart.y = event.clientY;
|
||||||
this.element.style.height = (this.bounding.height - 2) + "px";
|
|
||||||
this.element.style.left = (this.bounding.width - this.bounding.height * this.aspectRatio) / 2 + this.bounding.left + "px";
|
this.elemStart.left = this.element.offsetLeft;
|
||||||
this.element.style.top = this.bounding.top + "px";
|
this.elemStart.top = this.element.offsetTop;
|
||||||
} else {
|
this.elemStart.width = this.element.offsetWidth;
|
||||||
this.element.style.width = (this.bounding.width - 2) + "px";
|
this.elemStart.height = this.element.offsetHeight;
|
||||||
this.element.style.height = (this.bounding.width / this.aspectRatio - 2) + "px";
|
|
||||||
this.element.style.left = this.bounding.left + "px";
|
this.direction = [...event.target.classList].find(c => ["nw","ne","sw","se"].includes(c));
|
||||||
this.element.style.top = (this.bounding.height - this.bounding.width / this.aspectRatio) / 2 + this.bounding.top + "px";
|
|
||||||
|
switch (this.direction) {
|
||||||
|
case 'nw':
|
||||||
|
this.elemStart.corner_pos.x = this.element.offsetLeft;
|
||||||
|
this.elemStart.corner_pos.y = this.element.offsetTop;
|
||||||
|
break;
|
||||||
|
case 'ne':
|
||||||
|
this.elemStart.corner_pos.x = this.element.offsetLeft + this.element.offsetWidth;
|
||||||
|
this.elemStart.corner_pos.y = this.element.offsetTop;
|
||||||
|
break;
|
||||||
|
case 'sw':
|
||||||
|
this.elemStart.corner_pos.x = this.element.offsetLeft;
|
||||||
|
this.elemStart.corner_pos.y = this.element.offsetTop + this.element.offsetHeight;
|
||||||
|
break;
|
||||||
|
case 'se':
|
||||||
|
this.elemStart.corner_pos.x = this.element.offsetLeft + this.element.offsetWidth;
|
||||||
|
this.elemStart.corner_pos.y = this.element.offsetTop + this.element.offsetHeight;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
this.element.classList.add('moving');
|
||||||
|
|
||||||
this.element.style.left = this.bounding.offsetLeft + "px";
|
document.addEventListener('mousemove', dragMouseMove);
|
||||||
this.element.style.top = this.bounding.offsetTop + "px";
|
document.addEventListener('mouseup', dragMouseUp);
|
||||||
this.element.style.width = this.bounding.clientWidth + "px";
|
};
|
||||||
this.element.style.height = this.bounding.clientHeight + "px";
|
|
||||||
|
|
||||||
|
this.element.addEventListener('mousedown', dragMouseDown);
|
||||||
|
|
||||||
|
this.createHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
createHandles() {
|
||||||
|
const handles = this.element.querySelectorAll('.handle');
|
||||||
|
for (const handle of handles) {
|
||||||
|
this.element.removeChild(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const neHandle = document.createElement('div');
|
const neHandle = document.createElement('div');
|
||||||
|
|
@ -237,53 +294,10 @@ class ResizableBox {
|
||||||
this.element.appendChild(nwHandle);
|
this.element.appendChild(nwHandle);
|
||||||
this.element.appendChild(seHandle);
|
this.element.appendChild(seHandle);
|
||||||
this.element.appendChild(swHandle);
|
this.element.appendChild(swHandle);
|
||||||
|
|
||||||
parent.appendChild(this.element);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_mapCorner(rect, dir) {
|
getRect() {
|
||||||
const map = {
|
return new DOMRect(this.element.offsetLeft, this.element.offsetTop, this.element.offsetWidth, this.element.offsetHeight);
|
||||||
nw: { x: rect.left, y: rect.top },
|
|
||||||
ne: { x: rect.right, y: rect.top },
|
|
||||||
sw: { x: rect.left, y: rect.bottom },
|
|
||||||
se: { x: rect.right, y: rect.bottom }
|
|
||||||
};
|
|
||||||
|
|
||||||
return map[dir];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_applyAspectRatio(dx, dy, direction) {
|
|
||||||
|
|
||||||
const sign = this.DIRECTIONS[direction].sign;
|
|
||||||
const anchor = this._mapCorner(getRelativeClientRect(this.element), this.DIRECTIONS[direction].anchor);
|
|
||||||
|
|
||||||
const handle_size = getRelativeClientRect(this.element.querySelector(".handle"));
|
|
||||||
|
|
||||||
const sh = 1 + dx / this.elemStart.width
|
|
||||||
const sv = 1 + dy / this.elemStart.height
|
|
||||||
|
|
||||||
const dv = Math.abs(dx)
|
|
||||||
const dh = Math.abs(dy)
|
|
||||||
|
|
||||||
const s = (dv > dh) ? sv : sh
|
|
||||||
|
|
||||||
const sMaxX = (sign.x === +1)
|
|
||||||
? (this.bounding.right - anchor.x) / this.elemStart.width
|
|
||||||
: (anchor.x - this.bounding.left) / this.elemStart.width
|
|
||||||
|
|
||||||
const sMaxY = (sign.y === +1)
|
|
||||||
? (this.bounding.bottom - anchor.y) / this.elemStart.height
|
|
||||||
: (anchor.y - this.bounding.top) / this.elemStart.height
|
|
||||||
|
|
||||||
const sMin = Math.max(2*handle_size.width / this.elemStart.width, 2*handle_size.height / this.elemStart.height);
|
|
||||||
|
|
||||||
const sClamped = Math.max(Math.min(s, sMaxX, sMaxY), sMin);
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: sign.x * (sClamped * this.elemStart.width - this.elemStart.width),
|
|
||||||
y: sign.y * (sClamped * this.elemStart.height - this.elemStart.height)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -293,58 +307,45 @@ class Editor {
|
||||||
constructor(editorElement, aspectRatio) {
|
constructor(editorElement, aspectRatio) {
|
||||||
this._editor = editorElement;
|
this._editor = editorElement;
|
||||||
this.aspectRatio = aspectRatio;
|
this.aspectRatio = aspectRatio;
|
||||||
|
|
||||||
this._imgElement = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadImage(url) {
|
loadImage(url) {
|
||||||
this._imgElement = this._editor.querySelector(".editor-image");
|
const imgElement = new Image()
|
||||||
this._imgElement.src = url;
|
imgElement.classList.add("editor-image");
|
||||||
|
imgElement.src = url;
|
||||||
|
|
||||||
|
this._editor.replaceChildren(imgElement);
|
||||||
|
|
||||||
const that = this;
|
const that = this;
|
||||||
this._imgElement.addEventListener('load', (_) => {
|
imgElement.addEventListener('load', (_) => {
|
||||||
|
|
||||||
this._imgElement.style.left = (this._editor.clientWidth - this._imgElement.offsetWidth) / 2 + "px";
|
const size = {
|
||||||
this._imgElement.style.top = (this._editor.clientHeight - this._imgElement.offsetHeight) / 2 + "px";
|
width: imgElement.offsetWidth,
|
||||||
|
height: imgElement.offsetHeight
|
||||||
|
};
|
||||||
|
|
||||||
this._cutArea = new ResizableBox(this._editor, getRelativeClientRect(this._imgElement), {}, 4/3);
|
if (size.width > size.height * that.aspectRatio) {
|
||||||
|
size.width = size.height * that.aspectRatio;
|
||||||
|
} else {
|
||||||
|
size.height = size.width / that.aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
that._createSelectionBox(size.width, size.height);
|
||||||
|
|
||||||
document.querySelector("#theatergf-edit-save").style.visibility = "visible";
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
_createSelectionBox(width, height) {
|
||||||
|
const selector = document.createElement('div');
|
||||||
|
selector.classList.add('selector');
|
||||||
|
|
||||||
const relative_position = {
|
selector.style.width = (width - 1) + "px";
|
||||||
x: (this._cutSelector.offsetLeft + 1 - this._imgElement.offsetLeft) / this._imgElement.clientWidth,
|
selector.style.height = (height - 1) + "px";
|
||||||
y: (this._cutSelector.offsetTop + 1 - this._imgElement.offsetTop) / this._imgElement.clientHeight,
|
|
||||||
width: (this._cutSelector.clientWidth - 2) / this._imgElement.clientWidth,
|
|
||||||
height: (this._cutSelector.clientHeight - 2) / this._imgElement.clientHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapped_region = {
|
this._cutSelector = selector;
|
||||||
x: relative_position.x * this._imgElement.naturalWidth,
|
this._editor.appendChild(selector);
|
||||||
y: relative_position.y * this._imgElement.naturalHeight,
|
|
||||||
width: relative_position.width * this._imgElement.naturalWidth,
|
|
||||||
height: relative_position.height * this._imgElement.naturalHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(mapped_region)
|
this._cutArea = new ResizableBox(selector, width/height);
|
||||||
|
|
||||||
fetch(wpAPISettings.root + 'theatergf/gallery/v1/crop/new', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'X-WP-Nonce': wpAPISettings.nonce,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
img_id: 53,
|
|
||||||
x: mapped_region.x,
|
|
||||||
y: mapped_region.y,
|
|
||||||
width: mapped_region.width,
|
|
||||||
height: mapped_region.height
|
|
||||||
})
|
|
||||||
}).then((response) => response.json().then((json) => console.log(json))).catch((error) => console.log(error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +353,7 @@ class Editor {
|
||||||
|
|
||||||
jQuery(document).ready( ($) => {
|
jQuery(document).ready( ($) => {
|
||||||
let wp_file_selector_frame = null;
|
let wp_file_selector_frame = null;
|
||||||
let editor = new Editor(document.querySelector("#theatergf-editor"), 2/1);
|
let editor = new Editor(document.querySelector("#theatergf-editor"), 4/3);
|
||||||
|
|
||||||
$("#theatergf-select-image").on("click", (event) => {
|
$("#theatergf-select-image").on("click", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -374,17 +375,10 @@ jQuery(document).ready( ($) => {
|
||||||
wp_file_selector_frame.on('select', () => {
|
wp_file_selector_frame.on('select', () => {
|
||||||
const file = wp_file_selector_frame.state().get('selection').first().toJSON();
|
const file = wp_file_selector_frame.state().get('selection').first().toJSON();
|
||||||
|
|
||||||
console.log(file)
|
|
||||||
|
|
||||||
editor.loadImage(file.url);
|
editor.loadImage(file.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
wp_file_selector_frame.open();
|
wp_file_selector_frame.open();
|
||||||
})
|
})
|
||||||
|
|
||||||
$("#theatergf-edit-save").on("click", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
editor.save();
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,16 @@
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selector {
|
.selector {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: lightblue 1px solid;
|
border: blue 1px solid;
|
||||||
opacity: 50%;
|
|
||||||
|
|
||||||
/*top: 50%;
|
/*top: 50%;
|
||||||
left: 50%;*/
|
left: 50%;*/
|
||||||
|
|
@ -38,7 +40,7 @@
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|
||||||
border: lightblue 1px solid;
|
border: blue 1px solid;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/*transform: translate(-50%, -50%);*/
|
/*transform: translate(-50%, -50%);*/
|
||||||
|
|
@ -74,16 +76,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-button-row {
|
.image-edit-wrap {
|
||||||
|
aspect-ratio: 2 / 1;
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
width: 75%;
|
width: 75%;
|
||||||
|
height: 75%;
|
||||||
|
|
||||||
#theatergf-edit-save {
|
background-color: gray;
|
||||||
visibility: hidden;
|
|
||||||
|
#theatergf-image-editor {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#theatergf-image-editor-shadow {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace TheaterGF\Gallery\Backend;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/util.php';
|
|
||||||
|
|
||||||
require_once __DIR__ . '/endpoints/crop.php';
|
|
||||||
|
|
||||||
add_action( 'rest_api_init', function () {
|
|
||||||
$namespace = 'theatergf/gallery/v1';
|
|
||||||
|
|
||||||
$crop_controller = new Rest\CROP_Endpoints($namespace, 'crop');
|
|
||||||
$crop_controller->register_routes();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace TheaterGF\Gallery\Backend\Rest;
|
|
||||||
|
|
||||||
class CROP_Endpoints extends \WP_REST_Controller {
|
|
||||||
|
|
||||||
public function __construct( $namespace, $base_path ) {
|
|
||||||
$this->namespace = $namespace;
|
|
||||||
$this->rest_base = $base_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function register_routes() {
|
|
||||||
|
|
||||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/new', [
|
|
||||||
'methods' => \WP_REST_Server::CREATABLE,
|
|
||||||
'callback' => [ $this, 'create_item' ],
|
|
||||||
'permission_callback' => [ $this, 'create_item_permissions_check' ],
|
|
||||||
'args' => [
|
|
||||||
'img_id' => [
|
|
||||||
'required' => true,
|
|
||||||
'validate_callback' => function ( $param, $request, $key) { return wp_attachment_is_image($param); }
|
|
||||||
],
|
|
||||||
'x' => [
|
|
||||||
'required' => true,
|
|
||||||
'validate_callback' => function ( $param, $request, $key) { return is_numeric($param) && $param > 0; }
|
|
||||||
],
|
|
||||||
'y' => [
|
|
||||||
'required' => true,
|
|
||||||
'validate_callback' => function ( $param, $request, $key) { return is_numeric($param) && $param > 0; }
|
|
||||||
],
|
|
||||||
'width' => [
|
|
||||||
'required' => true,
|
|
||||||
'validate_callback' => function ( $param, $request, $key) { return is_numeric($param) && $param > 0; }
|
|
||||||
],
|
|
||||||
'height' => [
|
|
||||||
'required' => true,
|
|
||||||
'validate_callback' => function ( $param, $request, $key) { return is_numeric($param) && $param > 0; }
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create_item_permissions_check( $request ) {
|
|
||||||
|
|
||||||
if ( ! is_user_logged_in()) {
|
|
||||||
return new \WP_Error( 'unauthenticated', 'Log in to interact with this endpoint.', array( 'status' => 401 ));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! (is_user_logged_in() && current_user_can( 'edit_pages' )) ) {
|
|
||||||
return new \WP_Error( 'forbidden', 'No Permission for this endpoint.', array( 'status' => 403 ));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create_item( $request ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -34,5 +34,3 @@ add_action( 'init', 'TheaterGF\Gallery\block_init' );
|
||||||
if ( is_admin() ) {
|
if ( is_admin() ) {
|
||||||
require_once __DIR__ . '/src/admin/admin.php';
|
require_once __DIR__ . '/src/admin/admin.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/src/backend/backend.php';
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue