summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/common/utils.js
diff options
context:
space:
mode:
authorqsm-odoo <qsm@odoo.com>2019-11-18 16:56:42 +0000
committerqsm-odoo <qsm@odoo.com>2019-12-01 15:49:57 +0000
commitb38253f400596dc6c96c2aface43684a56b24d26 (patch)
treec1bee14687b795a3db8a192118b1ef145ba11c5a /addons/web_editor/static/src/js/common/utils.js
parent75ab52af9c067b4cbc5a67083e8d02736e11bc3c (diff)
[REF] web_editor, *: use widgets for left panel components
Before this commit, the rendering of inner content of the left panel options was handled through _buildXXXElement methods in the options widgets. Now they are handled through sub-widgets which also handle the user events. Each sub-widget is notified with the string value it should hold according to the snippet option target and methods. Each sub-widget notifies a string value following user interactions, which snippet options can use to adapt their target through their option methods. The current sub-widgets introduced by this commit are (others will follow): 1) we-button 2) we-checkbox 3) we-input 4) we-select (typically containing multiple we-button widgets) 5) we-multi (typically containing multiple we-input widget) Following this commit only 3 standard option methods remain, which can be used with any meaningful widget: 1) selectClass -> Same as before + handle the old 'toggleClass' method when used with a checkbox-like widget. 2) selectStyle -> Same as old setStyle, introduced recently (simply renamed) 3) selectDataAttribute -> Handle both old selectDataAttribute and setDataAttribute, introduced recently The parameters these methods received are now: - previewMode: same as before - widgetValue: the string value the widget currently holds - params: additional parameters (mainly dataset of the related xml) + params.possibleValues (all the possible values for the method, meaninful for a select or a checkbox) + params.defaultValue (the value that the widget would give if it even holds no value) When defining a method in XML, the given value is the default value. e.g. data-select-style="34px" data-css-property="margin-top" -> if set on any widget, allows to retrieve a value from the user to customize the margin-top, the default value being 34px. -> if used with a we-input, allow to retrieve any value and an empty value will be equal to 34px -> if used on a checkbox, allow to toggle between no value and 34px. -> ... Hopefully, detailed documentation about all of this will follow. Code documentation should already be helpful. Last note: the _updateUI method (replacing the old _setActive) is now async (so does all the functions calling it). In particular, the _select method is now async. Part of https://github.com/odoo/odoo/pull/40282 In preparation of task-2122935 and other tasks
Diffstat (limited to 'addons/web_editor/static/src/js/common/utils.js')
-rw-r--r--addons/web_editor/static/src/js/common/utils.js144
1 files changed, 144 insertions, 0 deletions
diff --git a/addons/web_editor/static/src/js/common/utils.js b/addons/web_editor/static/src/js/common/utils.js
new file mode 100644
index 00000000000..f3373c7bad2
--- /dev/null
+++ b/addons/web_editor/static/src/js/common/utils.js
@@ -0,0 +1,144 @@
+odoo.define('web_editor.utils', function (require) {
+'use strict';
+
+/**
+ * window.getComputedStyle cannot work properly with CSS shortcuts (like
+ * 'border-width' which is a shortcut for the top + right + bottom + left border
+ * widths. If an option wants to customize such a shortcut, it should be listed
+ * here with the non-shortcuts property it stands for, in order.
+ *
+ * @type {Object<string[]>}
+ */
+const CSS_SHORTHANDS = {
+ 'border-width': ['border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'],
+ 'border-radius': ['border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius'],
+};
+/**
+ * Key-value mapping to list converters from an unit A to an unit B.
+ * - The key is a string in the format '$1-$2' where $1 is the CSS symbol of
+ * unit A and $2 is the CSS symbol of unit B.
+ * - The value is a function that converts the received value (expressed in
+ * unit A) to another value expressed in unit B. Two other parameters is
+ * received: the css property on which the unit applies and the jQuery element
+ * on which that css property may change.
+ */
+const CSS_UNITS_CONVERSION = {
+ 's-ms': () => 1000,
+ 'ms-s': () => 0.001,
+ 'rem-px': () => _computePxByRem(),
+ 'px-rem': () => _computePxByRem(true),
+};
+
+/**
+ * Computes the number of "px" needed to make a "rem" unit. Subsequent calls
+ * returns the cached computed value.
+ *
+ * @param {boolean} [toRem=false]
+ * @returns {float} - number of px by rem if 'toRem' is false
+ * - the inverse otherwise
+ */
+function _computePxByRem(toRem) {
+ if (_computePxByRem.PX_BY_REM === undefined) {
+ const htmlStyle = window.getComputedStyle(document.documentElement);
+ _computePxByRem.PX_BY_REM = parseFloat(htmlStyle['font-size']);
+ }
+ return toRem ? (1 / _computePxByRem.PX_BY_REM) : _computePxByRem.PX_BY_REM;
+}
+/**
+ * Converts the given (value + unit) string to a numeric value expressed in
+ * the other given css unit.
+ *
+ * e.g. fct('400ms', 's') -> 0.4
+ *
+ * @param {string} value
+ * @param {string} unitTo
+ * @param {string} [cssProp] - the css property on which the unit applies
+ * @param {jQuery} [$target] - the jQuery element on which that css property
+ * may change
+ * @returns {number}
+ */
+function _convertValueToUnit(value, unitTo, cssProp, $target) {
+ const m = _getNumericAndUnit(value);
+ if (!m) {
+ return NaN;
+ }
+ const numValue = parseFloat(m[0]);
+ const valueUnit = m[1];
+ return _convertNumericToUnit(numValue, valueUnit, unitTo, cssProp, $target);
+}
+/**
+ * Converts the given numeric value expressed in the given css unit into
+ * the corresponding numeric value expressed in the other given css unit.
+ *
+ * e.g. fct(400, 'ms', 's') -> 0.4
+ *
+ * @param {number} value
+ * @param {string} unitFrom
+ * @param {string} unitTo
+ * @param {string} [cssProp] - the css property on which the unit applies
+ * @param {jQuery} [$target] - the jQuery element on which that css property
+ * may change
+ * @returns {number}
+ */
+function _convertNumericToUnit(value, unitFrom, unitTo, cssProp, $target) {
+ if (Math.abs(value) < Number.EPSILON || unitFrom === unitTo) {
+ return value;
+ }
+ const converter = CSS_UNITS_CONVERSION[`${unitFrom}-${unitTo}`];
+ if (converter === undefined) {
+ throw new Error(`Cannot convert '${unitFrom}' units into '${unitTo}' units !`);
+ }
+ return value * converter(cssProp, $target);
+}
+/**
+ * Returns the numeric value and unit of a css value.
+ *
+ * e.g. fct('400ms') -> [400, 'ms']
+ *
+ * @param {string} value
+ * @returns {Array|null}
+ */
+function _getNumericAndUnit(value) {
+ const m = value.trim().match(/^([0-9.]+)(\w*)$/);
+ if (!m) {
+ return null;
+ }
+ return [m[1], m[2]];
+}
+/**
+ * Checks if two css values are equal.
+ *
+ * @param {string} value1
+ * @param {string} value2
+ * @param {string} [cssProp] - the css property on which the unit applies
+ * @param {jQuery} [$target] - the jQuery element on which that css property
+ * may change
+ * @returns {boolean}
+ */
+function _areCssValuesEqual(value1, value2, cssProp, $target) {
+ // String comparison first
+ if (value1 === value2) {
+ return true;
+ }
+
+ // Convert the second value in the unit of the first one and compare
+ // floating values
+ const data = _getNumericAndUnit(value1);
+ if (!data) {
+ return false;
+ }
+ const numValue1 = data[0];
+ const numValue2 = _convertValueToUnit(value2, data[1], cssProp, $target);
+ return (Math.abs(numValue1 - numValue2) < Number.EPSILON);
+}
+
+return {
+ CSS_SHORTHANDS: CSS_SHORTHANDS,
+ CSS_UNITS_CONVERSION: CSS_UNITS_CONVERSION,
+ computePxByRem: _computePxByRem,
+ convertValueToUnit: _convertValueToUnit,
+ convertNumericToUnit: _convertNumericToUnit,
+ getNumericAndUnit: _getNumericAndUnit,
+ areCssValuesEqual: _areCssValuesEqual,
+};
+});