summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/basic/basic_controller.js
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2017-03-05 10:05:56 +0100
committerAaron Bohy <aab@odoo.com>2017-04-11 19:44:38 +0200
commit905e01921f3c3ef43ace6fc537d1d8c0d280002c (patch)
tree265c43ab21c5401a5d9f0f3d64d86f1ac417451c /addons/web/static/src/js/views/basic/basic_controller.js
parent54d4c73af4ad05c7640d28c1892247c9538b8017 (diff)
[REF] web, *: redesign all JS views
This commit introduce a full redesign of all JS views. We started basically from scratch. The goal was to unify all the various views under a common framework, to make them testable, to make then usable in different conditions (in studio, or in the frontend), and to make our lives easier. Some important points are: - we introduced new coding guidelines (camelCase, 80 chars width, ...) - we have a brand new testing framework (still QUnit based) - kanban view moved to the web addon - calendar view (formerly web_calender) moved to web as well - the tree view was removed - all new code should be documented We hope that this code is the start of a new era for the Odoo web client, we want to have a high quality codebase, well documented, well tested, well designed. Work done by the framework team: mostly aab, ged, chm, dmo, qsm
Diffstat (limited to 'addons/web/static/src/js/views/basic/basic_controller.js')
-rw-r--r--addons/web/static/src/js/views/basic/basic_controller.js178
1 files changed, 178 insertions, 0 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
new file mode 100644
index 00000000000..24b5c7fa3d0
--- /dev/null
+++ b/addons/web/static/src/js/views/basic/basic_controller.js
@@ -0,0 +1,178 @@
+odoo.define('web.BasicController', function (require) {
+"use strict";
+
+/**
+ * The BasicController is mostly here to share code between views that will use
+ * a BasicModel (or a subclass). Currently, the BasicViews are the form, list
+ * and kanban views.
+ */
+
+var AbstractController = require('web.AbstractController');
+var FieldManagerMixin = require('web.FieldManagerMixin');
+var core = require('web.core');
+var Dialog = require('web.Dialog');
+var Pager = require('web.Pager');
+
+var _t = core._t;
+
+return AbstractController.extend(FieldManagerMixin, {
+ custom_events: _.extend({}, AbstractController.prototype.custom_events, FieldManagerMixin.custom_events, {
+ reload: '_onReload',
+ }),
+ /**
+ * @override
+ * @param {Object} params
+ * @param {boolean} params.archiveEnabled
+ * @param {boolean} params.confirmOnDelete
+ * @param {boolean} params.hasButtons
+ */
+ init: function (parent, model, renderer, params) {
+ this._super.apply(this, arguments);
+ this.archiveEnabled = params.archiveEnabled;
+ this.confirmOnDelete = params.confirmOnDelete;
+ this.hasButtons = params.hasButtons;
+ FieldManagerMixin.init.call(this, this.model);
+ this.handle = params.initialState.id;
+ },
+ /**
+ * @override
+ * @returns {Deferred}
+ */
+ start: function () {
+ return this._super.apply(this, arguments)
+ .then(this._updateEnv.bind(this));
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ renderPager: function ($node, options) {
+ var data = this.model.get(this.handle, {raw: true});
+ this.pager = new Pager(this, data.count, data.offset + 1, data.limit, options);
+
+ this.pager.on('pager_changed', this, function (newState) {
+ var self = this;
+ this.pager.disable();
+ var limitChanged = (data.limit !== newState.limit);
+ this.reload({limit: newState.limit, offset: newState.current_min - 1})
+ .then(function () {
+ // Reset the scroll position to the top on page changed only
+ if (!limitChanged) {
+ self.trigger_up('scrollTo', {offset: 0});
+ }
+ })
+ .then(this.pager.enable.bind(this.pager));
+ });
+ this.pager.appendTo($node);
+ this._updatePager(); // to force proper visibility
+ },
+ /**
+ * @override
+ * @returns {Deferred}
+ */
+ update: function (params, options) {
+ var self = this;
+ return this._super(params, options).then(function () {
+ self._updateEnv();
+ self._updatePager();
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Delete records (and ask for confirmation if necessary)
+ *
+ * @param {string[]} ids list of local record ids
+ */
+ _deleteRecords: function (ids) {
+ var self = this;
+ function doIt() {
+ return self.model
+ .deleteRecords(ids, self.modelName, self.handle)
+ .then(self._onDeletedRecords.bind(self, ids));
+ }
+ if (this.confirmOnDelete) {
+ Dialog.confirm(this, _t("Are you sure you want to delete this record ?"), {
+ confirm_callback: doIt,
+ });
+ } else {
+ doIt();
+ }
+ },
+ /**
+ * Hook method, called when record(s) has been deleted.
+ *
+ * @see _deleteRecord
+ * @param {string[]} ids list of deleted ids (basic model local handles)
+ */
+ _onDeletedRecords: function (ids) {
+ this.update({});
+ },
+ /**
+ * Helper method, to get the current environment variables from the model
+ * and notifies the component chain (by bubbling an event up)
+ */
+ _updateEnv: function () {
+ var env = this.model.get(this.handle, {env: true});
+ this.trigger_up('env_updated', env);
+ },
+ /**
+ * Helper method, to make sure the information displayed by the pager is up
+ * to date.
+ */
+ _updatePager: function () {
+ if (this.pager) {
+ var data = this.model.get(this.handle, {raw: true});
+ this.pager.updateState({
+ current_min: data.offset + 1,
+ size: data.count,
+ });
+ var isRecord = data.type === 'record';
+ var hasData = !!data.count;
+ var isGrouped = data.groupedBy ? !!data.groupedBy.length : false;
+ var isNew = this.model.isNew(this.handle);
+ var isPagerVisible = isRecord ? !isNew : (hasData && !isGrouped);
+
+ this.pager.do_toggle(isPagerVisible);
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * When a reload event triggers up, we need to reload the full view.
+ * For example, after a form view dialog saved some data.
+ *
+ * @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
+ * re-render (reload the whole form by default)
+ * @param {string[]} [event.data.fieldNames] list of the record's fields to
+ * reload
+ */
+ _onReload: function (event) {
+ var data = event && event.data || {};
+ var handle = data.db_id;
+ if (handle) {
+ // reload the relational field given its db_id
+ this.model.reload(handle).then(this._confirmSave.bind(this, handle));
+ } else {
+ // no db_id given, so reload the main record
+ this.reload({fieldNames: data.fieldNames});
+ }
+ },
+
+});
+
+});