MDL-44000 Atto: Add option to constrain image size

(Keep aspect ratio)

Also some small improvements to the edit image dialogue.
This commit is contained in:
Damyon Wiese
2014-03-31 16:28:57 +08:00
parent b13f4e8e7c
commit ffb8aff65c
7 changed files with 447 additions and 131 deletions
@@ -34,6 +34,7 @@ $string['alignment_textbottom'] = 'Text bottom';
$string['alignment_texttop'] = 'Text top';
$string['alignment_top'] = 'Top';
$string['browserepositories'] = 'Browse repositories...';
$string['constrain'] = 'Keep ratio';
$string['createimage'] = 'Insert image';
$string['enteralt'] = 'Describe this image for someone who cannot see it';
$string['enterurl'] = 'Enter URL';
+1
View File
@@ -43,6 +43,7 @@ function atto_image_strings_for_js() {
'alignment_texttop',
'alignment_top',
'browserepositories',
'constrain',
'createimage',
'enterurl',
'enteralt',
+14
View File
@@ -2,3 +2,17 @@
max-width: 150px;
max-height: 150px;
}
.atto_image_size {
display: inline-block;
}
.atto_image_size input[type=checkbox] {
margin-left: 1em;
margin-right: 1em;
}
.atto_image_size input[type=text] {
width: 3em;
}
.atto_image_size label {
display: inline-block;
}
@@ -39,10 +39,12 @@ var CSS = {
INPUTHEIGHT: 'atto_image_heightentry',
INPUTSUBMIT: 'atto_image_urlentrysubmit',
INPUTURL: 'atto_image_urlentry',
INPUTSIZE: 'atto_image_size',
INPUTWIDTH: 'atto_image_widthentry',
IMAGEALTWARNING: 'atto_image_altwarning',
IMAGEBROWSER: 'openimagebrowser',
IMAGEPRESENTATION: 'atto_image_presentation',
INPUTCONSTRAIN: 'atto_image_constrain',
IMAGEPREVIEW: 'atto_image_preview'
},
ALIGNMENTS = [
@@ -119,15 +121,20 @@ var COMPONENTNAME = 'atto_image',
'<label class="sameline" for="{{elementid}}_{{CSS.IMAGEPRESENTATION}}">{{get_string "presentation" component}}</label>' +
'<br/>' +
// Add the width entry box.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTWIDTH}}">{{get_string "width" component}}</label>' +
'<input type="text" class="{{CSS.INPUTWIDTH}} id="{{elementid}}_{{CSS.INPUTWIDTH}}" size="10"/>' +
'<br/>' +
// Add the size entry boxes.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTSIZE}}">Size</label>' +
'<div id="{{elementid}}_{{CSS.INPUTSIZE}}" class="{{CSS.INPUTSIZE}}">' +
'<label class="accesshide" for="{{elementid}}_{{CSS.INPUTWIDTH}}">{{get_string "width" component}}</label>' +
'<input type="text" class="{{CSS.INPUTWIDTH}} input-mini" id="{{elementid}}_{{CSS.INPUTWIDTH}}" size="4"/> x ' +
// Add the height entry box.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTHEIGHT}}">{{get_string "height" component}}</label>' +
'<input type="text" class="{{CSS.INPUTHEIGHT}}" id="{{elementid}}_{{CSS.INPUTHEIGHT}}" size="10"/>' +
'<br/>' +
'<label class="accesshide" for="{{elementid}}_{{CSS.INPUTHEIGHT}}">{{get_string "height" component}}</label>' +
'<input type="text" class="{{CSS.INPUTHEIGHT}} input-mini" id="{{elementid}}_{{CSS.INPUTHEIGHT}}" size="4"/>' +
// Add the constrain checkbox.
'<input type="checkbox" class="{{CSS.INPUTCONSTRAIN}} sameline" id="{{elementid}}_{{CSS.INPUTCONSTRAIN}}"/>' +
'<label for="{{elementid}}_{{CSS.INPUTCONSTRAIN}}">{{get_string "constrain" component}}</label>' +
'</div>' +
// Add the alignment selector.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTALIGNMENT}}">{{get_string "alignment" component}}</label>' +
@@ -186,6 +193,24 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_form: null,
/**
* Remember the image true dimensions so we can constrain resizing.
*
* @param _imageRawWidth
* @type Integer
* @private
*/
_imageRawWidth: 0,
/**
* Remember the image true dimensions so we can constrain resizing.
*
* @param _imageRawHeight
* @type Integer
* @private
*/
_imageRawHeight: 0,
initializer: function() {
this.addButton({
icon: 'e/insert_edit_image',
@@ -219,6 +244,57 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
.show();
},
/**
* Set the inputs for width and height if they are not set, and calculate
* if the constrain checkbox should be checked or not.
*
* @method _loadPreviewImage
* @param {String} url
* @private
*/
_loadPreviewImage: function(url) {
var image = new Image(), self = this;
image.onload = function() {
var input, currentwidth, currentheight, widthRatio, heightRatio;
self._imageRawWidth = this.width;
self._imageRawHeight = this.height;
input = self._form.one('.' + CSS.INPUTWIDTH);
currentwidth = input.get('value');
if (currentwidth === '') {
input.set('value', this.width);
currentwidth = this.width;
}
input = self._form.one('.' + CSS.INPUTHEIGHT);
currentheight = input.get('value');
if (currentheight === '') {
input.set('value', this.height);
currentheight = this.height;
}
input = self._form.one('.' + CSS.IMAGEPREVIEW);
input.set('src', this.src);
input.setStyle('display', 'inline');
if (this.width === 0) {
this.width = 1;
}
if (this.height === 0) {
this.height = 1;
}
input = self._form.one('.' + CSS.INPUTCONSTRAIN);
widthRatio = Math.round(parseInt(currentwidth, 10) / this.width);
heightRatio = Math.round(parseInt(currentheight, 10) / this.height);
input.set('checked', widthRatio === heightRatio);
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = url;
},
/**
* Return the dialogue content for the tool, attaching any required
* events.
@@ -243,6 +319,9 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
// Configure the view of the current image.
this._applyImageProperties(this._form);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustHeight, this);
this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustWidth, this);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this);
@@ -255,6 +334,54 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return content;
},
/**
* Adjust the height to keep the aspect ratio.
*
* @method _autoAdjustHeight
* @private
*/
_autoAdjustHeight: function() {
var currentWidth, newHeight, currentHeight;
if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
return;
}
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
newHeight = Math.round((currentWidth / this._imageRawWidth) * this._imageRawHeight);
this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
},
/**
* Adjust the width to keep the aspect ratio.
*
* @method _autoAdjustWidth
* @private
*/
_autoAdjustWidth: function() {
var currentHeight, newWidth;
if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
return;
}
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
newWidth = Math.round((currentHeight / this._imageRawHeight) * this._imageRawWidth);
this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
},
/**
* Update the dialogue after an image was selected in the File Picker.
*
@@ -265,22 +392,15 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_filepickerCallback: function(params) {
if (params.url !== '') {
var input = this._form.one('.' + CSS.INPUTURL),
self = this;
var input = this._form.one('.' + CSS.INPUTURL);
input.set('value', params.url);
// Auto set the width and height.
var image = new Image();
image.onload = function() {
self._form.one('.' + CSS.INPUTWIDTH).set('value', this.width);
self._form.one('.' + CSS.INPUTHEIGHT).set('value', this.height);
self._form.one('.' + CSS.IMAGEPREVIEW).set('src', this.src);
self._form.one('.' + CSS.IMAGEPREVIEW).setStyle('display', 'inline');
self._form.one('.' + CSS.INPUTWIDTH).set('value', '');
self._form.one('.' + CSS.INPUTHEIGHT).set('value', '');
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = params.url;
// Load the preview image.
this._loadPreviewImage(params.url);
}
},
@@ -317,7 +437,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
}
if (properties.src) {
form.one('.' + CSS.INPUTURL).set('value', properties.src);
img.setAttribute('src', properties.src);
this._loadPreviewImage(properties.src);
}
if (properties.presentation) {
form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked');
@@ -392,31 +512,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
* @private
*/
_urlChanged: function() {
var input = this._form.one('.' + CSS.INPUTURL),
self = this;
var input = this._form.one('.' + CSS.INPUTURL);
if (input.get('value') !== '') {
// Auto set the width and height.
var image = new Image();
image.onload = function() {
var input;
input = self._form.one('.' + CSS.INPUTWIDTH);
if (input.get('value') === '') {
input.set('value', this.width);
}
input = self._form.one('.' + CSS.INPUTHEIGHT);
if (input.get('value') === '') {
input.set('value', this.height);
}
input = self._form.one('.' + CSS.IMAGEPREVIEW);
input.set('src', this.src);
input.setStyle('display', 'inline');
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = input.get('value');
// Load the preview image.
this._loadPreviewImage(input.get('value'));
}
},
File diff suppressed because one or more lines are too long
@@ -39,10 +39,12 @@ var CSS = {
INPUTHEIGHT: 'atto_image_heightentry',
INPUTSUBMIT: 'atto_image_urlentrysubmit',
INPUTURL: 'atto_image_urlentry',
INPUTSIZE: 'atto_image_size',
INPUTWIDTH: 'atto_image_widthentry',
IMAGEALTWARNING: 'atto_image_altwarning',
IMAGEBROWSER: 'openimagebrowser',
IMAGEPRESENTATION: 'atto_image_presentation',
INPUTCONSTRAIN: 'atto_image_constrain',
IMAGEPREVIEW: 'atto_image_preview'
},
ALIGNMENTS = [
@@ -119,15 +121,20 @@ var COMPONENTNAME = 'atto_image',
'<label class="sameline" for="{{elementid}}_{{CSS.IMAGEPRESENTATION}}">{{get_string "presentation" component}}</label>' +
'<br/>' +
// Add the width entry box.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTWIDTH}}">{{get_string "width" component}}</label>' +
'<input type="text" class="{{CSS.INPUTWIDTH}} id="{{elementid}}_{{CSS.INPUTWIDTH}}" size="10"/>' +
'<br/>' +
// Add the size entry boxes.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTSIZE}}">Size</label>' +
'<div id="{{elementid}}_{{CSS.INPUTSIZE}}" class="{{CSS.INPUTSIZE}}">' +
'<label class="accesshide" for="{{elementid}}_{{CSS.INPUTWIDTH}}">{{get_string "width" component}}</label>' +
'<input type="text" class="{{CSS.INPUTWIDTH}} input-mini" id="{{elementid}}_{{CSS.INPUTWIDTH}}" size="4"/> x ' +
// Add the height entry box.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTHEIGHT}}">{{get_string "height" component}}</label>' +
'<input type="text" class="{{CSS.INPUTHEIGHT}}" id="{{elementid}}_{{CSS.INPUTHEIGHT}}" size="10"/>' +
'<br/>' +
'<label class="accesshide" for="{{elementid}}_{{CSS.INPUTHEIGHT}}">{{get_string "height" component}}</label>' +
'<input type="text" class="{{CSS.INPUTHEIGHT}} input-mini" id="{{elementid}}_{{CSS.INPUTHEIGHT}}" size="4"/>' +
// Add the constrain checkbox.
'<input type="checkbox" class="{{CSS.INPUTCONSTRAIN}} sameline" id="{{elementid}}_{{CSS.INPUTCONSTRAIN}}"/>' +
'<label for="{{elementid}}_{{CSS.INPUTCONSTRAIN}}">{{get_string "constrain" component}}</label>' +
'</div>' +
// Add the alignment selector.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTALIGNMENT}}">{{get_string "alignment" component}}</label>' +
@@ -186,6 +193,24 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_form: null,
/**
* Remember the image true dimensions so we can constrain resizing.
*
* @param _imageRawWidth
* @type Integer
* @private
*/
_imageRawWidth: 0,
/**
* Remember the image true dimensions so we can constrain resizing.
*
* @param _imageRawHeight
* @type Integer
* @private
*/
_imageRawHeight: 0,
initializer: function() {
this.addButton({
icon: 'e/insert_edit_image',
@@ -219,6 +244,57 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
.show();
},
/**
* Set the inputs for width and height if they are not set, and calculate
* if the constrain checkbox should be checked or not.
*
* @method _loadPreviewImage
* @param {String} url
* @private
*/
_loadPreviewImage: function(url) {
var image = new Image(), self = this;
image.onload = function() {
var input, currentwidth, currentheight, widthRatio, heightRatio;
self._imageRawWidth = this.width;
self._imageRawHeight = this.height;
input = self._form.one('.' + CSS.INPUTWIDTH);
currentwidth = input.get('value');
if (currentwidth === '') {
input.set('value', this.width);
currentwidth = this.width;
}
input = self._form.one('.' + CSS.INPUTHEIGHT);
currentheight = input.get('value');
if (currentheight === '') {
input.set('value', this.height);
currentheight = this.height;
}
input = self._form.one('.' + CSS.IMAGEPREVIEW);
input.set('src', this.src);
input.setStyle('display', 'inline');
if (this.width === 0) {
this.width = 1;
}
if (this.height === 0) {
this.height = 1;
}
input = self._form.one('.' + CSS.INPUTCONSTRAIN);
widthRatio = Math.round(parseInt(currentwidth, 10) / this.width);
heightRatio = Math.round(parseInt(currentheight, 10) / this.height);
input.set('checked', widthRatio === heightRatio);
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = url;
},
/**
* Return the dialogue content for the tool, attaching any required
* events.
@@ -243,6 +319,9 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
// Configure the view of the current image.
this._applyImageProperties(this._form);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustHeight, this);
this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustWidth, this);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this);
@@ -255,6 +334,54 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return content;
},
/**
* Adjust the height to keep the aspect ratio.
*
* @method _autoAdjustHeight
* @private
*/
_autoAdjustHeight: function() {
var currentWidth, newHeight, currentHeight;
if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
return;
}
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
newHeight = Math.round((currentWidth / this._imageRawWidth) * this._imageRawHeight);
this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
},
/**
* Adjust the width to keep the aspect ratio.
*
* @method _autoAdjustWidth
* @private
*/
_autoAdjustWidth: function() {
var currentHeight, newWidth;
if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
return;
}
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
newWidth = Math.round((currentHeight / this._imageRawHeight) * this._imageRawWidth);
this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
},
/**
* Update the dialogue after an image was selected in the File Picker.
*
@@ -265,22 +392,15 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_filepickerCallback: function(params) {
if (params.url !== '') {
var input = this._form.one('.' + CSS.INPUTURL),
self = this;
var input = this._form.one('.' + CSS.INPUTURL);
input.set('value', params.url);
// Auto set the width and height.
var image = new Image();
image.onload = function() {
self._form.one('.' + CSS.INPUTWIDTH).set('value', this.width);
self._form.one('.' + CSS.INPUTHEIGHT).set('value', this.height);
self._form.one('.' + CSS.IMAGEPREVIEW).set('src', this.src);
self._form.one('.' + CSS.IMAGEPREVIEW).setStyle('display', 'inline');
self._form.one('.' + CSS.INPUTWIDTH).set('value', '');
self._form.one('.' + CSS.INPUTHEIGHT).set('value', '');
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = params.url;
// Load the preview image.
this._loadPreviewImage(params.url);
}
},
@@ -317,7 +437,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
}
if (properties.src) {
form.one('.' + CSS.INPUTURL).set('value', properties.src);
img.setAttribute('src', properties.src);
this._loadPreviewImage(properties.src);
}
if (properties.presentation) {
form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked');
@@ -392,31 +512,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
* @private
*/
_urlChanged: function() {
var input = this._form.one('.' + CSS.INPUTURL),
self = this;
var input = this._form.one('.' + CSS.INPUTURL);
if (input.get('value') !== '') {
// Auto set the width and height.
var image = new Image();
image.onload = function() {
var input;
input = self._form.one('.' + CSS.INPUTWIDTH);
if (input.get('value') === '') {
input.set('value', this.width);
}
input = self._form.one('.' + CSS.INPUTHEIGHT);
if (input.get('value') === '') {
input.set('value', this.height);
}
input = self._form.one('.' + CSS.IMAGEPREVIEW);
input.set('src', this.src);
input.setStyle('display', 'inline');
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = input.get('value');
// Load the preview image.
this._loadPreviewImage(input.get('value'));
}
},
+143 -43
View File
@@ -37,10 +37,12 @@ var CSS = {
INPUTHEIGHT: 'atto_image_heightentry',
INPUTSUBMIT: 'atto_image_urlentrysubmit',
INPUTURL: 'atto_image_urlentry',
INPUTSIZE: 'atto_image_size',
INPUTWIDTH: 'atto_image_widthentry',
IMAGEALTWARNING: 'atto_image_altwarning',
IMAGEBROWSER: 'openimagebrowser',
IMAGEPRESENTATION: 'atto_image_presentation',
INPUTCONSTRAIN: 'atto_image_constrain',
IMAGEPREVIEW: 'atto_image_preview'
},
ALIGNMENTS = [
@@ -117,15 +119,20 @@ var COMPONENTNAME = 'atto_image',
'<label class="sameline" for="{{elementid}}_{{CSS.IMAGEPRESENTATION}}">{{get_string "presentation" component}}</label>' +
'<br/>' +
// Add the width entry box.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTWIDTH}}">{{get_string "width" component}}</label>' +
'<input type="text" class="{{CSS.INPUTWIDTH}} id="{{elementid}}_{{CSS.INPUTWIDTH}}" size="10"/>' +
'<br/>' +
// Add the size entry boxes.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTSIZE}}">Size</label>' +
'<div id="{{elementid}}_{{CSS.INPUTSIZE}}" class="{{CSS.INPUTSIZE}}">' +
'<label class="accesshide" for="{{elementid}}_{{CSS.INPUTWIDTH}}">{{get_string "width" component}}</label>' +
'<input type="text" class="{{CSS.INPUTWIDTH}} input-mini" id="{{elementid}}_{{CSS.INPUTWIDTH}}" size="4"/> x ' +
// Add the height entry box.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTHEIGHT}}">{{get_string "height" component}}</label>' +
'<input type="text" class="{{CSS.INPUTHEIGHT}}" id="{{elementid}}_{{CSS.INPUTHEIGHT}}" size="10"/>' +
'<br/>' +
'<label class="accesshide" for="{{elementid}}_{{CSS.INPUTHEIGHT}}">{{get_string "height" component}}</label>' +
'<input type="text" class="{{CSS.INPUTHEIGHT}} input-mini" id="{{elementid}}_{{CSS.INPUTHEIGHT}}" size="4"/>' +
// Add the constrain checkbox.
'<input type="checkbox" class="{{CSS.INPUTCONSTRAIN}} sameline" id="{{elementid}}_{{CSS.INPUTCONSTRAIN}}"/>' +
'<label for="{{elementid}}_{{CSS.INPUTCONSTRAIN}}">{{get_string "constrain" component}}</label>' +
'</div>' +
// Add the alignment selector.
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTALIGNMENT}}">{{get_string "alignment" component}}</label>' +
@@ -184,6 +191,24 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_form: null,
/**
* Remember the image true dimensions so we can constrain resizing.
*
* @param _imageRawWidth
* @type Integer
* @private
*/
_imageRawWidth: 0,
/**
* Remember the image true dimensions so we can constrain resizing.
*
* @param _imageRawHeight
* @type Integer
* @private
*/
_imageRawHeight: 0,
initializer: function() {
this.addButton({
icon: 'e/insert_edit_image',
@@ -217,6 +242,57 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
.show();
},
/**
* Set the inputs for width and height if they are not set, and calculate
* if the constrain checkbox should be checked or not.
*
* @method _loadPreviewImage
* @param {String} url
* @private
*/
_loadPreviewImage: function(url) {
var image = new Image(), self = this;
image.onload = function() {
var input, currentwidth, currentheight, widthRatio, heightRatio;
self._imageRawWidth = this.width;
self._imageRawHeight = this.height;
input = self._form.one('.' + CSS.INPUTWIDTH);
currentwidth = input.get('value');
if (currentwidth === '') {
input.set('value', this.width);
currentwidth = this.width;
}
input = self._form.one('.' + CSS.INPUTHEIGHT);
currentheight = input.get('value');
if (currentheight === '') {
input.set('value', this.height);
currentheight = this.height;
}
input = self._form.one('.' + CSS.IMAGEPREVIEW);
input.set('src', this.src);
input.setStyle('display', 'inline');
if (this.width === 0) {
this.width = 1;
}
if (this.height === 0) {
this.height = 1;
}
input = self._form.one('.' + CSS.INPUTCONSTRAIN);
widthRatio = Math.round(parseInt(currentwidth, 10) / this.width);
heightRatio = Math.round(parseInt(currentheight, 10) / this.height);
input.set('checked', widthRatio === heightRatio);
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = url;
},
/**
* Return the dialogue content for the tool, attaching any required
* events.
@@ -241,6 +317,9 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
// Configure the view of the current image.
this._applyImageProperties(this._form);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustHeight, this);
this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustWidth, this);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this);
@@ -253,6 +332,54 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return content;
},
/**
* Adjust the height to keep the aspect ratio.
*
* @method _autoAdjustHeight
* @private
*/
_autoAdjustHeight: function() {
var currentWidth, newHeight, currentHeight;
if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
return;
}
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
newHeight = Math.round((currentWidth / this._imageRawWidth) * this._imageRawHeight);
this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
},
/**
* Adjust the width to keep the aspect ratio.
*
* @method _autoAdjustWidth
* @private
*/
_autoAdjustWidth: function() {
var currentHeight, newWidth;
if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
return;
}
currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
newWidth = Math.round((currentHeight / this._imageRawHeight) * this._imageRawWidth);
this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
},
/**
* Update the dialogue after an image was selected in the File Picker.
*
@@ -263,22 +390,15 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_filepickerCallback: function(params) {
if (params.url !== '') {
var input = this._form.one('.' + CSS.INPUTURL),
self = this;
var input = this._form.one('.' + CSS.INPUTURL);
input.set('value', params.url);
// Auto set the width and height.
var image = new Image();
image.onload = function() {
self._form.one('.' + CSS.INPUTWIDTH).set('value', this.width);
self._form.one('.' + CSS.INPUTHEIGHT).set('value', this.height);
self._form.one('.' + CSS.IMAGEPREVIEW).set('src', this.src);
self._form.one('.' + CSS.IMAGEPREVIEW).setStyle('display', 'inline');
self._form.one('.' + CSS.INPUTWIDTH).set('value', '');
self._form.one('.' + CSS.INPUTHEIGHT).set('value', '');
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = params.url;
// Load the preview image.
this._loadPreviewImage(params.url);
}
},
@@ -315,7 +435,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
}
if (properties.src) {
form.one('.' + CSS.INPUTURL).set('value', properties.src);
img.setAttribute('src', properties.src);
this._loadPreviewImage(properties.src);
}
if (properties.presentation) {
form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked');
@@ -390,31 +510,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
* @private
*/
_urlChanged: function() {
var input = this._form.one('.' + CSS.INPUTURL),
self = this;
var input = this._form.one('.' + CSS.INPUTURL);
if (input.get('value') !== '') {
// Auto set the width and height.
var image = new Image();
image.onload = function() {
var input;
input = self._form.one('.' + CSS.INPUTWIDTH);
if (input.get('value') === '') {
input.set('value', this.width);
}
input = self._form.one('.' + CSS.INPUTHEIGHT);
if (input.get('value') === '') {
input.set('value', this.height);
}
input = self._form.one('.' + CSS.IMAGEPREVIEW);
input.set('src', this.src);
input.setStyle('display', 'inline');
// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
};
image.src = input.get('value');
// Load the preview image.
this._loadPreviewImage(input.get('value'));
}
},