summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/basic
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2018-10-22 11:03:17 +0000
committerAaron Bohy <aab@odoo.com>2018-10-23 10:56:12 +0000
commit03fe95d6af9d96f961c47d9acfaec498966b8cfa (patch)
tree4ae97e4007ef1642b21cdaae596201a17e3cb316 /addons/web/static/src/js/views/basic
parent3c59add416fdba779675dc79580f6c0f56abc5a3 (diff)
[REF] web: small refactoring pass on some web components
(mainly views and ActionManager) - add missing docstrings - fix typos - correctly order functions and imports - put functions in correct sections - stop using 'event' as argument of handlers - don't call handlers directly - remove trailing spaces/tabs - move module created in stable version to its own file - follow js guidelines in general closes odoo/odoo#28024
Diffstat (limited to 'addons/web/static/src/js/views/basic')
-rw-r--r--addons/web/static/src/js/views/basic/basic_controller.js30
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js360
-rw-r--r--addons/web/static/src/js/views/basic/basic_renderer.js42
3 files changed, 216 insertions, 216 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js
index 43d604eac0b..0aff337dcbf 100644
--- a/addons/web/static/src/js/views/basic/basic_controller.js
+++ b/addons/web/static/src/js/views/basic/basic_controller.js
@@ -554,16 +554,16 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
*
* @todo: rename db_id into handle
*
- * @param {OdooEvent} event
- * @param {Object} event.data
- * @param {string} [event.data.db_id] handle of the data to reload and
+ * @param {OdooEvent} ev
+ * @param {Object} ev.data
+ * @param {string} [ev.data.db_id] handle of the data to reload and
* re-render (reload the whole form by default)
- * @param {string[]} [event.data.fieldNames] list of the record's fields to
+ * @param {string[]} [ev.data.fieldNames] list of the record's fields to
* reload
*/
- _onReload: function (event) {
- event.stopPropagation(); // prevent other controllers from handling this request
- var data = event && event.data || {};
+ _onReload: function (ev) {
+ ev.stopPropagation(); // prevent other controllers from handling this request
+ var data = ev && ev.data || {};
var handle = data.db_id;
if (handle) {
// reload the relational field given its db_id
@@ -589,28 +589,28 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* performed through the sidebar.
*
* @private
- * @param {OdooEvent} event
+ * @param {OdooEvent} ev
*/
- _onSidebarDataAsked: function (event) {
+ _onSidebarDataAsked: function (ev) {
var sidebarEnv = this._getSidebarEnv();
- event.data.callback(sidebarEnv);
+ ev.data.callback(sidebarEnv);
},
/**
* open the translation view for the current field
*
* @private
- * @param {OdooEvent} event
+ * @param {OdooEvent} ev
*/
- _onTranslate: function (event) {
- event.stopPropagation();
+ _onTranslate: function (ev) {
+ ev.stopPropagation();
var self = this;
- var record = this.model.get(event.data.id, {raw: true});
+ var record = this.model.get(ev.data.id, {raw: true});
this._rpc({
route: '/web/dataset/call_button',
params: {
model: 'ir.translation',
method: 'translate_fields',
- args: [record.model, record.res_id, event.data.fieldName, record.getContext()],
+ args: [record.model, record.res_id, ev.data.fieldName, record.getContext()],
}
}).then(function (result) {
self.do_action(result, {
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index de879018ad5..f8d6daf081d 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -202,6 +202,27 @@ var BasicModel = AbstractModel.extend({
});
},
/**
+ * Completes the fields and fieldsInfo of a dataPoint with the given ones.
+ * It is useful for the cases where a record element is shared between
+ * various views, such as a one2many with a tree and a form view.
+ *
+ * @param {string} recordID a valid element ID
+ * @param {Object} viewInfo
+ * @param {Object} viewInfo.fields
+ * @param {Object} viewInfo.fieldsInfo
+ */
+ addFieldsInfo: function (recordID, viewInfo) {
+ var record = this.localData[recordID];
+ record.fields = _.extend({}, record.fields, viewInfo.fields);
+ // complete the given fieldsInfo with the fields of the main view, so
+ // that those field will be reloaded if a reload is triggered by the
+ // secondary view
+ var fieldsInfo = _.mapObject(viewInfo.fieldsInfo, function (fieldsInfo) {
+ return _.defaults({}, fieldsInfo, record.fieldsInfo[record.viewType]);
+ });
+ record.fieldsInfo = _.extend({}, record.fieldsInfo, fieldsInfo);
+ },
+ /**
* Add and process default values for a given record. Those values are
* parsed and stored in the '_changes' key of the record. For relational
* fields, sub-dataPoints are created, and missing relational data is
@@ -309,108 +330,52 @@ var BasicModel = AbstractModel.extend({
});
},
/**
- * Compute the default value that the handle field should take.
- * We need to compute this in order for new lines to be added at the correct position.
+ * Returns true if a record can be abandoned.
*
- * @private
- * @param {Object} listID
- * @param {string} position
- * @return {Object} empty object if no overrie has to be done, or:
- * field: the name of the field to override,
- * value: the value to use for that field
+ * Case for not abandoning the record:
+ *
+ * 1. flagged as 'no abandon' (i.e. during a `default_get`, including any
+ * `onchange` from a `default_get`)
+ * 2. registered in a list on addition
+ *
+ * 2.1. registered as non-new addition
+ * 2.2. registered as new additon on update
+ *
+ * 3. record is not new
+ *
+ * Otherwise, the record can be abandoned.
+ *
+ * This is useful when discarding changes on this record, as it means that
+ * we must keep the record even if some fields are invalids (e.g. required
+ * field is empty).
+ *
+ * @param {string} id id for a local resource
+ * @returns {boolean}
*/
- _computeOverrideDefaultFields: function (listID, position) {
- var list = this.localData[listID];
- var handleField;
-
- // Here listID is actually just parentID, it's not yet confirmed
- // to be a list.
- // If we are not in the case that interests us,
- // listID will be undefined and this check will work.
- if (!list) {
- return {};
- }
-
- position = position || 'bottom';
-
- // Let's find if there is a field with handle.
- if (!list.fieldsInfo) {
- return {};
+ canBeAbandoned: function (id) {
+ // 1. no drop if flagged
+ if (this.localData[id]._noAbandon) {
+ return false;
}
- for (var field in list.fieldsInfo.list) {
- if (list.fieldsInfo.list[field].widget === 'handle') {
- handleField = field;
- break;
- // If there are 2 handle fields on the same list,
- // we take the first one we find.
- // And that will be alphabetically on the field name...
+ // 2. no drop in a list on "ADD in some cases
+ var record = this.localData[id];
+ var parent = this.localData[record.parentID];
+ if (parent) {
+ var entry = _.findWhere(parent._savePoint, {operation: 'ADD', id: id});
+ if (entry) {
+ // 2.1. no drop on non-new addition in list
+ if (!entry.isNew) {
+ return false;
+ }
+ // 2.2. no drop on new addition on "UPDATE"
+ var lastEntry = _.last(parent._savePoint);
+ if (lastEntry.operation === 'UPDATE' && lastEntry.id === id) {
+ return false;
+ }
}
}
-
- if (!handleField) {
- return {};
- }
-
- // We don't want to override the default value
- // if the list is not ordered by the handle field.
- var isOrderedByHandle = list.orderedBy
- && list.orderedBy.length
- && list.orderedBy[0].asc === true
- && list.orderedBy[0].name === handleField;
-
- if (!isOrderedByHandle) {
- return {};
- }
-
- // We compute the list (get) to apply the pending changes before doing our work,
- // otherwise new lines might not be taken into account.
- // We use raw: true because we only need to load the first level of relation.
- var computedList = this.get(list.id, {raw: true});
-
- // We don't need to worry about the position of a new line if the list is empty.
- if (!computedList || !computedList.data || !computedList.data.length) {
- return {};
- }
-
- // If there are less elements in the list than the limit of
- // the page then take the index of the last existing line.
-
- // If the button is at the top, we want the new element on
- // the first line of the page.
-
- // If the button is at the bottom, we want the new element
- // after the last line of the page
- // (= theorically it will be the first element of the next page).
-
- // We ignore list.offset because computedList.data
- // will only have the current page elements.
-
- var index = Math.min(
- computedList.data.length - 1,
- position !== 'top' ? list.limit - 1 : 0
- );
-
- // This positioning will almost be correct. There might just be
- // an issue if several other lines have the same handleFieldValue.
-
- // TODO ideally: if there is an element with the same handleFieldValue,
- // that one and all the following elements must be incremented
- // by 1 (at least until there is a gap in the numbering).
-
- // We don't do it now because it's not an important case.
- // However, we can for sure increment by 1 if we are on the last page.
-
- var handleFieldValue = computedList.data[index].data[handleField];
- if (position === 'top') {
- handleFieldValue--;
- } else if (list.count <= list.offset + list.limit - (list.tempLimitIncrement || 0)) {
- handleFieldValue++;
- }
-
- return {
- field: handleField,
- value: handleFieldValue,
- };
+ // 3. drop new records
+ return this.isNew(id);
},
/**
* Delete a list of records, then, if the records have a parent, reload it.
@@ -518,6 +483,20 @@ var BasicModel = AbstractModel.extend({
});
},
/**
+ * For list resources, this freezes the current records order.
+ *
+ * @param {string} listID a valid element ID of type list
+ */
+ freezeOrder: function (listID) {
+ var list = this.localData[listID];
+ if (list.type === 'record') {
+ return;
+ }
+ list = this._applyX2ManyOperations(list);
+ this._sortList(list);
+ this.localData[listID].orderedResIDs = list.res_ids;
+ },
+ /**
* The get method first argument is the handle returned by the load method.
* It is optional (the handle can be undefined). In some case, it makes
* sense to use the handle as a key, for example the BasicModel holds the
@@ -692,54 +671,6 @@ var BasicModel = AbstractModel.extend({
return _t("New");
},
/**
- * Returns true if a record can be abandoned.
- *
- * Case for not abandoning the record:
- *
- * 1. flagged as 'no abandon' (i.e. during a `default_get`, including any
- * `onchange` from a `default_get`)
- * 2. registered in a list on addition
- *
- * 2.1. registered as non-new addition
- * 2.2. registered as new additon on update
- *
- * 3. record is not new
- *
- * Otherwise, the record can be abandoned.
- *
- * This is useful when discarding changes on this record, as it means that
- * we must keep the record even if some fields are invalids (e.g. required
- * field is empty).
- *
- * @param {string} id id for a local resource
- * @returns {boolean}
- */
- canBeAbandoned: function (id) {
- // 1. no drop if flagged
- if (this.localData[id]._noAbandon) {
- return false;
- }
- // 2. no drop in a list on "ADD in some cases
- var record = this.localData[id];
- var parent = this.localData[record.parentID];
- if (parent) {
- var entry = _.findWhere(parent._savePoint, {operation: 'ADD', id: id});
- if (entry) {
- // 2.1. no drop on non-new addition in list
- if (!entry.isNew) {
- return false;
- }
- // 2.2. no drop on new addition on "UPDATE"
- var lastEntry = _.last(parent._savePoint);
- if (lastEntry.operation === 'UPDATE' && lastEntry.id === id) {
- return false;
- }
- }
- }
- // 3. drop new records
- return this.isNew(id);
- },
- /**
* Returns true if a record is dirty. A record is considered dirty if it has
* some unsaved changes, marked by the _isDirty property on the record or
* one of its subrecords.
@@ -1176,41 +1107,6 @@ var BasicModel = AbstractModel.extend({
});
},
/**
- * Completes the fields and fieldsInfo of a dataPoint with the given ones.
- * It is useful for the cases where a record element is shared between
- * various views, such as a one2many with a tree and a form view.
- *
- * @param {string} recordID a valid element ID
- * @param {Object} viewInfo
- * @param {Object} viewInfo.fields
- * @param {Object} viewInfo.fieldsInfo
- */
- addFieldsInfo: function (recordID, viewInfo) {
- var record = this.localData[recordID];
- record.fields = _.extend({}, record.fields, viewInfo.fields);
- // complete the given fieldsInfo with the fields of the main view, so
- // that those field will be reloaded if a reload is triggered by the
- // secondary view
- var fieldsInfo = _.mapObject(viewInfo.fieldsInfo, function (fieldsInfo) {
- return _.defaults({}, fieldsInfo, record.fieldsInfo[record.viewType]);
- });
- record.fieldsInfo = _.extend({}, record.fieldsInfo, fieldsInfo);
- },
- /**
- * For list resources, this freezes the current records order.
- *
- * @param {string} listID a valid element ID of type list
- */
- freezeOrder: function (listID) {
- var list = this.localData[listID];
- if (list.type === 'record') {
- return;
- }
- list = this._applyX2ManyOperations(list);
- this._sortList(list);
- this.localData[listID].orderedResIDs = list.res_ids;
- },
- /**
* Manually sets a resource as dirty. This is used to notify that a field
* has been modified, but with an invalid value. In that case, the value is
* not sent to the basic model, but the record should still be flagged as
@@ -2062,6 +1958,110 @@ var BasicModel = AbstractModel.extend({
return hasOnchange ? specs : false;
},
/**
+ * Compute the default value that the handle field should take.
+ * We need to compute this in order for new lines to be added at the correct position.
+ *
+ * @private
+ * @param {Object} listID
+ * @param {string} position
+ * @return {Object} empty object if no overrie has to be done, or:
+ * field: the name of the field to override,
+ * value: the value to use for that field
+ */
+ _computeOverrideDefaultFields: function (listID, position) {
+ var list = this.localData[listID];
+ var handleField;
+
+ // Here listID is actually just parentID, it's not yet confirmed
+ // to be a list.
+ // If we are not in the case that interests us,
+ // listID will be undefined and this check will work.
+ if (!list) {
+ return {};
+ }
+
+ position = position || 'bottom';
+
+ // Let's find if there is a field with handle.
+ if (!list.fieldsInfo) {
+ return {};
+ }
+ for (var field in list.fieldsInfo.list) {
+ if (list.fieldsInfo.list[field].widget === 'handle') {
+ handleField = field;
+ break;
+ // If there are 2 handle fields on the same list,
+ // we take the first one we find.
+ // And that will be alphabetically on the field name...
+ }
+ }
+
+ if (!handleField) {
+ return {};
+ }
+
+ // We don't want to override the default value
+ // if the list is not ordered by the handle field.
+ var isOrderedByHandle = list.orderedBy
+ && list.orderedBy.length
+ && list.orderedBy[0].asc === true
+ && list.orderedBy[0].name === handleField;
+
+ if (!isOrderedByHandle) {
+ return {};
+ }
+
+ // We compute the list (get) to apply the pending changes before doing our work,
+ // otherwise new lines might not be taken into account.
+ // We use raw: true because we only need to load the first level of relation.
+ var computedList = this.get(list.id, {raw: true});
+
+ // We don't need to worry about the position of a new line if the list is empty.
+ if (!computedList || !computedList.data || !computedList.data.length) {
+ return {};
+ }
+
+ // If there are less elements in the list than the limit of
+ // the page then take the index of the last existing line.
+
+ // If the button is at the top, we want the new element on
+ // the first line of the page.
+
+ // If the button is at the bottom, we want the new element
+ // after the last line of the page
+ // (= theorically it will be the first element of the next page).
+
+ // We ignore list.offset because computedList.data
+ // will only have the current page elements.
+
+ var index = Math.min(
+ computedList.data.length - 1,
+ position !== 'top' ? list.limit - 1 : 0
+ );
+
+ // This positioning will almost be correct. There might just be
+ // an issue if several other lines have the same handleFieldValue.
+
+ // TODO ideally: if there is an element with the same handleFieldValue,
+ // that one and all the following elements must be incremented
+ // by 1 (at least until there is a gap in the numbering).
+
+ // We don't do it now because it's not an important case.
+ // However, we can for sure increment by 1 if we are on the last page.
+
+ var handleFieldValue = computedList.data[index].data[handleField];
+ if (position === 'top') {
+ handleFieldValue--;
+ } else if (list.count <= list.offset + list.limit - (list.tempLimitIncrement || 0)) {
+ handleFieldValue++;
+ }
+
+ return {
+ field: handleField,
+ value: handleFieldValue,
+ };
+ },
+ /**
* Evaluate modifiers
*
* @private
diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js
index 33267283a15..8db200183ef 100644
--- a/addons/web/static/src/js/views/basic/basic_renderer.js
+++ b/addons/web/static/src/js/views/basic/basic_renderer.js
@@ -136,31 +136,12 @@ var BasicRenderer = AbstractRenderer.extend({
dom.setSelectionRange(field.getFocusableElement().get(0), {start: offset, end: offset});
}
},
+
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
- * Add a tooltip on a $node, depending on a field description
- *
- * @param {FieldWidget} widget
- * @param {$node} $node
- */
- _addFieldTooltip: function (widget, $node) {
- // optional argument $node, the jQuery element on which the tooltip
- // should be attached if not given, the tooltip is attached on the
- // widget's $el
- $node = $node.length ? $node : widget.$el;
- $node.tooltip({
- title: function () {
- return qweb.render('WidgetLabel.tooltip', {
- debug: config.debug,
- widget: widget,
- });
- }
- });
- },
- /**
* Activates the widget at the given index for the given record if possible
* or the "next" possible one. Usually, a widget can be activated if it is
* in edit mode, and if it is visible.
@@ -239,6 +220,26 @@ var BasicRenderer = AbstractRenderer.extend({
return this._activateFieldWidget(record, currentIndex, {inc:-1});
},
/**
+ * Add a tooltip on a $node, depending on a field description
+ *
+ * @param {FieldWidget} widget
+ * @param {$node} $node
+ */
+ _addFieldTooltip: function (widget, $node) {
+ // optional argument $node, the jQuery element on which the tooltip
+ // should be attached if not given, the tooltip is attached on the
+ // widget's $el
+ $node = $node.length ? $node : widget.$el;
+ $node.tooltip({
+ title: function () {
+ return qweb.render('WidgetLabel.tooltip', {
+ debug: config.debug,
+ widget: widget,
+ });
+ }
+ });
+ },
+ /**
* Does the necessary DOM updates to match the given modifiers data. The
* modifiers data is supposed to contain the properly evaluated modifiers
* associated to the given records and elements.
@@ -685,7 +686,6 @@ var BasicRenderer = AbstractRenderer.extend({
return $el;
},
-
/**
* Rerenders a given widget and make sure the associated data which
* referenced the old one is updated.