[MERGE]
bzr revid: nicolas.vanhoren@openerp.com-20110509144338-n4ilx5gjo7e6sesn
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<templates>
|
||||
<t t-name="jquery-extend">
|
||||
<ul><li>one</li></ul>
|
||||
</t>
|
||||
<t t-extend="jquery-extend">
|
||||
<t t-jquery="ul" t-operation="append"><li>3</li></t>
|
||||
</t>
|
||||
<t t-extend="jquery-extend">
|
||||
<t t-jquery="ul li:first-child" t-operation="replace"><li>2</li></t>
|
||||
</t>
|
||||
<t t-extend="jquery-extend">
|
||||
<t t-jquery="ul" t-operation="prepend"><li>1</li></t>
|
||||
<t t-jquery="ul" t-operation="before"><hr/></t>
|
||||
<t t-jquery="ul" t-operation="after"><hr/></t>
|
||||
</t>
|
||||
<t t-extend="jquery-extend">
|
||||
<t t-jquery="ul">
|
||||
this.attr('class', 'main');
|
||||
</t>
|
||||
</t>
|
||||
<t t-extend="jquery-extend">
|
||||
<t t-jquery="hr:eq(1)" t-operation="replace"><footer></footer></t>
|
||||
</t>
|
||||
<t t-extend="jquery-extend">
|
||||
<t t-jquery="footer" t-operation="inner"><b>END</b></t>
|
||||
</t>
|
||||
|
||||
<t t-name="jquery-extend-clone" t-extend="jquery-extend">
|
||||
<t t-jquery="ul" t-operation="append"><li>CLONED TEMPLATE</li></t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -5,6 +5,7 @@
|
||||
<link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen"/>
|
||||
<script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="qweb2.js"></script>
|
||||
|
||||
<script>
|
||||
@@ -235,6 +236,24 @@
|
||||
equals(QWeb.render('loopvars-aliasing', {seq:seq}), 'even odd even odd even ',
|
||||
"inner loop variables should be rebound as well");
|
||||
});
|
||||
|
||||
module("Template inheritance tests", {
|
||||
setup: function () {
|
||||
QWeb.add_template('qweb-test-extend.xml');
|
||||
},
|
||||
teardown: function () {
|
||||
QWeb.templates = [];
|
||||
QWeb.tag = {};
|
||||
QWeb.att = {};
|
||||
}
|
||||
});
|
||||
|
||||
test("jQuery extend", function () {
|
||||
equals(render('jquery-extend', {}), '<hr/><ul class="main"><li>1</li><li>2</li><li>3</li></ul><footer><b>END</b></footer>',
|
||||
"Extend template with jQuery");
|
||||
equals(render('jquery-extend-clone', {}), '<ul><li>one</li><li>CLONED TEMPLATE</li></ul>',
|
||||
"Clone template");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -77,6 +77,41 @@ var QWeb2 = {
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
xml_node_to_string : function(node, childs_only) {
|
||||
if (childs_only) {
|
||||
var childs = node.childNodes, r = [];
|
||||
for (var i = 0, ilen = childs.length; i < ilen; i++) {
|
||||
r.push(this.xml_node_to_string(childs[i]));
|
||||
}
|
||||
return r.join('');
|
||||
} else {
|
||||
if (node.xml !== undefined) {
|
||||
return node.xml;
|
||||
} else {
|
||||
return (new XMLSerializer()).serializeToString(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
xpath_selectNodes : function(node, expr) {
|
||||
if (node.selectNodes !== undefined) {
|
||||
return node.selectNodes(expr);
|
||||
} else {
|
||||
var xpath = new XPathEvaluator();
|
||||
try {
|
||||
var result = xpath.evaluate(expr, node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
|
||||
} catch(error) {
|
||||
this.exception("Error with XPath expression '" + expr + "' : " + error);
|
||||
}
|
||||
var r = [];
|
||||
if (result != null) {
|
||||
var element;
|
||||
while (element = result.iterateNext()) {
|
||||
r.push(element);
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
},
|
||||
call: function(context, template, old_dict, _import, callback) {
|
||||
var new_dict = this.extend({}, old_dict);
|
||||
new_dict['__caller__'] = old_dict['__template__'];
|
||||
@@ -157,8 +192,10 @@ QWeb2.Engine = (function() {
|
||||
this.templates_resources = []; // TODO: implement this.reload()
|
||||
this.templates = {};
|
||||
this.compiled_templates = {};
|
||||
this.extend_templates = {};
|
||||
this.dict = {};
|
||||
this.tools = QWeb2.tools;
|
||||
this.jQuery = window.jQuery;
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
this.add_template(arguments[i]);
|
||||
}
|
||||
@@ -178,8 +215,25 @@ QWeb2.Engine = (function() {
|
||||
return this.tools.exception(node.innerText);
|
||||
}
|
||||
var name = node.getAttribute(this.prefix + '-name');
|
||||
var extend = node.getAttribute(this.prefix + '-extend');
|
||||
if (name && extend) {
|
||||
// Clone template and extend it
|
||||
if (!this.templates[extend]) {
|
||||
return this.tools.exception("Can't clone undefined template " + extend);
|
||||
}
|
||||
this.templates[name] = this.templates[extend].cloneNode(true);
|
||||
extend = name;
|
||||
name = undefined;
|
||||
}
|
||||
if (name) {
|
||||
this.templates[name] = node;
|
||||
} else if (extend) {
|
||||
delete(this.compiled_templates[extend]);
|
||||
if (this.extend_templates[extend]) {
|
||||
this.extend_templates[extend].push(node);
|
||||
} else {
|
||||
this.extend_templates[extend] = [node];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,15 +310,26 @@ QWeb2.Engine = (function() {
|
||||
"});";
|
||||
},
|
||||
render : function(template, dict) {
|
||||
//console.time("QWeb render template " + template);
|
||||
if (this.debug && window['console'] !== undefined) {
|
||||
console.time("QWeb render template " + template);
|
||||
}
|
||||
var r = this._render(template, dict);
|
||||
//console.timeEnd("QWeb render template " + template);
|
||||
if (this.debug && window['console'] !== undefined) {
|
||||
console.timeEnd("QWeb render template " + template);
|
||||
}
|
||||
return r;
|
||||
},
|
||||
_render : function(template, dict) {
|
||||
if (this.compiled_templates[template]) {
|
||||
return this.compiled_templates[template].apply(this, [dict || {}]);
|
||||
} else if (this.templates[template]) {
|
||||
var ext;
|
||||
if (ext = this.extend_templates[template]) {
|
||||
var extend_node;
|
||||
while (extend_node = ext.shift()) {
|
||||
this.extend(template, extend_node);
|
||||
}
|
||||
}
|
||||
var code = this.compile(this.templates[template]), tcompiled;
|
||||
try {
|
||||
// tcompiled = new Function(code); TODO: Check if could use this in order to avoid eval
|
||||
@@ -278,6 +343,53 @@ QWeb2.Engine = (function() {
|
||||
} else {
|
||||
return this.tools.exception("Template '" + template + "' not found");
|
||||
}
|
||||
},
|
||||
extend : function(template, extend_node) {
|
||||
if (!this.jQuery) {
|
||||
return this.tools.exception("Can't extend template " + template + " without jQuery");
|
||||
}
|
||||
for (var i = 0, ilen = extend_node.childNodes.length; i < ilen; i++) {
|
||||
var child = extend_node.childNodes[i];
|
||||
if (child.nodeType === 1) {
|
||||
var xpath = child.getAttribute(this.prefix + '-xpath'),
|
||||
jquery = child.getAttribute(this.prefix + '-jquery'),
|
||||
operation = child.getAttribute(this.prefix + '-operation'),
|
||||
target,
|
||||
error_msg = "Error while extending template '" + template;
|
||||
if (jquery) {
|
||||
target = this.jQuery(jquery, this.templates[template]);
|
||||
} else if (xpath) {
|
||||
// NOTE: due to the XPath implementation, extending a template will only work once
|
||||
// when using XPath because XPathResult won't match objects with other constructor than 'Element'
|
||||
// As jQuery will create HTMLElements, xpath will ignore them then causing problems when a
|
||||
// template has already been extended. XPath selectors will probably be removed in QWeb.
|
||||
target = this.jQuery(this.tools.xpath_selectNodes(this.templates[template], xpath));
|
||||
} else {
|
||||
this.tools.exception(error_msg + "No expression given");
|
||||
}
|
||||
error_msg += "' (expression='" + (jquery || xpath) + "') : ";
|
||||
var inner = this.tools.xml_node_to_string(child, true);
|
||||
if (operation) {
|
||||
var allowed_operations = "append,prepend,before,after,replace,inner".split(',');
|
||||
if (this.tools.arrayIndexOf(allowed_operations, operation) == -1) {
|
||||
this.tools.exception(error_msg + "Invalid operation : '" + operation + "'");
|
||||
}
|
||||
operation = {'replace' : 'replaceWith', 'inner' : 'html'}[operation] || operation;
|
||||
target[operation]($(inner));
|
||||
} else {
|
||||
try {
|
||||
var f = new Function(['$'], inner);
|
||||
} catch(error) {
|
||||
return this.tools.exception("Parse " + error_msg + error);
|
||||
}
|
||||
try {
|
||||
f.apply(target, [this.jQuery]);
|
||||
} catch(error) {
|
||||
return this.tools.exception("Runtime " + error_msg + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return Engine;
|
||||
|
||||
@@ -568,7 +568,6 @@ body.openerp {
|
||||
/* Form */
|
||||
.openerp table.oe_frame td {
|
||||
color: #4c4c4c;
|
||||
font-weight: bold;
|
||||
}
|
||||
.openerp .required.error {
|
||||
border: 1px solid #900;
|
||||
@@ -611,6 +610,9 @@ body.openerp {
|
||||
min-width: 90px;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
.openerp textarea {
|
||||
resize:vertical;
|
||||
}
|
||||
.openerp input[type="text"], .openerp input[type="password"], .openerp select, .openerp .button {
|
||||
height: 22px;
|
||||
}
|
||||
@@ -646,6 +648,12 @@ body.openerp {
|
||||
background-color: #F66;
|
||||
border: 1px solid #D00;
|
||||
}
|
||||
.openerp div.oe-progressbar span {
|
||||
position: absolute;
|
||||
margin-left: 10px;
|
||||
margin-top: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* jQuery UI override */
|
||||
.openerp .ui-widget {
|
||||
|
||||
@@ -773,6 +773,14 @@ openerp.base.form.FieldProgressBar = openerp.base.form.Field.extend({
|
||||
value: this.value,
|
||||
disabled: this.readonly
|
||||
});
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
var show_value = Number(value);
|
||||
if (show_value === NaN) {
|
||||
show_value = 0;
|
||||
}
|
||||
this.$element.find('div').progressbar('option', 'value', show_value).find('span').html(show_value + '%');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+176
-118
@@ -44,6 +44,7 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
* @borrows openerp.base.ActionExecutor#execute_action as #execute_action
|
||||
*/
|
||||
init: function(view_manager, session, element_id, dataset, view_id, options) {
|
||||
var self = this;
|
||||
this._super(session, element_id);
|
||||
this.view_manager = view_manager;
|
||||
this.dataset = dataset;
|
||||
@@ -54,6 +55,35 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
this.rows = [];
|
||||
|
||||
this.options = _.extend({}, this.defaults, options || {});
|
||||
|
||||
this.list = new openerp.base.ListView.List({
|
||||
options: this.options,
|
||||
columns: this.columns,
|
||||
rows: this.rows
|
||||
});
|
||||
$(this.list).bind({
|
||||
'selected': function (e, selection) {
|
||||
self.$element.find('#oe-list-delete')
|
||||
.toggle(!!selection.length);
|
||||
},
|
||||
'deleted': function (e, ids) {
|
||||
self.do_delete(ids);
|
||||
},
|
||||
'action': function (e, action_name, id) {
|
||||
var action = _.detect(self.columns, function (field) {
|
||||
return field.name === action_name;
|
||||
});
|
||||
if (!action) { return; }
|
||||
// TODO: not supposed to reload everything, I think
|
||||
self.execute_action(
|
||||
action, self.dataset, self.session.action_manager,
|
||||
id, self.do_reload);
|
||||
},
|
||||
'row_link': function (e, index) {
|
||||
self.switch_to_record(index);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
/**
|
||||
* View startup method, the default behavior is to set the ``oe-listview``
|
||||
@@ -99,7 +129,9 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
|
||||
var fields = this.fields_view.fields;
|
||||
var domain_computer = openerp.base.form.compute_domain;
|
||||
this.columns = _(this.fields_view.arch.children).chain()
|
||||
|
||||
this.columns.splice(0, this.columns.length);
|
||||
this.columns.push.apply(this.columns, _(this.fields_view.arch.children).chain()
|
||||
.map(function (field) {
|
||||
var name = field.attrs.name;
|
||||
var column = _.extend({id: name, tag: field.tag},
|
||||
@@ -118,13 +150,14 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
column.attrs_for = function () { return {}; };
|
||||
}
|
||||
return column;
|
||||
}).value();
|
||||
}).value());
|
||||
|
||||
this.visible_columns = _.filter(this.columns, function (column) {
|
||||
return column.invisible !== '1';
|
||||
});
|
||||
|
||||
if (!this.fields_view.sorted) { this.fields_view.sorted = {}; }
|
||||
|
||||
this.$element.html(QWeb.render("ListView", this));
|
||||
|
||||
// Head hook
|
||||
@@ -142,42 +175,7 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
});
|
||||
|
||||
var $table = this.$element.find('table');
|
||||
// Cell events
|
||||
$table.delegate(
|
||||
'th.oe-record-selector', 'click', function (e) {
|
||||
// TODO: ~linear performances, would a simple counter work?
|
||||
if ($table.find('th.oe-record-selector input:checked').length) {
|
||||
$table.find('#oe-list-delete').show();
|
||||
} else {
|
||||
$table.find('#oe-list-delete').hide();
|
||||
}
|
||||
// A click in the selection cell should not activate the
|
||||
// linking feature
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
$table.delegate(
|
||||
'td.oe-field-cell button', 'click', function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
var $cell = $(e.currentTarget).closest('td');
|
||||
|
||||
var col_index = $cell.prevAll('td').length;
|
||||
var field = self.visible_columns[col_index];
|
||||
|
||||
var $row = $cell.parent('tr');
|
||||
var row = self.rows[$row.prevAll().length];
|
||||
|
||||
// TODO: we should probably only reload content, also maybe diff records or something, instead of replacing every single row
|
||||
self.execute_action(
|
||||
field, self.dataset, self.session.action_manager,
|
||||
row.data.id.value, self.do_reload);
|
||||
});
|
||||
$table.delegate(
|
||||
'td.oe-record-delete button', 'click', this.do_delete);
|
||||
|
||||
// Global rows handlers
|
||||
$table.delegate(
|
||||
'tr', 'click', this.on_select_row);
|
||||
this.list.move_to($table);
|
||||
|
||||
// sidebar stuff
|
||||
if (this.view_manager && this.view_manager.sidebar) {
|
||||
@@ -192,15 +190,15 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
* @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(result) {
|
||||
if (result.view) {
|
||||
this.on_loaded({fields_view: result.view});
|
||||
}
|
||||
var records = result.records;
|
||||
var $table = this.$element.find('table');
|
||||
this.rows = records;
|
||||
|
||||
this.rows.splice(0, this.rows.length);
|
||||
this.rows.push.apply(this.rows, records);
|
||||
|
||||
// Keep current selected record, if it's still in our new search
|
||||
var current_record_id = this.dataset.ids[this.dataset.index];
|
||||
@@ -214,46 +212,11 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
|
||||
this.dataset.count = this.dataset.ids.length;
|
||||
var results = this.rows.length;
|
||||
$table.find('.oe-pager-last').text(results);
|
||||
$table.find('.oe-pager-total').text(results);
|
||||
this.$element.find('table')
|
||||
.find('.oe-pager-last').text(results).end()
|
||||
.find('.oe-pager-total').text(results);
|
||||
|
||||
|
||||
// remove all data lines
|
||||
var $old_body = $table.find('tbody');
|
||||
|
||||
// add new content
|
||||
var columns = this.columns,
|
||||
rows = this.rows,
|
||||
options = this.options;
|
||||
|
||||
// Paginate by groups of 50 for rendering
|
||||
var PAGE_SIZE = 50,
|
||||
bodies_count = Math.ceil(this.rows.length / PAGE_SIZE),
|
||||
body = 0,
|
||||
$body = $('<tbody class="ui-widget-content">').appendTo($table);
|
||||
|
||||
var rendered = $.Deferred();
|
||||
var render_body = function () {
|
||||
setTimeout(function () {
|
||||
$body.append(
|
||||
QWeb.render("ListView.rows", {
|
||||
columns: columns,
|
||||
rows: rows.slice(body*PAGE_SIZE, (body+1)*PAGE_SIZE),
|
||||
options: options
|
||||
}));
|
||||
++body;
|
||||
if (body < bodies_count) {
|
||||
render_body();
|
||||
} else {
|
||||
rendered.resolve();
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
render_body();
|
||||
|
||||
return rendered.promise().then(function () {
|
||||
$old_body.remove();
|
||||
});
|
||||
this.list.refresh();
|
||||
},
|
||||
/**
|
||||
* Used to handle a click on a table row, if no other handler caught the
|
||||
@@ -279,30 +242,6 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
}
|
||||
}, 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')) {
|
||||
return;
|
||||
}
|
||||
// count number of preceding siblings to line clicked
|
||||
var row = this.rows[$target.prevAll().length];
|
||||
|
||||
var index = _.indexOf(this.dataset.ids, row.data.id.value);
|
||||
if (index == undefined || index === -1) {
|
||||
return;
|
||||
}
|
||||
this.switch_to_record(index);
|
||||
},
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
if (this.hidden) {
|
||||
@@ -361,13 +300,35 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
/**
|
||||
* Handles the signal to delete a line from the DOM
|
||||
*
|
||||
* @param e jQuery event object
|
||||
* @param {Array} ids the id of the object to delete
|
||||
*/
|
||||
do_delete: function (e) {
|
||||
// don't link to forms
|
||||
e.stopImmediatePropagation();
|
||||
this.dataset.unlink(
|
||||
[this.rows[$(e.currentTarget).closest('tr').prevAll().length].data.id.value]);
|
||||
do_delete: function (ids) {
|
||||
if (!ids.length) {
|
||||
return;
|
||||
}
|
||||
var self = this;
|
||||
return $.when(this.dataset.unlink(ids)).then(function () {
|
||||
_(self.rows).chain()
|
||||
.map(function (row, index) {
|
||||
return {
|
||||
index: index,
|
||||
id: row.data.id.value
|
||||
};})
|
||||
.filter(function (record) {
|
||||
return _.contains(ids, record.id);
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
// sort in reverse index order, so we delete from the end
|
||||
// and don't blow up the following indexes (leading to
|
||||
// removing the wrong records from the visible list)
|
||||
return b.index - a.index;
|
||||
})
|
||||
.each(function (record) {
|
||||
self.rows.splice(record.index, 1);
|
||||
});
|
||||
// TODO only refresh modified rows
|
||||
self.list.refresh();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Handles signal for the addition of a new record (can be a creation,
|
||||
@@ -383,10 +344,89 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
* Handles deletion of all selected lines
|
||||
*/
|
||||
do_delete_selected: function () {
|
||||
var selection = this.get_selection();
|
||||
if (selection.length) {
|
||||
this.dataset.unlink(selection);
|
||||
}
|
||||
this.do_delete(
|
||||
this.list.get_selection());
|
||||
}
|
||||
// TODO: implement reorder (drag and drop rows)
|
||||
});
|
||||
_.extend(openerp.base.ListView.prototype, openerp.base.ActionExecutor);
|
||||
|
||||
openerp.base.ListView.List = Class.extend(
|
||||
/** @lends openerp.base.ListView.List# */{
|
||||
/**
|
||||
* List display for the ListView, handles basic DOM events and transforms
|
||||
* them in the relevant higher-level events, to which the list view (or
|
||||
* other consumers) can subscribe.
|
||||
*
|
||||
* Events on this object are registered via jQuery.
|
||||
*
|
||||
* Available events:
|
||||
*
|
||||
* `selected`
|
||||
* Triggered when a row is selected (using check boxes), provides an
|
||||
* array of ids of all the selected records.
|
||||
* `deleted`
|
||||
* Triggered when deletion buttons are hit, provide an array of ids of
|
||||
* all the records being marked for suppression.
|
||||
* `action`
|
||||
* Triggered when an action button is clicked, provides two parameters:
|
||||
*
|
||||
* * The name of the action to execute (as a string)
|
||||
* * The id of the record to execute the action on
|
||||
* `row_link`
|
||||
* Triggered when a row of the table is clicked, provides the index (in
|
||||
* the rows array) and id of the selected record to the handle function.
|
||||
*
|
||||
* @constructs
|
||||
* @param {Object} opts display options, identical to those of :js:class:`openerp.base.ListView`
|
||||
*/
|
||||
init: function (opts) {
|
||||
var self = this;
|
||||
// columns, rows, options
|
||||
|
||||
this.options = opts.options;
|
||||
this.columns = opts.columns;
|
||||
this.rows = opts.rows;
|
||||
|
||||
this.$_element = $('<tbody class="ui-widget-content">')
|
||||
.appendTo(document.body)
|
||||
.delegate('th.oe-record-selector', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
$(self).trigger('selected', [self.get_selection()]);
|
||||
})
|
||||
.delegate('td.oe-record-delete button', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
var $row = $(e.target).closest('tr');
|
||||
$(self).trigger('deleted', [[self.row_id($row)]]);
|
||||
})
|
||||
.delegate('td.oe-field-cell button', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
var $target = $(e.currentTarget),
|
||||
field = $target.closest('td').data('field'),
|
||||
record_id = self.row_id($target.closest('tr'));
|
||||
|
||||
$(self).trigger('action', [field, record_id]);
|
||||
})
|
||||
.delegate('tr', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
$(self).trigger(
|
||||
'row_link',
|
||||
[self.row_position(e.currentTarget),
|
||||
self.row_id(e.currentTarget)]);
|
||||
});
|
||||
},
|
||||
move_to: function (element) {
|
||||
this.$current = this.$_element.clone(true).appendTo(element);
|
||||
this.render();
|
||||
return this;
|
||||
},
|
||||
render: function () {
|
||||
this.$current.empty().append($(QWeb.render('ListView.rows', this)));
|
||||
return this;
|
||||
},
|
||||
refresh: function () {
|
||||
this.render();
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Gets the ids of all currently selected records, if any
|
||||
@@ -397,15 +437,33 @@ openerp.base.ListView = openerp.base.Controller.extend(
|
||||
return [];
|
||||
}
|
||||
var rows = this.rows;
|
||||
return this.$element.find('th.oe-record-selector input:checked')
|
||||
return this.$current.find('th.oe-record-selector input:checked')
|
||||
.closest('tr').map(function () {
|
||||
return rows[$(this).prevAll().length].data.id.value;
|
||||
}).get();
|
||||
},
|
||||
/**
|
||||
* Returns the index of the row in the list of rows.
|
||||
*
|
||||
* @param {Object} row the selected row
|
||||
* @returns {Number} the position of the row in this.rows
|
||||
*/
|
||||
row_position: function (row) {
|
||||
return $(row).prevAll().length;
|
||||
},
|
||||
/**
|
||||
* Returns the identifier of the object displayed in the provided table
|
||||
* row
|
||||
*
|
||||
* @param {Object} row the selected table row
|
||||
* @returns {Number|String} the identifier of the row's object
|
||||
*/
|
||||
row_id: function (row) {
|
||||
return this.rows[this.row_position(row)].data.id.value;
|
||||
}
|
||||
// TODO: implement sort (click on column headers), if sorted, the list can not be reordered anymore
|
||||
// TODO: implement reorder (drag and drop rows)
|
||||
// drag and drop
|
||||
// editable?
|
||||
});
|
||||
_.extend(openerp.base.ListView.prototype, openerp.base.ActionExecutor);
|
||||
|
||||
openerp.base.TreeView = openerp.base.Controller.extend({
|
||||
});
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
<t t-foreach="columns" t-as="column">
|
||||
<t t-set="attrs" t-value="column.attrs_for(row.data)"/>
|
||||
<td t-if="column.invisible !== '1'" t-att-title="column.help"
|
||||
class="oe-field-cell">
|
||||
class="oe-field-cell" t-att-data-field="column.id">
|
||||
<t t-if="!attrs.invisible">
|
||||
<t t-set="is_button" t-value="column.tag === 'button'"/>
|
||||
<!-- TODO: get correct widget from form -->
|
||||
@@ -365,7 +365,9 @@
|
||||
t-att-class="'field_' + widget.type"/>
|
||||
</t>
|
||||
<t t-name="FieldProgressBar">
|
||||
<div t-opentag="true"></div>
|
||||
<div t-opentag="true" class="oe-progressbar">
|
||||
<span></span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="WidgetButton">
|
||||
<button type="button"
|
||||
|
||||
Reference in New Issue
Block a user