From fd84e1c9f829f90d3c7ee61f916fe186cb73671c Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Mon, 19 Oct 2020 19:59:54 +0200 Subject: [PATCH] Refactor crop editor into a proper class. --- public/js/crop_editor.js | 406 ++++++++++++++++++++------------------- 1 file changed, 204 insertions(+), 202 deletions(-) diff --git a/public/js/crop_editor.js b/public/js/crop_editor.js index e010d03..8e3884d 100644 --- a/public/js/crop_editor.js +++ b/public/js/crop_editor.js @@ -1,218 +1,220 @@ -function CropEditor(opt) { - this.opt = opt; +class CropEditor { + constructor(opt) { + this.opt = opt; - this.edit_crop_button = document.createElement("span"); - this.edit_crop_button.className = "btn"; - this.edit_crop_button.innerHTML = "Edit crop"; - this.edit_crop_button.addEventListener('click', this.show.bind(this)); + this.edit_crop_button = document.createElement("span"); + this.edit_crop_button.className = "btn"; + this.edit_crop_button.textContent = "Edit crop"; + this.edit_crop_button.addEventListener('click', this.show.bind(this)); - this.thumbnail_select = document.getElementById(opt.thumbnail_select_id); - this.thumbnail_select.addEventListener('change', this.toggleCropButton.bind(this)); - this.thumbnail_select.parentNode.insertBefore(this.edit_crop_button, this.thumbnail_select.nextSibling); + this.thumbnail_select = document.getElementById(opt.thumbnail_select_id); + this.thumbnail_select.addEventListener('change', this.toggleCropButton.bind(this)); + this.thumbnail_select.parentNode.insertBefore(this.edit_crop_button, this.thumbnail_select.nextSibling); - this.toggleCropButton(); -} - -CropEditor.prototype.buildContainer = function() { - this.container = document.createElement("div"); - this.container.id = "crop_editor"; - - this.position = document.createElement("div"); - this.position.className = "crop_position"; - this.container.appendChild(this.position); - - var source_x_label = document.createTextNode("Source X:"); - this.position.appendChild(source_x_label); - - this.source_x = document.createElement("input"); - this.source_x.addEventListener("keyup", this.positionBoundary.bind(this)); - this.position.appendChild(this.source_x); - - var source_y_label = document.createTextNode("Source Y:"); - this.position.appendChild(source_y_label); - - this.source_y = document.createElement("input"); - this.source_y.addEventListener("keyup", this.positionBoundary.bind(this)); - this.position.appendChild(this.source_y); - - var crop_width_label = document.createTextNode("Crop width:"); - this.position.appendChild(crop_width_label); - - this.crop_width = document.createElement("input"); - this.crop_width.addEventListener("keyup", this.positionBoundary.bind(this)); - this.position.appendChild(this.crop_width); - - var crop_height_label = document.createTextNode("Crop height:"); - this.position.appendChild(crop_height_label); - - this.crop_height = document.createElement("input"); - this.crop_height.addEventListener("keyup", this.positionBoundary.bind(this)); - this.position.appendChild(this.crop_height); - - this.save_button = document.createElement("span"); - this.save_button.className = "btn"; - this.save_button.innerHTML = "Save"; - this.save_button.addEventListener('click', this.save.bind(this)); - this.position.appendChild(this.save_button); - - this.abort_button = document.createElement("span"); - this.abort_button.className = "btn btn-red"; - this.abort_button.innerHTML = "Abort"; - this.abort_button.addEventListener('click', this.hide.bind(this)); - this.position.appendChild(this.abort_button); - - this.image_container = document.createElement("div"); - this.image_container.className = "crop_image_container"; - this.container.appendChild(this.image_container); - - this.crop_boundary = document.createElement("div"); - this.crop_boundary.id = "crop_boundary"; - this.image_container.appendChild(this.crop_boundary); - - this.original_image = document.createElement("img"); - this.original_image.id = "original_image"; - this.original_image.src = this.opt.original_image_src; - this.image_container.appendChild(this.original_image); - - this.parent = document.getElementById(this.opt.editor_container_parent_id); - this.parent.appendChild(this.container); -}; - -CropEditor.prototype.setInputValues = function() { - var current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset; - - if (typeof current.crop_region === "undefined") { - var source_ratio = this.original_image.naturalWidth / this.original_image.naturalHeight, - crop_ratio = current.crop_width / current.crop_height, - min_dim = Math.min(this.original_image.naturalWidth, this.original_image.naturalHeight); - - // Cropping from the centre? - if (current.crop_method === "c") { - // Crop vertically from the centre, using the entire width. - if (source_ratio < crop_ratio) { - this.crop_width.value = this.original_image.naturalWidth; - this.crop_height.value = Math.ceil(this.original_image.naturalWidth / crop_ratio); - this.source_x.value = 0; - this.source_y.value = Math.ceil((this.original_image.naturalHeight - this.crop_height.value) / 2); - } - // Crop horizontally from the centre, using the entire height. - else { - this.crop_width.value = Math.ceil(current.crop_width * this.original_image.naturalHeight / current.crop_height); - this.crop_height.value = this.original_image.naturalHeight; - this.source_x.value = Math.ceil((this.original_image.naturalWidth - this.crop_width.value) / 2); - this.source_y.value = 0; - } - } - // Cropping a top or bottom slice? - else { - // Can we actually take a top or bottom slice from the original image? - if (source_ratio < crop_ratio) { - this.crop_width.value = this.original_image.naturalWidth; - this.crop_height.value = Math.floor(this.original_image.naturalHeight / crop_ratio); - this.source_x.value = "0"; - this.source_y.value = current.crop_method.indexOf("t") !== -1 ? "0" : this.original_image.naturalHeight - this.crop_height.value; - } - // Otherwise, take a vertical slice from the centre. - else { - this.crop_width.value = Math.floor(this.original_image.naturalHeight * crop_ratio); - this.crop_height.value = this.original_image.naturalHeight; - this.source_x.value = Math.floor((this.original_image.naturalWidth - this.crop_width.value) / 2); - this.source_y.value = "0"; - } - } - } else { - var region = current.crop_region.split(','); - this.crop_width.value = region[0]; - this.crop_height.value = region[1]; - this.source_x.value = region[2]; - this.source_y.value = region[3]; - } -}; - -CropEditor.prototype.showContainer = function() { - this.container.style.display = "block"; - this.setInputValues(); - this.positionBoundary(); -} - -CropEditor.prototype.save = function() { - var current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset; - var payload = { - thumb_width: current.crop_width, - thumb_height: current.crop_height, - crop_method: current.crop_method, - crop_width: this.crop_width.value, - crop_height: this.crop_height.value, - source_x: this.source_x.value, - source_y: this.source_y.value - }; - var req = HttpRequest("post", this.opt.submitUrl + "?id=" + this.opt.asset_id + "&updatethumb", - "data=" + encodeURIComponent(JSON.stringify(payload)), function(response) { - this.opt.after_save(response); - this.hide(); - }.bind(this)); -}; - -CropEditor.prototype.show = function() { - if (typeof this.container === "undefined") { - this.buildContainer(); + this.toggleCropButton(); } - // Defer showing and positioning until image is loaded. - // !!! TODO: add a spinner in the mean time? - if (this.original_image.naturalWidth > 0) { - this.showContainer(); - } else { - this.original_image.addEventListener("load", function() { + buildContainer() { + this.container = document.createElement("div"); + this.container.id = "crop_editor"; + + this.position = document.createElement("div"); + this.position.className = "crop_position"; + this.container.appendChild(this.position); + + let source_x_label = document.createTextNode("Source X:"); + this.position.appendChild(source_x_label); + + this.source_x = document.createElement("input"); + this.source_x.addEventListener("keyup", this.positionBoundary.bind(this)); + this.position.appendChild(this.source_x); + + let source_y_label = document.createTextNode("Source Y:"); + this.position.appendChild(source_y_label); + + this.source_y = document.createElement("input"); + this.source_y.addEventListener("keyup", this.positionBoundary.bind(this)); + this.position.appendChild(this.source_y); + + let crop_width_label = document.createTextNode("Crop width:"); + this.position.appendChild(crop_width_label); + + this.crop_width = document.createElement("input"); + this.crop_width.addEventListener("keyup", this.positionBoundary.bind(this)); + this.position.appendChild(this.crop_width); + + let crop_height_label = document.createTextNode("Crop height:"); + this.position.appendChild(crop_height_label); + + this.crop_height = document.createElement("input"); + this.crop_height.addEventListener("keyup", this.positionBoundary.bind(this)); + this.position.appendChild(this.crop_height); + + this.save_button = document.createElement("span"); + this.save_button.className = "btn"; + this.save_button.textContent = "Save"; + this.save_button.addEventListener('click', this.save.bind(this)); + this.position.appendChild(this.save_button); + + this.abort_button = document.createElement("span"); + this.abort_button.className = "btn btn-red"; + this.abort_button.textContent = "Abort"; + this.abort_button.addEventListener('click', this.hide.bind(this)); + this.position.appendChild(this.abort_button); + + this.image_container = document.createElement("div"); + this.image_container.className = "crop_image_container"; + this.container.appendChild(this.image_container); + + this.crop_boundary = document.createElement("div"); + this.crop_boundary.id = "crop_boundary"; + this.image_container.appendChild(this.crop_boundary); + + this.original_image = document.createElement("img"); + this.original_image.id = "original_image"; + this.original_image.src = this.opt.original_image_src; + this.image_container.appendChild(this.original_image); + + this.parent = document.getElementById(this.opt.editor_container_parent_id); + this.parent.appendChild(this.container); + } + + setInputValues() { + let current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset; + + if (typeof current.crop_region === "undefined") { + let source_ratio = this.original_image.naturalWidth / this.original_image.naturalHeight, + crop_ratio = current.crop_width / current.crop_height, + min_dim = Math.min(this.original_image.naturalWidth, this.original_image.naturalHeight); + + // Cropping from the centre? + if (current.crop_method === "c") { + // Crop vertically from the centre, using the entire width. + if (source_ratio < crop_ratio) { + this.crop_width.value = this.original_image.naturalWidth; + this.crop_height.value = Math.ceil(this.original_image.naturalWidth / crop_ratio); + this.source_x.value = 0; + this.source_y.value = Math.ceil((this.original_image.naturalHeight - this.crop_height.value) / 2); + } + // Crop horizontally from the centre, using the entire height. + else { + this.crop_width.value = Math.ceil(current.crop_width * this.original_image.naturalHeight / current.crop_height); + this.crop_height.value = this.original_image.naturalHeight; + this.source_x.value = Math.ceil((this.original_image.naturalWidth - this.crop_width.value) / 2); + this.source_y.value = 0; + } + } + // Cropping a top or bottom slice? + else { + // Can we actually take a top or bottom slice from the original image? + if (source_ratio < crop_ratio) { + this.crop_width.value = this.original_image.naturalWidth; + this.crop_height.value = Math.floor(this.original_image.naturalHeight / crop_ratio); + this.source_x.value = "0"; + this.source_y.value = current.crop_method.indexOf("t") !== -1 ? "0" : this.original_image.naturalHeight - this.crop_height.value; + } + // Otherwise, take a vertical slice from the centre. + else { + this.crop_width.value = Math.floor(this.original_image.naturalHeight * crop_ratio); + this.crop_height.value = this.original_image.naturalHeight; + this.source_x.value = Math.floor((this.original_image.naturalWidth - this.crop_width.value) / 2); + this.source_y.value = "0"; + } + } + } else { + let region = current.crop_region.split(','); + this.crop_width.value = region[0]; + this.crop_height.value = region[1]; + this.source_x.value = region[2]; + this.source_y.value = region[3]; + } + } + + showContainer() { + this.container.style.display = "block"; + this.setInputValues(); + this.positionBoundary(); + } + + save() { + let current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset; + let payload = { + thumb_width: current.crop_width, + thumb_height: current.crop_height, + crop_method: current.crop_method, + crop_width: this.crop_width.value, + crop_height: this.crop_height.value, + source_x: this.source_x.value, + source_y: this.source_y.value + }; + let req = HttpRequest("post", this.opt.submitUrl + "?id=" + this.opt.asset_id + "&updatethumb", + "data=" + encodeURIComponent(JSON.stringify(payload)), function(response) { + this.opt.after_save(response); + this.hide(); + }.bind(this)); + } + + show() { + if (typeof this.container === "undefined") { + this.buildContainer(); + } + + // Defer showing and positioning until image is loaded. + // !!! TODO: add a spinner in the mean time? + if (this.original_image.naturalWidth > 0) { this.showContainer(); - }.bind(this)); + } else { + this.original_image.addEventListener("load", function() { + this.showContainer(); + }.bind(this)); + } } -}; -CropEditor.prototype.hide = function() { - this.container.style.display = "none"; -}; + hide() { + this.container.style.display = "none"; + } -CropEditor.prototype.addEvents = function(event) { - var drag_target = document.getElementById(opt.drag_target); - drag_target.addEventListener('dragstart', this.dragStart); - drag_target.addEventListener('drag', this.drag); - drag_target.addEventListener('dragend', this.dragEnd); -}; + addEvents(event) { + let drag_target = document.getElementById(opt.drag_target); + drag_target.addEventListener('dragstart', this.dragStart); + drag_target.addEventListener('drag', this.drag); + drag_target.addEventListener('dragend', this.dragEnd); + } -CropEditor.prototype.dragStart = function(event) { - console.log(event); - event.preventDefault(); -}; + dragStart(event) { + console.log(event); + event.preventDefault(); + } -CropEditor.prototype.dragEnd = function(event) { - console.log(event); -}; + dragEnd(event) { + console.log(event); + } -CropEditor.prototype.drag = function(event) { - console.log(event); -}; + drag(event) { + console.log(event); + } -CropEditor.prototype.toggleCropButton = function() { - var current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset; - this.edit_crop_button.style.display = typeof current.crop_method === "undefined" ? "none" : ""; -}; + toggleCropButton() { + let current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset; + this.edit_crop_button.style.display = typeof current.crop_method === "undefined" ? "none" : ""; + } -CropEditor.prototype.positionBoundary = function(event) { - var source_x = parseInt(this.source_x.value), - source_y = parseInt(this.source_y.value), - crop_width = parseInt(this.crop_width.value), - crop_height = parseInt(this.crop_height.value), - real_width = this.original_image.naturalWidth, - real_height = this.original_image.naturalHeight, - scaled_width = this.original_image.clientWidth, - scaled_height = this.original_image.clientHeight; + positionBoundary(event) { + let source_x = parseInt(this.source_x.value), + source_y = parseInt(this.source_y.value), + crop_width = parseInt(this.crop_width.value), + crop_height = parseInt(this.crop_height.value), + real_width = this.original_image.naturalWidth, + real_height = this.original_image.naturalHeight, + scaled_width = this.original_image.clientWidth, + scaled_height = this.original_image.clientHeight; - var width_scale = scaled_width / real_width, - height_scale = scaled_height / real_height; + let width_scale = scaled_width / real_width, + height_scale = scaled_height / real_height; - crop_boundary.style.left = (this.source_x.value) * width_scale + "px"; - crop_boundary.style.top = (this.source_y.value) * height_scale + "px"; - crop_boundary.style.width = (this.crop_width.value) * width_scale + "px"; - crop_boundary.style.height = (this.crop_height.value) * height_scale + "px"; -}; + crop_boundary.style.left = (this.source_x.value) * width_scale + "px"; + crop_boundary.style.top = (this.source_y.value) * height_scale + "px"; + crop_boundary.style.width = (this.crop_width.value) * width_scale + "px"; + crop_boundary.style.height = (this.crop_height.value) * height_scale + "px"; + } +} \ No newline at end of file