From d4fdbad99a776052340d0ea941cac8e85cdfebc5 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Tue, 14 Mar 2017 10:30:10 +0100 Subject: [PATCH] [REF] web: kanban: adapt code to new style This commit adapts some kanban files to the new style and guidelines. --- .../src/js/views/kanban/kanban_column.js | 247 +++++++++++------- .../src/js/views/kanban/kanban_controller.js | 18 +- .../src/js/views/kanban/kanban_model.js | 190 +++++++++----- .../src/js/views/kanban/kanban_record.js | 4 +- .../src/js/views/kanban/kanban_renderer.js | 201 ++++++++------ 5 files changed, 412 insertions(+), 248 deletions(-) diff --git a/addons/web/static/src/js/views/kanban/kanban_column.js b/addons/web/static/src/js/views/kanban/kanban_column.js index b93f75cd9df..9dab04aa4fc 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column.js +++ b/addons/web/static/src/js/views/kanban/kanban_column.js @@ -4,36 +4,33 @@ odoo.define('web.KanbanColumn', function (require) { var config = require('web.config'); var core = require('web.core'); var Dialog = require('web.Dialog'); -var view_dialogs = require('web.view_dialogs'); -var quick_create = require('web.kanban_quick_create'); +var kanban_quick_create = require('web.kanban_quick_create'); var KanbanRecord = require('web.KanbanRecord'); +var view_dialogs = require('web.view_dialogs'); var Widget = require('web.Widget'); var _t = core._t; var QWeb = core.qweb; -var RecordQuickCreate = quick_create.RecordQuickCreate; +var RecordQuickCreate = kanban_quick_create.RecordQuickCreate; var KanbanColumn = Widget.extend({ - template: "KanbanView.Group", - events: { - 'click .o_column_edit': 'edit_column', - 'click .o_column_delete': 'delete_column', - 'click .o_column_archive': 'archive_records', - 'click .o_column_unarchive': 'unarchive_records', - 'click .o_kanban_quick_add': 'add_quick_create', - 'click .o_kanban_load_more': 'load_more', - 'click .o_kanban_toggle_fold': 'toggle_fold', - }, + template: 'KanbanView.Group', custom_events: { - 'kanban_record_delete': 'delete_record', - 'cancel_quick_create': 'cancel_quick_create', - 'quick_create_add_record': 'quick_create_add_record', + cancel_quick_create: '_onCancelQuickCreate', + kanban_record_delete: '_onDeleteRecord', + quick_create_add_record: '_onQuickCreateAddRecord', + }, + events: { + 'click .o_column_edit': '_onEditColumn', + 'click .o_column_delete': '_onDeleteColumn', + 'click .o_column_archive': '_onArchiveRecords', + 'click .o_column_unarchive': '_onUnarchiveRecords', + 'click .o_kanban_quick_add': '_onAddQuickCreate', + 'click .o_kanban_load_more': '_onLoadMore', + 'click .o_kanban_toggle_fold': '_onToggleFold', }, /** - * @param {any} parent - * @param {any} data - * @param {any} options - * @param {any} recordOptions + * @override */ init: function (parent, data, options, recordOptions) { this._super(parent); @@ -81,14 +78,14 @@ var KanbanColumn = Widget.extend({ } }, /** - * @returns {Deferred} + * @override */ start: function () { var self = this; this.$header = this.$('.o_kanban_header'); for (var i = 0; i < this.data_records.length; i++) { - this.add_record(this.data_records[i], {no_update: true}); + this.addRecord(this.data_records[i], {no_update: true}); } this.$header.tooltip(); @@ -105,7 +102,7 @@ var KanbanColumn = Widget.extend({ cursor: 'move', over: function () { self.$el.addClass('o_kanban_hover'); - self.update_column(); + self._update(); }, out: function () { self.$el.removeClass('o_kanban_hover'); @@ -118,34 +115,61 @@ var KanbanColumn = Widget.extend({ if (index >= 0) { if ($.contains(self.$el[0], record.$el[0])) { // resequencing records - self.trigger_up('kanban_column_resequence', {ids: self.get_ids()}); + self.trigger_up('kanban_column_resequence', {ids: self._getIDs()}); } } else { // adding record to this column - self.trigger_up('kanban_column_add_record', {record: record, ids: self.get_ids()}); + self.trigger_up('kanban_column_add_record', {record: record, ids: self._getIDs()}); } } }); } this.$el.click(function (event) { if (self.folded) { - self.toggle_fold(event); + self._onToggleFold(event); } }); - this.update_column(); + this._update(); return this._super.apply(this, arguments); }, - is_empty: function () { - return !this.records.length; - }, + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - add_record: function (data, options) { - var record = new KanbanRecord(this, data, this.record_options); + /** + * Adds the quick create record to the top of the column. + */ + addQuickCreate: function () { + if (this.quickCreateWidget) { + return; + } + var self = this; + var width = this.records.length ? this.records[0].$el.innerWidth() : this.$el.width() - 8; + this.quickCreateWidget = new RecordQuickCreate(this, width); + this.quickCreateWidget.insertAfter(this.$header); + this.quickCreateWidget.$el.focusout(function () { + var hasFocus = (self.quickCreateWidget.$(':focus').length > 0); + if (! hasFocus && self.quickCreateWidget) { + self._cancelQuickCreate(); + } + }); + }, + /** + * Adds a record in the column. + * + * @param {Object} recordState + * @param {Object} options + * @params {string} options.position 'before' to add the record at the top, + * added at the bottom by default + * @params {Boolean} options.no_update set to true not to update the column + */ + addRecord: function (recordState, options) { + var record = new KanbanRecord(this, recordState, this.record_options); this.records.push(record); if (options.position === 'before') { - record.insertAfter(this.quick_create_widget ? this.quick_create_widget.$el : this.$header); + record.insertAfter(this.quickCreateWidget ? this.quickCreateWidget.$el : this.$header); } else { var $load_more = this.$('.o_kanban_load_more'); if ($load_more.length) { @@ -155,19 +179,43 @@ var KanbanColumn = Widget.extend({ } } if (!options.no_update) { - this.update_column(); + this._update(); } }, + /** + * @returns {Boolean} true iff the column is empty + */ + isEmpty: function () { + return !this.records.length; + }, - get_ids: function () { + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Destroys the QuickCreate widget. + * + * @private + */ + _cancelQuickCreate: function () { + this.quickCreateWidget.destroy(); + this.quickCreateWidget = undefined; + }, + /** + * @returns {integer[]} the res_ids of the records in the column + */ + _getIDs: function () { var ids = []; this.$('.o_kanban_record').each(function (index, r) { ids.push($(r).data('record').id); }); return ids; }, - - update_column: function () { + /** + * @private + */ + _update: function () { var title = this.folded ? this.title + ' (' + this.size + ')' : this.title; this.$header.find('.o_column_title').text(title); this.$header.find('.o-kanban-count').text(this.records.length); @@ -183,29 +231,42 @@ var KanbanColumn = Widget.extend({ } }, - archive_records: function (event) { + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @private + */ + _onAddQuickCreate: function () { + this.addQuickCreate(); + }, + /** + * @private + * @param {MouseEvent} event + */ + _onArchiveRecords: function (event) { event.preventDefault(); this.trigger_up('kanban_column_archive_records', {archive: true}); }, - - unarchive_records: function (event) { - event.preventDefault(); - this.trigger_up('kanban_column_archive_records', {archive: false}); + /** + * @private + */ + _onCancelQuickCreate: function () { + this.cancelQuickCreate(); }, - - toggle_fold: function (event) { - event.preventDefault(); - this.trigger_up('column_toggle_fold'); - }, - - delete_column: function (event) { + /** + * @private + * @param {MouseEvent} event + */ + _onDeleteColumn: function (event) { event.preventDefault(); var buttons = [ { text: _t("Ok"), classes: 'btn-primary', close: true, - click: this.trigger_up.bind(this, 'kanban_column_delete') + click: this.trigger_up.bind(this, 'kanban_column_delete'), }, {text: _t("Cancel"), close: true} ]; @@ -217,8 +278,24 @@ var KanbanColumn = Widget.extend({ }), }).open(); }, - - edit_column: function (event) { + /** + * @private + * @param {OdooEvent} event + */ + _onDeleteRecord: function (event) { + var self = this; + event.data.parent_id = this.db_id; + event.data.after = function cleanup() { + var index = self.records.indexOf(event.data.record); + self.records.splice(index, 1); + self._update(); + }; + }, + /** + * @private + * @param {MouseEvent} event + */ + _onEditColumn: function (event) { event.preventDefault(); new view_dialogs.FormViewDialog(this, { res_model: this.relation, @@ -227,47 +304,37 @@ var KanbanColumn = Widget.extend({ on_saved: this.trigger_up.bind(this, 'reload'), }).open(); }, - - delete_record: function (event) { - var self = this; - event.data.parent_id = this.db_id; - event.data.after = function cleanup() { - var index = self.records.indexOf(event.data.record); - self.records.splice(index, 1); - self.update_column(); - }; - }, - - add_quick_create: function () { - if (this.quick_create_widget) { - return; - } - var self = this; - var width = this.records.length ? this.records[0].$el.innerWidth() : this.$el.width() - 8; - this.quick_create_widget = new RecordQuickCreate(this, width); - this.quick_create_widget.insertAfter(this.$header); - this.quick_create_widget.$el.focusout(function () { - var hasFocus = (self.quick_create_widget.$(':focus').length > 0); - if (! hasFocus && self.quick_create_widget) { - self.cancel_quick_create(); - } - }); - }, - - cancel_quick_create: function () { - this.quick_create_widget.destroy(); - this.quick_create_widget = undefined; - }, - - quick_create_add_record: function (event) { - this.trigger_up('quick_create_record', event.data); - }, - - load_more: function (event) { + /** + * @private + * @param {MouseEvent} event + */ + _onLoadMore: function (event) { event.preventDefault(); this.trigger_up('kanban_load_more'); }, - + /** + * @private + * @param {OdooEvent} event + */ + _onQuickCreateAddRecord: function (event) { + this.trigger_up('quick_create_record', event.data); + }, + /** + * @private + * @param {MouseEvent} event + */ + _onToggleFold: function (event) { + event.preventDefault(); + this.trigger_up('column_toggle_fold'); + }, + /** + * @private + * @param {MouseEvent} event + */ + _onUnarchiveRecords: function (event) { + event.preventDefault(); + this.trigger_up('kanban_column_archive_records', {archive: false}); + }, }); return KanbanColumn; diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 6061ef436b7..c00cbc568d2 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -59,7 +59,7 @@ var KanbanController = BasicController.extend({ var data = self.model.get(self.handle, {raw: true}); if (data.groupedBy.length > 0 && data.count > 0 && self.on_create === 'quick_create') { // Activate the quick create in the first column - self.renderer.add_quick_create(); + self.renderer.addQuickCreate(); } else if (self.on_create && self.on_create !== 'quick_create') { // Execute the given action self.do_action(self.on_create, { @@ -101,7 +101,7 @@ var KanbanController = BasicController.extend({ * @param {string} id local id from the basic record data */ _confirmSave: function (id) { - this.renderer.update_record(this.model.get(id)); + this.renderer.updateRecord(this.model.get(id)); }, /** * @todo this is dead code right now. resurrect this? @@ -181,7 +181,7 @@ var KanbanController = BasicController.extend({ .then(function () { _.each(column_db_ids, function (db_id) { var data = self.model.get(db_id); - self.renderer.update_column(db_id, data); + self.renderer.updateColumn(db_id, data); }); }); }).fail(this.reload.bind(this)); @@ -207,7 +207,7 @@ var KanbanController = BasicController.extend({ .toggleActive(record_ids, active_value, column.db_id) .then(function (db_id) { var data = self.model.get(db_id); - self.renderer.update_column(db_id, data); + self.renderer.updateColumn(db_id, data); }); } }, @@ -228,8 +228,8 @@ var KanbanController = BasicController.extend({ this.model .deleteRecords([column.db_id], relatedModelName, this.handle) .done(function () { - if (column.is_empty()) { - self.renderer.remove_widget(column); + if (column.isEmpty()) { + self.renderer.removeWidget(column); self._updateButtons(); } else { self.reload(); @@ -255,7 +255,7 @@ var KanbanController = BasicController.extend({ var column = event.target; this.model.load_more(column.db_id).then(function (db_id) { var data = self.model.get(db_id); - self.renderer.update_column(db_id, data); + self.renderer.updateColumn(db_id, data); }); }, /** @@ -297,7 +297,7 @@ var KanbanController = BasicController.extend({ return self.model .addRecordToGroup(data.id, records[0]) .then(function (db_id) { - column.add_record(self.model.get(db_id), {position: 'before'}); + column.addRecord(self.model.get(db_id), {position: 'before'}); }); } data.context['default_' + data.groupedBy[0]] = column.id; @@ -347,7 +347,7 @@ var KanbanController = BasicController.extend({ var column = event.target; this.model.toggleGroup(column.db_id).then(function (db_id) { var data = self.model.get(db_id); - self.renderer.update_column(db_id, data); + self.renderer.updateColumn(db_id, data); }); }, /** diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js index 780039edacc..2bfe117829d 100644 --- a/addons/web/static/src/js/views/kanban/kanban_model.js +++ b/addons/web/static/src/js/views/kanban/kanban_model.js @@ -1,26 +1,30 @@ odoo.define('web.KanbanModel', function (require) { "use strict"; +/** + * The KanbanModel extends the BasicModel to add Kanban specific features like + * moving a record from a group to another, resequencing records... + */ + var BasicModel = require('web.BasicModel'); -return BasicModel.extend({ - load: function (params) { - this.defaultGroupedBy = params.groupBy; - params.groupedBy = params.groupedBy.length ? params.groupedBy : this.defaultGroupedBy; - return this._super(params); - }, - reload: function (id, options) { - // if the groupBy is given in the options and if it is an empty array, - // fallback on the default groupBy - if (options && options.groupBy && !options.groupBy.length) { - options.groupBy = this.defaultGroupedBy; - } - return this._super(id, options); - }, - addRecordToGroup: function (group_id, res_id) { - var group = this.localData[group_id]; +var KanbanModel = BasicModel.extend({ + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Adds a record to a group in the localData, and fetch the record. + * + * @param {string} groupID localID of the group + * @param {integer} resId id of the record + * @returns {Deferred} resolves to the local id of the new record + */ + addRecordToGroup: function (groupID, resId) { + var group = this.localData[groupID]; var new_record = this._makeDataPoint({ - res_id: res_id, + res_id: resId, modelName: group.model, fields: group.fields, fieldNames: group.fieldNames, @@ -34,60 +38,13 @@ return BasicModel.extend({ return result.id; }); }, - moveRecord: function (record_id, group_id, parent_id) { - var self = this; - var parent = this.localData[parent_id]; - var new_group = this.localData[group_id]; - var changes = {}; - var groupedFieldName = parent.groupedBy[0]; - var groupedField = parent.fields[groupedFieldName]; - if (groupedField.type === 'many2one') { - changes[groupedFieldName] = { - id: new_group.res_id, - display_name: new_group.value, - }; - } else { - changes[groupedFieldName] = new_group.value; - } - return this.notifyChanges(record_id, changes).then(function () { - return self.save(record_id); - }).then(function (result) { - // Remove record from its current group - var old_group; - for (var i = 0; i < parent.count; i++) { - old_group = self.localData[parent.data[i]]; - var index = _.indexOf(old_group.data, record_id); - if (index >= 0) { - old_group.data.splice(index, 1); - old_group.count--; - break; - } - } - // Add record to its new group - new_group.data.push(result.id); - new_group.count++; - return [old_group.id, new_group.id]; - }); - }, - resequence: function (modelName, res_ids, parent_id) { - if ((res_ids.length <= 1)) { - return $.when(parent_id); // there is nothing to sort - } - var self = this; - var data = self.localData[parent_id]; - var def; - if (data.fields.sequence) { - def = this._rpc('/web/dataset/resequence') - .params({model: modelName, ids: res_ids}) - .exec(); - } - return $.when(def).then(function () { - data.data = _.sortBy(data.data, function (d) { - return _.indexOf(res_ids, d.res_id); - }); - return parent_id; - }); - }, + /** + * Creates a new group from a name (performs a name_create). + * + * @param {string} name + * @param {string} parentID localID of the parent of the group + * @returns {Deferred} resolves to the local id of the new group + */ createGroup: function (name, parentID) { var self = this; var parent = this.localData[parentID]; @@ -121,6 +78,97 @@ return BasicModel.extend({ return newGroup.id; }); }, + /** + * @override + */ + load: function (params) { + this.defaultGroupedBy = params.groupBy; + params.groupedBy = params.groupedBy.length ? params.groupedBy : this.defaultGroupedBy; + return this._super(params); + }, + /** + * Moves a record from a group to another. + * + * @param {string} recordID localID of the record + * @param {string} groupID localID of the new group of the record + * @param {string} parentID localID of the parent + * @returns {Deferred} resolves to a pair [oldGroupID, newGroupID] + */ + moveRecord: function (recordID, groupID, parentID) { + var self = this; + var parent = this.localData[parentID]; + var new_group = this.localData[groupID]; + var changes = {}; + var groupedFieldName = parent.groupedBy[0]; + var groupedField = parent.fields[groupedFieldName]; + if (groupedField.type === 'many2one') { + changes[groupedFieldName] = { + id: new_group.res_id, + display_name: new_group.value, + }; + } else { + changes[groupedFieldName] = new_group.value; + } + return this.notifyChanges(recordID, changes).then(function () { + return self.save(recordID); + }).then(function (result) { + // Remove record from its current group + var old_group; + for (var i = 0; i < parent.count; i++) { + old_group = self.localData[parent.data[i]]; + var index = _.indexOf(old_group.data, recordID); + if (index >= 0) { + old_group.data.splice(index, 1); + old_group.count--; + break; + } + } + // Add record to its new group + new_group.data.push(result.id); + new_group.count++; + return [old_group.id, new_group.id]; + }); + }, + /** + * @override + */ + reload: function (id, options) { + // if the groupBy is given in the options and if it is an empty array, + // fallback on the default groupBy + if (options && options.groupBy && !options.groupBy.length) { + options.groupBy = this.defaultGroupedBy; + } + return this._super(id, options); + }, + /** + * Resequences records. + * + * @param {string} modelName + * @param {Array[integer]} resIDs the new sequence of ids + * @param {string]} parentID the localID of the parent + * @returns {Deferred} resolves to the local id of the parent + */ + resequence: function (modelName, resIDs, parentID) { + if ((resIDs.length <= 1)) { + return $.when(parentID); // there is nothing to sort + } + var self = this; + var data = self.localData[parentID]; + var def; + if (data.fields.sequence) { + def = this._rpc('/web/dataset/resequence') + .params({model: modelName, ids: resIDs}) + .exec(); + } + return $.when(def).then(function () { + data.data = _.sortBy(data.data, function (d) { + return _.indexOf(resIDs, d.res_id); + }); + return parentID; + }); + }, }); +return KanbanModel; + }); diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index d82c79b592b..2aeff18867b 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -14,14 +14,12 @@ var _t = core._t; var KanbanRecord = Widget.extend({ template: 'KanbanView.record', - events: { 'click .oe_kanban_action': 'on_kanban_action_clicked', 'click .o_kanban_manage_toggle_button': 'toggle_manage_pane', }, - custom_events: { - 'kanban_update_record': 'update_record', + kanban_update_record: 'update_record', }, init: function (parent, state, options) { diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js index fd6bc6b6419..faeb08d72bc 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js @@ -15,7 +15,7 @@ var ColumnQuickCreate = quick_create.ColumnQuickCreate; var qweb = core.qweb; -function find_in_node(node, predicate) { +function findInNode(node, predicate) { if (predicate(node)) { return node; } @@ -23,25 +23,25 @@ function find_in_node(node, predicate) { return undefined; } for (var i = 0; i < node.children.length; i++) { - if (find_in_node(node.children[i], predicate)) { + if (findInNode(node.children[i], predicate)) { return node.children[i]; } } } -function qweb_add_if(node, condition) { +function qwebAddIf(node, condition) { if (node.attrs[qweb.prefix + '-if']) { condition = _.str.sprintf("(%s) and (%s)", node.attrs[qweb.prefix + '-if'], condition); } node.attrs[qweb.prefix + '-if'] = condition; } -function transform_qweb_template(node, fields) { +function transformQwebTemplate(node, fields) { // Process modifiers if (node.tag && node.attrs.modifiers) { var modifiers = JSON.parse(node.attrs.modifiers || "{}"); if (modifiers.invisible) { - qweb_add_if(node, _.str.sprintf("!kanban_compute_domain(%s)", JSON.stringify(modifiers.invisible))); + qwebAddIf(node, _.str.sprintf("!kanban_compute_domain(%s)", JSON.stringify(modifiers.invisible))); } } switch (node.tag) { @@ -108,116 +108,136 @@ function transform_qweb_template(node, fields) { } if (node.children) { for (var i = 0, ii = node.children.length; i < ii; i++) { - transform_qweb_template(node.children[i], fields); + transformQwebTemplate(node.children[i], fields); } } } -return BasicRenderer.extend({ - className: "o_kanban_view", +var KanbanRenderer = BasicRenderer.extend({ + className: 'o_kanban_view', + /** + * @override + */ init: function (parent, state, params) { this._super.apply(this, arguments); this.qweb = new QWeb(session.debug, {_s: session.origin}); - var templates = find_in_node(this.arch, function (n) { return n.tag === 'templates';}); - transform_qweb_template(templates, state.fields); + var templates = findInNode(this.arch, function (n) { return n.tag === 'templates';}); + transformQwebTemplate(templates, state.fields); this.qweb.add_template(utils.json_node_to_xml(templates)); - this.record_options = _.extend({}, params.record_options, { qweb: this.qweb }); - this.column_options = _.extend({}, params.column_options, { qweb: this.qweb }); + this.recordOptions = _.extend({}, params.record_options, { qweb: this.qweb }); + this.columnOptions = _.extend({}, params.column_options, { qweb: this.qweb }); }, - update: function (state, fields) { - this.fields = fields; - return this._super(state); + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Displays the quick create record in the first column. + */ + addQuickCreate: function () { + this.widgets[0].addQuickCreate(); }, - update_record: function (record_state) { - var is_grouped = !!this.state.groupedBy.length; + /** + * Removes a widget (record if ungrouped, column if grouped) from the view. + * + * @param {Widget} widget the instance of the widget to remove + */ + removeWidget: function (widget) { + this.widgets.splice(this.widgets.indexOf(widget), 1); + widget.destroy(); + }, + /** + * Updates a given column with its new state. + * + * @param {string} localID the column id + * @param {Object} columnState + * + * @returns {Deferred} + */ + updateColumn: function (localID, columnState) { + var column = _.findWhere(this.widgets, {db_id: localID}); + this.widgets.splice(_.indexOf(this.widgets, column), 1); // remove column from widgets' list + var newColumn = new KanbanColumn(this, columnState, this.columnOptions, this.recordOptions); + this.widgets.push(newColumn); + return newColumn.insertAfter(column.$el).then(column.destroy.bind(column)); + }, + /** + * Updates a given record with its new state. + * + * @param {Object} recordState + */ + updateRecord: function (recordState) { + var isGrouped = !!this.state.groupedBy.length; var record; - if (is_grouped) { - // if grouped, this.widgets are kanban columns - // so we need to find the kanban record inside + if (isGrouped) { + // if grouped, this.widgets are kanban columns so we need to find + // the kanban record inside _.each(this.widgets, function (widget) { - record = record || _.findWhere(widget.records, {db_id: record_state.id}); + record = record || _.findWhere(widget.records, { + db_id: recordState.id, + }); }); } else { - record = _.findWhere(this.widgets, {db_id: record_state.id}); + record = _.findWhere(this.widgets, {db_id: recordState.id}); } if (record) { - record.update(record_state); + record.update(recordState); } }, - update_column: function (column_db_id, data) { - var column = _.findWhere(this.widgets, {db_id: column_db_id}); - this.widgets.splice(_.indexOf(this.widgets, column), 1); // remove column from widgets' list - var new_column = new KanbanColumn(this, data, this.column_options, this.record_options); - this.widgets.push(new_column); - return new_column.insertAfter(column.$el).then(column.destroy.bind(column)); - }, - _renderView: function () { - var is_grouped = !!this.state.groupedBy.length; - this.$el.toggleClass('o_kanban_grouped', is_grouped); - this.$el.toggleClass('o_kanban_ungrouped', !is_grouped); - this.$el.empty(); - var fragment = document.createDocumentFragment(); - if (is_grouped) { - this._renderGrouped(fragment); - } else { - this._render_ungrouped(fragment); - } - this.$el.append(fragment); - return this._super.apply(this, arguments); - }, - _render_ungrouped: function (fragment) { - var self = this; - _.each(this.state.data, function (record) { - var kanban_record = new KanbanRecord(self, record, self.record_options); - self.widgets.push(kanban_record); - kanban_record.appendTo(fragment); - }); + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- - // append ghost divs to ensure that all kanban records are left aligned - this._appendGhostDivs(fragment, 6); - }, /** - * Appends empty invisible divs to a document fragment. + * Renders empty invisible divs in a document fragment. * + * @private * @param {DocumentFragment} fragment * @param {integer} nbDivs the number of divs to append */ - _appendGhostDivs: function (fragment, nbDivs) { + _renderGhostDivs: function (fragment, nbDivs) { for (var $ghost, i = 0; i < nbDivs; i++) { $ghost = $('
').addClass('o_kanban_record o_kanban_ghost'); $ghost.appendTo(fragment); } }, + /** + * Renders an grouped kanban view in a fragment. + * + * @private + * @param {DocumentFragment} fragment + */ _renderGrouped: function (fragment) { var self = this; - var group_by_field_attrs = this.state.fields[this.state.groupedBy[0]]; + var groupByFieldAttrs = this.state.fields[this.state.groupedBy[0]]; // Deactivate the drag'n'drop if the groupedBy field: // - is a date or datetime since we group by month or // - is readonly var draggable = true; - if (group_by_field_attrs) { - if (group_by_field_attrs.type === "date" || group_by_field_attrs.type === "datetime") { + if (groupByFieldAttrs) { + if (groupByFieldAttrs.type === "date" || groupByFieldAttrs.type === "datetime") { draggable = false; - } else if (group_by_field_attrs.readonly !== undefined) { - draggable = !(group_by_field_attrs.readonly); + } else if (groupByFieldAttrs.readonly !== undefined) { + draggable = !(groupByFieldAttrs.readonly); } } - var grouped_by_m2o = group_by_field_attrs && (group_by_field_attrs.type === 'many2one'); - var grouped_by_field = grouped_by_m2o && group_by_field_attrs.relation; - this.column_options = _.extend(this.column_options, { + var groupedByM2O = groupByFieldAttrs && (groupByFieldAttrs.type === 'many2one'); + var grouped_by_field = groupedByM2O && groupByFieldAttrs.relation; + this.columnOptions = _.extend(this.columnOptions, { draggable: draggable, - grouped_by_m2o: grouped_by_m2o, + grouped_by_m2o: groupedByM2O, relation: grouped_by_field, }); // Render columns _.each(this.state.data, function (group) { - var column = new KanbanColumn(self, group, self.column_options, self.record_options); + var column = new KanbanColumn(self, group, self.columnOptions, self.recordOptions); if (!group.value) { column.prependTo(fragment); // display the 'Undefined' group first self.widgets.unshift(column); @@ -247,18 +267,49 @@ return BasicRenderer.extend({ }); // Column quick create - if (this.column_options.group_creatable && grouped_by_m2o) { - this.column_quick_create = new ColumnQuickCreate(this); - this.column_quick_create.appendTo(fragment); + if (this.columnOptions.group_creatable && groupedByM2O) { + var quickCreate = new ColumnQuickCreate(this); + quickCreate.appendTo(fragment); } }, - add_quick_create: function () { - this.widgets[0].add_quick_create(); + /** + * Renders an ungrouped kanban view in a fragment. + * + * @private + * @param {DocumentFragment} fragment + */ + _renderUngrouped: function (fragment) { + var self = this; + _.each(this.state.data, function (record) { + var kanbanRecord = new KanbanRecord(self, record, self.recordOptions); + self.widgets.push(kanbanRecord); + kanbanRecord.appendTo(fragment); + }); + + // append ghost divs to ensure that all kanban records are left aligned + this._renderGhostDivs(fragment, 6); + }, + /** + * @override + * @private + */ + _renderView: function () { + var isGrouped = !!this.state.groupedBy.length; + this.$el.toggleClass('o_kanban_grouped', isGrouped); + this.$el.toggleClass('o_kanban_ungrouped', !isGrouped); + this.$el.empty(); + + var fragment = document.createDocumentFragment(); + if (isGrouped) { + this._renderGrouped(fragment); + } else { + this._renderUngrouped(fragment); + } + this.$el.append(fragment); + return this._super.apply(this, arguments); }, - remove_widget: function (widget) { - this.widgets.splice(this.widgets.indexOf(widget), 1); - widget.destroy(); - } }); +return KanbanRenderer; + });