diff --git a/addons/web_editor/static/src/js/common/utils.js b/addons/web_editor/static/src/js/common/utils.js
index 16de3f2dc23..3049eb706c0 100644
--- a/addons/web_editor/static/src/js/common/utils.js
+++ b/addons/web_editor/static/src/js/common/utils.js
@@ -172,6 +172,23 @@ function _areCssValuesEqual(value1, value2, cssProp, $target) {
return true;
}
+ // In case the values are a size, they might be made of two parts.
+ if (cssProp && cssProp.endsWith('-size')) {
+ // Avoid re-splitting each part during their individual comparison.
+ const pseudoPartProp = cssProp + '-part';
+ const re = /-?[0-9.]+\s*[A-Za-z%-]+|auto/g;
+ const parts1 = value1.match(re);
+ const parts2 = value2.match(re);
+ for (const index of [0, 1]) {
+ const part1 = parts1 && parts1.length > index ? parts1[index] : 'auto';
+ const part2 = parts2 && parts2.length > index ? parts2[index] : 'auto';
+ if (!_areCssValuesEqual(part1, part2, pseudoPartProp, $target)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
// It could be a CSS variable, in that case the actual value has to be
// retrieved before comparing.
if (value1.startsWith('var(--')) {
diff --git a/addons/web_editor/static/tests/utils_tests.js b/addons/web_editor/static/tests/utils_tests.js
new file mode 100644
index 00000000000..2d53e6e48d1
--- /dev/null
+++ b/addons/web_editor/static/tests/utils_tests.js
@@ -0,0 +1,77 @@
+/** @odoo-module **/
+import weUtils from 'web_editor.utils';
+
+QUnit.module('web_editor', {}, function () {
+QUnit.module('utils', {}, function () {
+ QUnit.module('Utils functions');
+ // Test weUtils
+
+ QUnit.test('compare CSS property values', async function (assert) {
+ assert.expect(74);
+
+ let $div = $(`
abc
`);
+ let currentProperty = 'font-size';
+ function compare(expected, value1, value2, property = currentProperty, $target = $div) {
+ // Comparisons are done in both directions if values are different.
+ assert.strictEqual(weUtils.areCssValuesEqual(value1, value2, property, $target), expected,
+ `'${value1}' should be ${expected ? 'equal to' : 'different from'} '${value2}'`
+ );
+ if (value1 !== value2) {
+ assert.strictEqual(weUtils.areCssValuesEqual(value2, value1, property, $target), expected,
+ `'${value2}' should be ${expected ? 'equal to' : 'different from'} '${value1}'`
+ );
+ }
+ }
+ compare(true, '', '');
+ compare(true, 'auto', 'auto');
+ compare(true, '', 'auto');
+ compare(true, '15px', '15px');
+ compare(true, '15.0px', '15px');
+ compare(true, '15 px', '15px');
+ compare(false, '15px', '25px');
+ compare(false, '15px', '');
+ compare(false, '15px', 'auto');
+
+ currentProperty = 'background-size';
+ compare(true, '', '');
+ compare(true, 'auto', 'auto');
+ compare(true, '', 'auto');
+ compare(true, '15px', '15px');
+ compare(true, '15.0px', '15px');
+ compare(false, '15px', '25px');
+ compare(false, '15px', '');
+ compare(false, '15px', 'auto');
+ compare(true, '', 'auto auto');
+ compare(true, 'auto', 'auto auto');
+ compare(true, 'auto auto', 'auto auto');
+ compare(true, '15px 15px', '15px 15px');
+ compare(false, '15px 25px', '15px 15px');
+ compare(false, '25px 15px', '15px 15px');
+ compare(true, 'auto 15px', 'auto 15px');
+ compare(true, '15px auto', '15px auto');
+ compare(true, '15px', '15px auto');
+ compare(false, 'auto 25px', 'auto 15px');
+ compare(false, '25px auto', '15px auto');
+ compare(false, '25px', '15px auto');
+
+ currentProperty = 'color';
+ compare(true, '', '');
+ compare(false, '', '#123456');
+ compare(true, '#123456', '#123456');
+ compare(false, '#123456', '#654321');
+ compare(true, 'rgb(255, 0, 0)', '#FF0000');
+ compare(false, 'rgb(255, 0, 0)', '#EE0000');
+
+ currentProperty = 'background-image';
+ compare(true, '', '');
+ compare(false, '', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(true, 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(false, 'linear-gradient(0deg, rgb(10, 0, 0) 0%, rgb(1, 1, 1) 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(false, 'linear-gradient(10deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(false, 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(10, 1, 1) 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(false, 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(9, 9, 9) 50%, rgb(1, 1, 1) 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(true, 'linear-gradient(0deg, #000000 0%, #010101 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ compare(false, 'linear-gradient(0deg, #FF0000 0%, #010101 100%)', 'linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(1, 1, 1) 100%)');
+ });
+});
+});