function CropEditor(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.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.parent.action + "?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(); } // 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() { this.showContainer(); }.bind(this)); } }; CropEditor.prototype.hide = function() { 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); }; CropEditor.prototype.dragStart = function(event) { console.log(event); event.preventDefault(); }; CropEditor.prototype.dragEnd = function(event) { console.log(event); }; CropEditor.prototype.drag = function(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" : ""; }; 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; var 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"; };