/*global documents: true define: true*/
/*
* Aloha Image Plugin - Allow image manipulation in Aloha Editor
*
* Author & Copyright (c) 2013 Gentics Software GmbH
* aloha-sales@gentics.com
* Contributors
* Johannes Schüth - http://jotschi.de
* Nicolas karageuzian - http://nka.me/
* Benjamin Athur Lupton - http://www.balupton.com/
* Thomas Lete
* Nils Dehl
* Christopher Hlubek
* Edward Tsech
* Haymo Meran
* Martin Schönberger
*
* Licensed under the terms of http://www.aloha-editor.org/license.php
*/
define([
// js
'jquery',
'aloha/plugin',
'image/image-floatingMenu',
'i18n!aloha/nls/i18n',
'i18n!image/nls/i18n',
'jqueryui',
'image/vendor/jcrop/jquery.jcrop.min',
'image/vendor/mousewheel/mousewheel'
], function AlohaImagePlugin(
aQuery,
Plugin,
ImageFloatingMenu,
i18nCore,
i18n
){
'use strict';
var jQuery = aQuery;
var $ = aQuery;
var GENTICS = window.GENTICS;
var Aloha = window.Aloha;
var resizing = false;
// Attributes manipulation utilities
// Aloha team may want to factorize, it could be useful for other plugins
// Prototypes
String.prototype.toInteger = String.prototype.toInteger || function () {
return parseInt(String(this).replace(/px$/, '') || 0, 10);
};
String.prototype.toFloat = String.prototype.toInteger || function () {
return parseFloat(String(this).replace(/px$/, '') || 0, 10);
};
Number.prototype.toInteger = Number.prototype.toInteger || String.prototype.toInteger;
Number.prototype.toFloat = Number.prototype.toFloat || String.prototype.toFloat;
// Insert jQuery Prototypes
jQuery.extend(true, jQuery.fn, {
increase: jQuery.fn.increase || function (attr) {
var obj = jQuery(this), value, newValue;
if (!obj.length) {
return obj;
}
value = obj.css(attr).toFloat();
newValue = Math.round((value || 1) * 1.2);
// when value is 2, won't increase
if (value === newValue) {
newValue++;
}
obj.css(attr, newValue);
return obj;
},
decrease: jQuery.fn.decrease || function (attr) {
var obj = jQuery(this), value, newValue;
// Check
if (!obj.length) {
return obj;
}
// Calculate
value = obj.css(attr).toFloat();
newValue = Math.round((value || 0) * 0.8);
// Apply
if (value === newValue && newValue > 0) {
// when value is 2, won't increase
newValue--;
}
obj.css(attr, newValue);
// Chain
return obj;
}
});
// Create and register Image Plugin
return Plugin.create('image', {
defaultSettings: {
'maxWidth': 1600,
'minWidth': 3,
'maxHeight': 1200,
'minHeight': 3,
// This setting will manually correct values that are out of bounds
'autoCorrectManualInput': true,
// This setting will define a fixed aspect ratio for all resize actions
'fixedAspectRatio' : false,
// When enabled this setting will order the plugin to automatically resize images to given bounds
'autoResize': false,
//Image manipulation options - ONLY in default config section
ui: {
meta : true, // If imageResizeWidth and imageResizeHeight are displayed, then you will want to set this to true, so that the width and height text fields are updated automatically.
crop : true, // If imageCropButton is displayed, then you have to enable this.
resizable : true // Resizable ui-drag image
},
handles : 'ne, se, sw, nw', // set handles for resize
/**
* Crop callback is triggered after the user clicked accept to accept his crop
* @param image jquery image object reference
* @param props cropping properties
*/
onCropped: function ($image, props) {
Aloha.Log.info('Default onCropped invoked', $image, props);
},
/**
* Reset callback is triggered before the internal reset procedure is applied
* if this function returns true, then the reset has been handled by the callback
* which means that no other reset will be applied
* if false is returned the internal reset procedure will be applied
* @param image jquery image object reference
* @return true if a reset has been applied, false otherwise
*/
onReset: function ($image) {
Aloha.Log.info('Default onReset invoked', $image);
return false;
},
/**
* Example callback method which gets called while the resize process is being executed.
*/
onResize: function ($image) {
Aloha.Log.info('Default onResize invoked', $image);
},
/**
* Resize callback is triggered after the internal resize procedure is applied.
*/
onResized: function ($image) {
Aloha.Log.info('Default onResized invoked', $image);
}
},
/**
* Internal callback hook which gets invoked when cropping has been finished
*/
_onCropped: function ($image, props) {
$('body').trigger('aloha-image-cropped', [$image, props]);
// After successful cropping, the aspect ratio value has to recalculated
if (this.keepAspectRatio) {
this.aspectRatioValue = this.imageObj.width() / this.imageObj.height();
}
// Call the custom onCropped function
this.onCropped($image, props);
},
/**
* Internal callback hook which gets invoked when resetting images
*/
_onReset: function ($image) {
// No default behaviour defined besides event triggering
$('body').trigger('aloha-image-reset', $image);
$('#' + this.ui.imgResizeHeightField.getInputId()).val($image.height());
$('#' + this.ui.imgResizeWidthField.getInputId()).val($image.width());
// Call the custom resize function
return this.onReset($image);
},
/**
* Internal callback hook which gets invoked while the image is being resized
*/
_onResize: function ($image) {
// No default behaviour defined besides event triggering
$('body').trigger('aloha-image-resize', $image);
$('#' + this.ui.imgResizeHeightField.getInputId()).val($image.height());
$('#' + this.ui.imgResizeWidthField.getInputId()).val($image.width());
// Call the custom resize function
this.onResize($image);
},
/**
* Internal callback hook which gets invoked when the current resizing action has stopped
*/
_onResized: function ($image) {
$('body').trigger('aloha-image-resized', $image);
$('#' + this.ui.imgResizeHeightField.getInputId()).val($image.height());
$('#' + this.ui.imgResizeWidthField.getInputId()).val($image.width());
// Call the custom resize function
this.onResized($image);
},
/**
* The image that is currently edited
*/
imageObj: null,
/**
* The Jcrop API reference
* this is needed to be able to destroy the cropping frame later on
* the variable is linked to the api object whilst cropping, or set to null otherwise
* strange, but done as documented http://deepliquid.com/content/Jcrop_API.html
*/
jcAPI: null,
/**
* State variable for the aspect ratio toggle feature
*/
keepAspectRatio: false,
/**
* Variable that will hold the value of the aspect ratio. This ratio will be used once startResize has been called
*/
aspectRatioValue: false,
/**
* This will contain an image's original properties to be able to undo previous settings
*
* when an image is clicked for the first time, a new object will be added to the array
* {
* obj : [the image object reference],
* src : [the original src url],
* width : [initial width],
* height : [initial height]
* }
*
* when an image is clicked the second time, the array will be checked for the image object
* reference, to prevent double entries
*/
restoreProps: [],
/**
* the defined object types to be used for this instance
*/
objectTypeFilter: [],
/**
* Plugin initialization method
*/
init: function () {
var plugin = this;
var imagePluginUrl = Aloha.getPluginUrl('image');
if ( typeof this.settings.objectTypeFilter != 'undefined' ) {
this.objectTypeFilter = this.settings.objectTypeFilter;
}
// Extend the default settings with the custom ones (done by default)
plugin.config = plugin.defaultSettings;
plugin.settings = jQuery.extend(true, plugin.defaultSettings, plugin.settings);
// Determine the flag and the value of the aspect ratio depending on settings
if ( typeof this.settings.fixedAspectRatio === 'number' ) {
this.aspectRatioValue = this.settings.fixedAspectRatio;
plugin.keepAspectRatio = true;
} else {
if ((plugin.settings.fixedAspectRatio) === true) {
plugin.keepAspectRatio = true;
} else {
plugin.keepAspectRatio = false;
}
}
plugin.initializeUI();
plugin.bindInteractions();
plugin.subscribeEvents();
},
/**
* Create buttons
*/
initializeUI: function () {
var that = this;
this.ui = new ImageFloatingMenu();
this.ui.init(this);
},
/**
* Bind plugin interactions
*/
bindInteractions: function () {
var plugin = this;
if (plugin.settings.ui.resizable) {
try {
// this will disable mozillas image resizing facilities
document.execCommand('enableObjectResizing', false, false);
} catch (e) {
Aloha.Log.info(e, 'Could not disable enableObjectResizing');
// this is just for internet explorer, which will not support disabling enableObjectResizing
}
}
if (plugin.settings.ui.meta) {
// update image object when src changes
plugin.ui.imgSrcField.addListener('keyup', function (event) {
plugin.srcChange();
});
plugin.ui.imgSrcField.addListener('blur', function (event) {
// TODO remove image or do something useful if the user leaves the
// image without defining a valid image src
var img = jQuery(plugin.ui.imgSrcField.getTargetObject());
if (img.attr('src') === '') {
img.remove();
} // image removal when src field is blank
});
}
// Override the default method by using the given one
if (plugin.settings.onCropped && typeof plugin.settings.onCropped === "function") {
plugin.onCropped = plugin.settings.onCropped;
}
// Override the default method by using the given one
if (plugin.settings.onReset && typeof plugin.settings.onReset === "function") {
plugin.onReset = plugin.settings.onReset;
}
// Override the default method by using the given one
if (plugin.settings.onResized && typeof plugin.settings.onResized === "function") {
plugin.onResized = plugin.settings.onResized;
}
// Override the default method by using the given one
if (plugin.settings.onResize && typeof plugin.settings.onResize === "function") {
plugin.onResize = this.settings.onResize;
}
},
/**
* Subscribe to Aloha events and DragAndDropPlugin Event
*/
subscribeEvents: function () {
var plugin = this;
var config = this.settings;
jQuery('img').filter(config.globalselector).unbind();
jQuery('img').filter(config.globalselector).click(function (event) {
plugin.clickImage(event);
});
Aloha.bind('aloha-drop-files-in-editable', function (event, data) {
var img, len = data.filesObjs.length, fileObj, config;
while (--len >= 0) {
fileObj = data.filesObjs[len];
if (fileObj.file.type.match(/image\//)) {
config = plugin.getEditableConfig(data.editable);
// Prepare
img = jQuery('');
img.css({
"max-width": that.maxWidth,
"max-height": that.maxHeight
});
img.attr('id', fileObj.id);
if (typeof fileObj.src === 'undefined') {
img.attr('src', fileObj.data);
//fileObj.src = fileObj.data ;
} else {
img.attr('src', fileObj.src);
}
GENTICS.Utils.Dom.insertIntoDOM(img, data.range, jQuery(Aloha.activeEditable.obj));
}
}
});
/*
* Add the event handler for selection change
*/
Aloha.bind('aloha-selection-changed', function (event, rangeObject, originalEvent) {
var config, foundMarkup;
if (originalEvent && originalEvent.target) {
// Check if the element is currently being resized
if (plugin.settings.ui.resizable && !jQuery(originalEvent.target).hasClass('ui-resizable-handle')) {
plugin.endResize();
plugin.imageObj = null;
Aloha.trigger('aloha-image-unselected');
}
}
if (Aloha.activeEditable !== null) {
foundMarkup = plugin.findImgMarkup(rangeObject);
config = plugin.getEditableConfig(Aloha.activeEditable.obj);
if (typeof config !== 'undefined') {
plugin.ui._insertImageButton.show();
} else {
plugin.ui._insertImageButton.hide();
return;
}
// Enable image specific ui components if the element is an image
if (foundMarkup) { // TODO : this is always null (below is dead code, moving it to clickImage)
plugin.ui._insertImageButton.show();
plugin.ui.setScope();
if (plugin.settings.ui.meta) {
plugin.ui.imgSrcField.setTargetObject(foundMarkup, 'src');
plugin.ui.imgTitleField.setTargetObject(foundMarkup, 'title');
}
plugin.ui.imgSrcField.foreground();
plugin.ui.imgSrcField.focus();
} else {
if (plugin.settings.ui.meta) {
plugin.ui.imgSrcField.setTargetObject(null);
}
}
// TODO this should not be necessary here!
plugin.ui.doLayout();
}
});
Aloha.bind('aloha-editable-created', function (event, editable) {
try {
// this disables mozillas image resizing facilities
document.execCommand('enableObjectResizing', false, false);
} catch (e) {
Aloha.Log.info(e, 'Could not disable enableObjectResizing');
// this is just for other browsers, which do not support disabling enableObjectResizing
}
// Inital click on images will be handled here
// editable.obj.find('img').attr('_moz_resizing', false);
// editable.obj.find('img').contentEditable(false);
editable.obj.delegate('img', 'mouseup', function (event) {
if (!resizing) {
plugin.clickImage(event);
event.stopPropagation();
}
});
});
plugin._subscribeToResizeFieldEvents();
},
/**
* Automatically resize the image to fit into defined bounds.
* @param doScaleUp if true, small images are scaled up to fit minimum size
*/
autoResize: function(doScaleUp) {
// @todo handle ratio mismatches (eg 4:3 is set but image is 16:9 --> image needs to be cut)
var that = this;
var widthField = jQuery("#" + that.ui.imgResizeWidthField.getInputId());
var heightField = jQuery("#" + that.ui.imgResizeHeightField.getInputId());
var width = that.imageObj.width();
var height = that.imageObj.height();
var resize = false;
// Only normalize the field values if the image exceeds the defined bounds
if (width < that.settings.minWidth ||
width > that.settings.maxWidth ||
height < that.settings.minHeight ||
height > that.settings.maxHeight) {
resize = true;
}
var aspectRatio = width / height;
if (resize) {
if (width > that.settings.maxWidth) {
width = that.settings.maxWidth;
height = width / aspectRatio;
}
if (height > that.settings.maxHeight) {
height = that.settings.maxHeight;
width = height * aspectRatio;
}
if ((width < that.settings.minWidth) && doScaleUp) {
width = that.settings.minWidth;
height = width / aspectRatio;
}
if ((height < that.settings.minHeight) && doScaleUp) {
height = that.settings.minHeight;
width = width * aspectRatio;
}
widthField.val(width);
heightField.val(height);
that.setSizeByFieldValue();
return true;
}
return false;
},
/**
* Toggle the keep aspect ratio functionality
*/
toggleKeepAspectRatio: function() {
this.keepAspectRatio = !this.keepAspectRatio;
if (typeof this.jcAPI !== 'undefined' && this.jcAPI !== null) {
//toggling keepaspectratio during crop is deactivated until implemented
//this.ui._imageCnrRatioButton.setState(false);
} else {
this.endResize();
if (!this.keepAspectRatio) {
this.aspectRatioValue = false;
} else {
// If no fixed aspect ratio was given a new start aspect ratio is calculated
// that will be used for the next startResize action
if ( typeof this.settings.fixedAspectRatio !== 'number' ) {
this.aspectRatioValue = this.imageObj.width() / this.imageObj.height();
} else {
this.aspectRatioValue = this.settings.fixedAspectRatio;
}
}
this.startResize();
}
},
/**
* Bind interaction events that are invoked on the resize fields
*/
_subscribeToResizeFieldEvents: function () {
var plugin = this;
/**
* Handle the keyup event on the field
*/
function handleKeyUpEventOnField(e) {
// Load the max/min from the data properties of this event
var minValue = e.data.minValue;
var maxValue = e.data.maxValue;
var fieldName = e.data.fieldName;
// Allow backspace and delete
if (e.keyCode === 8 || e.keyCode === 46) {
// Only resize if field values are ok
if (plugin._updateFields(fieldName, $(this).val(), false)) {
// Check if we are currently in cropping mode
if (typeof plugin.jcAPI !== 'undefined' && plugin.jcAPI !== null) {
plugin.setCropAreaByFieldValue();
} else {
plugin.setSizeByFieldValue();
}
}
// 0-9 keys
} else if (e.keyCode <= 57 && e.keyCode >= 48 || e.keyCode <= 105 && e.keyCode >= 96 ) {
// Only resize if field values are ok
if (plugin._updateFields(fieldName, $(this).val(), false)) {
// Check if we are currently in cropping mode
if (typeof plugin.jcAPI !== 'undefined' && plugin.jcAPI !== null) {
plugin.setCropAreaByFieldValue();
} else {
plugin.setSizeByFieldValue();
}
}
} else {
var delta = 0;
if (e.keyCode === 38 || e.keyCode === 107) {
delta = +1;
} else if (e.keyCode === 40 || e.keyCode === 109) {
delta = -1;
}
// Handle key combinations
if (e.shiftKey || e.metaKey || e.ctrlKey) {
delta = delta * 10;
}
var isDecrement = false;
if (delta < 0) {
isDecrement = true;
}
var newValue = parseInt($(this).val(), 10) + delta;
// Only resize if field values are ok
if (plugin._updateFields(fieldName, newValue, isDecrement)) {
// Check if we are currently in cropping mode
if (typeof plugin.jcAPI !== 'undefined' && plugin.jcAPI !== null) {
plugin.setCropAreaByFieldValue();
} else {
plugin.setSizeByFieldValue();
}
}
}
e.preventDefault();
return false;
}
/**
* Handle the mouse wheel event on the field
*/
function handleMouseWheelEventOnField(e, delta) {
var minValue = e.data.minValue;
var maxValue = e.data.maxValue;
var fieldName = e.data.fieldName;
// Handle key combinations
if (e.shiftKey || e.metaKey || e.ctrlKey) {
delta = delta * 10;
}
var newValue = parseInt($(this).val(), 10) + delta;
var decrement = false;
if (delta < 0) {
decrement = true;
}
// Only resize if field values are ok
if (plugin._updateFields(fieldName, newValue, decrement)) {
// Check if we are currently in cropping mode
if (typeof plugin.jcAPI !== 'undefined' && plugin.jcAPI !== null) {
plugin.setCropAreaByFieldValue();
} else {
plugin.setSizeByFieldValue();
}
}
return false;
}
/**
* Handle mousewheel,keyup actions on both fields
*/
var $heightField = $('#' + plugin.ui.imgResizeHeightField.getInputId());
var heightEventData = {fieldName: 'height', maxValue: plugin.ui.imgResizeHeightField.maxValue, minValue: plugin.ui.imgResizeHeightField.minValue };
$heightField.live('keyup', heightEventData, handleKeyUpEventOnField);
$heightField.live('mousewheel', heightEventData, handleMouseWheelEventOnField);
var $widthField = $('#' + plugin.ui.imgResizeWidthField.getInputId());
var widthEventData = {fieldName: 'width', maxValue: plugin.ui.imgResizeWidthField.maxValue, minValue: plugin.ui.imgResizeWidthField.minValue};
$widthField.live('keyup', widthEventData, handleKeyUpEventOnField);
$widthField.live('mousewheel', widthEventData, handleMouseWheelEventOnField);
},
/**
* Manually set the given size for the current image
*/
setSize: function (width, height) {
var plugin = this;
plugin.imageObj.width(width);
plugin.imageObj.height(height);
var $wrapper = plugin.imageObj.closest('.Aloha_Image_Resize');
$wrapper.height(height);
$wrapper.width(width);
plugin._onResize(plugin.imageObj);
plugin._onResized(plugin.imageObj);
},
/**
* This method will handle the mouseUp event on images (eg. within editables).
* It will if enabled activate the resizing action.
*/
clickImage: function (e) {
var plugin = this;
plugin.endResize(); // removes previous resize handler
plugin.imageObj = jQuery(e.target);
var currentImage = plugin.imageObj;
// Ignore any images that are part of the ui (e.g. block edit and delete icons)
if (currentImage.hasClass('aloha-ui')) {
return;
}
plugin.ui.setScope();
var editable = currentImage.closest('.aloha-editable');
this.ui._imageCnrRatioButton.setState(this.keepAspectRatio);
// Disabling the content editable. This will disable the resizeHandles in internet explorer
// already done in resize on a smaller scope, this block next aloha-selection-change event
// to be thrown
// editable.contentEditable(false);
//Store the current props of the image
this.restoreProps.push({
obj : e.srcElement,
src : plugin.imageObj.attr('src'),
width : plugin.imageObj.width(),
height : plugin.imageObj.height()
});
// Update the resize input fields with the new width and height
var heightField = $('#' + plugin.ui.imgResizeHeightField.getInputId());
heightField.val(plugin.imageObj.height());
heightField.css('background-color', '');
var widthField = $('#' + plugin.ui.imgResizeWidthField.getInputId());
widthField.val(plugin.imageObj.width());
widthField.css('background-color', '');
if (plugin.settings.ui.meta) {
plugin.ui.imgSrcField.setTargetObject(plugin.imageObj, 'src');
plugin.ui.imgTitleField.setTargetObject(plugin.imageObj, 'title');
}
Aloha.Selection.preventSelectionChanged();
try {
plugin.ui.imgSrcField.focus();
} catch(e) {
// FIXME for some reason execution breaks at this point
}
//to handle switching between images, aspect ratio is recalculated on click
plugin.aspectRatioValue = plugin.imageObj.width() / plugin.imageObj.height();
if (plugin.settings.ui.resizable) {
plugin.startResize();
}
if (plugin.settings.autoResize) {
plugin.autoResize(true);
}
Aloha.Selection.preventSelectionChangedFlag = false;
Aloha.trigger('aloha-image-selected');
},
/**
* This method extracts determins if the range selection contains an image
*
* UNUSED as long as clickImage don't change the selection
* @see getPluginFocus instead
*/
findImgMarkup: function (range) {
var plugin = this;
var config = this.config;
var result, targetObj;
if (typeof range === 'undefined') {
range = Aloha.Selection.getRangeObject();
}
targetObj = jQuery(range.startContainer);
try {
if (Aloha.activeEditable) {
if ((typeof range.startContainer !== 'undefined' &&
typeof range.startContainer.childNodes !== 'undefined' &&
typeof range.startOffset !== 'undefined' &&
typeof range.startContainer.childNodes[range.startOffset] !== 'undefined' &&
range.startContainer.childNodes[range.startOffset].nodeName.toLowerCase() === 'img' &&
range.startOffset + 1 === range.endOffset) ||
(targetObj.hasClass('Aloha_Image_Resize')))
{
result = targetObj.find('img')[0];
if (! result.css) {
result.css = '';
}
if (! result.title) {
result.title = '';
}
if (! result.src) {
result.src = '';
}
return result;
}
else {
return null;
}
}
} catch (e) {
Aloha.Log.debug(e, "Error finding img markup.");
}
return null;
},
/**
* Gets the plugin focus target
*/
getPluginFocus: function () {
return this.imageObj;
},
/**
* Helper function that checks a field-input (of height or width), adjusts
* its value to conform to minimum/maximum values, and corrects the other field
* if the aspect ratio is to be kept
* @param primaryFieldName the field which is currently edited ('height' or 'width')
* @param newValue the value as it was entered into the primary field
* @param isDecrement true if value is being decreased (by key or mousewheel); prevents decreasing below minimum
* @return true if values are correct or have been corrected, and image can be resized
*/
_updateFields: function (primaryFieldName, newValue, isDecrement) {
var plugin = this;
var primaryField = null;
var secondaryField = null;
var adjustedAspectRatio = null;
var primaryMin = null;
var primaryMax = null;
var secondaryMin = null;
var secondaryMax = null;
//depending on the field that is edited, primary and secondary values are set
if (primaryFieldName == 'width') {
primaryField = jQuery("#" + plugin.ui.imgResizeWidthField.getInputId());
secondaryField = jQuery("#" + plugin.ui.imgResizeHeightField.getInputId());
adjustedAspectRatio = ( 1 / plugin.aspectRatioValue );
primaryMin = plugin.settings.minWidth;
primaryMax = plugin.settings.maxWidth;
secondaryMin = plugin.settings.minHeight;
secondaryMax = plugin.settings.maxHeight;
} else if (primaryFieldName == 'height') {
primaryField = jQuery("#" + plugin.ui.imgResizeHeightField.getInputId());
secondaryField = jQuery("#" + plugin.ui.imgResizeWidthField.getInputId());
adjustedAspectRatio = plugin.aspectRatioValue;
primaryMin = plugin.settings.minHeight;
primaryMax = plugin.settings.maxHeight;
secondaryMin = plugin.settings.minWidth;
secondaryMax = plugin.settings.maxWidth;
} else {
//if primaryFieldName is neither width nor height, don't update the fields
return false;
}
if (isNaN(newValue)) {
primaryField.css('background-color', 'red');
// If the current value of the field can't be parsed it is not updated
return false;
}
else {
primaryField.val(newValue);
}
var correctPrimary = true;
if (newValue > primaryMax) {
// Auto correct out of bounds values
if (plugin.settings.autoCorrectManualInput) {
primaryField.val(primaryMax);
newValue = primaryField.val();
primaryField.css('background-color', '');
correctPrimary = true;
// Just notify the user, do nothing
} else {
primaryField.css('background-color', 'red');
correctPrimary = false;
}
} else if (newValue < primaryMin) {
// Don't let the user decrement values below minimum
if (isDecrement) {
primaryField.val(primaryMin);
newValue = primaryField.val();
correctPrimary = true;
// Auto correct out of bounds values
} else if (plugin.settings.autoCorrectManualInput) {
primaryField.css('background-color', 'wheat');
correctPrimary = false;
// Just notify the user, do nothing
} else {
primaryField.css('background-color', 'red');
correctPrimary = false;
}
} else {
primaryField.css('background-color', '');
correctPrimary = true;
}
var correctSecondary = true;
// if keep aspect ratio is enabled, the field that is not edited is updated as well
if ( plugin.keepAspectRatio ) {
var secondary = Math.round(newValue * adjustedAspectRatio);
if (secondary > secondaryMax) {
// Auto correct out of bounds values
if (plugin.settings.autoCorrectManualInput) {
secondaryField.val(secondaryMax);
primaryField.val(secondaryField.val() / adjustedAspectRatio);
newValue = primaryField.val();
primaryField.css('background-color', '');
secondaryField.css('background-color', '');
correctSecondary = true;
// Just notify the user, do nothing
} else {
secondary.css('background-color', 'red');
correctSecondary = false;
}
} else if (secondary < secondaryMin) {
// Don't let the user decrement values below minimum
if (isDecrement) {
secondaryField.val(secondaryMin);
primaryField.val(secondaryField.val() / adjustedAspectRatio);
newValue = primaryField.val();
correctPrimary = true;
// Auto correct out of bounds values
} else if (plugin.settings.autoCorrectManualInput) {
secondaryField.val(secondary);
secondaryField.css('background-color', 'wheat');
correctSecondary = false;
// Just notify the user, do nothing
} else {
secondaryField.css('background-color', 'red');
correctSecondary = false;
}
} else {
secondaryField.val(secondary);
secondaryField.css('background-color', '');
correctSecondary = true;
}
}
//Success if values are correct or have been adjusted accordingly
if (correctPrimary && correctSecondary) {
return true;
}
return false;
},
/**
* Helper function that will set the new image size using the field values
*/
setSizeByFieldValue: function () {
var plugin = this;
var width = $('#' + plugin.ui.imgResizeWidthField.getInputId()).val();
var height = $('#' + plugin.ui.imgResizeHeightField.getInputId()).val();
plugin.setSize(width, height);
},
/**
* Helper function that will set the new crop area width and height using the field values
*/
setCropAreaByFieldValue: function () {
var plugin = this;
var currentCropArea = plugin.jcAPI.tellSelect();
var width = $('#' + plugin.ui.imgResizeWidthField.getInputId()).val();
width = parseInt(width, 10);
var height = $('#' + plugin.ui.imgResizeHeightField.getInputId()).val();
height = parseInt(height, 10);
var selection = [currentCropArea['x'], currentCropArea['y'], currentCropArea['x'] + width,currentCropArea['y'] + height];
plugin.jcAPI.setSelect(selection);
},
/**
* This method will insert a new image dom element into the dom tree
*/
insertImg: function () {
var range = Aloha.Selection.getRangeObject(),
config = this.getEditableConfig(Aloha.activeEditable.obj),
imagePluginUrl = Aloha.getPluginUrl('image'),
imagestyle, imagetag, newImg;
if (range.isCollapsed()) {
// TODO I would suggest to call the srcChange method. So all image src
// changes are on one single point.
imagestyle = "max-width: " + config.maxWidth + "; max-height: " + config.maxHeight;
imagetag = '
';
newImg = jQuery(imagetag);
// add the click selection handler
//newImg.click( Aloha.Image.clickImage ); - Using delegate now
GENTICS.Utils.Dom.insertIntoDOM(newImg, range, jQuery(Aloha.activeEditable.obj));
} else {
Aloha.Log.error('img cannot markup a selection');
// TODO the desired behavior could be me the selected content is
// replaced by an image.
// TODO it should be editor's choice, with an NON-Ext Dialog instead of alert
}
},
srcChange: function () {
// TODO the src changed. I suggest :
// 1. set an loading image (I suggest set src base64 enc) to show the user
// we are trying to load an image
// 2. start a request to get the image
// 3a. the image is ok change the src
// 3b. the image is not availbable show an error.
this.imageObj.attr('src', this.ui.imgSrcField.getValue()); // (the img tag)
// jQuery(img).attr('src', this.imgSrcField.getQueryValue()); // (the query value in the inputfield)
// this.imgSrcField.getItem(); // (optinal a selected resource item)
// TODO additionally implement an srcChange Handler to let implementer
// customize
},
/**
* Reposition the crop buttons below the crop area
*/
positionCropButtons: function() {
var jt = jQuery('.jcrop-tracker:first'),
off = jt.offset(),
jtt = off.top,
jtl = off.left,
jth = jt.height(),
jtw = jt.width();
var oldLeft = 0,
oldTop = 0;
var btns = jQuery('#aloha-CropNResize-btns');
// Hack to hide the buttons when the user just clicked into the image
if (jtt === 0 && jtl === 0) {
btns.hide();
}
// move the icons to the bottom right side
jtt = parseInt(jtt + jth + 3, 10);
jtl = parseInt(jtl + (jtw / 2) - (btns.width() / 2) + 10, 10);
// comparison to old values hinders flickering bug in FF
if (oldLeft != jtl || oldTop != jtt) {
btns.offset({top: jtt, left: jtl});
}
oldLeft = jtl;
oldTop = jtt;
},
/**
* Code imported from CropnResize Plugin
*
*/
initCropButtons: function() {
var that = this,
btns;
jQuery('body').append(
'