[MERGE] Sync with trunk
bzr revid: tde@openerp.com-20130725135118-urwxu1ilv1m6ljwh
This commit is contained in:
commit
7f0824e762
34
.bzrignore
34
.bzrignore
|
@ -1,21 +1,15 @@
|
|||
.*.swp
|
||||
.bzrignore
|
||||
.idea
|
||||
.project
|
||||
.pydevproject
|
||||
.ropeproject
|
||||
.settings
|
||||
.DS_Store
|
||||
openerp/addons/*
|
||||
openerp/filestore*
|
||||
.Python
|
||||
*.pyc
|
||||
*.pyo
|
||||
bin/*
|
||||
.*
|
||||
*.egg-info
|
||||
*.orig
|
||||
*.vim
|
||||
build/
|
||||
include/
|
||||
lib/
|
||||
share/
|
||||
doc/_build/*
|
||||
win32/*.bat
|
||||
win32/meta.py
|
||||
RE:^bin/
|
||||
RE:^dist/
|
||||
RE:^include/
|
||||
|
||||
RE:^share/
|
||||
RE:^man/
|
||||
RE:^lib/
|
||||
|
||||
RE:^addons/\w+/doc/_build/
|
||||
RE:^.*?/node_modules
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
src: ['static/src/**/*.js', 'static/test/**/*.js'],
|
||||
options: {
|
||||
sub: true, //[] instead of .
|
||||
evil: true, //eval
|
||||
laxbreak: true, //unsafe line breaks
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
|
||||
grunt.registerTask('test', ['jshint']);
|
||||
|
||||
grunt.registerTask('default', ['jshint']);
|
||||
|
||||
};
|
|
@ -88,9 +88,6 @@ def rjsmin(script):
|
|||
|
||||
db_list = http.db_list
|
||||
|
||||
def db_monodb_redirect():
|
||||
return http.db_redirect(not config['list_db'])
|
||||
|
||||
db_monodb = http.db_monodb
|
||||
|
||||
def redirect_with_hash(url, code=303):
|
||||
|
@ -296,13 +293,13 @@ def manifest_glob(extension, addons=None, db=None, include_remotes=False):
|
|||
r.append((path, fs2web(path[len(addons_path):])))
|
||||
return r
|
||||
|
||||
def manifest_list(extension, mods=None, db=None):
|
||||
def manifest_list(extension, mods=None, db=None, debug=False):
|
||||
""" list ressources to load specifying either:
|
||||
mods: a comma separated string listing modules
|
||||
db: a database name (return all installed modules in that database)
|
||||
"""
|
||||
files = manifest_glob(extension, addons=mods, db=db, include_remotes=True)
|
||||
if not request.debug:
|
||||
if not debug:
|
||||
path = '/web/webclient/' + extension
|
||||
if mods is not None:
|
||||
path += '?' + urllib.urlencode({'mods': mods})
|
||||
|
@ -535,13 +532,24 @@ html_template = """<!DOCTYPE html>
|
|||
class Home(http.Controller):
|
||||
|
||||
@http.route('/', type='http', auth="none")
|
||||
def index(self, s_action=None, db=None, **kw):
|
||||
db, redir = db_monodb_redirect()
|
||||
if redir:
|
||||
return redirect_with_hash(redir)
|
||||
def index(self, s_action=None, db=None, debug=False, **kw):
|
||||
debug = debug != False
|
||||
if db is not None:
|
||||
lst = http.db_list(True)
|
||||
if db in lst and db != request.session.db:
|
||||
request.session.logout()
|
||||
request.session.db = db
|
||||
|
||||
js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list('js', db=db))
|
||||
css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list('css', db=db))
|
||||
if db != request.session.db:
|
||||
query = dict(urlparse.parse_qsl(request.httprequest.query_string, keep_blank_values=True))
|
||||
query.update({'db': request.session.db})
|
||||
redirect = request.httprequest.path + '?' + urllib.urlencode(query)
|
||||
return redirect_with_hash(redirect)
|
||||
|
||||
db = request.session.db
|
||||
|
||||
js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list('js', db=db, debug=debug))
|
||||
css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list('css', db=db, debug=debug))
|
||||
|
||||
r = html_template % {
|
||||
'js': js,
|
||||
|
@ -549,7 +557,7 @@ class Home(http.Controller):
|
|||
'modules': simplejson.dumps(module_boot(db=db)),
|
||||
'init': 'var wc = new s.web.WebClient();wc.appendTo($(document.body));'
|
||||
}
|
||||
return r
|
||||
return request.make_response(r, {'Cache-Control': 'no-cache', 'Content-Type': 'text/html; charset=utf-8'})
|
||||
|
||||
@http.route('/login', type='http', auth="user")
|
||||
def login(self, db, login, key):
|
||||
|
@ -819,7 +827,7 @@ class Session(http.Controller):
|
|||
@http.route('/web/session/get_session_info', type='json', auth="none")
|
||||
def get_session_info(self):
|
||||
request.uid = request.session.uid
|
||||
request.db = request.session.db
|
||||
request.disable_db = False
|
||||
return self.session_info()
|
||||
|
||||
@http.route('/web/session/authenticate', type='json', auth="none")
|
||||
|
|
|
@ -85,10 +85,6 @@ class WebRequest(object):
|
|||
|
||||
:class:`~collections.Mapping` of context values for the current request
|
||||
|
||||
.. attribute:: debug
|
||||
|
||||
``bool``, indicates whether the debug mode is active on the client
|
||||
|
||||
.. attribute:: db
|
||||
|
||||
``str``, the name of the database linked to the current request. Can be ``None``
|
||||
|
@ -105,16 +101,13 @@ class WebRequest(object):
|
|||
self.httpsession = httprequest.session
|
||||
self.session = httprequest.session
|
||||
self.session_id = httprequest.session.sid
|
||||
self.db = None
|
||||
self.disable_db = False
|
||||
self.uid = None
|
||||
self.func = None
|
||||
self.auth_method = None
|
||||
self._cr_cm = None
|
||||
self._cr = None
|
||||
self.func_request_type = None
|
||||
self.debug = self.httprequest.args.get('debug', False) is not False
|
||||
with set_request(self):
|
||||
self.db = self.session.db or db_monodb()
|
||||
# set db/uid trackers - they're cleaned up at the WSGI
|
||||
# dispatching phase in openerp.service.wsgi_server.application
|
||||
if self.db:
|
||||
|
@ -132,17 +125,16 @@ class WebRequest(object):
|
|||
self.session.logout()
|
||||
raise SessionExpiredException("Session expired for request %s" % self.httprequest)
|
||||
if self.auth_method == "none":
|
||||
self.db = None
|
||||
self.disable_db = True
|
||||
self.uid = None
|
||||
elif self.auth_method == "admin":
|
||||
self.db = self.session.db or db_monodb()
|
||||
self.disable_db = False
|
||||
if not self.db:
|
||||
raise SessionExpiredException("No valid database for request %s" % self.httprequest)
|
||||
self.uid = openerp.SUPERUSER_ID
|
||||
else: # auth
|
||||
self.db = self.session.db
|
||||
self.disable_db = False
|
||||
self.uid = self.session.uid
|
||||
|
||||
@property
|
||||
def registry(self):
|
||||
"""
|
||||
|
@ -151,6 +143,14 @@ class WebRequest(object):
|
|||
"""
|
||||
return openerp.modules.registry.RegistryManager.get(self.db) if self.db else None
|
||||
|
||||
@property
|
||||
def db(self):
|
||||
"""
|
||||
The registry to the database linked to this request. Can be ``None`` if the current request uses the
|
||||
``none'' authentication.
|
||||
"""
|
||||
return self.session.db if not self.disable_db else None
|
||||
|
||||
@property
|
||||
def cr(self):
|
||||
"""
|
||||
|
@ -184,7 +184,7 @@ class WebRequest(object):
|
|||
return self.func(*args, **kwargs)
|
||||
finally:
|
||||
# just to be sure no one tries to re-use the request
|
||||
self.db = None
|
||||
self.disable_db = True
|
||||
self.uid = None
|
||||
|
||||
def route(route, type="http", auth="user"):
|
||||
|
@ -304,8 +304,6 @@ class JsonRequest(WebRequest):
|
|||
error = None
|
||||
|
||||
try:
|
||||
#if _logger.isEnabledFor(logging.DEBUG):
|
||||
# _logger.debug("--> %s.%s\n%s", func.im_class.__name__, func.__name__, pprint.pformat(self.jsonrequest))
|
||||
response['id'] = self.jsonrequest.get('id')
|
||||
response["result"] = self._call_function(**self.params)
|
||||
except AuthenticationError, e:
|
||||
|
@ -327,9 +325,6 @@ class JsonRequest(WebRequest):
|
|||
if error:
|
||||
response["error"] = error
|
||||
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug("<--\n%s", pprint.pformat(response))
|
||||
|
||||
if self.jsonp:
|
||||
# If we use jsonp, that's mean we are called from another host
|
||||
# Some browser (IE and Safari) do no allow third party cookies
|
||||
|
@ -394,7 +389,7 @@ class HttpRequest(WebRequest):
|
|||
def __init__(self, *args):
|
||||
super(HttpRequest, self).__init__(*args)
|
||||
params = dict(self.httprequest.args)
|
||||
ex = set(["session_id", "debug"])
|
||||
ex = set(["session_id"])
|
||||
for k in params.keys():
|
||||
if k in ex:
|
||||
del params[k]
|
||||
|
@ -409,7 +404,6 @@ class HttpRequest(WebRequest):
|
|||
akw[key] = value
|
||||
else:
|
||||
akw[key] = type(value)
|
||||
#_logger.debug("%s --> %s.%s %r", self.httprequest.func, func.im_class.__name__, func.__name__, akw)
|
||||
try:
|
||||
r = self._call_function(**self.params)
|
||||
except werkzeug.exceptions.HTTPException, e:
|
||||
|
@ -426,10 +420,6 @@ class HttpRequest(WebRequest):
|
|||
else:
|
||||
if not r:
|
||||
r = werkzeug.wrappers.Response(status=204) # no content
|
||||
if isinstance(r, (werkzeug.wrappers.BaseResponse, werkzeug.exceptions.HTTPException)):
|
||||
_logger.debug('<-- %s', r)
|
||||
else:
|
||||
_logger.debug("<-- size: %s", len(r))
|
||||
return r
|
||||
|
||||
def make_response(self, data, headers=None, cookies=None):
|
||||
|
@ -626,8 +616,8 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
|
|||
self.uid = uid
|
||||
self.login = login
|
||||
self.password = password
|
||||
request.db = db
|
||||
request.uid = uid
|
||||
request.disable_db = False
|
||||
|
||||
if uid: self.get_context()
|
||||
return uid
|
||||
|
@ -900,6 +890,8 @@ class Root(object):
|
|||
else:
|
||||
httprequest.session = self.session_store.get(sid)
|
||||
|
||||
self._find_db(httprequest)
|
||||
|
||||
if not "lang" in httprequest.session.context:
|
||||
lang = httprequest.accept_languages.best or "en_US"
|
||||
lang = babel.core.LOCALE_ALIASES.get(lang, lang).replace('-', '_')
|
||||
|
@ -936,6 +928,12 @@ class Root(object):
|
|||
except werkzeug.exceptions.HTTPException, e:
|
||||
return e(environ, start_response)
|
||||
|
||||
def _find_db(self, httprequest):
|
||||
db = db_monodb(httprequest)
|
||||
if db != httprequest.session.db:
|
||||
httprequest.session.logout()
|
||||
httprequest.session.db = db
|
||||
|
||||
def _build_request(self, httprequest):
|
||||
if httprequest.args.get('jsonp'):
|
||||
return JsonRequest(httprequest)
|
||||
|
@ -1050,43 +1048,16 @@ class Root(object):
|
|||
|
||||
root = None
|
||||
|
||||
def db_list(force=False):
|
||||
proxy = request.session.proxy("db")
|
||||
dbs = proxy.list(force)
|
||||
h = request.httprequest.environ['HTTP_HOST'].split(':')[0]
|
||||
def db_list(force=False, httprequest=None):
|
||||
httprequest = httprequest or request.httprequest
|
||||
dbs = openerp.netsvc.dispatch_rpc("db", "list", [force])
|
||||
h = httprequest.environ['HTTP_HOST'].split(':')[0]
|
||||
d = h.split('.')[0]
|
||||
r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
|
||||
dbs = [i for i in dbs if re.match(r, i)]
|
||||
return dbs
|
||||
|
||||
def db_redirect(match_first_only_if_unique):
|
||||
db = None
|
||||
redirect = None
|
||||
|
||||
dbs = db_list(True)
|
||||
|
||||
# 1 try the db in the url
|
||||
db_url = request.httprequest.args.get('db')
|
||||
if db_url in dbs:
|
||||
return (db_url, None)
|
||||
|
||||
# 2 use the database from the cookie if it's listable and still listed
|
||||
cookie_db = request.httprequest.cookies.get('last_used_database')
|
||||
if cookie_db in dbs:
|
||||
db = cookie_db
|
||||
|
||||
# 3 use the first db if user can list databases
|
||||
if dbs and not db and (not match_first_only_if_unique or len(dbs) == 1):
|
||||
db = dbs[0]
|
||||
|
||||
# redirect to the chosen db if multiple are available
|
||||
if db and len(dbs) > 1:
|
||||
query = dict(urlparse.parse_qsl(request.httprequest.query_string, keep_blank_values=True))
|
||||
query.update({'db': db})
|
||||
redirect = request.httprequest.path + '?' + urllib.urlencode(query)
|
||||
return (db, redirect)
|
||||
|
||||
def db_monodb():
|
||||
def db_monodb(httprequest=None):
|
||||
"""
|
||||
Magic function to find the current database.
|
||||
|
||||
|
@ -1095,10 +1066,27 @@ def db_monodb():
|
|||
* Magic
|
||||
* More magic
|
||||
|
||||
Return ``None`` if the magic is not magic enough.
|
||||
Returns ``None`` if the magic is not magic enough.
|
||||
"""
|
||||
return db_redirect(True)[0]
|
||||
httprequest = httprequest or request.httprequest
|
||||
db = None
|
||||
redirect = None
|
||||
|
||||
dbs = db_list(True, httprequest)
|
||||
|
||||
# 1 try the db already in the session
|
||||
db_session = httprequest.session.db
|
||||
if db_session in dbs:
|
||||
return db_session
|
||||
|
||||
# 2 if there is only one db in the db filters, take it
|
||||
if len(dbs) == 1:
|
||||
return dbs[0]
|
||||
|
||||
# 3 if there are multiple dbs, take the first one only if we can list them
|
||||
if len(dbs) > 1 and config['list_db']:
|
||||
return dbs[0]
|
||||
return None
|
||||
|
||||
class CommonController(Controller):
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-contrib-jshint": "~0.6.0"
|
||||
}
|
||||
}
|
|
@ -438,7 +438,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
|
|||
self.$el.html(QWeb.render("DatabaseManager", { widget : self }));
|
||||
$('.oe_user_menu_placeholder').append(QWeb.render("DatabaseManager.user_menu",{ widget : self }));
|
||||
$('.oe_secondary_menus_container').append(QWeb.render("DatabaseManager.menu",{ widget : self }));
|
||||
$('ul.oe_secondary_submenu > li:first').addClass('oe_active')
|
||||
$('ul.oe_secondary_submenu > li:first').addClass('oe_active');
|
||||
$('ul.oe_secondary_submenu > li').bind('click', function (event) {
|
||||
var menuitem = $(this);
|
||||
menuitem.addClass('oe_active').siblings().removeClass('oe_active');
|
||||
|
@ -705,20 +705,9 @@ instance.web.Login = instance.web.Widget.extend({
|
|||
}
|
||||
return d;
|
||||
},
|
||||
remember_last_used_database: function(db) {
|
||||
// This cookie will be used server side in order to avoid db reloading on first visit
|
||||
var ttl = 24 * 60 * 60 * 365;
|
||||
document.cookie = [
|
||||
'last_used_database=' + db,
|
||||
'path=/',
|
||||
'max-age=' + ttl,
|
||||
'expires=' + new Date(new Date().getTime() + ttl * 1000).toGMTString()
|
||||
].join(';');
|
||||
},
|
||||
database_selected: function(db) {
|
||||
var params = $.deparam.querystring();
|
||||
params.db = db;
|
||||
this.remember_last_used_database(db);
|
||||
this.$('.oe_login_dbpane').empty().text(_t('Loading...'));
|
||||
this.$('[name=login], [name=password]').prop('readonly', true);
|
||||
instance.web.redirect('/?' + $.param(params));
|
||||
|
@ -769,7 +758,6 @@ instance.web.Login = instance.web.Widget.extend({
|
|||
self.hide_error();
|
||||
self.$(".oe_login_pane").fadeOut("slow");
|
||||
return this.session.session_authenticate(db, login, password).then(function() {
|
||||
self.remember_last_used_database(db);
|
||||
if (self.has_local_storage && self.remember_credentials) {
|
||||
localStorage.setItem(db + '|last_login', login);
|
||||
if (self.session.debug) {
|
||||
|
@ -804,10 +792,17 @@ instance.web.redirect = function(url, wait) {
|
|||
instance.client.crashmanager.active = false;
|
||||
}
|
||||
|
||||
var wait_server = function() {
|
||||
instance.session.rpc("/web/webclient/version_info", {}).done(function() {
|
||||
var load = function() {
|
||||
var old = "" + window.location;
|
||||
if (old === url) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
window.location = url;
|
||||
}).fail(function() {
|
||||
}
|
||||
};
|
||||
|
||||
var wait_server = function() {
|
||||
instance.session.rpc("/web/webclient/version_info", {}).done(load).fail(function() {
|
||||
setTimeout(wait_server, 250);
|
||||
});
|
||||
};
|
||||
|
@ -815,7 +810,7 @@ instance.web.redirect = function(url, wait) {
|
|||
if (wait) {
|
||||
setTimeout(wait_server, 1000);
|
||||
} else {
|
||||
window.location = url;
|
||||
load();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -830,7 +825,6 @@ instance.web.Reload = function(parent, action) {
|
|||
var l = window.location;
|
||||
|
||||
var sobj = $.deparam(l.search.substr(1));
|
||||
sobj.ts = new Date().getTime();
|
||||
if (params.url_search) {
|
||||
sobj = _.extend(sobj, params.url_search);
|
||||
}
|
||||
|
@ -875,7 +869,7 @@ instance.web.ChangePassword = instance.web.Widget.extend({
|
|||
$button.appendTo(this.getParent().$buttons);
|
||||
$button.eq(2).click(function(){
|
||||
self.getParent().close();
|
||||
})
|
||||
});
|
||||
$button.eq(0).click(function(){
|
||||
self.rpc("/web/session/change_password",{
|
||||
'fields': $("form[name=change_password_form]").serializeArray()
|
||||
|
@ -887,7 +881,7 @@ instance.web.ChangePassword = instance.web.Widget.extend({
|
|||
instance.webclient.on_logout();
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
},
|
||||
display_error: function (error) {
|
||||
return instance.web.dialog($('<div>'), {
|
||||
|
@ -898,7 +892,7 @@ instance.web.ChangePassword = instance.web.Widget.extend({
|
|||
]
|
||||
}).html(error.error);
|
||||
},
|
||||
})
|
||||
});
|
||||
instance.web.client_actions.add("change_password", "instance.web.ChangePassword");
|
||||
|
||||
instance.web.Menu = instance.web.Widget.extend({
|
||||
|
@ -1114,7 +1108,7 @@ instance.web.Menu = instance.web.Widget.extend({
|
|||
add_menu_ids(menu);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
add_menu_ids(menu);
|
||||
self.do_load_needaction(menu_ids).then(function () {
|
||||
self.trigger("need_action_reloaded");
|
||||
|
|
|
@ -73,7 +73,7 @@ openerp.web.corelib = function(instance) {
|
|||
*/
|
||||
(function() {
|
||||
var initializing = false,
|
||||
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
fnTest = /xyz/.test(function(){xyz();}) ? /\b_super\b/ : /.*/;
|
||||
// The web Class implementation (does nothing)
|
||||
instance.web.Class = function(){};
|
||||
|
||||
|
@ -96,7 +96,7 @@ openerp.web.corelib = function(instance) {
|
|||
initializing = false;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
_.each(prop, function(val, name) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
fnTest.test(prop[name]) ?
|
||||
|
@ -117,13 +117,12 @@ openerp.web.corelib = function(instance) {
|
|||
};
|
||||
})(name, prop[name]) :
|
||||
prop[name];
|
||||
}
|
||||
});
|
||||
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
if(this.constructor !== instance.web.Class){
|
||||
throw new Error("You can only instanciate objects with the 'new' operator");
|
||||
return null;
|
||||
}
|
||||
// All construction is actually done in the init method
|
||||
if (!initializing && this.init) {
|
||||
|
@ -133,7 +132,7 @@ openerp.web.corelib = function(instance) {
|
|||
return this;
|
||||
}
|
||||
Class.include = function (properties) {
|
||||
for (var name in properties) {
|
||||
_.each(properties, function(val, name) {
|
||||
if (typeof properties[name] !== 'function'
|
||||
|| !fnTest.test(properties[name])) {
|
||||
prototype[name] = properties[name];
|
||||
|
@ -146,7 +145,7 @@ openerp.web.corelib = function(instance) {
|
|||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
})(name, properties[name], prototype[name]);
|
||||
} else if (typeof _super[name] === 'function') {
|
||||
prototype[name] = (function (name, fn) {
|
||||
|
@ -156,10 +155,10 @@ openerp.web.corelib = function(instance) {
|
|||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
})(name, properties[name]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Populate our constructed prototype object
|
||||
|
@ -297,7 +296,7 @@ var Events = instance.web.Class.extend({
|
|||
var ev;
|
||||
events = events.split(/\s+/);
|
||||
var calls = this._callbacks || (this._callbacks = {});
|
||||
while (ev = events.shift()) {
|
||||
while ((ev = events.shift())) {
|
||||
var list = calls[ev] || (calls[ev] = {});
|
||||
var tail = list.tail || (list.tail = list.next = {});
|
||||
tail.callback = callback;
|
||||
|
@ -311,9 +310,9 @@ var Events = instance.web.Class.extend({
|
|||
var ev, calls, node;
|
||||
if (!events) {
|
||||
delete this._callbacks;
|
||||
} else if (calls = this._callbacks) {
|
||||
} else if ((calls = this._callbacks)) {
|
||||
events = events.split(/\s+/);
|
||||
while (ev = events.shift()) {
|
||||
while ((ev = events.shift())) {
|
||||
node = calls[ev];
|
||||
delete calls[ev];
|
||||
if (!callback || !node)
|
||||
|
@ -347,7 +346,7 @@ var Events = instance.web.Class.extend({
|
|||
all = calls['all'];
|
||||
(events = events.split(/\s+/)).push(null);
|
||||
// Save references to the current heads & tails.
|
||||
while (event = events.shift()) {
|
||||
while ((event = events.shift())) {
|
||||
if (all)
|
||||
events.push({
|
||||
next : all.next,
|
||||
|
@ -362,7 +361,7 @@ var Events = instance.web.Class.extend({
|
|||
});
|
||||
}
|
||||
rest = Array.prototype.slice.call(arguments, 1);
|
||||
while (node = events.pop()) {
|
||||
while ((node = events.pop())) {
|
||||
tail = node.tail;
|
||||
args = node.event ? [ node.event ].concat(rest) : rest;
|
||||
while ((node = node.next) !== tail) {
|
||||
|
@ -504,7 +503,7 @@ instance.web.Controller = instance.web.Class.extend(instance.web.PropertiesMixin
|
|||
return function () {
|
||||
var fn = (typeof method === 'string') ? self[method] : method;
|
||||
return fn.apply(self, arguments);
|
||||
}
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Informs the action manager to do an action. This supposes that
|
||||
|
@ -692,11 +691,6 @@ instance.web.Widget = instance.web.Controller.extend({
|
|||
insertion(target);
|
||||
return this.start();
|
||||
},
|
||||
/**
|
||||
* This is the method to implement to render the Widget.
|
||||
*/
|
||||
renderElement: function() {
|
||||
},
|
||||
/**
|
||||
* Method called after rendering. Mostly used to bind actions, perform asynchronous
|
||||
* calls, etc...
|
||||
|
@ -889,7 +883,7 @@ instance.web.Registry = instance.web.Class.extend({
|
|||
contains: function (key) {
|
||||
if (key === undefined) { return false; }
|
||||
if (key in this.map) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
if (this.parent) {
|
||||
return this.parent.contains(key);
|
||||
|
@ -966,7 +960,7 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
|||
init: function() {
|
||||
instance.web.PropertiesMixin.init.call(this);
|
||||
this.server = null;
|
||||
this.debug = ($.deparam($.param.querystring()).debug != undefined);
|
||||
this.debug = ($.deparam($.param.querystring()).debug !== undefined);
|
||||
this.override_session = false;
|
||||
this.session_id = undefined;
|
||||
},
|
||||
|
@ -1154,6 +1148,6 @@ instance.web.py_eval = function(expr, context) {
|
|||
return py.eval(expr, _.extend({}, context || {}, {"true": true, "false": false, "null": null}));
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
|
|
@ -88,7 +88,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
|||
this.session_id = this.get_cookie('session_id');
|
||||
}
|
||||
return def.then(function() {
|
||||
return self.rpc("/web/session/get_session_info", {})
|
||||
return self.rpc("/web/session/get_session_info", {});
|
||||
}).then(function(result) {
|
||||
// If immediately follows a login (triggered by trying to restore
|
||||
// an invalid session or no session at all), refresh session data
|
||||
|
@ -250,7 +250,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
|||
continue;
|
||||
instance[mod] = {};
|
||||
// init module mod
|
||||
if(instance._openerp[mod] != undefined) {
|
||||
if(instance._openerp[mod] !== undefined) {
|
||||
instance._openerp[mod](instance,instance[mod]);
|
||||
this.module_loaded[mod] = true;
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
|||
$input = $('<input type="hidden" name="' + key + '">')
|
||||
.appendTo($form_data);
|
||||
}
|
||||
$input.val(value)
|
||||
$input.val(value);
|
||||
});
|
||||
|
||||
$form
|
||||
|
@ -404,7 +404,7 @@ instance.web.Bus = instance.web.Class.extend(instance.web.EventDispatcherMixin,
|
|||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
instance.web.bus = new instance.web.Bus();
|
||||
|
||||
/** OpenERP Translations */
|
||||
|
@ -466,12 +466,12 @@ $.fn.getAttributes = function() {
|
|||
var o = {};
|
||||
if (this.length) {
|
||||
for (var attr, i = 0, attrs = this[0].attributes, l = attrs.length; i < l; i++) {
|
||||
attr = attrs.item(i)
|
||||
attr = attrs.item(i);
|
||||
o[attr.nodeName] = attr.nodeValue;
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
$.fn.openerpClass = function(additionalClass) {
|
||||
// This plugin should be applied on top level elements
|
||||
additionalClass = additionalClass || '';
|
||||
|
@ -557,7 +557,7 @@ instance.web._t = new instance.web.TranslationDataBase().build_translation_funct
|
|||
* @returns {Object} lazy translation object
|
||||
*/
|
||||
instance.web._lt = function (s) {
|
||||
return {toString: function () { return instance.web._t(s); }}
|
||||
return {toString: function () { return instance.web._t(s); }};
|
||||
};
|
||||
instance.web.qweb = new QWeb2.Engine();
|
||||
instance.web.qweb.debug = instance.session.debug;
|
||||
|
@ -585,7 +585,7 @@ instance.web.qweb.preprocess_node = function() {
|
|||
case Node.ELEMENT_NODE:
|
||||
// Element
|
||||
var attr, attrs = ['label', 'title', 'alt', 'placeholder'];
|
||||
while (attr = attrs.pop()) {
|
||||
while ((attr = attrs.pop())) {
|
||||
if (this.attributes[attr]) {
|
||||
this.attributes[attr] = instance.web._t(this.attributes[attr]);
|
||||
}
|
||||
|
@ -692,13 +692,13 @@ instance.web.blockUI = function() {
|
|||
instance.web.Throbber.throbbers.push(throbber);
|
||||
throbber.appendTo($(".oe_blockui_spin_container"));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
instance.web.unblockUI = function() {
|
||||
_.each(instance.web.Throbber.throbbers, function(el) {
|
||||
el.destroy();
|
||||
});
|
||||
return $.unblockUI.apply($, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry for all the client actions key: tag value: widget
|
||||
|
|
|
@ -100,7 +100,7 @@ instance.web.Query = instance.web.Class.extend({
|
|||
* @returns {jQuery.Deferred<Number>}
|
||||
*/
|
||||
count: function () {
|
||||
if (this._count != undefined) { return $.when(this._count); }
|
||||
if (this._count !== undefined) { return $.when(this._count); }
|
||||
return this._model.call(
|
||||
'search_count', [this._filter], {
|
||||
context: this._model.context(this._context)});
|
||||
|
@ -494,7 +494,7 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin,
|
|||
return this._model.call('create', [data], {
|
||||
context: this.get_context()
|
||||
}).done(function () {
|
||||
self.trigger('dataset_changed', data, options)
|
||||
self.trigger('dataset_changed', data, options);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -514,7 +514,7 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin,
|
|||
return this._model.call('write', [[id], data], {
|
||||
context: this.get_context(options.context)
|
||||
}).done(function () {
|
||||
self.trigger('dataset_changed', id, data, options)
|
||||
self.trigger('dataset_changed', id, data, options);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -527,7 +527,7 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin,
|
|||
return this._model.call('unlink', [ids], {
|
||||
context: this.get_context()
|
||||
}).done(function () {
|
||||
self.trigger('dataset_changed', ids)
|
||||
self.trigger('dataset_changed', ids);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
@ -747,7 +747,7 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({
|
|||
});
|
||||
},
|
||||
size: function () {
|
||||
if (this._length != null) {
|
||||
if (this._length !== null) {
|
||||
return this._length;
|
||||
}
|
||||
return this._super();
|
||||
|
@ -810,7 +810,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
|
|||
var self = this;
|
||||
_.each(ids, function(id) {
|
||||
if (! _.detect(self.to_create, function(x) { return x.id === id; })) {
|
||||
self.to_delete.push({id: id})
|
||||
self.to_delete.push({id: id});
|
||||
}
|
||||
});
|
||||
this.to_create = _.reject(this.to_create, function(x) { return _.include(ids, x.id);});
|
||||
|
@ -838,7 +838,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
|
|||
_.each(fields, function(x) {if (cached.values[x] === undefined)
|
||||
cached.values[x] = created.defaults[x] || false;});
|
||||
} else {
|
||||
if (!cached || !_.all(fields, function(x) {return cached.values[x] !== undefined}))
|
||||
if (!cached || !_.all(fields, function(x) {return cached.values[x] !== undefined;}))
|
||||
to_get.push(id);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -71,7 +71,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
|
|||
opt.replaceChild(
|
||||
document.createTextNode(
|
||||
_.str.sprintf("%s — %s", format.label, format.error)),
|
||||
opt.childNodes[0])
|
||||
opt.childNodes[0]);
|
||||
}
|
||||
$fmts.append(opt);
|
||||
});
|
||||
|
@ -93,7 +93,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
|
|||
self.$el.find('#fields_list option').remove();
|
||||
var export_id = self.$el.find('#saved_export_list option:selected').val();
|
||||
if (export_id) {
|
||||
self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}).done(self.do_load_export_field);
|
||||
self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id, 10)}).done(self.do_load_export_field);
|
||||
}
|
||||
});
|
||||
self.$el.find('#delete_export_list').click(function() {
|
||||
|
@ -215,7 +215,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
|
|||
self.$el.find("tr[id='treerow-" + record.id + "']").click(function(e) {
|
||||
if (e.shiftKey) {
|
||||
var frst_click, scnd_click = '';
|
||||
if (self.row_index == 0) {
|
||||
if (self.row_index === 0) {
|
||||
self.row_index = this.rowIndex;
|
||||
frst_click = self.$el.find("tr[id^='treerow-']")[self.row_index-1];
|
||||
$(frst_click).addClass("ui-selected");
|
||||
|
|
|
@ -141,6 +141,7 @@ instance.web.format_value = function (value, descriptor, value_if_empty) {
|
|||
return '';
|
||||
}
|
||||
console.warn('Field', descriptor, 'had an empty string as value, treating as false...');
|
||||
return value_if_empty === undefined ? '' : value_if_empty;
|
||||
case false:
|
||||
case Infinity:
|
||||
case -Infinity:
|
||||
|
@ -199,7 +200,7 @@ instance.web.format_value = function (value, descriptor, value_if_empty) {
|
|||
case 'selection': case 'statusbar':
|
||||
// Each choice is [value, label]
|
||||
if(_.isArray(value)) {
|
||||
value = value[0]
|
||||
value = value[0];
|
||||
}
|
||||
var result = _(descriptor.selection).detect(function (choice) {
|
||||
return choice[0] === value;
|
||||
|
@ -219,9 +220,9 @@ instance.web.parse_value = function (value, descriptor, value_if_empty) {
|
|||
case "":
|
||||
return value_if_empty === undefined ? false : value_if_empty;
|
||||
}
|
||||
var tmp;
|
||||
switch (descriptor.widget || descriptor.type || (descriptor.field && descriptor.field.type)) {
|
||||
case 'integer':
|
||||
var tmp;
|
||||
do {
|
||||
tmp = value;
|
||||
value = value.replace(instance.web._t.database.parameters.thousands_sep, "");
|
||||
|
@ -231,7 +232,7 @@ instance.web.parse_value = function (value, descriptor, value_if_empty) {
|
|||
throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
|
||||
return tmp;
|
||||
case 'float':
|
||||
var tmp = Number(value);
|
||||
tmp = Number(value);
|
||||
if (!isNaN(tmp))
|
||||
return tmp;
|
||||
|
||||
|
@ -314,4 +315,34 @@ instance.web.auto_date_to_str = function(value, type) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* performs a half up rounding with arbitrary precision, correcting for float loss of precision
|
||||
* See the corresponding float_round() in server/tools/float_utils.py for more info
|
||||
* @param {Number} the value to be rounded
|
||||
* @param {Number} a non zero precision parameter. eg: 0.01 rounds to two digits.
|
||||
*/
|
||||
instance.web.round_precision = function(value, precision){
|
||||
if(!value){
|
||||
return 0;
|
||||
}else if(!precision){
|
||||
throw new Error('round_precision(...): Cannot round value: '+value+' with a precision of zero (or undefined)');
|
||||
}
|
||||
var normalized_value = value / precision;
|
||||
var epsilon_magnitude = Math.log(Math.abs(normalized_value))/Math.log(2);
|
||||
var epsilon = Math.pow(2, epsilon_magnitude - 53);
|
||||
normalized_value += normalized_value >= 0 ? epsilon : -epsilon;
|
||||
var rounded_value = Math.round(normalized_value);
|
||||
return rounded_value * precision;
|
||||
};
|
||||
|
||||
/**
|
||||
* performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision
|
||||
* See the corresponding float_round() in server/tools/float_utils.py for more info
|
||||
* @param {Number} the value to be rounded
|
||||
* @param {Number} the number of decimals. eg: round_decimals(3.141592,2) -> 3.14
|
||||
*/
|
||||
instance.web.round_decimals = function(value, decimals){
|
||||
return instance.web.round_precision(value, Math.pow(10,-decimals));
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -97,7 +97,7 @@ openerp.web.pyeval = function (instance) {
|
|||
divmod(n, 365, function (_n1, n) {
|
||||
n1 = _n1;
|
||||
n0 = n;
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -139,7 +139,7 @@ openerp.web.pyeval = function (instance) {
|
|||
if (microsecond < 0 || microsecond > 999999) {
|
||||
divmod(microsecond, 1000000, function (carry, ms) {
|
||||
microsecond = ms;
|
||||
second += carry
|
||||
second += carry;
|
||||
});
|
||||
}
|
||||
if (second < 0 || second > 59) {
|
||||
|
@ -152,13 +152,13 @@ openerp.web.pyeval = function (instance) {
|
|||
divmod(minute, 60, function (carry, m) {
|
||||
minute = m;
|
||||
hour += carry;
|
||||
})
|
||||
});
|
||||
}
|
||||
if (hour < 0 || hour > 23) {
|
||||
divmod(hour, 24, function (carry, h) {
|
||||
hour = h;
|
||||
day += carry;
|
||||
})
|
||||
});
|
||||
}
|
||||
// That was easy. Now it gets muddy: the proper range for day
|
||||
// can't be determined without knowing the correct month and year,
|
||||
|
@ -170,7 +170,7 @@ openerp.web.pyeval = function (instance) {
|
|||
divmod(month-1, 12, function (carry, m) {
|
||||
month = m + 1;
|
||||
year += carry;
|
||||
})
|
||||
});
|
||||
}
|
||||
// Now only day can be out of bounds (year may also be out of bounds
|
||||
// for a datetime object, but we don't care about that here).
|
||||
|
@ -247,7 +247,7 @@ openerp.web.pyeval = function (instance) {
|
|||
});
|
||||
divmod(seconds, 24*3600, function (days, seconds) {
|
||||
d += days;
|
||||
s += seconds
|
||||
s += seconds;
|
||||
});
|
||||
// seconds isn't referenced again before redefinition
|
||||
|
||||
|
@ -358,7 +358,7 @@ openerp.web.pyeval = function (instance) {
|
|||
return py.float.fromJSON(
|
||||
this.days * 86400
|
||||
+ this.seconds
|
||||
+ this.microseconds / 1000000)
|
||||
+ this.microseconds / 1000000);
|
||||
},
|
||||
__nonzero__: function () {
|
||||
return (!!this.days || !!this.seconds || !!this.microseconds)
|
||||
|
@ -466,7 +466,7 @@ openerp.web.pyeval = function (instance) {
|
|||
return py.float.fromJSON(ymd2ord(this.year, this.month, this.day));
|
||||
},
|
||||
fromJSON: function (year, month, day) {
|
||||
return py.PY_call(datetime.date, [year, month, day])
|
||||
return py.PY_call(datetime.date, [year, month, day]);
|
||||
}
|
||||
});
|
||||
/**
|
||||
|
@ -505,7 +505,7 @@ openerp.web.pyeval = function (instance) {
|
|||
var args = _.map(('year month day hour minute second microsecond '
|
||||
+ 'years months weeks days hours minutes secondes microseconds '
|
||||
+ 'weekday leakdays yearday nlyearday').split(' '), function (arg) {
|
||||
return [arg, null]
|
||||
return [arg, null];
|
||||
});
|
||||
args.unshift('*');
|
||||
var relativedelta = py.type('relativedelta', null, {
|
||||
|
@ -795,13 +795,20 @@ openerp.web.pyeval = function (instance) {
|
|||
|
||||
//noinspection FallthroughInSwitchStatementJS
|
||||
switch(type) {
|
||||
case 'context': object = [object];
|
||||
case 'contexts': return eval_contexts((options.no_user_context ? [] : [instance.session.user_context]).concat(object), context);
|
||||
case 'domain': object = [object];
|
||||
case 'domains': return eval_domains(object, context);
|
||||
case 'groupbys': return eval_groupbys(object, context);
|
||||
case 'context':
|
||||
case 'contexts':
|
||||
if (type === 'context')
|
||||
object = [object];
|
||||
return eval_contexts((options.no_user_context ? [] : [instance.session.user_context]).concat(object), context);
|
||||
case 'domain':
|
||||
case 'domains':
|
||||
if (type === 'domain')
|
||||
object = [object];
|
||||
return eval_domains(object, context);
|
||||
case 'groupbys':
|
||||
return eval_groupbys(object, context);
|
||||
}
|
||||
throw new Error("Unknow evaluation type " + type)
|
||||
throw new Error("Unknow evaluation type " + type);
|
||||
};
|
||||
|
||||
var eval_arg = function (arg) {
|
||||
|
@ -856,5 +863,5 @@ openerp.web.pyeval = function (instance) {
|
|||
}});
|
||||
}
|
||||
}, 0); });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ my.SearchQuery = B.Collection.extend({
|
|||
}, this);
|
||||
},
|
||||
add: function (values, options) {
|
||||
options || (options = {});
|
||||
options = options || {};
|
||||
if (!(values instanceof Array)) {
|
||||
values = [values];
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ my.SearchQuery = B.Collection.extend({
|
|||
return this;
|
||||
},
|
||||
toggle: function (value, options) {
|
||||
options || (options = {});
|
||||
options = options || {};
|
||||
|
||||
var facet = this.detect(function (facet) {
|
||||
return facet.get('category') === value.category
|
||||
|
@ -148,7 +148,7 @@ my.InputView = instance.web.Widget.extend({
|
|||
range.setStart(root, 0);
|
||||
}
|
||||
if (range.endContainer === this.el && range.endOffset === 1) {
|
||||
range.setEnd(root, root.length)
|
||||
range.setEnd(root, root.length);
|
||||
}
|
||||
assert(range.startContainer === root,
|
||||
"selection should be in the input view");
|
||||
|
@ -157,7 +157,7 @@ my.InputView = instance.web.Widget.extend({
|
|||
return {
|
||||
start: range.startOffset,
|
||||
end: range.endOffset
|
||||
}
|
||||
};
|
||||
},
|
||||
onKeydown: function (e) {
|
||||
this.el.normalize();
|
||||
|
@ -401,7 +401,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
});
|
||||
|
||||
$.when(load_view).then(function (r) {
|
||||
return self.search_view_loaded(r)
|
||||
return self.search_view_loaded(r);
|
||||
}).fail(function () {
|
||||
self.ready.reject.apply(null, arguments);
|
||||
});
|
||||
|
@ -950,7 +950,7 @@ instance.web.search.Input = instance.web.search.Widget.extend( /** @lends instan
|
|||
* @returns {jQuery.Deferred<null|Array>}
|
||||
*/
|
||||
complete: function (value) {
|
||||
return $.when(null)
|
||||
return $.when(null);
|
||||
},
|
||||
/**
|
||||
* Returns a Facet instance for the provided defaults if they apply to
|
||||
|
@ -1073,7 +1073,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
icon: this.icon,
|
||||
values: values,
|
||||
field: this
|
||||
}
|
||||
};
|
||||
},
|
||||
make_value: function (filter) {
|
||||
return {
|
||||
|
@ -1107,7 +1107,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
|
||||
if (!contexts.length) { return; }
|
||||
if (contexts.length === 1) { return contexts[0]; }
|
||||
return _.extend(new instance.web.CompoundContext, {
|
||||
return _.extend(new instance.web.CompoundContext(), {
|
||||
__contexts: contexts
|
||||
});
|
||||
},
|
||||
|
@ -1176,7 +1176,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
label: _.str.sprintf(self.completion_label.toString(),
|
||||
_.escape(facet_value.label)),
|
||||
facet: self.make_facet([facet_value])
|
||||
}
|
||||
};
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
@ -1198,7 +1198,7 @@ instance.web.search.GroupbyGroup = instance.web.search.FilterGroup.extend({
|
|||
get_context: this.proxy('get_context'),
|
||||
get_domain: this.proxy('get_domain'),
|
||||
get_groupby: this.proxy('get_groupby')
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
match_facet: function (facet) {
|
||||
|
@ -1276,7 +1276,7 @@ instance.web.search.Field = instance.web.search.Input.extend( /** @lends instanc
|
|||
|
||||
if (contexts.length === 1) { return contexts[0]; }
|
||||
|
||||
return _.extend(new instance.web.CompoundContext, {
|
||||
return _.extend(new instance.web.CompoundContext(), {
|
||||
__contexts: contexts
|
||||
});
|
||||
},
|
||||
|
@ -1321,7 +1321,7 @@ instance.web.search.Field = instance.web.search.Input.extend( /** @lends instanc
|
|||
domains.unshift(['|']);
|
||||
}
|
||||
|
||||
return _.extend(new instance.web.CompoundDomain, {
|
||||
return _.extend(new instance.web.CompoundDomain(), {
|
||||
__domains: domains
|
||||
});
|
||||
}
|
||||
|
@ -1564,7 +1564,7 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
|
|||
return this.model.call('name_get', [value]).then(function (names) {
|
||||
if (_(names).isEmpty()) { return null; }
|
||||
return facet_from(self, names[0]);
|
||||
})
|
||||
});
|
||||
},
|
||||
value_from: function (facetValue) {
|
||||
return facetValue.get('label');
|
||||
|
@ -1919,7 +1919,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
|
|||
},
|
||||
changed: function() {
|
||||
var nval = this.$(".searchview_extended_prop_field").val();
|
||||
if(this.attrs.selected == null || nval != this.attrs.selected.name) {
|
||||
if(this.attrs.selected === null || this.attrs.selected === undefined || nval != this.attrs.selected.name) {
|
||||
this.select_field(_.detect(this.fields, function(x) {return x.name == nval;}));
|
||||
}
|
||||
},
|
||||
|
@ -1941,13 +1941,13 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
|
|||
*/
|
||||
select_field: function(field) {
|
||||
var self = this;
|
||||
if(this.attrs.selected != null) {
|
||||
if(this.attrs.selected !== null && this.attrs.selected !== undefined) {
|
||||
this.value.destroy();
|
||||
this.value = null;
|
||||
this.$('.searchview_extended_prop_op').html('');
|
||||
}
|
||||
this.attrs.selected = field;
|
||||
if(field == null) {
|
||||
if(field === null || field === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1967,7 +1967,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
|
|||
|
||||
},
|
||||
get_proposition: function() {
|
||||
if ( this.attrs.selected == null)
|
||||
if (this.attrs.selected === null || this.attrs.selected === undefined)
|
||||
return null;
|
||||
var field = this.attrs.selected;
|
||||
var op_select = this.$('.searchview_extended_prop_op')[0];
|
||||
|
@ -2097,7 +2097,7 @@ instance.web.search.ExtendedSearchProposition.Integer = instance.web.search.Exte
|
|||
get_value: function() {
|
||||
try {
|
||||
var val =this.$el.val();
|
||||
return instance.web.parse_value(val == "" ? 0 : val, {'widget': 'integer'});
|
||||
return instance.web.parse_value(val === "" ? 0 : val, {'widget': 'integer'});
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
|
@ -2124,7 +2124,7 @@ instance.web.search.ExtendedSearchProposition.Float = instance.web.search.Extend
|
|||
get_value: function() {
|
||||
try {
|
||||
var val =this.$el.val();
|
||||
return instance.web.parse_value(val == "" ? 0.0 : val, {'widget': 'float'});
|
||||
return instance.web.parse_value(val === "" ? 0.0 : val, {'widget': 'float'});
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -73,6 +73,6 @@ openerp.test_support = {
|
|||
return;
|
||||
}
|
||||
fn(e.data.name);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -176,9 +176,9 @@ openerp.testing = {};
|
|||
});
|
||||
|
||||
QUnit.module(testing.current_module + '.' + name, {_oe: options});
|
||||
body(testing.case);
|
||||
body(testing['case']);
|
||||
};
|
||||
testing.case = function (name, options, callback) {
|
||||
testing['case'] = function (name, options, callback) {
|
||||
if (_.isFunction(options)) {
|
||||
callback = options;
|
||||
options = {};
|
||||
|
@ -359,7 +359,7 @@ openerp.testing = {};
|
|||
|
||||
return $.Deferred(function (d) {
|
||||
$.when(result).then(function () {
|
||||
d.resolve.apply(d, arguments)
|
||||
d.resolve.apply(d, arguments);
|
||||
}, function () {
|
||||
d.reject.apply(d, arguments);
|
||||
});
|
||||
|
|
|
@ -346,7 +346,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
self.on_form_changed();
|
||||
self.rendering_engine.init_fields();
|
||||
self.is_initialized.resolve();
|
||||
self.do_update_pager(record.id == null);
|
||||
self.do_update_pager(record.id === null || record.id === undefined);
|
||||
if (self.sidebar) {
|
||||
self.sidebar.do_attachement_update(self.dataset, self.datarecord.id);
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
|
||||
var method = call[1];
|
||||
if (!_.str.trim(call[2])) {
|
||||
return {method: method, args: []}
|
||||
return {method: method, args: []};
|
||||
}
|
||||
|
||||
var argument_replacement = {
|
||||
|
@ -465,7 +465,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
// form field
|
||||
if (self.fields[field]) {
|
||||
var value_ = self.fields[field].get_value();
|
||||
return value_ == null ? false : value_;
|
||||
return value_ === null || value_ === undefined ? false : value_;
|
||||
}
|
||||
// parent field
|
||||
var splitted = field.split('.');
|
||||
|
@ -475,7 +475,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
}
|
||||
var p_val = parent_fields[_.str.trim(splitted[1])];
|
||||
if (p_val !== undefined) {
|
||||
return p_val == null ? false : p_val;
|
||||
return p_val === null || p_val === undefined ? false : p_val;
|
||||
}
|
||||
}
|
||||
// string literal
|
||||
|
@ -621,7 +621,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
}
|
||||
return $.when();
|
||||
});
|
||||
};
|
||||
}
|
||||
return iterate();
|
||||
});
|
||||
},
|
||||
|
@ -778,7 +778,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
} else {
|
||||
$.async_when().done(function () {
|
||||
def.reject();
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
return def.promise();
|
||||
|
@ -943,11 +943,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
reload: function() {
|
||||
var self = this;
|
||||
return this.reload_mutex.exec(function() {
|
||||
if (self.dataset.index == null) {
|
||||
if (self.dataset.index === null || self.dataset.index === undefined) {
|
||||
self.trigger("previous_view");
|
||||
return $.Deferred().reject().promise();
|
||||
}
|
||||
if (self.dataset.index == null || self.dataset.index < 0) {
|
||||
if (self.dataset.index < 0) {
|
||||
return $.when(self.on_button_new());
|
||||
} else {
|
||||
var fields = _.keys(self.fields_view.fields);
|
||||
|
@ -1028,7 +1028,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
return field.get_displayed();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
var fields = _.chain(this.fields)
|
||||
.map(function (field) {
|
||||
var value = field.get_value();
|
||||
|
@ -1049,7 +1049,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
string: field.string,
|
||||
value: value,
|
||||
displayed: display(field, value),
|
||||
}
|
||||
};
|
||||
})
|
||||
.compact()
|
||||
.sortBy(function (field) { return field.string; })
|
||||
|
@ -1063,7 +1063,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
|||
string: field.string,
|
||||
value: value,
|
||||
displayed: display(field, value),
|
||||
}
|
||||
};
|
||||
})
|
||||
.value();
|
||||
|
||||
|
@ -1429,7 +1429,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
|
|||
row_cols = cols;
|
||||
} else if (tagName==='group') {
|
||||
// When <group> <group/><group/> </group>, we need a spacing between the two groups
|
||||
$td.addClass('oe_group_right')
|
||||
$td.addClass('oe_group_right');
|
||||
}
|
||||
row_cols -= colspan;
|
||||
|
||||
|
@ -1714,7 +1714,7 @@ instance.web.form.compute_domain = function(expr, fields) {
|
|||
};
|
||||
|
||||
instance.web.form.is_bin_size = function(v) {
|
||||
return /^\d+(\.\d*)? \w+$/.test(v);
|
||||
return (/^\d+(\.\d*)? \w+$/).test(v);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1852,7 +1852,8 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
|
|||
return QWeb.render(template, {
|
||||
debug: instance.session.debug,
|
||||
widget: widget
|
||||
})},
|
||||
});
|
||||
},
|
||||
gravity: $.fn.tipsy.autoBounds(50, 'nw'),
|
||||
html: true,
|
||||
opacity: 0.85,
|
||||
|
@ -2073,7 +2074,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
|
|||
* @param node
|
||||
*/
|
||||
init: function(field_manager, node) {
|
||||
var self = this
|
||||
var self = this;
|
||||
this._super(field_manager, node);
|
||||
this.name = this.node.attrs.name;
|
||||
this.field = this.field_manager.get_field_desc(this.name);
|
||||
|
@ -2642,7 +2643,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we
|
|||
if (! this.get("effective_readonly")) {
|
||||
var show_value = instance.web.format_value(this.get('value'), this, '');
|
||||
if (show_value === '') {
|
||||
this.$textarea.css('height', parseInt(this.default_height)+"px");
|
||||
this.$textarea.css('height', parseInt(this.default_height, 10)+"px");
|
||||
}
|
||||
this.$textarea.val(show_value);
|
||||
if (! this.auto_sized) {
|
||||
|
@ -2937,7 +2938,7 @@ instance.web.form.FieldRadio = instance.web.form.AbstractField.extend(instance.w
|
|||
set_value: function (value_) {
|
||||
if (value_) {
|
||||
if (this.field.type == "selection") {
|
||||
value_ = _.find(this.field.selection, function (sel) { return sel[0] == value_});
|
||||
value_ = _.find(this.field.selection, function (sel) { return sel[0] == value_;});
|
||||
}
|
||||
else if (!this.selection.length) {
|
||||
this.selection = [value_];
|
||||
|
@ -2954,7 +2955,7 @@ instance.web.form.FieldRadio = instance.web.form.AbstractField.extend(instance.w
|
|||
this.$el.toggleClass("oe_readonly", this.get('effective_readonly'));
|
||||
this.$("input:checked").prop("checked", false);
|
||||
if (this.get_value()) {
|
||||
this.$("input").filter(function () {return this.value == self.get_value()}).prop("checked", true);
|
||||
this.$("input").filter(function () {return this.value == self.get_value();}).prop("checked", true);
|
||||
this.$(".oe_radio_readonly").text(this.get('value') ? this.get('value')[1] : "");
|
||||
}
|
||||
}
|
||||
|
@ -3090,7 +3091,7 @@ instance.web.form.CompletionFieldMixin = {
|
|||
self.field.relation,
|
||||
{
|
||||
title: (view === 'search' ? _t("Search: ") : _t("Create: ")) + this.string,
|
||||
initial_ids: ids ? _.map(ids, function(x) {return x[0]}) : undefined,
|
||||
initial_ids: ids ? _.map(ids, function(x) {return x[0];}) : undefined,
|
||||
initial_view: view,
|
||||
disable_multiple_selection: true
|
||||
},
|
||||
|
@ -3265,7 +3266,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
|
|||
this.$input.keydown(input_changed);
|
||||
this.$input.change(input_changed);
|
||||
this.$drop_down.click(function() {
|
||||
self.$input.focus();
|
||||
self.$input.focus();
|
||||
if (self.$input.autocomplete("widget").is(":visible")) {
|
||||
self.$input.autocomplete("close");
|
||||
} else {
|
||||
|
@ -3455,7 +3456,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
|
|||
var self = this;
|
||||
if (value_ instanceof Array) {
|
||||
this.display_value = {};
|
||||
this.display_value_backup = {}
|
||||
this.display_value_backup = {};
|
||||
if (! this.options.always_reload) {
|
||||
this.display_value["" + value_[0]] = value_[1];
|
||||
}
|
||||
|
@ -3720,7 +3721,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
|||
});
|
||||
controller.on('pager_action_executed',self,self.save_any_view);
|
||||
} else if (view_type == "graph") {
|
||||
self.reload_current_view()
|
||||
self.reload_current_view();
|
||||
}
|
||||
def.resolve();
|
||||
});
|
||||
|
@ -3740,7 +3741,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
|||
},
|
||||
reload_current_view: function() {
|
||||
var self = this;
|
||||
return self.is_loaded = self.is_loaded.then(function() {
|
||||
self.is_loaded = self.is_loaded.then(function() {
|
||||
var active_view = self.viewmanager.active_view;
|
||||
var view = self.viewmanager.views[active_view].controller;
|
||||
if(active_view === "list") {
|
||||
|
@ -3758,13 +3759,15 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
|||
return view.do_search(self.build_domain(), self.dataset.get_context(), []);
|
||||
}
|
||||
}, undefined);
|
||||
return self.is_loaded;
|
||||
},
|
||||
set_value: function(value_) {
|
||||
value_ = value_ || [];
|
||||
var self = this;
|
||||
this.dataset.reset_ids([]);
|
||||
var ids;
|
||||
if(value_.length >= 1 && value_[0] instanceof Array) {
|
||||
var ids = [];
|
||||
ids = [];
|
||||
_.each(value_, function(command) {
|
||||
var obj = {values: command[2]};
|
||||
switch (command[0]) {
|
||||
|
@ -3795,7 +3798,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
|||
this._super(ids);
|
||||
this.dataset.set_ids(ids);
|
||||
} else if (value_.length >= 1 && typeof(value_[0]) === "object") {
|
||||
var ids = [];
|
||||
ids = [];
|
||||
this.dataset.delete_all = true;
|
||||
_.each(value_, function(command) {
|
||||
var obj = {values: command};
|
||||
|
@ -3850,7 +3853,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
|||
this.viewmanager.views[this.viewmanager.active_view].controller) {
|
||||
var view = this.viewmanager.views[this.viewmanager.active_view].controller;
|
||||
if (this.viewmanager.active_view === "form") {
|
||||
if (!view.is_initialized.state() === 'resolved') {
|
||||
if (view.is_initialized.state() !== 'resolved') {
|
||||
return $.when(false);
|
||||
}
|
||||
return $.when(view.save());
|
||||
|
@ -3870,7 +3873,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
|
|||
.invoke('is_valid')
|
||||
.all(_.identity)
|
||||
.value();
|
||||
break;
|
||||
case 'list':
|
||||
return view.is_valid();
|
||||
}
|
||||
|
@ -3962,7 +3964,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
|
|||
var form = editor.form;
|
||||
// If no edition is pending, the listview can not be invalid (?)
|
||||
if (!editor.record) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
// If the form has not been modified, the view can only be valid
|
||||
// NB: is_dirty will also be set on defaults/onchanges/whatever?
|
||||
|
@ -4167,7 +4169,7 @@ instance.web.form.One2ManyList = instance.web.ListView.List.extend({
|
|||
if ($padding.length) {
|
||||
$padding.before($newrow);
|
||||
} else {
|
||||
this.$current.append($newrow)
|
||||
this.$current.append($newrow);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -4256,7 +4258,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
|
|||
},
|
||||
core: {
|
||||
onSetInputData: function(e, data) {
|
||||
if (data == '') {
|
||||
if (data === '') {
|
||||
this._plugins.autocomplete._suggestions = null;
|
||||
}
|
||||
this.input().val(data);
|
||||
|
@ -4578,8 +4580,9 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
|
|||
if (type !== "form")
|
||||
return;
|
||||
var self = this;
|
||||
var pop;
|
||||
if (this.dataset.index === null) {
|
||||
var pop = new instance.web.form.SelectCreatePopup(this);
|
||||
pop = new instance.web.form.SelectCreatePopup(this);
|
||||
pop.select_element(
|
||||
this.field.relation,
|
||||
{
|
||||
|
@ -4599,7 +4602,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
|
|||
});
|
||||
} else {
|
||||
var id = self.dataset.ids[self.dataset.index];
|
||||
var pop = new instance.web.form.FormOpenPopup(this);
|
||||
pop = new instance.web.form.FormOpenPopup(this);
|
||||
pop.show_element(self.field.relation, id, self.build_context(), {
|
||||
title: _t("Open: ") + self.string,
|
||||
write_function: function(id, data, options) {
|
||||
|
@ -4935,7 +4938,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
|
|||
self.select_elements(self.selected_ids);
|
||||
self.destroy();
|
||||
});
|
||||
var $cbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-create");
|
||||
$cbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-create");
|
||||
$cbutton.click(function() {
|
||||
self.new_object();
|
||||
});
|
||||
|
@ -5020,8 +5023,8 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
|
|||
this.selection.on("change:value", this, this.on_selection_changed);
|
||||
this.selection.appendTo(this.$(".oe_form_view_reference_selection"));
|
||||
this.selection
|
||||
.on('focused', null, function () {self.trigger('focused')})
|
||||
.on('blurred', null, function () {self.trigger('blurred')});
|
||||
.on('focused', null, function () {self.trigger('focused');})
|
||||
.on('blurred', null, function () {self.trigger('blurred');});
|
||||
|
||||
this.m2o = new instance.web.form.FieldMany2One(fm, { attrs: {
|
||||
name: 'm2o',
|
||||
|
@ -5030,8 +5033,8 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
|
|||
this.m2o.on("change:value", this, this.data_changed);
|
||||
this.m2o.appendTo(this.$(".oe_form_view_reference_m2o"));
|
||||
this.m2o
|
||||
.on('focused', null, function () {self.trigger('focused')})
|
||||
.on('blurred', null, function () {self.trigger('blurred')});
|
||||
.on('focused', null, function () {self.trigger('focused');})
|
||||
.on('blurred', null, function () {self.trigger('blurred');});
|
||||
},
|
||||
on_selection_changed: function() {
|
||||
if (this.reference_ready) {
|
||||
|
@ -5190,18 +5193,18 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
|
|||
}
|
||||
},
|
||||
render_value: function() {
|
||||
var show_value;
|
||||
if (!this.get("effective_readonly")) {
|
||||
var show_value;
|
||||
if (this.node.attrs.filename) {
|
||||
show_value = this.view.datarecord[this.node.attrs.filename] || '';
|
||||
} else {
|
||||
show_value = (this.get('value') != null && this.get('value') !== false) ? this.get('value') : '';
|
||||
show_value = (this.get('value') !== null && this.get('value') !== undefined && this.get('value') !== false) ? this.get('value') : '';
|
||||
}
|
||||
this.$el.find('input').eq(0).val(show_value);
|
||||
} else {
|
||||
this.$el.find('a').toggle(!!this.get('value'));
|
||||
if (this.get('value')) {
|
||||
var show_value = _t("Download")
|
||||
show_value = _t("Download");
|
||||
if (this.view)
|
||||
show_value += " " + (this.view.datarecord[this.node.attrs.filename] || '');
|
||||
this.$el.find('a').text(show_value);
|
||||
|
@ -5420,7 +5423,7 @@ instance.web.form.FieldMany2ManyBinaryMultiFiles = instance.web.form.AbstractFie
|
|||
values.push(result.id);
|
||||
this.set({'value': values});
|
||||
}
|
||||
this.render_value()
|
||||
this.render_value();
|
||||
},
|
||||
on_file_delete: function (event) {
|
||||
event.stopPropagation();
|
||||
|
@ -5474,7 +5477,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
var self = this;
|
||||
var content = QWeb.render("FieldStatus.content", {
|
||||
'widget': self,
|
||||
'value_folded': _.find(self.selection.folded, function(i){return i[0] === self.get('value')})
|
||||
'value_folded': _.find(self.selection.folded, function(i){return i[0] === self.get('value');})
|
||||
});
|
||||
self.$el.html(content);
|
||||
},
|
||||
|
@ -5506,7 +5509,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
return new instance.web.DataSetSearch(self, self.field.relation, self.build_context(), self.get("evaluated_selection_domain"))
|
||||
.read_slice(fields.fold ? ['fold'] : ['id'], {}).then(function (records) {
|
||||
|
||||
var ids = _.map(records, function (val) {return val.id});
|
||||
var ids = _.map(records, function (val) {return val.id;});
|
||||
return self.dataset.name_get(ids).then(function (records_name) {
|
||||
_.each(records, function (record) {
|
||||
var name = _.find(records_name, function (val) {return val[0] == record.id;})[1];
|
||||
|
@ -5516,7 +5519,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
selection_unfolded.push([record.id, name]);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
@ -5548,16 +5551,17 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
|
|||
return new instance.web.Model(self.field.relation).call("fields_get", [["fold"]]).then(function(fields) {
|
||||
self.distant_fields = fields;
|
||||
return fields;
|
||||
})
|
||||
});
|
||||
},
|
||||
on_click_stage: function (ev) {
|
||||
var self = this;
|
||||
var $li = $(ev.currentTarget);
|
||||
var val;
|
||||
if (this.field.type == "many2one") {
|
||||
var val = parseInt($li.data("id"));
|
||||
val = parseInt($li.data("id"), 10);
|
||||
}
|
||||
else {
|
||||
var val = $li.data("id");
|
||||
val = $li.data("id");
|
||||
}
|
||||
if (val != self.get('value')) {
|
||||
this.view.recursive_save().done(function() {
|
||||
|
|
|
@ -171,11 +171,13 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
|||
current_date: new Date().toString('yyyy-MM-dd')
|
||||
// TODO: time, datetime, relativedelta
|
||||
});
|
||||
|
||||
var i;
|
||||
var pair;
|
||||
var expression;
|
||||
if (this.fonts) {
|
||||
for(var i=0, len=this.fonts.length; i<len; ++i) {
|
||||
var pair = this.fonts[i],
|
||||
font = pair[0],
|
||||
for(i=0, len=this.fonts.length; i<len; ++i) {
|
||||
pair = this.fonts[i];
|
||||
var font = pair[0];
|
||||
expression = pair[1];
|
||||
if (py.evaluate(expression, context).toJSON()) {
|
||||
switch(font) {
|
||||
|
@ -194,10 +196,10 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
|||
}
|
||||
|
||||
if (!this.colors) { return style; }
|
||||
for(var i=0, len=this.colors.length; i<len; ++i) {
|
||||
var pair = this.colors[i],
|
||||
color = pair[0],
|
||||
expression = pair[1];
|
||||
for(i=0, len=this.colors.length; i<len; ++i) {
|
||||
pair = this.colors[i];
|
||||
var color = pair[0];
|
||||
expression = pair[1];
|
||||
if (py.evaluate(expression, context).toJSON()) {
|
||||
return style += 'color: ' + color + ';';
|
||||
}
|
||||
|
@ -361,7 +363,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
|||
sort_by_column: function (e) {
|
||||
e.stopPropagation();
|
||||
var $column = $(e.currentTarget);
|
||||
var col_name = $column.data('id')
|
||||
var col_name = $column.data('id');
|
||||
var field = this.fields_view.fields[col_name];
|
||||
// test if the field is a function field with store=false, since it's impossible
|
||||
// for the server to sort those fields we desactivate the feature
|
||||
|
@ -394,7 +396,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
|||
|
||||
var total = dataset.size();
|
||||
var limit = this.limit() || total;
|
||||
if (total == 0)
|
||||
if (total === 0)
|
||||
this.$pager.hide();
|
||||
else
|
||||
this.$pager.css("display", "");
|
||||
|
@ -454,7 +456,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
|||
* @param {String} [view="page"] the view type to switch to
|
||||
*/
|
||||
select_record:function (index, view) {
|
||||
view = view || index == null ? 'form' : 'form';
|
||||
view = view || index === null || index === undefined ? 'form' : 'form';
|
||||
this.dataset.index = index;
|
||||
_.delay(_.bind(function () {
|
||||
this.do_switch_view(view);
|
||||
|
@ -503,7 +505,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
|||
var reloaded = $.Deferred();
|
||||
this.$el.find('.oe_list_content').append(
|
||||
this.groups.render(function () {
|
||||
if (self.dataset.index == null && self.records.length ||
|
||||
if ((self.dataset.index === null || self.dataset.index === undefined) && self.records.length ||
|
||||
self.dataset.index >= self.records.length) {
|
||||
self.dataset.index = 0;
|
||||
}
|
||||
|
@ -1459,7 +1461,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
|
|||
d = new $.Deferred(),
|
||||
page = this.datagroup.openable ? this.page : view.page;
|
||||
|
||||
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
|
||||
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name');
|
||||
var options = { offset: page * limit, limit: limit, context: {bin_size: true} };
|
||||
//TODO xmo: investigate why we need to put the setTimeout
|
||||
$.async_when().done(function() {
|
||||
|
@ -1548,20 +1550,21 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
|
|||
// if drag to 1st row (to = 0), start sequencing from 0
|
||||
// (exclusive lower bound)
|
||||
seq = to ? list.records.at(to - 1).get(seqname) : 0;
|
||||
while (++seq, record = list.records.at(index++)) {
|
||||
var fct = function (dataset, id, seq) {
|
||||
$.async_when().done(function () {
|
||||
var attrs = {};
|
||||
attrs[seqname] = seq;
|
||||
dataset.write(id, attrs);
|
||||
});
|
||||
};
|
||||
while (++seq, (record = list.records.at(index++))) {
|
||||
// write are independent from one another, so we can just
|
||||
// launch them all at the same time and we don't really
|
||||
// give a fig about when they're done
|
||||
// FIXME: breaks on o2ms (e.g. Accounting > Financial
|
||||
// Accounting > Taxes > Taxes, child tax accounts)
|
||||
// when synchronous (without setTimeout)
|
||||
(function (dataset, id, seq) {
|
||||
$.async_when().done(function () {
|
||||
var attrs = {};
|
||||
attrs[seqname] = seq;
|
||||
dataset.write(id, attrs);
|
||||
});
|
||||
}(dataset, record.get('id'), seq));
|
||||
fct(dataset, record.get('id'), seq);
|
||||
record.set(seqname, seq);
|
||||
}
|
||||
}
|
||||
|
@ -1574,7 +1577,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
|
|||
|
||||
this.datagroup.list(
|
||||
_(this.view.visible_columns).chain()
|
||||
.filter(function (column) { return column.tag === 'field' })
|
||||
.filter(function (column) { return column.tag === 'field';})
|
||||
.pluck('name').value(),
|
||||
function (groups) {
|
||||
$el[0].appendChild(
|
||||
|
@ -1619,7 +1622,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
|
|||
return {
|
||||
count: this.datagroup.length,
|
||||
values: this.datagroup.aggregates
|
||||
}
|
||||
};
|
||||
}
|
||||
return _(this.children).chain()
|
||||
.map(function (child) {
|
||||
|
@ -1856,7 +1859,7 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
|
|||
var instance_ = (records[i] instanceof Record) ? records[i] : new Record(records[i]);
|
||||
instance_.bind(null, this._onRecordEvent);
|
||||
this._byId[instance_.get('id')] = instance_;
|
||||
if (options.at == undefined) {
|
||||
if (options.at === undefined || options.at === null) {
|
||||
this.records.push(instance_);
|
||||
if (!options.silent) {
|
||||
this.trigger('add', this, instance_, this.records.length-1);
|
||||
|
@ -1898,7 +1901,8 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
|
|||
if (!_(this._proxies).isEmpty()) {
|
||||
var record = null;
|
||||
_(this._proxies).detect(function (proxy) {
|
||||
return record = proxy.get(id);
|
||||
record = proxy.get(id);
|
||||
return record;
|
||||
});
|
||||
return record;
|
||||
}
|
||||
|
@ -1912,10 +1916,11 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
|
|||
* @returns {Collection}
|
||||
*/
|
||||
proxy: function (section) {
|
||||
return this._proxies[section] = new Collection(null, {
|
||||
this._proxies[section] = new Collection(null, {
|
||||
parent: this,
|
||||
key: section
|
||||
}).bind(null, this._onRecordEvent);
|
||||
return this._proxies[section];
|
||||
},
|
||||
/**
|
||||
* @param {Array} [records]
|
||||
|
@ -1985,7 +1990,7 @@ var Collection = instance.web.Class.extend(/** @lends Collection# */{
|
|||
var record;
|
||||
for(var section in this._proxies) {
|
||||
if (!this._proxies.hasOwnProperty(section)) {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
if ((record = this._proxies[section].find(callback))) {
|
||||
return record;
|
||||
|
@ -2102,7 +2107,7 @@ instance.web.list.columns.for_ = function (id, field, node) {
|
|||
tag + '.'+ description.type,
|
||||
tag
|
||||
]);
|
||||
return new Type(id, node.tag, description)
|
||||
return new Type(id, node.tag, description);
|
||||
};
|
||||
|
||||
instance.web.list.Column = instance.web.Class.extend({
|
||||
|
@ -2265,7 +2270,7 @@ instance.web.list.Char = instance.web.list.Column.extend({
|
|||
_format: function (row_data, options) {
|
||||
var value = row_data[this.id].value;
|
||||
if (value && this.password === 'True') {
|
||||
return value.replace(/[\s\S]/g, _.escape(this.replacement))
|
||||
return value.replace(/[\s\S]/g, _.escape(this.replacement));
|
||||
}
|
||||
return this._super(row_data, options);
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ openerp.web.list_editable = function (instance) {
|
|||
make_empty_record: function (id) {
|
||||
var attrs = {id: id};
|
||||
_(this.columns).chain()
|
||||
.filter(function (x) { return x.tag === 'field'})
|
||||
.filter(function (x) { return x.tag === 'field';})
|
||||
.pluck('name')
|
||||
.each(function (field) { attrs[field] = false; });
|
||||
return new instance.web.list.Record(attrs);
|
||||
|
@ -260,7 +260,7 @@ openerp.web.list_editable = function (instance) {
|
|||
get_cells_for: function ($row) {
|
||||
var cells = {};
|
||||
$row.children('td').each(function (index, el) {
|
||||
cells[el.getAttribute('data-field')] = el
|
||||
cells[el.getAttribute('data-field')] = el;
|
||||
});
|
||||
return cells;
|
||||
},
|
||||
|
@ -346,7 +346,7 @@ openerp.web.list_editable = function (instance) {
|
|||
var record = self.records.get(attrs.id);
|
||||
if (!record) {
|
||||
// Record removed by third party during edition
|
||||
return
|
||||
return;
|
||||
}
|
||||
return self.reload_record(record);
|
||||
}
|
||||
|
@ -515,10 +515,6 @@ openerp.web.list_editable = function (instance) {
|
|||
};
|
||||
} else if (document.body.createTextRange) {
|
||||
throw new Error("Implement text range handling for MSIE");
|
||||
var sel = document.body.createTextRange();
|
||||
if (sel.parentElement() === el) {
|
||||
|
||||
}
|
||||
}
|
||||
// Element without selection ranges (select, div/@contenteditable)
|
||||
return null;
|
||||
|
@ -695,9 +691,9 @@ openerp.web.list_editable = function (instance) {
|
|||
var arch = edition_view.arch;
|
||||
if (!(arch && arch.children instanceof Array)) {
|
||||
throw new Error("Editor delegate's #edition_view must have a" +
|
||||
" non-empty arch")
|
||||
" non-empty arch");
|
||||
}
|
||||
if (!(arch.tag === "form")) {
|
||||
if (arch.tag !== "form") {
|
||||
throw new Error("Editor delegate's #edition_view must have a" +
|
||||
" 'form' root node");
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
|||
if (last) {
|
||||
last.hide();
|
||||
}
|
||||
var item = _.extend({
|
||||
item = _.extend({
|
||||
show: function(index) {
|
||||
this.widget.$el.show();
|
||||
},
|
||||
|
@ -423,7 +423,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
|||
|
||||
if (!(ClientWidget.prototype instanceof instance.web.Widget)) {
|
||||
var next;
|
||||
if (next = ClientWidget(this, action)) {
|
||||
if ((next = ClientWidget(this, action))) {
|
||||
return this.do_action(next, options);
|
||||
}
|
||||
return $.when();
|
||||
|
@ -459,7 +459,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
|||
action_id: action.id,
|
||||
context: action.context || {}
|
||||
}).done(function (action) {
|
||||
self.do_action(action, options)
|
||||
self.do_action(action, options);
|
||||
});
|
||||
},
|
||||
ir_actions_report_xml: function(action, options) {
|
||||
|
@ -478,8 +478,8 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
|||
var params = {
|
||||
action: JSON.stringify(action),
|
||||
token: new Date().getTime()
|
||||
}
|
||||
var url = self.session.url('/web/report', params)
|
||||
};
|
||||
var url = self.session.url('/web/report', params);
|
||||
instance.web.unblockUI();
|
||||
$('<a href="'+url+'" target="_blank"></a>')[0].click();
|
||||
return;
|
||||
|
@ -502,7 +502,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
|||
c.rpc_error.apply(c, arguments);
|
||||
d.reject();
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -677,7 +677,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
|
|||
this.$el.find('.oe_view_title_text:first').text(title);
|
||||
},
|
||||
add_breadcrumb: function(options) {
|
||||
var options = options || {};
|
||||
options = options || {};
|
||||
var self = this;
|
||||
var views = [this.active_view || this.views_src[0].view_type];
|
||||
this.on('switch_mode', self, function(mode) {
|
||||
|
@ -958,7 +958,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
|
|||
view_type : 'list',
|
||||
view_mode : 'list'
|
||||
});
|
||||
break;
|
||||
case 'edit':
|
||||
this.do_edit_resource($option.data('model'), $option.data('id'), { name : $option.text() });
|
||||
break;
|
||||
|
@ -1000,7 +999,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
|
|||
evt.currentTarget.selectedIndex = 0;
|
||||
},
|
||||
do_edit_resource: function(model, id, action) {
|
||||
var action = _.extend({
|
||||
action = _.extend({
|
||||
res_model : model,
|
||||
res_id : id,
|
||||
type : 'ir.actions.act_window',
|
||||
|
@ -1038,7 +1037,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
|
|||
},
|
||||
get_action_manager: function() {
|
||||
var cur = this;
|
||||
while (cur = cur.getParent()) {
|
||||
while ((cur = cur.getParent())) {
|
||||
if (cur instanceof instance.web.ActionManager) {
|
||||
return cur;
|
||||
}
|
||||
|
@ -1122,7 +1121,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
|
|||
self.$("[title]").tipsy({
|
||||
'html': true,
|
||||
'delayIn': 500,
|
||||
})
|
||||
});
|
||||
},
|
||||
/**
|
||||
* For each item added to the section:
|
||||
|
@ -1166,7 +1165,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
|
|||
label: items[i]['name'],
|
||||
action: items[i],
|
||||
classname: 'oe_sidebar_' + type
|
||||
}
|
||||
};
|
||||
}
|
||||
self.add_items(type=='print' ? 'print' : 'other', items);
|
||||
}
|
||||
|
@ -1177,7 +1176,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
|
|||
self.getParent().sidebar_eval_context().done(function (sidebar_eval_context) {
|
||||
var ids = self.getParent().get_selected_ids();
|
||||
var domain = self.getParent().get_active_domain();
|
||||
if (ids.length == 0) {
|
||||
if (ids.length === 0) {
|
||||
instance.web.dialog($("<div />").text(_t("You must choose at least one record.")), { title: _t("Warning"), modal: true });
|
||||
return false;
|
||||
}
|
||||
|
@ -1435,7 +1434,7 @@ instance.web.View = instance.web.Widget.extend({
|
|||
if (self.is_active()) {
|
||||
fn.apply(self, arguments);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
do_push_state: function(state) {
|
||||
if (this.getParent() && this.getParent().do_push_state) {
|
||||
|
@ -1546,9 +1545,10 @@ instance.web.xml_to_json = function(node, strip_whitespace) {
|
|||
children: _.compact(_.map(node.childNodes, function(node) {
|
||||
return instance.web.xml_to_json(node, strip_whitespace);
|
||||
})),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
instance.web.json_node_to_xml = function(node, human_readable, indent) {
|
||||
// For debugging purpose, this function will convert a json node back to xml
|
||||
indent = indent || 0;
|
||||
|
|
|
@ -459,7 +459,7 @@
|
|||
<tr>
|
||||
<td class="oe_leftbar" valign="top">
|
||||
<t t-set="debug" t-value="__debug__ ? '&debug' : ''"/>
|
||||
<a class="oe_logo" t-attf-href="/?ts=#{Date.now()}#{debug}">
|
||||
<a class="oe_logo" t-attf-href="/?#{debug}">
|
||||
<span class="oe_logo_edit">Edit Company data</span>
|
||||
<img t-att-src='widget.session.url("/web/binary/company_logo")'/>
|
||||
</a>
|
||||
|
|
|
@ -7,7 +7,7 @@ openerp.testing.section('Widget.proxy', {
|
|||
this.executed = true;
|
||||
}
|
||||
});
|
||||
var w = new W;
|
||||
var w = new W();
|
||||
var fn = w.proxy('exec');
|
||||
fn();
|
||||
ok(w.executed, 'should execute the named method in the right context');
|
||||
|
@ -18,7 +18,7 @@ openerp.testing.section('Widget.proxy', {
|
|||
this.executed = arg;
|
||||
}
|
||||
});
|
||||
var w = new W;
|
||||
var w = new W();
|
||||
var fn = w.proxy('exec');
|
||||
fn(42);
|
||||
ok(w.executed, "should execute the named method in the right context");
|
||||
|
@ -32,7 +32,7 @@ openerp.testing.section('Widget.proxy', {
|
|||
this.executed = 1;
|
||||
}
|
||||
});
|
||||
var w = new W;
|
||||
var w = new W();
|
||||
var fn = w.proxy('exec');
|
||||
W.include({
|
||||
exec: function () { this.executed = 2; }
|
||||
|
@ -43,14 +43,14 @@ openerp.testing.section('Widget.proxy', {
|
|||
});
|
||||
|
||||
test('(Function)', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({ }));
|
||||
var w = new (instance.web.Widget.extend({ }))();
|
||||
|
||||
var fn = w.proxy(function () { this.executed = true; });
|
||||
fn();
|
||||
ok(w.executed, "should set the function's context (like Function#bind)");
|
||||
});
|
||||
test('(Function)(*args)', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({ }));
|
||||
var w = new (instance.web.Widget.extend({ }))();
|
||||
|
||||
var fn = w.proxy(function (arg) { this.executed = arg; });
|
||||
fn(42);
|
||||
|
@ -79,7 +79,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
}
|
||||
}, function (test) {
|
||||
test('no template, default', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({ }));
|
||||
var w = new (instance.web.Widget.extend({ }))();
|
||||
|
||||
var $original = w.$el;
|
||||
ok($original, "should initially have a root element");
|
||||
|
@ -96,7 +96,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
test('no template, custom tag', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
tagName: 'ul'
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
equal(w.el.nodeName, 'UL', "should have generated the custom element tag");
|
||||
|
@ -104,7 +104,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
test('no template, @id', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
id: 'foo'
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
equal(w.el.attributes.length, 1, "should have one attribute");
|
||||
|
@ -114,7 +114,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
test('no template, @className', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
className: 'oe_some_class'
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
equal(w.el.className, 'oe_some_class', "should have the right property");
|
||||
|
@ -129,7 +129,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
'clark': 'gable',
|
||||
'spoiler': 'snape kills dumbledore'
|
||||
}
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
equal(w.el.attributes.length, 5, "should have all the specified attributes");
|
||||
|
@ -150,7 +150,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
test('template', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template'
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
equal(w.el.nodeName, 'OL');
|
||||
|
@ -160,7 +160,7 @@ openerp.testing.section('Widget.renderElement', {
|
|||
test('repeated', { asserts: 4 }, function (instance, $fix) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template-value'
|
||||
}));
|
||||
}))();
|
||||
w.value = 42;
|
||||
return w.appendTo($fix)
|
||||
.done(function () {
|
||||
|
@ -194,7 +194,7 @@ openerp.testing.section('Widget.$', {
|
|||
test('basic-alias', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template'
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
ok(w.$('li:eq(3)').is(w.$el.find('li:eq(3)')),
|
||||
|
@ -226,13 +226,13 @@ openerp.testing.section('Widget.events', {
|
|||
events: {
|
||||
'click': function () {
|
||||
a[0] = true;
|
||||
strictEqual(this, w, "should trigger events in widget")
|
||||
strictEqual(this, w, "should trigger events in widget");
|
||||
},
|
||||
'click li.class-3': 'class3',
|
||||
'change input': function () { a[2] = true; }
|
||||
},
|
||||
class3: function () { a[1] = true; }
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
|
||||
w.$el.click();
|
||||
|
@ -248,9 +248,9 @@ openerp.testing.section('Widget.events', {
|
|||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template',
|
||||
events: { 'click li': function () { clicked = true; } }
|
||||
}));
|
||||
}))();
|
||||
w.renderElement();
|
||||
w.$el.on('click', 'li', function () { newclicked = true });
|
||||
w.$el.on('click', 'li', function () { newclicked = true; });
|
||||
|
||||
w.$('li').click();
|
||||
ok(clicked, "should trigger bound events");
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
openerp.testing.section('data.model.group_by', {
|
||||
rpc: 'mock',
|
||||
dependencies: ['web.data'],
|
||||
}, function (test) {
|
||||
var group_result = [{
|
||||
bar: 3, bar_count: 5, __context: {}, __domain: [['bar', '=', 3]],
|
||||
}, {
|
||||
bar: 5, bar_count: 3, __context: {}, __domain: [['bar', '=', 5]],
|
||||
}, {
|
||||
bar: 8, bar_count: 0, __context: {}, __domain: [['bar', '=', 8]],
|
||||
}];
|
||||
test('basic', {asserts: 7}, function (instance, $fix, mock) {
|
||||
var m = new instance.web.Model('foo');
|
||||
mock('foo:read_group', function (args, kwargs) {
|
||||
deepEqual(kwargs.fields, ['bar'],
|
||||
"should read grouping field");
|
||||
deepEqual(kwargs.groupby, ['bar'],
|
||||
"should have single grouping field");
|
||||
return group_result;
|
||||
});
|
||||
mock('/web/dataset/search_read', function (args) {
|
||||
deepEqual(args.params.domain, [['bar', '=', 3]],
|
||||
"should have domain matching that of group_by result");
|
||||
return {records: [
|
||||
{bar: 3, id: 1},
|
||||
{bar: 3, id: 2},
|
||||
{bar: 3, id: 4},
|
||||
{bar: 3, id: 8},
|
||||
{bar: 3, id: 16}
|
||||
], length: 5};
|
||||
});
|
||||
|
||||
return m.query().group_by('bar')
|
||||
.then(function (groups) {
|
||||
ok(groups, "should have data");
|
||||
equal(groups.length, 3, "should have three results");
|
||||
var first = groups[0];
|
||||
ok(first.attributes.has_children, "should have children");
|
||||
return first.query().all();
|
||||
}).done(function (first) {
|
||||
equal(first.length, 5, "should have 5 records");
|
||||
});
|
||||
});
|
||||
test('noleaf', {asserts: 5}, function (instance, $fix, mock) {
|
||||
var m = new instance.web.Model('foo', {group_by_no_leaf: true});
|
||||
mock('foo:read_group', function (args, kwargs) {
|
||||
deepEqual(kwargs.fields, ['bar'],
|
||||
"should read grouping field");
|
||||
deepEqual(kwargs.groupby, ['bar'],
|
||||
"should have single grouping field");
|
||||
|
||||
return group_result;
|
||||
});
|
||||
return m.query().group_by('bar')
|
||||
.then(function (groups) {
|
||||
ok(groups, "should have data");
|
||||
equal(groups.length, 3, "should have three results");
|
||||
ok(!groups[0].attributes.has_children,
|
||||
"should not have children because no_leaf");
|
||||
});
|
||||
});
|
||||
test('nogroup', {rpc: false}, function (instance, $f, mock) {
|
||||
var m = new instance.web.Model('foo');
|
||||
strictEqual(m.query().group_by(), null, "should not group");
|
||||
});
|
||||
test('empty.noleaf', {asserts: 1}, function (instance, $f, mock) {
|
||||
var m = new instance.web.Model('foo', {group_by_no_leaf: true});
|
||||
mock('foo:read_group', function (args, kwargs) {
|
||||
return [{__context: [], __domain: []}];
|
||||
});
|
||||
return m.query().group_by().done(function (groups) {
|
||||
strictEqual(groups.length, 1,
|
||||
"should generate a single fake-ish group");
|
||||
});
|
||||
});
|
||||
});
|
|
@ -9,9 +9,9 @@ openerp.testing.section('eval.types', {
|
|||
return function (expr, func, message) {
|
||||
// evaluate expr between two calls to new Date(), and check that
|
||||
// the result is between the transformed dates
|
||||
var d0 = new Date;
|
||||
var d0 = new Date();
|
||||
var result = py.eval(expr, context);
|
||||
var d1 = new Date;
|
||||
var d1 = new Date();
|
||||
ok(func(d0) <= result && result <= func(d1), message);
|
||||
};
|
||||
};
|
||||
|
@ -118,7 +118,7 @@ openerp.testing.section('eval.types', {
|
|||
// Issue #11576
|
||||
eq('td(999999999, 86399, 999999) - td(999999999, 86399, 999998)', 'td(0, 0, 1)');
|
||||
eq('td(999999999, 1, 1) - td(999999999, 1, 0)',
|
||||
'td(0, 0, 1)')
|
||||
'td(0, 0, 1)');
|
||||
});
|
||||
test('timedelta.test_basic_attributes', function (instance) {
|
||||
var ctx = instance.web.pyeval.context();
|
||||
|
@ -264,7 +264,7 @@ openerp.testing.section('eval.types', {
|
|||
py.eval("(datetime.date(2012, 2, 15) + relativedelta(days=-1)).strftime('%Y-%m-%d 23:59:59')",
|
||||
instance.web.pyeval.context()),
|
||||
"2012-02-14 23:59:59");
|
||||
})
|
||||
});
|
||||
});
|
||||
openerp.testing.section('eval.edc', {
|
||||
dependencies: ['web.data'],
|
||||
|
|
|
@ -126,8 +126,8 @@ openerp.testing.section('web-formats', {
|
|||
var str = "134,112.1234";
|
||||
var val = instance.web.parse_value(str, {type:"float"});
|
||||
equal(val, 134112.1234);
|
||||
var str = "-134,112.1234";
|
||||
var val = instance.web.parse_value(str, {type:"float"});
|
||||
str = "-134,112.1234";
|
||||
val = instance.web.parse_value(str, {type:"float"});
|
||||
equal(val, -134112.1234);
|
||||
_.extend(instance.web._t.database.parameters, {
|
||||
decimal_point: ',',
|
||||
|
|
|
@ -49,7 +49,7 @@ openerp.testing.section('editor', {
|
|||
readonly: field.readonly
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
return {
|
||||
arch: {
|
||||
|
@ -108,7 +108,7 @@ openerp.testing.section('editor', {
|
|||
.done(function (record) {
|
||||
ok(!e.is_editing(), "should have stopped editing");
|
||||
equal(record.id, 42, "should have newly created id");
|
||||
})
|
||||
});
|
||||
});
|
||||
test('toggle-edition-cancel', { asserts: 2 }, function (instance, $fix) {
|
||||
var e = new instance.web.list.Editor({
|
||||
|
@ -131,7 +131,7 @@ openerp.testing.section('editor', {
|
|||
.done(function (record) {
|
||||
ok(!e.is_editing(), "should have stopped editing");
|
||||
ok(!record.id, "should have no id");
|
||||
})
|
||||
});
|
||||
});
|
||||
test('toggle-save-required', {
|
||||
asserts: 2,
|
||||
|
|
|
@ -7,7 +7,7 @@ openerp.testing.section('list.events', {
|
|||
}
|
||||
function Cls() {}
|
||||
Cls.prototype = o;
|
||||
return new Cls;
|
||||
return new Cls();
|
||||
};
|
||||
test('Simple event triggering', function (instance) {
|
||||
var e = create(instance.web.list.Events), passed = false;
|
||||
|
@ -23,9 +23,9 @@ openerp.testing.section('list.events', {
|
|||
});
|
||||
test('Propagate trigger params', function (instance) {
|
||||
var e = create(instance.web.list.Events), p = false;
|
||||
e.bind(null, function (_, param) { p = param });
|
||||
e.bind(null, function (_, param) { p = param; });
|
||||
e.trigger('foo', true);
|
||||
strictEqual(p, true)
|
||||
strictEqual(p, true);
|
||||
});
|
||||
test('Bind multiple callbacks', function (instance) {
|
||||
var e = create(instance.web.list.Events), count;
|
||||
|
@ -53,7 +53,7 @@ openerp.testing.section('list.events', {
|
|||
method: function () { this.trigger('e'); }
|
||||
});
|
||||
cls.include(instance.web.list.Events);
|
||||
var i = new cls, triggered = false;
|
||||
var i = new cls(), triggered = false;
|
||||
|
||||
i.bind('e', function () { triggered = true; });
|
||||
i.method();
|
||||
|
@ -97,7 +97,7 @@ openerp.testing.section('list.records', {
|
|||
test('Change all the things', function (instance) {
|
||||
var r = new instance.web.list.Record(), changed = false, field;
|
||||
r.bind('change', function () { changed = true; });
|
||||
r.bind(null, function (e) { field = field || e.split(':')[1]});
|
||||
r.bind(null, function (e) { field = field || e.split(':')[1]; });
|
||||
r.set('foo', 1);
|
||||
strictEqual(r.get('foo'), 1);
|
||||
ok(changed);
|
||||
|
|
|
@ -122,6 +122,6 @@ openerp.testing.section('misordered resolution managemeng', {
|
|||
ok(!fail2);
|
||||
done.resolve();
|
||||
}, 400);
|
||||
return $.when(d1, d2, done)
|
||||
return $.when(d1, d2, done);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@ openerp.testing.section('search.query', {
|
|||
dependencies: ['web.search']
|
||||
}, function (test) {
|
||||
test('Adding a facet to the query creates a facet and a value', function (instance) {
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
var field = {};
|
||||
query.add({
|
||||
category: 'Foo',
|
||||
|
@ -16,7 +16,7 @@ openerp.testing.section('search.query', {
|
|||
deepEqual(facet.get('values'), [{label: 'Value', value: 3}]);
|
||||
});
|
||||
test('Adding two facets', function (instance) {
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
query.add([
|
||||
{ category: 'Foo', field: {}, values: [{label: 'Value', value: 3}] },
|
||||
{ category: 'Bar', field: {}, values: [{label: 'Value 2', value: 4}] }
|
||||
|
@ -27,7 +27,7 @@ openerp.testing.section('search.query', {
|
|||
equal(query.at(1).values.length, 1);
|
||||
});
|
||||
test('If a facet already exists, add values to it', function (instance) {
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
var field = {};
|
||||
query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
query.add({category: 'A', field: field, values: [{label: 'V2', value: 1}]});
|
||||
|
@ -40,18 +40,18 @@ openerp.testing.section('search.query', {
|
|||
]);
|
||||
});
|
||||
test('Facet being implicitly changed should trigger change, not add', function (instance) {
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
var field = {}, added = false, changed = false;
|
||||
query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
query.on('add', function () { added = true; })
|
||||
.on('change', function () { changed = true });
|
||||
.on('change', function () { changed = true; });
|
||||
query.add({category: 'A', field: field, values: [{label: 'V2', value: 1}]});
|
||||
|
||||
ok(!added, "query.add adding values to a facet should not trigger an add");
|
||||
ok(changed, "query.add adding values to a facet should not trigger a change");
|
||||
});
|
||||
test('Toggling a facet, value which does not exist should add it', function (instance) {
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
var field = {};
|
||||
query.toggle({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
|
||||
|
@ -63,7 +63,7 @@ openerp.testing.section('search.query', {
|
|||
});
|
||||
test('Toggling a facet which exists with a value which does not should add the value to the facet', function (instance) {
|
||||
var field = {};
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
query.toggle({category: 'A', field: field, values: [{label: 'V2', value: 1}]});
|
||||
|
||||
|
@ -77,7 +77,7 @@ openerp.testing.section('search.query', {
|
|||
});
|
||||
test('Toggling a facet which exists with a value which does as well should remove the value from the facet', function (instance) {
|
||||
var field = {};
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
query.add({category: 'A', field: field, values: [{label: 'V2', value: 1}]});
|
||||
|
||||
|
@ -92,7 +92,7 @@ openerp.testing.section('search.query', {
|
|||
});
|
||||
test('Toggling off the last value of a facet should remove the facet', function (instance) {
|
||||
var field = {};
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
|
||||
query.toggle({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
|
@ -101,7 +101,7 @@ openerp.testing.section('search.query', {
|
|||
});
|
||||
test('Intermediate emptiness should not remove the facet', function (instance) {
|
||||
var field = {};
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]});
|
||||
|
||||
query.toggle({category: 'A', field: field, values: [
|
||||
|
@ -118,7 +118,7 @@ openerp.testing.section('search.query', {
|
|||
});
|
||||
|
||||
test('Reseting with multiple facets should still work to load defaults', function (instance) {
|
||||
var query = new instance.web.search.SearchQuery;
|
||||
var query = new instance.web.search.SearchQuery();
|
||||
var field = {};
|
||||
query.reset([
|
||||
{category: 'A', field: field, values: [{label: 'V1', value: 0}]},
|
||||
|
@ -129,7 +129,7 @@ openerp.testing.section('search.query', {
|
|||
deepEqual(query.at(0).get('values'), [
|
||||
{label: 'V1', value: 0},
|
||||
{label: 'V2', value: 1}
|
||||
])
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -346,7 +346,7 @@ openerp.testing.section('search.defaults', {
|
|||
{attrs: {name: 'dummy', string: 'Dummy'}},
|
||||
{relation: 'dummy.model.name'},
|
||||
view);
|
||||
mock('dummy.model.name:name_get', function () { return [] });
|
||||
mock('dummy.model.name:name_get', function () { return []; });
|
||||
return f.facet_for_defaults({dummy: id})
|
||||
.done(function (facet) {
|
||||
ok(!facet, "an invalid m2o default should yield a non-facet");
|
||||
|
@ -358,9 +358,9 @@ openerp.testing.section('search.defaults', {
|
|||
{attrs: {name: 'dummy', string: 'Dummy'}},
|
||||
{relation: 'dummy.model.name'},
|
||||
view);
|
||||
raises(function () { f.facet_for_defaults({dummy: [6, 7]}) },
|
||||
raises(function () { f.facet_for_defaults({dummy: [6, 7]}); },
|
||||
"should not accept multiple default values");
|
||||
})
|
||||
});
|
||||
});
|
||||
openerp.testing.section('search.completions', {
|
||||
dependencies: ['web.search'],
|
||||
|
@ -614,6 +614,59 @@ openerp.testing.section('search.completions', {
|
|||
{relation: 'dummy.model'}, view);
|
||||
return f.complete("bob");
|
||||
});
|
||||
test('Integer: invalid', {asserts: 1}, function (instance) {
|
||||
var view = {inputs: []};
|
||||
var f = new instance.web.search.IntegerField(
|
||||
{attrs: {string: "Dummy"}}, {}, view);
|
||||
return f.complete("qux")
|
||||
.done(function (completions) {
|
||||
ok(!completions, "non-number => no completion");
|
||||
});
|
||||
});
|
||||
test('Integer: non-zero', {asserts: 5}, function (instance) {
|
||||
var view = {inputs: []};
|
||||
var f = new instance.web.search.IntegerField(
|
||||
{attrs: {string: "Dummy"}}, {}, view);
|
||||
return f.complete("-2")
|
||||
.done(function (completions) {
|
||||
equal(completions.length, 1, "number fields provide 1 completion only");
|
||||
var facet = new instance.web.search.Facet(completions[0].facet);
|
||||
equal(facet.get('category'), f.attrs.string);
|
||||
equal(facet.get('field'), f);
|
||||
var value = facet.values.at(0);
|
||||
equal(value.get('label'), "-2");
|
||||
equal(value.get('value'), -2);
|
||||
});
|
||||
});
|
||||
test('Integer: zero', {asserts: 3}, function (instance) {
|
||||
var view = {inputs: []};
|
||||
var f = new instance.web.search.IntegerField(
|
||||
{attrs: {string: "Dummy"}}, {}, view);
|
||||
return f.complete("0")
|
||||
.done(function (completions) {
|
||||
equal(completions.length, 1, "number fields provide 1 completion only");
|
||||
var facet = new instance.web.search.Facet(completions[0].facet);
|
||||
var value = facet.values.at(0);
|
||||
equal(value.get('label'), "0");
|
||||
equal(value.get('value'), 0);
|
||||
});
|
||||
});
|
||||
test('Float: non-zero', {asserts: 5}, function (instance) {
|
||||
var view = {inputs: []};
|
||||
var f = new instance.web.search.FloatField(
|
||||
{attrs: {string: "Dummy"}}, {}, view);
|
||||
return f.complete("42.37")
|
||||
.done(function (completions) {
|
||||
equal(completions.length, 1, "float fields provide 1 completion only");
|
||||
var facet = new instance.web.search.Facet(completions[0].facet);
|
||||
equal(facet.get('category'), f.attrs.string);
|
||||
equal(facet.get('field'), f);
|
||||
var value = facet.values.at(0);
|
||||
equal(value.get('label'), "42.37");
|
||||
equal(value.get('value'), 42.37);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
openerp.testing.section('search.serialization', {
|
||||
dependencies: ['web.search'],
|
||||
|
@ -651,7 +704,7 @@ openerp.testing.section('search.serialization', {
|
|||
|
||||
ok(!got_groupby, "no facet, should not have fetched groupby");
|
||||
ok(_(gs).isEmpty(), "groupby list should be empty");
|
||||
})
|
||||
});
|
||||
});
|
||||
test('London, calling', {asserts: 8}, function (instance, $fix) {
|
||||
var got_domain = false, got_context = false, got_groupby = false;
|
||||
|
@ -686,7 +739,7 @@ openerp.testing.section('search.serialization', {
|
|||
|
||||
ok(got_groupby, "should have fetched groupby");
|
||||
ok(_(gs).isEmpty(), "groupby list should be empty");
|
||||
})
|
||||
});
|
||||
});
|
||||
test('Generate domains', {asserts: 1}, function (instance, $fix) {
|
||||
var view = makeSearchView(instance, {
|
||||
|
@ -1065,7 +1118,7 @@ openerp.testing.section('search.groupby', {
|
|||
'<filter string="Baz" context="{\'group_by\': \'baz\'}"/>',
|
||||
'</search>'
|
||||
].join(''),
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}, function (instance, $fix) {
|
||||
|
@ -1076,7 +1129,7 @@ openerp.testing.section('search.groupby', {
|
|||
equal(view.inputs.length, 7,
|
||||
'should have 7 inputs total');
|
||||
var group = _.find(view.inputs, function (f) {
|
||||
return f instanceof instance.web.search.GroupbyGroup
|
||||
return f instanceof instance.web.search.GroupbyGroup;
|
||||
});
|
||||
ok(group, "should have a GroupbyGroup input");
|
||||
strictEqual(group.getParent(), view,
|
||||
|
@ -1095,7 +1148,7 @@ openerp.testing.section('search.groupby', {
|
|||
deepEqual(results.groupbys, [
|
||||
"{'group_by': 'foo'}",
|
||||
"{'group_by': 'baz'}"
|
||||
], "should have sequence of contexts")
|
||||
], "should have sequence of contexts");
|
||||
});
|
||||
});
|
||||
test('unified multiple groupby groups', {
|
||||
|
@ -1114,7 +1167,7 @@ openerp.testing.section('search.groupby', {
|
|||
'<filter string="Baz" context="{\'group_by\': \'baz\'}"/>',
|
||||
'</search>'
|
||||
].join(''),
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}, function (instance, $fix) {
|
||||
|
@ -1125,7 +1178,7 @@ openerp.testing.section('search.groupby', {
|
|||
equal(view.inputs.length, 9, "should have 9 inputs total");
|
||||
|
||||
var groups = _.filter(view.inputs, function (f) {
|
||||
return f instanceof instance.web.search.GroupbyGroup
|
||||
return f instanceof instance.web.search.GroupbyGroup;
|
||||
});
|
||||
equal(groups.length, 3, "should have 3 GroupbyGroups");
|
||||
|
||||
|
@ -1169,7 +1222,7 @@ openerp.testing.section('search.filters.saved', {
|
|||
"displayed label should be the name of the filter");
|
||||
equal(values.at(0).get('value'), null,
|
||||
"should have no value set");
|
||||
})
|
||||
});
|
||||
});
|
||||
test('removal', {asserts: 1}, function (instance, $fix, mock) {
|
||||
var view = makeSearchView(instance);
|
||||
|
@ -1361,7 +1414,7 @@ openerp.testing.section('search.invisible', {
|
|||
}, ['<search>',
|
||||
'<field name="field0"/>',
|
||||
'<field name="field1" modifiers="{"invisible": true}"/>',
|
||||
'</search>'].join());
|
||||
'</search>'].join(''));
|
||||
return view.appendTo($fix)
|
||||
.then(function () {
|
||||
var done = $.Deferred();
|
||||
|
@ -1380,7 +1433,7 @@ openerp.testing.section('search.invisible', {
|
|||
'<search>',
|
||||
'<filter string="filter 0"/>',
|
||||
'<filter string="filter 1" modifiers="{"invisible": true}"/>',
|
||||
'</search>'].join());
|
||||
'</search>'].join(''));
|
||||
return view.appendTo($fix)
|
||||
.then(function () {
|
||||
var $fs = $fix.find('.oe_searchview_filters ul');
|
||||
|
@ -1400,6 +1453,26 @@ openerp.testing.section('search.invisible', {
|
|||
return done;
|
||||
});
|
||||
});
|
||||
test('invisible-previous-sibling', {asserts: 3}, function (instance, $fix, mock) {
|
||||
var view = makeView(instance, mock, {}, [
|
||||
'<search>',
|
||||
'<filter string="filter 0" context="{"test": 0}"/>',
|
||||
'<filter string="filter 1" modifiers="{"invisible": true}" context="{"test": 1}"/>',
|
||||
'<filter string="filter 2" modifiers="{"invisible": true}" context="{"test": 2}"/>',
|
||||
'<filter string="filter 3" context="{"test": 3}"/>',
|
||||
'</search>'].join(''));
|
||||
return view.appendTo($fix)
|
||||
.done(function () {
|
||||
// Select filter 3
|
||||
$fix.find('.oe_searchview_filters ul li:contains("filter 3")').click();
|
||||
equal(view.query.length, 1, "should have selected a filter");
|
||||
var facet = view.query.at(0);
|
||||
strictEqual(facet.values.at(0).get('label'), "filter 3",
|
||||
"should have correctly labelled the facet");
|
||||
deepEqual(view.build_search_data().contexts, [{test: 3}],
|
||||
"should have built correct context");
|
||||
});
|
||||
});
|
||||
// Invisible filter groups should not appear in the drawer
|
||||
// Group invisibility should be inherited by children
|
||||
test('group-invisibility', {asserts: 6}, function (instance, $fix, mock) {
|
||||
|
|
|
@ -21,7 +21,7 @@ openerp.testing.section('testing.stack', function (test) {
|
|||
return s.execute(function () {
|
||||
return $.when(42);
|
||||
}).then(function (val) {
|
||||
strictEqual(val, 42, "should return the handler value")
|
||||
strictEqual(val, 42, "should return the handler value");
|
||||
});
|
||||
});
|
||||
test('direct, deferred, failure', {asserts: 1}, function () {
|
||||
|
|
Loading…
Reference in New Issue