ORIENT/modules/cms/widgets/mediamanager/assets/js/mediamanager.imagecroppopup.js

474 lines
17 KiB
JavaScript

/*
* Media manager image editor popup
*/
+function ($) { "use strict";
if ($.oc.mediaManager === undefined)
$.oc.mediaManager = {}
var Base = $.oc.foundation.base,
BaseProto = Base.prototype
var MediaManagerImageCropPopup = function(path, options) {
this.$popupRootElement = null
this.$popupElement = null
this.selectionSizeLabel = null
this.imageArea = null
this.hRulerHolder = null
this.vRulerHolder = null
this.rulersVisible = false
this.prevScrollTop = 0
this.prevScrollLeft = 0
this.jCrop = null
this.options = $.extend({}, MediaManagerImageCropPopup.DEFAULTS, options)
this.path = path
Base.call(this)
this.init()
this.show()
}
MediaManagerImageCropPopup.prototype = Object.create(BaseProto)
MediaManagerImageCropPopup.prototype.constructor = MediaManagerImageCropPopup
MediaManagerImageCropPopup.prototype.dispose = function() {
this.unregisterHandlers()
this.removeAttachedControls()
this.$popupRootElement.remove()
this.$popupRootElement = null
this.$popupElement = null
this.selectionSizeLabel = null
this.imageArea = null
this.hRulerHolder = null
this.vRulerHolder = null
BaseProto.dispose.call(this)
}
MediaManagerImageCropPopup.prototype.init = function() {
if (this.options.alias === undefined)
throw new Error('Media Manager image crop popup option "alias" is not set.')
this.$popupRootElement = $('<div/>')
this.registerHandlers()
}
MediaManagerImageCropPopup.prototype.show = function() {
var data = {
path: this.path
}
this.$popupRootElement.popup({
extraData: data,
size: 'adaptive',
adaptiveHeight: true,
handler: this.options.alias + '::onLoadImageCropPopup',
zIndex: 1200 // Media Manager can be opened in a popup, so this new popup should have a higher z-index
})
}
MediaManagerImageCropPopup.prototype.registerHandlers = function() {
this.$popupRootElement.one('hide.oc.popup', this.proxy(this.onPopupHidden))
this.$popupRootElement.one('shown.oc.popup', this.proxy(this.onPopupShown))
}
MediaManagerImageCropPopup.prototype.unregisterHandlers = function() {
this.$popupElement.off('change', '[data-control="selection-mode"]', this.proxy(this.onSelectionModeChanged))
this.$popupElement.off('click', '[data-command]', this.proxy(this.onCommandClick))
this.$popupElement.off('shown.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupShown))
this.$popupElement.off('hidden.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupHidden))
if (this.rulersVisible) {
var $cropToolRoot = this.$popupElement.find('[data-control=media-manager-crop-tool]')
this.imageArea.removeEventListener('scroll', this.proxy(this.onImageScroll))
}
this.getWidthInput().off('change', this.proxy(this.onSizeInputChange))
this.getHeightInput().off('change', this.proxy(this.onSizeInputChange))
}
MediaManagerImageCropPopup.prototype.removeAttachedControls = function() {
if (this.$popupElement) {
// Note - the controls are destroyed and removed from DOM. If they're just destroyed,
// the JS plugins could be re-attached to them on window.onresize. -ab
this.$popupElement.find('[data-control="selection-mode"]').select2('destroy').remove()
this.$popupElement.find('[data-control=toolbar]').toolbar('dispose').remove()
this.jCrop.destroy()
}
this.jCrop = null
}
MediaManagerImageCropPopup.prototype.hide = function() {
if (this.$popupElement)
this.$popupElement.trigger('close.oc.popup')
}
MediaManagerImageCropPopup.prototype.getSelectionMode = function() {
return this.$popupElement.find('[data-control="selection-mode"]').val()
}
MediaManagerImageCropPopup.prototype.initRulers = function() {
if (!Modernizr.csstransforms)
return
var $cropToolRoot = this.$popupElement.find('[data-control=media-manager-crop-tool]'),
width = $cropToolRoot.data('image-width'),
height = $cropToolRoot.data('image-height')
if (!width || !height)
return
if ($cropToolRoot.width() > width)
width = $(window).width()
if ($cropToolRoot.height() > height)
height = $(window).height()
$cropToolRoot.find('.ruler-container').removeClass('hide')
$cropToolRoot.addClass('has-rulers')
var $hRuler = $cropToolRoot.find('[data-control=h-ruler]'),
$vRuler = $cropToolRoot.find('[data-control=v-ruler]'),
hTicks = width / 40 + 1,
vTicks = height / 40 + 1
this.createRulerTicks($hRuler, hTicks)
this.createRulerTicks($vRuler, vTicks)
this.rulersVisible = true
this.imageArea.addEventListener('scroll', this.proxy(this.onImageScroll))
this.hRulerHolder = $cropToolRoot.find('.ruler-container.horizontal .layout-relative').get(0)
this.vRulerHolder = $cropToolRoot.find('.ruler-container.vertical .layout-relative').get(0)
}
MediaManagerImageCropPopup.prototype.createRulerTicks = function($rulerElement, count) {
var list = document.createElement('ul')
for (var i=0; i <= count; i++) {
var li = document.createElement('li')
li.textContent = i*40
list.appendChild(li)
}
$rulerElement.append(list)
}
MediaManagerImageCropPopup.prototype.initJCrop = function() {
this.jCrop = $.Jcrop($(this.imageArea).find('img').get(0), {
shade: true,
onChange: this.proxy(this.onSelectionChanged)
})
}
MediaManagerImageCropPopup.prototype.fixDimensionValue = function(value) {
var result = value.replace(/[^0-9]+/, '')
if (!result.length)
result = 200
if (result == '0')
result = 1
return result
}
MediaManagerImageCropPopup.prototype.getWidthInput = function() {
return this.$popupElement.find('[data-control="crop-width-input"]')
}
MediaManagerImageCropPopup.prototype.getHeightInput = function() {
return this.$popupElement.find('[data-control="crop-height-input"]')
}
MediaManagerImageCropPopup.prototype.applySelectionMode = function() {
if (!this.jCrop)
return
var $widthInput = this.getWidthInput(),
$heightInput = this.getHeightInput(),
width = this.fixDimensionValue($widthInput.val()),
height = this.fixDimensionValue($heightInput.val()),
mode = this.getSelectionMode()
switch (mode) {
case 'fixed-ratio' :
this.jCrop.setOptions({
aspectRatio: width/height,
minSize: [0, 0],
maxSize: [0, 0],
allowResize: true
})
break
case 'fixed-size' :
this.jCrop.setOptions({
aspectRatio: 0,
minSize: [width, height],
maxSize: [width, height],
allowResize: false
})
break
case 'normal' :
this.jCrop.setOptions({
aspectRatio: 0,
minSize: [0, 0],
maxSize: [0, 0],
allowResize: true
})
break
}
}
MediaManagerImageCropPopup.prototype.cropAndInsert = function() {
var data = {
img: $(this.imageArea).find('img').attr('src'),
selection: this.jCrop.tellSelect()
}
$.oc.stripeLoadIndicator.show()
this.$popupElement.find('form').request(
this.options.alias+'::onCropImage', {
data: data
}
).always(function() {
$.oc.stripeLoadIndicator.hide()
}).done(this.proxy(this.onImageCropped))
}
MediaManagerImageCropPopup.prototype.onImageCropped = function(response) {
this.hide()
if (this.options.onDone !== undefined)
this.options.onDone(response.result)
}
MediaManagerImageCropPopup.prototype.showResizePopup = function() {
this.$popupElement.find('button[data-command=resize]').popup({
content: this.$popupElement.find('[data-control="resize-template"]').html(),
zIndex: 1220
})
}
MediaManagerImageCropPopup.prototype.onResizePopupShown = function(ev, button, popup) {
var $popup = $(popup),
$widthControl = $popup.find('input[name=width]'),
$heightControl = $popup.find('input[name=height]'),
imageWidth = this.fixDimensionValue(this.$popupElement.find('input[data-control=dimension-width]').val()),
imageHeight = this.fixDimensionValue(this.$popupElement.find('input[data-control=dimension-height]').val())
$widthControl.val(imageWidth)
$heightControl.val(imageHeight)
$widthControl.focus()
$popup.on('submit.media', 'form', this.proxy(this.onResizeSubmit))
$widthControl.on('keyup.media', this.proxy(this.onResizeDimensionKeyUp))
$heightControl.on('keyup.media', this.proxy(this.onResizeDimensionKeyUp))
$widthControl.on('change.media', this.proxy(this.onResizeDimensionChanged))
$heightControl.on('change.media', this.proxy(this.onResizeDimensionChanged))
}
MediaManagerImageCropPopup.prototype.onResizePopupHidden = function(ev, button, popup) {
var $popup = $(popup),
$widthControl = $popup.find('input[name=width]'),
$heightControl = $popup.find('input[name=height]')
$popup.off('.media', 'form')
$widthControl.off('.media')
$heightControl.off('.media')
}
MediaManagerImageCropPopup.prototype.onResizeDimensionKeyUp = function(ev) {
var $target = $(ev.target),
targetValue = this.fixDimensionValue($target.val()),
otherDimensionName = $target.attr('name') == 'width' ? 'height' : 'width',
$otherInput = $target.closest('form').find('input[name='+otherDimensionName+']'),
ratio = this.$popupElement.find('[data-control=original-ratio]').val(),
value = otherDimensionName == 'height' ? targetValue / ratio : targetValue * ratio
$otherInput.val(Math.round(value))
}
MediaManagerImageCropPopup.prototype.onResizeDimensionChanged = function(ev) {
var $target = $(ev.target)
$target.val(this.fixDimensionValue($target.val()))
}
MediaManagerImageCropPopup.prototype.onResizeSubmit = function(ev) {
var data = {
cropSessionKey: this.$popupElement.find('input[name=cropSessionKey]').val(),
path: this.$popupElement.find('input[name=path]').val()
}
$.oc.stripeLoadIndicator.show()
$(ev.target).request(this.options.alias+'::onResizeImage', {
data: data
}).always(function() {
$.oc.stripeLoadIndicator.hide()
}).done(this.proxy(this.imageResized))
ev.preventDefault()
return false
}
MediaManagerImageCropPopup.prototype.imageResized = function(response) {
this.$popupElement.find('button[data-command=resize]').popup('hide')
this.updateImage(response.url, response.dimensions[0], response.dimensions[1])
}
MediaManagerImageCropPopup.prototype.updateImage = function(url, width, hegiht) {
this.jCrop.destroy()
this.$popupElement.find('span[data-label=width]').text(width)
this.$popupElement.find('span[data-label=height]').text(hegiht)
this.$popupElement.find('input[data-control=dimension-width]').val(width)
this.$popupElement.find('input[data-control=dimension-height]').val(hegiht)
var $imageArea = $(this.imageArea)
$imageArea.find('img').remove()
var $img = $('<img>').attr('src', url)
$img.one('load', this.proxy(this.initJCrop))
$imageArea.append($img)
this.imageArea.scrollTop = 0
this.imageArea.scrollLeft = 0
this.onImageScroll()
}
MediaManagerImageCropPopup.prototype.undoResizing = function() {
this.updateImage(
this.$popupElement.find('input[data-control=original-url]').val(),
this.$popupElement.find('input[data-control=original-width]').val(),
this.$popupElement.find('input[data-control=original-height]').val()
)
}
MediaManagerImageCropPopup.prototype.updateSelectionSizeLabel = function(width, height) {
if (width == 0 && height == 0) {
this.selectionSizeLabel.setAttribute('class', 'hide')
return
}
this.selectionSizeLabel.setAttribute('class', '')
this.selectionSizeLabel.querySelector('[data-label=selection-width]').textContent = width
this.selectionSizeLabel.querySelector('[data-label=selection-height]').textContent = height
}
// EVENT HANDLERS
// ============================
MediaManagerImageCropPopup.prototype.onPopupHidden = function(event, element, popup) {
this.$popupElement.find('form').request(this.options.alias+'::onEndCroppingSession')
// Release clickedElement reference inside redactor.js
// If we don't do it, the image editor popup DOM elements
// won't be removed from the memory.
$(document).trigger('mousedown')
this.dispose()
}
MediaManagerImageCropPopup.prototype.onPopupShown = function(event, element, popup) {
this.$popupElement = popup
this.$popupElement.on('change', '[data-control="selection-mode"]', this.proxy(this.onSelectionModeChanged))
this.$popupElement.on('click', '[data-command]', this.proxy(this.onCommandClick))
this.$popupElement.on('shown.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupShown))
this.$popupElement.on('hidden.oc.popup', 'button[data-command=resize]', this.proxy(this.onResizePopupHidden))
this.imageArea = popup.find('[data-control=media-manager-crop-tool]').get(0).querySelector('.image_area')
this.selectionSizeLabel = popup.find('[data-label="selection-size"]').get(0)
this.getWidthInput().on('change', this.proxy(this.onSizeInputChange))
this.getHeightInput().on('change', this.proxy(this.onSizeInputChange))
this.initRulers()
this.initJCrop()
}
MediaManagerImageCropPopup.prototype.onSelectionModeChanged = function() {
var mode = this.getSelectionMode(),
$widthInput = this.getWidthInput(),
$heightInput = this.getHeightInput()
if (mode === 'normal') {
$widthInput.attr('disabled', 'disabled')
$heightInput.attr('disabled', 'disabled')
} else {
$widthInput.removeAttr('disabled')
$heightInput.removeAttr('disabled')
$widthInput.val(this.fixDimensionValue($widthInput.val()))
$heightInput.val(this.fixDimensionValue($heightInput.val()))
}
this.applySelectionMode()
}
MediaManagerImageCropPopup.prototype.onImageScroll = function() {
var scrollTop = this.imageArea.scrollTop,
scrollLeft = this.imageArea.scrollLeft
if (this.prevScrollTop != scrollTop) {
this.prevScrollTop = scrollTop
this.vRulerHolder.scrollTop = scrollTop
}
if (this.prevScrollLeft != scrollLeft) {
this.prevScrollLeft = scrollLeft
this.hRulerHolder.scrollLeft = scrollLeft
}
}
MediaManagerImageCropPopup.prototype.onSizeInputChange = function(ev) {
var $target = $(ev.target)
$target.val(this.fixDimensionValue($target.val()))
this.applySelectionMode()
}
MediaManagerImageCropPopup.prototype.onCommandClick = function(ev) {
var command = $(ev.currentTarget).data('command')
switch (command) {
case 'insert' :
this.cropAndInsert()
break
case 'resize' :
this.showResizePopup()
break
case 'undo-resizing' :
this.undoResizing()
break
}
}
MediaManagerImageCropPopup.prototype.onSelectionChanged = function(c) {
this.updateSelectionSizeLabel(c.w, c.h)
}
MediaManagerImageCropPopup.DEFAULTS = {
alias: undefined,
onDone: undefined
}
$.oc.mediaManager.imageCropPopup = MediaManagerImageCropPopup
}(window.jQuery);