[Merge] With trunk upto revision 550.
bzr revid: noz@tinyerp.com-20110701051745-4t2i4a5n99x52e9k
This commit is contained in:
@@ -237,18 +237,18 @@ def eval_context_and_domain(session, context, domain=None):
|
||||
# should we give the evaluated context as an evaluation context to the domain?
|
||||
e_domain = session.eval_domain(domain or [])
|
||||
|
||||
return (e_context, e_domain)
|
||||
return e_context, e_domain
|
||||
|
||||
def load_actions_from_ir_values(req, key, key2, models, meta, context):
|
||||
Values = req.session.model('ir.values')
|
||||
actions = Values.get(key, key2, models, meta, context)
|
||||
|
||||
for _, _, action in actions:
|
||||
clean_action(action, req.session)
|
||||
|
||||
return actions
|
||||
return [(id, name, clean_action(action, req.session))
|
||||
for id, name, action in actions]
|
||||
|
||||
def clean_action(action, session):
|
||||
if action['type'] != 'ir.actions.act_window':
|
||||
return action
|
||||
# values come from the server, we can just eval them
|
||||
if isinstance(action.get('context', None), basestring):
|
||||
action['context'] = eval(
|
||||
@@ -260,11 +260,49 @@ def clean_action(action, session):
|
||||
action['domain'],
|
||||
session.evaluation_context(
|
||||
action['context'])) or []
|
||||
if not action.has_key('flags'):
|
||||
if 'flags' not in action:
|
||||
# Set empty flags dictionary for web client.
|
||||
action['flags'] = dict()
|
||||
return fix_view_modes(action)
|
||||
|
||||
def generate_views(action):
|
||||
"""
|
||||
While the server generates a sequence called "views" computing dependencies
|
||||
between a bunch of stuff for views coming directly from the database
|
||||
(the ``ir.actions.act_window model``), it's also possible for e.g. buttons
|
||||
to return custom view dictionaries generated on the fly.
|
||||
|
||||
In that case, there is no ``views`` key available on the action.
|
||||
|
||||
Since the web client relies on ``action['views']``, generate it here from
|
||||
``view_mode`` and ``view_id``.
|
||||
|
||||
Currently handles two different cases:
|
||||
|
||||
* no view_id, multiple view_mode
|
||||
* single view_id, single view_mode
|
||||
|
||||
:param dict action: action descriptor dictionary to generate a views key for
|
||||
"""
|
||||
view_id = action.get('view_id', False)
|
||||
if isinstance(view_id, (list, tuple)):
|
||||
view_id = view_id[0]
|
||||
|
||||
# providing at least one view mode is a requirement, not an option
|
||||
view_modes = action['view_mode'].split(',')
|
||||
|
||||
if len(view_modes) > 1:
|
||||
if view_id:
|
||||
raise ValueError('Non-db action dictionaries should provide '
|
||||
'either multiple view modes or a single view '
|
||||
'mode and an optional view id.\n\n Got view '
|
||||
'modes %r and view id %r for action %r' % (
|
||||
view_modes, view_id, action))
|
||||
action['views'] = [(False, mode) for mode in view_modes]
|
||||
return
|
||||
action['views'] = [(view_id, view_modes[0])]
|
||||
|
||||
|
||||
def fix_view_modes(action):
|
||||
""" For historical reasons, OpenERP has weird dealings in relation to
|
||||
view_mode and the view_type attribute (on window actions):
|
||||
@@ -283,18 +321,17 @@ def fix_view_modes(action):
|
||||
:param dict action: an action descriptor
|
||||
:returns: nothing, the action is modified in place
|
||||
"""
|
||||
if 'views' not in action:
|
||||
generate_views(action)
|
||||
|
||||
if action.pop('view_type') != 'form':
|
||||
return
|
||||
|
||||
if action.has_key('view_mode'):
|
||||
action['view_mode'] = ','.join(
|
||||
mode if mode != 'tree' else 'list'
|
||||
for mode in action['view_mode'].split(','))
|
||||
if action.has_key('views'):
|
||||
action['views'] = [
|
||||
[id, mode if mode != 'tree' else 'list']
|
||||
for id, mode in action['views']
|
||||
]
|
||||
action['views'] = [
|
||||
[id, mode if mode != 'tree' else 'list']
|
||||
for id, mode in action['views']
|
||||
]
|
||||
|
||||
return action
|
||||
|
||||
class Menu(openerpweb.Controller):
|
||||
@@ -438,21 +475,20 @@ class DataSet(openerpweb.Controller):
|
||||
return {'result': r}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def unlink(self, request, model, ids=[]):
|
||||
def unlink(self, request, model, ids=()):
|
||||
Model = request.session.model(model)
|
||||
return Model.unlink(ids, request.session.eval_context(request.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 []
|
||||
context = args[context_id] if context_id and len(args) - 1 >= context_id else {}
|
||||
c, d = eval_context_and_domain(req.session, context, domain);
|
||||
if(domain_id and len(args) - 1 >= domain_id):
|
||||
c, d = eval_context_and_domain(req.session, context, domain)
|
||||
if domain_id and len(args) - 1 >= domain_id:
|
||||
args[domain_id] = d
|
||||
if(context_id and len(args) - 1 >= context_id):
|
||||
if context_id and len(args) - 1 >= context_id:
|
||||
args[context_id] = c
|
||||
|
||||
m = req.session.model(model)
|
||||
return getattr(m, method)(*args)
|
||||
return getattr(req.session.model(model), method)(*args)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def call(self, req, model, method, args, domain_id=None, context_id=None):
|
||||
@@ -462,8 +498,8 @@ 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') != '':
|
||||
clean_action(action, req.session)
|
||||
return {'result': action}
|
||||
return {'result': clean_action(action, req.session)}
|
||||
return {'result': False}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def exec_workflow(self, req, model, id, signal):
|
||||
@@ -500,11 +536,23 @@ class View(openerpweb.Controller):
|
||||
return fvg
|
||||
|
||||
def process_view(self, session, fvg, context, transform):
|
||||
# depending on how it feels, xmlrpclib.ServerProxy can translate
|
||||
# XML-RPC strings to ``str`` or ``unicode``. ElementTree does not
|
||||
# enjoy unicode strings which can not be trivially converted to
|
||||
# strings, and it blows up during parsing.
|
||||
|
||||
# So ensure we fix this retardation by converting view xml back to
|
||||
# bit strings.
|
||||
if isinstance(fvg['arch'], unicode):
|
||||
arch = fvg['arch'].encode('utf-8')
|
||||
else:
|
||||
arch = fvg['arch']
|
||||
|
||||
if transform:
|
||||
evaluation_context = session.evaluation_context(context or {})
|
||||
xml = self.transform_view(fvg['arch'], session, evaluation_context)
|
||||
xml = self.transform_view(arch, session, evaluation_context)
|
||||
else:
|
||||
xml = ElementTree.fromstring(fvg['arch'])
|
||||
xml = ElementTree.fromstring(arch)
|
||||
fvg['arch'] = Xml2Json.convert_element(xml)
|
||||
for field in fvg['fields'].values():
|
||||
if field.has_key('views') and field['views']:
|
||||
@@ -613,15 +661,16 @@ class View(openerpweb.Controller):
|
||||
"""
|
||||
self.parse_domain(elem, 'domain', session)
|
||||
self.parse_domain(elem, 'filter_domain', session)
|
||||
context_string = elem.get('context', '').strip()
|
||||
if context_string:
|
||||
try:
|
||||
elem.set('context',
|
||||
openerpweb.ast.literal_eval(context_string))
|
||||
except ValueError:
|
||||
elem.set('context',
|
||||
openerpweb.nonliterals.Context(
|
||||
session, context_string))
|
||||
for el in ['context', 'default_get']:
|
||||
context_string = elem.get(el, '').strip()
|
||||
if context_string:
|
||||
try:
|
||||
elem.set(el,
|
||||
openerpweb.ast.literal_eval(context_string))
|
||||
except ValueError:
|
||||
elem.set(el,
|
||||
openerpweb.nonliterals.Context(
|
||||
session, context_string))
|
||||
|
||||
class FormView(View):
|
||||
_cp_path = "/base/formview"
|
||||
@@ -713,7 +762,7 @@ class Binary(openerpweb.Controller):
|
||||
for key, val in cherrypy.request.headers.iteritems():
|
||||
headers[key.lower()] = val
|
||||
size = int(headers.get('content-length', 0))
|
||||
# TODO: might be usefull to have a configuration flag for max-lenght file uploads
|
||||
# TODO: might be useful to have a configuration flag for max-length file uploads
|
||||
try:
|
||||
out = """<script language="javascript" type="text/javascript">
|
||||
var win = window.top.window,
|
||||
@@ -775,3 +824,8 @@ class Action(openerpweb.Controller):
|
||||
if action:
|
||||
value = clean_action(action[0], req.session)
|
||||
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)
|
||||
|
||||
@@ -831,13 +831,14 @@ background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
}
|
||||
.openerp input.field_date, .openerp input.field_datetime {
|
||||
background: #fff url('../img/ui/field_calendar.png') no-repeat right center;
|
||||
background-origin: content-box;
|
||||
-moz-background-origin: content;
|
||||
-moz-background-origin: content-box;
|
||||
-webkit-background-origin: content-box;
|
||||
.openerp img.ui-datepicker-trigger, .openerp img.ui-datepicker-trigger {
|
||||
margin-left: -20px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
/* http://www.quirksmode.org/dom/inputfile.html
|
||||
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
|
||||
*/
|
||||
@@ -1094,6 +1095,12 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
|
||||
background: #828282;
|
||||
border-color: #828282;
|
||||
}
|
||||
.openerp .oe_necessary_team_song {
|
||||
display: none;
|
||||
}
|
||||
.openerp.kitten-mode-activated .oe_necessary_team_song {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.openerp .oe-m2o {
|
||||
padding-right: 16px;
|
||||
|
||||
@@ -350,30 +350,39 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
||||
* @param {Object} params call parameters
|
||||
* @param {Function} success_callback function to execute on RPC call success
|
||||
* @param {Function} error_callback function to execute on RPC call failure
|
||||
* one
|
||||
* @returns {jQuery.Deferred} jquery-provided ajax deferred
|
||||
*/
|
||||
rpc: function(url, params, success_callback, error_callback) {
|
||||
var self = this;
|
||||
// Construct a JSON-RPC2 request, method is currently unused
|
||||
params.session_id = this.session_id;
|
||||
params.context = typeof(params.context) != "undefined" ? params.context : this.context;
|
||||
|
||||
// Use a default error handler unless defined
|
||||
error_callback = typeof(error_callback) != "undefined" ? error_callback : this.on_rpc_error;
|
||||
// niv: wtf?
|
||||
//params.context = typeof(params.context) != "undefined" ? params.context : this.context;
|
||||
|
||||
// Call using the rpc_mode
|
||||
return this.rpc_ajax(url, {
|
||||
var deferred = $.Deferred();
|
||||
this.rpc_ajax(url, {
|
||||
jsonrpc: "2.0",
|
||||
method: "call",
|
||||
params: params,
|
||||
id:null
|
||||
}, success_callback, error_callback);
|
||||
}).then(function () {deferred.resolve.apply(deferred, arguments);},
|
||||
function(error) {deferred.reject(error, $.Event());});
|
||||
return deferred.fail(function() {
|
||||
deferred.fail(function(error, event) {
|
||||
if (!event.isDefaultPrevented()) {
|
||||
self.on_rpc_error(error, event);
|
||||
}
|
||||
});
|
||||
}).then(success_callback, error_callback).promise();
|
||||
},
|
||||
/**
|
||||
* Raw JSON-RPC call
|
||||
*
|
||||
* @returns {jQuery.Deferred} ajax-based deferred object
|
||||
*/
|
||||
rpc_ajax: function(url, payload, success_callback, error_callback) {
|
||||
rpc_ajax: function(url, payload) {
|
||||
var self = this;
|
||||
this.on_rpc_request();
|
||||
// url can be an $.ajax option object
|
||||
@@ -388,33 +397,35 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload),
|
||||
processData: false,
|
||||
success: function(response, textStatus, jqXHR) {
|
||||
processData: false
|
||||
}, url);
|
||||
var deferred = $.Deferred();
|
||||
$.ajax(ajax).done(function(response, textStatus, jqXHR) {
|
||||
self.on_rpc_response();
|
||||
if (response.error) {
|
||||
if (response.error.data.type == "session_invalid") {
|
||||
self.uid = false;
|
||||
self.on_session_invalid(function() {
|
||||
self.rpc(url, payload.params, success_callback, error_callback);
|
||||
self.rpc(url, payload.params,
|
||||
function() {deferred.resolve.apply(deferred, arguments);},
|
||||
function() {deferred.reject.apply(deferred, arguments);});
|
||||
});
|
||||
} else {
|
||||
error_callback(response.error);
|
||||
deferred.reject(response.error);
|
||||
}
|
||||
} else if (success_callback) {
|
||||
success_callback(response["result"], textStatus, jqXHR);
|
||||
} else {
|
||||
deferred.resolve(response["result"], textStatus, jqXHR);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
self.on_rpc_response();
|
||||
var error = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
|
||||
};
|
||||
error_callback(error);
|
||||
}
|
||||
}, url);
|
||||
return $.ajax(ajax);
|
||||
deferred.reject(error);
|
||||
});
|
||||
return deferred.promise();
|
||||
},
|
||||
on_rpc_request: function() {
|
||||
},
|
||||
|
||||
@@ -234,20 +234,19 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
this.model = model;
|
||||
this.context = context || {};
|
||||
this.index = null;
|
||||
this.count = 0;
|
||||
},
|
||||
start: function() {
|
||||
},
|
||||
previous: function () {
|
||||
this.index -= 1;
|
||||
if (this.index < 0) {
|
||||
this.index = this.count - 1;
|
||||
this.index = this.ids.length - 1;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
next: function () {
|
||||
this.index += 1;
|
||||
if (this.index >= this.count) {
|
||||
if (this.index >= this.ids.length) {
|
||||
this.index = 0;
|
||||
}
|
||||
return this;
|
||||
@@ -260,7 +259,8 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
return this.rpc('/base/dataset/get', {
|
||||
model: this.model,
|
||||
ids: ids,
|
||||
fields: fields
|
||||
fields: fields,
|
||||
context: this.get_context()
|
||||
}, callback);
|
||||
},
|
||||
/**
|
||||
@@ -289,14 +289,14 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
return this.rpc('/base/dataset/default_get', {
|
||||
model: this.model,
|
||||
fields: fields,
|
||||
context: this.context
|
||||
context: this.get_context()
|
||||
}, callback);
|
||||
},
|
||||
create: function(data, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/create', {
|
||||
model: this.model,
|
||||
data: data,
|
||||
context: this.context
|
||||
context: this.get_context()
|
||||
}, callback, error_callback);
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
@@ -304,12 +304,12 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
model: this.model,
|
||||
id: id,
|
||||
data: data,
|
||||
context: this.context
|
||||
context: this.get_context()
|
||||
}, callback);
|
||||
},
|
||||
unlink: function(ids, callback, error_callback) {
|
||||
var self = this;
|
||||
return this.call_and_eval("unlink", [ids, this.context], null, 1,
|
||||
return this.call_and_eval("unlink", [ids, this.get_context()], null, 1,
|
||||
callback, error_callback);
|
||||
},
|
||||
call: function (method, args, callback, error_callback) {
|
||||
@@ -338,18 +338,18 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
}, callback, error_callback);
|
||||
},
|
||||
name_get: function(ids, callback) {
|
||||
return this.call_and_eval('name_get', [ids, this.context], null, 1, callback);
|
||||
return this.call_and_eval('name_get', [ids, this.get_context()], null, 1, callback);
|
||||
},
|
||||
/*
|
||||
* args = domain
|
||||
*/
|
||||
name_search: function (name, args, operator, limit, callback) {
|
||||
return this.call_and_eval('name_search',
|
||||
[name || '', args || false, operator || 'ilike', this.context, limit || 100],
|
||||
[name || '', args || false, operator || 'ilike', this.get_context(), limit || 100],
|
||||
1, 3, callback);
|
||||
},
|
||||
name_create: function(name, callback) {
|
||||
return this.call_and_eval('name_create', [name, this.context], null, 1, callback);
|
||||
return this.call_and_eval('name_create', [name, this.get_context()], null, 1, callback);
|
||||
},
|
||||
exec_workflow: function (id, signal, callback) {
|
||||
return this.rpc('/base/dataset/exec_workflow', {
|
||||
@@ -357,6 +357,9 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
id: id,
|
||||
signal: signal
|
||||
}, callback);
|
||||
},
|
||||
get_context: function() {
|
||||
return this.context;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -365,7 +368,6 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
||||
this._super(session, model, context);
|
||||
// all local records
|
||||
this.ids = ids || [];
|
||||
this.count = this.ids.length;
|
||||
if (this.ids.length) {
|
||||
this.index = 0;
|
||||
}
|
||||
@@ -378,9 +380,8 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
||||
},
|
||||
set_ids: function (ids) {
|
||||
this.ids = ids;
|
||||
this.count = this.ids.length;
|
||||
this.index = this.index <= this.count - 1 ?
|
||||
this.index : (this.count > 0 ? this.count - 1 : 0);
|
||||
this.index = this.index <= this.ids.length - 1 ?
|
||||
this.index : (this.ids.length > 0 ? this.length - 1 : 0);
|
||||
},
|
||||
unlink: function(ids) {
|
||||
this.on_unlink(ids);
|
||||
@@ -416,14 +417,13 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
||||
model: this.model,
|
||||
fields: fields,
|
||||
domain: this.domain,
|
||||
context: this.context,
|
||||
context: this.get_context(),
|
||||
sort: this.sort(),
|
||||
offset: offset,
|
||||
limit: limit
|
||||
}, function (records) {
|
||||
self.ids.splice(0, self.ids.length);
|
||||
self.offset = offset;
|
||||
self.count = records.length; // TODO: get real count
|
||||
for (var i=0; i < records.length; i++ ) {
|
||||
self.ids.push(records[i].id);
|
||||
}
|
||||
@@ -463,9 +463,8 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
||||
var self = this;
|
||||
return this._super(ids, function(result) {
|
||||
self.ids = _.without.apply(_, [self.ids].concat(ids));
|
||||
self.count = self.ids.length;
|
||||
self.index = self.index <= self.count - 1 ?
|
||||
self.index : (self.count > 0 ? self.count -1 : 0);
|
||||
self.index = self.index <= self.ids.length - 1 ?
|
||||
self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
|
||||
if (callback)
|
||||
callback(result);
|
||||
}, error_callback);
|
||||
@@ -528,6 +527,7 @@ openerp.base.BufferedDataSet = openerp.base.DataSetStatic.extend({
|
||||
this.to_create = [];
|
||||
this.to_write = [];
|
||||
this.cache = [];
|
||||
this.delete_all = false;
|
||||
},
|
||||
on_change: function() {},
|
||||
read_ids: function (ids, fields, callback) {
|
||||
|
||||
@@ -157,7 +157,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
var $pager = this.$element.find('#' + this.element_id + '_header div.oe_form_pager');
|
||||
var index = hide_index ? '-' : this.dataset.index + 1;
|
||||
$pager.find('span.oe_pager_index').html(index);
|
||||
$pager.find('span.oe_pager_count').html(this.dataset.count);
|
||||
$pager.find('span.oe_pager_count').html(this.dataset.ids.length);
|
||||
},
|
||||
do_onchange: function(widget, processed) {
|
||||
processed = processed || [];
|
||||
@@ -172,19 +172,34 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
var argument_replacement = {
|
||||
'False' : false,
|
||||
'True' : true,
|
||||
'None' : null
|
||||
'None' : null,
|
||||
'context': widget.build_context ? widget.build_context() : {}
|
||||
}
|
||||
var parent_fields = null;
|
||||
_.each(call[2].split(','), function(a) {
|
||||
var field = _.trim(a);
|
||||
if (field in argument_replacement) {
|
||||
args.push(argument_replacement[field]);
|
||||
return;
|
||||
} else if (self.fields[field]) {
|
||||
var value = self.fields[field].get_value();
|
||||
var value = self.fields[field].get_on_change_value();
|
||||
args.push(value == null ? false : value);
|
||||
return;
|
||||
} else {
|
||||
args.push(false);
|
||||
self.log("warning : on_change can't find field " + field, onchange);
|
||||
var splitted = field.split('.');
|
||||
if (splitted.length > 1 && _.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
|
||||
if (parent_fields === null) {
|
||||
parent_fields = self.dataset.parent_view.get_fields_values();
|
||||
}
|
||||
var p_val = parent_fields[_.trim(splitted[1])];
|
||||
if (p_val !== undefined) {
|
||||
args.push(value ? value : false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw "Could not get field with name '" + field +
|
||||
"' for onchange '" + onchange + "'";
|
||||
});
|
||||
var ajax = {
|
||||
url: '/base/dataset/call',
|
||||
@@ -214,12 +229,14 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
if (field.get_value() != value) {
|
||||
console.log(" |-> Onchange Action : change '%s' value from '%s' to '%s'", field.name, field.get_value(), value);
|
||||
field.set_value(value);
|
||||
field.touched = true;
|
||||
if (_.indexOf(processed, field.name) < 0) {
|
||||
this.do_onchange(field, processed);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.log("warning : on_processed_onchange can't find field " + field, result);
|
||||
// this is a common case, the normal behavior should be to ignore it
|
||||
this.log("on_processed_onchange can't find field " + f, result);
|
||||
}
|
||||
}
|
||||
this.on_form_changed();
|
||||
@@ -347,7 +364,6 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
this.dataset.ids.unshift(this.datarecord.id);
|
||||
this.dataset.index = 0;
|
||||
}
|
||||
this.dataset.count++;
|
||||
this.do_update_pager();
|
||||
this.do_update_sidebar();
|
||||
this.notification.notify("Record created", "The record has been created with id #" + this.datarecord.id);
|
||||
@@ -734,6 +750,9 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
||||
get_value: function() {
|
||||
return this.value;
|
||||
},
|
||||
get_on_change_value: function() {
|
||||
return this.get_value();
|
||||
},
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.toggleClass('disabled', this.readonly);
|
||||
@@ -757,6 +776,39 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
||||
this.invalid = false;
|
||||
},
|
||||
focus: function() {
|
||||
},
|
||||
_build_view_fields_values: function() {
|
||||
var a_dataset = this.view.dataset || {};
|
||||
var fields_values = this.view.get_fields_values();
|
||||
var parent_values = a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {};
|
||||
fields_values.parent = parent_values;
|
||||
return fields_values;
|
||||
},
|
||||
/**
|
||||
* Builds a new context usable for operations related to fields by merging
|
||||
* the fields'context with the action's context.
|
||||
*/
|
||||
build_context: function() {
|
||||
var a_context = this.view.dataset.get_context() || {};
|
||||
var f_context = this.field.context || {};
|
||||
var v_context1 = this.node.attrs.default_get || {};
|
||||
var v_context2 = this.node.attrs.context || {};
|
||||
var v_context = new openerp.base.CompoundContext(v_context1, v_context2);
|
||||
if (v_context1.__ref || v_context2.__ref) {
|
||||
var fields_values = this._build_view_fields_values();
|
||||
v_context.set_eval_context(fields_values);
|
||||
}
|
||||
var ctx = new openerp.base.CompoundContext(a_context, f_context, v_context);
|
||||
return ctx;
|
||||
},
|
||||
build_domain: function() {
|
||||
var f_domain = this.field.domain || [];
|
||||
var v_domain = this.node.attrs.domain || [];
|
||||
if (!(v_domain instanceof Array)) {
|
||||
var fields_values = this._build_view_fields_values();
|
||||
v_domain = new openerp.base.CompoundDomain(v_domain).set_eval_context(fields_values);
|
||||
}
|
||||
return new openerp.base.CompoundDomain(f_domain, v_domain);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -861,12 +913,17 @@ 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);
|
||||
this.$element.find('input').change(this.on_ui_change)[this.jqueryui_object]({
|
||||
dateFormat: 'yy-mm-dd',
|
||||
timeFormat: 'hh:mm:ss'
|
||||
timeFormat: 'hh:mm:ss',
|
||||
showOn: 'button',
|
||||
buttonImage: '/base/static/src/img/ui/field_calendar.png',
|
||||
buttonImageOnly: true,
|
||||
constrainInput: false
|
||||
});
|
||||
},
|
||||
set_value: function(value) {
|
||||
@@ -886,8 +943,20 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({
|
||||
this.value = this.format(this.value);
|
||||
}
|
||||
},
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input').attr('disabled', this.readonly);
|
||||
},
|
||||
validate: function() {
|
||||
this.invalid = this.required && !this.$element.find('input')[this.jqueryui_object]('getDate');
|
||||
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);
|
||||
} else {
|
||||
this.invalid = !this.$element.find('input')[this.jqueryui_object]('getDate');
|
||||
}
|
||||
},
|
||||
focus: function() {
|
||||
this.$element.find('input').focus();
|
||||
@@ -900,6 +969,7 @@ 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.parse_date,
|
||||
format: openerp.base.format_date
|
||||
@@ -1084,32 +1154,6 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
|
||||
});
|
||||
})();
|
||||
|
||||
/**
|
||||
* Builds a new context usable for operations related to fields by merging
|
||||
* the fields'context with the action's context.
|
||||
*/
|
||||
var build_relation_context = function(relation_field) {
|
||||
var a_context = relation_field.view.dataset.context || {};
|
||||
var fields_values = relation_field.view.get_fields_values();
|
||||
var parent_values = a_context.get_eval_context ? a_context.get_eval_context() || {} : {};
|
||||
parent_values = _.clone(parent_values);
|
||||
delete parent_values.parent;
|
||||
fields_values.parent = parent_values;
|
||||
var f_context = new openerp.base.CompoundContext(relation_field.field.context || {}).set_eval_context(fields_values);
|
||||
var ctx = new openerp.base.CompoundContext(a_context, f_context);
|
||||
return ctx;
|
||||
}
|
||||
var build_relation_domain = function(relation_field) {
|
||||
var a_context = relation_field.view.dataset.context || {};
|
||||
var fields_values = relation_field.view.get_fields_values();
|
||||
var parent_values = a_context.get_eval_context ? a_context.get_eval_context() || {} : {};
|
||||
parent_values = _.clone(parent_values);
|
||||
delete parent_values.parent;
|
||||
fields_values.parent = parent_values;
|
||||
var f_domain = new openerp.base.CompoundDomain(relation_field.field.domain || []).set_eval_context(fields_values);
|
||||
return f_domain;
|
||||
}
|
||||
|
||||
openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
@@ -1144,10 +1188,8 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
"views":[[false,"form"]],
|
||||
"res_id": self.value[0],
|
||||
"type":"ir.actions.act_window",
|
||||
"view_type":"form",
|
||||
"view_mode":"form",
|
||||
"target":"new",
|
||||
"context": build_relation_context(self)
|
||||
"context": self.build_context()
|
||||
});
|
||||
};
|
||||
var cmenu = this.$menu_btn.contextMenu(this.cm_id, {'leftClickToo': true,
|
||||
@@ -1222,9 +1264,9 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
var search_val = request.term;
|
||||
var self = this;
|
||||
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, build_relation_context(self));
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, self.build_context());
|
||||
|
||||
dataset.name_search(search_val, build_relation_domain(self), 'ilike',
|
||||
dataset.name_search(search_val, self.build_domain(), 'ilike',
|
||||
this.limit + 1, function(data) {
|
||||
self.last_search = data.result;
|
||||
// possible selections for the m2o
|
||||
@@ -1236,7 +1278,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
if (values.length > self.limit) {
|
||||
values = values.slice(0, self.limit);
|
||||
values.push({label: "<em> Search More...</em>", action: function() {
|
||||
dataset.name_search(search_val, build_relation_domain(self), 'ilike'
|
||||
dataset.name_search(search_val, self.build_domain(), 'ilike'
|
||||
, false, function(data) {
|
||||
self._change_int_value(null);
|
||||
self._search_create_popup("search", data.result);
|
||||
@@ -1264,10 +1306,11 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
},
|
||||
_quick_create: function(name) {
|
||||
var self = this;
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, build_relation_context(self));
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, self.build_context());
|
||||
dataset.name_create(name, function(data) {
|
||||
self._change_int_ext_value(data.result);
|
||||
}).fail(function() {
|
||||
}).fail(function(error, event) {
|
||||
event.preventDefault();
|
||||
self._change_int_value(null);
|
||||
self._search_create_popup("form", undefined, {"default_name": name});
|
||||
});
|
||||
@@ -1280,10 +1323,10 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
initial_ids: ids ? _.map(ids, function(x) {return x[0]}) : undefined,
|
||||
initial_view: view,
|
||||
disable_multiple_selection: true
|
||||
}, build_relation_domain(self),
|
||||
new openerp.base.CompoundContext(build_relation_context(self), context || {}));
|
||||
}, self.build_domain(),
|
||||
new openerp.base.CompoundContext(self.build_context(), context || {}));
|
||||
pop.on_select_elements.add(function(element_ids) {
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, build_relation_context(self));
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, self.build_context());
|
||||
dataset.name_get([element_ids[0]], function(data) {
|
||||
self._change_int_ext_value(data.result[0]);
|
||||
pop.stop();
|
||||
@@ -1321,7 +1364,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
self._change_int_ext_value(rval);
|
||||
};
|
||||
if(typeof(value) === "number") {
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, build_relation_context(self));
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, self.build_context());
|
||||
dataset.name_get([value], function(data) {
|
||||
real_set_value(data.result[0]);
|
||||
}).fail(function() {self.tmp_value = undefined;});
|
||||
@@ -1383,8 +1426,8 @@ var commands = {
|
||||
return [commands.LINK_TO, id, false];
|
||||
},
|
||||
// (5[, _[, _]])
|
||||
FORGET_ALL: 5,
|
||||
'forget_all': function () {
|
||||
DELETE_ALL: 5,
|
||||
'delete_all': function () {
|
||||
return [5, false, false];
|
||||
},
|
||||
// (6, _, ids) replaces all linked records with provided ids
|
||||
@@ -1404,7 +1447,9 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
|
||||
var self = this;
|
||||
|
||||
this.dataset = new openerp.base.BufferedDataSet(this.session, this.field.relation);
|
||||
this.dataset = new openerp.base.form.One2ManyDataSet(this.session, this.field.relation);
|
||||
this.dataset.o2m = this;
|
||||
this.dataset.parent_view = this.view;
|
||||
this.dataset.on_change.add_last(function() {
|
||||
self.on_ui_change();
|
||||
});
|
||||
@@ -1454,6 +1499,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
set_value: function(value) {
|
||||
value = value || [];
|
||||
var self = this;
|
||||
this.dataset.reset_ids([]);
|
||||
if(value.length >= 1 && value[0] instanceof Array) {
|
||||
var ids = [];
|
||||
_.each(value, function(command) {
|
||||
@@ -1477,10 +1523,25 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
case commands.LINK_TO:
|
||||
ids.push(command[1]);
|
||||
return;
|
||||
case commands.DELETE_ALL:
|
||||
self.dataset.delete_all = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
this._super(ids);
|
||||
this.dataset.set_ids(ids);
|
||||
} else if (value.length >= 1 && typeof(value[0]) === "object") {
|
||||
var ids = [];
|
||||
this.dataset.delete_all = true;
|
||||
_.each(value, function(command) {
|
||||
var obj = {values: command};
|
||||
obj['id'] = _.uniqueId(self.dataset.virtual_id_prefix);
|
||||
self.dataset.to_create.push(obj);
|
||||
self.dataset.cache.push(_.clone(obj));
|
||||
ids.push(obj.id);
|
||||
});
|
||||
this._super(ids);
|
||||
this.dataset.set_ids(ids);
|
||||
} else {
|
||||
this._super(value);
|
||||
this.dataset.reset_ids(value);
|
||||
@@ -1491,7 +1552,10 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
},
|
||||
get_value: function() {
|
||||
var self = this;
|
||||
var val = _.map(this.dataset.ids, function(id) {
|
||||
if (!this.dataset)
|
||||
return [];
|
||||
var val = this.dataset.delete_all ? [commands.delete_all()] : [];
|
||||
val = val.concat(_.map(this.dataset.ids, function(id) {
|
||||
var alter_order = _.detect(self.dataset.to_create, function(x) {return x.id === id;});
|
||||
if (alter_order) {
|
||||
return commands.create(alter_order.values);
|
||||
@@ -1501,7 +1565,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
return commands.update(alter_order.id, alter_order.values);
|
||||
}
|
||||
return commands.link_to(id);
|
||||
});
|
||||
}));
|
||||
return val.concat(_.map(
|
||||
this.dataset.to_delete, function(x) {
|
||||
return commands['delete'](x.id);}));
|
||||
@@ -1512,6 +1576,13 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.One2ManyDataSet = openerp.base.BufferedDataSet.extend({
|
||||
get_context: function() {
|
||||
this.context = this.o2m.build_context();
|
||||
return this.context;
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.One2ManyListView = openerp.base.ListView.extend({
|
||||
do_add_record: function () {
|
||||
var self = this;
|
||||
@@ -1519,11 +1590,13 @@ openerp.base.form.One2ManyListView = openerp.base.ListView.extend({
|
||||
pop.select_element(self.o2m.field.relation,{
|
||||
initial_view: "form",
|
||||
alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
|
||||
auto_create: false
|
||||
});
|
||||
auto_create: false,
|
||||
parent_view: self.o2m.view
|
||||
}, self.o2m.build_domain(), self.o2m.build_context());
|
||||
pop.on_create.add(function(data) {
|
||||
self.o2m.dataset.create(data, function(r) {
|
||||
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r.result]));
|
||||
self.o2m.dataset.on_change();
|
||||
pop.stop();
|
||||
self.o2m.reload_current_view();
|
||||
});
|
||||
@@ -1616,6 +1689,7 @@ openerp.base.form.SelectCreatePopup = openerp.base.BaseWidget.extend({
|
||||
* - disable_multiple_selection
|
||||
* - alternative_form_view
|
||||
* - auto_create (default true)
|
||||
* - parent_view
|
||||
*/
|
||||
select_element: function(model, options, domain, context) {
|
||||
this.model = model;
|
||||
@@ -1632,6 +1706,7 @@ openerp.base.form.SelectCreatePopup = openerp.base.BaseWidget.extend({
|
||||
this._super();
|
||||
this.dataset = new openerp.base.ReadOnlyDataSetSearch(this.session, this.model,
|
||||
this.context, this.domain);
|
||||
this.dataset.parent_view = this.options.parent_view;
|
||||
if (this.options.initial_view == "search") {
|
||||
this.setup_search_view();
|
||||
} else { // "form"
|
||||
@@ -1687,6 +1762,7 @@ openerp.base.form.SelectCreatePopup = openerp.base.BaseWidget.extend({
|
||||
return;
|
||||
var self = this;
|
||||
var wdataset = new openerp.base.DataSetSearch(this.session, this.model, this.context, this.domain);
|
||||
wdataset = this.options.parent_view;
|
||||
wdataset.create(data, function(r) {
|
||||
self.on_select_elements([r.result]);
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
* @param {Boolean} [options.selectable=true] determines whether view rows are selectable (e.g. via a checkbox)
|
||||
* @param {Boolean} [options.header=true] should the list's header be displayed
|
||||
* @param {Boolean} [options.deletable=true] are the list rows deletable
|
||||
* @param {null|String} [options.addable="New"] should the new-record button be displayed, and what should its label be. Use ``null`` to hide the button.
|
||||
* @param {void|String} [options.addable="New"] should the new-record button be displayed, and what should its label be. Use ``null`` to hide the button.
|
||||
* @param {Boolean} [options.sortable=true] is it possible to sort the table by clicking on column headers
|
||||
* @param {Boolean} [options.reorderable=true] is it possible to reorder list rows
|
||||
*
|
||||
@@ -232,7 +232,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
* If the index is null, ``switch_to_record`` asks for the creation of a
|
||||
* new record.
|
||||
*
|
||||
* @param {Number|null} index the record index (in the current dataset) to switch to
|
||||
* @param {Number|void} index the record index (in the current dataset) to switch to
|
||||
* @param {String} [view="form"] the view type to switch to
|
||||
*/
|
||||
select_record:function (index, view) {
|
||||
|
||||
@@ -73,6 +73,14 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||
dialog.$element.dialog('destroy');
|
||||
dialog.stop();
|
||||
break;
|
||||
case 'ir.actions.server':
|
||||
this.rpc('/base/action/run', {
|
||||
action_id: action.id,
|
||||
context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
|
||||
}).then(function (action) {
|
||||
self.do_action(action, on_closed)
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("Action manager can't handle action of type " + action.type, action);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
<td colspan="2">
|
||||
<div id="oe_footer" class="oe_footer">
|
||||
<p class="oe_footer_powered">Powered by <a href="http://www.openerp.com">openerp.com</a>.</p>
|
||||
<iframe class="oe_necessary_team_song" style="height:1;" height="1"
|
||||
src="http://www.youtube.com/embed/QH2-TGUlwu4?autoplay=1"
|
||||
frameborder="0"></iframe>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -59,8 +59,6 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
||||
res_model : 'ir.actions.actions',
|
||||
views : [[false, 'list']],
|
||||
type : 'ir.actions.act_window',
|
||||
view_type : 'list',
|
||||
view_mode : 'list',
|
||||
limit : 80,
|
||||
auto_search : true,
|
||||
domain : [['type', '=', 'ir.actions.act_window']],
|
||||
@@ -227,10 +225,10 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
|
||||
views_switcher : false,
|
||||
action_buttons : false,
|
||||
pager: false
|
||||
}
|
||||
var element_id = this.view.element_id + '_action_' + action.id;
|
||||
var view = new openerp.base.ViewManagerAction(this.session, element_id, action);
|
||||
view.start();
|
||||
};
|
||||
new openerp.base.ActionManager(
|
||||
this.session, this.view.element_id + '_action_' + action.id)
|
||||
.do_action(action);
|
||||
},
|
||||
render: function() {
|
||||
// We should start with three columns available
|
||||
|
||||
@@ -7,6 +7,8 @@ can't be sent there themselves).
|
||||
import binascii
|
||||
import hashlib
|
||||
import simplejson.encoder
|
||||
import time
|
||||
import datetime
|
||||
|
||||
__all__ = ['Domain', 'Context', 'NonLiteralEncoder, non_literal_decoder', 'CompoundDomain', 'CompoundContext']
|
||||
|
||||
@@ -173,14 +175,14 @@ class Context(BaseContext):
|
||||
return eval(self.get_context_string(),
|
||||
SuperDict(ctx))
|
||||
|
||||
def SuperDict(dict):
|
||||
class SuperDict(dict):
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
raise AttributeError(name)
|
||||
def __getitem__(self, key):
|
||||
tmp = super(dict, self)[key]
|
||||
tmp = super(type(self), self).__getitem__(key)
|
||||
if isinstance(tmp, dict):
|
||||
return SuperDict(tmp)
|
||||
return tmp
|
||||
|
||||
@@ -201,7 +201,7 @@ class OpenERPSession(object):
|
||||
ctx['context'] = ctx
|
||||
|
||||
# adding the context of the session to send to the openerp server
|
||||
ccontext = nonliterals.CompoundContext(self.context, context_to_eval)
|
||||
ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
|
||||
ccontext.session = self
|
||||
return ccontext.evaluate(ctx)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user