[MERGE] openerp-web.

bzr revid: vda@tinyerp.com-20110825123248-px72llfueox1wnez
This commit is contained in:
Vaibhav (OpenERP)
2011-08-25 18:02:48 +05:30
9 changed files with 345 additions and 165 deletions
+11 -1
View File
@@ -870,6 +870,9 @@ label.error {
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .button {
height: 22px;
}
.openerp .oe_forms input.field_datetime {
min-width: 11em;
}
.openerp .oe_forms .button {
color: #4c4c4c;
white-space: nowrap;
@@ -878,13 +881,20 @@ label.error {
position: relative;
vertical-align: top;
}
.openerp img.ui-datepicker-trigger, .openerp img.ui-datepicker-trigger {
.openerp img.ui-datepicker-trigger {
margin-left: -20px;
vertical-align: middle;
cursor: pointer;
position: relative;
top: -1px;
}
.openerp img.oe_field_translate {
margin-left: -21px;
vertical-align: top;
cursor: pointer;
position: relative;
top: 4px;
}
/* http://www.quirksmode.org/dom/inputfile.html
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
+2 -2
View File
@@ -567,8 +567,8 @@ openerp.base.Session = openerp.base.CallbackEnabled.extend( /** @lends openerp.b
self.do_load_js(file_list.concat(files));
});
} else {
self.do_load_css(file_list.concat(["/base/webclient/css?mods="+modules]));
self.do_load_js(["/base/webclient/js?mods="+modules]);
self.do_load_css(["/base/webclient/css?mods="+modules]);
self.do_load_js(file_list.concat(["/base/webclient/js?mods="+modules]));
}
openerp._modules_loaded = true;
});
+29 -78
View File
@@ -38,6 +38,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
this.registry = openerp.base.form.widgets;
this.has_been_loaded = $.Deferred();
this.$form_header = null;
this.translatable_fields = [];
_.defaults(this.options, {"always_show_new_button": true});
},
start: function() {
@@ -461,7 +462,7 @@ openerp.base.form.SidebarAttachments = openerp.base.Widget.extend({
['res_model', '=', this.view.dataset.model],
['res_id', '=', this.view.datarecord.id],
['type', 'in', ['binary', 'url']]
])).read_slice(['name', 'url', 'type'], this.on_attachments_loaded);
])).read_slice(['name', 'url', 'type'], {}, this.on_attachments_loaded);
}
},
on_attachments_loaded: function(attachments) {
@@ -840,6 +841,13 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
this.invalid = false;
this.dirty = false;
},
start: function() {
this._super.apply(this, arguments);
if (this.field.translate) {
this.view.translatable_fields.push(this);
this.$element.find('.oe_field_translate').click(this.on_translate);
}
},
set_value: function(value) {
this.value = value;
this.invalid = false;
@@ -851,6 +859,9 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
},
on_value_changed: function() {
},
on_translate: function() {
this.view.open_translate_dialog(this);
},
get_value: function() {
return this.value;
},
@@ -939,7 +950,7 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({
},
set_value: function(value) {
this._super.apply(this, arguments);
var show_value = (value != null && value !== false) ? value : '';
var show_value = openerp.base.format_value(value, this, '');
this.$element.find('input').val(show_value);
},
update_dom: function() {
@@ -947,16 +958,16 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({
this.$element.find('input').attr('disabled', this.readonly);
},
set_value_from_ui: function() {
this.value = this.$element.find('input').val();
this.value = openerp.base.parse_value(this.$element.find('input').val(), this);
this._super();
},
validate: function() {
this.invalid = false;
var value = this.$element.find('input').val();
if (value === "") {
this.invalid = this.required;
} else if (this.validation_regex) {
this.invalid = !this.validation_regex.test(value);
try {
var value = openerp.base.parse_value(this.$element.find('input').val(), this, '');
this.invalid = this.required && value === '';
} catch(e) {
this.invalid = true;
}
},
focus: function() {
@@ -968,7 +979,6 @@ openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({
init: function(view, node) {
this._super(view, node);
this.template = "FieldEmail";
this.validation_regex = /@/;
},
start: function() {
this._super.apply(this, arguments);
@@ -983,8 +993,7 @@ openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({
},
set_value: function(value) {
this._super.apply(this, arguments);
var show_value = (value != null && value !== false) ? value : '';
this.$element.find('a').attr('href', 'mailto:' + show_value);
this.$element.find('a').attr('href', 'mailto:' + this.$element.find('input').val());
}
});
@@ -1007,44 +1016,13 @@ openerp.base.form.FieldUrl = openerp.base.form.FieldChar.extend({
});
openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({
init: function(view, node) {
this._super(view, node);
this.validation_regex = /^-?\d+(\.\d+)?$/;
},
set_value: function(value) {
this._super.apply(this, [value]);
if (value === false || value === undefined) {
// As in GTK client, floats default to 0
value = 0;
this.dirty = true;
}
var show_value = value.toFixed(2);
this.$element.find('input').val(show_value);
},
set_value_from_ui: function() {
this.value = Number(this.$element.find('input').val().replace(/,/g, '.'));
this._super();
}
});
openerp.base.form.FieldInteger = openerp.base.form.FieldFloat.extend({
init: function(view, node) {
this._super(view, node);
this.validation_regex = /^-?\d+$/;
},
set_value: function(value) {
this._super.apply(this, [value]);
if (value === false || value === undefined) {
// TODO fme: check if GTK client default integers to 0 (like it does with floats)
value = 0;
this.dirty = true;
}
var show_value = parseInt(value, 10);
this.$element.find('input').val(show_value);
},
set_value_from_ui: function() {
this.value = Number(this.$element.find('input').val());
this._super();
}
});
@@ -1053,7 +1031,6 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({
this._super(view, node);
this.template = "FieldDate";
this.jqueryui_object = 'datetimepicker';
this.validation_regex = /^\d+-\d+-\d+( \d+:\d+(:\d+)?)?$/;
},
start: function() {
this._super.apply(this, arguments);
@@ -1093,8 +1070,6 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({
var value = this.$element.find('input').val();
if (value === "") {
this.invalid = this.required;
} else if (this.validation_regex) {
this.invalid = !this.validation_regex.test(value);
} else {
this.invalid = !this.$element.find('input')[this.jqueryui_object]('getDate');
}
@@ -1110,39 +1085,15 @@ openerp.base.form.FieldDate = openerp.base.form.FieldDatetime.extend({
init: function(view, node) {
this._super(view, node);
this.jqueryui_object = 'datepicker';
this.validation_regex = /^\d+-\d+-\d+$/;
},
parse: openerp.base.str_to_date,
format: openerp.base.date_to_str
});
openerp.base.form.FieldFloatTime = openerp.base.form.FieldChar.extend({
init: function(view, node) {
this._super(view, node);
this.validation_regex = /^\d+:\d+$/;
},
set_value: function(value) {
this._super.apply(this, [value]);
if (value === false || value === undefined) {
// As in GTK client, floats default to 0
value = 0;
this.dirty = true;
}
var show_value = _.sprintf("%02d:%02d", Math.floor(value), Math.round((value % 1) * 60));
this.$element.find('input').val(show_value);
},
set_value_from_ui: function() {
var time = this.$element.find('input').val().split(':');
this.set_value(parseInt(time[0], 10) + parseInt(time[1], 10) / 60);
this._super();
}
});
openerp.base.form.FieldText = openerp.base.form.Field.extend({
init: function(view, node) {
this._super(view, node);
this.template = "FieldText";
this.validation_regex = null;
},
start: function() {
this._super.apply(this, arguments);
@@ -1150,7 +1101,7 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({
},
set_value: function(value) {
this._super.apply(this, arguments);
var show_value = (value != null && value !== false) ? value : '';
var show_value = openerp.base.format_value(value, this, '');
this.$element.find('textarea').val(show_value);
},
update_dom: function() {
@@ -1158,16 +1109,16 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({
this.$element.find('textarea').attr('disabled', this.readonly);
},
set_value_from_ui: function() {
this.value = this.$element.find('textarea').val();
this.value = openerp.base.parse_value(this.$element.find('textarea').val(), this);
this._super();
},
validate: function() {
this.invalid = false;
var value = this.$element.find('textarea').val();
if (value === "") {
this.invalid = this.required;
} else if (this.validation_regex) {
this.invalid = !this.validation_regex.test(value);
try {
var value = openerp.base.parse_value(this.$element.find('textarea').val(), this, '');
this.invalid = this.required && value === '';
} catch(e) {
this.invalid = true;
}
},
focus: function() {
@@ -2430,9 +2381,9 @@ openerp.base.form.widgets = new openerp.base.Registry({
'reference' : 'openerp.base.form.FieldReference',
'boolean' : 'openerp.base.form.FieldBoolean',
'float' : 'openerp.base.form.FieldFloat',
'integer': 'openerp.base.form.FieldInteger',
'integer': 'openerp.base.form.FieldFloat',
'float_time': 'openerp.base.form.FieldFloat',
'progressbar': 'openerp.base.form.FieldProgressBar',
'float_time': 'openerp.base.form.FieldFloatTime',
'image': 'openerp.base.form.FieldBinaryImage',
'binary': 'openerp.base.form.FieldBinaryFile'
});
+17 -7
View File
@@ -45,8 +45,8 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
if (typeof(value) == "string")
value = openerp.base.str_to_datetime(value);
try {
return value.format(_.sprintf("%s %s", openerp.base._t.database.parameters.date_format,
openerp.base._t.database.parameters.time_format));
return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
Date.CultureInfo.formatPatterns.longTime));
} catch (e) {
return value.format("%m/%d/%Y %H:%M:%S");
}
@@ -55,7 +55,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
if (typeof(value) == "string")
value = openerp.base.str_to_date(value);
try {
return value.format(openerp.base._t.database.parameters.date_format);
return value.toString(Date.CultureInfo.formatPatterns.shortDate);
} catch (e) {
return value.format("%m/%d/%Y");
}
@@ -63,7 +63,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
if (typeof(value) == "string")
value = openerp.base.str_to_time(value);
try {
return value.format(openerp.base._t.database.parameters.time_format);
return value.toString(Date.CultureInfo.formatPatterns.longTime);
} catch (e) {
return value.format("%H:%M:%S");
}
@@ -108,17 +108,27 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) {
case 'progressbar':
return openerp.base.parse_value(value, {type: "float"});
case 'datetime':
var tmp = Date.parse(value);
var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
Date.CultureInfo.formatPatterns.longTime));
if (tmp !== null)
return tmp;
tmp = Date.parse(value);
if (tmp !== null)
return tmp;
throw value + " is not a valid datetime";
case 'date':
var tmp = Date.parse(value);
var tmp = Date.parseExact(Date.CultureInfo.formatPatterns.shortDate);
if (tmp !== null)
return tmp;
tmp = Date.parse(value);
if (tmp !== null)
return tmp;
throw value + " is not a valid date";
case 'time':
var tmp = Date.parse(value);
var tmp = Date.parseExact(Date.CultureInfo.formatPatterns.longTime);
if (tmp !== null)
return tmp;
tmp = Date.parse(value);
if (tmp !== null)
return tmp;
throw value + " is not a valid time";
+48 -15
View File
@@ -92,7 +92,7 @@ openerp.base.list_editable = function (openerp) {
if (!this.options.editable) {
return this._super(event);
}
this.edit_record();
this.edit_record($(event.currentTarget).data('id'));
},
/**
* Checks if a record is being edited, and if so cancels it
@@ -104,8 +104,8 @@ openerp.base.list_editable = function (openerp) {
return cancelled.promise();
}
if (this.edition_index !== null) {
this.reload_record(this.edition_index).then(function () {
if (this.edition_id != null) {
this.reload_record(self.records.get(this.edition_id)).then(function () {
cancelled.resolve();
});
} else {
@@ -115,13 +115,14 @@ openerp.base.list_editable = function (openerp) {
self.edition_form.stop();
self.edition_form.$element.remove();
delete self.edition_form;
delete self.edition_index;
delete self.edition_id;
delete self.edition;
});
return cancelled.promise();
},
/**
* Adapts this list's view description to be suitable to the inner form view of a row being edited.
* Adapts this list's view description to be suitable to the inner form
* view of a row being edited.
*
* @returns {Object} fields_view_get's view section suitable for putting into form view of editable rows.
*/
@@ -140,10 +141,10 @@ openerp.base.list_editable = function (openerp) {
render_row_as_form: function (row) {
var self = this;
this.cancel_pending_edition().then(function () {
var record_id = $(row).data('id');
var $new_row = $('<tr>', {
id: _.uniqueId('oe-editable-row-'),
'data-id': $(row).data('id'),
'data-index': $(row).data('index'),
'data-id': record_id,
'class': $(row).attr('class') + ' oe_forms',
click: function (e) {e.stopPropagation();}
})
@@ -176,7 +177,7 @@ openerp.base.list_editable = function (openerp) {
self.$current.append($new_row);
}
self.edition = true;
self.edition_index = self.dataset.index;
self.edition_id = record_id;
self.edition_form = _.extend(new openerp.base.FormView(
self, $new_row.attr('id'), self.dataset, false), {
template: 'ListView.row.form',
@@ -201,6 +202,25 @@ openerp.base.list_editable = function (openerp) {
});
});
},
handle_onwrite: function (source_record_id) {
var self = this;
var on_write_callback = self.view.fields_view.arch.attrs.on_write;
if (!on_write_callback) { return; }
this.dataset.call(on_write_callback, [source_record_id], function (ids) {
_(ids).each(function (id) {
var record = self.records.get(id);
if (!record) {
// insert after the source record
var index = self.records.indexOf(
self.records.get(source_record_id)) + 1;
record = new openerp.base.list.Record({id: id});
self.records.add(record, {at: index});
self.dataset.ids.splice(index, 0, id);
}
self.reload_record(record);
});
});
},
/**
* Saves the current row, and triggers the edition of its following
* sibling if asked.
@@ -210,11 +230,16 @@ openerp.base.list_editable = function (openerp) {
save_row: function (edit_next) {
var self = this;
this.edition_form.do_save(function (result) {
if (result.created && !self.edition_index) {
if (result.created && !self.edition_id) {
self.records.add({id: result.result},
{at: self.options.editable === 'top' ? 0 : null});
self.edition_index = self.dataset.index;
self.edition_id = result.result;
}
var edited_record = self.records.get(self.edition_id),
next_record = self.records.at(
self.records.indexOf(edited_record) + 1);
self.handle_onwrite(self.edition_id);
self.cancel_pending_edition().then(function () {
$(self).trigger('saved', [self.dataset]);
if (!edit_next) {
@@ -224,8 +249,16 @@ openerp.base.list_editable = function (openerp) {
self.new_record();
return;
}
self.dataset.next();
self.edit_record();
var next_record_id;
if (next_record) {
next_record_id = next_record.get('id');
self.dataset.index = _(self.dataset.ids)
.indexOf(next_record_id);
} else {
self.dataset.index = 0;
next_record_id = self.records.at(0).get('id');
}
self.edit_record(next_record_id);
});
}, this.options.editable === 'top');
},
@@ -238,12 +271,12 @@ openerp.base.list_editable = function (openerp) {
/**
* Edits record currently selected via dataset
*/
edit_record: function () {
edit_record: function (record_id) {
this.render_row_as_form(
this.$current.children(':eq(' + this.dataset.index + ')'));
this.$current.find('[data-id=' + record_id + ']'));
$(this).trigger(
'edit',
[this.records.at(this.dataset.index).get('id'), this.dataset]);
[record_id, this.dataset]);
},
new_record: function () {
this.dataset.index = null;
+48 -47
View File
@@ -120,7 +120,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
*/
start: function() {
this.$element.addClass('oe-listview');
return this.reload_view();
return this.reload_view(null, null, true);
},
/**
* Called after loading the list view's description, sets up such things
@@ -362,7 +362,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
* @param {Boolean} [grouped] Should the list be displayed grouped
* @param {Object} [context] context to send the server while loading the view
*/
reload_view: function (grouped, context) {
reload_view: function (grouped, context, initial) {
var self = this;
var callback = function (field_view_get) {
self.on_loaded(field_view_get, grouped);
@@ -641,12 +641,22 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
'reset': $.proxy(this, 'on_records_reset'),
'change': function (event, record) {
var $row = self.$current.find('[data-id=' + record.get('id') + ']');
$row.replaceWith(self.render_record($row.data('index')));
$row.replaceWith(self.render_record(record));
},
'add': function (ev, records, record, index) {
$('<tr>').attr({
var $new_row = $('<tr>').attr({
'data-id': record.get('id')
}).insertAfter(self.$current.children(':eq(' + index + ')'));
});
if (index === 0) {
$new_row.prependTo(self.$current);
} else {
var previous_record = records.at(index-1),
$previous_sibling = self.$current.find(
'[data-id=' + previous_record.get('id') + ']');
$new_row.insertAfter($previous_sibling);
}
self.refresh_zebra(index, 1);
}
};
@@ -672,16 +682,17 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
var $target = $(e.currentTarget),
field = $target.closest('td').data('field'),
$row = $target.closest('tr'),
record_id = self.row_id($row),
index = self.row_position($row);
record_id = self.row_id($row);
$(self).trigger('action', [field, record_id, function () {
return self.reload_record(index);
return self.reload_record(self.records.get(record_id));
}]);
})
.delegate('tr', 'click', function (e) {
e.stopPropagation();
self.dataset.index = self.row_position(e.currentTarget);
self.dataset.index = self.records.indexOf(
self.records.get(
self.row_id(e.currentTarget)));
self.row_clicked(e);
});
},
@@ -718,15 +729,6 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
});
return result;
},
/**
* 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).data('index');
},
/**
* Returns the identifier of the object displayed in the provided table
* row
@@ -755,48 +757,43 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
});
},
/**
* Reloads the record at index ``row_index`` in the list's rows.
* Reloads the provided record by re-reading its content from the server.
*
* By default, simply re-renders the record. If the ``fetch`` parameter is
* provided and ``true``, will first fetch the record anew.
*
* @param {Number} record_index index of the record to reload
* @param {Boolean} fetch fetches the record from remote before reloading it
* @param {Record} record
* @returns {$.Deferred} promise to the finalization of the reloading
*/
reload_record: function (record_index) {
var r = this.records.at(record_index);
reload_record: function (record) {
return this.dataset.read_ids(
[r.get('id')],
[record.get('id')],
_.pluck(_(this.columns).filter(function (r) {
return r.tag === 'field';
}), 'name'),
function (record) {
_(record[0]).each(function (value, key) {
r.set(key, value, {silent: true});
function (records) {
_(records[0]).each(function (value, key) {
record.set(key, value, {silent: true});
});
r.trigger('change', r);
record.trigger('change', record);
}
);
},
/**
* Renders a list record to HTML
*
* @param {Number} record_index index of the record to render in ``this.rows``
* @param {Record} record index of the record to render in ``this.rows``
* @returns {String} QWeb rendering of the selected record
*/
render_record: function (record_index) {
render_record: function (record) {
var index = this.records.indexOf(record);
return QWeb.render('ListView.row', {
columns: this.columns,
options: this.options,
record: this.records.at(record_index),
row_parity: (record_index % 2 === 0) ? 'even' : 'odd',
row_index: record_index,
record: record,
row_parity: (index % 2 === 0) ? 'even' : 'odd',
render_cell: openerp.base.format_cell
});
},
/**
* Fixes @data-index on all table rows, and fixes the even/odd classes
* Fixes fixes the even/odd classes
*
* @param {Number} [from_index] index from which to resequence
* @param {Number} [offset = 0] selection offset for DOM, in case there are rows to ignore in the table
@@ -810,8 +807,7 @@ openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.
var index = from_index + i;
// reset record-index accelerators on rows and even/odd
var even = index%2 === 0;
$(e).attr('data-index', index)
.toggleClass('even', even)
$(e).toggleClass('even', even)
.toggleClass('odd', !even);
});
}
@@ -1075,14 +1071,12 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
// ondrop, move relevant record & fix sequences
list.$current.sortable({
stop: function (event, ui) {
var from = ui.item.data('index'),
to = ui.item.prev().data('index') || 0;
if (from === to) { return; }
var to_move = list.records.at(from);
list.records.remove(to_move);
list.records.add(to_move, {at: to});
var to_move = list.records.get(ui.item.data('id')),
target_id = ui.item.prev().data('id');
list.refresh_zebra();
list.records.remove(to_move);
var to = target_id ? list.records.indexOf(list.records.get(target_id)) : 0;
list.records.add(to_move, { at: to });
// resequencing time!
var record, index = to,
@@ -1096,6 +1090,8 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
dataset.write(record.get('id'), {sequence: seq});
record.set('sequence', seq);
}
list.refresh_zebra();
}
});
},
@@ -1440,6 +1436,11 @@ var Collection = openerp.base.Class.extend(/** @lends Collection# */{
});
return results;
},
pluck: function (fieldname) {
return this.map(function (record) {
return record.get(fieldname);
});
},
indexOf: function (record) {
return _(this.records).indexOf(record);
}
+36 -8
View File
@@ -590,6 +590,20 @@ openerp.base.search.Field = openerp.base.search.Input.extend( /** @lends openerp
{}, context,
{own_values: {self: val}});
},
/**
* Function creating the returned domain for the field, override this
* methods in children if you only need to customize the field's domain
* without more complex alterations or tests (and without the need to
* change override the handling of filter_domain)
*
* @param {String} name the field's name
* @param {String} operator the field's operator (either attribute-specified or default operator for the field
* @param {Number|String} value parsed value for the field
* @returns {Array<Array>} domain to include in the resulting search
*/
make_domain: function (name, operator, value) {
return [[name, operator, value]];
},
get_domain: function () {
var val = this.get_value();
if (val === null || val === '') {
@@ -598,11 +612,10 @@ openerp.base.search.Field = openerp.base.search.Input.extend( /** @lends openerp
var domain = this.attrs['filter_domain'];
if (!domain) {
return [[
return this.make_domain(
this.attrs.name,
this.attrs.operator || this.default_operator,
this.get_value()
]];
val);
}
return _.extend({}, domain, {own_values: {self: val}});
}
@@ -723,7 +736,22 @@ openerp.base.search.DateField = openerp.base.search.Field.extend( /** @lends ope
return this.$element.val();
}
});
openerp.base.search.DateTimeField = openerp.base.search.DateField.extend({
/**
* Implementation of the ``datetime`` openerp field type:
*
* * Uses the same widget as the ``date`` field type (a simple date)
*
* * Builds a slighly more complex, it's a datetime range (includes time)
* spanning the whole day selected by the date widget
*
* @class
* @extends openerp.base.DateField
*/
openerp.base.search.DateTimeField = openerp.base.search.DateField.extend(/** @lends openerp.base.search.DateTimeField# */{
make_domain: function (name, operator, value) {
return ['&', [name, '>=', value + ' 00:00:00'],
[name, '<=', value + ' 23:59:59']];
}
});
openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({
init: function (view_section, field, view) {
@@ -781,16 +809,16 @@ openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({
}
return this._super(defaults);
},
get_domain: function () {
make_domain: function (name, operator, value) {
if (this.id && this.name) {
if (this.$element.val() === this.name) {
return [[this.attrs.name, '=', this.id]];
if (value === this.name) {
return [[name, '=', this.id]];
} else {
delete this.id;
delete this.name;
}
}
return this._super();
return this._super(name, operator, value);
}
});
+113 -3
View File
@@ -4,6 +4,8 @@
openerp.base.views = function(openerp) {
var _t = openerp.base._t;
/**
* Registry for all the client actions key: tag value: widget
*/
@@ -323,8 +325,9 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
}
},
on_mode_switch: function (view_type) {
this._super(view_type);
this.shortcut_check(this.views[view_type]);
return $.when(
this._super(view_type),
this.shortcut_check(this.views[view_type]));
},
shortcut_check : function(view) {
var self = this;
@@ -450,6 +453,106 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
}
});
openerp.base.TranslateDialog = openerp.base.Dialog.extend({
dialog_title: _t("Translations"),
init: function(view) {
this['on_button' + _t("Save")] = this.on_button_Save;
this['on_button' + _t("Close")] = this.on_button_Close;
this._super(view, {
width: '80%',
height: '80%'
});
this.view = view;
this.view_type = view.fields_view.type || '';
this.$fields_form = null;
this.$view_form = null;
this.$sidebar_form = null;
this.translatable_fields_keys = _.map(this.view.translatable_fields || [], function(i) { return i.name });
this.languages = null;
this.languages_loaded = $.Deferred();
(new openerp.base.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(),
[['translatable', '=', '1']])).read_slice(['code', 'name'], { sort: 'id' }, this.on_languages_loaded);
},
start: function() {
var self = this;
this._super();
$.when(this.languages_loaded).then(function() {
self.$element.html(QWeb.render('TranslateDialog', { widget: self }));
self.$element.tabs();
if (!(self.view.translatable_fields && self.view.translatable_fields.length)) {
self.hide_tabs('fields');
self.select_tab('view');
}
self.$fields_form = self.$element.find('.oe_translation_form');
});
return this;
},
on_languages_loaded: function(langs) {
this.languages = langs;
this.languages_loaded.resolve();
},
do_load_fields_values: function(callback) {
var self = this,
deffered = [];
this.$fields_form.find('.oe_trad_field').val('').removeClass('touched');
_.each(self.languages, function(lg) {
var deff = $.Deferred();
deffered.push(deff);
self.rpc('/base/dataset/get', {
model: self.view.dataset.model,
ids: [self.view.datarecord.id],
fields: self.translatable_fields_keys,
context: self.view.dataset.get_context({
'lang': lg.code
})
}, function(values) {
_.each(self.translatable_fields_keys, function(f) {
self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '');
});
deff.resolve();
});
});
$.when.apply(null, deffered).then(callback);
},
show_tabs: function() {
for (var i = 0; i < arguments.length; i++) {
this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().show();
}
},
hide_tabs: function() {
for (var i = 0; i < arguments.length; i++) {
this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().hide();
}
},
select_tab: function(name) {
this.show_tabs(name);
var index = this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().index() - 1;
this.$element.tabs('select', index);
},
open: function(field) {
var self = this,
sup = this._super;
$.when(this.languages_loaded).then(function() {
if (self.view.translatable_fields && self.view.translatable_fields.length) {
self.do_load_fields_values(function() {
sup.call(self);
if (field) {
// TODO: focus and scroll to field
}
});
} else {
sup.call(self);
}
});
},
on_button_Save: function() {
this.close();
},
on_button_Close: function() {
this.close();
}
});
openerp.base.View = openerp.base.Widget.extend({
set_default_options: function(options) {
this.options = options || {};
@@ -461,6 +564,12 @@ openerp.base.View = openerp.base.Widget.extend({
action_views_ids: {}
});
},
open_translate_dialog: function(field) {
if (!this.translate_dialog) {
this.translate_dialog = new openerp.base.TranslateDialog(this).start();
}
this.translate_dialog.open(field);
},
/**
* Fetches and executes the action identified by ``action_data``.
*
@@ -542,7 +651,7 @@ openerp.base.View = openerp.base.Widget.extend({
}, {
label: "Translate",
callback: this.on_sidebar_translate,
classname: 'oe_hide oe_sidebar_translate'
classname: 'oe_sidebar_translate'
}, {
label: "View Log",
callback: this.on_sidebar_view_log,
@@ -570,6 +679,7 @@ openerp.base.View = openerp.base.Widget.extend({
export_view.start();
},
on_sidebar_translate: function() {
this.open_translate_dialog();
},
on_sidebar_view_log: function() {
}
+41 -4
View File
@@ -453,6 +453,40 @@
</ul>
</div>
</t>
<t t-name="TranslateDialog">
<ul class="oe_translate_tabs">
<li><a t-attf-href="##{widget.element_id}_fields">Fields</a></li>
<li><a t-attf-href="##{widget.element_id}_view">View labels</a></li>
<li><a t-attf-href="##{widget.element_id}_sidebar">Sidebar Relates</a></li>
</ul>
<div t-attf-id="#{widget.element_id}_fields">
<table t-if="widget.view.translatable_fields" class="oe_frame oe_forms oe_translation_form" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td class="oe_form_separator" width="1%" nowrap="nowrap">
<div class="separator horizontal">Field</div>
</td>
<th t-foreach="widget.languages" align="left">
<div class="separator horizontal"><t t-esc="name"/></div>
</th>
</tr>
<tr t-foreach="widget.view.translatable_fields" t-as="field">
<td class="oe_form_frame_cell" width="1%" nowrap="nowrap">
<label class="oe_form_label"><t t-esc="field.string"/>:</label>
</td>
<td t-foreach="widget.languages" t-as="lg" class="oe_form_frame_cell">
<input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" class="oe_trad_field" style="width: 100%"/>
<textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" class="oe_trad_field" style="width: 100%"></textarea>
</td>
</tr>
</table>
</div>
<div t-attf-id="#{widget.element_id}_view">
Translate view
</div>
<div t-attf-id="#{widget.element_id}_sidebar">
Translate sidebar
</div>
</t>
<t t-name="TreeView">
<h2 class="oe_view_title"><t t-esc="title"/></h2>
<select t-if="toolbar" style="width: 30%">
@@ -554,12 +588,11 @@
<t t-name="ListView.rows" t-foreach="records.length" t-as="index">
<t t-call="ListView.row">
<t t-set="record" t-value="records.at(index)"/>
<t t-set="row_index" t-value="index"/>
<t t-set="row_parity" t-value="index_parity"/>
</t>
</t>
<tr t-name="ListView.row" t-att-class="row_parity"
t-att-data-index="row_index" t-att-data-id="record.get('id')">
t-att-data-id="record.get('id')">
<t t-foreach="columns" t-as="column">
<td t-if="column.meta">
@@ -703,8 +736,10 @@
<input type="text" size="1"
t-att-name="widget.name"
t-att-id="widget.element_id + '_field'"
t-att-class="'field_' + widget.type" style="width: 100%"
t-att-class="'field_' + widget.type"
t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
/>
<img class="oe_field_translate" t-if="widget.field.translate" src="/base/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/>
</t>
<t t-name="FieldEmail">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
@@ -735,11 +770,13 @@
</table>
</t>
<t t-name="FieldText">
<textarea rows="6" style="width: 100%;"
<textarea rows="6"
t-att-name="widget.name"
t-att-id="widget.element_id + '_field'"
t-att-class="'field_' + widget.type"
t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
></textarea>
<img class="oe_field_translate" t-if="widget.field.translate" src="/base/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/>
</t>
<t t-name="FieldDate">
<input type="text" size="1" style="width: 100%"