[MER] Merge from openerp-web.
bzr revid: jra@tinyerp.com-20110829055035-861s4xm5hp90ecep
This commit is contained in:
@@ -140,7 +140,7 @@ class WebClient(openerpweb.Controller):
|
||||
return content
|
||||
|
||||
@openerpweb.httprequest
|
||||
def home(self, req, s_action=None):
|
||||
def home(self, req, s_action=None, **kw):
|
||||
# script tags
|
||||
jslist = ['/base/webclient/js']
|
||||
if req.debug:
|
||||
@@ -423,25 +423,25 @@ def eval_context_and_domain(session, context, domain=None):
|
||||
|
||||
return e_context, e_domain
|
||||
|
||||
def load_actions_from_ir_values(req, key, key2, models, meta, context):
|
||||
def load_actions_from_ir_values(req, key, key2, models, meta):
|
||||
context = req.session.eval_context(req.context)
|
||||
Values = req.session.model('ir.values')
|
||||
actions = Values.get(key, key2, models, meta, context)
|
||||
|
||||
return [(id, name, clean_action(action, req.session, context=context))
|
||||
return [(id, name, clean_action(req, action))
|
||||
for id, name, action in actions]
|
||||
|
||||
def clean_action(action, session, context=None):
|
||||
def clean_action(req, action):
|
||||
context = req.session.eval_context(req.context)
|
||||
eval_ctx = req.session.evaluation_context(context)
|
||||
action.setdefault('flags', {})
|
||||
if action['type'] != 'ir.actions.act_window':
|
||||
return action
|
||||
|
||||
# values come from the server, we can just eval them
|
||||
if isinstance(action.get('context'), basestring):
|
||||
localvars = session.evaluation_context(context=context)
|
||||
action['context'] = eval( action['context'], localvars ) or {}
|
||||
action['context'] = eval( action['context'], eval_ctx ) or {}
|
||||
|
||||
if isinstance(action.get('domain'), basestring):
|
||||
localvars = session.evaluation_context( action.get('context', {}))
|
||||
action['domain'] = eval( action['domain'], localvars ) or []
|
||||
action['domain'] = eval( action['domain'], eval_ctx ) or []
|
||||
|
||||
return fix_view_modes(action)
|
||||
|
||||
@@ -559,8 +559,7 @@ class Menu(openerpweb.Controller):
|
||||
@openerpweb.jsonrequest
|
||||
def action(self, req, menu_id):
|
||||
actions = load_actions_from_ir_values(req,'action', 'tree_but_open',
|
||||
[('ir.ui.menu', menu_id)], False,
|
||||
req.session.eval_context(req.context))
|
||||
[('ir.ui.menu', menu_id)], False)
|
||||
return {"action": actions}
|
||||
|
||||
class DataSet(openerpweb.Controller):
|
||||
@@ -572,15 +571,15 @@ class DataSet(openerpweb.Controller):
|
||||
req.session.eval_context(req.context))}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, sort=None):
|
||||
return self.do_search_read(request, model, fields, offset, limit, domain, sort)
|
||||
def do_search_read(self, request, model, fields=False, offset=0, limit=False, domain=None
|
||||
def search_read(self, req, model, fields=False, offset=0, limit=False, domain=None, sort=None):
|
||||
return self.do_search_read(req, model, fields, offset, limit, domain, sort)
|
||||
def do_search_read(self, req, model, fields=False, offset=0, limit=False, domain=None
|
||||
, sort=None):
|
||||
""" Performs a search() followed by a read() (if needed) using the
|
||||
provided search criteria
|
||||
|
||||
:param request: a JSON-RPC request object
|
||||
:type request: openerpweb.JsonRequest
|
||||
:param req: a JSON-RPC request object
|
||||
:type req: openerpweb.JsonRequest
|
||||
:param str model: the name of the model to search on
|
||||
:param fields: a list of the fields to return in the result records
|
||||
:type fields: [str]
|
||||
@@ -593,10 +592,10 @@ class DataSet(openerpweb.Controller):
|
||||
matching fields selection set)
|
||||
:rtype: list
|
||||
"""
|
||||
Model = request.session.model(model)
|
||||
Model = req.session.model(model)
|
||||
|
||||
context, domain = eval_context_and_domain(
|
||||
request.session, request.context, domain)
|
||||
req.session, req.context, domain)
|
||||
|
||||
ids = Model.search(domain, 0, False, sort or False, context)
|
||||
# need to fill the dataset with all ids for the (domain, context) pair,
|
||||
@@ -618,22 +617,22 @@ class DataSet(openerpweb.Controller):
|
||||
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def read(self, request, model, ids, fields=False):
|
||||
return self.do_search_read(request, model, ids, fields)
|
||||
def read(self, req, model, ids, fields=False):
|
||||
return self.do_search_read(req, model, ids, fields)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get(self, request, model, ids, fields=False):
|
||||
return self.do_get(request, model, ids, fields)
|
||||
def get(self, req, model, ids, fields=False):
|
||||
return self.do_get(req, model, ids, fields)
|
||||
|
||||
def do_get(self, request, model, ids, fields=False):
|
||||
def do_get(self, req, model, ids, fields=False):
|
||||
""" Fetches and returns the records of the model ``model`` whose ids
|
||||
are in ``ids``.
|
||||
|
||||
The results are in the same order as the inputs, but elements may be
|
||||
missing (if there is no record left for the id)
|
||||
|
||||
:param request: the JSON-RPC2 request object
|
||||
:type request: openerpweb.JsonRequest
|
||||
:param req: the JSON-RPC2 request object
|
||||
:type req: openerpweb.JsonRequest
|
||||
:param model: the model to read from
|
||||
:type model: str
|
||||
:param ids: a list of identifiers
|
||||
@@ -644,8 +643,8 @@ class DataSet(openerpweb.Controller):
|
||||
:returns: a list of records, in the same order as the list of ids
|
||||
:rtype: list
|
||||
"""
|
||||
Model = request.session.model(model)
|
||||
records = Model.read(ids, fields, request.session.eval_context(request.context))
|
||||
Model = req.session.model(model)
|
||||
records = Model.read(ids, fields, req.session.eval_context(req.context))
|
||||
|
||||
record_map = dict((record['id'], record) for record in records)
|
||||
|
||||
@@ -673,9 +672,9 @@ class DataSet(openerpweb.Controller):
|
||||
return {'result': r}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def unlink(self, request, model, ids=()):
|
||||
Model = request.session.model(model)
|
||||
return Model.unlink(ids, request.session.eval_context(request.context))
|
||||
def unlink(self, req, model, ids=()):
|
||||
Model = req.session.model(model)
|
||||
return Model.unlink(ids, req.session.eval_context(req.context))
|
||||
|
||||
def call_common(self, req, model, method, args, domain_id=None, context_id=None):
|
||||
domain = args[domain_id] if domain_id and len(args) - 1 >= domain_id else []
|
||||
@@ -696,7 +695,7 @@ class DataSet(openerpweb.Controller):
|
||||
def call_button(self, req, model, method, args, domain_id=None, context_id=None):
|
||||
action = self.call_common(req, model, method, args, domain_id, context_id)
|
||||
if isinstance(action, dict) and action.get('type') != '':
|
||||
return {'result': clean_action(action, req.session)}
|
||||
return {'result': clean_action(req, action)}
|
||||
return {'result': False}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
@@ -718,9 +717,9 @@ class DataSet(openerpweb.Controller):
|
||||
class DataGroup(openerpweb.Controller):
|
||||
_cp_path = "/base/group"
|
||||
@openerpweb.jsonrequest
|
||||
def read(self, request, model, fields, group_by_fields, domain=None, sort=None):
|
||||
Model = request.session.model(model)
|
||||
context, domain = eval_context_and_domain(request.session, request.context, domain)
|
||||
def read(self, req, model, fields, group_by_fields, domain=None, sort=None):
|
||||
Model = req.session.model(model)
|
||||
context, domain = eval_context_and_domain(req.session, req.context, domain)
|
||||
|
||||
return Model.read_group(
|
||||
domain or [], fields, group_by_fields, 0, False,
|
||||
@@ -729,13 +728,13 @@ class DataGroup(openerpweb.Controller):
|
||||
class View(openerpweb.Controller):
|
||||
_cp_path = "/base/view"
|
||||
|
||||
def fields_view_get(self, request, model, view_id, view_type,
|
||||
def fields_view_get(self, req, model, view_id, view_type,
|
||||
transform=True, toolbar=False, submenu=False):
|
||||
Model = request.session.model(model)
|
||||
context = request.session.eval_context(request.context)
|
||||
Model = req.session.model(model)
|
||||
context = req.session.eval_context(req.context)
|
||||
fvg = Model.fields_view_get(view_id, view_type, context, toolbar, submenu)
|
||||
# todo fme?: check that we should pass the evaluated context here
|
||||
self.process_view(request.session, fvg, context, transform)
|
||||
self.process_view(req.session, fvg, context, transform)
|
||||
return fvg
|
||||
|
||||
def process_view(self, session, fvg, context, transform):
|
||||
@@ -768,20 +767,20 @@ class View(openerpweb.Controller):
|
||||
field["context"] = self.parse_context(field["context"], session)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def add_custom(self, request, view_id, arch):
|
||||
CustomView = request.session.model('ir.ui.view.custom')
|
||||
def add_custom(self, req, view_id, arch):
|
||||
CustomView = req.session.model('ir.ui.view.custom')
|
||||
CustomView.create({
|
||||
'user_id': request.session._uid,
|
||||
'user_id': req.session._uid,
|
||||
'ref_id': view_id,
|
||||
'arch': arch
|
||||
}, request.session.eval_context(request.context))
|
||||
}, req.session.eval_context(req.context))
|
||||
return {'result': True}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def undo_custom(self, request, view_id, reset=False):
|
||||
CustomView = request.session.model('ir.ui.view.custom')
|
||||
context = request.session.eval_context(request.context)
|
||||
vcustom = CustomView.search([('user_id', '=', request.session._uid), ('ref_id' ,'=', view_id)],
|
||||
def undo_custom(self, req, view_id, reset=False):
|
||||
CustomView = req.session.model('ir.ui.view.custom')
|
||||
context = req.session.eval_context(req.context)
|
||||
vcustom = CustomView.search([('user_id', '=', req.session._uid), ('ref_id' ,'=', view_id)],
|
||||
0, False, False, context)
|
||||
if vcustom:
|
||||
if reset:
|
||||
@@ -1040,13 +1039,13 @@ class Action(openerpweb.Controller):
|
||||
action = req.session.model(action_type[0]['type']).read([action_id], False,
|
||||
context)
|
||||
if action:
|
||||
value = clean_action(action[0], req.session)
|
||||
value = clean_action(req, action[0])
|
||||
return {'result': value}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def run(self, req, action_id):
|
||||
return clean_action(req.session.model('ir.actions.server').run(
|
||||
[action_id], req.session.eval_context(req.context)), req.session)
|
||||
return clean_action(req, req.session.model('ir.actions.server').run(
|
||||
[action_id], req.session.eval_context(req.context)))
|
||||
|
||||
class TreeView(View):
|
||||
_cp_path = "/base/treeview"
|
||||
@@ -1059,7 +1058,7 @@ class TreeView(View):
|
||||
def action(self, req, model, id):
|
||||
return load_actions_from_ir_values(
|
||||
req,'action', 'tree_but_open',[(model, id)],
|
||||
False, req.session.eval_context(req.context))
|
||||
False)
|
||||
|
||||
def export_csv(fields, result):
|
||||
fp = StringIO()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -590,22 +590,27 @@ openerp.base.Header = openerp.base.Widget.extend({
|
||||
sc.binding = {};
|
||||
$(sc.binding).bind({
|
||||
'add': function (e, attrs) {
|
||||
var $shortcut = $('<li>', {
|
||||
shortcuts_ds.create(attrs, function (out) {
|
||||
$('<li>', {
|
||||
'data-shortcut-id':out.result,
|
||||
'data-id': attrs.res_id
|
||||
}).text(attrs.name)
|
||||
.appendTo(self.$element.find('.oe-shortcuts ul'));
|
||||
shortcuts_ds.create(attrs, function (out) {
|
||||
$shortcut.data('shortcut-id', out.result);
|
||||
.appendTo(self.$element.find('.oe-shortcuts ul'));
|
||||
attrs.id = out.result;
|
||||
sc.push(attrs);
|
||||
});
|
||||
},
|
||||
'remove-current': function () {
|
||||
var menu_id = self.session.active_id;
|
||||
var $shortcut = self.$element
|
||||
.find('.oe-shortcuts li[data-id=' + menu_id + ']');
|
||||
.find('.oe-shortcuts li[data-id=' + menu_id + ']');
|
||||
var shortcut_id = $shortcut.data('shortcut-id');
|
||||
$shortcut.remove();
|
||||
shortcuts_ds.unlink([shortcut_id]);
|
||||
}
|
||||
var sc_new = _.reject(sc, function(shortcut){ return shortcut_id === shortcut.id});
|
||||
sc.splice(0, sc.length);
|
||||
sc.push.apply(sc, sc_new);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.rpc('/base/session/sc_list', {}, function(shortcuts) {
|
||||
@@ -615,6 +620,7 @@ openerp.base.Header = openerp.base.Widget.extend({
|
||||
self.$element.find('.oe-shortcuts')
|
||||
.html(QWeb.render('Shortcuts', {'shortcuts': shortcuts}))
|
||||
.undelegate('li', 'click')
|
||||
|
||||
.delegate('li', 'click', function(e) {
|
||||
e.stopPropagation();
|
||||
var id = $(this).data('id');
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -396,18 +396,18 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {Array} [args]
|
||||
* @param {Number} [domain_id] index of a domain to evaluate in the args array
|
||||
* @param {Number} [context_id] index of a context to evaluate in the args array
|
||||
* @param {Number} [domain_index] index of a domain to evaluate in the args array
|
||||
* @param {Number} [context_index] index of a context to evaluate in the args array
|
||||
* @param {Function} callback
|
||||
* @param {Function }error_callback
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
call_and_eval: function (method, args, domain_id, context_id, callback, error_callback) {
|
||||
call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/call', {
|
||||
model: this.model,
|
||||
method: method,
|
||||
domain_id: domain_id || null,
|
||||
context_id: context_id || null,
|
||||
domain_id: domain_index || null,
|
||||
context_id: context_index || null,
|
||||
args: args || []
|
||||
}, callback, error_callback);
|
||||
},
|
||||
|
||||
@@ -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() {
|
||||
@@ -440,6 +441,10 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||
values[key] = val;
|
||||
});
|
||||
return values;
|
||||
},
|
||||
get_selected_ids: function() {
|
||||
var id = this.dataset.ids[this.dataset.index];
|
||||
return id ? [id] : [];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -461,7 +466,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) {
|
||||
@@ -839,6 +844,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;
|
||||
@@ -850,6 +862,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;
|
||||
},
|
||||
@@ -938,7 +953,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() {
|
||||
@@ -946,16 +961,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() {
|
||||
@@ -967,7 +982,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);
|
||||
@@ -982,8 +996,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());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1006,44 +1019,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();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1052,7 +1034,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);
|
||||
@@ -1092,8 +1073,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');
|
||||
}
|
||||
@@ -1109,39 +1088,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);
|
||||
@@ -1149,7 +1104,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() {
|
||||
@@ -1157,16 +1112,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() {
|
||||
@@ -1355,36 +1310,56 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
this.$input = this.$element.find("input");
|
||||
this.$drop_down = this.$element.find(".oe-m2o-drop-down-button");
|
||||
this.$menu_btn = this.$element.find(".oe-m2o-cm-button");
|
||||
|
||||
|
||||
// context menu
|
||||
var bindings = {};
|
||||
bindings[this.cm_id + "_search"] = function() {
|
||||
self._search_create_popup("search");
|
||||
};
|
||||
bindings[this.cm_id + "_create"] = function() {
|
||||
self._search_create_popup("form");
|
||||
};
|
||||
bindings[this.cm_id + "_open"] = function() {
|
||||
if (!self.value) {
|
||||
return;
|
||||
}
|
||||
var pop = new openerp.base.form.FormOpenPopup(self.view);
|
||||
pop.show_element(self.field.relation, self.value[0],self.build_context(), {});
|
||||
pop.on_write_completed.add_last(function() {
|
||||
self.set_value(self.value[0]);
|
||||
var init_context_menu_def = $.Deferred().then(function(e) {
|
||||
var rdataset = new openerp.base.DataSetStatic(self, "ir.values", self.build_context());
|
||||
rdataset.call("get", ['action', 'client_action_relate',
|
||||
[[self.field.relation, false]], false, rdataset.get_context()], false, 0)
|
||||
.then(function(result) {
|
||||
self.related_entries = result;
|
||||
|
||||
var $cmenu = $("#" + self.cm_id);
|
||||
$cmenu.append(QWeb.render("FieldMany2One.context_menu", {widget: self}));
|
||||
var bindings = {};
|
||||
bindings[self.cm_id + "_search"] = function() {
|
||||
self._search_create_popup("search");
|
||||
};
|
||||
bindings[self.cm_id + "_create"] = function() {
|
||||
self._search_create_popup("form");
|
||||
};
|
||||
bindings[self.cm_id + "_open"] = function() {
|
||||
if (!self.value) {
|
||||
return;
|
||||
}
|
||||
var pop = new openerp.base.form.FormOpenPopup(self.view);
|
||||
pop.show_element(self.field.relation, self.value[0],self.build_context(), {});
|
||||
pop.on_write_completed.add_last(function() {
|
||||
self.set_value(self.value[0]);
|
||||
});
|
||||
};
|
||||
_.each(_.range(self.related_entries.length), function(i) {
|
||||
bindings[self.cm_id + "_related_" + i] = function() {
|
||||
self.open_related(self.related_entries[i]);
|
||||
};
|
||||
});
|
||||
var cmenu = self.$menu_btn.contextMenu(self.cm_id, {'leftClickToo': true,
|
||||
bindings: bindings, itemStyle: {"color": ""},
|
||||
onContextMenu: function() {
|
||||
if(self.value) {
|
||||
$("#" + self.cm_id + " .oe_m2o_menu_item_mandatory").removeClass("oe-m2o-disabled-cm");
|
||||
} else {
|
||||
$("#" + self.cm_id + " .oe_m2o_menu_item_mandatory").addClass("oe-m2o-disabled-cm");
|
||||
}
|
||||
return true;
|
||||
}, menuStyle: {width: "200px"}
|
||||
});
|
||||
setTimeout(function() {self.$menu_btn.trigger(e);}, 0);
|
||||
});
|
||||
};
|
||||
var cmenu = this.$menu_btn.contextMenu(this.cm_id, {'leftClickToo': true,
|
||||
bindings: bindings, itemStyle: {"color": ""},
|
||||
onContextMenu: function() {
|
||||
if(self.value) {
|
||||
$("#" + self.cm_id + "_open").removeClass("oe-m2o-disabled-cm");
|
||||
} else {
|
||||
$("#" + self.cm_id + "_open").addClass("oe-m2o-disabled-cm");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
var ctx_callback = function(e) {init_context_menu_def.resolve(e); e.preventDefault()};
|
||||
this.$menu_btn.bind('contextmenu', ctx_callback);
|
||||
this.$menu_btn.click(ctx_callback);
|
||||
|
||||
// some behavior for input
|
||||
this.$input.keyup(function() {
|
||||
@@ -1578,6 +1553,21 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
if (this.value === null) {
|
||||
this.invalid = this.required;
|
||||
}
|
||||
},
|
||||
open_related: function(related) {
|
||||
var self = this;
|
||||
if (!self.value)
|
||||
return;
|
||||
self.rpc("/base/action/load", {
|
||||
action_id: related[2].id,
|
||||
context: {
|
||||
active_id: self.value[0],
|
||||
active_ids: [self.value[0]],
|
||||
active_model: self.field.relation
|
||||
}
|
||||
}, function(result) {
|
||||
self.do_action(result.result);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2429,9 +2419,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'
|
||||
});
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -382,10 +382,19 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
* re-renders the content of the list view
|
||||
*/
|
||||
reload_content: function () {
|
||||
var self = this;
|
||||
this.records.reset();
|
||||
this.$element.find('.oe-listview-content').append(
|
||||
this.groups.render(
|
||||
$.proxy(this, 'compute_aggregates')));
|
||||
this.groups.render(function () {
|
||||
if (self.dataset.index == null) {
|
||||
var has_one = false;
|
||||
self.records.each(function () { has_one = true; });
|
||||
if (has_one) {
|
||||
self.dataset.index = 0;
|
||||
}
|
||||
}
|
||||
self.compute_aggregates();
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Event handler for a search, asks for the computation/folding of domains
|
||||
@@ -398,8 +407,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
*/
|
||||
do_search: function (domains, contexts, groupbys) {
|
||||
return this.rpc('/base/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
domains: [this.dataset.get_domain()].concat(domains),
|
||||
contexts: [this.dataset.get_context()].concat(contexts),
|
||||
group_by_seq: groupbys
|
||||
}, $.proxy(this, 'do_actual_search'));
|
||||
},
|
||||
@@ -588,8 +597,11 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
$footer_cells.filter(_.sprintf('[data-field=%s]', column.id))
|
||||
.html(openerp.base.format_cell(aggregation, column));
|
||||
});
|
||||
},
|
||||
get_selected_ids: function() {
|
||||
var ids = this.groups.get_selection().ids;
|
||||
return ids;
|
||||
}
|
||||
// TODO: implement reorder (drag and drop rows)
|
||||
});
|
||||
openerp.base.ListView.List = openerp.base.Class.extend( /** @lends openerp.base.ListView.List# */{
|
||||
/**
|
||||
@@ -641,12 +653,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 +694,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 +741,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 +769,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 +819,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);
|
||||
});
|
||||
}
|
||||
@@ -1043,25 +1051,25 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
|
||||
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
|
||||
var options = { offset: page * limit, limit: limit };
|
||||
dataset.read_slice(fields, options , function (records) {
|
||||
if (!self.datagroup.openable) {
|
||||
view.configure_pager(dataset);
|
||||
} else {
|
||||
var pages = Math.ceil(dataset.ids.length / limit);
|
||||
self.$row
|
||||
.find('.oe-pager-state')
|
||||
.text(_.sprintf('%d/%d', page + 1, pages))
|
||||
.end()
|
||||
.find('button[data-pager-action=previous]')
|
||||
.attr('disabled', page === 0)
|
||||
.end()
|
||||
.find('button[data-pager-action=next]')
|
||||
.attr('disabled', page === pages - 1);
|
||||
}
|
||||
if (!self.datagroup.openable) {
|
||||
view.configure_pager(dataset);
|
||||
} else {
|
||||
var pages = Math.ceil(dataset.ids.length / limit);
|
||||
self.$row
|
||||
.find('.oe-pager-state')
|
||||
.text(_.sprintf('%d/%d', page + 1, pages))
|
||||
.end()
|
||||
.find('button[data-pager-action=previous]')
|
||||
.attr('disabled', page === 0)
|
||||
.end()
|
||||
.find('button[data-pager-action=next]')
|
||||
.attr('disabled', page === pages - 1);
|
||||
}
|
||||
|
||||
self.records.add(records, {silent: true});
|
||||
list.render();
|
||||
d.resolve(list);
|
||||
});
|
||||
self.records.add(records, {silent: true});
|
||||
list.render();
|
||||
d.resolve(list);
|
||||
});
|
||||
return d.promise();
|
||||
},
|
||||
setup_resequence_rows: function (list, dataset) {
|
||||
@@ -1075,14 +1083,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 +1102,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 +1448,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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -773,6 +801,8 @@ openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({
|
||||
render: function (defaults) {
|
||||
if (defaults[this.attrs.name]) {
|
||||
this.id = defaults[this.attrs.name];
|
||||
if (this.id instanceof Array)
|
||||
this.id = this.id[0];
|
||||
// TODO: maybe this should not be completely removed
|
||||
delete defaults[this.attrs.name];
|
||||
this.dataset.name_get([this.id], $.proxy(this, 'on_name_get'));
|
||||
@@ -781,16 +811,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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -347,20 +350,22 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||
shortcut_add_remove: function() {
|
||||
var self = this;
|
||||
var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
|
||||
$shortcut_toggle.click(function() {
|
||||
if ($shortcut_toggle.hasClass("oe-shortcut-remove")) {
|
||||
$(self.session.shortcuts.binding).trigger('remove-current');
|
||||
$shortcut_toggle.removeClass("oe-shortcut-remove");
|
||||
} else {
|
||||
$(self.session.shortcuts.binding).trigger('add', {
|
||||
'user_id': self.session.uid,
|
||||
'res_id': self.session.active_id,
|
||||
'resource': 'ir.ui.menu',
|
||||
'name': self.action.name
|
||||
});
|
||||
$shortcut_toggle.addClass("oe-shortcut-remove");
|
||||
}
|
||||
});
|
||||
$shortcut_toggle
|
||||
.unbind("click")
|
||||
.click(function() {
|
||||
if ($shortcut_toggle.hasClass("oe-shortcut-remove")) {
|
||||
$(self.session.shortcuts.binding).trigger('remove-current');
|
||||
$shortcut_toggle.removeClass("oe-shortcut-remove");
|
||||
} else {
|
||||
$(self.session.shortcuts.binding).trigger('add', {
|
||||
'user_id': self.session.uid,
|
||||
'res_id': self.session.active_id,
|
||||
'resource': 'ir.ui.menu',
|
||||
'name': self.action.name
|
||||
});
|
||||
$shortcut_toggle.addClass("oe-shortcut-remove");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -371,8 +376,8 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
|
||||
this.sections = {};
|
||||
},
|
||||
start: function() {
|
||||
this._super(this);
|
||||
var self = this;
|
||||
this._super(this, arguments);
|
||||
this.$element.html(QWeb.render('Sidebar'));
|
||||
this.$element.find(".toggle-sidebar").click(function(e) {
|
||||
self.do_toggle();
|
||||
@@ -428,9 +433,23 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
|
||||
item.callback();
|
||||
}
|
||||
if (item.action) {
|
||||
item.action.flags = item.action.flags || {};
|
||||
item.action.flags.new_window = true;
|
||||
self.do_action(item.action);
|
||||
var ids = self.widget_parent.get_selected_ids();
|
||||
if (ids.length == 0) {
|
||||
//TODO niv: maybe show a warning?
|
||||
return false;
|
||||
}
|
||||
self.rpc("/base/action/load", {
|
||||
action_id: item.action.id,
|
||||
context: {
|
||||
active_id: ids[0],
|
||||
active_ids: ids,
|
||||
active_model: self.widget_parent.dataset.model
|
||||
}
|
||||
}, function(result) {
|
||||
result.result.flags = result.result.flags || {};
|
||||
result.result.flags.new_window = true;
|
||||
self.do_action(result.result);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -450,6 +469,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 +580,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 +667,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 +695,7 @@ openerp.base.View = openerp.base.Widget.extend({
|
||||
export_view.start();
|
||||
},
|
||||
on_sidebar_translate: function() {
|
||||
this.open_translate_dialog();
|
||||
},
|
||||
on_sidebar_view_log: function() {
|
||||
}
|
||||
|
||||
@@ -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%"
|
||||
@@ -768,13 +805,24 @@
|
||||
<img src="/base/static/src/img/down-arrow.png" /></span>
|
||||
<span class="oe-m2o-cm-button" t-att-id="widget.name + '_open'">
|
||||
<img src="/base/static/src/img/icons/gtk-index.png"/></span>
|
||||
<div t-att-id="widget.cm_id" class="contextMenu" style="display:none"><ul>
|
||||
<li t-att-id="widget.cm_id + '_open'" style="color:grey">Open...</li>
|
||||
<li t-att-id="widget.cm_id + '_create'">Create...</li>
|
||||
<li t-att-id="widget.cm_id + '_search'">Search...</li>
|
||||
</ul></div>
|
||||
<div t-att-id="widget.cm_id" class="contextMenu" style="display:none">
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="FieldMany2One.context_menu">
|
||||
<ul>
|
||||
<li t-att-id="widget.cm_id + '_open'" style="color:grey">Open...</li>
|
||||
<li t-att-id="widget.cm_id + '_create'">Create...</li>
|
||||
<li t-att-id="widget.cm_id + '_search'" class="oe_m2o_menu_item_mandatory">Search...</li>
|
||||
<t t-set="i" t-value="0"/>
|
||||
<t t-foreach="widget.related_entries" t-as="entry">
|
||||
<li t-att-id="widget.cm_id + '_related_' + i" style="color:grey" class="oe_m2o_menu_item_mandatory">
|
||||
... <t t-esc="(entry[2] || {})['name'] || ''"/>
|
||||
</li>
|
||||
<t t-set="i" t-value="i+1"/>
|
||||
</t>
|
||||
</ul>
|
||||
</t>
|
||||
<t t-name="FieldOne2Many">
|
||||
<div t-att-id="widget.element_id">
|
||||
</div>
|
||||
|
||||
@@ -327,6 +327,10 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
||||
if (this.sidebar) {
|
||||
this.sidebar.$element.hide();
|
||||
}
|
||||
},
|
||||
get_selected_ids: function() {
|
||||
// no way to select a record anyway
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import openerpweb
|
||||
|
||||
WIDGET_CONTENT_PATTERN = """<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>[[Widget %(id)d]]</title></head>
|
||||
<body>
|
||||
%(content)s
|
||||
<script type="text/javascript">
|
||||
var load = window.onload;
|
||||
window.onload = function () {
|
||||
if (load) {
|
||||
load();
|
||||
}
|
||||
window.frameElement.style.height = document.height + 'px';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
class Widgets(openerpweb.openerpweb.Controller):
|
||||
_cp_path = '/base_dashboard/widgets'
|
||||
|
||||
@openerpweb.httprequest
|
||||
def content(self, request, widget_id):
|
||||
return request.session.model('res.widget').read(
|
||||
return WIDGET_CONTENT_PATTERN % request.session.model('res.widget').read(
|
||||
[widget_id], ['content'], request.session.eval_context(request.context)
|
||||
)[0]['content']
|
||||
)[0]
|
||||
|
||||
@@ -321,7 +321,7 @@ openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({
|
||||
$progress.progressbar({value: $progress.data('completion')});
|
||||
|
||||
var self = this;
|
||||
this.$element.find('div.oe-dashboard-config-overview ul')
|
||||
this.$element.find('dl')
|
||||
.delegate('input', 'click', function (e) {
|
||||
// switch todo status
|
||||
e.stopImmediatePropagation();
|
||||
@@ -372,39 +372,36 @@ openerp.base_dashboard.ApplicationTiles = openerp.base.View.extend({
|
||||
}
|
||||
});
|
||||
openerp.base.client_actions.add(
|
||||
'board.home.widgets', 'openerp.base_dashboard.Widgets');
|
||||
openerp.base_dashboard.Widgets = openerp.base.View.extend({
|
||||
template: 'HomeWidgets',
|
||||
start: function () {
|
||||
return new openerp.base.DataSetSearch(
|
||||
this, 'res.widget.user', null,
|
||||
['|', ['user_id', '=', false],
|
||||
['user_id', '=', parseInt(this.session.uid, 10)]])
|
||||
.read_slice(['widget_id', 'user_id'], {}, this.on_widgets_list_loaded);
|
||||
'board.home.widgets', 'openerp.base_dashboard.Widget');
|
||||
openerp.base_dashboard.Widget = openerp.base.View.extend(/** @lends openerp.base_dashboard.Widgets# */{
|
||||
template: 'HomeWidget',
|
||||
/**
|
||||
* Initializes a "HomeWidget" client widget: handles the display of a given
|
||||
* res.widget objects in an OpenERP view (mainly a dashboard).
|
||||
*
|
||||
* @constructs
|
||||
* @extends openerp.base.View
|
||||
* @param {Object} parent
|
||||
* @param {Object} options
|
||||
* @param {Number} options.widget_id
|
||||
*/
|
||||
init: function (parent, options) {
|
||||
this._super(parent);
|
||||
this.widget_id = options.widget_id;
|
||||
},
|
||||
on_widgets_list_loaded: function (user_widgets) {
|
||||
var self = this;
|
||||
var widget_user = {};
|
||||
_(user_widgets).each(function (widget) {
|
||||
widget['widget_id'] = widget['widget_id'][0];
|
||||
widget_user[widget['widget_id']] = {
|
||||
removable: widget['user_id'] !== false,
|
||||
user_widget_id: widget['id']
|
||||
};
|
||||
});
|
||||
new openerp.base.DataSetSearch(this, 'res.widget')
|
||||
.read_ids(_(user_widgets).pluck('widget_id'), ['title'], function (widgets) {
|
||||
_(widgets).each(function (widget) {
|
||||
_.extend(widget, widget_user[widget['id']]);
|
||||
});
|
||||
var url = _.sprintf(
|
||||
'/base_dashboard/widgets/content?session_id=%s&widget_id=',
|
||||
self.session.session_id);
|
||||
self.$element.html(QWeb.render('HomeWidgets', {
|
||||
widgets: widgets,
|
||||
url: url
|
||||
}));
|
||||
});
|
||||
start: function () {
|
||||
return new openerp.base.DataSet(this, 'res.widget').read_ids(
|
||||
[this.widget_id], ['title'], this.on_widget_loaded);
|
||||
},
|
||||
on_widget_loaded: function (widgets) {
|
||||
var widget = widgets[0];
|
||||
var url = _.sprintf(
|
||||
'/base_dashboard/widgets/content?session_id=%s&widget_id=%d',
|
||||
this.session.session_id, widget.id);
|
||||
this.$element.html(QWeb.render('HomeWidget.content', {
|
||||
widget: widget,
|
||||
url: url
|
||||
}));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -107,10 +107,9 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div t-name="HomeWidgets" class="oe-dashboard-home-widgets"/>
|
||||
<div t-name="HomeWidgets.content" class="oe-dashboard-home-widgets-widget"
|
||||
t-foreach="widgets" t-as="widget">
|
||||
<div t-name="HomeWidget" class="oe-dashboard-home-widget"/>
|
||||
<t t-name="HomeWidget.content">
|
||||
<h3><t t-esc="widget.title"/></h3>
|
||||
<iframe width="100%" frameborder="0" t-att-src="url + widget.id"/>
|
||||
</div>
|
||||
<iframe width="100%" frameborder="0" t-att-src="url"/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user