summaryrefslogtreecommitdiff
path: root/addons/base/static/src
diff options
context:
space:
mode:
Diffstat (limited to 'addons/base/static/src')
-rw-r--r--addons/base/static/src/css/base.css16
-rw-r--r--addons/base/static/src/js/data.js7
-rw-r--r--addons/base/static/src/js/form.js36
-rw-r--r--addons/base/static/src/js/list.js110
-rw-r--r--addons/base/static/src/js/views.js22
-rw-r--r--addons/base/static/src/xml/base.xml47
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">