diff options
| author | vda (OpenERP) <vda@tinyerp.com> | 2011-04-27 15:54:56 +0530 |
|---|---|---|
| committer | vda (OpenERP) <vda@tinyerp.com> | 2011-04-27 15:54:56 +0530 |
| commit | 023119776de85a8274f88941adeb577a773ac00a (patch) | |
| tree | 681a78071cecae21c72c9817b7d37ac0debd5847 /addons/base/static/src | |
| parent | bf5a922f889e81e1393523c3b9a3837932961b36 (diff) | |
| parent | ceb524e3376d92dde25e68dd7d74b6de0a5c8a6d (diff) | |
[MERGE] Merged latest trunk branch.Improved dashboard using addwidget api.
bzr revid: vda@tinyerp.com-20110427102456-icjhuk24ke8x8cbg
Diffstat (limited to 'addons/base/static/src')
| -rw-r--r-- | addons/base/static/src/css/base.css | 16 | ||||
| -rw-r--r-- | addons/base/static/src/js/data.js | 7 | ||||
| -rw-r--r-- | addons/base/static/src/js/form.js | 36 | ||||
| -rw-r--r-- | addons/base/static/src/js/list.js | 110 | ||||
| -rw-r--r-- | addons/base/static/src/js/views.js | 22 | ||||
| -rw-r--r-- | addons/base/static/src/xml/base.xml | 47 |
6 files changed, 164 insertions, 74 deletions
diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index cf6d0beabd4..1bd004b53f6 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -336,8 +336,9 @@ body.openerp { } /* Main Application */ -.openerp .application { +.openerp .oe-application { padding: 0px; + height: 100%; } .openerp h2.oe_view_title { @@ -486,6 +487,9 @@ body.openerp { vertical-align: middle; } +.openerp .oe-listview .oe-field-cell { + cursor: pointer; +} .openerp .oe-listview .oe-field-cell button { padding: 0; border: none; @@ -636,7 +640,7 @@ body.openerp { .openerp td.required input, .openerp td.required select { background-color: #D2D2FF; } -.openerp td.invalid input, .openerp td.invalid select { +.openerp td.invalid input, .openerp td.invalid select, .openerp td.invalid textarea { background-color: #F66; border: 1px solid #D00; } @@ -673,13 +677,14 @@ body.openerp { } .openerp .view-manager-main-content { + width: 100%; padding: 6px; } .openerp .view-manager-main-sidebar { - width:0; - padding:0; - margin:0; + width: 180px; + padding: 0; + margin: 0; } .openerp .sidebar-main-div { @@ -746,6 +751,7 @@ body.openerp { } .openerp .toggle-sidebar { + cursor: pointer; border-color: #D2CFCF; border-style: solid; border-width: 1px; diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 5ed21be533c..a29f320b79c 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -118,6 +118,13 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. ids: ids, args: args }, callback); + }, + exec_workflow: function (id, signal, callback) { + return this.rpc('/base/dataset/exec_workflow', { + model: this.model, + id: id, + signal: signal + }, callback); } }); diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 9efa3cd01b6..84d7fe0babd 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -457,16 +457,14 @@ openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({ } this.add_widget(widget); }, - add_widget: function(w) { - if (!w.invisible) { - var current_row = this.table[this.table.length - 1]; - if (current_row.length && (this.x + w.colspan) > this.columns) { - current_row = this.add_row(); - } - current_row.push(w); - this.x += w.colspan; - } - return w; + add_widget: function(widget) { + var current_row = this.table[this.table.length - 1]; + if (current_row.length && (this.x + widget.colspan) > this.columns) { + current_row = this.add_row(); + } + current_row.push(widget); + this.x += widget.colspan; + return widget; } }); @@ -534,7 +532,7 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({ on_confirmed: function() { var attrs = this.node.attrs; if (attrs.special) { - this.on_button_object({ + this.on_button_action({ result : { type: 'ir.actions.act_window_close' } }); } else { @@ -542,19 +540,20 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({ var context = _.extend({}, this.view.dataset.context, attrs.context || {}); switch(type) { case 'object': - return this.view.dataset.call(attrs.name, [this.view.datarecord.id], [context], this.on_button_object); - break; + return this.view.dataset.call(attrs.name, [this.view.datarecord.id], [context], this.on_button_action); + case 'action': + return this.rpc('/base/action/load', { action_id: parseInt(attrs.name) }, this.on_button_action); default: - this.log(_.sprintf("Unsupported button type : %s", type)); + return this.view.dataset.exec_workflow(this.view.datarecord.id, attrs.name, this.on_button_action); } } }, - on_button_object: function(r) { - if (r.result === false) { - this.log("Button object returns false"); - } else if (r.result.constructor == Object) { + on_button_action: function(r) { + console.log("Got reesonse button", r) + if (r.result && r.result.constructor == Object) { this.session.action_manager.do_action(r.result); } else { + this.log("Button returned", r.result); this.view.reload(); } } @@ -911,7 +910,6 @@ openerp.base.form.FieldReference = openerp.base.form.Field.extend({ * Registry of form widgets, called by :js:`openerp.base.FormView` */ openerp.base.form.widgets = new openerp.base.Registry({ - 'hpaned': 'openerp.base.form.Hpaned', 'group' : 'openerp.base.form.WidgetFrame', 'notebook' : 'openerp.base.form.WidgetNotebook', 'separator' : 'openerp.base.form.WidgetSeparator', diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 5a08b96ac14..8035616e59a 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -10,9 +10,23 @@ openerp.base.ListView = openerp.base.Controller.extend( // whether the column headers should be displayed 'header': true, // display addition button, with that label - 'addable': "New" + 'addable': "New", + // whether the list view can be sorted, note that once a view has been + // sorted it can not be reordered anymore + 'sortable': true, + // whether the view rows can be reordered (via vertical drag & drop) + 'reorderable': true }, /** + * Core class for list-type displays. + * + * As a view, needs a number of view-related parameters to be correctly + * instantiated, provides options and overridable methods for behavioral + * customization. + * + * See constructor parameters and method documentations for information on + * the default behaviors and possible options for the list view. + * * @constructs * @param view_manager * @param session An OpenERP session object @@ -24,6 +38,8 @@ openerp.base.ListView = openerp.base.Controller.extend( * @param {Boolean} [options.header=true] should the list's header be displayed * @param {Boolean} [options.deletable=true] are the list rows deletable * @param {null|String} [options.addable="New"] should the new-record button be displayed, and what should its label be. Use ``null`` to hide the button. + * @param {Boolean} [options.sortable=true] is it possible to sort the table by clicking on column headers + * @param {Boolean} [options.reorderable=true] is it possible to reorder list rows */ init: function(view_manager, session, element_id, dataset, view_id, options) { this._super(session, element_id); @@ -37,11 +53,42 @@ openerp.base.ListView = openerp.base.Controller.extend( this.options = _.extend({}, this.defaults, options || {}); }, + /** + * View startup method, the default behavior is to set the ``oe-listview`` + * class on its root element and to perform an RPC load call. + * + * @returns {$.Deferred} loading promise + */ start: function() { this.$element.addClass('oe-listview'); - return this.rpc("/base/listview/load", {"model": this.model, "view_id":this.view_id, - toolbar:!!this.view_manager.sidebar}, this.on_loaded); + return this.rpc("/base/listview/load", { + model: this.model, + view_id: this.view_id, + toolbar: !!this.view_manager.sidebar + }, this.on_loaded); }, + /** + * Called after loading the list view's description, sets up such things + * as the view table's columns, renders the table itself and hooks up the + * various table-level and row-level DOM events (action buttons, deletion + * buttons, selection of records, [New] button, selection of a given + * record, ...) + * + * Sets up the following: + * + * * Processes arch and fields to generate a complete field descriptor for each field + * * Create the table itself and allocate visible columns + * * Hook in the top-level (header) [New|Add] and [Delete] button + * * Sets up showing/hiding the top-level [Delete] button based on records being selected or not + * * Sets up event handlers for action buttons and per-row deletion button + * * Hooks global callback for clicking on a row + * * Sets up its sidebar, if any + * + * @param {Object} data wrapped fields_view_get result + * @param {Object} data.fields_view fields_view_get result (processed) + * @param {Object} data.fields_view.fields mapping of fields for the current model + * @param {Object} data.fields_view.arch current list view descriptor + */ on_loaded: function(data) { var self = this; this.fields_view = data.fields_view; @@ -108,8 +155,9 @@ openerp.base.ListView = openerp.base.Controller.extend( var context = _.extend( {}, self.dataset.context, field.context || {}); - self.dataset.call(action, [row.data.id.value], [context], - self.do_reload); + self.notification.notify( + '[Dummy] Execute action', self.dataset.model + '#' + action + "([" + row.data.id.value + '])'); + // TODO: implement actions correctly once the corresponding manager has been extracted (and filled) e.stopImmediatePropagation(); }); $table.delegate( @@ -127,10 +175,18 @@ openerp.base.ListView = openerp.base.Controller.extend( /** * Fills the table with the provided records after emptying it * - * @param {Array} records the records to fill the list view with + * TODO: should also re-load the table itself, as e.g. columns may have changed + * + * @param {Object} result filling result + * @param {Array} [result.view] the new view (wrapped fields_view_get result) + * @param {Array} result.records records the records to fill the list view with * @returns {Promise} promise to the end of view rendering (list views are asynchronously filled for improved responsiveness) */ - do_fill_table: function(records) { + do_fill_table: function(result) { + if (result.view) { + this.on_loaded({fields_view: result.view}); + } + var records = result.records; var $table = this.$element.find('table'); this.rows = records; @@ -188,14 +244,19 @@ openerp.base.ListView = openerp.base.Controller.extend( }); }, /** - * Asks the view manager to switch to a different view, using the provided - * record index (within the current dataset). + * Used to handle a click on a table row, if no other handler caught the + * event. + * + * The default implementation asks the list view's view manager to switch + * to a different view (by calling + * :js:func:`~openerp.base.ViewManager.on_mode_switch`), using the + * provided record index (within the current list view's dataset). * * If the index is null, ``switch_to_record`` asks for the creation of a * new record. * * @param {Number|null} index the record index (in the current dataset) to switch to - * @param {String} [view="form"] the view to switch to + * @param {String} [view="form"] the view type to switch to */ switch_to_record:function (index, view) { view = view || 'form'; @@ -204,6 +265,16 @@ openerp.base.ListView = openerp.base.Controller.extend( this.view_manager.on_mode_switch(view); }, this)); }, + /** + * Base handler for clicking on a row, discovers the index of the record + * corresponding to the clicked row in the list view's dataset. + * + * Should not be overridden, use + * :js:func:`~openerp.base.ListView.switch_to_record` to customize the + * behavior of the list view when clicking on a row instead. + * + * @param {Object} event jQuery DOM event object + */ on_select_row: function (event) { var $target = $(event.currentTarget); if (!$target.parent().is('tbody')) { @@ -216,8 +287,8 @@ openerp.base.ListView = openerp.base.Controller.extend( if (index == undefined || index === -1) { return; } - this.switch_to_record(index); - }, + this.switch_to_record(index); + }, do_show: function () { this.$element.show(); if (this.hidden) { @@ -246,6 +317,15 @@ openerp.base.ListView = openerp.base.Controller.extend( 'domain': this.dataset.domain }, this.do_fill_table); }, + /** + * Event handler for a search, asks for the computation/folding of domains + * and contexts (and group-by), then reloads the view's content. + * + * @param {Array} domains a sequence of literal and non-literal domains + * @param {Array} contexts a sequence of literal and non-literal contexts + * @param {Array} groupbys a sequence of literal and non-literal group-by contexts + * @returns {$.Deferred} fold request evaluation promise + */ do_search: function (domains, contexts, groupbys) { var self = this; return this.rpc('/base/session/eval_domain_and_context', { @@ -266,7 +346,7 @@ openerp.base.ListView = openerp.base.Controller.extend( /** * Handles the signal to delete a line from the DOM * - * @param e + * @param e jQuery event object */ do_delete: function (e) { // don't link to forms @@ -295,7 +375,7 @@ openerp.base.ListView = openerp.base.Controller.extend( }, /** * Gets the ids of all currently selected records, if any - * @returns a list of ids, empty if no record is selected (or the list view is not selectable + * @returns {Array} empty if no record is selected (or the list view is not selectable) */ get_selection: function () { if (!this.options.selectable) { @@ -307,6 +387,8 @@ openerp.base.ListView = openerp.base.Controller.extend( return rows[$(this).prevAll().length].data.id.value; }).get(); } + // TODO: implement sort (click on column headers), if sorted, the list can not be reordered anymore + // TODO: implement reorder (drag and drop rows) }); openerp.base.TreeView = openerp.base.Controller.extend({ diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index f79d0e611eb..8ef14a3edbf 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -19,7 +19,6 @@ openerp.base.ActionManager = openerp.base.Controller.extend({ * Supported actions: act_window */ do_action: function(action) { - this.log(action); var self = this; // instantiate the right controllers by understanding the action switch (action.type) { @@ -36,14 +35,14 @@ openerp.base.ActionManager = openerp.base.Controller.extend({ // When dialog is closed with ESC key or close manually, branch to act_window_close logic self.do_action({ type: 'ir.actions.act_window_close' }); }); - var viewmanager = new openerp.base.ViewManagerAction(this.session ,element_id, action, false); + var viewmanager = new openerp.base.ViewManagerAction(this.session, element_id, action, false); viewmanager.start(); this.dialog_stack.push(viewmanager); - } else if (action.target == "current") { + } else { if (this.viewmanager) { this.viewmanager.stop(); } - this.viewmanager = new openerp.base.ViewManagerAction(this.session,this.element_id, action, true); + this.viewmanager = new openerp.base.ViewManagerAction(this.session, this.element_id, action, true); this.viewmanager.start(); } break; @@ -211,14 +210,17 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ // init search view var searchview_id = this.action.search_view_id && this.action.search_view_id[0]; - var searchview_loaded = this.setup_search_view( - searchview_id || false, search_defaults); + if (searchview_id) { + var searchview_loaded = this.setup_search_view( + searchview_id, search_defaults); - // schedule auto_search - if (searchview_loaded != null && this.action['auto_search']) { - $.when(searchview_loaded, inital_view_loaded) - .then(this.searchview.do_search); + // schedule auto_search + if (this.action['auto_search']) { + $.when(searchview_loaded, inital_view_loaded) + .then(this.searchview.do_search); + } } + }, stop: function() { // should be replaced by automatic destruction implemented in BaseWidget diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index cbb90ca9e2e..b49ef2c7d6a 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -18,9 +18,6 @@ </div> </div> <div id="oe_login" class="login"></div> - <div style="position: absolute; right: 2px; top: 38px;"> - <button onclick="QWeb.add_template('base.xml'); $('body').css('background-color', '#FFFF9C'); setTimeout(function() { $('body').css('background-color', '#FFF'); }, 500);">Reload QWEB</button> - </div> <table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" t-att-class="'main_table' + (typeof kitten == 'undefined' ? '' : ' kitten-mode-activated')"> <tr> @@ -33,10 +30,7 @@ <td valign="top" id="oe_secondary_menu" class="secondary_menu"> </td> <td valign="top" width="100%" height="100%"> - <div id="oe_main" class="main"> - <div id="oe_app" class="application"></div> - <div id="oe_sidebar"></div> - </div> + <div id="oe_app" class="oe-application"></div> </td> </tr> <tr> @@ -135,23 +129,23 @@ <t t-name="ViewManager"> <table class="view-manager-main-table"> <tr> - <td class="view-manager-main-content"> - <!-- TODO prefix id with the element_id of the controller t-attf-id="#{prefix}_localid" --> - <div class="oe_vm_switch"> - <t t-foreach="views" t-as="view"> - <button type="button" t-att-data-view-type="view[1]"> - <t t-esc="view[1]"/> - </button> - </t> - </div> - <div t-attf-id="#{prefix}_search"/> - <t t-foreach="views" t-as="view"> - <div t-attf-id="#{prefix}_view_#{view[1]}"/> - </t> - </td> - <td class="view-manager-main-sidebar"> - </td> - </tr> + <td class="view-manager-main-content"> + <!-- TODO prefix id with the element_id of the controller t-attf-id="#{prefix}_localid" --> + <div class="oe_vm_switch"> + <t t-foreach="views" t-as="view"> + <button type="button" t-att-data-view-type="view[1]"> + <t t-esc="view[1]"/> + </button> + </t> + </div> + <div t-attf-id="#{prefix}_search" t-opentag="true"/> + <t t-foreach="views" t-as="view"> + <div t-attf-id="#{prefix}_view_#{view[1]}"/> + </t> + </td> + <td class="view-manager-main-sidebar"> + </td> + </tr> </table> </t> <table t-name="ListView"> @@ -217,7 +211,8 @@ <t t-set="is_button" t-value="column.tag === 'button'"/> <!-- TODO: get correct widget from form --> <t t-if="!is_button and row['data'][column.id].value"> - <t t-esc="row['data'][column.id].value"/> + <t t-set="value" t-value="row['data'][column.id].value"/> + <t t-esc="value instanceof Array ? value[1] : value"/> </t> <button type="button" t-att-title="column.help" t-if="is_button"> @@ -299,7 +294,7 @@ t-att-ondblclick="'console.log(\'' + widget.element_id + '\', openerp.screen.' + widget.element_id + ')'"> <t t-esc="widget.string"/> <span t-if="widget.help">?</span> - <t t-if="widget.string">:</t> + <t t-if="widget.string and widget.node.tag != 'label'">:</t> </label> </t> <t t-name="FieldChar"> |
