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:
@@ -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);
|
||||
}
|
||||
|
||||
Vendored
+113
-73
@@ -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.
|
||||
*
|
||||
|
||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
Vendored
+111
-73
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user