Skip to content

Commit

Permalink
MDL-45034 Atto: Image dialogue improvements.
Browse files Browse the repository at this point in the history
1. Fix Nan bugs in auto width / height
2. Allow percentages in auto width / height
3. Change dialogue title
4. Prevent preview image resizing from changing the height of the dialogue.
5. Change wording to "Auto size"
6. Auto adjust size when the "Auto size" checkbox is toggled.
7. Add img-responsive to images with the original aspect ratio.
8. If the width and height fields are left blank, revert them to the image size.
  • Loading branch information
Damyon Wiese committed Apr 15, 2014
1 parent 7bbc64b commit d3931a7
Show file tree
Hide file tree
Showing 7 changed files with 360 additions and 123 deletions.
4 changes: 3 additions & 1 deletion lib/editor/atto/plugins/image/lang/en/atto_image.php
Expand Up @@ -29,14 +29,16 @@
$string['alignment_right'] = 'Right';
$string['alignment_top'] = 'Top';
$string['browserepositories'] = 'Browse repositories...';
$string['constrain'] = 'Keep ratio';
$string['constrain'] = 'Auto size';
$string['createimage'] = 'Insert image';
$string['customstyle'] = 'Custom style';
$string['enteralt'] = 'Describe this image for someone who cannot see it';
$string['enterurl'] = 'Enter URL';
$string['height'] = 'Height';
$string['imageproperties'] = 'Image properties';
$string['presentation'] = 'Description not necessary';
$string['pluginname'] = 'Image';
$string['presentationoraltrequired'] = 'Images must have a description, except if the description is marked as not necessary.';
$string['preview'] = 'Preview';
$string['saveimage'] = 'Save image';
$string['width'] = 'Width';
3 changes: 2 additions & 1 deletion lib/editor/atto/plugins/image/lib.php
Expand Up @@ -39,7 +39,8 @@ function atto_image_strings_for_js() {
'alignment_top',
'browserepositories',
'constrain',
'createimage',
'saveimage',
'imageproperties',
'customstyle',
'enterurl',
'enteralt',
Expand Down
3 changes: 3 additions & 0 deletions lib/editor/atto/plugins/image/styles.css
@@ -1,6 +1,9 @@
.atto_image_preview {
max-width: 150px;
max-height: 150px;
}
.atto_image_preview_box {
height: 150px;
margin-bottom: 1em;
}

Expand Down
Expand Up @@ -34,6 +34,7 @@ YUI.add('moodle-atto_image-button', function (Y, NAME) {
*/

var CSS = {
RESPONSIVE: 'img-responsive',
INPUTALIGNMENT: 'atto_image_alignment',
INPUTALT: 'atto_image_altentry',
INPUTHEIGHT: 'atto_image_heightentry',
Expand All @@ -46,7 +47,8 @@ var CSS = {
IMAGEPRESENTATION: 'atto_image_presentation',
INPUTCONSTRAIN: 'atto_image_constrain',
INPUTCUSTOMSTYLE: 'atto_image_customstyle',
IMAGEPREVIEW: 'atto_image_preview'
IMAGEPREVIEW: 'atto_image_preview',
IMAGEPREVIEWBOX: 'atto_image_preview_box'
},
ALIGNMENTS = [
// Vertical alignment.
Expand Down Expand Up @@ -84,9 +86,13 @@ var CSS = {
str: 'customstyle',
value: 'style'
}
];
],

var COMPONENTNAME = 'atto_image',
REGEX = {
ISPERCENT: /\d+%/
},

COMPONENTNAME = 'atto_image',

TEMPLATE = '' +
'<form class="atto_form">' +
Expand Down Expand Up @@ -140,11 +146,13 @@ var COMPONENTNAME = 'atto_image',

// Add the image preview.
'<div class="mdl-align">' +
'<div class="{{CSS.IMAGEPREVIEWBOX}}">' +
'<img src="#" class="{{CSS.IMAGEPREVIEW}}" id="{{elementid}}_{{CSS.IMAGEPREVIEW}}" alt="" style="display: none;"/>' +
'</div>' +
'<br/>' +

// Add the submit button and close the form.
'<button class="{{CSS.INPUTSUBMIT}}" type="submit">{{get_string "createimage" component}}</button>' +
'<button class="{{CSS.INPUTSUBMIT}}" type="submit">{{get_string "saveimage" component}}</button>' +
'</div>' +
'</form>',

Expand All @@ -154,6 +162,7 @@ var COMPONENTNAME = 'atto_image',
'{{#if height}}height="{{height}}" {{/if}}' +
'{{#if presentation}}role="presentation" {{/if}}' +
'style="{{alignment}}{{margin}}{{customstyle}}"' +
'{{#if classlist}}class="{{classlist}}" {{/if}}' +
'/>';

Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
Expand Down Expand Up @@ -242,7 +251,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
}

var dialogue = this.getDialogue({
headerContent: M.util.get_string('createimage', COMPONENTNAME),
headerContent: M.util.get_string('imageproperties', COMPONENTNAME),
width: '480px',
focusAfterHide: true
});
Expand Down Expand Up @@ -273,28 +282,33 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
currentwidth = input.get('value');
if (currentwidth === '') {
input.set('value', this.width);
currentwidth = 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;
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);
if (currentwidth.match(REGEX.ISPERCENT) && currentheight.match(REGEX.ISPERCENT)) {
input.set('checked', currentwidth === currentheight);
} else {
if (this.width === 0) {
this.width = 1;
}
if (this.height === 0) {
this.height = 1;
}
// This is the same as comparing to 3 decimal places.
widthRatio = Math.round(1000*parseInt(currentwidth, 10) / this.width);
heightRatio = Math.round(1000*parseInt(currentheight, 10) / this.height);
input.set('checked', widthRatio === heightRatio);
}

// Centre the dialogue once the preview image has loaded.
self.getDialogue().centerDialogue();
Expand Down Expand Up @@ -332,6 +346,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
this._form.one('.' + CSS.INPUTALT).on('change', this._updateWarning, 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.INPUTCONSTRAIN).on('change', function(event) {
if (event.target.get('checked')) {
this._autoAdjustHeight();
}
}, this);
this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this);

Expand All @@ -353,19 +372,36 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
_autoAdjustHeight: function() {
var currentWidth, newHeight, currentHeight;

// Set the width back to default if it is empty.
if (this._form.one('.' + CSS.INPUTWIDTH).get('value') === '') {
this._form.one('.' + CSS.INPUTWIDTH).set('value', this._imageRawWidth);
}

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);
currentWidth = this._form.one('.' + CSS.INPUTWIDTH).get('value');
currentHeight = this._form.one('.' + CSS.INPUTHEIGHT).get('value');
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);
currentWidth = this._form.one('.' + CSS.INPUTWIDTH).get('value').trim();
// If this is a percentage based width, copy it verbatim to the height.
if (currentWidth.match(REGEX.ISPERCENT)) {
newHeight = currentWidth;
this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
} else {
currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
newHeight = Math.round((currentWidth / this._imageRawWidth) * this._imageRawHeight);

if (!isNaN(newHeight)) {
this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
}
}
},

/**
Expand All @@ -377,19 +413,35 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
_autoAdjustWidth: function() {
var currentHeight, newWidth;

// Set the height back to default if it is empty.
if (this._form.one('.' + CSS.INPUTHEIGHT).get('value') === '') {
this._form.one('.' + CSS.INPUTHEIGHT).set('value', this._imageRawHeight);
}

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);
currentWidth = this._form.one('.' + CSS.INPUTWIDTH).get('value');
currentHeight = this._form.one('.' + CSS.INPUTHEIGHT).get('value');
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);
currentHeight = this._form.one('.' + CSS.INPUTHEIGHT).get('value').trim();
// If this is a percentage based width, copy it verbatim to the height.
if (currentHeight.match(REGEX.ISPERCENT)) {
newWidth = currentHeight;
this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
} else {
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);
if (!isNaN(newWidth)) {
this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
}
}
},

/**
Expand Down Expand Up @@ -423,7 +475,8 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*/
_applyImageProperties: function(form) {
var properties = this._getSelectedImageProperties(),
img = form.one('.' + CSS.IMAGEPREVIEW);
img = form.one('.' + CSS.IMAGEPREVIEW),
i;

if (properties === false) {
img.setStyle('display', 'none');
Expand Down Expand Up @@ -505,13 +558,20 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
style = image.getAttribute('style');
properties.customstyle = style;
style = style.replace(/ /g, '');
width = parseInt(image.getAttribute('width'), 10);
height = parseInt(image.getAttribute('height'), 10);

if (width > 0) {
width = image.getAttribute('width');
if (!width.match(REGEX.ISPERCENT)) {
width = parseInt(width, 10);
}
height = image.getAttribute('height');
if (!height.match(REGEX.ISPERCENT)) {
height = parseInt(height, 10);
}

if (width !== 0) {
properties.width = width;
}
if (height > 0) {
if (height !== 0) {
properties.height = height;
}
for (i in ALIGNMENTS) {
Expand Down Expand Up @@ -569,9 +629,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
alignment = form.one('.' + CSS.INPUTALIGNMENT).get('value'),
margin = '',
presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'),
constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'),
imagehtml,
customstyle = '',
i,
classlist = [],
host = this.get('host');

e.preventDefault();
Expand All @@ -581,10 +643,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return;
}

this.getDialogue({
focusAfterHide: null
}).hide();

// Focus on the editor in preparation for inserting the image.
host.focus();
if (url !== '') {
Expand All @@ -606,6 +664,19 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
}
}

if (constrain) {
classlist.push(CSS.RESPONSIVE);
}

if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) {
form.one('.' + CSS.INPUTWIDTH).focus();
return;
}
if (!height.match(REGEX.ISPERCENT) && isNaN(parseInt(height, 10))) {
form.one('.' + CSS.INPUTHEIGHT).focus();
return;
}

template = Y.Handlebars.compile(IMAGETEMPLATE);
imagehtml = template({
url: url,
Expand All @@ -615,13 +686,19 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
presentation: presentation,
alignment: alignment,
margin: margin,
customstyle: customstyle
customstyle: customstyle,
classlist: classlist.join(' ')
});

this.get('host').insertContentAtFocusPoint(imagehtml);

this.markUpdated();
}

this.getDialogue({
focusAfterHide: null
}).hide();

},

/**
Expand Down

0 comments on commit d3931a7

Please sign in to comment.