MDL-52317 Atto: Large resized images may display scroll bars

When an image was added via Atto and it was set to resize automatically
if the alignment was set to Top, Middle or Bottom when it was made
smaller then a vertical scroll bar would be displayed.

This was caused by the interaction of the margin settings on the image
and the 100% width set via the img-responsive css class. The width of
an element only includes the content area and not any borders, padding
or margins.

This change stops atto hardcoding the styles for image alignment into
the images style tag, it instead adds a class that defines the alignment
the image should have.

This change has the benefit that themers will now be able to adjust
how atto image alignments work if they wish.

Images added before this patch will continue to have the issue
until they are edited by the plugin, at which time their legacy style
will be removed and the new alignment method will be added.

Thanks to Andrew Nicols who provided a refactor for the Alignment
and style detection code.
This commit is contained in:
Neill Magill
2016-09-30 08:50:38 +01:00
parent 049d20856c
commit b9143c7883
5 changed files with 373 additions and 222 deletions
+33
View File
@@ -27,3 +27,36 @@
.atto_image_size label {
display: inline-block;
}
.atto_image_button_text-top {
vertical-align: text-top;
margin: 0 0.5em;
}
.atto_image_button_middle {
vertical-align: middle;
margin: 0 0.5em;
}
.atto_image_button_text-bottom {
vertical-align: text-bottom;
margin: 0 0.5em;
}
.atto_image_button_text-top.img-responsive,
.atto_image_button_middle.img-responsive,
.atto_image_button_text-bottom.img-responsive {
max-width: calc(100% - 1em);
}
.atto_image_button_left {
float: left;
margin: 0 0.5em 0 0;
max-width: calc(100% - 1em);
}
.atto_image_button_right {
float: right;
margin: 0 0 0 0.5em;
max-width: calc(100% - 1em);
}
@@ -48,7 +48,8 @@ var CSS = {
INPUTCONSTRAIN: 'atto_image_constrain',
INPUTCUSTOMSTYLE: 'atto_image_customstyle',
IMAGEPREVIEW: 'atto_image_preview',
IMAGEPREVIEWBOX: 'atto_image_preview_box'
IMAGEPREVIEWBOX: 'atto_image_preview_box',
ALIGNSETTINGS: 'atto_image_button'
},
SELECTORS = {
INPUTURL: '.' + CSS.INPUTURL
@@ -56,38 +57,34 @@ var CSS = {
ALIGNMENTS = [
// Vertical alignment.
{
name: 'text-top',
name: 'verticalAlign',
str: 'alignment_top',
value: 'vertical-align',
margin: '0 .5em'
value: 'text-top',
margin: '0 0.5em'
}, {
name: 'middle',
name: 'verticalAlign',
str: 'alignment_middle',
value: 'vertical-align',
margin: '0 .5em'
value: 'middle',
margin: '0 0.5em'
}, {
name: 'text-bottom',
name: 'verticalAlign',
str: 'alignment_bottom',
value: 'vertical-align',
margin: '0 .5em',
value: 'text-bottom',
margin: '0 0.5em',
isDefault: true
},
// Floats.
{
name: 'left',
name: 'float',
str: 'alignment_left',
value: 'float',
margin: '0 .5em 0 0'
value: 'left',
margin: '0 0.5em 0 0'
}, {
name: 'right',
name: 'float',
str: 'alignment_right',
value: 'float',
margin: '0 0 0 .5em'
}, {
name: 'customstyle',
str: 'customstyle',
value: 'style'
value: 'right',
margin: '0 0 0 0.5em'
}
],
@@ -142,7 +139,7 @@ var CSS = {
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTALIGNMENT}}">{{get_string "alignment" component}}</label>' +
'<select class="{{CSS.INPUTALIGNMENT}}" id="{{elementid}}_{{CSS.INPUTALIGNMENT}}">' +
'{{#each alignments}}' +
'<option value="{{value}}:{{name}};">{{get_string str ../component}}</option>' +
'<option value="{{value}}">{{get_string str ../component}}</option>' +
'{{/each}}' +
'</select>' +
// Hidden input to store custom styles.
@@ -165,7 +162,7 @@ var CSS = {
'{{#if width}}width="{{width}}" {{/if}}' +
'{{#if height}}height="{{height}}" {{/if}}' +
'{{#if presentation}}role="presentation" {{/if}}' +
'style="{{alignment}}{{margin}}{{customstyle}}"' +
'{{#if customstyle}}style="{{customstyle}}" {{/if}}' +
'{{#if classlist}}class="{{classlist}}" {{/if}}' +
'{{#if id}}id="{{id}}" {{/if}}' +
'/>';
@@ -230,6 +227,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*
* @method _handleDragDrop
* @param {EventFacade} e
* @return mixed
* @private
*/
_handleDragDrop: function(e) {
@@ -642,30 +640,25 @@ 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),
i,
css;
img = form.one('.' + CSS.IMAGEPREVIEW);
if (properties === false) {
img.setStyle('display', 'none');
// Set the default alignment.
for (i in ALIGNMENTS) {
if (ALIGNMENTS[i].isDefault === true) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
form.one('.' + CSS.INPUTALIGNMENT).set('value', css);
ALIGNMENTS.some(function(alignment) {
if (alignment.isDefault) {
form.one('.' + CSS.INPUTALIGNMENT).set('value', alignment.value);
return true;
}
}
// Remove the custom style option if this is a new image.
form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
return false;
}, this);
return;
}
if (properties.align) {
form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align);
// Remove the custom style option if we have a standard alignment.
form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
} else {
form.one('.' + CSS.INPUTALIGNMENT).set('value', 'style:customstyle;');
}
if (properties.customstyle) {
form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle);
@@ -712,25 +705,21 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
// Get the current selection.
images = this.get('host').getSelectedNodes(),
i,
width,
height,
style,
css,
image,
margin;
image;
if (images) {
images = images.filter('img');
}
if (images && images.size()) {
image = images.item(0);
image = this._removeLegacyAlignment(images.item(0));
this._selectedImage = image;
style = image.getAttribute('style');
properties.customstyle = style;
style = style.replace(/ /g, '');
width = image.getAttribute('width');
if (!width.match(REGEX.ISPERCENT)) {
@@ -747,18 +736,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
if (height !== 0) {
properties.height = height;
}
for (i in ALIGNMENTS) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
if (style.indexOf(css) !== -1) {
margin = 'margin:' + ALIGNMENTS[i].margin + ';';
margin = margin.replace(/ /g, '');
// Must match alignment and margins - otherwise custom style is selected.
if (style.indexOf(margin) !== -1) {
properties.align = css;
break;
}
}
}
this._getAlignmentPropeties(image, properties);
properties.src = image.getAttribute('src');
properties.alt = image.getAttribute('alt') || '';
properties.presentation = (image.get('role') === 'presentation');
@@ -770,6 +748,40 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return false;
},
/**
* Sets the alignment of a properties object.
*
* @method _getAlignmentPropeties
* @param {Node} image The image that the alignment properties should be found for
* @param {Object} properties The properties object that is created in _getSelectedImageProperties()
* @private
*/
_getAlignmentPropeties: function(image, properties) {
var complete = false,
defaultAlignment;
// Check for an alignment value.
complete = ALIGNMENTS.some(function(alignment) {
var classname = this._getAlignmentClass(alignment.value);
if (image.hasClass(classname)) {
properties.align = alignment.value;
Y.log('Found alignment ' + alignment.value, 'debug', 'atto_image-button');
return true;
}
if (alignment.isDefault) {
defaultAlignment = alignment.value;
}
return false;
}, this);
if (!complete && defaultAlignment) {
properties.align = defaultAlignment;
}
},
/**
* Update the form when the URL was changed. This includes updating the
* height, width, and image preview.
@@ -799,14 +811,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
alt = form.one('.' + CSS.INPUTALT).get('value'),
width = form.one('.' + CSS.INPUTWIDTH).get('value'),
height = form.one('.' + CSS.INPUTHEIGHT).get('value'),
alignment = form.one('.' + CSS.INPUTALIGNMENT).get('value'),
margin = '',
alignment = this._getAlignmentClass(form.one('.' + CSS.INPUTALIGNMENT).get('value')),
presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'),
constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'),
imagehtml,
customstyle = '',
i,
css,
customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value'),
classlist = [],
host = this.get('host');
@@ -826,22 +835,13 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
host.setSelection(this._currentSelection);
}
if (alignment === 'style:customstyle;') {
alignment = '';
customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value');
} else {
for (i in ALIGNMENTS) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
if (alignment === css) {
margin = ' margin: ' + ALIGNMENTS[i].margin + ';';
}
}
}
if (constrain) {
classlist.push(CSS.RESPONSIVE);
}
// Add the alignment class for the image.
classlist.push(alignment);
if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) {
form.one('.' + CSS.INPUTWIDTH).focus();
return;
@@ -858,8 +858,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
width: width,
height: height,
presentation: presentation,
alignment: alignment,
margin: margin,
customstyle: customstyle,
classlist: classlist.join(' ')
});
@@ -875,6 +873,48 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
},
/**
* Removes any legacy styles added by previous versions of the atto image button.
*
* @method _removeLegacyAlignment
* @param {Y.Node} imageNode
* @return {Y.Node}
* @private
*/
_removeLegacyAlignment: function(imageNode) {
if (!imageNode.getStyle('margin')) {
// There is no margin therefore this cannot match any known alignments.
return imageNode;
}
ALIGNMENTS.some(function(alignment) {
if (imageNode.getStyle(alignment.name) !== alignment.value) {
// The name/value do not match. Skip.
return false;
}
var normalisedNode = Y.Node.create('<div>');
normalisedNode.setStyle('margin', alignment.margin);
if (imageNode.getStyle('margin') !== normalisedNode.getStyle('margin')) {
// The margin does not match.
return false;
}
Y.log('Legacy alignment found and removed.', 'info', 'atto_image-button');
imageNode.addClass(this._getAlignmentClass(alignment.value));
imageNode.setStyle(alignment.name, null);
imageNode.setStyle('margin', null);
return true;
}, this);
return imageNode;
},
_getAlignmentClass: function(alignment) {
return CSS.ALIGNSETTINGS + '_' + alignment;
},
/**
* Update the alt text warning live.
*
File diff suppressed because one or more lines are too long
@@ -48,7 +48,8 @@ var CSS = {
INPUTCONSTRAIN: 'atto_image_constrain',
INPUTCUSTOMSTYLE: 'atto_image_customstyle',
IMAGEPREVIEW: 'atto_image_preview',
IMAGEPREVIEWBOX: 'atto_image_preview_box'
IMAGEPREVIEWBOX: 'atto_image_preview_box',
ALIGNSETTINGS: 'atto_image_button'
},
SELECTORS = {
INPUTURL: '.' + CSS.INPUTURL
@@ -56,38 +57,34 @@ var CSS = {
ALIGNMENTS = [
// Vertical alignment.
{
name: 'text-top',
name: 'verticalAlign',
str: 'alignment_top',
value: 'vertical-align',
margin: '0 .5em'
value: 'text-top',
margin: '0 0.5em'
}, {
name: 'middle',
name: 'verticalAlign',
str: 'alignment_middle',
value: 'vertical-align',
margin: '0 .5em'
value: 'middle',
margin: '0 0.5em'
}, {
name: 'text-bottom',
name: 'verticalAlign',
str: 'alignment_bottom',
value: 'vertical-align',
margin: '0 .5em',
value: 'text-bottom',
margin: '0 0.5em',
isDefault: true
},
// Floats.
{
name: 'left',
name: 'float',
str: 'alignment_left',
value: 'float',
margin: '0 .5em 0 0'
value: 'left',
margin: '0 0.5em 0 0'
}, {
name: 'right',
name: 'float',
str: 'alignment_right',
value: 'float',
margin: '0 0 0 .5em'
}, {
name: 'customstyle',
str: 'customstyle',
value: 'style'
value: 'right',
margin: '0 0 0 0.5em'
}
],
@@ -142,7 +139,7 @@ var CSS = {
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTALIGNMENT}}">{{get_string "alignment" component}}</label>' +
'<select class="{{CSS.INPUTALIGNMENT}}" id="{{elementid}}_{{CSS.INPUTALIGNMENT}}">' +
'{{#each alignments}}' +
'<option value="{{value}}:{{name}};">{{get_string str ../component}}</option>' +
'<option value="{{value}}">{{get_string str ../component}}</option>' +
'{{/each}}' +
'</select>' +
// Hidden input to store custom styles.
@@ -165,7 +162,7 @@ var CSS = {
'{{#if width}}width="{{width}}" {{/if}}' +
'{{#if height}}height="{{height}}" {{/if}}' +
'{{#if presentation}}role="presentation" {{/if}}' +
'style="{{alignment}}{{margin}}{{customstyle}}"' +
'{{#if customstyle}}style="{{customstyle}}" {{/if}}' +
'{{#if classlist}}class="{{classlist}}" {{/if}}' +
'{{#if id}}id="{{id}}" {{/if}}' +
'/>';
@@ -230,6 +227,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*
* @method _handleDragDrop
* @param {EventFacade} e
* @return mixed
* @private
*/
_handleDragDrop: function(e) {
@@ -642,30 +640,25 @@ 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),
i,
css;
img = form.one('.' + CSS.IMAGEPREVIEW);
if (properties === false) {
img.setStyle('display', 'none');
// Set the default alignment.
for (i in ALIGNMENTS) {
if (ALIGNMENTS[i].isDefault === true) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
form.one('.' + CSS.INPUTALIGNMENT).set('value', css);
ALIGNMENTS.some(function(alignment) {
if (alignment.isDefault) {
form.one('.' + CSS.INPUTALIGNMENT).set('value', alignment.value);
return true;
}
}
// Remove the custom style option if this is a new image.
form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
return false;
}, this);
return;
}
if (properties.align) {
form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align);
// Remove the custom style option if we have a standard alignment.
form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
} else {
form.one('.' + CSS.INPUTALIGNMENT).set('value', 'style:customstyle;');
}
if (properties.customstyle) {
form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle);
@@ -712,25 +705,21 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
// Get the current selection.
images = this.get('host').getSelectedNodes(),
i,
width,
height,
style,
css,
image,
margin;
image;
if (images) {
images = images.filter('img');
}
if (images && images.size()) {
image = images.item(0);
image = this._removeLegacyAlignment(images.item(0));
this._selectedImage = image;
style = image.getAttribute('style');
properties.customstyle = style;
style = style.replace(/ /g, '');
width = image.getAttribute('width');
if (!width.match(REGEX.ISPERCENT)) {
@@ -747,18 +736,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
if (height !== 0) {
properties.height = height;
}
for (i in ALIGNMENTS) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
if (style.indexOf(css) !== -1) {
margin = 'margin:' + ALIGNMENTS[i].margin + ';';
margin = margin.replace(/ /g, '');
// Must match alignment and margins - otherwise custom style is selected.
if (style.indexOf(margin) !== -1) {
properties.align = css;
break;
}
}
}
this._getAlignmentPropeties(image, properties);
properties.src = image.getAttribute('src');
properties.alt = image.getAttribute('alt') || '';
properties.presentation = (image.get('role') === 'presentation');
@@ -770,6 +748,39 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return false;
},
/**
* Sets the alignment of a properties object.
*
* @method _getAlignmentPropeties
* @param {Node} image The image that the alignment properties should be found for
* @param {Object} properties The properties object that is created in _getSelectedImageProperties()
* @private
*/
_getAlignmentPropeties: function(image, properties) {
var complete = false,
defaultAlignment;
// Check for an alignment value.
complete = ALIGNMENTS.some(function(alignment) {
var classname = this._getAlignmentClass(alignment.value);
if (image.hasClass(classname)) {
properties.align = alignment.value;
return true;
}
if (alignment.isDefault) {
defaultAlignment = alignment.value;
}
return false;
}, this);
if (!complete && defaultAlignment) {
properties.align = defaultAlignment;
}
},
/**
* Update the form when the URL was changed. This includes updating the
* height, width, and image preview.
@@ -799,14 +810,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
alt = form.one('.' + CSS.INPUTALT).get('value'),
width = form.one('.' + CSS.INPUTWIDTH).get('value'),
height = form.one('.' + CSS.INPUTHEIGHT).get('value'),
alignment = form.one('.' + CSS.INPUTALIGNMENT).get('value'),
margin = '',
alignment = this._getAlignmentClass(form.one('.' + CSS.INPUTALIGNMENT).get('value')),
presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'),
constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'),
imagehtml,
customstyle = '',
i,
css,
customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value'),
classlist = [],
host = this.get('host');
@@ -826,22 +834,13 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
host.setSelection(this._currentSelection);
}
if (alignment === 'style:customstyle;') {
alignment = '';
customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value');
} else {
for (i in ALIGNMENTS) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
if (alignment === css) {
margin = ' margin: ' + ALIGNMENTS[i].margin + ';';
}
}
}
if (constrain) {
classlist.push(CSS.RESPONSIVE);
}
// Add the alignment class for the image.
classlist.push(alignment);
if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) {
form.one('.' + CSS.INPUTWIDTH).focus();
return;
@@ -858,8 +857,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
width: width,
height: height,
presentation: presentation,
alignment: alignment,
margin: margin,
customstyle: customstyle,
classlist: classlist.join(' ')
});
@@ -875,6 +872,47 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
},
/**
* Removes any legacy styles added by previous versions of the atto image button.
*
* @method _removeLegacyAlignment
* @param {Y.Node} imageNode
* @return {Y.Node}
* @private
*/
_removeLegacyAlignment: function(imageNode) {
if (!imageNode.getStyle('margin')) {
// There is no margin therefore this cannot match any known alignments.
return imageNode;
}
ALIGNMENTS.some(function(alignment) {
if (imageNode.getStyle(alignment.name) !== alignment.value) {
// The name/value do not match. Skip.
return false;
}
var normalisedNode = Y.Node.create('<div>');
normalisedNode.setStyle('margin', alignment.margin);
if (imageNode.getStyle('margin') !== normalisedNode.getStyle('margin')) {
// The margin does not match.
return false;
}
imageNode.addClass(this._getAlignmentClass(alignment.value));
imageNode.setStyle(alignment.name, null);
imageNode.setStyle('margin', null);
return true;
}, this);
return imageNode;
},
_getAlignmentClass: function(alignment) {
return CSS.ALIGNSETTINGS + '_' + alignment;
},
/**
* Update the alt text warning live.
*
+113 -73
View File
@@ -46,7 +46,8 @@ var CSS = {
INPUTCONSTRAIN: 'atto_image_constrain',
INPUTCUSTOMSTYLE: 'atto_image_customstyle',
IMAGEPREVIEW: 'atto_image_preview',
IMAGEPREVIEWBOX: 'atto_image_preview_box'
IMAGEPREVIEWBOX: 'atto_image_preview_box',
ALIGNSETTINGS: 'atto_image_button'
},
SELECTORS = {
INPUTURL: '.' + CSS.INPUTURL
@@ -54,38 +55,34 @@ var CSS = {
ALIGNMENTS = [
// Vertical alignment.
{
name: 'text-top',
name: 'verticalAlign',
str: 'alignment_top',
value: 'vertical-align',
margin: '0 .5em'
value: 'text-top',
margin: '0 0.5em'
}, {
name: 'middle',
name: 'verticalAlign',
str: 'alignment_middle',
value: 'vertical-align',
margin: '0 .5em'
value: 'middle',
margin: '0 0.5em'
}, {
name: 'text-bottom',
name: 'verticalAlign',
str: 'alignment_bottom',
value: 'vertical-align',
margin: '0 .5em',
value: 'text-bottom',
margin: '0 0.5em',
isDefault: true
},
// Floats.
{
name: 'left',
name: 'float',
str: 'alignment_left',
value: 'float',
margin: '0 .5em 0 0'
value: 'left',
margin: '0 0.5em 0 0'
}, {
name: 'right',
name: 'float',
str: 'alignment_right',
value: 'float',
margin: '0 0 0 .5em'
}, {
name: 'customstyle',
str: 'customstyle',
value: 'style'
value: 'right',
margin: '0 0 0 0.5em'
}
],
@@ -140,7 +137,7 @@ var CSS = {
'<label class="sameline" for="{{elementid}}_{{CSS.INPUTALIGNMENT}}">{{get_string "alignment" component}}</label>' +
'<select class="{{CSS.INPUTALIGNMENT}}" id="{{elementid}}_{{CSS.INPUTALIGNMENT}}">' +
'{{#each alignments}}' +
'<option value="{{value}}:{{name}};">{{get_string str ../component}}</option>' +
'<option value="{{value}}">{{get_string str ../component}}</option>' +
'{{/each}}' +
'</select>' +
// Hidden input to store custom styles.
@@ -163,7 +160,7 @@ var CSS = {
'{{#if width}}width="{{width}}" {{/if}}' +
'{{#if height}}height="{{height}}" {{/if}}' +
'{{#if presentation}}role="presentation" {{/if}}' +
'style="{{alignment}}{{margin}}{{customstyle}}"' +
'{{#if customstyle}}style="{{customstyle}}" {{/if}}' +
'{{#if classlist}}class="{{classlist}}" {{/if}}' +
'{{#if id}}id="{{id}}" {{/if}}' +
'/>';
@@ -228,6 +225,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
*
* @method _handleDragDrop
* @param {EventFacade} e
* @return mixed
* @private
*/
_handleDragDrop: function(e) {
@@ -640,30 +638,25 @@ 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),
i,
css;
img = form.one('.' + CSS.IMAGEPREVIEW);
if (properties === false) {
img.setStyle('display', 'none');
// Set the default alignment.
for (i in ALIGNMENTS) {
if (ALIGNMENTS[i].isDefault === true) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
form.one('.' + CSS.INPUTALIGNMENT).set('value', css);
ALIGNMENTS.some(function(alignment) {
if (alignment.isDefault) {
form.one('.' + CSS.INPUTALIGNMENT).set('value', alignment.value);
return true;
}
}
// Remove the custom style option if this is a new image.
form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
return false;
}, this);
return;
}
if (properties.align) {
form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align);
// Remove the custom style option if we have a standard alignment.
form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
} else {
form.one('.' + CSS.INPUTALIGNMENT).set('value', 'style:customstyle;');
}
if (properties.customstyle) {
form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle);
@@ -710,25 +703,21 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
// Get the current selection.
images = this.get('host').getSelectedNodes(),
i,
width,
height,
style,
css,
image,
margin;
image;
if (images) {
images = images.filter('img');
}
if (images && images.size()) {
image = images.item(0);
image = this._removeLegacyAlignment(images.item(0));
this._selectedImage = image;
style = image.getAttribute('style');
properties.customstyle = style;
style = style.replace(/ /g, '');
width = image.getAttribute('width');
if (!width.match(REGEX.ISPERCENT)) {
@@ -745,18 +734,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
if (height !== 0) {
properties.height = height;
}
for (i in ALIGNMENTS) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
if (style.indexOf(css) !== -1) {
margin = 'margin:' + ALIGNMENTS[i].margin + ';';
margin = margin.replace(/ /g, '');
// Must match alignment and margins - otherwise custom style is selected.
if (style.indexOf(margin) !== -1) {
properties.align = css;
break;
}
}
}
this._getAlignmentPropeties(image, properties);
properties.src = image.getAttribute('src');
properties.alt = image.getAttribute('alt') || '';
properties.presentation = (image.get('role') === 'presentation');
@@ -768,6 +746,40 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return false;
},
/**
* Sets the alignment of a properties object.
*
* @method _getAlignmentPropeties
* @param {Node} image The image that the alignment properties should be found for
* @param {Object} properties The properties object that is created in _getSelectedImageProperties()
* @private
*/
_getAlignmentPropeties: function(image, properties) {
var complete = false,
defaultAlignment;
// Check for an alignment value.
complete = ALIGNMENTS.some(function(alignment) {
var classname = this._getAlignmentClass(alignment.value);
if (image.hasClass(classname)) {
properties.align = alignment.value;
Y.log('Found alignment ' + alignment.value, 'debug', 'atto_image-button');
return true;
}
if (alignment.isDefault) {
defaultAlignment = alignment.value;
}
return false;
}, this);
if (!complete && defaultAlignment) {
properties.align = defaultAlignment;
}
},
/**
* Update the form when the URL was changed. This includes updating the
* height, width, and image preview.
@@ -797,14 +809,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
alt = form.one('.' + CSS.INPUTALT).get('value'),
width = form.one('.' + CSS.INPUTWIDTH).get('value'),
height = form.one('.' + CSS.INPUTHEIGHT).get('value'),
alignment = form.one('.' + CSS.INPUTALIGNMENT).get('value'),
margin = '',
alignment = this._getAlignmentClass(form.one('.' + CSS.INPUTALIGNMENT).get('value')),
presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'),
constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'),
imagehtml,
customstyle = '',
i,
css,
customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value'),
classlist = [],
host = this.get('host');
@@ -824,22 +833,13 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
host.setSelection(this._currentSelection);
}
if (alignment === 'style:customstyle;') {
alignment = '';
customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value');
} else {
for (i in ALIGNMENTS) {
css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
if (alignment === css) {
margin = ' margin: ' + ALIGNMENTS[i].margin + ';';
}
}
}
if (constrain) {
classlist.push(CSS.RESPONSIVE);
}
// Add the alignment class for the image.
classlist.push(alignment);
if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) {
form.one('.' + CSS.INPUTWIDTH).focus();
return;
@@ -856,8 +856,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
width: width,
height: height,
presentation: presentation,
alignment: alignment,
margin: margin,
customstyle: customstyle,
classlist: classlist.join(' ')
});
@@ -873,6 +871,48 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
},
/**
* Removes any legacy styles added by previous versions of the atto image button.
*
* @method _removeLegacyAlignment
* @param {Y.Node} imageNode
* @return {Y.Node}
* @private
*/
_removeLegacyAlignment: function(imageNode) {
if (!imageNode.getStyle('margin')) {
// There is no margin therefore this cannot match any known alignments.
return imageNode;
}
ALIGNMENTS.some(function(alignment) {
if (imageNode.getStyle(alignment.name) !== alignment.value) {
// The name/value do not match. Skip.
return false;
}
var normalisedNode = Y.Node.create('<div>');
normalisedNode.setStyle('margin', alignment.margin);
if (imageNode.getStyle('margin') !== normalisedNode.getStyle('margin')) {
// The margin does not match.
return false;
}
Y.log('Legacy alignment found and removed.', 'info', 'atto_image-button');
imageNode.addClass(this._getAlignmentClass(alignment.value));
imageNode.setStyle(alignment.name, null);
imageNode.setStyle('margin', null);
return true;
}, this);
return imageNode;
},
_getAlignmentClass: function(alignment) {
return CSS.ALIGNSETTINGS + '_' + alignment;
},
/**
* Update the alt text warning live.
*