[FIX] web_editor: browser-unify alignment editor option

Summernote uses `document.execCommand` to apply most styles when
editing, leveraging the implementation to the browser.

Summernote is configured to use HTML styling (`'styleWithSpan': false`),
and in this case, browsers such as Firefox use HTML attributes for
styling text align, while Chrome still uses CSS for that. In fact,
`document.execCommand` is browser-inconsistent... but so is the
`styleWithSpan` option. Indeed, setting the option to `true` will make
Firefox use CSS property for alignment too... but not Internet Explorer.
So we might consider changing this option's value but this would not
solve the current problem.

Indeed, any CSS `text-align` style in Firefox takes precedence above
the element's `align` attribute, so when users were trying to align text
on stuff that was pre-aligned, they were unable to do so.

We can better explain the situation with this example:
A user tries to left-align in Firefox a `p.text-center` element, and
produces this:

```html
<p class="text-center" align="left"/>
```

(`align` attribute is ignored because of the `text-center` class)

On Chrome, this would be produced with the same steps:

```html
<p class="text-center" style="text-align:left"/>
```

With this patch, we actually make that HTML look like expected by the
user, no matter the browser he's using, by forcing the editor to use
the text-align CSS property. Note that the implementation is quite
ugly but had to take care of compatibility.

See https://github.com/odoo/odoo/pull/20900
(thanks to @Yajo for original PR)
This commit is contained in:
qsm-odoo
2017-12-15 14:06:04 +01:00
parent c8df0333f5
commit 69d4383d7b
@@ -19,6 +19,57 @@ var editor = eventHandler.modules.editor;
var renderer = $.summernote.renderer;
var options = $.summernote.options;
// Browser-unify execCommand
var oldJustify = {};
_.each(['Left', 'Right', 'Full', 'Center'], function (align) {
oldJustify[align] = editor['justify' + align];
editor['justify' + align] = function ($editable, value) {
// Before calling the standard function, check all elements which have
// an 'align' attribute and mark them with their value
var $align = $editable.find('[align]');
_.each($align, function (el) {
var $el = $(el);
$el.data('__align', $el.attr('align'));
});
// Call the standard function
oldJustify[align].apply(this, arguments);
// Then:
// Remove the text-align of elements which lost the 'align' attribute
var $newAlign = $editable.find('[align]');
$align.not($newAlign).css('text-align', '');
// Transform the 'align' attribute into the 'text-align' css
// property for elements which received the 'align' attribute or whose
// 'align' attribute changed
_.each($newAlign, function (el) {
var $el = $(el);
var oldAlignValue = $align.data('__align');
var alignValue = $el.attr('align');
if (oldAlignValue === alignValue) {
// If the element already had an 'align' attribute and that it
// did not changed, do nothing (compatibility)
return;
}
$el.removeAttr('align');
$el.css('text-align', alignValue);
// Note the first step (removing the text-align of elemnts which
// lost the 'align' attribute) is kinda the same as this one, but
// this one handles the elements which have been edited with chrome
// or with this new system
$el.find('*').css('text-align', '');
});
// Unmark the elements
$align.removeData('__align');
};
});
//////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Add method to Summernote*/