diff options
| author | Jiten (OpenERP) <jra@tinyerp.com> | 2012-11-19 11:11:38 +0530 |
|---|---|---|
| committer | Jiten (OpenERP) <jra@tinyerp.com> | 2012-11-19 11:11:38 +0530 |
| commit | 4346af9c96ddc0e88d2d55d47ee0c4e21865aa2d (patch) | |
| tree | 24feb522a8d01a5babe5a5a6fde7cc1c77b7de25 | |
| parent | 3646b669516f78aa0a1be69ca8a241468cc9d98b (diff) | |
| parent | 37209eb5e76a7b373a0f302e1f62be32fd2f37d2 (diff) | |
[MERGE] Merged trunk.
bzr revid: jra@tinyerp.com-20121119054138-lkrx5jo1tgbr71ek
326 files changed, 4876 insertions, 2760 deletions
diff --git a/.bzrignore b/.bzrignore index 8531ad42bbb..1e0564801ab 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,19 +1,14 @@ -.*.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/* +RE:^bin/ +RE:^dist/ +RE:^include/ + +RE:^share/ +RE:^man/ +RE:^lib/ + +RE:^addons/\w+/doc/_build/ diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 51712954c53..d83636de0f9 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -1,6 +1,7 @@ { 'name': 'Web', 'category': 'Hidden', + 'version': '7.0.1.0', 'description': """ OpenERP Web core module. @@ -38,8 +39,9 @@ This module provides the core of the OpenERP Web Client. "static/lib/underscore/underscore.string.js", "static/lib/backbone/backbone.js", "static/lib/cleditor/jquery.cleditor.js", - "static/lib/py.js/lib/py.js", + "static/lib/py.js/lib/py.js", "static/src/js/boot.js", + "static/src/js/testing.js", "static/src/js/corelib.js", "static/src/js/coresetup.js", "static/src/js/dates.js", @@ -67,4 +69,21 @@ This module provides the core of the OpenERP Web Client. 'qweb' : [ "static/src/xml/*.xml", ], + 'test': [ + "static/test/testing.js", + "static/test/class.js", + "static/test/registry.js", + "static/test/form.js", + "static/test/list-utils.js", + "static/test/formats.js", + "static/test/rpc.js", + "static/test/evals.js", + "static/test/search.js", + "static/test/Widget.js", + "static/test/list.js", + "static/test/list-editable.js", + "static/test/mutex.js" + ], + 'bootstrap': True, + 'twitter': False, } diff --git a/addons/web/controllers/__init__.py b/addons/web/controllers/__init__.py index 12a7e529b67..74c27518ece 100644 --- a/addons/web/controllers/__init__.py +++ b/addons/web/controllers/__init__.py @@ -1 +1,2 @@ from . import main +from . import testing diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index ad8d91ed1dd..fb7b45a4056 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -81,57 +81,6 @@ def rjsmin(script): ).strip() return result -def sass2scss(src): - # Validated by diff -u of sass2scss against: - # sass-convert -F sass -T scss openerp.sass openerp.scss - block = [] - sass = ('', block) - reComment = re.compile(r'//.*$') - reIndent = re.compile(r'^\s+') - reIgnore = re.compile(r'^\s*(//.*)?$') - reFixes = { re.compile(r'\(\((.*)\)\)') : r'(\1)', } - lastLevel = 0 - prevBlocks = {} - for l in src.split('\n'): - l = l.rstrip() - if reIgnore.search(l): continue - l = reComment.sub('', l) - l = l.rstrip() - indent = reIndent.match(l) - level = indent.end() if indent else 0 - l = l[level:] - if level>lastLevel: - prevBlocks[lastLevel] = block - newBlock = [] - block[-1] = (block[-1], newBlock) - block = newBlock - elif level<lastLevel: - block = prevBlocks[level] - lastLevel = level - if not l: continue - # Fixes - for ereg, repl in reFixes.items(): - l = ereg.sub(repl if type(repl)==str else repl(), l) - block.append(l) - - def write(sass, level=-1): - out = "" - indent = ' '*level - if type(sass)==tuple: - if level>=0: - out += indent+sass[0]+" {\n" - for e in sass[1]: - out += write(e, level+1) - if level>=0: - out = out.rstrip(" \n") - out += ' }\n' - if level==0: - out += "\n" - else: - out += indent+sass+";\n" - return out - return write(sass) - def db_list(req): dbs = [] proxy = req.session.proxy("db") @@ -142,6 +91,17 @@ def db_list(req): dbs = [i for i in dbs if re.match(r, i)] return dbs +def db_monodb(req): + # if only one db is listed returns it else return False + try: + dbs = db_list(req) + if len(dbs) == 1: + return dbs[0] + except xmlrpclib.Fault: + # ignore access denied + pass + return False + def module_topological_sort(modules): """ Return a list of module names sorted so that their dependencies of the modules are listed before the module itself @@ -231,22 +191,14 @@ def module_installed_bypass_session(dbname): def module_boot(req): server_wide_modules = openerp.conf.server_wide_modules or ['web'] - return [m for m in server_wide_modules if m in openerpweb.addons_manifest] - # TODO the following will be enabled once we separate the module code and translation loading serverside = [] dbside = [] for i in server_wide_modules: if i in openerpweb.addons_manifest: serverside.append(i) - # if only one db load every module at boot - dbs = [] - try: - dbs = db_list(req) - except xmlrpclib.Fault: - # ignore access denied - pass - if len(dbs) == 1: - dbside = module_installed_bypass_session(dbs[0]) + monodb = db_monodb(req) + if monodb: + dbside = module_installed_bypass_session(monodb) dbside = [i for i in dbside if i not in serverside] addons = serverside + dbside return addons @@ -306,10 +258,20 @@ def concat_files(file_list, reader=None, intersperse=""): files_concat = intersperse.join(files_content) return files_concat, checksum.hexdigest() +concat_js_cache = {} + def concat_js(file_list): content, checksum = concat_files(file_list, intersperse=';') - content = rjsmin(content) - return content, checksum + if checksum in concat_js_cache: + content = concat_js_cache[checksum] + else: + content = rjsmin(content) + concat_js_cache[checksum] = content + return content, checksum + +def fs2web(path): + """convert FS path into web path""" + return '/'.join(path.split(os.path.sep)) def manifest_glob(req, addons, key): if addons is None: @@ -326,7 +288,7 @@ def manifest_glob(req, addons, key): globlist = manifest.get(key, []) for pattern in globlist: for path in glob.glob(os.path.normpath(os.path.join(addons_path, addon, pattern))): - r.append((path, path[len(addons_path):])) + r.append((path, fs2web(path[len(addons_path):]))) return r def manifest_list(req, mods, extension): @@ -549,7 +511,7 @@ def _local_web_translations(trans_file): messages.append({'id': x.id, 'string': x.string}) return messages -def from_elementtree(el, preserve_whitespaces=False): +def xml2json_from_elementtree(el, preserve_whitespaces=False): """ xml2json-direct Simple and straightforward XML-to-JSON converter in Python New BSD Licensed @@ -569,13 +531,12 @@ def from_elementtree(el, preserve_whitespaces=False): if el.text and (preserve_whitespaces or el.text.strip() != ''): kids.append(el.text) for kid in el: - kids.append(from_elementtree(kid, preserve_whitespaces)) + kids.append(xml2json_from_elementtree(kid, preserve_whitespaces)) if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''): kids.append(kid.tail) res["children"] = kids return res - def content_disposition(filename, req): filename = filename.encode('utf8') escaped = urllib2.quote(filename) @@ -612,8 +573,7 @@ html_template = """<!DOCTYPE html> </head> <body> <!--[if lte IE 8]> - <script type="text/javascript" - src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script> + <script src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script> <script> var test = function() { CFInstall.check({ @@ -687,8 +647,7 @@ class WebClient(openerpweb.Controller): data = fp.read().decode('utf-8') path = file_map[f] - # convert FS path into web path - web_dir = '/'.join(os.path.dirname(path).split(os.path.sep)) + web_dir = os.path.dirname(path) data = re.sub( rx_import, @@ -741,21 +700,20 @@ class WebClient(openerpweb.Controller): until we have established a valid session. This is meant only for translating the login page and db management chrome, using the browser's language. """ - lang = req.httprequest.accept_languages.best or 'en' # For performance reasons we only load a single translation, so for # sub-languages (that should only be partially translated) we load the # main language PO instead - that should be enough for the login screen. - if '-' in lang: # RFC2616 uses '-' separators for sublanguages - lang = lang.split('-')[0] + lang = req.lang.split('_')[0] translations_per_module = {} for addon_name in mods: - addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] - f_name = os.path.join(addons_path, addon_name, "i18n", lang + ".po") - if not os.path.exists(f_name): - continue - translations_per_module[addon_name] = {'messages': _local_web_translations(f_name)} - + if openerpweb.addons_manifest[addon_name].get('bootstrap'): + addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] + f_name = os.path.join(addons_path, addon_name, "i18n", lang + ".po") + if not os.path.exists(f_name): + continue + translations_per_module[addon_name] = {'messages': _local_web_translations(f_name)} + return {"modules": translations_per_module, "lang_parameters": None} @@ -814,21 +772,36 @@ class Database(openerpweb.Controller): @openerpweb.jsonrequest def get_list(self, req): - dbs = db_list(req) - return {"db_list": dbs} + return db_list(req) @openerpweb.jsonrequest def create(self, req, fields): params = dict(map(operator.itemgetter('name', 'value'), fields)) - create_attrs = ( + return req.session.proxy("db").create_database( params['super_admin_pwd'], params['db_name'], bool(params.get('demo_data')), params['db_lang'], - params['create_admin_pwd'] + params['create_admin_pwd']) + + @openerpweb.jsonrequest + def duplicate(self, req, fields): + params = dict(map(operator.itemgetter('name', 'value'), fields)) + return req.session.proxy("db").duplicate_database( + params['super_admin_pwd'], + params['db_original_name'], + params['db_name']) + + @openerpweb.jsonrequest + def duplicate(self, req, fields): + params = dict(map(operator.itemgetter('name', 'value'), fields)) + duplicate_attrs = ( + params['super_admin_pwd'], + params['db_original_name'], + params['db_name'], ) - return req.session.proxy("db").create_database(*create_attrs) + return req.session.proxy("db").duplicate_database(*duplicate_attrs) @openerpweb.jsonrequest def drop(self, req, fields): @@ -936,10 +909,7 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def get_lang_list(self, req): try: - return { - 'lang_list': (req.session.proxy("db").list_lang() or []), - 'error': "" - } + return req.session.proxy("db").list_lang() or [] except Exception, e: return {"error": e, "title": "Languages"} @@ -1298,17 +1268,6 @@ class DataSet(openerpweb.Controller): m.write(id, { field: i + offset }) return True -class DataGroup(openerpweb.Controller): - _cp_path = "/web/group" - @openerpweb.jsonrequest - def read(self, req, model, fields, group_by_fields, domain=None, sort=None): - Model = req.session.model(model) - context, domain = eval_context_and_domain(req.session, req.context, domain) - - return Model.read_group( - domain or [], fields, group_by_fields, 0, False, - dict(context, group_by=group_by_fields), sort or False) - class View(openerpweb.Controller): _cp_path = "/web/view" @@ -1342,7 +1301,7 @@ class View(openerpweb.Controller): xml = self.transform_view(arch, session, evaluation_context) else: xml = ElementTree.fromstring(arch) - fvg['arch'] = from_elementtree(xml, preserve_whitespaces) + fvg['arch'] = xml2json_from_elementtree(xml, preserve_whitespaces) if 'id' in fvg['fields']: # Special case for id's @@ -1516,11 +1475,24 @@ class Binary(openerpweb.Controller): try: if not id: res = Model.default_get([field], context).get(field) - image_data = base64.b64decode(res) + image_base64 = res else: res = Model.read([id], [last_update, field], context)[0] retag = hashlib.md5(res.get(last_update)).hexdigest() - image_data = base64.b64decode(res.get(field)) + image_base64 = res.get(field) + + if kw.get('resize'): + resize = kw.get('resize').split(','); + if len(resize) == 2 and int(resize[0]) and int(resize[1]): + width = int(resize[0]) + height = int(resize[1]) + # resize maximum 500*500 + if width > 500: width = 500 + if height > 500: height = 500 + image_base64 = openerp.tools.image_resize_image(base64_source=image_base64, size=(width, height), encoding='base64', filetype='PNG') + + image_data = base64.b64decode(image_base64) + except (TypeError, xmlrpclib.Fault): image_data = self.placeholder(req) headers.append(('ETag', retag)) @@ -2010,112 +1982,4 @@ class Reports(View): ('Content-Length', len(report))], cookies={'fileToken': int(token)}) -class Import(View): - _cp_path = "/web/import" - - def fields_get(self, req, model): - Model = req.session.model(model) - fields = Model.fields_get(False, req.session.eval_context(req.context)) - return fields - - @openerpweb.httprequest - def detect_data(self, req, csvfile, csvsep=',', csvdel='"', csvcode='utf-8', jsonp='callback'): - try: - data = list(csv.reader( - csvfile, quotechar=str(csvdel), delimiter=str(csvsep))) - except csv.Error, e: - csvfile.seek(0) - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({'error': { - 'message': 'Error parsing CSV file: %s' % e, - # decodes each byte to a unicode character, which may or - # may not be printable, but decoding will succeed. - # Otherwise simplejson will try to decode the `str` using - # utf-8, which is very likely to blow up on characters out - # of the ascii range (in range [128, 256)) - 'preview': csvfile.read(200).decode('iso-8859-1')}})) - - try: - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps( - {'records': data[:10]}, encoding=csvcode)) - except UnicodeDecodeError: - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({ - 'message': u"Failed to decode CSV file using encoding %s, " - u"try switching to a different encoding" % csvcode - })) - - @openerpweb.httprequest - def import_data(self, req, model, csvfile, csvsep, csvdel, csvcode, jsonp, - meta): - modle_obj = req.session.model(model) - skip, indices, fields = operator.itemgetter('skip', 'indices', 'fields')( - simplejson.loads(meta)) - - error = None - if not (csvdel and len(csvdel) == 1): - error = u"The CSV delimiter must be a single character" - - if not indices and fields: - error = u"You must select at least one field to import" - - if error: - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({'error': {'message': error}})) - - # skip ignored records (@skip parameter) - # then skip empty lines (not valid csv) - # nb: should these operations be reverted? - rows_to_import = itertools.ifilter( - None, - itertools.islice( - csv.reader(csvfile, quotechar=str(csvdel), delimiter=str(csvsep)), - skip, None)) - - # if only one index, itemgetter will return an atom rather than a tuple - if len(indices) == 1: mapper = lambda row: [row[indices[0]]] - else: mapper = operator.itemgetter(*indices) - - data = None - error = None - try: - # decode each data row - data = [ - [record.decode(csvcode) for record in row] - for row in itertools.imap(mapper, rows_to_import) - # don't insert completely empty rows (can happen due to fields - # filtering in case of e.g. o2m content rows) - if any(row) - ] - except UnicodeDecodeError: - error = u"Failed to decode CSV file using encoding %s" % csvcode - except csv.Error, e: - error = u"Could not process CSV file: %s" % e - - # If the file contains nothing, - if not data: - error = u"File to import is empty" - if error: - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({'error': {'message': error}})) - - try: - (code, record, message, _nope) = modle_obj.import_data( - fields, data, 'init', '', False, - req.session.eval_context(req.context)) - except xmlrpclib.Fault, e: - error = {"message": u"%s, %s" % (e.faultCode, e.faultString)} - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({'error':error})) - - if code != -1: - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({'success':True})) - - msg = u"Error during import: %s\n\nTrying to import record %r" % ( - message, record) - return '<script>window.top.%s(%s);</script>' % ( - jsonp, simplejson.dumps({'error': {'message':msg}})) - # vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/web/controllers/testing.py b/addons/web/controllers/testing.py new file mode 100644 index 00000000000..3c7c4899b6c --- /dev/null +++ b/addons/web/controllers/testing.py @@ -0,0 +1,162 @@ +# coding=utf-8 +# -*- encoding: utf-8 -*- + +import glob +import itertools +import json +import operator +import os + +from mako.template import Template +from openerp.modules import module + +from .main import module_topological_sort +from ..http import Controller, httprequest + +NOMODULE_TEMPLATE = Template(u"""<!DOCTYPE html> +<html> + <head> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <title>OpenERP Testing</title> + </head> + <body> + <form action="/web/tests" method="GET"> + <button name="mod" value="*">Run all tests</button> + <ul> + % for name, module in modules: + <li>${name} <button name="mod" value="${module}"> + Run Tests</button></li> + % endfor + </ul> + </form> + </body> +</html> +""") +NOTFOUND = Template(u""" +<p>Unable to find the module [${module}], please check that the module + name is correct and the module is on OpenERP's path.</p> +<a href="/web/tests"><< Back to tests</a> +""") +TESTING = Template(u"""<!DOCTYPE html> +<html style="height: 100%"> +<%def name="to_path(module, p)">/${module}/${p}</%def> +<head> + <meta http-equiv="X-UA-Compatible" content="IE=edge"/> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <title>OpenERP Web Tests</title> + <link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/> + + <link rel="stylesheet" href="/web/static/lib/qunit/qunit.css"> + <script src="/web/static/lib/qunit/qunit.js"></script> + + <script type="text/javascript"> + var oe_db_info = ${db_info}; + // List of modules, each module is preceded by its dependencies + var oe_all_dependencies = ${dependencies}; + QUnit.config.testTimeout = 5 * 60 * 1000; + </script> +</head> +<body id="oe" class="openerp"> + <div id="qunit"></div> + <div id="qunit-fixture"></div> +</body> +% for module, jss, tests, templates in files: + % for js in jss: + <script src="${to_path(module, js)}"></script> + % endfor + % if tests or templates: + <script> + openerp.testing.current_module = "${module}"; + % for template in templates: + openerp.testing.add_template("${to_path(module, template)}"); + % endfor + </script> + % endif + % if tests: + % for test in tests: + <script type="text/javascript" src="${to_path(module, test)}"></script> + % endfor + % endif +% endfor +</html> +""") + +class TestRunnerController(Controller): + _cp_path = '/web/tests' + + @httprequest + def index(self, req, mod=None, **kwargs): + ms = module.get_modules() + manifests = dict( + (name, desc) + for name, desc in zip(ms, map(self.load_manifest, ms)) + if desc # remove not-actually-openerp-modules + ) + + if not mod: + return NOMODULE_TEMPLATE.render(modules=( + (manifest['name'], name) + for name, manifest in manifests.iteritems() + if any(testfile.endswith('.js') + for testfile in manifest['test']) + )) + sorted_mods = module_topological_sort(dict( + (name, manifest.get('depends', [])) + for name, manifest in manifests.iteritems() + )) + # to_load and to_test should be zippable lists of the same length. + # A falsy value in to_test indicate nothing to test at that index (just + # load the corresponding part of to_load) + to_test = sorted_mods + if mod != '*': + if mod not in manifests: + return req.not_found(NOTFOUND.render(module=mod)) + idx = sorted_mods.index(mod) + to_test = [None] * len(sorted_mods) + to_test[idx] = mod + + tests_candicates = [ + filter(lambda path: path.endswith('.js'), + manifests[mod]['test'] if mod else []) + for mod in to_test] + # remove trailing test-less modules + tests = reversed(list( + itertools.dropwhile( + operator.not_, + reversed(tests_candicates)))) + + files = [ + (mod, manifests[mod]['js'], tests, manifests[mod]['qweb']) + for mod, tests in itertools.izip(sorted_mods, tests) + ] + + # if all three db_info parameters are present, send them to the page + db_info = dict((k, v) for k, v in kwargs.iteritems() + if k in ['source', 'supadmin', 'password']) + if len(db_info) != 3: + db_info = None + + return TESTING.render(files=files, dependencies=json.dumps( + [name for name in sorted_mods + if module.get_module_resource(name, 'static') + if manifests[name]['js']]), db_info=json.dumps(db_info)) + + def load_manifest(self, name): + manifest = module.load_information_from_description_file(name) + if manifest: + path = module.get_module_path(name) + manifest['js'] = list( + self.expand_patterns(path, manifest.get('js', []))) + manifest['test'] = list( + self.expand_patterns(path, manifest.get('test', []))) + manifest['qweb'] = list( + self.expand_patterns(path, manifest.get('qweb', []))) + return manifest + + def expand_patterns(self, root, patterns): + for pattern in patterns: + normalized_pattern = os.path.normpath(os.path.join(root, pattern)) + for path in glob.glob(normalized_pattern): + # replace OS path separators (from join & normpath) by URI ones + yield path[len(root):].replace(os.path.sep, '/') diff --git a/addons/web/doc/async.rst b/addons/web/doc/async.rst index bd23d5a31d3..6782fdac029 100644 --- a/addons/web/doc/async.rst +++ b/addons/web/doc/async.rst @@ -26,8 +26,7 @@ Deferreds --------- Deferreds are a form of `promises`_. OpenERP Web currently uses -`jQuery's deferred`_, but any `CommonJS Promises/A`_ implementation -should work. +`jQuery's deferred`_. The core idea of deferreds is that potentially asynchronous methods will return a :js:class:`Deferred` object instead of an arbitrary @@ -44,9 +43,8 @@ directly to asynchronous methods is the ability to :ref:`compose them Using deferreds ~~~~~~~~~~~~~~~ -`CommonJS Promises/A`_ deferreds have only one method of importance: -:js:func:`Deferred.then`. This method is used to attach new callbacks -to the deferred object. +Deferreds's most important method is :js:func:`Deferred.then`. It is +used to attach new callbacks to the deferred object. * the first parameter attaches a success callback, called when the deferred object is successfully resolved and provided with the @@ -178,9 +176,9 @@ Deferred chaining A second useful composition is starting an asynchronous operation as the result of an other asynchronous operation, and wanting the result -of both: :js:func:`Deferred.then` returns the deferred on which it was -called, so handle e.g. OpenERP's search/read sequence with this would -require something along the lines of: +of both: with the tools described so far, handling e.g. OpenERP's +search/read sequence with this would require something along the lines +of: .. code-block:: javascript @@ -195,21 +193,14 @@ require something along the lines of: While it doesn't look too bad for trivial code, this quickly gets unwieldy. -Instead, jQuery provides a tool to handle this kind of chains: -:js:func:`Deferred.pipe`. - -:js:func:`~Deferred.pipe` has the same signature as -:js:func:`~Deferred.then` and could be used in the same manner -provided its return value was not used. - -It differs from :js:func:`~Deferred.then` in two ways: it returns a -new promise object, not the one it was called with, and the return -values of the callbacks is actually important to it: whichever -callback is called, +But :js:func:`~Deferred.then` also allows handling this kind of +chains: it returns a new promise object, not the one it was called +with, and the return values of the callbacks is actually important to +it: whichever callback is called, * If the callback is not set (not provided or left to null), the resolution or rejection value(s) is simply forwarded to - :js:func:`~Deferred.pipe`'s promise (it's essentially a noop) + :js:func:`~Deferred.then`'s promise (it's essentially a noop) * If the callback is set and does not return an observable object (a deferred or a promise), the value it returns (``undefined`` if it @@ -217,7 +208,7 @@ callback is called, .. code-block:: javascript - promise.pipe(function () { + promise.then(function () { console.log('called'); }); @@ -234,7 +225,7 @@ callback is called, .. code-block:: javascript - return Model.search(condition).pipe(function (ids) { + return Model.search(condition).then(function (ids) { return Model.read(ids, fields); }); @@ -243,10 +234,11 @@ callback is called, will be resolved with ``read``'s resolution values if the chain executes correctly. -:js:func:`~Deferred.pipe` is also useful to adapt third-party +:js:func:`~Deferred.then` is also useful to adapt third-party promise-based APIs, in order to filter their resolution value counts -for instance (to take advantage of :js:func:`when` 's special treatment -of single-value promises). +for instance (to take advantage of :js:func:`when` 's special +treatment of single-value promises). + jQuery.Deferred API ~~~~~~~~~~~~~~~~~~~ @@ -269,6 +261,11 @@ jQuery.Deferred API ``doneCallback``, to provide only a success callback the second argument can just be ignored (and not passed at all). + Returns a new deferred which resolves to the result of the + corresponding callback, if a callback returns a deferred + itself that new deferred will be used as the resolution of the + chain. + :param doneCallback: function called when the deferred is resolved :type doneCallback: Function :param failCallback: function called when the deferred is rejected @@ -326,12 +323,6 @@ jQuery.Deferred API Rejecting a deferred which has already been resolved or rejected has no effect. - .. js:function:: Deferred.pipe(doneFilter[, failFilter]) - - Filters the result of a deferred, able to transform a success - into failure and a failure into success, or to delay - resolution further. - .. [#] or simply calling :js:class:`Deferred` as a function, the result is the same diff --git a/addons/web/doc/guides/client-action.rst b/addons/web/doc/client_action.rst index 30f0c7eeb27..af48fff08a7 100644 --- a/addons/web/doc/guides/client-action.rst +++ b/addons/web/doc/client_action.rst @@ -1,7 +1,7 @@ .. highlight:: javascript -Creating a new client action -============================ +Client actions +============== Client actions are the client-side version of OpenERP's "Server Actions": instead of allowing for semi-arbitrary code to be executed diff --git a/addons/web/doc/conf.py b/addons/web/doc/conf.py index ac5b8907e0e..54434190707 100644 --- a/addons/web/doc/conf.py +++ b/addons/web/doc/conf.py @@ -16,10 +16,9 @@ import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) sys.path.append(os.path.abspath('_themes')) -sys.path.append(os.path.abspath('..')) -sys.path.append(os.path.abspath('../openerp')) +sys.path.insert(0, os.path.abspath('../addons')) +sys.path.insert(0, os.path.abspath('..')) # -- General configuration ----------------------------------------------------- @@ -43,7 +42,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'OpenERP Server Developers Documentation' +project = u'OpenERP Web Developers Documentation' copyright = u'2012, OpenERP s.a.' # The version info for the project you're documenting, acts as replacement for @@ -53,7 +52,7 @@ copyright = u'2012, OpenERP s.a.' # The short X.Y version. version = '7.0' # The full version, including alpha/beta/rc tags. -release = '7.0b' +release = '7.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -171,7 +170,7 @@ html_sidebars = { #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'openerp-server-doc' +htmlhelp_basename = 'openerp-web-doc' # -- Options for LaTeX output -------------------------------------------------- @@ -190,7 +189,7 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'openerp-server-doc.tex', u'OpenERP Server Developers Documentation', + ('index', 'openerp-web-doc.tex', u'OpenERP Web Developers Documentation', u'OpenERP s.a.', 'manual'), ] @@ -220,7 +219,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'openerp-server-doc', u'OpenERP Server Developers Documentation', + ('index', 'openerp-web-doc', u'OpenERP Web Developers Documentation', [u'OpenERP s.a.'], 1) ] @@ -234,8 +233,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'OpenERPServerDocumentation', u'OpenERP Server Developers Documentation', - u'OpenERP s.a.', 'OpenERPServerDocumentation', 'Developers documentation for the openobject-server project.', + ('index', 'OpenERPWebDocumentation', u'OpenERP Web Developers Documentation', + u'OpenERP s.a.', 'OpenERPWebDocumentation', 'Developers documentation for the openerp-web project.', 'Miscellaneous'), ] @@ -248,10 +247,12 @@ texinfo_documents = [ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' +todo_include_todos = True # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { 'python': ('http://docs.python.org/', None), - 'openerpweb': ('http://doc.openerp.com/trunk/developers/web', None), + 'openerpserver': ('http://doc.openerp.com/trunk/developers/server', None), 'openerpdev': ('http://doc.openerp.com/trunk/developers', None), + 'openerpcommand': ('http://doc.openerp.com/trunk/developers/command', None), } diff --git a/addons/web/doc/form-notes.rst b/addons/web/doc/form_view.rst index 98d4a4de67e..98d4a4de67e 100644 --- a/addons/web/doc/form-notes.rst +++ b/addons/web/doc/form_view.rst diff --git a/addons/web/doc/images/db-query.png b/addons/web/doc/images/db-query.png Binary files differnew file mode 100644 index 00000000000..e063b724001 --- /dev/null +++ b/addons/web/doc/images/db-query.png diff --git a/addons/web/doc/images/runner.png b/addons/web/doc/images/runner.png Binary files differnew file mode 100644 index 00000000000..bd48e9d2922 --- /dev/null +++ b/addons/web/doc/images/runner.png diff --git a/addons/web/doc/images/runner2.png b/addons/web/doc/images/runner2.png Binary files differnew file mode 100644 index 00000000000..38ea2949cfc --- /dev/null +++ b/addons/web/doc/images/runner2.png diff --git a/addons/web/doc/images/tests.png b/addons/web/doc/images/tests.png Binary files differnew file mode 100644 index 00000000000..84083d9e5ed --- /dev/null +++ b/addons/web/doc/images/tests.png diff --git a/addons/web/doc/images/tests2.png b/addons/web/doc/images/tests2.png Binary files differnew file mode 100644 index 00000000000..c8a6f8ae9ee --- /dev/null +++ b/addons/web/doc/images/tests2.png diff --git a/addons/web/doc/images/tests3.png b/addons/web/doc/images/tests3.png Binary files differnew file mode 100644 index 00000000000..247f70716af --- /dev/null +++ b/addons/web/doc/images/tests3.png diff --git a/addons/web/doc/index.rst b/addons/web/doc/index.rst index 99edd1156e0..06534c50903 100644 --- a/addons/web/doc/index.rst +++ b/addons/web/doc/index.rst @@ -12,20 +12,19 @@ Contents: :maxdepth: 1 presentation - - changelog-7.0 - async - rpc + + testing widget qweb - search-view - - list-view - form-notes + rpc + client_action + form_view + search_view + list_view - guides/client-action + changelog-7.0 Indices and tables ================== diff --git a/addons/web/doc/list-view.rst b/addons/web/doc/list_view.rst index b7cdc1cd039..51188d95f7b 100644 --- a/addons/web/doc/list-view.rst +++ b/addons/web/doc/list_view.rst @@ -451,7 +451,7 @@ formview, delegating instead to its created. The result should be a valid form view, see :doc:`Form Notes - <form-notes>` for various peculiarities of the form view + <form_view>` for various peculiarities of the form view format. :param editor: editor object asking for the view diff --git a/addons/web/doc/presentation.rst b/addons/web/doc/presentation.rst index c249b540513..26328b44e48 100644 --- a/addons/web/doc/presentation.rst +++ b/addons/web/doc/presentation.rst @@ -7,17 +7,17 @@ Prerequisites Prerequisites to code addons for the OpenERP Web Client: -- Html -- Css -- Javascript +- HTML5 +- CSS +- Javascript (Ecmascript 5) - jQuery Once you know all this, that's only the beginning. Most usages of Javascript/jQuery are small hacks to make a web page nicer. The OpenERP Client Web is different: it's a web application, not a web site. It doesn't have multiple pages generated by a server side code. Only one unique empty page is loaded and all the html is generated by Javascript code, the page is never reloaded. If you never developed that kind of application you still have lot of good practices to learn. -Recommendations ---------------- +Generic Guidelines +------------------ -First, here are the 5 golden rules when you create web 2.0 applications: +First, here are some generic recommandations about web 2.0 applications: * **Do not use ids**. Html ids are evil, the key anti-feature that makes your components non-reusable. You want to identify a dom part? Save a jQuery object over that dom element. If you really need to use ids, use _.uniqueId(), but 99% of the time you don't need to, classes are sufficient. * **Do not use predictable css class names** like "content" or "navigation", ten other developers will have the same idea than you and there will be clashes. A simple way to avoid this is to use prefixes. For example, if you need a css class for the button named "new" that is contained in the form view which is itself contained in the OpenERP application, name it "oe-form-view-new-button". @@ -25,12 +25,18 @@ First, here are the 5 golden rules when you create web 2.0 applications: * As a general advice, **Never assume you own the page**. When you create a component, it is never unique and is always surrounded by a bunch of crazy html. You have to do with it. * **Learn how to use jQuery's deferreds** [1]_. That concept may seem over-complicated, but the experience tell us that it is nearly impossible to create big-size javascript applications without that. +OpenERP guidelines +------------------ More recommendations related to the specific case of the OpenERP Web Client: -* Your components should inherit from the *Widget* class. +* The code should conform to EcmasScript 5 without the "use strict" mode as we support IE9. + +* Your components should inherit from the *Widget* class. And use *Widget* 's methods (*appendTo*, *replace*,...) to insert your component and its content into the dom. + * Use QWeb templates for html rendering. -* Use *Widget* 's methods (*appendTo*, *replace*,...) to insert your component and its content into the dom. + * All css classes should have the prefix *oe-* . + * Functions that call rpc() should return a deferred, even if it calls it indirectly. So a function that calls a function that calls a function that calls rpc() should return a deferred too. .. [1] http://api.jquery.com/category/deferred-object/ diff --git a/addons/web/doc/qweb.rst b/addons/web/doc/qweb.rst index 85719c6742d..7ad1e20d57a 100644 --- a/addons/web/doc/qweb.rst +++ b/addons/web/doc/qweb.rst @@ -1,6 +1,6 @@ -QWeb Cookbook -============= +QWeb +==== QWeb is the template engine used by the OpenERP Web Client. It is a home made engine create by OpenERP developers. There are a few things to note about it: diff --git a/addons/web/doc/search-view.rst b/addons/web/doc/search_view.rst index 16a91c5e9ac..16a91c5e9ac 100644 --- a/addons/web/doc/search-view.rst +++ b/addons/web/doc/search_view.rst diff --git a/addons/web/doc/test-report.txt b/addons/web/doc/test-report.txt new file mode 100644 index 00000000000..ce52618fe20 --- /dev/null +++ b/addons/web/doc/test-report.txt @@ -0,0 +1,25 @@ +test_empty_find (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok +test_ids_shortcut (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok +test_regular_find (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok +web.testing.stack: direct, value, success ... ok +web.testing.stack: direct, deferred, success ... ok +web.testing.stack: direct, value, error ... ok +web.testing.stack: direct, deferred, failure ... ok +web.testing.stack: successful setup ... ok +web.testing.stack: successful teardown ... ok +web.testing.stack: successful setup and teardown ... ok + +[snip ~150 lines] + +test_convert_complex_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok +test_convert_complex_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok +test_convert_literal_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok +test_convert_literal_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok +test_retrieve_nonliteral_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok +test_retrieve_nonliteral_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok + +---------------------------------------------------------------------- +Ran 181 tests in 15.706s + +OK + diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst new file mode 100644 index 00000000000..600d379aa02 --- /dev/null +++ b/addons/web/doc/testing.rst @@ -0,0 +1,693 @@ +.. highlight:: javascript + +Testing in OpenERP Web +====================== + +Javascript Unit Testing +----------------------- + +OpenERP Web 7.0 includes means to unit-test both the core code of +OpenERP Web and your own javascript modules. On the javascript side, +unit-testing is based on QUnit_ with a number of helpers and +extensions for better integration with OpenERP. + +To see what the runner looks like, find (or start) an OpenERP server +with the web client enabled, and navigate to ``/web/tests`` e.g. `on +OpenERP's CI <http://trunk.runbot.openerp.com/web/tests>`_. This will +show the runner selector, which lists all modules with javascript unit +tests, and allows starting any of them (or all javascript tests in all +modules at once). + +.. image:: ./images/runner.png + :align: center + +Clicking any runner button will launch the corresponding tests in the +bundled QUnit_ runner: + +.. image:: ./images/tests.png + :align: center + +Writing a test case +------------------- + +The first step is to list the test file(s). This is done through the +``test`` key of the openerp manifest, by adding javascript files to it +(next to the usual YAML files, if any): + +.. code-block:: python + + { + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'test': ['static/test/demo.js'], + } + +and to create the corresponding test file(s) + +.. note:: + + Test files which do not exist will be ignored, if all test files + of a module are ignored (can not be found), the test runner will + consider that the module has no javascript tests. + +After that, refreshing the runner selector will display the new module +and allow running all of its (0 so far) tests: + +.. image:: ./images/runner2.png + :align: center + +The next step is to create a test case:: + + openerp.testing.section('basic section', function (test) { + test('my first test', function () { + ok(false, "this test has run"); + }); + }); + +All testing helpers and structures live in the ``openerp.testing`` +module. OpenERP tests live in a :js:func:`~openerp.testing.section`, +which is itself part of a module. The first argument to a section is +the name of the section, the second one is the section body. + +:js:func:`test <openerp.testing.case>`, provided by the +:js:func:`~openerp.testing.section` to the callback, is used to +register a given test case which will be run whenever the test runner +actually does its job. OpenERP Web test case use standard `QUnit +assertions`_ within them. + +Launching the test runner at this point will run the test and display +the corresponding assertion message, with red colors indicating the +test failed: + +.. image:: ./images/tests2.png + :align: center + +Fixing the test (by replacing ``false`` to ``true`` in the assertion) +will make it pass: + +.. image:: ./images/tests3.png + :align: center + +Assertions +---------- + +As noted above, OpenERP Web's tests use `qunit assertions`_. They are +available globally (so they can just be called without references to +anything). The following list is available: + +.. js:function:: ok(state[, message]) + + checks that ``state`` is truthy (in the javascript sense) + +.. js:function:: strictEqual(actual, expected[, message]) + + checks that the actual (produced by a method being tested) and + expected values are identical (roughly equivalent to ``ok(actual + === expected, message)``) + +.. js:function:: notStrictEqual(actual, expected[, message]) + + checks that the actual and expected values are *not* identical + (roughly equivalent to ``ok(actual !== expected, message)``) + +.. js:function:: deepEqual(actual, expected[, message]) + + deep comparison between actual and expected: recurse into + containers (objects and arrays) to ensure that they have the same + keys/number of elements, and the values match. + +.. js:function:: notDeepEqual(actual, expected[, message]) + + inverse operation to :js:func:`deepEqual` + +.. js:function:: throws(block[, expected][, message]) + + checks that, when called, the ``block`` throws an + error. Optionally validates that error against ``expected``. + + :param Function block: + :param expected: if a regexp, checks that the thrown error's + message matches the regular expression. If an + error type, checks that the thrown error is of + that type. + :type expected: Error | RegExp + +.. js:function:: equal(actual, expected[, message]) + + checks that ``actual`` and ``expected`` are loosely equal, using + the ``==`` operator and its coercion rules. + +.. js:function:: notEqual(actual, expected[, message]) + + inverse operation to :js:func:`equal` + +Getting an OpenERP instance +--------------------------- + +The OpenERP instance is the base through which most OpenERP Web +modules behaviors (functions, objects, …) are accessed. As a result, +the test framework automatically builds one, and loads the module +being tested and all of its dependencies inside it. This new instance +is provided as the first positional parameter to your test +cases. Let's observe by adding javascript code (not test code) to the +test module: + +.. code-block:: python + + { + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'js': ['static/src/js/demo.js'], + 'test': ['static/test/demo.js'], + } + +:: + + // src/js/demo.js + openerp.web_tests_demo = function (instance) { + instance.web_tests_demo = { + value_true: true, + SomeType: instance.web.Class.extend({ + init: function (value) { + this.value = value; + } + }) + }; + }; + +and then adding a new test case, which simply checks that the +``instance`` contains all the expected stuff we created in the +module:: + + // test/demo.js + test('module content', function (instance) { + ok(instance.web_tests_demo.value_true, "should have a true value"); + var type_instance = new instance.web_tests_demo.SomeType(42); + strictEqual(type_instance.value, 42, "should have provided value"); + }); + +DOM Scratchpad +-------------- + +As in the wider client, arbitrarily accessing document content is +strongly discouraged during tests. But DOM access is still needed to +e.g. fully initialize :js:class:`widgets <~openerp.web.Widget>` before +testing them. + +Thus, a test case gets a DOM scratchpad as its second positional +parameter, in a jQuery instance. That scratchpad is fully cleaned up +before each test, and as long as it doesn't do anything outside the +scratchpad your code can do whatever it wants:: + + // test/demo.js + test('DOM content', function (instance, $scratchpad) { + $scratchpad.html('<div><span class="foo bar">ok</span></div>'); + ok($scratchpad.find('span').hasClass('foo'), + "should have provided class"); + }); + test('clean scratchpad', function (instance, $scratchpad) { + ok(!$scratchpad.children().length, "should have no content"); + ok(!$scratchpad.text(), "should have no text"); + }); + +.. note:: + + The top-level element of the scratchpad is not cleaned up, test + cases can add text or DOM children but shoud not alter + ``$scratchpad`` itself. + +Loading templates +----------------- + +To avoid the corresponding processing costs, by default templates are +not loaded into QWeb. If you need to render e.g. widgets making use of +QWeb templates, you can request their loading through the +:js:attr:`~TestOptions.templates` option to the :js:func:`test case +function <openerp.testing.case>`. + +This will automatically load all relevant templates in the instance's +qweb before running the test case: + +.. code-block:: python + + { + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'js': ['static/src/js/demo.js'], + 'test': ['static/test/demo.js'], + 'qweb': ['static/src/xml/demo.xml'], + } + +.. code-block:: xml + + <!-- src/xml/demo.xml --> + <templates id="template" xml:space="preserve"> + <t t-name="DemoTemplate"> + <t t-foreach="5" t-as="value"> + <p><t t-esc="value"/></p> + </t> + </t> + </templates> + +:: + + // test/demo.js + test('templates', {templates: true}, function (instance) { + var s = instance.web.qweb.render('DemoTemplate'); + var texts = $(s).find('p').map(function () { + return $(this).text(); + }).get(); + + deepEqual(texts, ['0', '1', '2', '3', '4']); + }); + +Asynchronous cases +------------------ + +The test case examples so far are all synchronous, they execute from +the first to the last line and once the last line has executed the +test is done. But the web client is full of :doc:`asynchronous code +</async>`, and thus test cases need to be async-aware. + +This is done by returning a :js:class:`deferred <Deferred>` from the +case callback:: + + // test/demo.js + test('asynchronous', { + asserts: 1 + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.resolve(); + }, 100); + return d; + }); + +This example also uses the :js:class:`options parameter <TestOptions>` +to specify the number of assertions the case should expect, if less or +more assertions are specified the case will count as failed. + +Asynchronous test cases *must* specify the number of assertions they +will run. This allows more easily catching situations where e.g. the +test architecture was not warned about asynchronous operations. + +.. note:: + + Asynchronous test cases also have a 2 seconds timeout: if the test + does not finish within 2 seconds, it will be considered + failed. This pretty much always means the test will not + resolve. This timeout *only* applies to the test itself, not to + the setup and teardown processes. + +.. note:: + + If the returned deferred is rejected, the test will be failed + unless :js:attr:`~TestOptions.fail_on_rejection` is set to + ``false``. + +RPC +--- + +An important subset of asynchronous test cases is test cases which +need to perform (and chain, to an extent) RPC calls. + +.. note:: + + Because they are a subset of asynchronous cases, RPC cases must + also provide a valid :js:attr:`assertions count + <TestOptions.asserts>`. + +By default, test cases will fail when trying to perform an RPC +call. The ability to perform RPC calls must be explicitly requested by +a test case (or its containing test suite) through +:js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or +``rpc``. + +Mock RPC +++++++++ + +The preferred (and fastest from a setup and execution time point of +view) way to do RPC during tests is to mock the RPC calls: while +setting up the test case, provide what the RPC responses "should" be, +and only test the code between the "user" (the test itself) and the +RPC call, before the call is effectively done. + +To do this, set the :js:attr:`rpc option <TestOptions.rpc>` to +``mock``. This will add a third parameter to the test case callback: + +.. js:function:: mock(rpc_spec, handler) + + Can be used in two different ways depending on the shape of the + first parameter: + + * If it matches the pattern ``model:method`` (if it contains a + colon, essentially) the call will set up the mocking of an RPC + call straight to the OpenERP server (through XMLRPC) as + performed via e.g. :js:func:`openerp.web.Model.call`. + + In that case, ``handler`` should be a function taking two + arguments ``args`` and ``kwargs``, matching the corresponding + arguments on the server side and should simply return the value + as if it were returned by the Python XMLRPC handler:: + + test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) { + // set up mocking + mock('people.famous:name_search', function (args, kwargs) { + strictEqual(kwargs.name, 'bob'); + return [ + [1, "Microsoft Bob"], + [2, "Bob the Builder"], + [3, "Silent Bob"] + ]; + }); + + // actual test code + return new instance.web.Model('people.famous') + .call('name_search', {name: 'bob'}).then(function (result) { + strictEqual(result.length, 3, "shoud return 3 people"); + strictEqual(result[0][1], "Microsoft Bob", + "the most famous bob should be Microsoft Bob"); + }); + }); + + * Otherwise, if it matches an absolute path (e.g. ``/a/b/c``) it + will mock a JSON-RPC call to a web client controller, such as + ``/web/webclient/translations``. In that case, the handler takes + a single ``params`` argument holding all of the parameters + provided over JSON-RPC. + + As previously, the handler should simply return the result value + as if returned by the original JSON-RPC handler:: + + test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) { + var fetched_dbs = false, fetched_langs = false; + mock('/web/database/get_list', function () { + fetched_dbs = true; + return ['foo', 'bar', 'baz']; + }); + mock('/web/session/get_lang_list', function () { + fetched_langs = true; + return [['vo_IS', 'Hopelandic / Vonlenska']]; + }); + + // widget needs that or it blows up + instance.webclient = {toggle_bars: openerp.testing.noop}; + var dbm = new instance.web.DatabaseManager({}); + return dbm.appendTo($s).then(function () { + ok(fetched_dbs, "should have fetched databases"); + ok(fetched_langs, "should have fetched languages"); + deepEqual(dbm.db_list, ['foo', 'bar', 'baz']); + }); + }); + +.. note:: + + Mock handlers can contain assertions, these assertions should be + part of the assertions count (and if multiple calls are made to a + handler containing assertions, it multiplies the effective number + of assertions). + +.. _testing-rpc-rpc: + +Actual RPC +++++++++++ + +A more realistic (but significantly slower and more expensive) way to +perform RPC calls is to perform actual calls to an actually running +OpenERP server. To do this, set the :js:attr:`rpc option +<~TestOptions.rpc>` to ``rpc``, it will not provide any new parameter +but will enable actual RPC, and the automatic creation and destruction +of databases (from a specified source) around tests. + +First, create a basic model we can test stuff with: + +.. code-block:: javascript + + from openerp.osv import orm, fields + + class TestObject(orm.Model): + _name = 'web_tests_demo.model' + + _columns = { + 'name': fields.char("Name", required=True), + 'thing': fields.char("Thing"), + 'other': fields.char("Other", required=True) + } + _defaults = { + 'other': "bob" + } + +then the actual test:: + + test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) { + var Model = new instance.web.Model('web_tests_demo.model'); + return Model.call('create', [{name: "Bob"}]) + .then(function (id) { + return Model.call('read', [[id]]); + }).then(function (records) { + strictEqual(records.length, 1); + var record = records[0]; + strictEqual(record.name, "Bob"); + strictEqual(record.thing, false); + // default value + strictEqual(record.other, 'bob'); + }); + }); + +This test looks like a "mock" RPC test but for the lack of mock +response (and the different ``rpc`` type), however it has further +ranging consequences in that it will copy an existing database to a +new one, run the test in full on that temporary database and destroy +the database, to simulate an isolated and transactional context and +avoid affecting other tests. One of the consequences is that it takes +a *long* time to run (5~10s, most of that time being spent waiting for +a database duplication). + +Furthermore, as the test needs to clone a database, it also has to ask +which database to clone, the database/super-admin password and the +password of the ``admin`` user (in order to authenticate as said +user). As a result, the first time the test runner encounters an +``rpc: "rpc"`` test configuration it will produce the following +prompt: + +.. image:: ./images/db-query.png + :align: center + +and stop the testing process until the necessary information has been +provided. + +The prompt will only appear once per test run, all tests will use the +same "source" database. + +.. note:: + + The handling of that information is currently rather brittle and + unchecked, incorrect values will likely crash the runner. + +.. note:: + + The runner does not currently store this information (for any + longer than a test run that is), the prompt will have to be filled + every time. + +Testing API +----------- + +.. js:function:: openerp.testing.section(name[, options], body) + + A test section, serves as shared namespace for related tests (for + constants or values to only set up once). The ``body`` function + should contain the tests themselves. + + Note that the order in which tests are run is essentially + undefined, do *not* rely on it. + + :param String name: + :param TestOptions options: + :param body: + :type body: Function<:js:func:`~openerp.testing.case`, void> + +.. js:function:: openerp.testing.case(name[, options], callback) + + Registers a test case callback in the test runner, the callback + will only be run once the runner is started (or maybe not at all, + if the test is filtered out). + + :param String name: + :param TestOptions options: + :param callback: + :type callback: Function<instance, $, Function<String, Function, void>> + +.. js:class:: TestOptions + + the various options which can be passed to + :js:func:`~openerp.testing.section` or + :js:func:`~openerp.testing.case`. Except for + :js:attr:`~TestOptions.setup` and + :js:attr:`~TestOptions.teardown`, an option on + :js:func:`~openerp.testing.case` will overwrite the corresponding + option on :js:func:`~openerp.testing.section` so + e.g. :js:attr:`~TestOptions.rpc` can be set for a + :js:func:`~openerp.testing.section` and then differently set for + some :js:func:`~openerp.testing.case` of that + :js:func:`~openerp.testing.section` + + .. js:attribute:: TestOptions.asserts + + An integer, the number of assertions which should run during a + normal execution of the test. Mandatory for asynchronous tests. + + .. js:attribute:: TestOptions.setup + + Test case setup, run right before each test case. A section's + :js:func:`~TestOptions.setup` is run before the case's own, if + both are specified. + + .. js:attribute:: TestOptions.teardown + + Test case teardown, a case's :js:func:`~TestOptions.teardown` + is run before the corresponding section if both are present. + + .. js:attribute:: TestOptions.fail_on_rejection + + If the test is asynchronous and its resulting promise is + rejected, fail the test. Defaults to ``true``, set to + ``false`` to not fail the test in case of rejection:: + + // test/demo.js + test('unfail rejection', { + asserts: 1, + fail_on_rejection: false + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.reject(); + }, 100); + return d; + }); + + .. js:attribute:: TestOptions.rpc + + RPC method to use during tests, one of ``"mock"`` or + ``"rpc"``. Any other value will disable RPC for the test (if + they were enabled by the suite for instance). + + .. js:attribute:: TestOptions.templates + + Whether the current module (and its dependencies)'s templates + should be loaded into QWeb before starting the test. A + boolean, ``false`` by default. + +The test runner can also use two global configuration values set +directly on the ``window`` object: + +* ``oe_all_dependencies`` is an ``Array`` of all modules with a web + component, ordered by dependency (for a module ``A`` with + dependencies ``A'``, any module of ``A'`` must come before ``A`` in + the array) + +* ``oe_db_info`` is an object with 3 keys ``source``, ``supadmin`` and + ``password``. It is used to pre-configure :ref:`actual RPC + <testing-rpc-rpc>` tests, to avoid a prompt being displayed + (especially for headless situations). + +Running through Python +---------------------- + +The web client includes the means to run these tests on the +command-line (or in a CI system), but while actually running it is +pretty simple the setup of the pre-requisite parts has some +complexities. + +1. Install unittest2_ and QUnitSuite_ in your Python environment. Both + can trivially be installed via `pip <http://pip-installer.org>`_ or + `easy_install + <http://packages.python.org/distribute/easy_install.html>`_. + + The former is the unit-testing framework used by OpenERP, the + latter is an adapter module to run qunit_ test suites and convert + their result into something unittest2_ can understand and report. + +2. Install PhantomJS_. It is a headless + browser which allows automating running and testing web + pages. QUnitSuite_ uses it to actually run the qunit_ test suite. + + The PhantomJS_ website provides pre-built binaries for some + platforms, and your OS's package management probably provides it as + well. + + If you're building PhantomJS_ from source, I recommend preparing + for some knitting time as it's not exactly fast (it needs to + compile both `Qt <http://qt-project.org/>`_ and `Webkit + <http://www.webkit.org/>`_, both being pretty big projects). + + .. note:: + + Because PhantomJS_ is webkit-based, it will not be able to test + if Firefox, Opera or Internet Explorer can correctly run the + test suite (and it is only an approximation for Safari and + Chrome). It is therefore recommended to *also* run the test + suites in actual browsers once in a while. + + .. note:: + + The version of PhantomJS_ this was build through is 1.7, + previous versions *should* work but are not actually supported + (and tend to just segfault when something goes wrong in + PhantomJS_ itself so they're a pain to debug). + +3. Set up :ref:`OpenERP Command <openerpcommand:openerp-command>`, + which will be used to actually run the tests: running the qunit_ + test suite requires a running server, so at this point OpenERP + Server isn't able to do it on its own during the building/testing + process. + +4. Install a new database with all relevant modules (all modules with + a web component at least), then restart the server + + .. note:: + + For some tests, a source database needs to be duplicated. This + operation requires that there be no connection to the database + being duplicated, but OpenERP doesn't currently break + existing/outstanding connections, so restarting the server is + the simplest way to ensure everything is in the right state. + +5. Launch ``oe run-tests -d $DATABASE -mweb`` with the correct + addons-path specified (and replacing ``$DATABASE`` by the source + database you created above) + + .. note:: + + If you leave out ``-mweb``, the runner will attempt to run all + the tests in all the modules, which may or may not work. + +If everything went correctly, you should now see a list of tests with +(hopefully) ``ok`` next to their names, closing with a report of the +number of tests run and the time it took: + +.. literalinclude:: test-report.txt + :language: text + +Congratulation, you have just performed a successful "offline" run of +the OpenERP Web test suite. + +.. note:: + + Note that this runs all the Python tests for the ``web`` module, + but all the web tests for all of OpenERP. This can be surprising. + +.. _qunit: http://qunitjs.com/ + +.. _qunit assertions: http://api.qunitjs.com/category/assert/ + +.. _unittest2: http://pypi.python.org/pypi/unittest2 + +.. _QUnitSuite: http://pypi.python.org/pypi/QUnitSuite/ + +.. _PhantomJS: http://phantomjs.org/ diff --git a/addons/web/doc/widget.rst b/addons/web/doc/widget.rst index ddfe525227d..7466ebaf3e8 100644 --- a/addons/web/doc/widget.rst +++ b/addons/web/doc/widget.rst @@ -1,5 +1,5 @@ -User Interaction: Widget -======================== +Widget +====== This is the base class for all visual components. It corresponds to an MVC view. It provides a number of services to handle a section of a page: diff --git a/addons/web/http.py b/addons/web/http.py index 1a636971fb5..fc80cb03864 100644 --- a/addons/web/http.py +++ b/addons/web/http.py @@ -11,6 +11,7 @@ import logging import mimetypes import os import pprint +import random import sys import tempfile import threading @@ -21,6 +22,7 @@ import urlparse import uuid import xmlrpclib +import babel.core import simplejson import werkzeug.contrib.sessions import werkzeug.datastructures @@ -91,9 +93,25 @@ class WebRequest(object): self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex self.session = self.httpsession.get(self.session_id) if not self.session: - self.httpsession[self.session_id] = self.session = session.OpenERPSession() + self.session = session.OpenERPSession() + self.httpsession[self.session_id] = self.session self.context = self.params.pop('context', None) - self.debug = self.params.pop('debug', False) != False + self.debug = self.params.pop('debug', False) is not False + # Determine self.lang + lang = self.params.get('lang', None) + if lang is None: + lang = self.session.eval_context(self.context).get('lang') + if lang is None: + lang = self.httprequest.cookies.get('lang') + if lang is None: + lang = self.httprequest.accept_languages.best + if lang is None: + lang = 'en_US' + # tranform 2 letters lang like 'en' into 5 letters like 'en_US' + lang = babel.core.LOCALE_ALIASES.get(lang, lang) + # we use _ as seprator where RFC2616 uses '-' + self.lang = lang.replace('-', '_') + class JsonRequest(WebRequest): """ JSON-RPC2 over HTTP. @@ -210,6 +228,10 @@ class JsonRequest(WebRequest): _logger.debug("<--\n%s", pprint.pformat(response)) if 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 + # We need then to manage http sessions manually. + response['httpsessionid'] = self.httpsession.sid mime = 'application/javascript' body = "%s(%s);" % (jsonp, simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder),) else: @@ -336,23 +358,13 @@ class Controller(object): #---------------------------------------------------------- # Session context manager #---------------------------------------------------------- -STORES = {} - @contextlib.contextmanager -def session_context(request, storage_path, session_cookie='httpsessionid'): - session_store, session_lock = STORES.get(storage_path, (None, None)) - if not session_store: - session_store = werkzeug.contrib.sessions.FilesystemSessionStore( storage_path) - session_lock = threading.Lock() - STORES[storage_path] = session_store, session_lock - - sid = request.cookies.get(session_cookie) +def session_context(request, session_store, session_lock, sid): with session_lock: if sid: request.session = session_store.get(sid) else: request.session = session_store.new() - try: yield request.session finally: @@ -404,6 +416,18 @@ def session_context(request, storage_path, session_cookie='httpsessionid'): session_store.save(request.session) +def session_gc(session_store): + if random.random() < 0.001: + # we keep session one week + last_week = time.time() - 60*60*24*7 + for fname in os.listdir(session_store.path): + path = os.path.join(session_store.path, fname) + try: + if os.path.getmtime(path) < last_week: + os.unlink(path) + except OSError: + pass + #---------------------------------------------------------- # WSGI Application #---------------------------------------------------------- @@ -434,26 +458,31 @@ class DisableCacheMiddleware(object): start_response(status, new_headers) return self.app(environ, start_wrapped) +def session_path(): + try: + username = getpass.getuser() + except Exception: + username = "unknown" + path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username) + if not os.path.exists(path): + os.mkdir(path, 0700) + return path + class Root(object): """Root WSGI application for the OpenERP Web Client. """ def __init__(self): - self.httpsession_cookie = 'httpsessionid' self.addons = {} static_dirs = self._load_addons() app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs) self.dispatch = DisableCacheMiddleware(app) - try: - username = getpass.getuser() - except Exception: - username = "unknown" - self.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username) - - if not os.path.exists(self.session_storage): - os.mkdir(self.session_storage, 0700) - _logger.debug('HTTP sessions stored in: %s', self.session_storage) + # Setup http sessions + path = session_path() + self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path) + self.session_lock = threading.Lock() + _logger.debug('HTTP sessions stored in: %s', path) def __call__(self, environ, start_response): """ Handle a WSGI request @@ -476,8 +505,14 @@ class Root(object): if not handler: response = werkzeug.exceptions.NotFound() else: - with session_context(request, self.session_storage, self.httpsession_cookie) as session: - result = handler( request) + sid = request.cookies.get('sid') + if not sid: + sid = request.args.get('sid') + + session_gc(self.session_store) + + with session_context(request, self.session_store, self.session_lock, sid) as session: + result = handler(request) if isinstance(result, basestring): headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))] @@ -486,7 +521,7 @@ class Root(object): response = result if hasattr(response, 'set_cookie'): - response.set_cookie(self.httpsession_cookie, session.sid) + response.set_cookie('sid', session.sid) return response(environ, start_response) @@ -530,7 +565,7 @@ class Root(object): :rtype: ``Controller | None`` """ if l: - ps = '/' + '/'.join(l) + ps = '/' + '/'.join(filter(None, l)) method_name = 'index' while ps: c = controllers_path.get(ps) diff --git a/addons/web/i18n/ar.po b/addons/web/i18n/ar.po index e5d92071388..933e81f8772 100644 --- a/addons/web/i18n/ar.po +++ b/addons/web/i18n/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/bg.po b/addons/web/i18n/bg.po index cb1ffd2c5ab..3cc1bb77ec8 100644 --- a/addons/web/i18n/bg.po +++ b/addons/web/i18n/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/bn.po b/addons/web/i18n/bn.po index a1934f5346e..78d247805a3 100644 --- a/addons/web/i18n/bn.po +++ b/addons/web/i18n/bn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/bs.po b/addons/web/i18n/bs.po index 525a46053bd..4ca035262f7 100644 --- a/addons/web/i18n/bs.po +++ b/addons/web/i18n/bs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/ca.po b/addons/web/i18n/ca.po index 8082c37717d..88fc0e32653 100644 --- a/addons/web/i18n/ca.po +++ b/addons/web/i18n/ca.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/cs.po b/addons/web/i18n/cs.po index a12beb474b9..ceb1015a763 100644 --- a/addons/web/i18n/cs.po +++ b/addons/web/i18n/cs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" "X-Poedit-Language: Czech\n" #. openerp-web diff --git a/addons/web/i18n/da.po b/addons/web/i18n/da.po index 2f8d5ef4e36..a35bac7c918 100644 --- a/addons/web/i18n/da.po +++ b/addons/web/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/de.po b/addons/web/i18n/de.po index 078004291a0..552f1e30f1b 100644 --- a/addons/web/i18n/de.po +++ b/addons/web/i18n/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/en_AU.po b/addons/web/i18n/en_AU.po index bdcedadd13d..268be13bd10 100644 --- a/addons/web/i18n/en_AU.po +++ b/addons/web/i18n/en_AU.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/en_GB.po b/addons/web/i18n/en_GB.po index 59a4e42c925..48d5af11c8a 100644 --- a/addons/web/i18n/en_GB.po +++ b/addons/web/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/es.po b/addons/web/i18n/es.po index 8a086ec3654..745ba60db93 100644 --- a/addons/web/i18n/es.po +++ b/addons/web/i18n/es.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/es_CL.po b/addons/web/i18n/es_CL.po index f52e92abcee..9c0839670f2 100644 --- a/addons/web/i18n/es_CL.po +++ b/addons/web/i18n/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/es_CR.po b/addons/web/i18n/es_CR.po index c09f10df847..29b09fa3d6c 100644 --- a/addons/web/i18n/es_CR.po +++ b/addons/web/i18n/es_CR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" "Language: es\n" #. openerp-web diff --git a/addons/web/i18n/es_EC.po b/addons/web/i18n/es_EC.po index 28de64fb3c2..2f834527232 100644 --- a/addons/web/i18n/es_EC.po +++ b/addons/web/i18n/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/et.po b/addons/web/i18n/et.po index bc1e88e7cf9..fc4fd35beac 100644 --- a/addons/web/i18n/et.po +++ b/addons/web/i18n/et.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/eu.po b/addons/web/i18n/eu.po index 2f724a53987..1e4526e67cc 100644 --- a/addons/web/i18n/eu.po +++ b/addons/web/i18n/eu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/fi.po b/addons/web/i18n/fi.po index 9301615a6f5..ce97bef4c44 100644 --- a/addons/web/i18n/fi.po +++ b/addons/web/i18n/fi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/fr.po b/addons/web/i18n/fr.po index bdcecc565d0..fdc3c87a399 100644 --- a/addons/web/i18n/fr.po +++ b/addons/web/i18n/fr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/fr_CA.po b/addons/web/i18n/fr_CA.po index 104237fcc96..63c777fed9c 100644 --- a/addons/web/i18n/fr_CA.po +++ b/addons/web/i18n/fr_CA.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/gl.po b/addons/web/i18n/gl.po index 82804e9a00b..e6a8a84970d 100644 --- a/addons/web/i18n/gl.po +++ b/addons/web/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/gu.po b/addons/web/i18n/gu.po index 0e9bb980006..eed6596d47d 100644 --- a/addons/web/i18n/gu.po +++ b/addons/web/i18n/gu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/hi.po b/addons/web/i18n/hi.po index 4ded6cef521..c3fec02900b 100644 --- a/addons/web/i18n/hi.po +++ b/addons/web/i18n/hi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/hr.po b/addons/web/i18n/hr.po index 6ce16f5bda3..774b006975c 100644 --- a/addons/web/i18n/hr.po +++ b/addons/web/i18n/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/hu.po b/addons/web/i18n/hu.po index cea5493c029..9587dbd3081 100644 --- a/addons/web/i18n/hu.po +++ b/addons/web/i18n/hu.po @@ -9,13 +9,13 @@ msgstr "" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "POT-Creation-Date: 2012-07-02 09:06+0200\n" "PO-Revision-Date: 2012-10-26 12:17+0000\n" -"Last-Translator: Herczeg Péter <herczegp@gmail.com>\n" +"Last-Translator: Herczeg Péter <hp@erp-cloud.hu>\n" "Language-Team: Hungarian <hu@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-27 05:15+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/id.po b/addons/web/i18n/id.po index b681859b55a..12509847ba3 100644 --- a/addons/web/i18n/id.po +++ b/addons/web/i18n/id.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/it.po b/addons/web/i18n/it.po index 7df8f4c27bb..6f0f9025e18 100644 --- a/addons/web/i18n/it.po +++ b/addons/web/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-23 05:05+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/ja.po b/addons/web/i18n/ja.po index 3da4bb12ac5..ae6f58716ba 100644 --- a/addons/web/i18n/ja.po +++ b/addons/web/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/ka.po b/addons/web/i18n/ka.po index 1abd1880405..7c64ddb5ec9 100644 --- a/addons/web/i18n/ka.po +++ b/addons/web/i18n/ka.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/lt.po b/addons/web/i18n/lt.po index 195c0f3c82c..ecbe6ec4085 100644 --- a/addons/web/i18n/lt.po +++ b/addons/web/i18n/lt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 @@ -66,7 +66,7 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/chrome.js:499 msgid "Restored" -msgstr "" +msgstr "Atkurta" #. openerp-web #: addons/web/static/src/js/chrome.js:499 @@ -253,7 +253,7 @@ msgstr "" #: addons/web/static/src/js/formats.js:139 #, python-format msgid "(%d records)" -msgstr "" +msgstr "(%d įrašai(-ų))" #. openerp-web #: addons/web/static/src/js/formats.js:325 @@ -265,7 +265,7 @@ msgstr "Atsisiųsti" #: addons/web/static/src/js/formats.js:330 #, python-format msgid "Download \"%s\"" -msgstr "" +msgstr "Parsisiųsti \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:437 @@ -527,12 +527,12 @@ msgstr "Forma" #: addons/web/static/src/xml/base.xml:763 #: addons/web/static/src/xml/base.xml:1714 msgid "Delete" -msgstr "" +msgstr "Ištrinti" #. openerp-web #: addons/web/static/src/xml/base.xml:762 msgid "Duplicate" -msgstr "" +msgstr "Sukurti kopiją" #. openerp-web #: addons/web/static/src/js/view_form.js:133 @@ -589,12 +589,12 @@ msgstr "" #: addons/web/static/src/js/view_form.js:2238 #, python-format msgid "<em> Create \"<strong>%s</strong>\"</em>" -msgstr "" +msgstr "<em> Sukurti \"<strong>%s</strong>\"</em>" #. openerp-web #: addons/web/static/src/js/view_form.js:2244 msgid "<em> Create and Edit...</em>" -msgstr "" +msgstr "<em> Sukurti ir redaguoti...</em>" #. openerp-web #: addons/web/static/src/js/view_form.js:2277 @@ -606,7 +606,7 @@ msgstr "Paieška: " #: addons/web/static/src/js/view_form.js:2277 #: addons/web/static/src/js/view_form.js:2765 msgid "Create: " -msgstr "" +msgstr "Sukurti " #. openerp-web #: addons/web/static/src/js/view_form.js:2062 @@ -668,7 +668,7 @@ msgstr "Grupė" #. openerp-web #: addons/web/static/src/js/view_list.js:549 msgid "Do you really want to remove these records?" -msgstr "" +msgstr "Ar tikrai norite ištrinti šiuos įrašus?" #. openerp-web #: addons/web/static/src/js/views.js:925 @@ -813,25 +813,25 @@ msgstr "" #. openerp-web #: addons/web/static/src/xml/base.xml:297 msgid "Invalid username or password" -msgstr "" +msgstr "Neteisingas naudotojo vardas arba slaptažodis" #. openerp-web #: addons/web/static/src/xml/base.xml:116 #: addons/web/static/src/xml/base.xml:150 #: addons/web/static/src/xml/base.xml:301 msgid "Database:" -msgstr "" +msgstr "Duomenų bazė:" #. openerp-web #: addons/web/static/src/xml/base.xml:306 msgid "Username" -msgstr "" +msgstr "Naudotojas" #. openerp-web #: addons/web/static/src/xml/base.xml:308 #: addons/web/static/src/xml/base.xml:331 msgid "Password" -msgstr "" +msgstr "Slaptažodis" #. openerp-web #: addons/web/static/src/xml/base.xml:310 @@ -870,17 +870,17 @@ msgstr "" #: addons/web/static/src/xml/base.xml:195 #: addons/web/static/src/xml/base.xml:330 msgid "Restore" -msgstr "" +msgstr "Atkurti" #. openerp-web #: addons/web/static/src/xml/base.xml:332 msgid "Back to Login" -msgstr "" +msgstr "Grįžti į prisijungimo langą" #. openerp-web #: addons/web/static/src/xml/base.xml:61 msgid "CREATE DATABASE" -msgstr "" +msgstr "SUKURTI DUOMENŲ BAZĘ" #. openerp-web #: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211 @@ -922,7 +922,7 @@ msgstr "" #: addons/web/static/src/xml/base.xml:162 #: addons/web/static/src/xml/base.xml:187 msgid "Master Password:" -msgstr "" +msgstr "Pagrindinis slaptažodis" #. openerp-web #: addons/web/static/src/xml/base.xml:143 @@ -932,7 +932,7 @@ msgstr "" #. openerp-web #: addons/web/static/src/xml/base.xml:175 msgid "RESTORE DATABASE" -msgstr "" +msgstr "ATKURTI DUOMENŲ BAZĘ" #. openerp-web #: addons/web/static/src/xml/base.xml:182 @@ -1012,17 +1012,17 @@ msgstr "OpenERP.com" #. openerp-web #: addons/web/static/src/xml/base.xml:1720 msgid "Old Password:" -msgstr "" +msgstr "Esamas slaptažodis:" #. openerp-web #: addons/web/static/src/xml/base.xml:1725 msgid "New Password:" -msgstr "" +msgstr "Naujas slaptažodis:" #. openerp-web #: addons/web/static/src/xml/base.xml:1730 msgid "Confirm Password:" -msgstr "" +msgstr "Patvirtinti slaptažodį:" #. openerp-web #: addons/web/static/src/xml/base.xml:390 @@ -1254,7 +1254,7 @@ msgstr "" #: addons/web/static/src/xml/base.xml:1222 #: addons/web/static/src/xml/base.xml:1279 msgid "Clear" -msgstr "" +msgstr "Išvalyti" #. openerp-web #: addons/web/static/src/xml/base.xml:1179 @@ -1408,12 +1408,12 @@ msgstr "" #. openerp-web #: addons/web/static/src/xml/base.xml:1509 msgid "Save & New" -msgstr "" +msgstr "Išsaugoti ir sukurti naują" #. openerp-web #: addons/web/static/src/xml/base.xml:1510 msgid "Save & Close" -msgstr "" +msgstr "Išsaugoti ir uždaryti" #. openerp-web #: addons/web/static/src/xml/base.xml:1617 @@ -1572,9 +1572,6 @@ msgstr "" #~ msgid "Advanced Filters" #~ msgstr "Išplėstiniai filtrai" -#~ msgid "Other Options" -#~ msgstr "Kiti nustatymai" - #~ msgid "OK" #~ msgstr "Gerai" @@ -1602,3 +1599,22 @@ msgstr "" #~ msgid "Reports" #~ msgstr "Ataskaitos" + +#~ msgid "Other Options" +#~ msgstr "Kitos parinktys" + +#~ msgid "LOGOUT" +#~ msgstr "ATSIJUNGTI" + +#~ msgid "Create..." +#~ msgstr "Sukurti..." + +#~ msgid "Search" +#~ msgstr "Ieškoti" + +#~ msgid "Search..." +#~ msgstr "Ieškoti..." + +#, python-format +#~ msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" +#~ msgstr "[%(first_record)d iki %(last_record)d] iš %(records_count)d" diff --git a/addons/web/i18n/mk.po b/addons/web/i18n/mk.po index 62bef3d0015..30db39b4dfc 100644 --- a/addons/web/i18n/mk.po +++ b/addons/web/i18n/mk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/mn.po b/addons/web/i18n/mn.po index a862954b815..3ee9a552022 100644 --- a/addons/web/i18n/mn.po +++ b/addons/web/i18n/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/nb.po b/addons/web/i18n/nb.po index f47de43b3cf..0b44af2712d 100644 --- a/addons/web/i18n/nb.po +++ b/addons/web/i18n/nb.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/nl.po b/addons/web/i18n/nl.po index 49631585157..eb80e4586ba 100644 --- a/addons/web/i18n/nl.po +++ b/addons/web/i18n/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/nl_BE.po b/addons/web/i18n/nl_BE.po index b3be018903b..04e45611f2d 100644 --- a/addons/web/i18n/nl_BE.po +++ b/addons/web/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/pl.po b/addons/web/i18n/pl.po index d5d854768d0..25cf2862611 100644 --- a/addons/web/i18n/pl.po +++ b/addons/web/i18n/pl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 @@ -243,17 +243,19 @@ msgid "" "Destination fields should only be selected once, some fields are selected " "more than once:" msgstr "" +"Pola docelowe muszą być wybierane tylko raz. niektóre inne pola mogą być " +"wybierane więcej niż raz:" #. openerp-web #: addons/web/static/src/js/data_import.js:386 msgid "*Required Fields are not selected :" -msgstr "" +msgstr "*Wymagane pola nie zostały wybrane :" #. openerp-web #: addons/web/static/src/js/formats.js:139 #, python-format msgid "(%d records)" -msgstr "" +msgstr "(%d rekordów)" #. openerp-web #: addons/web/static/src/js/formats.js:325 diff --git a/addons/web/i18n/pt.po b/addons/web/i18n/pt.po index 3bf3fa6062d..95f3c546400 100644 --- a/addons/web/i18n/pt.po +++ b/addons/web/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/pt_BR.po b/addons/web/i18n/pt_BR.po index d950e97938c..6f14bf1f547 100644 --- a/addons/web/i18n/pt_BR.po +++ b/addons/web/i18n/pt_BR.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/ro.po b/addons/web/i18n/ro.po index 934e2e77f63..6a77472b1e4 100644 --- a/addons/web/i18n/ro.po +++ b/addons/web/i18n/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/ru.po b/addons/web/i18n/ru.po index ed5735602d0..341f683e953 100644 --- a/addons/web/i18n/ru.po +++ b/addons/web/i18n/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-02 05:20+0000\n" -"X-Generator: Launchpad (build 16218)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/sk.po b/addons/web/i18n/sk.po index 39bdd647453..12b5d5a1c56 100644 --- a/addons/web/i18n/sk.po +++ b/addons/web/i18n/sk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/sl.po b/addons/web/i18n/sl.po index 687742a1775..0c745f42d41 100644 --- a/addons/web/i18n/sl.po +++ b/addons/web/i18n/sl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-02 05:20+0000\n" -"X-Generator: Launchpad (build 16218)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/sq.po b/addons/web/i18n/sq.po index df11fea07c0..357e83e2bcf 100644 --- a/addons/web/i18n/sq.po +++ b/addons/web/i18n/sq.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/sr@latin.po b/addons/web/i18n/sr@latin.po index f52bea117d6..9fc0e685c54 100644 --- a/addons/web/i18n/sr@latin.po +++ b/addons/web/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/sv.po b/addons/web/i18n/sv.po index 64fc3c7e767..db6d9f7ae88 100644 --- a/addons/web/i18n/sv.po +++ b/addons/web/i18n/sv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/tr.po b/addons/web/i18n/tr.po index 2467938d84d..9c5554bc028 100644 --- a/addons/web/i18n/tr.po +++ b/addons/web/i18n/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/uk.po b/addons/web/i18n/uk.po index 2b981ebf178..553beb5d123 100644 --- a/addons/web/i18n/uk.po +++ b/addons/web/i18n/uk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/zh_CN.po b/addons/web/i18n/zh_CN.po index 09a7d041b88..e66a5742745 100644 --- a/addons/web/i18n/zh_CN.po +++ b/addons/web/i18n/zh_CN.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-07 04:55+0000\n" -"X-Generator: Launchpad (build 16232)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/i18n/zh_TW.po b/addons/web/i18n/zh_TW.po index b803a5c04c3..b07bc75ae31 100644 --- a/addons/web/i18n/zh_TW.po +++ b/addons/web/i18n/zh_TW.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 diff --git a/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js b/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js index 5929d591261..e978042f21b 100644 --- a/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js +++ b/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js @@ -27,7 +27,8 @@ var $tip = this.tip(); $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title); - $tip[0].className = 'tipsy openerp oe_tooltip '; // reset classname in case of dynamic gravity + $tip[0].className = 'tipsy '; // reset classname in case of dynamic gravity + $tip.openerpClass('oe_tooltip'); $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body); var pos = $.extend({}, this.$element.offset(), { diff --git a/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css b/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css index a06e9447afc..f19c56caed1 100644 --- a/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css +++ b/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css @@ -1115,7 +1115,7 @@ body .ui-tooltip { border-width:2px; } /*** Input field styling from Bootstrap **/ - input, textarea { +/* input, textarea { -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -ms-transition: border linear 0.2s, box-shadow linear 0.2s; @@ -1137,12 +1137,12 @@ input[type=file]:focus, input[type=checkbox]:focus, select:focus { -moz-box-shadow: none; box-shadow: none; outline: 1px dotted #666; -} +}*/ -input[type="text"], -input[type="password"], +/*input[type="text"], +input[type="password"],*/ .ui-autocomplete-input, -textarea, +/*textarea,*/ .uneditable-input { display: inline-block; padding: 4px; diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 94d02758ad0..ab7b74f85fe 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -20,20 +20,6 @@ font-style: normal; } -@media print { - .oe_topbar, .oe_leftbar, .oe_loading { - display: none !important; - } -} -.openerp.openerp_webclient_container { - height: 100%; -} - -.text-tag .text-button { - height: auto !important; - min-height: 16px; -} - .openerp { padding: 0; margin: 0; @@ -46,6 +32,9 @@ * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image */ } +.openerp.openerp_webclient_container { + height: 100%; +} .openerp :-moz-placeholder { color: #afafb6 !important; font-style: italic !important; @@ -197,6 +186,10 @@ .openerp .oe_bounce_container { display: inline-block; } +.openerp .text-tag .text-button { + height: auto !important; + min-height: 16px; +} .openerp .ui-tabs { position: static; } @@ -1136,6 +1129,7 @@ height: 40px; width: 157px; margin: 14px 0; + border: 0; } .openerp .oe_footer { position: fixed; @@ -2306,16 +2300,16 @@ text-align: justify; } .openerp .oe_form_editable .oe_form .oe_form_field_integer input { - width: 6em !important; + width: 6em; } .openerp .oe_form_editable .oe_form .oe_form_field_float input { - width: 7em !important; + width: 7em; } .openerp .oe_form_editable .oe_form .oe_form_field_date input { - width: 7.5em !important; + width: 7.5em; } .openerp .oe_form_editable .oe_form .oe_form_field_datetime input { - width: 11.5em !important; + width: 11.5em; } .openerp .oe_hidden_input_file { position: relative; @@ -2361,6 +2355,77 @@ .openerp .oe_form .oe_form_field_image:hover .oe_form_field_image_controls { display: block; } +.openerp .oe_fileupload { + display: inline-block; + clear: both; + width: 100%; +} +.openerp .oe_fileupload .oe_add { + float: left; + position: relative; + width: 100%; + left: 2px; + top: 7px; +} +.openerp .oe_fileupload .oe_add button { + display: inline; + height: 24px; + font-size: 12px; + line-height: 12px; + vertical-align: middle; +} +.openerp .oe_fileupload .oe_add button.oe_attach { + width: 24px; + overflow: hidden; + width: 24px; + overflow: hidden; + background: transparent; + color: #7c7bad; + box-shadow: none; + border: none; + text-shadow: none; +} +.openerp .oe_fileupload .oe_add button.oe_attach .oe_e { + position: relative; + top: -1px; + left: -9px; +} +.openerp .oe_fileupload .oe_add input.oe_form_binary_file { + display: inline-block; + margin-left: -5px; + height: 28px; + width: 52px; + margin-top: -26px; +} +.openerp .oe_fileupload .oe_add .oe_attach_label { + color: #7c7bad; + margin-left: -3px; +} +.openerp .oe_fileupload .oe_attachments { + margin-bottom: 4px; + margin-right: 0px; + font-size: 12px; + border-radius: 2px; + border: solid 1px rgba(124, 123, 173, 0.14); +} +.openerp .oe_fileupload .oe_attachments .oe_attachment { + padding: 2px; + padding-left: 4px; + padding-right: 4px; +} +.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e { + font-size: 23px; + margin-top: -5px; +} +.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e:hover { + text-decoration: none; +} +.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(odd) { + background: white; +} +.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(even) { + background: #f4f5fa; +} .openerp .oe_form_field_many2one td:first-child { position: relative; } @@ -2374,6 +2439,9 @@ float: right; padding-left: 2px; } +.openerp .oe_form_field_many2one input { + padding-right: 13px; +} .openerp.ui-autocomplete li.oe_m2o_dropdown_option a { font-style: italic; padding-left: 2em; @@ -2578,32 +2646,33 @@ top: 5px; } .openerp .oe_list.oe_list_editable.oe_editing .oe_m2o_cm_button { - display: none; + line-height: 19px; } -.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea { - height: 27px; +.openerp .oe_list.oe_list_editable.oe_editing .oe_input_icon { + margin-top: 5px; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field { + min-width: 0; + max-width: none; } .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea { + height: 27px; -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border: 1px solid #aaaaff; margin: 0; } +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field select { + min-width: 0; +} .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_float input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_view_integer input { text-align: right; width: 100% !important; } -.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime > span, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date > span { - width: 100% !important; -} .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime input.oe_datepicker_master, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date input.oe_datepicker_master { width: 100% !important; } -.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field .oe_form_field_float, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field .oe_form_view_integer, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date { - min-width: 0 !important; - max-width: none !important; -} .openerp .oe_list_group_name { white-space: nowrap; } @@ -2668,6 +2737,9 @@ text-align: right !important; max-width: 100px; } +.openerp .oe_list_content td.oe_list_field_date, .openerp .oe_list_content th.oe_list_header_date { + min-width: 6em; +} .openerp .oe_list_content > thead { border-bottom: 2px solid #cacaca; background: #eeeeee; @@ -2735,6 +2807,10 @@ .openerp .oe_list_content > tbody > tr > td.oe_list_checkbox:first-child:after, .openerp .oe_list_content > tbody > tr th.oe_list_checkbox:first-child:after { border-width: 0; } +.openerp .oe_list_content > tbody > tr > td.oe_list_field_boolean input { + filter: alpha(opacity=50); + opacity: 0.5; +} .openerp .oe_list_content > tbody > tr:nth-child(odd) { background-color: #f0f0fa; background-color: #f0f0fa; @@ -2882,78 +2958,6 @@ color: #333333; } -.openerp .oe_fileupload { - display: inline-block; - clear: both; - width: 100%; -} -.openerp .oe_fileupload .oe_add { - float: left; - position: relative; - width: 100%; - left: 2px; - top: 7px; -} -.openerp .oe_fileupload .oe_add button { - display: inline; - height: 24px; - font-size: 12px; - line-height: 12px; - vertical-align: middle; -} -.openerp .oe_fileupload .oe_add button.oe_attach { - width: 24px; - overflow: hidden; - width: 24px; - overflow: hidden; - background: transparent; - color: #7c7bad; - box-shadow: none; - border: none; - text-shadow: none; -} -.openerp .oe_fileupload .oe_add button.oe_attach .oe_e { - position: relative; - top: -1px; - left: -9px; -} -.openerp .oe_fileupload .oe_add input.oe_form_binary_file { - display: inline-block; - margin-left: -5px; - height: 28px; - width: 52px; - margin-top: -26px; -} -.openerp .oe_fileupload .oe_add .oe_attach_label { - color: #7c7bad; - margin-left: -3px; -} -.openerp .oe_fileupload .oe_attachments { - margin-bottom: 4px; - margin-right: 0px; - font-size: 12px; - border-radius: 2px; - border: solid 1px rgba(124, 123, 173, 0.14); -} -.openerp .oe_fileupload .oe_attachments .oe_attachment { - padding: 2px; - padding-left: 4px; - padding-right: 4px; -} -.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e { - font-size: 23px; - margin-top: -5px; -} -.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e:hover { - text-decoration: none; -} -.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(odd) { - background: white; -} -.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(even) { - background: #f4f5fa; -} - .kitten-mode-activated { background-image: url(http://placekitten.com/g/1365/769); background-size: cover; @@ -3012,8 +3016,8 @@ div.ui-widget-overlay { .openerp { text-shadow: none; } - .openerp .oe_header_row, .openerp ul.oe_header, .openerp div.oe_mail_thread_action, .openerp .oe_mail_recthread_actions, .openerp .oe_button_box, .openerp .oe_form button, .openerp button.oe_invite, .openerp .oe_form header, .openerp .openerp .oe_notebook > li.ui-state-default { - display: none; + .openerp .oe_header_row, .openerp ul.oe_header, .openerp div.oe_mail_thread_action, .openerp .oe_mail_recthread_actions, .openerp .oe_button_box, .openerp .oe_form button, .openerp button.oe_invite, .openerp .oe_form header, .openerp .openerp .oe_notebook > li.ui-state-default, .openerp .oe_topbar, .openerp .oe_leftbar, .openerp .oe_loading { + display: none !important; } .openerp .oe_list_content button, .openerp .oe_list_content input[type=checkbox] { visibility: hidden; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index f911929e159..c5fcb8008a5 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -140,18 +140,6 @@ $sheet-padding: 16px // }}} -@media print - .oe_topbar, .oe_leftbar, .oe_loading - display: none !important - -.openerp.openerp_webclient_container - height: 100% - -// jQueryUI css bug fixing -.text-tag .text-button - height: auto !important - min-height: 16px - .openerp // Global style {{{ padding: 0 @@ -161,6 +149,8 @@ $sheet-padding: 16px font-size: 13px background: white text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5) + &.openerp_webclient_container + height: 100% // }}} //Placeholder style{{{ \:-moz-placeholder @@ -254,6 +244,11 @@ $sheet-padding: 16px .oe_bounce_container display: inline-block + // Bug lp:1051746 + .text-tag .text-button + height: auto !important + min-height: 16px + // bug noted in jquery ui CSS doesn't seem to occur in IE9, // so remove position:relative .ui-tabs @@ -928,6 +923,7 @@ $sheet-padding: 16px height: 40px width: 157px margin: 14px 0 + border: 0 .oe_footer position: fixed bottom: 0 @@ -1837,13 +1833,13 @@ $sheet-padding: 16px .oe_form_editable .oe_form .oe_form_field_integer input - width: 6em !important + width: 6em .oe_form_field_float input - width: 7em !important + width: 7em .oe_form_field_date input - width: 7.5em !important + width: 7.5em .oe_form_field_datetime input - width: 11.5em !important + width: 11.5em // }}} // FormView.fields_binary {{{ /* http://www.quirksmode.org/dom/inputfile.html @@ -1886,6 +1882,64 @@ $sheet-padding: 16px @include box-sizing(border) &:hover .oe_form_field_image_controls display: block + .oe_fileupload + display: inline-block + clear: both + width: 100% + .oe_add + float: left + position: relative + width: 100% + left: +2px + top: +7px + button + display: inline + height: 24px + font-size: 12px + line-height: 12px + vertical-align: middle + button.oe_attach + width: 24px + overflow: hidden + width: 24px + overflow: hidden + background: transparent + color: #7C7BAD + box-shadow: none + border: none + text-shadow: none + .oe_e + position: relative + top: -1px + left: -9px + input.oe_form_binary_file + display: inline-block + margin-left: -5px + height: 28px + width: 52px + margin-top: -26px + .oe_attach_label + color: #7C7BAD + margin-left: -3px + .oe_attachments + margin-bottom: 4px + margin-right: 0px + font-size: 12px + border-radius: 2px + border: solid 1px rgba(124,123,173,0.14) + .oe_attachment + padding: 2px + padding-left: 4px + padding-right: 4px + .oe_e + font-size: 23px + margin-top: -5px + .oe_e:hover + text-decoration: none + .oe_attachment:nth-child(odd) + background: white + .oe_attachment:nth-child(even) + background: #F4F5FA // }}} // FormView.many2one {{{ .oe_form_field_many2one @@ -1899,6 +1953,8 @@ $sheet-padding: 16px line-height: 14px float: right padding-left: 2px + input + padding-right: 13px &.ui-autocomplete li.oe_m2o_dropdown_option a font-style: italic @@ -2041,26 +2097,26 @@ $sheet-padding: 16px .oe_m2o_drop_down_button top: 5px .oe_m2o_cm_button - display: none + line-height: 19px + .oe_input_icon + margin-top: 5px .oe_form_field + min-width: 0 + max-width: none input, textarea height: $row-height - input, textarea @include radius(0) border: 1px solid #aaf margin: 0 + input, textarea, select + min-width: 0 &.oe_form_field_float,&.oe_form_view_integer input text-align: right width: 100% !important &.oe_form_field_datetime,&.oe_form_field_date - > span - width: 100% !important input.oe_datepicker_master width: 100% !important - .oe_form_field_float,.oe_form_view_integer,&.oe_form_field_datetime,&.oe_form_field_date - min-width: 0 !important - max-width: none !important .oe_list_group_name white-space: nowrap // }}} @@ -2119,6 +2175,8 @@ $sheet-padding: 16px td.oe_number text-align: right !important max-width: 100px + td.oe_list_field_date, th.oe_list_header_date + min-width: 6em > thead border-bottom: 2px solid #cacaca background: #eee @@ -2168,6 +2226,8 @@ $sheet-padding: 16px width: 17px &:after border-width: 0 + > td.oe_list_field_boolean input + @include opacity() > tr:nth-child(odd) background-color: #f0f0fa @include vertical-gradient(#f0f0fa, #eeeef6) @@ -2282,67 +2342,6 @@ $sheet-padding: 16px float: right color: #333 // }}} - -.openerp - .oe_fileupload - display: inline-block - clear: both - width: 100% - .oe_add - float: left - position: relative - width: 100% - left: +2px - top: +7px - button - display: inline - height: 24px - font-size: 12px - line-height: 12px - vertical-align: middle - button.oe_attach - width: 24px - overflow: hidden - width: 24px - overflow: hidden - background: transparent - color: #7C7BAD - box-shadow: none - border: none - text-shadow: none - .oe_e - position: relative - top: -1px - left: -9px - input.oe_form_binary_file - display: inline-block - margin-left: -5px - height: 28px - width: 52px - margin-top: -26px - .oe_attach_label - color: #7C7BAD - margin-left: -3px - .oe_attachments - margin-bottom: 4px - margin-right: 0px - font-size: 12px - border-radius: 2px - border: solid 1px rgba(124,123,173,0.14) - .oe_attachment - padding: 2px - padding-left: 4px - padding-right: 4px - .oe_e - font-size: 23px - margin-top: -5px - .oe_e:hover - text-decoration: none - .oe_attachment:nth-child(odd) - background: white - .oe_attachment:nth-child(even) - background: #F4F5FA - // Kitten Mode {{{ .kitten-mode-activated background-image: url(http://placekitten.com/g/1365/769) @@ -2352,11 +2351,13 @@ $sheet-padding: 16px opacity: 0.70 // }}} +// jQueryUI top level {{{ // The jQuery-ui overlay and Autocomplete are outside the .openerp div, please don't add indentation !!! div.ui-widget-overlay background: black @include opacity(0.3) - +// TODO: I think only the overlay is problematic, the other top level widgets should use $.fn.openerpClass() +// eg: $el.autocomplete().openerpClass(); .ui-widget font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif color: #4c4c4c @@ -2383,11 +2384,14 @@ div.ui-widget-overlay .ui-corner-all @include radius(3px) +// }}} +// @media print {{{ @media print .openerp - .oe_header_row, ul.oe_header, div.oe_mail_thread_action, .oe_mail_recthread_actions, .oe_button_box, .oe_form button, button.oe_invite, .oe_form header, .openerp .oe_notebook > li.ui-state-default - display: none + .oe_header_row, ul.oe_header, div.oe_mail_thread_action, .oe_mail_recthread_actions, .oe_button_box, .oe_form button, button.oe_invite, .oe_form header, .openerp .oe_notebook > li.ui-state-default, .oe_topbar, .oe_leftbar, .oe_loading + // We use !important here because jQuery adds @style = display: block on elements when using $.fn.show() + display: none !important .oe_list_content button, input[type=checkbox] visibility: hidden @@ -2413,5 +2417,7 @@ div.ui-widget-overlay background: none .openerp div.oe_mail_wall overflow: hidden !important +// }}} + // au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css" // vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker: diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 05ce709e80a..631a7f8c6f5 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -19,12 +19,14 @@ /** * OpenERP instance constructor * - * @param {Array} modules list of modules to initialize + * @param {Array|String} modules list of modules to initialize */ init: function(modules) { - // By default only web will be loaded, the rest will be by loaded - // by openerp.web.Session on the first session_authenticate - modules = _.union(['web'], modules || []); + if (modules === "fuck your shit, don't load anything you cunt") { + modules = []; + } else { + modules = _.union(['web'], modules || []); + } var new_instance = { // links to the global openerp _openerp: openerp, diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 9c249a5fb0c..b95550c74a0 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -48,7 +48,7 @@ instance.web.Notification = instance.web.Widget.extend({ */ instance.web.dialog = function(element) { var result = element.dialog.apply(element, _.rest(_.toArray(arguments))); - result.dialog("widget").addClass("openerp"); + result.dialog("widget").openerpClass(); return result; }; @@ -189,8 +189,15 @@ instance.web.Dialog = instance.web.Widget.extend({ } }); -instance.web.CrashManager = instance.web.CallbackEnabled.extend({ +instance.web.CrashManager = instance.web.Class.extend({ + init: function() { + this.active = true; + }, + rpc_error: function(error) { + if (!this.active) { + return; + } if (error.data.fault_code) { var split = ("" + error.data.fault_code).split('\n')[0].split(' -- '); if (split.length > 1) { @@ -205,6 +212,9 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({ } }, show_warning: function(error) { + if (!this.active) { + return; + } instance.web.dialog($('<div>' + QWeb.render('CrashManager.warning', {error: error}) + '</div>'), { title: "OpenERP " + _.str.capitalize(error.type), buttons: [ @@ -213,7 +223,9 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({ }); }, show_error: function(error) { - var self = this; + if (!this.active) { + return; + } var buttons = {}; buttons[_t("Ok")] = function() { $(this).dialog("close"); @@ -303,14 +315,14 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ $('.oe_secondary_menus_container,.oe_user_menu_placeholder').empty(); var fetch_db = this.rpc("/web/database/get_list", {}).then( function(result) { - self.db_list = result.db_list; + self.db_list = result; }, function (_, ev) { ev.preventDefault(); self.db_list = null; }); var fetch_langs = this.rpc("/web/session/get_lang_list", {}).done(function(result) { - self.lang_list = result.lang_list; + self.lang_list = result; }); return $.when(fetch_db, fetch_langs).done(self.do_render); }, @@ -333,6 +345,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ self.$el.find("tr td:first-child").addClass("oe_form_group_cell_label"); self.$el.find("label").addClass("oe_form_label"); self.$el.find("form[name=create_db_form]").validate({ submitHandler: self.do_create }); + self.$el.find("form[name=duplicate_db_form]").validate({ submitHandler: self.do_duplicate }); self.$el.find("form[name=drop_db_form]").validate({ submitHandler: self.do_drop }); self.$el.find("form[name=backup_db_form]").validate({ submitHandler: self.do_backup }); self.$el.find("form[name=restore_db_form]").validate({ submitHandler: self.do_restore }); @@ -418,6 +431,18 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ self.do_action(client_action); }); }, + do_duplicate: function(form) { + var self = this; + var fields = $(form).serializeArray(); + self.rpc("/web/database/duplicate", {'fields': fields}).then(function(result) { + if (result.error) { + self.display_error(result); + return; + } + self.do_notify("Duplicating database", "The database has been duplicated."); + self.start(); + }); + }, do_drop: function(form) { var self = this; var $form = $(form), @@ -518,6 +543,9 @@ instance.web.Login = instance.web.Widget.extend({ this.selected_db = null; this.selected_login = null; this.params = action.params || {}; + if (_.isEmpty(this.params)) { + this.params = $.bbq.getState(true); + } if (this.params.login_successful) { this.on('login_successful', this, this.params.login_successful); @@ -548,7 +576,7 @@ instance.web.Login = instance.web.Widget.extend({ return d; }, on_db_loaded: function (result) { - this.db_list = result.db_list; + this.db_list = result; this.$("[name=db]").replaceWith(QWeb.render('Login.dblist', { db_list: this.db_list, selected_db: this.selected_db})); if(this.db_list.length === 0) { this.do_action("database_manager"); @@ -620,8 +648,34 @@ instance.web.Login = instance.web.Widget.extend({ instance.web.client_actions.add("login", "instance.web.Login"); /** + * Redirect to url by replacing window.location + * If wait is true, sleep 1s and wait for the server i.e. after a restart. + */ +instance.web.redirect = function(url, wait) { + // Dont display a dialog if some xmlhttprequest are in progress + if (instance.client && instance.client.crashmanager) { + instance.client.crashmanager.active = false; + } + + var wait_server = function() { + instance.session.rpc("/web/webclient/version_info", {}).done(function() { + window.location = url; + }).fail(function() { + setTimeout(wait_server, 250); + }); + }; + + if (wait) { + setTimeout(wait_server, 1000); + } else { + window.location = url; + } +}; + +/** * Client action to reload the whole interface. - * If params has an entry 'menu_id', it opens the given menu entry. + * If params.menu_id, it opens the given menu entry. + * If params.wait, reload will wait the openerp server to be reachable before reloading */ instance.web.Reload = function(parent, action) { var params = action.params || {}; @@ -637,8 +691,8 @@ instance.web.Reload = function(parent, action) { hash = "#menu_id=" + menu_id; } var url = l.protocol + "//" + l.host + l.pathname + search + hash; - window.onerror = function() {}; - window.location = url; + + instance.web.redirect(url, params.wait); }; instance.web.client_actions.add("reload", "instance.web.Reload"); @@ -648,7 +702,7 @@ instance.web.client_actions.add("reload", "instance.web.Reload"); */ instance.web.HistoryBack = function(parent) { if (!parent.history_back()) { - window.location = '/' + (window.location.search || ''); + instance.web.Home(parent); } }; instance.web.client_actions.add("history_back", "instance.web.HistoryBack"); @@ -656,11 +710,10 @@ instance.web.client_actions.add("history_back", "instance.web.HistoryBack"); /** * Client action to go back home. */ -instance.web.Home = instance.web.Widget.extend({ - init: function(parent) { - window.location = '/' + (window.location.search || ''); - } -}); +instance.web.Home = function(parent, action) { + var url = '/' + (window.location.search || ''); + instance.web.redirect(url, action.params && action.params.wait); +}; instance.web.client_actions.add("home", "instance.web.Home"); instance.web.ChangePassword = instance.web.Widget.extend({ @@ -887,7 +940,7 @@ instance.web.UserMenu = instance.web.Widget.extend({ if(res.company_id[0] > 1) topbar_name = _.str.sprintf("%s (%s)", topbar_name, res.company_id[1]); self.$el.find('.oe_topbar_name').text(topbar_name); - var avatar_src = _.str.sprintf('%s/web/binary/image?session_id=%s&model=res.users&field=image_small&id=%s', self.session.prefix, self.session.session_id, self.session.uid); + var avatar_src = self.session.url('/web/binary/image', {model:'res.users', field: 'image_small', id: self.session.uid}); $avatar.attr('src', avatar_src); }); }; @@ -899,7 +952,7 @@ instance.web.UserMenu = instance.web.Widget.extend({ on_menu_settings: function() { var self = this; if (!this.getParent().has_uncommitted_changes()) { - self.rpc("/web/action/load", { action_id: "base.action_res_users_my" }, function(result) { + self.rpc("/web/action/load", { action_id: "base.action_res_users_my" }).done(function(result) { result.res_id = instance.session.uid; self.getParent().action_manager.do_action(result); }); @@ -930,6 +983,7 @@ instance.web.Client = instance.web.Widget.extend({ return instance.session.session_bind(this.origin).then(function() { var $e = $(QWeb.render(self._template, {})); self.replaceElement($e); + $e.openerpClass(); self.bind_events(); return self.show_common(); }); @@ -1106,10 +1160,10 @@ instance.web.WebClient = instance.web.Client.extend({ var self = this; var state = event.getState(true); if (!_.isEqual(this._current_state, state)) { - if(state.action_id === undefined && state.menu_id) { + if(!state.action && state.menu_id) { self.menu.has_been_loaded.done(function() { self.menu.do_reload().done(function() { - self.menu.menu_click(state.menu_id) + self.menu.menu_click(state.menu_id); }); }); } else { diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js index d2e94d37939..06b3940f1e1 100644 --- a/addons/web/static/src/js/corelib.js +++ b/addons/web/static/src/js/corelib.js @@ -243,15 +243,17 @@ instance.web.ParentedMixin = { /** * Backbone's events. Do not ever use it directly, use EventDispatcherMixin instead. + * + * This class just handle the dispatching of events, it is not meant to be extended, + * nor used directly. All integration with parenting and automatic unregistration of + * events is done in EventDispatcherMixin. + * + * Copyright notice for the following Class: * * (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. * Backbone may be freely distributed under the MIT license. * For all details and documentation: * http://backbonejs.org - * - * This class just handle the dispatching of events, it is not meant to be extended, - * nor used directly. All integration with parenting and automatic unregistration of - * events is done in EventDispatcherMixin. * */ var Events = instance.web.Class.extend({ @@ -334,7 +336,6 @@ var Events = instance.web.Class.extend({ return this; } }); -// end of Jeremy Ashkenas' code instance.web.EventDispatcherMixin = _.extend({}, instance.web.ParentedMixin, { __eventDispatcherMixin: true, @@ -426,66 +427,94 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, { } }); -instance.web.CallbackEnabledMixin = _.extend({}, instance.web.PropertiesMixin, { - init: function() { - instance.web.PropertiesMixin.init.call(this); - var self = this; - // Transform on_/do_* methods into callbacks - var callback_maker = function(fn) { - return function() { - return fn.apply(self, arguments); - } - }; - for (var name in this) { - if(typeof(this[name]) == "function") { - if((/^on_|^do_/).test(name)) { - this[name] = callback_maker(this[name]); - } - } - } - }, +// Classes + +/** + * Base class for all visual components. Provides a lot of functionalities helpful + * for the management of a part of the DOM. + * + * Widget handles: + * - Rendering with QWeb. + * - Life-cycle management and parenting (when a parent is destroyed, all its children are + * destroyed too). + * - Insertion in DOM. + * + * Guide to create implementations of the Widget class: + * ============================================== + * + * Here is a sample child class: + * + * MyWidget = instance.base.Widget.extend({ + * // the name of the QWeb template to use for rendering + * template: "MyQWebTemplate", + * + * init: function(parent) { + * this._super(parent); + * // stuff that you want to init before the rendering + * }, + * start: function() { + * // stuff you want to make after the rendering, `this.$el` holds a correct value + * this.$el.find(".my_button").click(/* an example of event binding * /); + * + * // if you have some asynchronous operations, it's a good idea to return + * // a promise in start() + * var promise = this.rpc(...); + * return promise; + * } + * }); + * + * Now this class can simply be used with the following syntax: + * + * var my_widget = new MyWidget(this); + * my_widget.appendTo($(".some-div")); + * + * With these two lines, the MyWidget instance was inited, rendered, it was inserted into the + * DOM inside the ".some-div" div and its events were binded. + * + * And of course, when you don't need that widget anymore, just do: + * + * my_widget.destroy(); + * + * That will kill the widget in a clean way and erase its content from the dom. + */ +instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, { + // Backbone-ish API + tagName: 'div', + id: null, + className: null, + attributes: {}, + events: {}, /** - * Proxies a method of the object, in order to keep the right ``this`` on - * method invocations. - * - * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and - * even more so to ``jQuery.proxy`` with a fundamental difference: its - * resolution of the method being called is lazy, meaning it will use the - * method as it is when the proxy is called, not when the proxy is created. - * - * Other methods will fix the bound method to what it is when creating the - * binding/proxy, which is fine in most javascript code but problematic in - * OpenERP Web where developers may want to replace existing callbacks with - * theirs. - * - * The semantics of this precisely replace closing over the method call. + * The name of the QWeb template that will be used for rendering. Must be + * redefined in subclasses or the default render() method can not be used. * - * @param {String|Function} method function or name of the method to invoke - * @returns {Function} proxied method + * @type string */ - proxy: function (method) { - var self = this; - return function () { - var fn = (typeof method === 'string') ? self[method] : method; - return fn.apply(self, arguments); - } - } -}); - -instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, { + template: null, /** * Constructs the widget and sets its parent if a parent is given. * * @constructs instance.web.Widget - * @extends instance.web.CallbackEnabled * * @param {instance.web.Widget} parent Binds the current instance to the given Widget instance. * When that widget is destroyed by calling destroy(), the current instance will be * destroyed too. Can be null. */ init: function(parent) { - instance.web.CallbackEnabledMixin.init.call(this); + instance.web.PropertiesMixin.init.call(this); this.setParent(parent); + // Bind on_/do_* methods to this + // We might remove this automatic binding in the future + for (var name in this) { + if(typeof(this[name]) == "function") { + if((/^on_|^do_/).test(name)) { + this[name] = this[name].bind(this); + } + } + } + // FIXME: this should not be + this.setElement(this._make_descriptive()); + this.session = instance.session; }, /** * Destroys the current widget, also destroys all its children before destroying itself. @@ -574,94 +603,32 @@ instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, { */ start: function() { return $.when(); - } -}); - -// Classes - -instance.web.CallbackEnabled = instance.web.Class.extend(instance.web.CallbackEnabledMixin, { - init: function() { - instance.web.CallbackEnabledMixin.init.call(this); - } -}); - -/** - * Base class for all visual components. Provides a lot of functionalities helpful - * for the management of a part of the DOM. - * - * Widget handles: - * - Rendering with QWeb. - * - Life-cycle management and parenting (when a parent is destroyed, all its children are - * destroyed too). - * - Insertion in DOM. - * - * Guide to create implementations of the Widget class: - * ============================================== - * - * Here is a sample child class: - * - * MyWidget = instance.base.Widget.extend({ - * // the name of the QWeb template to use for rendering - * template: "MyQWebTemplate", - * - * init: function(parent) { - * this._super(parent); - * // stuff that you want to init before the rendering - * }, - * start: function() { - * // stuff you want to make after the rendering, `this.$el` holds a correct value - * this.$el.find(".my_button").click(/* an example of event binding * /); - * - * // if you have some asynchronous operations, it's a good idea to return - * // a promise in start() - * var promise = this.rpc(...); - * return promise; - * } - * }); - * - * Now this class can simply be used with the following syntax: - * - * var my_widget = new MyWidget(this); - * my_widget.appendTo($(".some-div")); - * - * With these two lines, the MyWidget instance was inited, rendered, it was inserted into the - * DOM inside the ".some-div" div and its events were binded. - * - * And of course, when you don't need that widget anymore, just do: - * - * my_widget.destroy(); - * - * That will kill the widget in a clean way and erase its content from the dom. - */ -instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, { - // Backbone-ish API - tagName: 'div', - id: null, - className: null, - attributes: {}, - events: {}, + }, /** - * The name of the QWeb template that will be used for rendering. Must be - * redefined in subclasses or the default render() method can not be used. + * Proxies a method of the object, in order to keep the right ``this`` on + * method invocations. * - * @type string - */ - template: null, - /** - * Constructs the widget and sets its parent if a parent is given. + * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and + * even more so to ``jQuery.proxy`` with a fundamental difference: its + * resolution of the method being called is lazy, meaning it will use the + * method as it is when the proxy is called, not when the proxy is created. * - * @constructs instance.web.Widget - * @extends instance.web.CallbackEnabled + * Other methods will fix the bound method to what it is when creating the + * binding/proxy, which is fine in most javascript code but problematic in + * OpenERP Web where developers may want to replace existing callbacks with + * theirs. * - * @param {instance.web.Widget} parent Binds the current instance to the given Widget instance. - * When that widget is destroyed by calling destroy(), the current instance will be - * destroyed too. Can be null. + * The semantics of this precisely replace closing over the method call. + * + * @param {String|Function} method function or name of the method to invoke + * @returns {Function} proxied method */ - init: function(parent) { - instance.web.WidgetMixin.init.call(this,parent); - // FIXME: this should not be - this.setElement(this._make_descriptive()); - this.session = instance.session; + proxy: function (method) { + var self = this; + return function () { + var fn = (typeof method === 'string') ? self[method] : method; + return fn.apply(self, arguments); + } }, /** * Renders the element. The default implementation renders the widget using QWeb, @@ -678,7 +645,6 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, { } this.replaceElement($el); }, - /** * Re-sets the widget's root element and replaces the old root element * (if any) by the new one in the DOM. @@ -808,10 +774,10 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, { } return false; }, - rpc: function(url, data, success, error) { - var def = $.Deferred().done(success).fail(error); + rpc: function(url, data, options) { + var def = $.Deferred(); var self = this; - instance.session.rpc(url, data).done(function() { + instance.session.rpc(url, data, options).done(function() { if (!self.isDestroyed()) def.resolve.apply(def, arguments); }).fail(function() { @@ -941,7 +907,7 @@ instance.web.Registry = instance.web.Class.extend({ } }); -instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ +instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, { triggers: { 'request': 'Request sent', 'response': 'Response received', @@ -950,13 +916,12 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ }, /** * @constructs instance.web.JsonRPC - * @extends instance.web.CallbackEnabled * * @param {String} [server] JSON-RPC endpoint hostname * @param {String} [port] JSON-RPC endpoint port */ init: function() { - this._super(); + instance.web.PropertiesMixin.init.call(this); this.server = null; this.debug = ($.deparam($.param.querystring()).debug != undefined); }, @@ -1266,12 +1231,14 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ * * @param {String} url RPC endpoint * @param {Object} params call parameters + * @param {Object} options additional options for rpc call * @param {Function} success_callback function to execute on RPC call success * @param {Function} error_callback function to execute on RPC call failure * @returns {jQuery.Deferred} jquery-provided ajax deferred */ - rpc: function(url, params) { + rpc: function(url, params, options) { var self = this; + options = options || {}; // url can be an $.ajax option object if (_.isString(url)) { url = { url: url }; @@ -1286,10 +1253,12 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ id: _.uniqueId('r') }; var deferred = $.Deferred(); - this.trigger('request', url, payload); + if (! options.shadow) + this.trigger('request', url, payload); var request = this.rpc_function(url, payload).done( function (response, textStatus, jqXHR) { - self.trigger('response', response); + if (! options.shadow) + self.trigger('response', response); if (!response.error) { if (url.url === '/web/session/eval_domain_and_context') { self.test_eval(params, response.result); @@ -1303,7 +1272,8 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ } ).fail( function(jqXHR, textStatus, errorThrown) { - self.trigger('response_failed', jqXHR); + if (! options.shadow) + self.trigger('response_failed', jqXHR); var error = { code: -32098, message: "XmlHttpRequestError " + errorThrown, @@ -1311,7 +1281,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ }; deferred.reject(error, $.Event()); }); - // Allow deferred user to disable on_rpc_error in fail + // Allow deferred user to disable rpc_error call in fail deferred.fail(function() { deferred.fail(function(error, event) { if (!event.isDefaultPrevented()) { @@ -1344,9 +1314,18 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ // extracted from payload to set on the url var data = { session_id: this.session_id, - id: payload.id + id: payload.id, + sid: this.httpsessionid, }; - url.url = this.get_url(url.url); + + var set_sid = function (response, textStatus, jqXHR) { + // If response give us the http session id, we store it for next requests... + if (response.httpsessionid) { + self.httpsessionid = response.httpsessionid; + } + }; + + url.url = this.url(url.url, null); var ajax = _.extend({ type: "GET", dataType: 'jsonp', @@ -1361,7 +1340,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ if(payload_url.length < 2000) { // Direct jsonp request ajax.data.r = payload_str; - return $.ajax(ajax); + return $.ajax(ajax).done(set_sid); } else { // Indirect jsonp request var ifid = _.uniqueId('oe_rpc_iframe'); @@ -1399,11 +1378,20 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ }); // append the iframe to the DOM (will trigger the first load) $form.after($iframe); - return deferred; + return deferred.done(set_sid); } }, - get_url: function (file) { - return this.prefix + file; + + url: function(path, params) { + var qs = ''; + if (!_.isNull(params)) { + params = _.extend(params || {}, {session_id: this.session_id}); + if (this.httpsessionid) { + params.sid = this.httpsessionid; + } + qs = '?' + $.param(params); + } + return this.prefix + path + qs; }, }); diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index b7dac303520..7ddefa301f2 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -3,10 +3,13 @@ *--------------------------------------------------------*/ var console; if (!console) { - console = {log: function () {}}; -} -if (!console.debug) { - console.debug = console.log; + // Even IE9 only exposes console object if debug window opened + console = {}; + ('log error debug info warn assert clear dir dirxml trace group' + + ' groupCollapsed groupEnd time timeEnd profile profileEnd count' + + ' exception').split(/\s+/).forEach(function(property) { + console[property] = _.identity; + }); } openerp.web.coresetup = function(instance) { @@ -19,9 +22,9 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess this.name = instance._session_id; this.qweb_mutex = new $.Mutex(); }, - rpc: function(url, params) { + rpc: function(url, params, options) { params.session_id = this.session_id; - return this._super(url, params); + return this._super(url, params, options); }, /** * Setup a sessionm @@ -53,7 +56,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess this.session_id = this.get_cookie('session_id'); return this.session_reload().then(function(result) { var modules = instance._modules.join(','); - var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).then(self.do_load_qweb); + var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).then(self.load_qweb.bind(self)); if(self.session_is_valid()) { return deferred.then(function() { return self.load_modules(); }); } @@ -155,28 +158,26 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess load_modules: function() { var self = this; return this.rpc('/web/session/modules', {}).then(function(result) { - var lang = self.user_context.lang, - all_modules = _.uniq(self.module_list.concat(result)); - var params = { mods: all_modules, lang: lang}; + var all_modules = _.uniq(self.module_list.concat(result)); var to_load = _.difference(result, self.module_list).join(','); self.module_list = all_modules; - var loaded = self.rpc('/web/webclient/translations', params).done(function(trans) { - instance.web._t.database.set_bundle(trans); - }); - var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"]; + var loaded = self.load_translations(); + var datejs_locale = "/web/static/lib/datejs/globalization/" + self.user_context.lang.replace("_", "-") + ".js"; + + var file_list = [ datejs_locale ]; if(to_load.length) { loaded = $.when( loaded, - self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.do_load_css), - self.rpc('/web/webclient/qweblist', {mods: to_load}).then(self.do_load_qweb), + self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.load_css.bind(self)), + self.rpc('/web/webclient/qweblist', {mods: to_load}).then(self.load_qweb.bind(self)), self.rpc('/web/webclient/jslist', {mods: to_load}).done(function(files) { file_list = file_list.concat(files); }) ); } return loaded.then(function () { - return self.do_load_js(file_list); + return self.load_js(file_list); }).done(function() { self.on_modules_loaded(); self.trigger('module_loaded'); @@ -190,29 +191,35 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess }); }); }, - do_load_css: function (files) { + load_translations: function() { + var params = { mods: this.module_list, lang: this.user_context.lang }; + return this.rpc('/web/webclient/translations', params).done(function(trans) { + instance.web._t.database.set_bundle(trans); + }); + }, + load_css: function (files) { var self = this; _.each(files, function (file) { $('head').append($('<link>', { - 'href': self.get_url(file), + 'href': self.url(file, null), 'rel': 'stylesheet', 'type': 'text/css' })); }); }, - do_load_js: function(files) { + load_js: function(files) { var self = this; var d = $.Deferred(); - if(files.length != 0) { + if(files.length !== 0) { var file = files.shift(); var tag = document.createElement('script'); tag.type = 'text/javascript'; - tag.src = self.get_url(file); + tag.src = self.url(file, null); tag.onload = tag.onreadystatechange = function() { if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done ) return; tag.onload_done = true; - self.do_load_js(files).done(function () { + self.load_js(files).done(function () { d.resolve(); }); }; @@ -223,7 +230,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess } return d; }, - do_load_qweb: function(files) { + load_qweb: function(files) { var self = this; _.each(files, function(file) { self.qweb_mutex.exec(function() { @@ -453,6 +460,16 @@ $.fn.getAttributes = function() { } return o; } +$.fn.openerpClass = function(additionalClass) { + // This plugin should be applied on top level elements + additionalClass = additionalClass || ''; + if (!!$.browser.msie) { + additionalClass += ' openerp_ie'; + } + return this.each(function() { + $(this).addClass('openerp ' + additionalClass); + }); +}; /** Jquery extentions */ $.Mutex = (function() { diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 2f8679794b0..524a88bdc48 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -278,9 +278,10 @@ instance.web.Model = instance.web.Class.extend({ * @param {String} method name of the method to call * @param {Array} [args] positional arguments * @param {Object} [kwargs] keyword arguments + * @param {Object} [options] additional options for the rpc() method * @returns {jQuery.Deferred<>} call result */ - call: function (method, args, kwargs) { + call: function (method, args, kwargs, options) { args = args || []; kwargs = kwargs || {}; if (!_.isArray(args)) { @@ -294,7 +295,7 @@ instance.web.Model = instance.web.Class.extend({ method: method, args: args, kwargs: kwargs - }); + }, options); }, /** * Fetches a Query instance bound to this model, for searching @@ -358,17 +359,16 @@ instance.web.Model = instance.web.Class.extend({ }, }); -instance.web.DataSet = instance.web.CallbackEnabled.extend({ +instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin, { /** * Collection of OpenERP records, used to share records and the current selection between views. * * @constructs instance.web.DataSet - * @extends instance.web.CallbackEnabled * * @param {String} model the OpenERP model this dataset will manage */ init: function(parent, model, context) { - this._super(parent); + instance.web.PropertiesMixin.init.call(this); this.model = model; this.context = context || {}; this.index = null; @@ -722,10 +722,10 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ this.last_default_get = {}; }, default_get: function(fields, options) { - return this._super(fields, options).done(this.on_default_get); - }, - on_default_get: function(res) { - this.last_default_get = res; + var self = this; + return this._super(fields, options).done(function(res) { + self.last_default_get = res; + }); }, create: function(data) { var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data, diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index 03b2c5b775d..e586b94db6b 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -83,6 +83,42 @@ instance.web.strip_raw_chars = function (value) { var normalize_format = function (format) { return Date.normalizeFormat(instance.web.strip_raw_chars(format)); }; + +/** + * Check with a scary heuristic if the value is a bin_size or not. + * If not, compute an approximate size out of the base64 encoded string. + * + * @param {String} value original format + */ +instance.web.binary_to_binsize = function (value) { + if (!value) { + return instance.web.human_size(0); + } + if (value.substr(0, 10).indexOf(' ') == -1) { + // Computing approximate size out of base64 encoded string + // http://en.wikipedia.org/wiki/Base64#MIME + return instance.web.human_size(value.length / 1.37); + } else { + // already bin_size + return value; + } +}; + +/** + * Returns a human readable size + * + * @param {Number} numner of bytes + */ +instance.web.human_size = function(size) { + var units = _t("Bytes,Kb,Mb,Gb,Tb,Pb,Eb,Zb,Yb").split(','); + var i = 0; + while (size >= 1024) { + size /= 1024; + ++i; + } + return size.toFixed(2) + ' ' + units[i]; +}; + /** * Formats a single atomic value based on a field descriptor * diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index e84ea66ff9a..0f25b2484c3 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -349,7 +349,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea $.when(load_view) .then(function(r) { self.search_view_loaded(r) - }).fail(function () { + }, function () { self.ready.reject.apply(null, arguments); }); } @@ -459,7 +459,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea complete_global_search: function (req, resp) { $.when.apply(null, _(this.inputs).chain() .invoke('complete', req.term) - .value()).done(function () { + .value()).then(function () { resp(_(_(arguments).compact()).flatten(true)); }); }, @@ -527,7 +527,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea childView.on('blurred', self, self.proxy('childBlurred')); }); - $.when.apply(null, started).done(function () { + $.when.apply(null, started).then(function () { var input_to_focus; // options.at: facet inserted at given index, focus next input // otherwise just focus last input @@ -608,7 +608,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea // add Filters to this.inputs, need view.controls filled (new instance.web.search.Filters(this)); // add custom filters to this.inputs - (new instance.web.search.CustomFilters(this)); + this.custom_filters = new instance.web.search.CustomFilters(this); // add Advanced to this.inputs (new instance.web.search.Advanced(this)); }, @@ -635,16 +635,41 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea // load defaults var defaults_fetched = $.when.apply(null, _(this.inputs).invoke( - 'facet_for_defaults', this.defaults)).done(function () { - self.query.reset(_(arguments).compact(), {preventSearch: true}); - }); - + 'facet_for_defaults', this.defaults)) + .then(this.proxy('setup_default_query')); + return $.when(drawer_started, defaults_fetched) .done(function () { self.trigger("search_view_loaded", data); self.ready.resolve(); }); }, + setup_default_query: function () { + // Hacky implementation of CustomFilters#facet_for_defaults ensure + // CustomFilters will be ready (and CustomFilters#filters will be + // correctly filled) by the time this method executes. + var custom_filters = this.custom_filters.filters; + if (!_(custom_filters).isEmpty()) { + // Check for any is_default custom filter + var personal_filter = _(custom_filters).find(function (filter) { + return filter.user_id && filter.is_default; + }); + if (personal_filter) { + this.custom_filters.enable_filter(personal_filter, true); + return; + } + + var global_filter = _(custom_filters).find(function (filter) { + return !filter.user_id && filter.is_default; + }); + if (global_filter) { + this.custom_filters.enable_filter(global_filter, true); + return; + } + } + // No custom filter, or no is_default custom filter, apply view defaults + this.query.reset(_(arguments).compact(), {preventSearch: true}); + }, /** * Extract search data from the view's facets. * @@ -1460,10 +1485,15 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({ instance.web.search.CustomFilters = instance.web.search.Input.extend({ template: 'SearchView.CustomFilters', _in_drawer: true, + init: function () { + this.is_ready = $.Deferred(); + this._super.apply(this, arguments); + }, start: function () { var self = this; this.model = new instance.web.Model('ir.filters'); this.filters = {}; + this.$filters = {}; this.view.query .on('remove', function (facet) { if (!facet.get('is_custom_filter')) { @@ -1479,24 +1509,78 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ // FIXME: local eval of domain and context to get rid of special endpoint return this.rpc('/web/searchview/get_filters', { model: this.view.model - }).then(this.proxy('set_filters')); + }) + .then(this.proxy('set_filters')) + .then(function () { + self.is_ready.resolve(null); + }, function () { + self.is_ready.reject(); + }); + }, + /** + * Special implementation delaying defaults until CustomFilters is loaded + */ + facet_for_defaults: function () { + return this.is_ready; + }, + /** + * Generates a mapping key (in the filters and $filter mappings) for the + * filter descriptor object provided (as returned by ``get_filters``). + * + * The mapping key is guaranteed to be unique for a given (user_id, name) + * pair. + * + * @param {Object} filter + * @param {String} filter.name + * @param {Number|Pair<Number, String>} [filter.user_id] + * @return {String} mapping key corresponding to the filter + */ + key_for: function (filter) { + var user_id = filter.user_id; + var uid = (user_id instanceof Array) ? user_id[0] : user_id; + return _.str.sprintf('(%s)%s', uid, filter.name); + }, + /** + * Generates a :js:class:`~instance.web.search.Facet` descriptor from a + * filter descriptor + * + * @param {Object} filter + * @param {String} filter.name + * @param {Object} [filter.context] + * @param {Array} [filter.domain] + * @return {Object} + */ + facet_for: function (filter) { + return { + category: _t("Custom Filter"), + icon: 'M', + field: { + get_context: function () { return filter.context; }, + get_groupby: function () { return [filter.context]; }, + get_domain: function () { return filter.domain; } + }, + is_custom_filter: true, + values: [{label: filter.name, value: null}] + }; }, clear_selection: function () { this.$('li.oe_selected').removeClass('oe_selected'); }, append_filter: function (filter) { var self = this; - var key = _.str.sprintf('(%s)%s', filter.user_id, filter.name); + var key = this.key_for(filter); var $filter; - if (key in this.filters) { - $filter = this.filters[key]; + if (key in this.$filters) { + $filter = this.$filters[key]; } else { var id = filter.id; - $filter = this.filters[key] = $('<li></li>') + this.filters[key] = filter; + $filter = this.$filters[key] = $('<li></li>') .appendTo(this.$('.oe_searchview_custom_list')) .addClass(filter.user_id ? 'oe_searchview_custom_private' : 'oe_searchview_custom_public') + .toggleClass('oe_searchview_custom_default', filter.is_default) .text(filter.name); $('<a class="oe_searchview_custom_delete">x</a>') @@ -1504,33 +1588,30 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ e.stopPropagation(); self.model.call('unlink', [id]).done(function () { $filter.remove(); + delete self.$filters[key]; + delete self.filters[key]; }); }) .appendTo($filter); } $filter.unbind('click').click(function () { - self.view.query.reset([{ - category: _t("Custom Filter"), - icon: 'M', - field: { - get_context: function () { return filter.context; }, - get_groupby: function () { return [filter.context]; }, - get_domain: function () { return filter.domain; } - }, - is_custom_filter: true, - values: [{label: filter.name, value: null}] - }]); - $filter.addClass('oe_selected'); + self.enable_filter(filter); }); }, + enable_filter: function (filter, preventSearch) { + this.view.query.reset([this.facet_for(filter)], { + preventSearch: preventSearch || false}); + this.$filters[this.key_for(filter)].addClass('oe_selected'); + }, set_filters: function (filters) { _(filters).map(_.bind(this.append_filter, this)); }, save_current: function () { var self = this; var $name = this.$('input:first'); - var private_filter = !this.$('input:last').prop('checked'); + var private_filter = !this.$('#oe_searchview_custom_public').prop('checked'); + var set_as_default = this.$('#oe_searchview_custom_default').prop('checked'); var search = this.view.build_search_data(); this.rpc('/web/session/eval_domain_and_context', { @@ -1546,7 +1627,8 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ user_id: private_filter ? instance.session.uid : false, model_id: self.view.model, context: results.context, - domain: results.domain + domain: results.domain, + is_default: set_as_default }; // FIXME: current context? return self.model.call('create_or_replace', [filter]).done(function (id) { diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js new file mode 100644 index 00000000000..bf39f543734 --- /dev/null +++ b/addons/web/static/src/js/testing.js @@ -0,0 +1,393 @@ +// Test support structures and methods for OpenERP +openerp.testing = {}; +(function (testing) { + var dependencies = { + corelib: [], + coresetup: ['corelib'], + data: ['corelib', 'coresetup'], + dates: [], + formats: ['coresetup', 'dates'], + chrome: ['corelib', 'coresetup'], + views: ['corelib', 'coresetup', 'data', 'chrome'], + search: ['data', 'coresetup', 'formats'], + list: ['views', 'data'], + form: ['data', 'views', 'list', 'formats'], + list_editable: ['list', 'form', 'data'], + }; + + testing.dependencies = window['oe_all_dependencies'] || []; + testing.current_module = null; + testing.templates = { }; + testing.add_template = function (name) { + var xhr = QWeb2.Engine.prototype.get_xhr(); + xhr.open('GET', name, false); + xhr.send(null); + (testing.templates[testing.current_module] = + testing.templates[testing.current_module] || []) + .push(xhr.responseXML); + }; + /** + * Function which does not do anything + */ + testing.noop = function () { }; + /** + * Alter provided instance's ``session`` attribute to make response + * mockable: + * + * * The ``responses`` parameter can be used to provide a map of (RPC) + * paths (e.g. ``/web/view/load``) to a function returning a response + * to the query. + * * ``instance.session`` grows a ``responses`` attribute which is + * a map of the same (and is in fact initialized to the ``responses`` + * parameter if one is provided) + * + * Note that RPC requests to un-mocked URLs will be rejected with an + * error message: only explicitly specified urls will get a response. + * + * Mocked sessions will *never* perform an actual RPC connection. + * + * @param instance openerp instance being initialized + * @param {Object} [responses] + */ + testing.mockifyRPC = function (instance, responses) { + var session = instance.session; + session.responses = responses || {}; + session.rpc_function = function (url, payload) { + var fn, params; + var needle = payload.params.model + ':' + payload.params.method; + if (url.url === '/web/dataset/call_kw' + && needle in this.responses) { + fn = this.responses[needle]; + params = [ + payload.params.args || [], + payload.params.kwargs || {} + ]; + } else { + fn = this.responses[url.url]; + params = [payload]; + } + + if (!fn) { + return $.Deferred().reject({}, 'failed', + _.str.sprintf("Url %s not found in mock responses, with arguments %s", + url.url, JSON.stringify(payload.params)) + ).promise(); + } + try { + return $.when(fn.apply(null, params)).then(function (result) { + // Wrap for RPC layer unwrapper thingy + return {result: result}; + }); + } catch (e) { + // not sure why this looks like that + return $.Deferred().reject({}, 'failed', String(e)); + } + }; + }; + + var StackProto = { + execute: function (fn) { + var args = [].slice.call(arguments, 1); + // Warning: here be dragons + var i = 0, setups = this.setups, teardowns = this.teardowns; + var d = $.Deferred(); + + var succeeded, failed; + var success = function () { + succeeded = _.toArray(arguments); + return teardown(); + }; + var failure = function () { + // save first failure + if (!failed) { + failed = _.toArray(arguments); + } + // chain onto next teardown + return teardown(); + }; + + var setup = function () { + // if setup to execute + if (i < setups.length) { + var f = setups[i] || testing.noop; + $.when(f.apply(null, args)).then(function () { + ++i; + setup(); + }, failure); + } else { + $.when(fn.apply(null, args)).then(success, failure); + } + }; + var teardown = function () { + // if teardown to execute + if (i > 0) { + var f = teardowns[--i] || testing.noop; + $.when(f.apply(null, args)).then(teardown, failure); + } else { + if (failed) { + d.reject.apply(d, failed); + } else if (succeeded) { + d.resolve.apply(d, succeeded); + } else { + throw new Error("Didn't succeed or fail?"); + } + } + }; + setup(); + + return d; + }, + push: function (setup, teardown) { + return _.extend(Object.create(StackProto), { + setups: this.setups.concat([setup]), + teardowns: this.teardowns.concat([teardown]) + }); + }, + unshift: function (setup, teardown) { + return _.extend(Object.create(StackProto), { + setups: [setup].concat(this.setups), + teardowns: [teardown].concat(this.teardowns) + }); + } + }; + /** + * + * @param {Function} [setup] + * @param {Function} [teardown] + * @return {*} + */ + testing.Stack = function (setup, teardown) { + return _.extend(Object.create(StackProto), { + setups: setup ? [setup] : [], + teardowns: teardown ? [teardown] : [] + }); + }; + + var db = window['oe_db_info']; + testing.section = function (name, options, body) { + if (_.isFunction(options)) { + body = options; + options = {}; + } + _.defaults(options, { + setup: testing.noop, + teardown: testing.noop + }); + + QUnit.module(testing.current_module + '.' + name, {_oe: options}); + body(testing.case); + }; + testing.case = function (name, options, callback) { + if (_.isFunction(options)) { + callback = options; + options = {}; + } + + var module = testing.current_module; + var module_index = _.indexOf(testing.dependencies, module); + var module_deps = testing.dependencies.slice( + // If module not in deps (because only tests, no JS) -> indexOf + // returns -1 -> index becomes 0 -> replace with ``undefined`` so + // Array#slice returns a full copy + 0, module_index + 1 || undefined); + + // Serialize options for this precise test case + // WARNING: typo is from jquery, do not fix! + var env = QUnit.config.currentModuleTestEnviroment; + // section setup + // case setup + // test + // case teardown + // section teardown + var case_stack = testing.Stack() + .push(env._oe.setup, env._oe.teardown) + .push(options.setup, options.teardown); + var opts = _.defaults({}, options, env._oe); + // FIXME: if this test is ignored, will still query + if (opts.rpc === 'rpc' && !db) { + QUnit.config.autostart = false; + db = { + source: null, + supadmin: null, + password: null + }; + var $msg = $('<form style="margin: 0 1em 1em;">') + .append('<h3>A test needs to clone a database</h3>') + .append('<h4>Please provide the source clone information</h4>') + .append(' Source DB: ').append('<input name="source">').append('<br>') + .append(' DB Password: ').append('<input name="supadmin">').append('<br>') + .append('Admin Password: ').append('<input name="password">').append('<br>') + .append('<input type="submit" value="OK"/>') + .submit(function (e) { + e.preventDefault(); + e.stopPropagation(); + db.source = $msg.find('input[name=source]').val(); + db.supadmin = $msg.find('input[name=supadmin]').val(); + db.password = $msg.find('input[name=password]').val(); + QUnit.start(); + $.unblockUI(); + }); + $.blockUI({ + message: $msg, + css: { + fontFamily: 'monospace', + textAlign: 'left', + whiteSpace: 'pre-wrap', + cursor: 'default' + } + }); + } + + QUnit.test(name, function () { + var instance; + if (!opts.dependencies) { + instance = openerp.init(module_deps); + } else { + // empty-but-specified dependencies actually allow running + // without loading any module into the instance + + // TODO: clean up this mess + var d = opts.dependencies.slice(); + // dependencies list should be in deps order, reverse to make + // loading order from last + d.reverse(); + var di = 0; + while (di < d.length) { + var m = /^web\.(\w+)$/.exec(d[di]); + if (m) { + d[di] = m[1]; + } + d.splice.apply(d, [di+1, 0].concat( + _(dependencies[d[di]]).reverse())); + ++di; + } + + instance = openerp.init("fuck your shit, don't load anything you cunt"); + _(d).chain() + .reverse() + .uniq() + .each(function (module) { + openerp.web[module](instance); + }); + } + if (_.isNumber(opts.asserts)) { + expect(opts.asserts); + } + + if (opts.templates) { + for(var i=0; i<module_deps.length; ++i) { + var dep = module_deps[i]; + var templates = testing.templates[dep]; + if (_.isEmpty(templates)) { continue; } + + for (var j=0; j < templates.length; ++j) { + instance.web.qweb.add_template(templates[j]); + } + } + } + + var $fixture = $('#qunit-fixture'); + + var mock, async = false; + switch (opts.rpc) { + case 'mock': + async = true; + testing.mockifyRPC(instance); + mock = function (spec, handler) { + instance.session.responses[spec] = handler; + }; + break; + case 'rpc': + async = true; + (function () { + // Bunch of random base36 characters + var dbname = 'test_' + Math.random().toString(36).slice(2); + // Add db setup/teardown at the start of the stack + case_stack = case_stack.unshift(function (instance) { + // FIXME hack: don't want the session to go through shitty loading process of everything + instance.session.session_init = testing.noop; + instance.session.load_modules = testing.noop; + instance.session.session_bind(); + return instance.session.rpc('/web/database/duplicate', { + fields: [ + {name: 'super_admin_pwd', value: db.supadmin}, + {name: 'db_original_name', value: db.source}, + {name: 'db_name', value: dbname} + ] + }).then(function (result) { + if (result.error) { + return $.Deferred().reject(result.error).promise(); + } + return instance.session.session_authenticate( + dbname, 'admin', db.password, true); + }); + }, function (instance) { + return instance.session.rpc('/web/database/drop', { + fields: [ + {name: 'drop_pwd', value: db.supadmin}, + {name: 'drop_db', value: dbname} + ] + }).then(function (result) { + if (result.error) { + return $.Deferred().reject(result.error).promise(); + } + return result; + }); + }); + })(); + } + + // Always execute tests asynchronously + stop(); + var timeout; + case_stack.execute(function () { + var result = callback.apply(null, arguments); + if (!(result && _.isFunction(result.then))) { + if (async) { + ok(false, "asynchronous test cases must return a promise"); + } + } else { + if (!_.isNumber(opts.asserts)) { + ok(false, "asynchronous test cases must specify the " + + "number of assertions they expect"); + } + } + + return $.Deferred(function (d) { + $.when(result).then(function () { + d.resolve.apply(d, arguments) + }, function () { + d.reject.apply(d, arguments); + }); + if (async || (result && result.then)) { + // async test can be either implicit async (rpc) or + // promise-returning + timeout = setTimeout(function () { + QUnit.config.semaphore = 1; + d.reject({message: "Test timed out"}); + }, 2000); + } + }); + }, instance, $fixture, mock).always(function () { + if (timeout) { clearTimeout(timeout); } + start(); + }).fail(function (error) { + if (options.fail_on_rejection === false) { + return; + } + var message; + if (typeof error !== 'object' + || typeof error.message !== 'string') { + message = JSON.stringify([].slice.apply(arguments)); + } else { + message = error.message; + if (error.data && error.data.debug) { + message += '\n\n' + error.data.debug; + } + } + + ok(false, message); + }); + }); + }; +})(openerp.testing); diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 906f1d8fe36..dad622fb7f9 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -173,10 +173,14 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } else { this.$el.find('.oe_form_buttons').replaceWith(this.$buttons); } - this.$buttons.on('click', '.oe_form_button_create', this.on_button_create); - this.$buttons.on('click', '.oe_form_button_edit', this.on_button_edit); - this.$buttons.on('click', '.oe_form_button_save', this.on_button_save); - this.$buttons.on('click', '.oe_form_button_cancel', this.on_button_cancel); + this.$buttons.on('click', '.oe_form_button_create', + this.guard_active(this.on_button_create)); + this.$buttons.on('click', '.oe_form_button_edit', + this.guard_active(this.on_button_edit)); + this.$buttons.on('click', '.oe_form_button_save', + this.guard_active(this.on_button_save)); + this.$buttons.on('click', '.oe_form_button_cancel', + this.guard_active(this.on_button_cancel)); if (this.options.footer_to_buttons) { this.$el.find('footer').appendTo(this.$buttons); } @@ -618,6 +622,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return self._process_save(save_obj).then(function() { save_obj.ret = _.toArray(arguments); return iterate(); + }, function() { + save_obj.error = true; }); } return $.when(); @@ -801,6 +807,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM var save_obj = {prepend_on_create: prepend_on_create, ret: null}; this.save_list.push(save_obj); return this._process_operations().then(function() { + if (save_obj.error) + return $.Deferred().reject(); return $.when.apply($, save_obj.ret); }); }, @@ -1187,14 +1195,36 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt }); } }, + view_arch_to_dom_node: function(arch) { + // Historic mess for views arch + // + // server: + // -> got xml as string + // -> parse to xml and manipulate domains and contexts + // -> convert to json + // client: + // -> got view as json + // -> convert back to xml as string + // -> parse it as xml doc (manipulate button@type for IE) + // -> convert back to string + // -> parse it as dom element with jquery + // -> for each widget, convert node to json + // + // Wow !!! + var xml = instance.web.json_node_to_xml(arch); + + var doc = $.parseXML('<div class="oe_form">' + xml + '</div>'); + $('button', doc).each(function() { + $(this).attr('data-button-type', $(this).attr('type')); + }); + xml = instance.web.xml_to_str(doc); + return $(xml); + }, render_to: function($target) { var self = this; this.$target = $target; - // TODO: I know this will save the world and all the kitten for a moment, - // but one day, we will have to get rid of xml2json - var xml = instance.web.json_node_to_xml(this.fvg.arch); - this.$form = $('<div class="oe_form">' + xml + '</div>'); + this.$form = this.view_arch_to_dom_node(this.fvg.arch); this.process_version(); @@ -1863,6 +1893,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ template: 'WidgetButton', init: function(field_manager, node) { + node.attrs.type = node.attrs['data-button-type']; this._super(field_manager, node); this.force_disabled = false; this.string = (this.node.attrs.string || '').replace(/_/g, ''); @@ -2152,17 +2183,10 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w }, set_dimensions: function (height, width) { - // remove width css property - this.$el.css('width', ''); - // extract style (without width) - var old_style = this.$el.attr('style'); - // jQuery doesn't understand/use !important - var style = 'width:' + width + 'px !important;'; - if (old_style) { - style += old_style - } - this.$el.attr('style', style); - this.$el.css('minHeight', height); + this.$el.css({ + width: width, + minHeight: height + }); }, commit_value: function() { return $.when(); @@ -2386,7 +2410,7 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({ self.$input.focus(); return; } - self.picker('setDate', self.value ? instance.web.auto_str_to_date(self.value) : new Date()); + self.picker('setDate', self.get('value') ? instance.web.auto_str_to_date(self.get('value')) : new Date()); self.$input_picker.show(); self.picker('show'); self.$input_picker.hide(); @@ -2639,22 +2663,18 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ } }); +/** + The progressbar field expect a float from 0 to 100. +*/ instance.web.form.FieldProgressBar = instance.web.form.AbstractField.extend({ template: 'FieldProgressBar', - start: function() { - this._super.apply(this, arguments); + render_value: function() { this.$el.progressbar({ - value: this.get('value'), + value: this.get('value') || 0, disabled: this.get("effective_readonly") }); - }, - render_value: function() { - var show_value = Number(this.get('value')); - if (isNaN(show_value)) { - show_value = 0; - } - var formatted_value = instance.web.format_value(show_value, { type : 'float' }, '0'); - this.$el.progressbar('option', 'value', show_value).find('span').html(formatted_value + '%'); + var formatted_value = instance.web.format_value(this.get('value') || 0, { type : 'float' }); + this.$('span').html(formatted_value + '%'); } }); @@ -3106,7 +3126,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc minLength: 0, delay: 0 }); - this.$input.autocomplete("widget").addClass("openerp"); + this.$input.autocomplete("widget").openerpClass(); // used to correct a bug when selecting an element by pushing 'enter' in an editable list this.$input.keyup(function(e) { if (e.which === 13) { // ENTER @@ -3817,26 +3837,13 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ this._super.apply(this, arguments); }, do_delete: function (ids) { - var self = this; - var next = $.when(); - var _super = this._super; - // handle deletion of an item which does not exist - // TODO: better handle that in the editable list? - var false_id_index = _(ids).indexOf(false); - if (false_id_index !== -1) { - ids.splice(false_id_index, 1); - next = this.cancel_edition(true); - } - return next.then(function () { - // wheeee - var confirm = window.confirm; - window.confirm = function () { return true; }; - try { - return _super.call(self, ids); - } finally { - window.confirm = confirm; - } - }); + var confirm = window.confirm; + window.confirm = function () { return true; }; + try { + return this._super(ids); + } finally { + window.confirm = confirm; + } } }); instance.web.form.One2ManyGroups = instance.web.ListView.Groups.extend({ @@ -3999,13 +4006,18 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in self._drop_shown = true; }); self.tags = self.$text.textext()[0].tags(); - self.$text.focusout(function() { - self.$text.trigger("setInputData", ""); - }).keydown(function(e) { - if (e.which === $.ui.keyCode.TAB && self._drop_shown) { - self.$text.textext()[0].autocomplete().selectFromDropdown(); - } - }); + self.$text + .focusin(function () { + self.trigger('focused'); + }) + .focusout(function() { + self.$text.trigger("setInputData", ""); + self.trigger('blurred'); + }).keydown(function(e) { + if (e.which === $.ui.keyCode.TAB && self._drop_shown) { + self.$text.textext()[0].autocomplete().selectFromDropdown(); + } + }); }, set_value: function(value_) { value_ = value_ || []; @@ -4794,15 +4806,6 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. this.$el.find('button.oe_form_binary_file_save').click(this.on_save_as); this.$el.find('.oe_form_binary_file_clear').click(this.on_clear); }, - human_filesize : function(size) { - var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - var i = 0; - while (size >= 1024) { - size /= 1024; - ++i; - } - return size.toFixed(2) + ' ' + units[i]; - }, on_file_change: function(e) { var self = this; var file_node = e.target; @@ -4850,6 +4853,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. link.href = "data:application/octet-stream;base64," + value; } else { instance.web.blockUI(); + var c = instance.webclient.crashmanager; this.session.get_file({ url: '/web/binary/saveas_ajax', data: {data: JSON.stringify({ @@ -4860,7 +4864,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. context: this.view.dataset.get_context() })}, complete: instance.web.unblockUI, - error: instance.webclient.crashmanager.on_rpc_error + error: c.rpc_error.bind(c) }); ev.stopPropagation(); return false; @@ -4919,7 +4923,7 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ on_file_uploaded_and_valid: function(size, name, content_type, file_base64) { this.binary_value = true; this.internal_set_value(file_base64); - var show_value = name + " (" + this.human_filesize(size) + ")"; + var show_value = name + " (" + instance.web.human_size(size) + ")"; this.$el.find('input').eq(0).val(show_value); this.set_filename(name); }, @@ -4939,12 +4943,16 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ if (this.get('value') && ! /^\d+(\.\d*)? \w+$/.test(this.get('value'))) { url = 'data:image/png;base64,' + this.get('value'); } else if (this.get('value')) { - var id = escape(JSON.stringify(this.view.datarecord.id || null)); + var id = JSON.stringify(this.view.datarecord.id || null); var field = this.name; if (this.options.preview_image) field = this.options.preview_image; - url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' + - this.view.dataset.model +'&id=' + id + '&field=' + field + '&t=' + (new Date().getTime()); + url = this.session.url('/web/binary/image', { + model: this.view.dataset.model, + id: id, + field: field, + t: (new Date().getTime()), + }); } else { url = this.placeholder; } @@ -4983,14 +4991,14 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ * Options on attribute ; "blockui" {Boolean} block the UI or not * during the file is uploading */ -instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend({ +instance.web.form.FieldMany2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend({ template: "FieldBinaryFileUploader", init: function(field_manager, node) { this._super(field_manager, node); this.field_manager = field_manager; this.node = node; - if(this.field.type != "one2many" || this.field.relation != 'ir.attachment') { - throw "The type of the field '"+this.field.string+"' must be a one2many field with a relation to 'ir.attachment' model."; + if(this.field.type != "many2many" || this.field.relation != 'ir.attachment') { + throw "The type of the field '"+this.field.string+"' must be a many2many field with a relation to 'ir.attachment' model."; } this.ds_file = new instance.web.DataSetSearch(this, 'ir.attachment'); this.fileupload_id = _.uniqueId('oe_fileupload_temp'); @@ -5000,21 +5008,85 @@ instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractFiel this._super(this); this.$el.on('change', 'input.oe_form_binary_file', this.on_file_change ); }, + set_value: function(value_) { + var value_ = value_ || []; + var self = this; + var ids = []; + _.each(value_, function(command) { + if (isNaN(command) && command.id == undefined) { + switch (command[0]) { + case commands.CREATE: + ids = ids.concat(command[2]); + return; + case commands.REPLACE_WITH: + ids = ids.concat(command[2]); + return; + case commands.UPDATE: + ids = ids.concat(command[2]); + return; + case commands.LINK_TO: + ids = ids.concat(command[1]); + return; + case commands.DELETE: + ids = _.filter(ids, function (id) { return id != command[1];}); + return; + case commands.DELETE_ALL: + ids = []; + return; + } + } else { + ids.push(command); + } + }); + this._super( ids ); + }, get_value: function() { return _.map(this.get('value'), function (value) { return commands.link_to( value.id ); }); }, get_file_url: function (attachment) { - return instance.origin + '/web/binary/saveas?session_id=' + this.session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id']; + return this.session.url('/web/binary/saveas', {model: 'ir.attachment', field: 'datas', filename_field: 'datas_fname', id: attachment['id']}); + }, + read_name_values : function () { + var self = this; + // select the list of id for a get_name + var values = []; + _.each(this.get('value'), function (val) { + if (typeof val != 'object') { + values.push(val); + } + }); + // send request for get_name + if (values.length) { + return this.ds_file.call('read', [values, ['id', 'name', 'datas_fname']]).done(function (datas) { + _.each(datas, function (data) { + data.no_unlink = true; + data.url = self.session.url('/web/binary/saveas', {model: 'ir.attachment', field: 'datas', filename_field: 'datas_fname', id: data.id}); + + _.each(self.get('value'), function (val, key) { + if(val == data.id) { + self.get('value')[key] = data; + } + }); + }); + }); + } else { + return $.when(this.get('value')); + } }, render_value: function () { - var render = $(instance.web.qweb.render('FieldBinaryFileUploader.files', {'widget': this})); - render.on('click', '.oe_delete', _.bind(this.on_file_delete, this)); - this.$('.oe_placeholder_files, .oe_attachments').replaceWith( render ); + var self = this; + this.read_name_values().then(function (datas) { - // reinit input type file - var $input = this.$('input.oe_form_binary_file'); - $input.after($input.clone(true)).remove(); - this.$(".oe_fileupload").show(); + var render = $(instance.web.qweb.render('FieldBinaryFileUploader.files', {'widget': self})); + render.on('click', '.oe_delete', _.bind(self.on_file_delete, self)); + self.$('.oe_placeholder_files, .oe_attachments').replaceWith( render ); + + // reinit input type file + var $input = self.$('input.oe_form_binary_file'); + $input.after($input.clone(true)).remove(); + self.$(".oe_fileupload").show(); + + }); }, on_file_change: function (event) { event.stopPropagation(); @@ -5030,7 +5102,7 @@ instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractFiel } // block UI or not - if(this.node.attrs.blockui) { + if(this.node.attrs.blockui>0) { instance.web.blockUI(); } @@ -5064,7 +5136,7 @@ instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractFiel }, on_file_loaded: function (event, result) { // unblock UI - if(this.node.attrs.blockui) { + if(this.node.attrs.blockui>0) { instance.web.unblockUI(); } @@ -5094,7 +5166,7 @@ instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractFiel if(file_id != this.get('value')[i].id){ files.push(this.get('value')[i]); } - else { + else if(!this.get('value')[i].no_unlink) { this.ds_file.unlink([file_id]); } } @@ -5256,7 +5328,7 @@ instance.web.form.widgets = new instance.web.Registry({ 'progressbar': 'instance.web.form.FieldProgressBar', 'image': 'instance.web.form.FieldBinaryImage', 'binary': 'instance.web.form.FieldBinaryFile', - 'one2many_binary': 'instance.web.form.FieldOne2ManyBinaryMultiFiles', + 'many2many_binary': 'instance.web.form.FieldMany2ManyBinaryMultiFiles', 'statusbar': 'instance.web.form.FieldStatus', 'monetary': 'instance.web.form.FieldMonetary', }); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 03a48297eca..df74674a343 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -1,6 +1,6 @@ openerp.web.list = function (instance) { var _t = instance.web._t, - _lt = instance.web._lt; + _lt = instance.web._lt; var QWeb = instance.web.qweb; instance.web.views.add('list', 'instance.web.ListView'); instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListView# */ { @@ -503,12 +503,17 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi return this.reload_content(); }, reload_record: function (record) { + var self = this; return this.dataset.read_ids( [record.get('id')], _.pluck(_(this.columns).filter(function (r) { return r.tag === 'field'; }), 'name') ).done(function (records) { + if (!records[0]) { + self.records.remove(record); + return; + } _(records[0]).each(function (value, key) { record.set(key, value, {silent: true}); }); @@ -1557,9 +1562,8 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we } }); -var DataGroup = instance.web.CallbackEnabled.extend({ +var DataGroup = instance.web.Class.extend({ init: function(parent, model, domain, context, group_by, level) { - this._super(parent, null); this.model = new instance.web.Model(model, context, domain); this.group_by = group_by; this.context = context; @@ -2152,7 +2156,7 @@ instance.web.list.Boolean = instance.web.list.Column.extend({ * @private */ _format: function (row_data, options) { - return _.str.sprintf('<input type="checkbox" %s disabled="disabled"/>', + return _.str.sprintf('<input type="checkbox" %s readonly="readonly"/>', row_data[this.id].value ? 'checked="checked"' : ''); } }); @@ -2164,20 +2168,24 @@ instance.web.list.Binary = instance.web.list.Column.extend({ */ _format: function (row_data, options) { var text = _t("Download"); - var download_url = _.str.sprintf( - '/web/binary/saveas?session_id=%s&model=%s&field=%s&id=%d', - instance.session.session_id, options.model, this.id, options.id); - if (this.filename) { - download_url += '&filename_field=' + this.filename; - if (row_data[this.filename]) { - text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value( - row_data[this.filename].value, {type: 'char'})); + var value = row_data[this.id].value; + var download_url; + if (value && value.substr(0, 10).indexOf(' ') == -1) { + download_url = "data:application/octet-stream;base64," + value; + } else { + download_url = this.session.url('/web/binary/saveas', {model: options.model, field: this.id, id: options.id}); + if (this.filename) { + download_url += '&filename_field=' + this.filename; } } - return _.template('<a href="<%-href%>"><%-text%></a> (%<-size%>)', { + if (this.filename && row_data[this.filename]) { + text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value( + row_data[this.filename].value, {type: 'char'})); + } + return _.template('<a href="<%-href%>"><%-text%></a> (<%-size%>)', { text: text, href: download_url, - size: row_data[this.id].value + size: instance.web.binary_to_binsize(value), }); } }); @@ -2217,7 +2225,7 @@ instance.web.list.Many2OneButton = instance.web.list.Column.extend({ }); instance.web.list.Many2Many = instance.web.list.Column.extend({ _format: function (row_data, options) { - if (row_data[this.id].value) { + if (!_.isEmpty(row_data[this.id].value)) { // If value, use __display version for printing row_data[this.id] = row_data[this.id + '__display']; } diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index 37ce8c4f8b4..1abe3caab39 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -77,6 +77,15 @@ openerp.web.list_editable = function (instance) { do_edit: function (index, id, dataset) { _.extend(this.dataset, dataset); }, + do_delete: function (ids) { + var _super = this._super.bind(this); + var next = this.editor.is_editing() + ? this.cancel_edition(true) + : $.when(); + return next.then(function () { + return _super(ids); + }); + }, editable: function () { return this.fields_view.arch.attrs.editable || this._context_editable @@ -117,13 +126,6 @@ openerp.web.list_editable = function (instance) { e.preventDefault(); self.cancel_edition(); }); - this.$el - .off('click', 'tbody td:not(.oe_list_field_cell)') - .on('click', 'tbody td:not(.oe_list_field_cell)', function () { - if (!self.editor.is_editing()) { - self.start_edition(); - } - }); this.editor.destroy(); // Editor is not restartable due to formview not being // restartable @@ -164,13 +166,23 @@ openerp.web.list_editable = function (instance) { * @returns {$.Deferred} */ ensure_saved: function () { - var self = this; - return this.saving_mutex.exec(function() { - if (!self.editor.is_editing()) { - return $.when(); - } - return self.save_edition(); - }); + return this.save_edition(); + }, + /** + * Builds a record with the provided id (``false`` for a creation), + * setting all columns with ``false`` value so code which relies on + * having an actual value behaves correctly + * + * @param {*} id + * @return {instance.web.list.Record} + */ + make_empty_record: function (id) { + var attrs = {id: id}; + _(this.columns).chain() + .filter(function (x) { return x.tag === 'field'}) + .pluck('name') + .each(function (field) { attrs[field] = false; }); + return new instance.web.list.Record(attrs); }, /** * Set up the edition of a record of the list view "inline" @@ -186,12 +198,7 @@ openerp.web.list_editable = function (instance) { if (record) { item = record.attributes; } else { - var attrs = {id: false}; - _(this.columns).chain() - .filter(function (x) { return x.tag === 'field'}) - .pluck('name') - .each(function (field) { attrs[field] = false; }); - record = new instance.web.list.Record(attrs); + record = this.make_empty_record(false); this.records.add(record, { at: this.prepends_on_create() ? 0 : null}); } @@ -269,29 +276,34 @@ openerp.web.list_editable = function (instance) { */ save_edition: function () { var self = this; - return this.with_event('save', { - editor: this.editor, - form: this.editor.form, - cancel: false - }, function () { - return this.editor.save().then(function (attrs) { - var created = false; - var record = self.records.get(attrs.id); - if (!record) { - // new record - created = true; - record = self.records.find(function (r) { - return !r.get('id'); - }).set('id', attrs.id); - } - // onwrite callback could be altering & reloading the - // record which has *just* been saved, so first perform all - // onwrites then do a final reload of the record - return self.handle_onwrite(record) - .then(function () { - return self.reload_record(record); }) - .then(function () { - return { created: created, record: record }; }); + return self.saving_mutex.exec(function() { + if (!self.editor.is_editing()) { + return $.when(); + } + return self.with_event('save', { + editor: self.editor, + form: self.editor.form, + cancel: false + }, function () { + return self.editor.save().then(function (attrs) { + var created = false; + var record = self.records.get(attrs.id); + if (!record) { + // new record + created = true; + record = self.records.find(function (r) { + return !r.get('id'); + }).set('id', attrs.id); + } + // onwrite callback could be altering & reloading the + // record which has *just* been saved, so first perform all + // onwrites then do a final reload of the record + return self.handle_onwrite(record) + .then(function () { + return self.reload_record(record); }) + .then(function () { + return { created: created, record: record }; }); + }); }); }); }, @@ -391,7 +403,7 @@ openerp.web.list_editable = function (instance) { if (!record) { // insert after the source record var index = this.records.indexOf(source_record) + 1; - record = new instance.web.list.Record({id: id}); + record = this.make_empty_record(id); this.records.add(record, {at: index}); this.dataset.ids.splice(index, 0, id); } diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 53132e454d1..641821152b2 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -213,8 +213,12 @@ instance.web.ActionManager = instance.web.Widget.extend({ if (run_action) { this.null_action(); action_loaded = this.do_action(state.action); - instance.webclient.menu.has_been_loaded.done(function() { - instance.webclient.menu.open_action(state.action); + $.when(action_loaded || null).done(function() { + instance.webclient.menu.has_been_loaded.done(function() { + if (self.inner_action && self.inner_action.id) { + instance.webclient.menu.open_action(self.inner_action.id); + } + }); }); } } @@ -306,15 +310,15 @@ instance.web.ActionManager = instance.web.Widget.extend({ } var widget = executor.widget(); if (executor.action.target === 'new') { - if (this.dialog_widget && ! this.dialog_widget.isDestroyed()) + if (this.dialog_widget && !this.dialog_widget.isDestroyed()) { this.dialog_widget.destroy(); - if (this.dialog === null || this.dialog.isDestroyed()) { - this.dialog = new instance.web.Dialog(this, { - dialogClass: executor.klass, - }); - this.dialog.on("closing", null, options.on_close); - this.dialog.init_dialog(); } + this.dialog_stop(); + this.dialog = new instance.web.Dialog(this, { + dialogClass: executor.klass, + }); + this.dialog.on("closing", null, options.on_close); + this.dialog.init_dialog(); this.dialog.dialog_title = executor.action.name; if (widget instanceof instance.web.ViewManager) { _.extend(widget.flags, { @@ -397,6 +401,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ }).done(function(res) { action = _.clone(action); action.context = res.context; + var c = instance.webclient.crashmanager; self.session.get_file({ url: '/web/report', data: {action: JSON.stringify(action)}, @@ -407,7 +412,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ } self.dialog_stop(); }, - error: instance.webclient.crashmanager.on_rpc_error + error: c.rpc_error.bind(c) }) }); }, @@ -504,7 +509,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ .find('.oe_view_manager_switch a').filter('[data-view-type="' + view_type + '"]') .parent().addClass('active'); - r = $.when(view_promise).done(function () { + return $.when(view_promise).done(function () { _.each(_.keys(self.views), function(view_name) { var controller = self.views[view_name].controller; if (controller) { @@ -520,7 +525,6 @@ instance.web.ViewManager = instance.web.Widget.extend({ }); self.trigger('switch_mode', view_type, no_store, view_options); }); - return r; }, do_create_view: function(view_type) { // Lazy loading of views @@ -785,8 +789,8 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ name: "JS Tests", target: 'new', type : 'ir.actions.act_url', - url: '/web/static/test/test.html' - }) + url: '/web/tests?mod=*' + }); break; case 'perm_read': var ids = current_view.get_selected_ids(); @@ -1098,11 +1102,11 @@ instance.web.Sidebar = instance.web.Widget.extend({ on_attachments_loaded: function(attachments) { var self = this; var items = []; - var prefix = this.session.origin + '/web/binary/saveas?session_id=' + self.session.session_id + '&model=ir.attachment&field=datas&filename_field=name&id='; + var prefix = this.session.url('/web/binary/saveas', {model: 'ir.attachment', field: 'datas', filename_field: 'name'}); _.each(attachments,function(a) { a.label = a.name; if(a.type === "binary") { - a.url = prefix + a.id + '&t=' + (new Date().getTime()); + a.url = prefix + '&id=' + a.id + '&t=' + (new Date().getTime()); } }); self.items['files'] = attachments; @@ -1235,11 +1239,12 @@ instance.web.View = instance.web.Widget.extend({ }); }, null); } else { + self.do_action({"type":"ir.actions.act_window_close"}); return result_handler(); } }; - if (action_data.special) { + if (action_data.special === 'cancel') { return handler({"type":"ir.actions.act_window_close"}); } else if (action_data.type=="object") { var args = [[record_id]], additional_args = []; @@ -1277,6 +1282,27 @@ instance.web.View = instance.web.Widget.extend({ do_hide: function () { this.$el.hide(); }, + is_active: function () { + var manager = this.getParent(); + return !manager || !manager.active_view + || manager.views[manager.active_view].controller === this; + }, /** + * Wraps fn to only call it if the current view is the active one. If the + * current view is not active, doesn't call fn. + * + * fn can not return anything, as a non-call to fn can't return anything + * either + * + * @param {Function} fn function to wrap in the active guard + */ + guard_active: function (fn) { + var self = this; + return function () { + if (self.is_active()) { + fn.apply(self, arguments); + } + } + }, do_push_state: function(state) { if (this.getParent() && this.getParent().do_push_state) { this.getParent().do_push_state(state); @@ -1384,14 +1410,16 @@ instance.web.json_node_to_xml = function(node, human_readable, indent) { } else { return r + '/>'; } -} +}; instance.web.xml_to_str = function(node) { - if (window.ActiveXObject) { + if (window.XMLSerializer) { + return (new XMLSerializer()).serializeToString(node); + } else if (window.ActiveXObject) { return node.xml; } else { - return (new XMLSerializer()).serializeToString(node); + throw new Error("Could not serialize XML"); } -} +}; instance.web.str_to_xml = function(s) { if (window.DOMParser) { var dp = new DOMParser(); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 215374cb6fb..1b7a5cea53a 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -152,6 +152,32 @@ </tr> </table> </form> + <form id="db_duplicate" name="duplicate_db_form" style="display: none;"> + <div class="oe_view_manager oe_view_manager_current"> + <div class="oe_view_manager_header" style="padding: 8px;"> + <div class="oe_header_row"> + <h2 class="oe_view_title"> + <span class="oe_view_title_text oe_breadcrumb_title">Duplicate Database</span> + </h2> + <button type="submit" class="oe_button oe_highlight db_duplicate">Duplicate</button> + </div> + </div> + </div> + <table align="center" class="db_option_table"> + <tr> + <td><label for="super_admin_pwd">Master password:</label></td> + <td><input type="password" name="super_admin_pwd" class="required" value="admin" /></td> + </tr> + <tr> + <td><label for="db_original_name">Original database name:</label></td> + <td><input type="text" name="db_original_name" class="required" matches="^[a-zA-Z][a-zA-Z0-9_-]+$" autofocus="true"/></td> + </tr> + <tr> + <td><label for="db_name">New database name:</label></td> + <td><input type="text" name="db_name" class="required" matches="^[a-zA-Z][a-zA-Z0-9_-]+$" /></td> + </tr> + </table> + </form> <form id="db_drop" name="drop_db_form" style="display: none; "> <div class="oe_view_manager oe_view_manager_current"> <div class="oe_view_manager_header" style="padding: 8px;"> @@ -279,6 +305,7 @@ <div class="oe_secondary_menu_section">Database Management</div> <ul class="oe_secondary_submenu"> <li><a href="#db_create">Create</a></li> + <li><a href="#db_duplicate">Duplicate</a></li> <li><a href="#db_drop">Drop</a></li> <li><a href="#db_backup">Backup</a></li> <li><a href="#db_restore">Restore</a></li> @@ -1182,26 +1209,28 @@ </t> <t t-name="FieldBinaryFileUploader.files"> <div class="oe_attachments"> - <t t-if="!widget.get('effective_readonly')" t-foreach="widget.get('value')" t-as="file"> - <div class="oe_attachment"> - <span t-if="(file.upload or file.percent_loaded<100)" t-attf-title="{(file.name || file.filename) + (file.date?' \n('+file.date+')':'' )}" t-attf-name="{file.name || file.filename}"> - <span class="oe_fileuploader_in_process">...Upload in progress...</span> - <t t-raw="file.name || file.filename"/> - </span> - <a t-if="(!file.upload or file.percent_loaded>=100)" t-att-href="file.url" t-attf-title="{(file.name || file.filename) + (file.date?' \n('+file.date+')':'' )}"> - <t t-raw="file.name || file.filename"/> - </a> - <t t-if="(!file.upload or file.percent_loaded>=100)"> - <a class="oe_right oe_delete oe_e" title="Delete this file" t-attf-data-id="{file.id}">[</a> - </t> - </div> - </t> - <t t-if="widget.get('effective_readonly')" t-foreach="widget.get('value')" t-as="file"> - <div> - <a t-att-href="file.url" t-attf-title="{(file.name || file.filename) + (file.date?' \n('+file.date+')':'' )}"> - <t t-raw="file.name || file.filename"/> - </a> - </div> + <t t-if="widget.get('value')"> + <t t-if="!widget.get('effective_readonly')" t-foreach="widget.get('value')" t-as="file"> + <div class="oe_attachment"> + <span t-if="(file.upload or file.percent_loaded<100)" t-attf-title="{(file.name || file.filename) + (file.date?' \n('+file.date+')':'' )}" t-attf-name="{file.name || file.filename}"> + <span class="oe_fileuploader_in_process">...Upload in progress...</span> + <t t-raw="file.name || file.filename"/> + </span> + <a t-if="(!file.upload or file.percent_loaded>=100)" t-att-href="file.url" t-attf-title="{(file.name || file.filename) + (file.date?' \n('+file.date+')':'' )}"> + <t t-raw="file.name || file.filename"/> + </a> + <t t-if="(!file.upload or file.percent_loaded>=100)"> + <a class="oe_right oe_delete oe_e" title="Delete this file" t-attf-data-id="{file.id}">[</a> + </t> + </div> + </t> + <t t-if="widget.get('effective_readonly')" t-foreach="widget.get('value')" t-as="file"> + <div> + <a t-att-href="file.url" t-attf-title="{(file.name || file.filename) + (file.date?' \n('+file.date+')':'' )}"> + <t t-raw="file.name || file.filename"/> + </a> + </div> + </t> </t> </div> </t> @@ -1512,17 +1541,19 @@ <h3><span class="oe_i">M</span> Custom Filters</h3> <ul class="oe_searchview_custom_list"/> <div class="oe_searchview_custom"> - <h4>Save current filter</h4> - <form> - <p><input id="oe_searchview_custom_input" placeholder="Filter name"/></p> - <p><input id="oe_searchview_custom_public" type="checkbox"/> - <label for="oe_searchview_custom_public">Share with all users</label></p> - <button>Save</button> - </form> + <h4>Save current filter</h4> + <form> + <p><input id="oe_searchview_custom_input" placeholder="Filter name"/></p> + <p> + <input id="oe_searchview_custom_public" type="checkbox"/> + <label for="oe_searchview_custom_public">Share with all users</label> + <input id="oe_searchview_custom_default" type="checkbox"/> + <label for="oe_searchview_custom_default">Use by default</label> + </p> + <button>Save</button> + </form> </div> </div> - <div> - </div> </div> <div t-name="SearchView.advanced" class="oe_searchview_advanced"> diff --git a/addons/web/static/test/Widget.js b/addons/web/static/test/Widget.js index 3e6cc262565..44b7cfe0dfa 100644 --- a/addons/web/static/test/Widget.js +++ b/addons/web/static/test/Widget.js @@ -1,32 +1,7 @@ -$(document).ready(function () { - var $fix = $('#qunit-fixture'); - var mod = { - setup: function () { - instance = window.openerp.init([]); - window.openerp.web.corelib(instance); - - instance.web.qweb = new QWeb2.Engine(); - instance.web.qweb.add_template( - '<no>' + - '<t t-name="test.widget.template">' + - '<ol>' + - '<li t-foreach="5" t-as="counter" ' + - 't-attf-class="class-#{counter}">' + - '<input/>' + - '<t t-esc="counter"/>' + - '</li>' + - '</ol>' + - '</t>' + - '<t t-name="test.widget.template-value">' + - '<p><t t-esc="widget.value"/></p>' + - '</t>' + - '</no>'); - } - }; - var instance; - - module('Widget.proxy', mod); - test('(String)', function () { +openerp.testing.section('Widget.proxy', { + dependencies: ['web.corelib'] +}, function (test) { + test('(String)', function (instance) { var W = instance.web.Widget.extend({ exec: function () { this.executed = true; @@ -37,7 +12,7 @@ $(document).ready(function () { fn(); ok(w.executed, 'should execute the named method in the right context'); }); - test('(String)(*args)', function () { + test('(String)(*args)', function (instance) { var W = instance.web.Widget.extend({ exec: function (arg) { this.executed = arg; @@ -49,7 +24,7 @@ $(document).ready(function () { ok(w.executed, "should execute the named method in the right context"); equal(w.executed, 42, "should be passed the proxy's arguments"); }); - test('(String), include', function () { + test('(String), include', function (instance) { // the proxy function should handle methods being changed on the class // and should always proxy "by name", to the most recent one var W = instance.web.Widget.extend({ @@ -67,23 +42,43 @@ $(document).ready(function () { equal(w.executed, 2, "should be lazily resolved"); }); - test('(Function)', function () { + test('(Function)', function (instance) { 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 () { + test('(Function)(*args)', function (instance) { var w = new (instance.web.Widget.extend({ })); var fn = w.proxy(function (arg) { this.executed = arg; }); fn(42); equal(w.executed, 42, "should be passed the proxy's arguments"); }); - - module('Widget.renderElement', mod); - test('no template, default', function () { +}); +openerp.testing.section('Widget.renderElement', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.qweb = new QWeb2.Engine(); + instance.web.qweb.add_template( + '<no>' + + '<t t-name="test.widget.template">' + + '<ol>' + + '<li t-foreach="5" t-as="counter" ' + + 't-attf-class="class-#{counter}">' + + '<input/>' + + '<t t-esc="counter"/>' + + '</li>' + + '</ol>' + + '</t>' + + '<t t-name="test.widget.template-value">' + + '<p><t t-esc="widget.value"/></p>' + + '</t>' + + '</no>'); + } +}, function (test) { + test('no template, default', function (instance) { var w = new (instance.web.Widget.extend({ })); var $original = w.$el; @@ -98,7 +93,7 @@ $(document).ready(function () { equal(w.el.attributes.length, 0, "should not have generated any attribute"); ok(_.isEmpty(w.$el.html(), "should not have generated any content")); }); - test('no template, custom tag', function () { + test('no template, custom tag', function (instance) { var w = new (instance.web.Widget.extend({ tagName: 'ul' })); @@ -106,7 +101,7 @@ $(document).ready(function () { equal(w.el.nodeName, 'UL', "should have generated the custom element tag"); }); - test('no template, @id', function () { + test('no template, @id', function (instance) { var w = new (instance.web.Widget.extend({ id: 'foo' })); @@ -116,7 +111,7 @@ $(document).ready(function () { equal(w.$el.attr('id'), 'foo', "should have generated the id attribute"); equal(w.el.id, 'foo', "should also be available via property"); }); - test('no template, @className', function () { + test('no template, @className', function (instance) { var w = new (instance.web.Widget.extend({ className: 'oe_some_class' })); @@ -125,7 +120,7 @@ $(document).ready(function () { equal(w.el.className, 'oe_some_class', "should have the right property"); equal(w.$el.attr('class'), 'oe_some_class', "should have the right attribute"); }); - test('no template, bunch of attributes', function () { + test('no template, bunch of attributes', function (instance) { var w = new (instance.web.Widget.extend({ attributes: { 'id': 'some_id', @@ -152,7 +147,7 @@ $(document).ready(function () { equal(w.$el.attr('spoiler'), 'snape kills dumbledore'); }); - test('template', function () { + test('template', function (instance) { var w = new (instance.web.Widget.extend({ template: 'test.widget.template' })); @@ -162,9 +157,41 @@ $(document).ready(function () { equal(w.$el.children().length, 5); equal(w.el.textContent, '01234'); }); - - module('Widget.$', mod); - test('basic-alias', function () { + 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 () { + equal($fix.find('p').text(), '42', "DOM fixture should contain initial value"); + equal(w.$el.text(), '42', "should set initial value"); + w.value = 36; + w.renderElement(); + equal($fix.find('p').text(), '36', "DOM fixture should use new value"); + equal(w.$el.text(), '36', "should set new value"); + }); + }); +}); +openerp.testing.section('Widget.$', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.qweb = new QWeb2.Engine(); + instance.web.qweb.add_template( + '<no>' + + '<t t-name="test.widget.template">' + + '<ol>' + + '<li t-foreach="5" t-as="counter" ' + + 't-attf-class="class-#{counter}">' + + '<input/>' + + '<t t-esc="counter"/>' + + '</li>' + + '</ol>' + + '</t>' + + '</no>'); + } +}, function (test) { + test('basic-alias', function (instance) { var w = new (instance.web.Widget.extend({ template: 'test.widget.template' })); @@ -173,9 +200,26 @@ $(document).ready(function () { ok(w.$('li:eq(3)').is(w.$el.find('li:eq(3)')), "should do the same thing as calling find on the widget root"); }); - - module('Widget.events', mod); - test('delegate', function () { +}); +openerp.testing.section('Widget.events', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.qweb = new QWeb2.Engine(); + instance.web.qweb.add_template( + '<no>' + + '<t t-name="test.widget.template">' + + '<ol>' + + '<li t-foreach="5" t-as="counter" ' + + 't-attf-class="class-#{counter}">' + + '<input/>' + + '<t t-esc="counter"/>' + + '</li>' + + '</ol>' + + '</t>' + + '</no>'); + } +}, function (test) { + test('delegate', function (instance) { var a = []; var w = new (instance.web.Widget.extend({ template: 'test.widget.template', @@ -199,7 +243,7 @@ $(document).ready(function () { ok(a[i], "should pass test " + i); } }); - test('undelegate', function () { + test('undelegate', function (instance) { var clicked = false, newclicked = false; var w = new (instance.web.Widget.extend({ template: 'test.widget.template', @@ -218,22 +262,4 @@ $(document).ready(function () { ok(!clicked, "undelegate should unbind events delegated"); ok(newclicked, "undelegate should only unbind events it created"); }); - - module('Widget.renderElement', mod); - asyncTest('repeated', 4, function () { - var w = new (instance.web.Widget.extend({ - template: 'test.widget.template-value' - })); - w.value = 42; - w.appendTo($fix) - .always(start) - .done(function () { - equal($fix.find('p').text(), '42', "DOM fixture should contain initial value"); - equal(w.$el.text(), '42', "should set initial value"); - w.value = 36; - w.renderElement(); - equal($fix.find('p').text(), '36', "DOM fixture should use new value"); - equal(w.$el.text(), '36', "should set new value"); - }); - }); }); diff --git a/addons/web/static/test/class.js b/addons/web/static/test/class.js index faad4421e31..bb3fb7e12b9 100644 --- a/addons/web/static/test/class.js +++ b/addons/web/static/test/class.js @@ -1,30 +1,25 @@ -$(document).ready(function () { - var openerp; - module('web-class', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - } - }); - test('Basic class creation', function () { - var C = openerp.web.Class.extend({ +openerp.testing.section('class', { + dependencies: ['web.corelib'] +}, function (test) { + test('Basic class creation', function (instance) { + var C = instance.web.Class.extend({ foo: function () { return this.somevar; } }); - var instance = new C(); - instance.somevar = 3; + var i = new C(); + i.somevar = 3; - ok(instance instanceof C); - strictEqual(instance.foo(), 3); + ok(i instanceof C); + strictEqual(i.foo(), 3); }); - test('Class initialization', function () { - var C1 = openerp.web.Class.extend({ + test('Class initialization', function (instance) { + var C1 = instance.web.Class.extend({ init: function () { this.foo = 3; } }); - var C2 = openerp.web.Class.extend({ + var C2 = instance.web.Class.extend({ init: function (arg) { this.foo = arg; } @@ -36,8 +31,8 @@ $(document).ready(function () { strictEqual(i1.foo, 3); strictEqual(i2.foo, 42); }); - test('Inheritance', function () { - var C0 = openerp.web.Class.extend({ + test('Inheritance', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; } @@ -57,8 +52,8 @@ $(document).ready(function () { strictEqual(new C1().foo(), 2); strictEqual(new C2().foo(), 3); }); - test('In-place extension', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extension', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 3; }, @@ -83,8 +78,8 @@ $(document).ready(function () { strictEqual(new C0().foo(), 5); strictEqual(new C0().qux(), 5); }); - test('In-place extension and inheritance', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extension and inheritance', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; }, bar: function () { return 1; } }); @@ -101,24 +96,24 @@ $(document).ready(function () { strictEqual(new C1().foo(), 4); strictEqual(new C1().bar(), 2); }); - test('In-place extensions alter existing instances', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extensions alter existing instances', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; }, bar: function () { return 1; } }); - var instance = new C0(); - strictEqual(instance.foo(), 1); - strictEqual(instance.bar(), 1); + var i = new C0(); + strictEqual(i.foo(), 1); + strictEqual(i.bar(), 1); C0.include({ foo: function () { return 2; }, bar: function () { return 2 + this._super(); } }); - strictEqual(instance.foo(), 2); - strictEqual(instance.bar(), 3); + strictEqual(i.foo(), 2); + strictEqual(i.bar(), 3); }); - test('In-place extension of subclassed types', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extension of subclassed types', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; }, bar: function () { return 1; } }); @@ -126,13 +121,13 @@ $(document).ready(function () { foo: function () { return 1 + this._super(); }, bar: function () { return 1 + this._super(); } }); - var instance = new C1(); - strictEqual(instance.foo(), 2); + var i = new C1(); + strictEqual(i.foo(), 2); C0.include({ foo: function () { return 2; }, bar: function () { return 2 + this._super(); } }); - strictEqual(instance.foo(), 3); - strictEqual(instance.bar(), 4); + strictEqual(i.foo(), 3); + strictEqual(i.bar(), 4); }); }); diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js index 757d98c5bcc..6eec615b199 100644 --- a/addons/web/static/test/evals.js +++ b/addons/web/static/test/evals.js @@ -1,18 +1,11 @@ -$(document).ready(function () { - var openerp; - - module("eval.contexts", { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - } - }); - test('context_sequences', function () { +openerp.testing.section('eval.contexts', { + dependencies: ['web.coresetup'] +}, function (test) { + test('context_sequences', function (instance) { // Context n should have base evaluation context + all of contexts // 0..n-1 in its own evaluation context var active_id = 4; - var result = openerp.session.test_eval_contexts([ + var result = instance.session.test_eval_contexts([ { "__contexts": [ { @@ -55,8 +48,8 @@ $(document).ready(function () { record_id: active_id }); }); - test('non-literal_eval_contexts', function () { - var result = openerp.session.test_eval_contexts([{ + test('non-literal_eval_contexts', function (instance) { + var result = instance.session.test_eval_contexts([{ "__ref": "compound_context", "__contexts": [ {"__ref": "context", "__debug": "{'type':parent.type}", @@ -133,17 +126,15 @@ $(document).ready(function () { }]); deepEqual(result, {type: 'out_invoice'}); }); - module('eval.domains', { - setup: function () { - openerp = window.openerp.testing.instanceFor('coresetup'); - window.openerp.web.dates(openerp); - } - }); - test('current_date', function () { - var current_date = openerp.web.date_to_str(new Date()); - var result = openerp.session.test_eval_domains( +}); +openerp.testing.section('eval.contexts', { + dependencies: ['web.coresetup', 'web.dates'] +}, function (test) { + test('current_date', function (instance) { + var current_date = instance.web.date_to_str(new Date()); + var result = instance.session.test_eval_domains( [[],{"__ref":"domain","__debug":"[('name','>=',current_date),('name','<=',current_date)]","__id":"5dedcfc96648"}], - openerp.session.test_eval_get_context()); + instance.session.test_eval_get_context()); deepEqual(result, [ ['name', '>=', current_date], ['name', '<=', current_date] diff --git a/addons/web/static/test/form.js b/addons/web/static/test/form.js index aace926a96a..0c8107ce9bc 100644 --- a/addons/web/static/test/form.js +++ b/addons/web/static/test/form.js @@ -1,33 +1,21 @@ -$(document).ready(function () { - var openerp; - module("form.widget", { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - window.openerp.web.form(openerp); - } - }); - test("compute_domain", function () { +openerp.testing.section('compute_domain', { + dependencies: ['web.form'] +}, function (test) { + test("basic", function (instance) { var fields = { 'a': {value: 3}, 'group_method': {value: 'line'}, 'select1': {value: 'day'}, 'rrule_type': {value: 'monthly'} }; - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( [['a', '=', 3]], fields)); - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( [['group_method','!=','count']], fields)); - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( [['select1','=','day'], ['rrule_type','=','monthly']], fields)); }); - test("compute_domain or", function () { + test("or", function (instance) { var web = { 'section_id': {value: null}, 'user_id': {value: null}, @@ -38,22 +26,22 @@ $(document).ready(function () { '|', ['user_id','=',3], ['member_ids', 'in', [3]]]; - ok(openerp.web.form.compute_domain(domain, _.extend( + ok(instance.web.form.compute_domain(domain, _.extend( {}, web, {'section_id': {value: 42}}))); - ok(openerp.web.form.compute_domain(domain, _.extend( + ok(instance.web.form.compute_domain(domain, _.extend( {}, web, {'user_id': {value: 3}}))); - ok(openerp.web.form.compute_domain(domain, _.extend( + ok(instance.web.form.compute_domain(domain, _.extend( {}, web, {'member_ids': {value: 3}}))); }); - test("compute_domain not", function () { + test("not", function (instance) { var fields = { 'a': {value: 5}, 'group_method': {value: 'line'} }; - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( ['!', ['a', '=', 3]], fields)); - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( ['!', ['group_method','=','count']], fields)); }); }); diff --git a/addons/web/static/test/formats.js b/addons/web/static/test/formats.js index 4fe07ff0a9c..4536501d71d 100644 --- a/addons/web/static/test/formats.js +++ b/addons/web/static/test/formats.js @@ -1,16 +1,8 @@ -$(document).ready(function () { - var openerp; - - module('server-formats', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.dates(openerp); - } - }); - test('Parse server datetime', function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); +openerp.testing.section('server-formats', { + dependencies: ['web.coresetup', 'web.dates'] +}, function (test) { + test('Parse server datetime', function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); deepEqual( [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()], @@ -20,92 +12,86 @@ $(document).ready(function () { date.getHours(), date.getMinutes(), date.getSeconds()], [2009, 5 - 1, 4, 12 - (date.getTimezoneOffset() / 60), 34, 23]); - var date2 = openerp.web.str_to_datetime('2011-12-10 00:00:00'); + var date2 = instance.web.str_to_datetime('2011-12-10 00:00:00'); deepEqual( [date2.getUTCFullYear(), date2.getUTCMonth(), date2.getUTCDate(), date2.getUTCHours(), date2.getUTCMinutes(), date2.getUTCSeconds()], [2011, 12 - 1, 10, 0, 0, 0]); }); - test('Parse server date', function () { - var date = openerp.web.str_to_date("2009-05-04"); + test('Parse server date', function (instance) { + var date = instance.web.str_to_date("2009-05-04"); deepEqual( [date.getFullYear(), date.getMonth(), date.getDate()], [2009, 5 - 1, 4]); }); - test('Parse server time', function () { - var date = openerp.web.str_to_time("12:34:23"); + test('Parse server time', function (instance) { + var date = instance.web.str_to_time("12:34:23"); deepEqual( [date.getHours(), date.getMinutes(), date.getSeconds()], [12, 34, 23]); }); - - module('web-formats', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.dates(openerp); - window.openerp.web.formats(openerp); - } - }); - test("format_datetime", function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); - var str = openerp.web.format_value(date, {type:"datetime"}); +}); +openerp.testing.section('web-formats', { + dependencies: ['web.formats'] +}, function (test) { + test("format_datetime", function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); + var str = instance.web.format_value(date, {type:"datetime"}); equal(str, date.toString("MM/dd/yyyy HH:mm:ss")); }); - test("format_date", function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); - var str = openerp.web.format_value(date, {type:"date"}); + test("format_date", function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); + var str = instance.web.format_value(date, {type:"date"}); equal(str, date.toString("MM/dd/yyyy")); }); - test("format_time", function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); - var str = openerp.web.format_value(date, {type:"time"}); + test("format_time", function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); + var str = instance.web.format_value(date, {type:"time"}); equal(str, date.toString("HH:mm:ss")); }); - test("format_float_time", function () { + test("format_float_time", function (instance) { strictEqual( - openerp.web.format_value(1.0, {type:'float', widget:'float_time'}), + instance.web.format_value(1.0, {type:'float', widget:'float_time'}), '01:00'); strictEqual( - openerp.web.format_value(0.9853, {type:'float', widget:'float_time'}), + instance.web.format_value(0.9853, {type:'float', widget:'float_time'}), '00:59'); strictEqual( - openerp.web.format_value(0.0085, {type:'float', widget:'float_time'}), + instance.web.format_value(0.0085, {type:'float', widget:'float_time'}), '00:01'); strictEqual( - openerp.web.format_value(-1.0, {type:'float', widget:'float_time'}), + instance.web.format_value(-1.0, {type:'float', widget:'float_time'}), '-01:00'); strictEqual( - openerp.web.format_value(-0.9853, {type:'float', widget:'float_time'}), + instance.web.format_value(-0.9853, {type:'float', widget:'float_time'}), '-00:59'); strictEqual( - openerp.web.format_value(-0.0085, {type:'float', widget:'float_time'}), + instance.web.format_value(-0.0085, {type:'float', widget:'float_time'}), '-00:01'); }); - test("format_float", function () { + test("format_float", function (instance) { var fl = 12.1234; - var str = openerp.web.format_value(fl, {type:"float"}); + var str = instance.web.format_value(fl, {type:"float"}); equal(str, "12.12"); - equal(openerp.web.format_value(12.02, {type: 'float'}), + equal(instance.web.format_value(12.02, {type: 'float'}), '12.02'); - equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 3]}), + equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 3]}), '0.000'); - equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 4]}), + equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 4]}), '0.0002'); - equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 6]}), + equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 6]}), '0.000200'); - equal(openerp.web.format_value(1, {type: 'float', digits: [1, 6]}), + equal(instance.web.format_value(1, {type: 'float', digits: [1, 6]}), '1.000000'); - equal(openerp.web.format_value(1, {type: 'float'}), + equal(instance.web.format_value(1, {type: 'float'}), '1.00'); - equal(openerp.web.format_value(-11.25, {type: 'float'}), + equal(instance.web.format_value(-11.25, {type: 'float'}), "-11.25"); - openerp.web._t.database.parameters.grouping = [1, 2, -1]; - equal(openerp.web.format_value(1111111.25, {type: 'float'}), + instance.web._t.database.parameters.grouping = [1, 2, -1]; + equal(instance.web.format_value(1111111.25, {type: 'float'}), "1111,11,1.25"); - openerp.web._t.database.parameters.grouping = [1, 0]; - equal(openerp.web.format_value(-11.25, {type: 'float'}), + instance.web._t.database.parameters.grouping = [1, 0]; + equal(instance.web.format_value(-11.25, {type: 'float'}), "-1,1.25"); }); // test("parse_datetime", function () { @@ -123,29 +109,29 @@ $(document).ready(function () { // var res = openerp.web.parse_value(val.toString("HH:mm:ss"), {type:"time"}); // equal(val.toString("HH:mm:ss"), res.toString("HH:mm:ss")); // }); - test('parse_integer', function () { - var val = openerp.web.parse_value('123,456', {type: 'integer'}); + test('parse_integer', function (instance) { + var val = instance.web.parse_value('123,456', {type: 'integer'}); equal(val, 123456); - openerp.web._t.database.parameters.thousands_sep = '|'; - var val2 = openerp.web.parse_value('123|456', {type: 'integer'}); + instance.web._t.database.parameters.thousands_sep = '|'; + var val2 = instance.web.parse_value('123|456', {type: 'integer'}); equal(val2, 123456); }); - test("parse_float", function () { + test("parse_float", function (instance) { var str = "134,112.1234"; - var val = openerp.web.parse_value(str, {type:"float"}); + var val = instance.web.parse_value(str, {type:"float"}); equal(val, 134112.1234); var str = "-134,112.1234"; - var val = openerp.web.parse_value(str, {type:"float"}); + var val = instance.web.parse_value(str, {type:"float"}); equal(val, -134112.1234); - _.extend(openerp.web._t.database.parameters, { + _.extend(instance.web._t.database.parameters, { decimal_point: ',', thousands_sep: '.' }); - var val3 = openerp.web.parse_value('123.456,789', {type: 'float'}); + var val3 = instance.web.parse_value('123.456,789', {type: 'float'}); equal(val3, 123456.789); }); - test('intersperse', function () { - var g = openerp.web.intersperse; + test('intersperse', function (instance) { + var g = instance.web.intersperse; equal(g("", []), ""); equal(g("0", []), "0"); equal(g("012", []), "012"); @@ -176,60 +162,61 @@ $(document).ready(function () { equal(g("12345678", [3,3,3,3], '.'), '12.345.678'); equal(g("12345678", [3,0], '.'), '12.345.678'); }); - test('format_integer', function () { - openerp.web._t.database.parameters.grouping = [3, 3, 3, 3]; - equal(openerp.web.format_value(1000000, {type: 'integer'}), + test('format_integer', function (instance) { + instance.web._t.database.parameters.grouping = [3, 3, 3, 3]; + equal(instance.web.format_value(1000000, {type: 'integer'}), '1,000,000'); - openerp.web._t.database.parameters.grouping = [3, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'integer'}), + instance.web._t.database.parameters.grouping = [3, 2, -1]; + equal(instance.web.format_value(106500, {type: 'integer'}), '1,06,500'); - openerp.web._t.database.parameters.grouping = [1, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'integer'}), + instance.web._t.database.parameters.grouping = [1, 2, -1]; + equal(instance.web.format_value(106500, {type: 'integer'}), '106,50,0'); }); - test('format_float', function () { - openerp.web._t.database.parameters.grouping = [3, 3, 3, 3]; - equal(openerp.web.format_value(1000000, {type: 'float'}), + test('format_float', function (instance) { + instance.web._t.database.parameters.grouping = [3, 3, 3, 3]; + equal(instance.web.format_value(1000000, {type: 'float'}), '1,000,000.00'); - openerp.web._t.database.parameters.grouping = [3, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'float'}), + instance.web._t.database.parameters.grouping = [3, 2, -1]; + equal(instance.web.format_value(106500, {type: 'float'}), '1,06,500.00'); - openerp.web._t.database.parameters.grouping = [1, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'float'}), + instance.web._t.database.parameters.grouping = [1, 2, -1]; + equal(instance.web.format_value(106500, {type: 'float'}), '106,50,0.00'); - _.extend(openerp.web._t.database.parameters, { + _.extend(instance.web._t.database.parameters, { grouping: [3, 0], decimal_point: ',', thousands_sep: '.' }); - equal(openerp.web.format_value(6000, {type: 'float'}), + equal(instance.web.format_value(6000, {type: 'float'}), '6.000,00'); }); - module('custom-date-formats', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.dates(openerp); - window.openerp.web.formats(openerp); - } - }); - test('format stripper', function () { - strictEqual(openerp.web.strip_raw_chars('%a, %Y %b %d'), '%a, %Y %b %d'); - strictEqual(openerp.web.strip_raw_chars('%a, %Y.eko %bren %da'), '%a, %Y. %b %d'); - }); - test('ES date format', function () { - openerp.web._t.database.parameters.date_format = '%a, %Y %b %d'; - var date = openerp.web.str_to_date("2009-05-04"); - strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009 May 04'); - strictEqual(openerp.web.parse_value('Mon, 2009 May 04', {type: 'date'}), '2009-05-04'); - }); - test('extended ES date format', function () { - openerp.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da'; - var date = openerp.web.str_to_date("2009-05-04"); - strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009. May 04'); - strictEqual(openerp.web.parse_value('Mon, 2009. May 04', {type: 'date'}), '2009-05-04'); +}); +openerp.testing.section('web-formats', { + dependencies: ['web.formats'] +}, function (test) { + test('format stripper', function (instance) { + strictEqual(instance.web.strip_raw_chars('%a, %Y %b %d'), + '%a, %Y %b %d'); + strictEqual(instance.web.strip_raw_chars('%a, %Y.eko %bren %da'), + '%a, %Y. %b %d'); + }); + test('ES date format', function (instance) { + instance.web._t.database.parameters.date_format = '%a, %Y %b %d'; + var date = instance.web.str_to_date("2009-05-04"); + strictEqual(instance.web.format_value(date, {type:"date"}), + 'Mon, 2009 May 04'); + strictEqual(instance.web.parse_value('Mon, 2009 May 04', {type: 'date'}), + '2009-05-04'); + }); + test('extended ES date format', function (instance) { + instance.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da'; + var date = instance.web.str_to_date("2009-05-04"); + strictEqual(instance.web.format_value(date, {type:"date"}), + 'Mon, 2009. May 04'); + strictEqual(instance.web.parse_value('Mon, 2009. May 04', {type: 'date'}), + '2009-05-04'); }); }); diff --git a/addons/web/static/test/list-editable.js b/addons/web/static/test/list-editable.js index 459a6df397a..b02e8abed96 100644 --- a/addons/web/static/test/list-editable.js +++ b/addons/web/static/test/list-editable.js @@ -1,16 +1,13 @@ -$(document).ready(function () { - var $fix = $('#qunit-fixture'); - - var instance; - var baseSetup = function () { - instance = openerp.testing.instanceFor('list_editable'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - }; - - +openerp.testing.section('editor', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + mock('test.model:create', function () { + return 42; + }); + } +}, function (test) { /** * * @param {String} name @@ -30,7 +27,7 @@ $(document).ready(function () { } /** - * @param {Array} fields + * @param {Array} [fields] * @return {Object} */ function makeFormView(fields) { @@ -67,46 +64,37 @@ $(document).ready(function () { }; } - module('editor', { - setup: baseSetup - }); - asyncTest('base-state', 2, function () { + test('base-state', {asserts: 2}, function (instance, $fix) { var e = new instance.web.list.Editor({ dataset: {ids: []}, edition_view: function () { return makeFormView(); } }); - e.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return e.appendTo($fix) .done(function () { ok(!e.is_editing(), "should not be editing"); ok(e.form instanceof instance.web.FormView, "should use default form type"); }); }); - asyncTest('toggle-edition-save', 4, function () { - instance.session.responses['/web/dataset/call_kw:create'] = function () { - return { result: 42 }; - }; - instance.session.responses['/web/dataset/call_kw:read'] = function () { - return { result: [{ - id: 42, - a: false, - b: false, - c: false - }]}; - }; + test('toggle-edition-save', { + asserts: 4, + setup: function (instance, $s, mock) { + mock('test.model:read', function () { + return [{id: 42, a: false, b: false, c: false}]; + }); + } + }, function (instance, $fix) { var e = new instance.web.list.Editor({ - dataset: new instance.web.DataSetSearch(), + dataset: new instance.web.DataSetSearch(null, 'test.model'), prepends_on_create: function () { return false; }, edition_view: function () { return makeFormView([ field('a'), field('b'), field('c') ]); } }); var counter = 0; - e.appendTo($fix) + return e.appendTo($fix) .then(function () { return e.edit({}, function () { ++counter; @@ -117,26 +105,21 @@ $(document).ready(function () { equal(counter, 3, "should have configured all fields"); return e.save(); }) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) .done(function (record) { ok(!e.is_editing(), "should have stopped editing"); equal(record.id, 42, "should have newly created id"); }) }); - asyncTest('toggle-edition-cancel', 2, function () { - instance.session.responses['/web/dataset/call_kw:create'] = function () { - return { result: 42 }; - }; + test('toggle-edition-cancel', { asserts: 2 }, function (instance, $fix) { var e = new instance.web.list.Editor({ - dataset: new instance.web.DataSetSearch(), + dataset: new instance.web.DataSetSearch(null, 'test.model'), prepends_on_create: function () { return false; }, edition_view: function () { return makeFormView([ field('a'), field('b'), field('c') ]); } }); var counter = 0; - e.appendTo($fix) + return e.appendTo($fix) .then(function () { return e.edit({}, function () { ++counter; @@ -145,22 +128,20 @@ $(document).ready(function () { .then(function (form) { return e.cancel(); }) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) .done(function (record) { ok(!e.is_editing(), "should have stopped editing"); ok(!record.id, "should have no id"); }) }); - asyncTest('toggle-save-required', 2, function () { - instance.session.responses['/web/dataset/call_kw:create'] = function () { - return { result: 42 }; - }; + test('toggle-save-required', { + asserts: 2, + fail_on_rejection: false + }, function (instance, $fix) { var e = new instance.web.list.Editor({ do_warn: function () { warnings++; }, - dataset: new instance.web.DataSetSearch(), + dataset: new instance.web.DataSetSearch(null, 'test.model'), prepends_on_create: function () { return false; }, edition_view: function () { return makeFormView([ @@ -169,7 +150,7 @@ $(document).ready(function () { }); var counter = 0; var warnings = 0; - e.appendTo($fix) + return e.appendTo($fix) .then(function () { return e.edit({}, function () { ++counter; @@ -178,78 +159,73 @@ $(document).ready(function () { .then(function (form) { return e.save(); }) - .always(start) .done(function () { ok(false, "cancel should not succeed"); }) .fail(function () { equal(warnings, 1, "should have been warned"); ok(e.is_editing(), "should have kept editing"); - }) + }); }); - - module('list-edition', { - setup: function () { - baseSetup(); - - var records = {}; - _.extend(instance.session.responses, { - '/web/view/load': function () { - return {result: { - type: 'tree', - fields: { - a: {type: 'char', string: "A"}, - b: {type: 'char', string: "B"}, - c: {type: 'char', string: "C"} - }, - arch: { - tag: 'tree', - attrs: {}, - children: [ - {tag: 'field', attrs: {name: 'a'}}, - {tag: 'field', attrs: {name: 'b'}}, - {tag: 'field', attrs: {name: 'c'}} - ] - } - }}; - }, - '/web/dataset/call_kw:create': function (params) { - records[42] = _.extend({}, params.params.args[0]); - return {result: 42}; +}); +openerp.testing.section('list.edition', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + var records = {}; + mock('demo:create', function (args) { + records[42] = _.extend({}, args[0]); + return 42; + }); + mock('demo:read', function (args) { + var id = args[0][0]; + if (id in records) { + return [records[id]]; + } + return []; + }); + mock('/web/view/load', function () { + return { + type: 'tree', + fields: { + a: {type: 'char', string: "A"}, + b: {type: 'char', string: "B"}, + c: {type: 'char', string: "C"} }, - '/web/dataset/call_kw:read': function (params) { - var id = params.params.args[0][0]; - if (id in records) { - return {result: [records[id]]}; - } - return {result: []}; + arch: { + tag: 'tree', + attrs: {}, + children: [ + {tag: 'field', attrs: {name: 'a'}}, + {tag: 'field', attrs: {name: 'b'}}, + {tag: 'field', attrs: {name: 'c'}} + ] } - }) - } - }); - asyncTest('newrecord', 6, function () { + }; + }); + } +}, function (test) { + test('newrecord', {asserts: 6}, function (instance, $fix, mock) { var got_defaults = false; - instance.session.responses['/web/dataset/call_kw:default_get'] = function (params) { - var fields = params.params.args[0]; + mock('demo:default_get', function (args) { + var fields = args[0]; deepEqual( fields, ['a', 'b', 'c'], "should ask defaults for all fields"); got_defaults = true; - return {result: { - a: "qux", - b: "quux" - }}; - }; + return { a: "qux", b: "quux" }; + }); var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]); var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); - l.appendTo($fix) + return l.appendTo($fix) .then(l.proxy('reload_content')) .then(function () { return l.start_edition(); }) - .always(start) .then(function () { ok(got_defaults, "should have fetched default values for form"); + return l.save_edition(); }) .then(function (result) { @@ -260,45 +236,39 @@ $(document).ready(function () { "should have used default values"); ok(!result.record.get('c'), "should have no value if there was no default"); - }) - .fail(function (e) { ok(false, e && e.message || e); }); + }); }); - - module('list-edition-events', { - setup: function () { - baseSetup(); - _.extend(instance.session.responses, { - '/web/view/load': function () { - return {result: { - type: 'tree', - fields: { - a: {type: 'char', string: "A"}, - b: {type: 'char', string: "B"}, - c: {type: 'char', string: "C"} - }, - arch: { - tag: 'tree', - attrs: {}, - children: [ - {tag: 'field', attrs: {name: 'a'}}, - {tag: 'field', attrs: {name: 'b'}}, - {tag: 'field', attrs: {name: 'c'}} - ] - } - }}; +}); +openerp.testing.section('list.edition.events', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + mock('demo:read', function () { + return [{ id: 1, a: 'foo', b: 'bar', c: 'baz' }]; + }); + mock('/web/view/load', function () { + return { + type: 'tree', + fields: { + a: {type: 'char', string: "A"}, + b: {type: 'char', string: "B"}, + c: {type: 'char', string: "C"} }, - '/web/dataset/call_kw:read': function (params) { - return {result: [{ - id: 1, - a: 'foo', - b: 'bar', - c: 'baz' - }]}; + arch: { + tag: 'tree', + attrs: {}, + children: [ + {tag: 'field', attrs: {name: 'a'}}, + {tag: 'field', attrs: {name: 'b'}}, + {tag: 'field', attrs: {name: 'c'}} + ] } - }); - } - }); - asyncTest('edition events', 4, function () { + }; + }); + } +}, function (test) { + test('edition events', {asserts: 4}, function (instance, $fix) { var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]); var o = { counter: 0, @@ -306,9 +276,8 @@ $(document).ready(function () { }; var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); l.on('edit:before edit:after', o, o.onEvent); - l.appendTo($fix) + return l.appendTo($fix) .then(l.proxy('reload_content')) - .always(start) .then(function () { ok(l.options.editable, "should be editable"); equal(o.counter, 0, "should have seen no event yet"); @@ -317,11 +286,10 @@ $(document).ready(function () { .then(function () { ok(l.editor.is_editing(), "should be editing"); equal(o.counter, 2, "should have seen two edition events"); - }) - .fail(function (e) { ok(false, e && e.message); }); + }); }); - asyncTest('edition events: cancelling', 3, function () { + test('edition events: cancelling', {asserts: 3}, function (instance, $fix) { var edit_after = false; var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]); var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); @@ -331,9 +299,8 @@ $(document).ready(function () { l.on('edit:after', {}, function () { edit_after = true; }); - l.appendTo($fix) + return l.appendTo($fix) .then(l.proxy('reload_content')) - .always(start) .then(function () { ok(l.options.editable, "should be editable"); return l.start_edition(); @@ -343,7 +310,71 @@ $(document).ready(function () { ok(!l.editor.is_editing(), "should not be editing"); ok(!edit_after, "should not have fired the edit:after event"); return $.when(); - }) - .fail(function (e) { ok(false, e && e.message || e); }); + }); + }); +}); + +openerp.testing.section('list.edition.onwrite', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, +}, function (test) { + test('record-to-read', {asserts: 4}, function (instance, $fix, mock) { + mock('/web/view/load', function () { + return { + type: 'tree', + fields: { + a: {type: 'char', string: "A"} + }, + arch: { + tag: 'tree', + attrs: { on_write: 'on_write', colors: 'red:a == "foo"' }, + children: [ + {tag: 'field', attrs: {name: 'a'}} + ] + } + }; + }); + mock('demo:read', function (args, kwargs) { + if (_.isEmpty(args[0])) { + return []; + } else if (_.isEqual(args[0], [1])) { + return [ + {id: 1, a: 'some value'} + ]; + } else if (_.isEqual(args[0], [42])) { + return [ {id: 42, a: 'foo'} ]; + } + throw new Error(JSON.stringify(_.toArray(arguments))); + }); + mock('demo:default_get', function () { return {}; }); + mock('demo:create', function () { return 1; }); + mock('demo:on_write', function () { return [42]; }); + + var ds = new instance.web.DataSetStatic(null, 'demo', null, []); + var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); + return l.appendTo($fix) + .then(l.proxy('reload_content')) + .then(function () { + return l.start_edition(); + }) + .then(function () { + $fix.find('.oe_form_field input').val("some value").change(); + }) + .then(function () { + return l.save_edition(); + }) + .then(function () { + strictEqual(ds.ids.length, 2, + 'should have id of created + on_write'); + strictEqual(l.records.length, 2, + 'should have record of created + on_write'); + strictEqual( + $fix.find('tbody tr:eq(1)').css('color'), 'rgb(255, 0, 0)', + 'shoud have color applied'); + strictEqual( + $fix.find('tbody tr:eq(2)').css('color'), 'rgb(0, 0, 0)', + 'should have default color applied'); + }); }); }); diff --git a/addons/web/static/test/list-utils.js b/addons/web/static/test/list-utils.js index 6200ba788ce..84661138315 100644 --- a/addons/web/static/test/list-utils.js +++ b/addons/web/static/test/list-utils.js @@ -1,45 +1,34 @@ -$(document).ready(function () { - var openerp, - create = function (o) { - if (typeof Object.create === 'function') { - return Object.create(o); - } - function Cls() {} - Cls.prototype = o; - return new Cls; - }; - module('list-events', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); +openerp.testing.section('list.events', { + dependencies: ['web.list'] +}, function (test) { + var create = function (o) { + if (typeof Object.create === 'function') { + return Object.create(o); } - }); - test('Simple event triggering', function () { - var e = create(openerp.web.list.Events), passed = false; + function Cls() {} + Cls.prototype = o; + return new Cls; + }; + test('Simple event triggering', function (instance) { + var e = create(instance.web.list.Events), passed = false; e.bind('foo', function () { passed = true; }); e.trigger('foo'); ok(passed); }); - test('Bind all', function () { - var e = create(openerp.web.list.Events), event = null; + test('Bind all', function (instance) { + var e = create(instance.web.list.Events), event = null; e.bind(null, function (ev) { event = ev; }); e.trigger('foo'); strictEqual(event, 'foo'); }); - test('Propagate trigger params', function () { - var e = create(openerp.web.list.Events), p = false; + test('Propagate trigger params', function (instance) { + var e = create(instance.web.list.Events), p = false; e.bind(null, function (_, param) { p = param }); e.trigger('foo', true); strictEqual(p, true) }); - test('Bind multiple callbacks', function () { - var e = create(openerp.web.list.Events), count; + test('Bind multiple callbacks', function (instance) { + var e = create(instance.web.list.Events), count; e.bind('foo', function () { count++; }) .bind('bar', function () { count++; }) .bind(null, function () { count++; }) @@ -59,20 +48,20 @@ $(document).ready(function () { e.trigger('baz'); strictEqual(count, 3); }); - test('Mixin events', function () { - var cls = openerp.web.Class.extend({ + test('Mixin events', function (instance) { + var cls = instance.web.Class.extend({ method: function () { this.trigger('e'); } }); - cls.include(openerp.web.list.Events); - var instance = new cls, triggered = false; + cls.include(instance.web.list.Events); + var i = new cls, triggered = false; - instance.bind('e', function () { triggered = true; }); - instance.method(); + i.bind('e', function () { triggered = true; }); + i.method(); ok(triggered); }); - test('Unbind all handlers', function () { - var e = create(openerp.web.list.Events), passed = 0; + test('Unbind all handlers', function (instance) { + var e = create(instance.web.list.Events), passed = 0; e.bind('foo', function () { passed++; }); e.trigger('foo'); strictEqual(passed, 1); @@ -80,8 +69,8 @@ $(document).ready(function () { e.trigger('foo'); strictEqual(passed, 1); }); - test('Unbind one handler', function () { - var e = create(openerp.web.list.Events), p1 = 0, p2 = 0, + test('Unbind one handler', function (instance) { + var e = create(instance.web.list.Events), p1 = 0, p2 = 0, h1 = function () { p1++; }, h2 = function () { p2++; }; e.bind('foo', h1); e.bind('foo', h2); @@ -93,29 +82,20 @@ $(document).ready(function () { strictEqual(p1, 1); strictEqual(p2, 2); }); - - module('list-records', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('Basic record initialization', function () { - var r = new openerp.web.list.Record({qux: 3}); +}); +openerp.testing.section('list.records', { + dependencies: ['web.list'] +}, function (test) { + test('Basic record initialization', function (instance) { + var r = new instance.web.list.Record({qux: 3}); r.set('foo', 1); r.set('bar', 2); strictEqual(r.get('foo'), 1); strictEqual(r.get('bar'), 2); strictEqual(r.get('qux'), 3); }); - test('Change all the things', function () { - var r = new openerp.web.list.Record(), changed = false, field; + 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.set('foo', 1); @@ -123,8 +103,8 @@ $(document).ready(function () { ok(changed); strictEqual(field, 'foo'); }); - test('Change single field', function () { - var r = new openerp.web.list.Record(), changed = 0; + test('Change single field', function (instance) { + var r = new instance.web.list.Record(), changed = 0; r.bind('change:foo', function () { changed++; }); r.set('foo', 1); r.set('bar', 1); @@ -132,21 +112,12 @@ $(document).ready(function () { strictEqual(r.get('bar'), 1); strictEqual(changed, 1); }); - - module('list-collections', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('degenerate-fetch', function () { - var c = new openerp.web.list.Collection(); +}); +openerp.testing.section('list.collections', { + dependencies: ['web.list'] +}, function (test) { + test('degenerate-fetch', function (instance) { + var c = new instance.web.list.Collection(); strictEqual(c.length, 0); c.add({id: 1, value: 2}); c.add({id: 2, value: 3}); @@ -155,16 +126,16 @@ $(document).ready(function () { strictEqual(c.length, 4); var r = c.at(2), r2 = c.get(1); - ok(r instanceof openerp.web.list.Record); + ok(r instanceof instance.web.list.Record); strictEqual(r.get('id'), 3); strictEqual(r.get('value'), 5); - ok(r2 instanceof openerp.web.list.Record); + ok(r2 instanceof instance.web.list.Record); strictEqual(r2.get('id'), 1); strictEqual(r2.get('value'), 2); }); - test('degenerate-indexed-add', function () { - var c = new openerp.web.list.Collection([ + test('degenerate-indexed-add', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -175,8 +146,8 @@ $(document).ready(function () { strictEqual(c.at(1).get('value'), 55); strictEqual(c.at(3).get('value'), 20); }); - test('degenerate-remove', function () { - var c = new openerp.web.list.Collection([ + test('degenerate-remove', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -188,9 +159,9 @@ $(document).ready(function () { equal(c.get(2), undefined); strictEqual(c.at(1).get('value'), 20); }); - test('degenerate-remove-bound', function () { + test('degenerate-remove-bound', function (instance) { var changed = false, - c = new openerp.web.list.Collection([ {id: 1, value: 5} ]); + c = new instance.web.list.Collection([ {id: 1, value: 5} ]); c.bind('change', function () { changed = true; }); var record = c.get(1); c.remove(record); @@ -198,8 +169,8 @@ $(document).ready(function () { ok(!changed, 'removed records should not trigger events in their ' + 'parent collection'); }); - test('degenerate-reset', function () { - var event, obj, c = new openerp.web.list.Collection([ + test('degenerate-reset', function (instance) { + var event, obj, c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -218,9 +189,9 @@ $(document).ready(function () { strictEqual(c.length, 1); strictEqual(c.get(42).get('value'), 55); }); - test('degenerate-reset-bound', function () { + test('degenerate-reset-bound', function (instance) { var changed = false, - c = new openerp.web.list.Collection([ {id: 1, value: 5} ]); + c = new instance.web.list.Collection([ {id: 1, value: 5} ]); c.bind('change', function () { changed = true; }); var record = c.get(1); c.reset(); @@ -229,9 +200,9 @@ $(document).ready(function () { 'parent collection'); }); - test('degenerate-propagations', function () { + test('degenerate-propagations', function (instance) { var values = []; - var c = new openerp.web.list.Collection([ + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -244,8 +215,8 @@ $(document).ready(function () { c.get(3).set('value', 21); deepEqual(values, [6, 11, 21]); }); - test('BTree', function () { - var root = new openerp.web.list.Collection(), + test('BTree', function (instance) { + var root = new instance.web.list.Collection(), c = root.proxy('admin'), total = 0; c.add({id: 1, name: "Administrator", login: 'admin'}); @@ -260,8 +231,8 @@ $(document).ready(function () { c.at(1).set('wealth', 5); strictEqual(total, 47); }); - test('degenerate-successor', function () { - var root = new openerp.web.list.Collection([ + test('degenerate-successor', function (instance) { + var root = new instance.web.list.Collection([ {id: 1, value: 1}, {id: 2, value: 2}, {id: 3, value: 3}, @@ -282,8 +253,8 @@ $(document).ready(function () { root.at(3).attributes, "wraparound should have no effect if not succ(last_record)"); }); - test('successor', function () { - var root = new openerp.web.list.Collection(); + test('successor', function (instance) { + var root = new instance.web.list.Collection(); root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]); root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]); root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]); @@ -298,8 +269,8 @@ $(document).ready(function () { root.get(3).attributes, "should wraparound within a collection"); }); - test('degenerate-predecessor', function () { - var root = new openerp.web.list.Collection([ + test('degenerate-predecessor', function (instance) { + var root = new instance.web.list.Collection([ {id: 1, value: 1}, {id: 2, value: 2}, {id: 3, value: 3}, @@ -320,8 +291,8 @@ $(document).ready(function () { root.at(0).attributes, "wraparound should have no effect if not pred(first_record)"); }); - test('predecessor', function () { - var root = new openerp.web.list.Collection(); + test('predecessor', function (instance) { + var root = new instance.web.list.Collection(); root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]); root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]); root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]); @@ -336,21 +307,12 @@ $(document).ready(function () { root.get(4).attributes, "should wraparound within a collection"); }); - - module('list-hofs', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('each, degenerate', function () { - var c = new openerp.web.list.Collection([ +}); +openerp.testing.section('list.collections.hom', { + dependencies: ['web.list'] +}, function (test) { + test('each, degenerate', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -362,8 +324,8 @@ $(document).ready(function () { ids, [1, 2, 3], 'degenerate collections should be iterated in record order'); }); - test('each, deep', function () { - var root = new openerp.web.list.Collection(), + test('each, deep', function (instance) { + var root = new instance.web.list.Collection(), ids = []; root.proxy('foo').add([ {id: 1, value: 5}, @@ -382,8 +344,8 @@ $(document).ready(function () { ids, [1, 2, 3, 10, 20, 30], 'tree collections should be deeply iterated'); }); - test('map, degenerate', function () { - var c = new openerp.web.list.Collection([ + test('map, degenerate', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -395,8 +357,8 @@ $(document).ready(function () { ids, [1, 2, 3], 'degenerate collections should be iterated in record order'); }); - test('map, deep', function () { - var root = new openerp.web.list.Collection(); + test('map, deep', function (instance) { + var root = new instance.web.list.Collection(); root.proxy('foo').add([ {id: 1, value: 5}, {id: 2, value: 10}, @@ -414,29 +376,20 @@ $(document).ready(function () { ids, [1, 2, 3, 10, 20, 30], 'tree collections should be deeply iterated'); }); - - module("list-weirds", { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('set-from-noid', function () { - var root = new openerp.web.list.Collection(); +}); +openerp.testing.section('list.collection.weirdoes', { + dependencies: ['web.list'] +}, function (test) { + test('set-from-noid', function (instance) { + var root = new instance.web.list.Collection(); root.add({v: 3}); root.at(0).set('id', 42); var record = root.get(42); equal(root.length, 1); equal(record.get('v'), 3, "should have fetched the original record"); }); - test('set-from-previd', function () { - var root = new openerp.web.list.Collection(); + test('set-from-previd', function (instance) { + var root = new instance.web.list.Collection(); root.add({id: 1, v: 2}); root.get(1).set('id', 42); var record = root.get(42); diff --git a/addons/web/static/test/list.js b/addons/web/static/test/list.js new file mode 100644 index 00000000000..22c33ef104a --- /dev/null +++ b/addons/web/static/test/list.js @@ -0,0 +1,56 @@ +openerp.testing.section('list.buttons', { + dependencies: ['web.list', 'web.form'], + rpc: 'mock', + templates: true +}, function (test) { + test('record-deletion', {asserts: 2}, function (instance, $fix, mock) { + mock('/web/view/load', function () { + return { + type: 'tree', + fields: { + a: {type: 'char', string: "A"} + }, + arch: { + tag: 'tree', + attrs: { }, + children: [ + {tag: 'field', attrs: {name: 'a'}}, + {tag: 'button', attrs: {type: 'object', name: 'foo'}} + ] + } + }; + }); + mock('demo:read', function (args, kwargs) { + if (_.isEqual(args[0], [1, 2, 3])) { + return [ + {id: 1, a: 'foo'}, {id: 2, a: 'bar'}, {id: 3, a: 'baz'} + ]; + } else if (_.isEqual(args[0], [2])) { + // button action virtually removed record + return []; + } + throw new Error(JSON.stringify(_.toArray(arguments))); + }); + mock('/web/dataset/call_button', function () { return false; }); + var ds = new instance.web.DataSetStatic(null, 'demo', null, [1, 2, 3]); + var l = new instance.web.ListView({ + do_action: openerp.testing.noop + }, ds, false, {editable: 'top'}); + return l.appendTo($fix) + .then(l.proxy('reload_content')) + .then(function () { + var d = $.Deferred(); + l.records.bind('remove', function () { + d.resolve(); + }); + $fix.find('table tbody tr:eq(1) button').click(); + return d.promise(); + }) + .then(function () { + strictEqual(l.records.length, 2, + "should have 2 records left"); + strictEqual($fix.find('table tbody tr[data-id]').length, 2, + "should have 2 rows left"); + }); + }); +}); diff --git a/addons/web/static/test/mutex.js b/addons/web/static/test/mutex.js new file mode 100644 index 00000000000..e88911b5b45 --- /dev/null +++ b/addons/web/static/test/mutex.js @@ -0,0 +1,60 @@ +openerp.testing.section('mutex', { + dependencies: ['web.coresetup'], + setup: function (instance) { + } +}, function (test) { + test('simpleScheduling', function (instance) { + var m = new $.Mutex(); + var def1 = $.Deferred(); + var def2 = $.Deferred(); + var p1 = m.exec(function() { return def1; }); + var p2 = m.exec(function() { return def2; }); + equal(p1.state(), "pending"); + equal(p2.state(), "pending"); + def1.resolve(); + equal(p1.state(), "resolved"); + equal(p2.state(), "pending"); + def2.resolve(); + equal(p1.state(), "resolved"); + equal(p2.state(), "resolved"); + }); + test('simpleScheduling2', function (instance) { + var m = new $.Mutex(); + var def1 = $.Deferred(); + var def2 = $.Deferred(); + var p1 = m.exec(function() { return def1; }); + var p2 = m.exec(function() { return def2; }); + equal(p1.state(), "pending"); + equal(p2.state(), "pending"); + def2.resolve(); + equal(p1.state(), "pending"); + equal(p2.state(), "pending"); + def1.resolve(); + equal(p1.state(), "resolved"); + equal(p2.state(), "resolved"); + }); + test('reject', function (instance) { + var m = new $.Mutex(); + var def1 = $.Deferred(); + var def2 = $.Deferred(); + var def3 = $.Deferred(); + var p1 = m.exec(function() {return def1;}); + var p2 = m.exec(function() {return def2;}); + var p3 = m.exec(function() {return def3;}); + equal(p1.state(), "pending"); + equal(p2.state(), "pending"); + equal(p3.state(), "pending"); + def1.resolve(); + equal(p1.state(), "resolved"); + equal(p2.state(), "pending"); + equal(p3.state(), "pending"); + def2.reject(); + equal(p1.state(), "resolved"); + equal(p2.state(), "rejected"); + equal(p3.state(), "pending"); + def3.resolve(); + equal(p1.state(), "resolved"); + equal(p2.state(), "rejected"); + equal(p3.state(), "resolved"); + }); +}); diff --git a/addons/web/static/test/registry.js b/addons/web/static/test/registry.js index ca689a351e0..2ad69a541bc 100644 --- a/addons/web/static/test/registry.js +++ b/addons/web/static/test/registry.js @@ -1,58 +1,55 @@ -$(document).ready(function () { - var openerp; - module('Registry', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - openerp.web.Foo = {}; - openerp.web.Bar = {}; - openerp.web.Foo2 = {}; - } - }); - test('key set', function () { - var reg = new openerp.web.Registry(); +openerp.testing.section('registry', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.Foo = {}; + instance.web.Bar = {}; + instance.web.Foo2 = {}; + } +}, function (test) { + test('key set', function (instance) { + var reg = new instance.web.Registry(); - reg.add('foo', 'openerp.web.Foo') - .add('bar', 'openerp.web.Bar'); - strictEqual(reg.get_object('bar'), openerp.web.Bar); + reg.add('foo', 'instance.web.Foo') + .add('bar', 'instance.web.Bar'); + strictEqual(reg.get_object('bar'), instance.web.Bar); }); - test('extension', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('extension', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); - var reg2 = reg.extend({ 'foo': 'openerp.web.Foo2' }); - strictEqual(reg.get_object('foo'), openerp.web.Foo); - strictEqual(reg2.get_object('foo'), openerp.web.Foo2); + var reg2 = reg.extend({ 'foo': 'instance.web.Foo2' }); + strictEqual(reg.get_object('foo'), instance.web.Foo); + strictEqual(reg2.get_object('foo'), instance.web.Foo2); }); - test('remain-linked', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('remain-linked', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); var reg2 = reg.extend(); - reg.add('foo2', 'openerp.web.Foo2'); - strictEqual(reg.get_object('foo2'), openerp.web.Foo2); - strictEqual(reg2.get_object('foo2'), openerp.web.Foo2); + reg.add('foo2', 'instance.web.Foo2'); + strictEqual(reg.get_object('foo2'), instance.web.Foo2); + strictEqual(reg2.get_object('foo2'), instance.web.Foo2); }); - test('multiget', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('multiget', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); strictEqual(reg.get_any(['qux', 'grault', 'bar', 'foo']), - openerp.web.Bar); + instance.web.Bar); }); - test('extended-multiget', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('extended-multiget', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); var reg2 = reg.extend(); strictEqual(reg2.get_any(['qux', 'grault', 'bar', 'foo']), - openerp.web.Bar); + instance.web.Bar); }); }); diff --git a/addons/web/static/test/rpc.js b/addons/web/static/test/rpc.js index be7cbce9f41..85f562ef225 100644 --- a/addons/web/static/test/rpc.js +++ b/addons/web/static/test/rpc.js @@ -1,16 +1,8 @@ -$(document).ready(function () { - var openerp; - - module('Misordered resolution management', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.data(openerp); - } - }); - test('Resolve all correctly ordered, sync', function () { - var dm = new openerp.web.DropMisordered(), flag = false; +openerp.testing.section('misordered resolution managemeng', { + dependencies: ['web.data'] +}, function (test) { + test('Resolve all correctly ordered, sync', function (instance) { + var dm = new instance.web.DropMisordered(), flag = false; var d1 = $.Deferred(), d2 = $.Deferred(), r1 = dm.add(d1), r2 = dm.add(d2); @@ -23,8 +15,8 @@ $(document).ready(function () { ok(flag); }); - test("Don't resolve mis-ordered, sync", function () { - var dm = new openerp.web.DropMisordered(), + test("Don't resolve mis-ordered, sync", function (instance) { + var dm = new instance.web.DropMisordered(), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -44,8 +36,8 @@ $(document).ready(function () { ok(done2); ok(!fail2); }); - test('Fail mis-ordered flag, sync', function () { - var dm = new openerp.web.DropMisordered(true), + test('Fail mis-ordered flag, sync', function (instance) { + var dm = new instance.web.DropMisordered(true), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -66,8 +58,8 @@ $(document).ready(function () { ok(!fail2); }); - asyncTest('Resolve all correctly ordered, async', 1, function () { - var dm = new openerp.web.DropMisordered(); + test('Resolve all correctly ordered, async', {asserts: 1}, function (instance) { + var dm = new instance.web.DropMisordered(); var d1 = $.Deferred(), d2 = $.Deferred(), r1 = dm.add(d1), r2 = dm.add(d2); @@ -75,13 +67,12 @@ $(document).ready(function () { setTimeout(function () { d1.resolve(); }, 100); setTimeout(function () { d2.resolve(); }, 200); - $.when(r1, r2).done(function () { - start(); + return $.when(r1, r2).done(function () { ok(true); }); }); - asyncTest("Don't resolve mis-ordered, async", 4, function () { - var dm = new openerp.web.DropMisordered(), + test("Don't resolve mis-ordered, async", {asserts: 4}, function (instance) { + var dm = new instance.web.DropMisordered(), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -94,18 +85,20 @@ $(document).ready(function () { setTimeout(function () { d1.resolve(); }, 200); setTimeout(function () { d2.resolve(); }, 100); + var done = $.Deferred(); setTimeout(function () { - start(); // d1 is in limbo ok(!done1); ok(!fail1); // d2 is resolved ok(done2); ok(!fail2); + done.resolve(); }, 400); + return $.when(d1, d2, done); }); - asyncTest('Fail mis-ordered flag, async', 4, function () { - var dm = new openerp.web.DropMisordered(true), + test('Fail mis-ordered flag, async', {asserts: 4}, function (instance) { + var dm = new instance.web.DropMisordered(true), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -118,6 +111,7 @@ $(document).ready(function () { setTimeout(function () { d1.resolve(); }, 200); setTimeout(function () { d2.resolve(); }, 100); + var done = $.Deferred(); setTimeout(function () { start(); // d1 is failed @@ -126,6 +120,8 @@ $(document).ready(function () { // d2 is resolved ok(done2); ok(!fail2); + done.resolve(); }, 400); + return $.when(d1, d2, done) }); }); diff --git a/addons/web/static/test/search.js b/addons/web/static/test/search.js index 3ef4d6840e2..20534eff76a 100644 --- a/addons/web/static/test/search.js +++ b/addons/web/static/test/search.js @@ -1,11 +1,7 @@ -$(document).ready(function () { - var instance; - module('query', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - } - }); - test('Adding a facet to the query creates a facet and a value', function () { +openerp.testing.section('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 field = {}; query.add({ @@ -19,7 +15,7 @@ $(document).ready(function () { equal(facet.get('field'), field); deepEqual(facet.get('values'), [{label: 'Value', value: 3}]); }); - test('Adding two facets', function () { + test('Adding two facets', function (instance) { var query = new instance.web.search.SearchQuery; query.add([ { category: 'Foo', field: {}, values: [{label: 'Value', value: 3}] }, @@ -30,7 +26,7 @@ $(document).ready(function () { equal(query.at(0).values.length, 1); equal(query.at(1).values.length, 1); }); - test('If a facet already exists, add values to it', function () { + test('If a facet already exists, add values to it', function (instance) { var query = new instance.web.search.SearchQuery; var field = {}; query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -43,7 +39,7 @@ $(document).ready(function () { {label: 'V2', value: 1} ]); }); - test('Facet being implicitly changed should trigger change, not add', function () { + test('Facet being implicitly changed should trigger change, not add', function (instance) { var query = new instance.web.search.SearchQuery; var field = {}, added = false, changed = false; query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -54,7 +50,7 @@ $(document).ready(function () { 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 () { + test('Toggling a facet, value which does not exist should add it', function (instance) { var query = new instance.web.search.SearchQuery; var field = {}; query.toggle({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -65,7 +61,7 @@ $(document).ready(function () { deepEqual(facet.get('values'), [{label: 'V1', value: 0}], "Facet's value should match input"); }); - test('Toggling a facet which exists with a value which does not should add the value to the facet', function () { + 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; query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -79,7 +75,7 @@ $(document).ready(function () { {label: 'V2', value: 1} ]); }); - test('Toggling a facet which exists with a value which does as well should remove the value from the facet', function () { + 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; query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -94,7 +90,7 @@ $(document).ready(function () { {label: 'V1', value: 0} ]); }); - test('Toggling off the last value of a facet should remove the facet', function () { + test('Toggling off the last value of a facet should remove the facet', function (instance) { var field = {}; var query = new instance.web.search.SearchQuery; query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -103,7 +99,7 @@ $(document).ready(function () { equal(query.length, 0, 'Should have removed the facet'); }); - test('Intermediate emptiness should not remove the facet', function () { + test('Intermediate emptiness should not remove the facet', function (instance) { var field = {}; var query = new instance.web.search.SearchQuery; query.add({category: 'A', field: field, values: [{label: 'V1', value: 0}]}); @@ -121,7 +117,7 @@ $(document).ready(function () { ]); }); - test('Reseting with multiple facets should still work to load defaults', function () { + test('Reseting with multiple facets should still work to load defaults', function (instance) { var query = new instance.web.search.SearchQuery; var field = {}; query.reset([ @@ -135,78 +131,75 @@ $(document).ready(function () { {label: 'V2', value: 1} ]) }); +}); - module('defaults', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } - }); - - /** - * Builds a basic search view with a single "dummy" field. The dummy - * extends `instance.web.search.Field`, it does not add any (class) - * attributes beyond what is provided through ``dummy_widget_attributes``. - * - * The view is returned un-started, it is the caller's role to start it - * (or use DOM-insertion methods to start it indirectly). - * - * @param [dummy_widget_attributes={}] - * @param [defaults={}] - * @return {instance.web.SearchView} - */ - function makeSearchView(dummy_widget_attributes, defaults) { - instance.web.search.fields.add( - 'dummy', 'instance.dummy.DummyWidget'); - instance.dummy = {}; - instance.dummy.DummyWidget = instance.web.search.Field.extend( - dummy_widget_attributes || {}); - if (!('/web/searchview/load' in instance.session.responses)) { - instance.session.responses['/web/searchview/load'] = function () { - return {result: {fields_view: { - type: 'search', - fields: { - dummy: {type: 'char', string: "Dummy"} - }, - arch: { - tag: 'search', - attrs: {}, - children: [{ - tag: 'field', - attrs: { - name: 'dummy', - widget: 'dummy' - }, - children: [] - }] - } - }}}; - }; - } - instance.session.responses['/web/searchview/get_filters'] = function () { - return {result: []}; - }; - instance.session.responses['/web/searchview/fields_get'] = function () { - return {result: {fields: { - dummy: {type: 'char', string: 'Dummy'} - }}}; +/** + * Builds a basic search view with a single "dummy" field. The dummy + * extends `instance.web.search.Field`, it does not add any (class) + * attributes beyond what is provided through ``dummy_widget_attributes``. + * + * The view is returned un-started, it is the caller's role to start it + * (or use DOM-insertion methods to start it indirectly). + * + * @param instance + * @param [dummy_widget_attributes={}] + * @param [defaults={}] + * @return {instance.web.SearchView} + */ +var makeSearchView = function (instance, dummy_widget_attributes, defaults) { + instance.web.search.fields.add( + 'dummy', 'instance.dummy.DummyWidget'); + instance.dummy = {}; + instance.dummy.DummyWidget = instance.web.search.Field.extend( + dummy_widget_attributes || {}); + if (!('/web/searchview/load' in instance.session.responses)) { + instance.session.responses['/web/searchview/load'] = function () { + return {fields_view: { + type: 'search', + fields: { + dummy: {type: 'char', string: "Dummy"} + }, + arch: { + tag: 'search', + attrs: {}, + children: [{ + tag: 'field', + attrs: { + name: 'dummy', + widget: 'dummy' + }, + children: [] + }] + } + }}; }; - - var dataset = {model: 'dummy.model', get_context: function () { return {}; }}; - var view = new instance.web.SearchView(null, dataset, false, defaults); - var self = this; - view.on('invalid_search', self, function () { - ok(false, JSON.stringify([].slice(arguments))); - }); - return view; } - asyncTest('calling', 2, function () { + instance.session.responses['/web/searchview/get_filters'] = function () { + return []; + }; + instance.session.responses['/web/searchview/fields_get'] = function () { + return {fields: { + dummy: {type: 'char', string: 'Dummy'} + }}; + }; + + var dataset = {model: 'dummy.model', get_context: function () { return {}; }}; + var view = new instance.web.SearchView(null, dataset, false, defaults); + var self = this; + view.on('invalid_search', self, function () { + ok(false, JSON.stringify([].slice(arguments))); + }); + return view; +}; +openerp.testing.section('defaults', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true, +}, function (test) { + test('calling', {asserts: 2}, function (instance, $s) { var defaults_called = false; - var view = makeSearchView({ + var view = makeSearchView(instance, { facet_for_defaults: function (defaults) { defaults_called = true; return $.when({ @@ -216,9 +209,7 @@ $(document).ready(function () { }); } }, {dummy: 42}); - view.appendTo($('#qunit-fixture')) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($s) .done(function () { ok(defaults_called, "should have called defaults"); deepEqual( @@ -227,7 +218,7 @@ $(document).ready(function () { "should have generated a facet with the default value"); }); }); - asyncTest('FilterGroup', 3, function () { + test('FilterGroup', {asserts: 3}, function (instance) { var view = {inputs: [], query: {on: function () {}}}; var filter_a = new instance.web.search.Filter( {attrs: {name: 'a'}}, view); @@ -235,9 +226,7 @@ $(document).ready(function () { {attrs: {name: 'b'}}, view); var group = new instance.web.search.FilterGroup( [filter_a, filter_b], view); - group.facet_for_defaults({a: true, b: true}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return group.facet_for_defaults({a: true, b: true}) .done(function (facet) { var model = facet; if (!(model instanceof instance.web.search.Facet)) { @@ -249,13 +238,11 @@ $(document).ready(function () { strictEqual(values.at(1).get('value'), filter_b); }); }); - asyncTest('Field', 4, function () { + test('Field', {asserts: 4}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.Field( {attrs: {string: 'Dummy', name: 'dummy'}}, {}, view); - f.facet_for_defaults({dummy: 42}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return f.facet_for_defaults({dummy: 42}) .done(function (facet) { var model = facet; if (!(model instanceof instance.web.search.Facet)) { @@ -275,15 +262,13 @@ $(document).ready(function () { "facet value should match provided default"); }); }); - asyncTest('Selection: valid value', 4, function () { + test('Selection: valid value', {asserts: 4}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.SelectionField( {attrs: {name: 'dummy', string: 'Dummy'}}, {selection: [[1, "Foo"], [2, "Bar"], [3, "Baz"], [4, "Qux"]]}, view); - f.facet_for_defaults({dummy: 3}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return f.facet_for_defaults({dummy: 3}) .done(function (facet) { var model = facet; if (!(model instanceof instance.web.search.Facet)) { @@ -303,36 +288,28 @@ $(document).ready(function () { "facet value should match provided default's selection"); }); }); - asyncTest('Selection: invalid value', 1, function () { + test('Selection: invalid value', {asserts: 1}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.SelectionField( {attrs: {name: 'dummy', string: 'Dummy'}}, {selection: [[1, "Foo"], [2, "Bar"], [3, "Baz"], [4, "Qux"]]}, view); - f.facet_for_defaults({dummy: 42}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return f.facet_for_defaults({dummy: 42}) .done(function (facet) { ok(!facet, "an invalid value should result in a not-facet"); }); }); - asyncTest("M2O default: value", 7, function () { + test("M2O default: value", {asserts: 5}, function (instance, $s, mock) { var view = {inputs: []}, id = 4; var f = new instance.web.search.ManyToOneField( {attrs: {name: 'dummy', string: 'Dummy'}}, {relation: 'dummy.model.name'}, view); - instance.session.responses['/web/dataset/call_kw'] = function (req) { - equal(req.params.method, 'name_get', - "m2o should resolve default id"); - equal(req.params.model, f.attrs.relation, - "query model should match m2o relation"); - equal(req.params.args[0], id); - return {result: [[id, "DumDumDum"]]}; - }; - f.facet_for_defaults({dummy: id}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + mock('dummy.model.name:name_get', function (args) { + equal(args[0], id); + return [[id, "DumDumDum"]]; + }); + return f.facet_for_defaults({dummy: id}) .done(function (facet) { var model = facet; if (!(model instanceof instance.web.search.Facet)) { @@ -352,34 +329,26 @@ $(document).ready(function () { "facet value should match provided default's selection"); }); }); - asyncTest("M2O default: value", 1, function () { + test("M2O default: value", {asserts: 1}, function (instance, $s, mock) { var view = {inputs: []}, id = 4; var f = new instance.web.search.ManyToOneField( {attrs: {name: 'dummy', string: 'Dummy'}}, {relation: 'dummy.model.name'}, view); - instance.session.responses['/web/dataset/call_kw'] = function (req) { - return {result: []}; - }; - f.facet_for_defaults({dummy: id}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + 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"); }); }); - - module('completions', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } - }); - asyncTest('calling', 4, function () { - var view = makeSearchView({ +}); +openerp.testing.section('completions', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true +}, function (test) { + test('calling', {asserts: 4}, function (instance, $s) { + var view = makeSearchView(instance, { complete: function () { return $.when({ label: "Dummy", @@ -391,10 +360,11 @@ $(document).ready(function () { }); } }); - view.appendTo($('#qunit-fixture')) - .done(function () { + var done = $.Deferred(); + view.appendTo($s) + .then(function () { view.complete_global_search({term: "dum"}, function (completions) { - start(); + done.resolve(); equal(completions.length, 1, "should have a single completion"); var completion = completions[0]; equal(completion.label, "Dummy", @@ -405,9 +375,10 @@ $(document).ready(function () { [{label: 'dummy', value: 42}], "should have provided values"); }); - }); + }).fail(function () { done.reject.apply(done, arguments); }); + return done; }); - asyncTest('facet selection', 2, function () { + test('facet selection', {asserts: 2}, function (instance, $s) { var completion = { label: "Dummy", facet: { @@ -421,10 +392,8 @@ $(document).ready(function () { } }; - var view = makeSearchView({}); - view.appendTo($('#qunit-fixture')) - .always(start) - .fail(function (error) { ok(false, error.message); }) + var view = makeSearchView(instance); + return view.appendTo($s) .done(function () { view.select_completion( {preventDefault: function () {}}, @@ -436,7 +405,7 @@ $(document).ready(function () { "should have the right facet in the query"); }); }); - asyncTest('facet selection: new value existing facet', 3, function () { + test('facet selection: new value existing facet', {asserts: 3}, function (instance, $s) { var field = { get_domain: openerp.testing.noop, get_context: openerp.testing.noop, @@ -451,10 +420,8 @@ $(document).ready(function () { } }; - var view = makeSearchView({}); - view.appendTo($('#qunit-fixture')) - .always(start) - .fail(function (error) { ok(false, error.message); }) + var view = makeSearchView(instance); + return view.appendTo($s) .done(function () { view.query.add({field: field, category: 'Dummy', values: [{label: 'previous', value: 41}]}); @@ -470,23 +437,19 @@ $(document).ready(function () { "should have added selected value to old one"); }); }); - asyncTest('Field', 1, function () { + test('Field', {asserts: 1}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.Field({attrs: {}}, {}, view); - f.complete('foo') - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete('foo') .done(function (completions) { ok(_(completions).isEmpty(), "field should not provide any completion"); }); }); - asyncTest('CharField', 6, function () { + test('CharField', {asserts: 6}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.CharField( {attrs: {string: "Dummy"}}, {}, view); - f.complete('foo<') - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete('foo<') .done(function (completions) { equal(completions.length, 1, "should provide a single completion"); var c = completions[0]; @@ -503,15 +466,13 @@ $(document).ready(function () { "facet should have single value using completion item"); }); }); - asyncTest('Selection: match found', 14, function () { + test('Selection: match found', {asserts: 14}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.SelectionField( {attrs: {string: "Dummy"}}, {selection: [[1, "Foo"], [2, "Bar"], [3, "Baz"], [4, "Bazador"]]}, view); - f.complete("ba") - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete("ba") .done(function (completions) { equal(completions.length, 4, "should provide two completions and a section title"); @@ -536,20 +497,18 @@ $(document).ready(function () { deepEqual(c3.facet.values, [{label: "Bazador", value: 4}]); }); }); - asyncTest('Selection: no match', 1, function () { + test('Selection: no match', {asserts: 1}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.SelectionField( {attrs: {string: "Dummy"}}, {selection: [[1, "Foo"], [2, "Bar"], [3, "Baz"], [4, "Bazador"]]}, view); - f.complete("qux") - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete("qux") .done(function (completions) { ok(!completions, "if no value matches the needle, no completion shall be provided"); }); }); - asyncTest('Date', 6, function () { + test('Date', {asserts: 6}, function (instance) { instance.web._t.database.parameters = { date_format: '%Y-%m-%d', time_format: '%H:%M:%S' @@ -557,9 +516,7 @@ $(document).ready(function () { var view = {inputs: []}; var f = new instance.web.search.DateField( {attrs: {string: "Dummy"}}, {type: 'datetime'}, view); - f.complete('2012-05-21T21:21:21') - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete('2012-05-21T21:21:21') .done(function (completions) { equal(completions.length, 1, "should provide a single completion"); var c = completions[0]; @@ -573,21 +530,17 @@ $(document).ready(function () { new Date(2012, 4, 21, 21, 21, 21).getTime()); }); }); - asyncTest("M2O", 15, function () { - instance.session.responses['/web/dataset/call_kw'] = function (req) { - equal(req.params.method, "name_search"); - equal(req.params.model, "dummy.model"); - deepEqual(req.params.args, []); - deepEqual(req.params.kwargs.name, 'bob'); - return {result: [[42, "choice 1"], [43, "choice @"]]} - }; + test("M2O", {asserts: 13}, function (instance, $s, mock) { + mock('dummy.model:name_search', function (args, kwargs) { + deepEqual(args, []); + strictEqual(kwargs.name, 'bob'); + return [[42, "choice 1"], [43, "choice @"]]; + }); var view = {inputs: []}; var f = new instance.web.search.ManyToOneField( {attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view); - f.complete("bob") - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete("bob") .done(function (c) { equal(c.length, 3, "should return results + title"); var title = c[0]; @@ -607,38 +560,29 @@ $(document).ready(function () { deepEqual(f2.values.toJSON(), [{label: 'choice @', value: 43}]); }); }); - asyncTest("M2O no match", 5, function () { - instance.session.responses['/web/dataset/call_kw'] = function (req) { - equal(req.params.method, "name_search"); - equal(req.params.model, "dummy.model"); - deepEqual(req.params.args, []); - deepEqual(req.params.kwargs.name, 'bob'); - return {result: []} - }; + test("M2O no match", {asserts: 3}, function (instance, $s, mock) { + mock('dummy.model:name_search', function (args, kwargs) { + deepEqual(args, []); + strictEqual(kwargs.name, 'bob'); + return []; + }); var view = {inputs: []}; var f = new instance.web.search.ManyToOneField( {attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view); - f.complete("bob") - .always(start) - .fail(function (error) { ok(false, error.message); }) + return f.complete("bob") .done(function (c) { ok(!c, "no match should yield no completion"); }); }); - - module('search-serialization', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } - }); - asyncTest('No facet, no call', 6, function () { +}); +openerp.testing.section('search-serialization', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true +}, function (test) { + test('No facet, no call', {asserts: 6}, function (instance, $s) { var got_domain = false, got_context = false, got_groupby = false; - var $fix = $('#qunit-fixture'); - var view = makeSearchView({ + var view = makeSearchView(instance, { get_domain: function () { got_domain = true; return null; @@ -654,11 +598,9 @@ $(document).ready(function () { }); var ds, cs, gs; view.on('search_data', this, function (d, c, g) { - ds = d, cs = c, gs = g; + ds = d; cs = c; gs = g; }); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($s) .done(function () { view.do_search(); ok(!got_domain, "no facet, should not have fetched domain"); @@ -671,10 +613,9 @@ $(document).ready(function () { ok(_(gs).isEmpty(), "groupby list should be empty"); }) }); - asyncTest('London, calling', 8, function () { + test('London, calling', {asserts: 8}, function (instance, $fix) { var got_domain = false, got_context = false, got_groupby = false; - var $fix = $('#qunit-fixture'); - var view = makeSearchView({ + var view = makeSearchView(instance, { get_domain: function (facet) { equal(facet.get('category'), "Dummy"); deepEqual(facet.values.toJSON(), [{label: "42", value: 42}]); @@ -692,11 +633,9 @@ $(document).ready(function () { }, {dummy: 42}); var ds, cs, gs; view.on('search_data', this, function (d, c, g) { - ds = d, cs = c, gs = g; + ds = d; cs = c; gs = g; }); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { view.do_search(); ok(got_domain, "should have fetched domain"); @@ -709,9 +648,8 @@ $(document).ready(function () { ok(_(gs).isEmpty(), "groupby list should be empty"); }) }); - asyncTest('Generate domains', 1, function () { - var $fix = $('#qunit-fixture'); - var view = makeSearchView({ + test('Generate domains', {asserts: 1}, function (instance, $fix) { + var view = makeSearchView(instance, { get_domain: function (facet) { return facet.values.map(function (value) { return ['win', '4', value.get('value')]; @@ -720,9 +658,7 @@ $(document).ready(function () { }, {dummy: 42}); var ds; view.on('search_data', this, function (d) { ds = d; }); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { view.do_search(); deepEqual(ds, [[['win', '4', 42]]], @@ -730,7 +666,9 @@ $(document).ready(function () { }); }); - test('Field single value, default domain & context', function () { + test('Field single value, default domain & context', { + rpc: false + }, function (instance) { var f = new instance.web.search.Field({}, {name: 'foo'}, {inputs: []}); var facet = new instance.web.search.Facet({ field: f, @@ -742,7 +680,9 @@ $(document).ready(function () { equal(f.get_context(facet), null, "default field context is null"); }); - test('Field multiple values, default domain & context', function () { + test('Field multiple values, default domain & context', { + rpc: false + }, function (instance) { var f = new instance.web.search.Field({}, {name: 'foo'}, {inputs: []}); var facet = new instance.web.search.Facet({ field: f, @@ -763,7 +703,9 @@ $(document).ready(function () { equal(f.get_context(facet), null, "default field context is null"); }); - test('Field single value, custom domain & context', function () { + test('Field single value, custom domain & context', { + rpc: false + }, function (instance) { var f = new instance.web.search.Field({attrs:{ context: "{'bob': self}", filter_domain: "[['edmund', 'is', self]]" @@ -793,7 +735,9 @@ $(document).ready(function () { self: "great" }, "evaluation context should hold facet value as self"); }); - test("M2O default", function () { + test("M2O default", { + rpc: false + }, function (instance) { var f = new instance.web.search.ManyToOneField( {}, {name: 'foo'}, {inputs: []}); var facet = new instance.web.search.Facet({ @@ -806,7 +750,9 @@ $(document).ready(function () { deepEqual(f.get_context(facet), {default_foo: 42}, "m2o should use value as context default"); }); - test("M2O default multiple values", function () { + test("M2O default multiple values", { + rpc: false + }, function (instance) { var f = new instance.web.search.ManyToOneField( {}, {name: 'foo'}, {inputs: []}); var facet = new instance.web.search.Facet({ @@ -823,7 +769,9 @@ $(document).ready(function () { equal(f.get_context(facet), null, "m2o should not have default context in case of multiple values"); }); - test("M2O custom operator", function () { + test("M2O custom operator", { + rpc: false + }, function (instance) { var f = new instance.web.search.ManyToOneField( {attrs: {operator: 'boos'}}, {name: 'foo'}, {inputs: []}); var facet = new instance.web.search.Facet({ @@ -836,7 +784,9 @@ $(document).ready(function () { deepEqual(f.get_context(facet), {default_foo: 42}, "m2o should use value as context default"); }); - test("M2O custom domain & context", function () { + test("M2O custom domain & context", { + rpc: false + }, function (instance) { var f = new instance.web.search.ManyToOneField({attrs: { context: "{'whee': self}", filter_domain: "[['filter', 'is', self]]" @@ -862,7 +812,7 @@ $(document).ready(function () { }, "custom context's self should be label"); }); - asyncTest('FilterGroup', 6, function () { + test('FilterGroup', {asserts: 6}, function (instance) { var view = {inputs: [], query: {on: function () {}}}; var filter_a = new instance.web.search.Filter( {attrs: {name: 'a', context: 'c1', domain: 'd1'}}, view); @@ -872,9 +822,7 @@ $(document).ready(function () { {attrs: {name: 'c', context: 'c3', domain: 'd3'}}, view); var group = new instance.web.search.FilterGroup( [filter_a, filter_b, filter_c], view); - group.facet_for_defaults({a: true, c: true}) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return group.facet_for_defaults({a: true, c: true}) .done(function (facet) { var model = facet; if (!(model instanceof instance.web.search.Facet)) { @@ -897,19 +845,14 @@ $(document).ready(function () { ok(!context.get_eval_context(), "context should have no evaluation context"); }); }); - - module('removal', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } - }); - asyncTest('clear button', function () { - var $fix = $('#qunit-fixture'); - var view = makeSearchView({ +}); +openerp.testing.section('removal', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true +}, function (test) { + test('clear button', {asserts: 2}, function (instance, $fix) { + var view = makeSearchView(instance, { facet_for_defaults: function (defaults) { return $.when({ field: this, @@ -918,31 +861,22 @@ $(document).ready(function () { }); } }, {dummy: 42}); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { equal(view.query.length, 1, "view should have default facet"); $fix.find('.oe_searchview_clear').click(); equal(view.query.length, 0, "cleared view should not have any facet"); }); }); - - module('drawer', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } - }); - asyncTest('is-drawn', 2, function () { - var view = makeSearchView(); - var $fix = $('#qunit-fixture'); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) +}); +openerp.testing.section('drawer', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true +}, function (test) { + test('is-drawn', {asserts: 2}, function (instance, $fix) { + var view = makeSearchView(instance); + return view.appendTo($fix) .done(function () { ok($fix.find('.oe_searchview_filters').length, "filters drawer control has been drawn"); @@ -950,50 +884,44 @@ $(document).ready(function () { "filters advanced search has been drawn"); }); }); - - module('filters', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance, { - '/web/searchview/load': function () { - // view with a single group of filters - return {result: {fields_view: { - type: 'search', - fields: {}, - arch: { - tag: 'search', - attrs: {}, - children: [{ - tag: 'filter', - attrs: { string: "Foo1", domain: [ ['foo', '=', '1'] ] }, - children: [] - }, { - tag: 'filter', - attrs: { - name: 'foo2', - string: "Foo2", - domain: [ ['foo', '=', '2'] ] }, - children: [] - }, { - tag: 'filter', - attrs: { string: "Foo3", domain: [ ['foo', '=', '3'] ] }, - children: [] - }] - } - }}}; +}); +openerp.testing.section('filters', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + mock('/web/searchview/load', function () { + // view with a single group of filters + return {fields_view: { + type: 'search', + fields: {}, + arch: { + tag: 'search', + attrs: {}, + children: [{ + tag: 'filter', + attrs: { string: "Foo1", domain: [ ['foo', '=', '1'] ] }, + children: [] + }, { + tag: 'filter', + attrs: { + name: 'foo2', + string: "Foo2", + domain: [ ['foo', '=', '2'] ] }, + children: [] + }, { + tag: 'filter', + attrs: { string: "Foo3", domain: [ ['foo', '=', '3'] ] }, + children: [] + }] } - }); - } - }); - asyncTest('drawn', 3, function () { - var view = makeSearchView(); - var $fix = $('#qunit-fixture'); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + }}; + }); + } +}, function (test) { + test('drawn', {asserts: 3}, function (instance, $fix) { + var view = makeSearchView(instance); + return view.appendTo($fix) .done(function () { var $fs = $fix.find('.oe_searchview_filters ul'); // 3 filters, 1 filtergroup, 1 custom filters widget, @@ -1006,12 +934,9 @@ $(document).ready(function () { "Text content of first filter option should match filter string"); }); }); - asyncTest('click adding from empty query', 4, function () { - var view = makeSearchView(); - var $fix = $('#qunit-fixture'); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + test('click adding from empty query', {asserts: 4}, function (instance, $fix) { + var view = makeSearchView(instance); + return view.appendTo($fix) .done(function () { var $fs = $fix.find('.oe_searchview_filters ul'); $fs.children(':eq(2)').trigger('click'); @@ -1025,12 +950,9 @@ $(document).ready(function () { "value should be third filter"); }); }); - asyncTest('click adding from existing query', 4, function () { - var view = makeSearchView({}, {foo2: true}); - var $fix = $('#qunit-fixture'); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + test('click adding from existing query', {asserts: 4}, function (instance, $fix) { + var view = makeSearchView(instance, {}, {foo2: true}); + return view.appendTo($fix) .done(function () { var $fs = $fix.find('.oe_searchview_filters ul'); $fs.children(':eq(2)').trigger('click'); @@ -1045,16 +967,13 @@ $(document).ready(function () { "second value should be clicked filter"); }); }); - asyncTest('click removing from query', 4, function () { + test('click removing from query', {asserts: 4}, function (instance, $fix) { var calls = 0; - var view = makeSearchView({}, {foo2: true}); + var view = makeSearchView(instance, {}, {foo2: true}); view.on('search_data', null, function () { ++calls; }); - var $fix = $('#qunit-fixture'); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { var $fs = $fix.find('.oe_searchview_filters ul'); // sanity check @@ -1065,29 +984,19 @@ $(document).ready(function () { strictEqual(calls, 1, "one search should have been triggered"); }); }); +}); +openerp.testing.section('saved_filters', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true +}, function (test) { + test('checkboxing', {asserts: 6}, function (instance, $fix, mock) { + var view = makeSearchView(instance); + mock('/web/searchview/get_filters', function () { + return [{ name: "filter name", user_id: 42 }]; + }); - module('saved_filters', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } - }); - asyncTest('checkboxing', 6, function () { - var view = makeSearchView(); - instance.session.responses['/web/searchview/get_filters'] = function () { - return {result: [{ - name: "filter name", - user_id: 42 - }]}; - }; - var $fix = $('#qunit-fixture'); - - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { var $row = $fix.find('.oe_searchview_custom li:first').click(); @@ -1104,44 +1013,31 @@ $(document).ready(function () { "should have no value set"); }) }); - asyncTest('removal', 1, function () { - var view = makeSearchView(); - instance.session.responses['/web/searchview/get_filters'] = function () { - return {result: [{ - name: "filter name", - user_id: 42 - }]}; - }; - var $fix = $('#qunit-fixture'); + test('removal', {asserts: 1}, function (instance, $fix, mock) { + var view = makeSearchView(instance); + mock('/web/searchview/get_filters', function () { + return [{ name: "filter name", user_id: 42 }]; + }); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { var $row = $fix.find('.oe_searchview_custom li:first').click(); view.query.remove(view.query.at(0)); ok(!$row.hasClass('oe_selected'), "should not be checked anymore"); - }) - }); - - module('advanced', { - setup: function () { - instance = openerp.testing.instanceFor('search'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - } + }); }); - asyncTest('single-advanced', 6, function () { - var view = makeSearchView(); - var $fix = $('#qunit-fixture'); - - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) +}); +openerp.testing.section('advanced', { + dependencies: ['web.search'], + rpc: 'mock', + templates: true +}, function (test) { + test('single-advanced', {asserts: 6}, function (instance, $fix) { + var view = makeSearchView(instance); + + return view.appendTo($fix) .done(function () { var $advanced = $fix.find('.oe_searchview_advanced'); // open advanced search (not actually useful) @@ -1174,13 +1070,10 @@ $(document).ready(function () { "advanced search facet should return proposed domain"); }); }); - asyncTest('multiple-advanced', 3, function () { - var view = makeSearchView(); - var $fix = $('#qunit-fixture'); + test('multiple-advanced', {asserts: 3}, function (instance, $fix) { + var view = makeSearchView(instance); - view.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error.message); }) + return view.appendTo($fix) .done(function () { var $advanced = $fix.find('.oe_searchview_advanced'); // open advanced search (not actually useful) diff --git a/addons/web/static/test/test.html b/addons/web/static/test/test.html deleted file mode 100644 index 185125659cc..00000000000 --- a/addons/web/static/test/test.html +++ /dev/null @@ -1,62 +0,0 @@ -<!DOCTYPE html> -<html style="height: 100%"> -<head> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <title>OpenERP Web Test Suite</title> - <link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/> - - <link rel="stylesheet" href="/web/static/lib/qunit/qunit.css"> - <script src="/web/static/lib/qunit/qunit.js" type="text/javascript"></script> - - <script src="/web/static/lib/underscore/underscore.js" type="text/javascript"></script> - <script src="/web/static/lib/underscore/underscore.string.js" type="text/javascript"></script> - <script src="/web/static/lib/backbone/backbone.js" type="text/javascript"></script> - - <!-- jquery --> - <script src="/web/static/lib/jquery/jquery-1.8.2.js"></script> - <script src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script> - <script src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script> - - <script src="/web/static/lib/datejs/globalization/en-US.js"></script> - <script src="/web/static/lib/datejs/core.js"></script> - <script src="/web/static/lib/datejs/parser.js"></script> - <script src="/web/static/lib/datejs/sugarpak.js"></script> - <script src="/web/static/lib/datejs/extras.js"></script> - - <script src="/web/static/lib/qweb/qweb2.js"></script> - - <script src="/web/static/lib/py.js/lib/py.js"></script> - - <script src="/web/static/src/js/boot.js"></script> - <script src="/web/static/src/js/corelib.js"></script> - <script src="/web/static/src/js/coresetup.js"></script> - <script src="/web/static/src/js/dates.js"></script> - <script src="/web/static/src/js/formats.js"></script> - <script src="/web/static/src/js/chrome.js"></script> - <script src="/web/static/src/js/data.js"></script> - <script src="/web/static/src/js/views.js"></script> - <script src="/web/static/src/js/search.js"></script> - <script src="/web/static/src/js/view_form.js"></script> - <script src="/web/static/src/js/view_list.js"></script> - <script src="/web/static/src/js/view_list_editable.js"></script> - - <script src="/web/static/test/testing.js"></script> - <script type="text/javascript"> - QUnit.config.testTimeout = 2000; - </script> -</head> - <body id="oe" class="openerp"> - <div id="qunit"></div> - <div id="qunit-fixture"></div> - </body> - <script type="text/javascript" src="/web/static/test/class.js"></script> - <script type="text/javascript" src="/web/static/test/registry.js"></script> - <script type="text/javascript" src="/web/static/test/form.js"></script> - <script type="text/javascript" src="/web/static/test/list-utils.js"></script> - <script type="text/javascript" src="/web/static/test/formats.js"></script> - <script type="text/javascript" src="/web/static/test/rpc.js"></script> - <script type="text/javascript" src="/web/static/test/evals.js"></script> - <script type="text/javascript" src="/web/static/test/search.js"></script> - <script type="text/javascript" src="/web/static/test/Widget.js"></script> - <script type="text/javascript" src="/web/static/test/list-editable.js"></script> -</html> diff --git a/addons/web/static/test/testing.js b/addons/web/static/test/testing.js index 1be8e94e74b..5bd008ad7ec 100644 --- a/addons/web/static/test/testing.js +++ b/addons/web/static/test/testing.js @@ -1,97 +1,244 @@ -// Test support structures and methods for OpenERP -openerp.testing = (function () { - var xhr = QWeb2.Engine.prototype.get_xhr(); - xhr.open('GET', '/web/static/src/xml/base.xml', false); - xhr.send(null); - var doc = xhr.responseXML; - - var dependencies = { - corelib: [], - coresetup: ['corelib'], - data: ['corelib', 'coresetup'], - dates: [], - formats: ['coresetup', 'dates'], - chrome: ['corelib', 'coresetup'], - views: ['corelib', 'coresetup', 'data', 'chrome'], - search: ['data', 'coresetup', 'formats'], - list: ['views', 'data'], - form: ['data', 'views', 'list', 'formats'], - list_editable: ['list', 'form', 'data'], +openerp.testing.section('testing.stack', function (test) { + // I heard you like tests, so I put tests in your testing infrastructure, + // so you can test what you test + var reject = function () { + // utility function, rejects a success + var args = _.toArray(arguments); + return $.Deferred(function (d) { + d.reject.apply(d, ["unexpected success"].concat(args)); + }); }; + test('direct, value, success', {asserts: 1}, function () { + var s = openerp.testing.Stack(); + return s.execute(function () { + return 42; + }).then(function (val) { + strictEqual(val, 42, "should return the handler value"); + }); + }); + test('direct, deferred, success', {asserts: 1}, function () { + var s = openerp.testing.Stack(); + return s.execute(function () { + return $.when(42); + }).then(function (val) { + strictEqual(val, 42, "should return the handler value") + }); + }); + test('direct, deferred, failure', {asserts: 1}, function () { + var s = openerp.testing.Stack(); + return s.execute(function () { + return $.Deferred(function (d) { + d.reject("failed"); + }); + }).then(reject, function (f) { + strictEqual(f, "failed", "should propagate failure"); + return $.when(); + }); + }); + + test('successful setup', {asserts: 2}, function () { + var setup_done = false; + var s = openerp.testing.Stack(); + return s.push(function () { + return $.Deferred(function (d) { + setTimeout(function () { + setup_done = true; + d.resolve(2); + }, 50); + }); + }).execute(function () { + return 42; + }).then(function (val) { + ok(setup_done, "should have executed setup"); + strictEqual(val, 42, "should return executed function value (not setup)"); + }); + }); + test('successful teardown', {asserts: 2}, function () { + var teardown = false; + var s = openerp.testing.Stack(); + return s.push(null, function () { + return $.Deferred(function (d) { + setTimeout(function () { + teardown = true; + d.resolve(2); + }, 50); + }); + }).execute(function () { + return 42; + }).then(function (val) { + ok(teardown, "should have executed teardown"); + strictEqual(val, 42, "should return executed function value (not setup)"); + }); + }); + test('successful setup and teardown', {asserts: 3}, function () { + var setup = false, teardown = false; + var s = openerp.testing.Stack(); + return s.push(function () { + return $.Deferred(function (d) { + setTimeout(function () { + setup = true; + d.resolve(2); + }, 50); + }); + }, function () { + return $.Deferred(function (d) { + setTimeout(function () { + teardown = true; + d.resolve(2); + }, 50); + }); + }).execute(function () { + return 42; + }).then(function (val) { + ok(setup, "should have executed setup"); + ok(teardown, "should have executed teardown"); + strictEqual(val, 42, "should return executed function value (not setup)"); + }); + }); + + test('multiple setups', {asserts: 2}, function () { + var setups = 0; + var s = openerp.testing.Stack(); + return s.push(function () { + setups++; + }).push(function () { + setups++; + }).push(function () { + setups++; + }).push(function () { + setups++; + }).execute(function () { + return 42; + }).then(function (val) { + strictEqual(setups, 4, "should have executed all setups of stack"); + strictEqual(val, 42); + }); + }); + test('multiple teardowns', {asserts: 2}, function () { + var teardowns = 0; + var s = openerp.testing.Stack(); + return s.push(null, function () { + teardowns++; + }).push(null, function () { + teardowns++; + }).push(null, function () { + teardowns++; + }).push(null, function () { + teardowns++; + }).execute(function () { + return 42; + }).then(function (val) { + strictEqual(teardowns, 4, "should have executed all teardowns of stack"); + strictEqual(val, 42); + }); + }); + test('holes in setups', {asserts: 2}, function () { + var setups = []; + var s = openerp.testing.Stack(); + return s.push(function () { + setups.push(0); + }).push().push().push(function () { + setups.push(3); + }).push(function () { + setups.push(4); + }).push().push(function () { + setups.push(6); + }).execute(function () { + return 42; + }).then(function (val) { + deepEqual(setups, [0, 3, 4, 6], + "should have executed setups in correct order"); + strictEqual(val, 42); + }); + }); + test('holes in teardowns', {asserts: 2}, function () { + var teardowns = []; + var s = openerp.testing.Stack(); + return s.push(null, function () { + teardowns.push(0); + }).push().push().push(null, function () { + teardowns.push(3); + }).push(null, function () { + teardowns.push(4); + }).push().push(null, function () { + teardowns.push(6); + }).execute(function () { + return 42; + }).then(function (val) { + deepEqual(teardowns, [6, 4, 3, 0], + "should have executed teardowns in correct order"); + strictEqual(val, 42); + }); - return { - /** - * Function which does not do anything - */ - noop: function () { }, - /** - * Loads 'base.xml' template file into qweb for the provided instance - * - * @param instance openerp instance being initialized, to load the template file in - */ - loadTemplate: function (instance) { - instance.web.qweb.add_template(doc); - }, - /** - * Alter provided instance's ``session`` attribute to make response - * mockable: - * - * * The ``responses`` parameter can be used to provide a map of (RPC) - * paths (e.g. ``/web/view/load``) to a function returning a response - * to the query. - * * ``instance.session`` grows a ``responses`` attribute which is - * a map of the same (and is in fact initialized to the ``responses`` - * parameter if one is provided) - * - * Note that RPC requests to un-mocked URLs will be rejected with an - * error message: only explicitly specified urls will get a response. - * - * Mocked sessions will *never* perform an actual RPC connection. - * - * @param instance openerp instance being initialized - * @param {Object} [responses] - */ - mockifyRPC: function (instance, responses) { - var session = instance.session; - session.responses = responses || {}; - session.rpc_function = function (url, payload) { - var fn = this.responses[url.url + ':' + payload.params.method] - || this.responses[url.url]; + }); - if (!fn) { - return $.Deferred().reject({}, 'failed', - _.str.sprintf("Url %s not found in mock responses, with arguments %s", - url.url, JSON.stringify(payload.params)) - ).promise(); - } - return $.when(fn(payload)); - }; - }, - /** - * Creates an openerp web instance loading the specified module after - * all of its dependencies. - * - * @param {String} module - * @returns OpenERP Web instance - */ - instanceFor: function (module) { - var instance = openerp.init([]); - this._load(instance, module); - return instance; - }, - _load: function (instance, module, loaded) { - if (!loaded) { loaded = []; } + test('failed setup', {asserts: 5}, function () { + var setup, teardown, teardown2, code; + return openerp.testing.Stack().push(function () { + setup = true; + }, function () { + teardown = true; + }).push(function () { + return $.Deferred().reject("Fail!"); + }, function () { + teardown2 = true; + }).execute(function () { + code = true; + return 42; + }).then(reject, function (m) { + ok(setup, "should have executed first setup function"); + ok(teardown, "should have executed first teardown function"); + ok(!teardown2, "should not have executed second teardown function"); + strictEqual(m, "Fail!", "should return setup failure message"); + ok(!code, "should not have executed callback"); + return $.when(); + }); + }); + test('failed teardown', {asserts: 2}, function () { + var teardowns = 0; + return openerp.testing.Stack().push(null, function () { + teardowns++; + return $.Deferred().reject('Fail 1'); + }).push(null, function () { + teardowns++; + }).push(null, function () { + teardowns++; + return $.Deferred().reject('Fail 3'); + }).execute(function () { + return 42; + }).then(reject, function (m) { + strictEqual(teardowns, 3, + "should have tried executing all teardowns"); + strictEqual(m, "Fail 3", "should return first failure message"); + return $.when(); + }); + }); + test('failed call + teardown', {asserts: 2}, function () { + var teardowns = 0; + return openerp.testing.Stack().push(null, function () { + teardowns++; + }).push(null, function () { + teardowns++; + return $.Deferred().reject('Fail 2'); + }).execute(function () { + return $.Deferred().reject("code"); + }).then(reject, function (m) { + strictEqual(teardowns, 2, + "should have tried executing all teardowns"); + strictEqual(m, "code", "should return first failure message"); + return $.when(); + }); + }); - var deps = dependencies[module]; - if (!deps) { throw new Error("Unknown dependencies for " + module); } + test('arguments passing', {asserts: 9}, function () { + var asserter = function (a, b, c) { + strictEqual(a, 1); + strictEqual(b, "foo"); + deepEqual(c, {bar: "baz", qux: 42}); + }; - var to_load = _.difference(deps, loaded); - while (!_.isEmpty(to_load)) { - this._load(instance, to_load[0], loaded); - to_load = _.difference(deps, loaded); - } - openerp.web[module](instance); - loaded.push(module); - } - } -})(); + return openerp.testing.Stack() + .push(asserter, asserter) + .execute(asserter, 1, "foo", {bar: 'baz', qux: 42}); + }); +}); diff --git a/addons/web/test_support/__init__.py b/addons/web/test_support/__init__.py deleted file mode 100644 index 59f6cc67ca2..00000000000 --- a/addons/web/test_support/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -import xmlrpclib -from ..common.openerplib.main import Connector - -execute_map = {} - -class TestConnector(Connector): - def db_list_lang(self): - return [('en_US', u'Test Language')] - - def common_authenticate(self, db, login, password, environment): - return 87539319 - - def common_login(self, db, login, password): - return self.common_authenticate(db, login, password, {}) - - def object_execute_kw(self, db, uid, password, model, method, args, kwargs): - if model in execute_map and hasattr(execute_map[model], method): - return getattr(execute_map[model], method)(*args, **kwargs) - - raise xmlrpclib.Fault({ - 'model': model, - 'method': method, - 'args': args, - 'kwargs': kwargs - }, '') - - def send(self, service_name, method, *args): - method_name = '%s_%s' % (service_name, method) - if hasattr(self, method_name): - return getattr(self, method_name)(*args) - - raise xmlrpclib.Fault({ - 'service': service_name, - 'method': method, - 'args': args - }, '') diff --git a/addons/web/test_support/controllers.py b/addons/web/test_support/controllers.py deleted file mode 100644 index f1013fbaaf8..00000000000 --- a/addons/web/test_support/controllers.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -from ..common import http, nonliterals -from ..controllers.main import Session - -UID = 87539319 -DB = 'test_db' -LOGIN = 'test_login' -PASSWORD = 'test_password' -CONTEXT = {'lang': 'en_US', 'tz': 'UTC', 'uid': UID} - -def bind(session): - session.bind(DB, UID, LOGIN, PASSWORD) - session.context = CONTEXT - session.build_connection().set_login_info(DB, LOGIN, PASSWORD, UID) - -class TestController(http.Controller): - _cp_path = '/tests' - - @http.jsonrequest - def add_nonliterals(self, req, domains, contexts): - return { - 'domains': [nonliterals.Domain(req.session, domain) - for domain in domains], - 'contexts': [nonliterals.Context(req.session, context) - for context in contexts] - } - -class TestSession(Session): - _cp_path = '/web/session' - - def session_info(self, req): - if not req.session._uid: - bind(req.session) - - return { - "session_id": req.session_id, - "uid": req.session._uid, - "context": CONTEXT, - "db": req.session._db, - "login": req.session._login, - } diff --git a/addons/web/tests/__init__.py b/addons/web/tests/__init__.py index fb1a593bc78..8cb2118e0b6 100644 --- a/addons/web/tests/__init__.py +++ b/addons/web/tests/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from . import test_dataset, test_menu, test_serving_base, test_view +from . import test_dataset, test_menu, test_serving_base, test_view, test_js fast_suite = [] checks = [ diff --git a/addons/web/tests/test_js.py b/addons/web/tests/test_js.py new file mode 100644 index 00000000000..a126ce4b2f3 --- /dev/null +++ b/addons/web/tests/test_js.py @@ -0,0 +1,25 @@ +import urlparse +from openerp import sql_db, tools +from qunitsuite.suite import QUnitSuite + +class WebSuite(QUnitSuite): + def __init__(self): + url = urlparse.urlunsplit([ + 'http', + 'localhost:{port}'.format(port=tools.config['xmlrpc_port']), + '/web/tests', + 'mod=*&source={db}&supadmin={supadmin}&password={password}'.format( + db=tools.config['db_name'], + supadmin=tools.config['db_password'] or 'admin', + password=tools.config['admin_passwd'] or 'admin'), + '' + ]) + super(WebSuite, self).__init__(url, 50000) + def run(self, result): + if sql_db._Pool is not None: + sql_db._Pool.close_all(sql_db.dsn(tools.config['db_name'])) + return super(WebSuite, self).run(result) + +def load_tests(loader, standard_tests, _): + standard_tests.addTest(WebSuite()) + return standard_tests diff --git a/addons/web_calendar/i18n/ar.po b/addons/web_calendar/i18n/ar.po index ab2b44e8c0f..f9241ca23d3 100644 --- a/addons/web_calendar/i18n/ar.po +++ b/addons/web_calendar/i18n/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/bg.po b/addons/web_calendar/i18n/bg.po index 1efca8799a5..3fb494c8f3f 100644 --- a/addons/web_calendar/i18n/bg.po +++ b/addons/web_calendar/i18n/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/bn.po b/addons/web_calendar/i18n/bn.po index cf1540dcfc8..a520f497700 100644 --- a/addons/web_calendar/i18n/bn.po +++ b/addons/web_calendar/i18n/bn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/bs.po b/addons/web_calendar/i18n/bs.po index 86271e95cf3..5c36cf3c0cc 100644 --- a/addons/web_calendar/i18n/bs.po +++ b/addons/web_calendar/i18n/bs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/ca.po b/addons/web_calendar/i18n/ca.po index 72d9ef16031..af2d7ea63a4 100644 --- a/addons/web_calendar/i18n/ca.po +++ b/addons/web_calendar/i18n/ca.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/cs.po b/addons/web_calendar/i18n/cs.po index 66bc1beb88c..5ac3d5d34b3 100644 --- a/addons/web_calendar/i18n/cs.po +++ b/addons/web_calendar/i18n/cs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" "X-Poedit-Language: Czech\n" #. openerp-web diff --git a/addons/web_calendar/i18n/da.po b/addons/web_calendar/i18n/da.po index 3e4b334c4c8..aefa989ec61 100644 --- a/addons/web_calendar/i18n/da.po +++ b/addons/web_calendar/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/de.po b/addons/web_calendar/i18n/de.po index df4a364ff1a..384635c1f49 100644 --- a/addons/web_calendar/i18n/de.po +++ b/addons/web_calendar/i18n/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/en_AU.po b/addons/web_calendar/i18n/en_AU.po index b4e653989a7..a06c829d2a8 100644 --- a/addons/web_calendar/i18n/en_AU.po +++ b/addons/web_calendar/i18n/en_AU.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/en_GB.po b/addons/web_calendar/i18n/en_GB.po index 1c4d71479d2..220c92d2e4c 100644 --- a/addons/web_calendar/i18n/en_GB.po +++ b/addons/web_calendar/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/es.po b/addons/web_calendar/i18n/es.po index c475d7c85ab..5c8764d16e9 100644 --- a/addons/web_calendar/i18n/es.po +++ b/addons/web_calendar/i18n/es.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/es_CL.po b/addons/web_calendar/i18n/es_CL.po index ddc28ac04e8..ed465fa1f9f 100644 --- a/addons/web_calendar/i18n/es_CL.po +++ b/addons/web_calendar/i18n/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/es_CR.po b/addons/web_calendar/i18n/es_CR.po index 22123fbf838..aa3315ad9ab 100644 --- a/addons/web_calendar/i18n/es_CR.po +++ b/addons/web_calendar/i18n/es_CR.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" "Language: es\n" #. openerp-web diff --git a/addons/web_calendar/i18n/es_EC.po b/addons/web_calendar/i18n/es_EC.po index 0333a6ac721..120e1181970 100644 --- a/addons/web_calendar/i18n/es_EC.po +++ b/addons/web_calendar/i18n/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/et.po b/addons/web_calendar/i18n/et.po index b51b759e47b..a6aa0042572 100644 --- a/addons/web_calendar/i18n/et.po +++ b/addons/web_calendar/i18n/et.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/eu.po b/addons/web_calendar/i18n/eu.po index fb4ed997f5d..dbce60de184 100644 --- a/addons/web_calendar/i18n/eu.po +++ b/addons/web_calendar/i18n/eu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/fa.po b/addons/web_calendar/i18n/fa.po index b0120f3ef10..d7c0d87a872 100644 --- a/addons/web_calendar/i18n/fa.po +++ b/addons/web_calendar/i18n/fa.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/fi.po b/addons/web_calendar/i18n/fi.po index 01732824cb6..7f9a8163010 100644 --- a/addons/web_calendar/i18n/fi.po +++ b/addons/web_calendar/i18n/fi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/fr.po b/addons/web_calendar/i18n/fr.po index de9875e1eb1..1c11cfc675a 100644 --- a/addons/web_calendar/i18n/fr.po +++ b/addons/web_calendar/i18n/fr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/fr_CA.po b/addons/web_calendar/i18n/fr_CA.po index 97f3f6cba13..4397816f032 100644 --- a/addons/web_calendar/i18n/fr_CA.po +++ b/addons/web_calendar/i18n/fr_CA.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/gl.po b/addons/web_calendar/i18n/gl.po index f6990a15bcd..1bbf185bdc2 100644 --- a/addons/web_calendar/i18n/gl.po +++ b/addons/web_calendar/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/gu.po b/addons/web_calendar/i18n/gu.po new file mode 100644 index 00000000000..65e20902cf5 --- /dev/null +++ b/addons/web_calendar/i18n/gu.po @@ -0,0 +1,141 @@ +# Gujarati translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2012-07-02 09:06+0200\n" +"PO-Revision-Date: 2012-11-17 12:42+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: Gujarati <gu@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n" +"X-Generator: Launchpad (build 16278)\n" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:11 +msgid "Calendar" +msgstr "કૅલેન્ડર" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:70 +msgid "Filter" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:144 +msgid "Today" +msgstr "આજે" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:145 +msgid "Day" +msgstr "દિવસ" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:146 +msgid "Week" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:147 +msgid "Month" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:148 +msgid "New event" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:149 +msgid "Save" +msgstr "સંગ્રહો" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:150 +msgid "Cancel" +msgstr "રદ કરો" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:151 +msgid "Details" +msgstr "વિગતો" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:152 +msgid "Edit" +msgstr "ફેરફાર કરો" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:153 +msgid "Delete" +msgstr "કાઢી નાંખો" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:155 +msgid "Event will be deleted permanently, are you sure?" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:156 +#: addons/web_calendar/static/src/js/calendar.js:169 +msgid "Description" +msgstr "વર્ણન" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:157 +msgid "Time period" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:158 +msgid "Full day" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:161 +msgid "Do you want to edit the whole set of repeated events?" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:162 +msgid "Repeat event" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:163 +msgid "Disabled" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:164 +msgid "Enabled" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:167 +#: addons/web_calendar/static/src/js/calendar.js:175 +msgid "Agenda" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:168 +msgid "Date" +msgstr "તારીખ" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:172 +msgid "Year" +msgstr "વર્ષ" + +#. openerp-web +#: addons/web_calendar/static/src/xml/web_calendar.xml:5 +#: addons/web_calendar/static/src/xml/web_calendar.xml:6 +msgid " " +msgstr " " diff --git a/addons/web_calendar/i18n/hr.po b/addons/web_calendar/i18n/hr.po index 3c50d92c7d6..420a7eb1c33 100644 --- a/addons/web_calendar/i18n/hr.po +++ b/addons/web_calendar/i18n/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/hu.po b/addons/web_calendar/i18n/hu.po index 97ff16d5b51..a7711c4020a 100644 --- a/addons/web_calendar/i18n/hu.po +++ b/addons/web_calendar/i18n/hu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/id.po b/addons/web_calendar/i18n/id.po index d1525772a40..e6de231635a 100644 --- a/addons/web_calendar/i18n/id.po +++ b/addons/web_calendar/i18n/id.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/it.po b/addons/web_calendar/i18n/it.po index 28758fc6086..a857dee48f8 100644 --- a/addons/web_calendar/i18n/it.po +++ b/addons/web_calendar/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/ja.po b/addons/web_calendar/i18n/ja.po index b13351a6d0e..65e1890e1c7 100644 --- a/addons/web_calendar/i18n/ja.po +++ b/addons/web_calendar/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/ka.po b/addons/web_calendar/i18n/ka.po index 71f560182fc..c6639155ad4 100644 --- a/addons/web_calendar/i18n/ka.po +++ b/addons/web_calendar/i18n/ka.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/lt.po b/addons/web_calendar/i18n/lt.po index b506033dd29..de38e7437c7 100644 --- a/addons/web_calendar/i18n/lt.po +++ b/addons/web_calendar/i18n/lt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/mk.po b/addons/web_calendar/i18n/mk.po index f6121903251..83616520f79 100644 --- a/addons/web_calendar/i18n/mk.po +++ b/addons/web_calendar/i18n/mk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/mn.po b/addons/web_calendar/i18n/mn.po index 5dbfd1146c5..f12b785fee7 100644 --- a/addons/web_calendar/i18n/mn.po +++ b/addons/web_calendar/i18n/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/nb.po b/addons/web_calendar/i18n/nb.po index 1bfd031fdca..151abb46415 100644 --- a/addons/web_calendar/i18n/nb.po +++ b/addons/web_calendar/i18n/nb.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/nl.po b/addons/web_calendar/i18n/nl.po index f85a54d90a8..855f44d7ec8 100644 --- a/addons/web_calendar/i18n/nl.po +++ b/addons/web_calendar/i18n/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/nl_BE.po b/addons/web_calendar/i18n/nl_BE.po index 25fc24a3121..6420eb49047 100644 --- a/addons/web_calendar/i18n/nl_BE.po +++ b/addons/web_calendar/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/pl.po b/addons/web_calendar/i18n/pl.po index 75d984ec95a..53066f91e89 100644 --- a/addons/web_calendar/i18n/pl.po +++ b/addons/web_calendar/i18n/pl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/pt.po b/addons/web_calendar/i18n/pt.po index 316e2886ebf..8c5762714de 100644 --- a/addons/web_calendar/i18n/pt.po +++ b/addons/web_calendar/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/pt_BR.po b/addons/web_calendar/i18n/pt_BR.po index fd1c6800f69..075f9c3cc52 100644 --- a/addons/web_calendar/i18n/pt_BR.po +++ b/addons/web_calendar/i18n/pt_BR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/ro.po b/addons/web_calendar/i18n/ro.po index f2be8570780..0b1be890e7e 100644 --- a/addons/web_calendar/i18n/ro.po +++ b/addons/web_calendar/i18n/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/ru.po b/addons/web_calendar/i18n/ru.po index c286c58bf1a..3f9cccf8b21 100644 --- a/addons/web_calendar/i18n/ru.po +++ b/addons/web_calendar/i18n/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-24 05:20+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/sk.po b/addons/web_calendar/i18n/sk.po index 10eaa327715..ccc7f62c3a3 100644 --- a/addons/web_calendar/i18n/sk.po +++ b/addons/web_calendar/i18n/sk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/sl.po b/addons/web_calendar/i18n/sl.po index 550fafc22d4..0dce08c77f4 100644 --- a/addons/web_calendar/i18n/sl.po +++ b/addons/web_calendar/i18n/sl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-02 05:20+0000\n" -"X-Generator: Launchpad (build 16218)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/sq.po b/addons/web_calendar/i18n/sq.po index 6dc15299697..a53cf945075 100644 --- a/addons/web_calendar/i18n/sq.po +++ b/addons/web_calendar/i18n/sq.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/sr@latin.po b/addons/web_calendar/i18n/sr@latin.po index d798c8d29c0..d5229958f93 100644 --- a/addons/web_calendar/i18n/sr@latin.po +++ b/addons/web_calendar/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/sv.po b/addons/web_calendar/i18n/sv.po index e6e72691141..fee033889cc 100644 --- a/addons/web_calendar/i18n/sv.po +++ b/addons/web_calendar/i18n/sv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/tr.po b/addons/web_calendar/i18n/tr.po index d429fbde854..0b06085aed8 100644 --- a/addons/web_calendar/i18n/tr.po +++ b/addons/web_calendar/i18n/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/uk.po b/addons/web_calendar/i18n/uk.po index 8ae70eb2f77..4f8c91ed43f 100644 --- a/addons/web_calendar/i18n/uk.po +++ b/addons/web_calendar/i18n/uk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/i18n/zh_CN.po b/addons/web_calendar/i18n/zh_CN.po index 134091e9d64..eda04768775 100644 --- a/addons/web_calendar/i18n/zh_CN.po +++ b/addons/web_calendar/i18n/zh_CN.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 51bce57f7cd..30b14c32749 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -2,6 +2,22 @@ * OpenERP web_calendar *---------------------------------------------------------*/ +(function() { + // Monkey patch dhtml scheduler in order to fix a bug. + // It manually implements some kind of dbl click event + // bubbling but fails to do it properly. + if (this.scheduler) { + var old_scheduler_dblclick = scheduler._on_dbl_click; + scheduler._on_dbl_click = function(e, src) { + if (src && !src.className) { + return; + } else { + old_scheduler_dblclick.apply(this, arguments); + } + }; + } +}()); + openerp.web_calendar = function(instance) { var _t = instance.web._t, _lt = instance.web._lt; @@ -219,7 +235,6 @@ instance.web_calendar.CalendarView = instance.web.View.extend({ if (!date.between(this.range_start, this.range_stop)) { this.update_range_dates(date); this.ranged_search(); - this.$el.find(".dhx_cal_navline div").removeAttr('style'); } this.ready.resolve(); }, diff --git a/addons/web_diagram/i18n/ar.po b/addons/web_diagram/i18n/ar.po index b2854ec93c6..4830e2a9572 100644 --- a/addons/web_diagram/i18n/ar.po +++ b/addons/web_diagram/i18n/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/bg.po b/addons/web_diagram/i18n/bg.po index cd73e4d4628..bbe9d04d00f 100644 --- a/addons/web_diagram/i18n/bg.po +++ b/addons/web_diagram/i18n/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/bn.po b/addons/web_diagram/i18n/bn.po index cb8d8b712c4..7af98d96e18 100644 --- a/addons/web_diagram/i18n/bn.po +++ b/addons/web_diagram/i18n/bn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/bs.po b/addons/web_diagram/i18n/bs.po index 78b776e129d..b2173f2d278 100644 --- a/addons/web_diagram/i18n/bs.po +++ b/addons/web_diagram/i18n/bs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/ca.po b/addons/web_diagram/i18n/ca.po index f835a46149c..980bb73c187 100644 --- a/addons/web_diagram/i18n/ca.po +++ b/addons/web_diagram/i18n/ca.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/cs.po b/addons/web_diagram/i18n/cs.po index 59b05ca204c..e2beae2bc3e 100644 --- a/addons/web_diagram/i18n/cs.po +++ b/addons/web_diagram/i18n/cs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" "X-Poedit-Language: Czech\n" #. openerp-web diff --git a/addons/web_diagram/i18n/da.po b/addons/web_diagram/i18n/da.po index 38cc3c33f5a..99d6694387e 100644 --- a/addons/web_diagram/i18n/da.po +++ b/addons/web_diagram/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/de.po b/addons/web_diagram/i18n/de.po index 0572c893571..02f01c0a298 100644 --- a/addons/web_diagram/i18n/de.po +++ b/addons/web_diagram/i18n/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/en_GB.po b/addons/web_diagram/i18n/en_GB.po index 9a1de1ff09a..f45a36ebfec 100644 --- a/addons/web_diagram/i18n/en_GB.po +++ b/addons/web_diagram/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/es.po b/addons/web_diagram/i18n/es.po index 57bee045a52..1127f66ac32 100644 --- a/addons/web_diagram/i18n/es.po +++ b/addons/web_diagram/i18n/es.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/es_CL.po b/addons/web_diagram/i18n/es_CL.po index ca18b98d811..0cd2218ad58 100644 --- a/addons/web_diagram/i18n/es_CL.po +++ b/addons/web_diagram/i18n/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/es_CR.po b/addons/web_diagram/i18n/es_CR.po index cb952c8d76d..853ed64e10c 100644 --- a/addons/web_diagram/i18n/es_CR.po +++ b/addons/web_diagram/i18n/es_CR.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" "Language: es\n" #. openerp-web diff --git a/addons/web_diagram/i18n/es_EC.po b/addons/web_diagram/i18n/es_EC.po index 64122e572d9..9d12b54ad84 100644 --- a/addons/web_diagram/i18n/es_EC.po +++ b/addons/web_diagram/i18n/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/et.po b/addons/web_diagram/i18n/et.po index 3b16af5630b..a91455e4f4c 100644 --- a/addons/web_diagram/i18n/et.po +++ b/addons/web_diagram/i18n/et.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/fa.po b/addons/web_diagram/i18n/fa.po index cf23a8270ef..5e11f131796 100644 --- a/addons/web_diagram/i18n/fa.po +++ b/addons/web_diagram/i18n/fa.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/fi.po b/addons/web_diagram/i18n/fi.po index 43dd28e6408..313dc4df75a 100644 --- a/addons/web_diagram/i18n/fi.po +++ b/addons/web_diagram/i18n/fi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/fr.po b/addons/web_diagram/i18n/fr.po index 775b01c4c79..28555736c81 100644 --- a/addons/web_diagram/i18n/fr.po +++ b/addons/web_diagram/i18n/fr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/gl.po b/addons/web_diagram/i18n/gl.po index c4db0075c79..c09f8dcf150 100644 --- a/addons/web_diagram/i18n/gl.po +++ b/addons/web_diagram/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/gu.po b/addons/web_diagram/i18n/gu.po new file mode 100644 index 00000000000..dac8f061956 --- /dev/null +++ b/addons/web_diagram/i18n/gu.po @@ -0,0 +1,74 @@ +# Gujarati translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2012-07-02 09:06+0200\n" +"PO-Revision-Date: 2012-11-17 11:58+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: Gujarati <gu@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n" +"X-Generator: Launchpad (build 16278)\n" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:11 +msgid "Diagram" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:165 +msgid "Are you sure?" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:195 +msgid "" +"Deleting this node cannot be undone.\n" +"It will also delete all connected transitions.\n" +"\n" +"Are you sure ?" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:213 +msgid "" +"Deleting this transition cannot be undone.\n" +"\n" +"Are you sure ?" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:224 +#: addons/web_diagram/static/src/js/diagram.js:257 +msgid "Activity" +msgstr "પ્રવૃત્તિ" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:232 +#: addons/web_diagram/static/src/js/diagram.js:296 +msgid "Open: " +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:262 +#: addons/web_diagram/static/src/js/diagram.js:314 +msgid "Create:" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:289 +#: addons/web_diagram/static/src/js/diagram.js:308 +msgid "Transition" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/xml/base_diagram.xml:6 +msgid "New Node" +msgstr "" diff --git a/addons/web_diagram/i18n/hr.po b/addons/web_diagram/i18n/hr.po index 416c3465db6..b2ecdefe05c 100644 --- a/addons/web_diagram/i18n/hr.po +++ b/addons/web_diagram/i18n/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/id.po b/addons/web_diagram/i18n/id.po index 2754693c6ac..ad64db2b7dc 100644 --- a/addons/web_diagram/i18n/id.po +++ b/addons/web_diagram/i18n/id.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/it.po b/addons/web_diagram/i18n/it.po index 6d0de20c705..d61a1bed790 100644 --- a/addons/web_diagram/i18n/it.po +++ b/addons/web_diagram/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/ja.po b/addons/web_diagram/i18n/ja.po index ec31f0d22a0..df4aa38e9b4 100644 --- a/addons/web_diagram/i18n/ja.po +++ b/addons/web_diagram/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/ka.po b/addons/web_diagram/i18n/ka.po index fd549ad47b6..23fe83c5ede 100644 --- a/addons/web_diagram/i18n/ka.po +++ b/addons/web_diagram/i18n/ka.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/lt.po b/addons/web_diagram/i18n/lt.po index 0d7eb1b2f38..69e24c3d916 100644 --- a/addons/web_diagram/i18n/lt.po +++ b/addons/web_diagram/i18n/lt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/mn.po b/addons/web_diagram/i18n/mn.po index 538bd4086ad..5f8eae9ae47 100644 --- a/addons/web_diagram/i18n/mn.po +++ b/addons/web_diagram/i18n/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/nl.po b/addons/web_diagram/i18n/nl.po index f04fa3d2ad7..601d2bde471 100644 --- a/addons/web_diagram/i18n/nl.po +++ b/addons/web_diagram/i18n/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/nl_BE.po b/addons/web_diagram/i18n/nl_BE.po index e612f2989b1..4b46f5eb164 100644 --- a/addons/web_diagram/i18n/nl_BE.po +++ b/addons/web_diagram/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/pl.po b/addons/web_diagram/i18n/pl.po index 1050e73f775..0c6a4a21b1e 100644 --- a/addons/web_diagram/i18n/pl.po +++ b/addons/web_diagram/i18n/pl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/pt.po b/addons/web_diagram/i18n/pt.po index e666dd56ae0..838ac158e93 100644 --- a/addons/web_diagram/i18n/pt.po +++ b/addons/web_diagram/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/pt_BR.po b/addons/web_diagram/i18n/pt_BR.po index c3d2bf290bb..1cd50b59da6 100644 --- a/addons/web_diagram/i18n/pt_BR.po +++ b/addons/web_diagram/i18n/pt_BR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/ro.po b/addons/web_diagram/i18n/ro.po index 8c5dc473e43..e191e16675a 100644 --- a/addons/web_diagram/i18n/ro.po +++ b/addons/web_diagram/i18n/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/ru.po b/addons/web_diagram/i18n/ru.po index 14062840b2f..274a99a3eb6 100644 --- a/addons/web_diagram/i18n/ru.po +++ b/addons/web_diagram/i18n/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-26 05:19+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/sl.po b/addons/web_diagram/i18n/sl.po index 37b554a2754..eafb11b74eb 100644 --- a/addons/web_diagram/i18n/sl.po +++ b/addons/web_diagram/i18n/sl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/sq.po b/addons/web_diagram/i18n/sq.po index d8191d79db2..c6e8dd1536e 100644 --- a/addons/web_diagram/i18n/sq.po +++ b/addons/web_diagram/i18n/sq.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/sr@latin.po b/addons/web_diagram/i18n/sr@latin.po index 06bf0eccafb..7ff90bf1a58 100644 --- a/addons/web_diagram/i18n/sr@latin.po +++ b/addons/web_diagram/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/sv.po b/addons/web_diagram/i18n/sv.po index 97fba58992f..de325566358 100644 --- a/addons/web_diagram/i18n/sv.po +++ b/addons/web_diagram/i18n/sv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/tr.po b/addons/web_diagram/i18n/tr.po index a3c2b3f1ccb..ae6e8c92859 100644 --- a/addons/web_diagram/i18n/tr.po +++ b/addons/web_diagram/i18n/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_diagram/i18n/zh_CN.po b/addons/web_diagram/i18n/zh_CN.po index a30f45d11c2..355d6bb98d9 100644 --- a/addons/web_diagram/i18n/zh_CN.po +++ b/addons/web_diagram/i18n/zh_CN.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 diff --git a/addons/web_gantt/i18n/ar.po b/addons/web_gantt/i18n/ar.po index e9ad745a76e..efc1fe00bec 100644 --- a/addons/web_gantt/i18n/ar.po +++ b/addons/web_gantt/i18n/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/bg.po b/addons/web_gantt/i18n/bg.po index 23976f96791..21aab3a1f0c 100644 --- a/addons/web_gantt/i18n/bg.po +++ b/addons/web_gantt/i18n/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/bn.po b/addons/web_gantt/i18n/bn.po index c2f60c8d625..c6bb1af2553 100644 --- a/addons/web_gantt/i18n/bn.po +++ b/addons/web_gantt/i18n/bn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/bs.po b/addons/web_gantt/i18n/bs.po index 175bc84cf5c..e6434dc0b2e 100644 --- a/addons/web_gantt/i18n/bs.po +++ b/addons/web_gantt/i18n/bs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/ca.po b/addons/web_gantt/i18n/ca.po index dd4c08c9b50..b7a907a44ad 100644 --- a/addons/web_gantt/i18n/ca.po +++ b/addons/web_gantt/i18n/ca.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/cs.po b/addons/web_gantt/i18n/cs.po index 6e57eebe539..1d1bca8db86 100644 --- a/addons/web_gantt/i18n/cs.po +++ b/addons/web_gantt/i18n/cs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" "X-Poedit-Language: Czech\n" #. openerp-web diff --git a/addons/web_gantt/i18n/da.po b/addons/web_gantt/i18n/da.po index 92d9e8f6bb3..6096374d6ac 100644 --- a/addons/web_gantt/i18n/da.po +++ b/addons/web_gantt/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/de.po b/addons/web_gantt/i18n/de.po index f8f5b69470a..29e8ae0b15f 100644 --- a/addons/web_gantt/i18n/de.po +++ b/addons/web_gantt/i18n/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/en_AU.po b/addons/web_gantt/i18n/en_AU.po index 595d3fc734b..9b50d740fe2 100644 --- a/addons/web_gantt/i18n/en_AU.po +++ b/addons/web_gantt/i18n/en_AU.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/en_GB.po b/addons/web_gantt/i18n/en_GB.po index 9c1d2cc5ec7..c211b69f7d3 100644 --- a/addons/web_gantt/i18n/en_GB.po +++ b/addons/web_gantt/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/es.po b/addons/web_gantt/i18n/es.po index fb6ed0101a1..0082b7c5548 100644 --- a/addons/web_gantt/i18n/es.po +++ b/addons/web_gantt/i18n/es.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/es_CL.po b/addons/web_gantt/i18n/es_CL.po index a472a7a1485..532c5c7e70a 100644 --- a/addons/web_gantt/i18n/es_CL.po +++ b/addons/web_gantt/i18n/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/es_CR.po b/addons/web_gantt/i18n/es_CR.po index fe29c2995f5..668df147118 100644 --- a/addons/web_gantt/i18n/es_CR.po +++ b/addons/web_gantt/i18n/es_CR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/es_EC.po b/addons/web_gantt/i18n/es_EC.po index c1735a3dd8b..239f4aaabdf 100644 --- a/addons/web_gantt/i18n/es_EC.po +++ b/addons/web_gantt/i18n/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/fa.po b/addons/web_gantt/i18n/fa.po index 86a25319f47..e34e1f663a1 100644 --- a/addons/web_gantt/i18n/fa.po +++ b/addons/web_gantt/i18n/fa.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/fi.po b/addons/web_gantt/i18n/fi.po index 268f133941d..1f9c20703e4 100644 --- a/addons/web_gantt/i18n/fi.po +++ b/addons/web_gantt/i18n/fi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/fr.po b/addons/web_gantt/i18n/fr.po index 5b0fadbf06a..2c3ef92e2db 100644 --- a/addons/web_gantt/i18n/fr.po +++ b/addons/web_gantt/i18n/fr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/gl.po b/addons/web_gantt/i18n/gl.po index 8624ee7a069..4ab201938cd 100644 --- a/addons/web_gantt/i18n/gl.po +++ b/addons/web_gantt/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/gu.po b/addons/web_gantt/i18n/gu.po new file mode 100644 index 00000000000..2c31432f767 --- /dev/null +++ b/addons/web_gantt/i18n/gu.po @@ -0,0 +1,28 @@ +# Gujarati translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2012-07-02 09:06+0200\n" +"PO-Revision-Date: 2012-11-17 10:36+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: Gujarati <gu@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n" +"X-Generator: Launchpad (build 16278)\n" + +#. openerp-web +#: addons/web_gantt/static/src/js/gantt.js:11 +msgid "Gantt" +msgstr "" + +#. openerp-web +#: addons/web_gantt/static/src/xml/web_gantt.xml:10 +msgid "Create" +msgstr "બનાવો" diff --git a/addons/web_gantt/i18n/hr.po b/addons/web_gantt/i18n/hr.po index 5d9863412ca..e9694fdb382 100644 --- a/addons/web_gantt/i18n/hr.po +++ b/addons/web_gantt/i18n/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/hu.po b/addons/web_gantt/i18n/hu.po index 04343f07b7c..fd289446d7f 100644 --- a/addons/web_gantt/i18n/hu.po +++ b/addons/web_gantt/i18n/hu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/it.po b/addons/web_gantt/i18n/it.po index 44392f14b66..17f5759ecfd 100644 --- a/addons/web_gantt/i18n/it.po +++ b/addons/web_gantt/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/ja.po b/addons/web_gantt/i18n/ja.po index 251322ebf3d..9a02f165279 100644 --- a/addons/web_gantt/i18n/ja.po +++ b/addons/web_gantt/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/ka.po b/addons/web_gantt/i18n/ka.po index 5e8bb8a4a5f..9d2f65285cd 100644 --- a/addons/web_gantt/i18n/ka.po +++ b/addons/web_gantt/i18n/ka.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/lt.po b/addons/web_gantt/i18n/lt.po index 6310962c04e..99905322c04 100644 --- a/addons/web_gantt/i18n/lt.po +++ b/addons/web_gantt/i18n/lt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/mk.po b/addons/web_gantt/i18n/mk.po index 2e7cb554db6..018a2a3b16c 100644 --- a/addons/web_gantt/i18n/mk.po +++ b/addons/web_gantt/i18n/mk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/mn.po b/addons/web_gantt/i18n/mn.po index 6f42fb9e495..d2c8da8e22f 100644 --- a/addons/web_gantt/i18n/mn.po +++ b/addons/web_gantt/i18n/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/nb.po b/addons/web_gantt/i18n/nb.po index b9f50c24a7c..501581bcb04 100644 --- a/addons/web_gantt/i18n/nb.po +++ b/addons/web_gantt/i18n/nb.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/nl.po b/addons/web_gantt/i18n/nl.po index 1f22a510595..795da258259 100644 --- a/addons/web_gantt/i18n/nl.po +++ b/addons/web_gantt/i18n/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/nl_BE.po b/addons/web_gantt/i18n/nl_BE.po index ad943f78869..29639d63418 100644 --- a/addons/web_gantt/i18n/nl_BE.po +++ b/addons/web_gantt/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/pl.po b/addons/web_gantt/i18n/pl.po index e92010a58c3..8861a13adfd 100644 --- a/addons/web_gantt/i18n/pl.po +++ b/addons/web_gantt/i18n/pl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/pt.po b/addons/web_gantt/i18n/pt.po index 308b740582d..580380da267 100644 --- a/addons/web_gantt/i18n/pt.po +++ b/addons/web_gantt/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/pt_BR.po b/addons/web_gantt/i18n/pt_BR.po index 361fab71df7..72b9f5724ee 100644 --- a/addons/web_gantt/i18n/pt_BR.po +++ b/addons/web_gantt/i18n/pt_BR.po @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/ro.po b/addons/web_gantt/i18n/ro.po index 262084e175b..1fe6e2d2c72 100644 --- a/addons/web_gantt/i18n/ro.po +++ b/addons/web_gantt/i18n/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/ru.po b/addons/web_gantt/i18n/ru.po index 43c6170f691..32d3b90e36b 100644 --- a/addons/web_gantt/i18n/ru.po +++ b/addons/web_gantt/i18n/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/sl.po b/addons/web_gantt/i18n/sl.po index 007ef01e8ca..f26f72b7b43 100644 --- a/addons/web_gantt/i18n/sl.po +++ b/addons/web_gantt/i18n/sl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/sq.po b/addons/web_gantt/i18n/sq.po index d9998290592..f514a0c2728 100644 --- a/addons/web_gantt/i18n/sq.po +++ b/addons/web_gantt/i18n/sq.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/sr@latin.po b/addons/web_gantt/i18n/sr@latin.po index c7049eb9c9f..12eae1b5924 100644 --- a/addons/web_gantt/i18n/sr@latin.po +++ b/addons/web_gantt/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/sv.po b/addons/web_gantt/i18n/sv.po index 547c50ac571..1dd0aa4086e 100644 --- a/addons/web_gantt/i18n/sv.po +++ b/addons/web_gantt/i18n/sv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/tr.po b/addons/web_gantt/i18n/tr.po index ce2779e23ae..70dea5797c2 100644 --- a/addons/web_gantt/i18n/tr.po +++ b/addons/web_gantt/i18n/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/zh_CN.po b/addons/web_gantt/i18n/zh_CN.po index e8739bf81ac..7e0a75f9387 100644 --- a/addons/web_gantt/i18n/zh_CN.po +++ b/addons/web_gantt/i18n/zh_CN.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_graph/i18n/ar.po b/addons/web_graph/i18n/ar.po index 3150b37d553..f4673c7eb0d 100644 --- a/addons/web_graph/i18n/ar.po +++ b/addons/web_graph/i18n/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/bg.po b/addons/web_graph/i18n/bg.po index 6aab3ad70b7..f53d8f2e766 100644 --- a/addons/web_graph/i18n/bg.po +++ b/addons/web_graph/i18n/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/bn.po b/addons/web_graph/i18n/bn.po index b19bfaf8fff..7ae977e2463 100644 --- a/addons/web_graph/i18n/bn.po +++ b/addons/web_graph/i18n/bn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/bs.po b/addons/web_graph/i18n/bs.po index d5bf94fc711..0ad1e813651 100644 --- a/addons/web_graph/i18n/bs.po +++ b/addons/web_graph/i18n/bs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/ca.po b/addons/web_graph/i18n/ca.po index 370b3190749..6e3328d6fa6 100644 --- a/addons/web_graph/i18n/ca.po +++ b/addons/web_graph/i18n/ca.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/cs.po b/addons/web_graph/i18n/cs.po index 9f216542bc0..e2a375305c9 100644 --- a/addons/web_graph/i18n/cs.po +++ b/addons/web_graph/i18n/cs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/da.po b/addons/web_graph/i18n/da.po index 6c1a477a417..bce5117670f 100644 --- a/addons/web_graph/i18n/da.po +++ b/addons/web_graph/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/de.po b/addons/web_graph/i18n/de.po index ec6a4d249e3..004eaad2c94 100644 --- a/addons/web_graph/i18n/de.po +++ b/addons/web_graph/i18n/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/en_AU.po b/addons/web_graph/i18n/en_AU.po index f89a24e1332..23da37b7f15 100644 --- a/addons/web_graph/i18n/en_AU.po +++ b/addons/web_graph/i18n/en_AU.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/en_GB.po b/addons/web_graph/i18n/en_GB.po index 70e0a38837f..6ce1fd26bef 100644 --- a/addons/web_graph/i18n/en_GB.po +++ b/addons/web_graph/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/es.po b/addons/web_graph/i18n/es.po index 0b23d1a7052..8ad576a49ea 100644 --- a/addons/web_graph/i18n/es.po +++ b/addons/web_graph/i18n/es.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/es_CL.po b/addons/web_graph/i18n/es_CL.po index 5588bd39e9b..f3235627451 100644 --- a/addons/web_graph/i18n/es_CL.po +++ b/addons/web_graph/i18n/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/es_CR.po b/addons/web_graph/i18n/es_CR.po index 28cd92a1bdf..e26959c1b36 100644 --- a/addons/web_graph/i18n/es_CR.po +++ b/addons/web_graph/i18n/es_CR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/es_EC.po b/addons/web_graph/i18n/es_EC.po index e4b016a8a3d..9a137d32e74 100644 --- a/addons/web_graph/i18n/es_EC.po +++ b/addons/web_graph/i18n/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/fa.po b/addons/web_graph/i18n/fa.po index 1d9ba33c635..70e66f3bed7 100644 --- a/addons/web_graph/i18n/fa.po +++ b/addons/web_graph/i18n/fa.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/fi.po b/addons/web_graph/i18n/fi.po index 1588337b41c..ef55e2f3353 100644 --- a/addons/web_graph/i18n/fi.po +++ b/addons/web_graph/i18n/fi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/fr.po b/addons/web_graph/i18n/fr.po index 9e07304a87d..6d4cf6f63a1 100644 --- a/addons/web_graph/i18n/fr.po +++ b/addons/web_graph/i18n/fr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/gl.po b/addons/web_graph/i18n/gl.po index 5d89c5e7a7a..b83edaa0003 100644 --- a/addons/web_graph/i18n/gl.po +++ b/addons/web_graph/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/gu.po b/addons/web_graph/i18n/gu.po new file mode 100644 index 00000000000..25b35828984 --- /dev/null +++ b/addons/web_graph/i18n/gu.po @@ -0,0 +1,98 @@ +# Gujarati translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2012-07-02 09:06+0200\n" +"PO-Revision-Date: 2012-11-17 10:34+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: Gujarati <gu@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n" +"X-Generator: Launchpad (build 16278)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "આલેખ" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:5 +msgid "Graph Options" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:7 +msgid "Graph Mode" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:11 +msgid "Pie" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:12 +msgid "Bars" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:14 +msgid "Lines" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:15 +msgid "Areas" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:18 +msgid "Radar" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:20 +msgid "Legend" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:24 +msgid "Hidden" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:25 +msgid "Inside" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:26 +msgid "Top" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:28 +msgid "Actions" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:32 +msgid "Switch Axis" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:33 +msgid "Show Data" +msgstr "" + +#. openerp-web +#: addons/web_graph/static/src/xml/web_graph.xml:34 +msgid "Download as PNG" +msgstr "" diff --git a/addons/web_graph/i18n/hr.po b/addons/web_graph/i18n/hr.po index f42d955f760..13c509d2824 100644 --- a/addons/web_graph/i18n/hr.po +++ b/addons/web_graph/i18n/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/hu.po b/addons/web_graph/i18n/hu.po index 7c401a38d11..b6ae8e819ea 100644 --- a/addons/web_graph/i18n/hu.po +++ b/addons/web_graph/i18n/hu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/it.po b/addons/web_graph/i18n/it.po index 3c297f69fea..c93b1893e9c 100644 --- a/addons/web_graph/i18n/it.po +++ b/addons/web_graph/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/ja.po b/addons/web_graph/i18n/ja.po index e2328b4107a..d79e3780ed2 100644 --- a/addons/web_graph/i18n/ja.po +++ b/addons/web_graph/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/ka.po b/addons/web_graph/i18n/ka.po index f01c0ae5f99..2ba2b591c5f 100644 --- a/addons/web_graph/i18n/ka.po +++ b/addons/web_graph/i18n/ka.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/lt.po b/addons/web_graph/i18n/lt.po index ad566156e26..3cb8e482d6e 100644 --- a/addons/web_graph/i18n/lt.po +++ b/addons/web_graph/i18n/lt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/mk.po b/addons/web_graph/i18n/mk.po index 502b1ccf3ff..279cfc26e1c 100644 --- a/addons/web_graph/i18n/mk.po +++ b/addons/web_graph/i18n/mk.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/mn.po b/addons/web_graph/i18n/mn.po index 6f1a85b3526..c454eb74a17 100644 --- a/addons/web_graph/i18n/mn.po +++ b/addons/web_graph/i18n/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/nl.po b/addons/web_graph/i18n/nl.po index 66526cb0d63..19360ad4092 100644 --- a/addons/web_graph/i18n/nl.po +++ b/addons/web_graph/i18n/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/nl_BE.po b/addons/web_graph/i18n/nl_BE.po index 59a936a06b2..b8adf273d37 100644 --- a/addons/web_graph/i18n/nl_BE.po +++ b/addons/web_graph/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/pl.po b/addons/web_graph/i18n/pl.po index 06cee6ac833..cb77a0c8f84 100644 --- a/addons/web_graph/i18n/pl.po +++ b/addons/web_graph/i18n/pl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/pt.po b/addons/web_graph/i18n/pt.po index 3f8edebbf9b..eb00e9406fa 100644 --- a/addons/web_graph/i18n/pt.po +++ b/addons/web_graph/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/pt_BR.po b/addons/web_graph/i18n/pt_BR.po index a99a4819e09..96fd7730fcf 100644 --- a/addons/web_graph/i18n/pt_BR.po +++ b/addons/web_graph/i18n/pt_BR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/ro.po b/addons/web_graph/i18n/ro.po index 395789af612..efcbc0afe63 100644 --- a/addons/web_graph/i18n/ro.po +++ b/addons/web_graph/i18n/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/ru.po b/addons/web_graph/i18n/ru.po index fcb97444257..5006d7c124f 100644 --- a/addons/web_graph/i18n/ru.po +++ b/addons/web_graph/i18n/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-24 05:20+0000\n" -"X-Generator: Launchpad (build 16179)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/sl.po b/addons/web_graph/i18n/sl.po index 159b01142da..d8275c1dd29 100644 --- a/addons/web_graph/i18n/sl.po +++ b/addons/web_graph/i18n/sl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/sq.po b/addons/web_graph/i18n/sq.po index 5a9b63f8c35..dafb35d6d04 100644 --- a/addons/web_graph/i18n/sq.po +++ b/addons/web_graph/i18n/sq.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/sr@latin.po b/addons/web_graph/i18n/sr@latin.po index 54fd7987d5e..8c41f4579da 100644 --- a/addons/web_graph/i18n/sr@latin.po +++ b/addons/web_graph/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/sv.po b/addons/web_graph/i18n/sv.po index e1a5d2f9032..3ff11c4d03d 100644 --- a/addons/web_graph/i18n/sv.po +++ b/addons/web_graph/i18n/sv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/tr.po b/addons/web_graph/i18n/tr.po index 720a4039a7b..2eb5c4651f7 100644 --- a/addons/web_graph/i18n/tr.po +++ b/addons/web_graph/i18n/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/i18n/zh_CN.po b/addons/web_graph/i18n/zh_CN.po index a2bc90c1827..db352a3e5d9 100644 --- a/addons/web_graph/i18n/zh_CN.po +++ b/addons/web_graph/i18n/zh_CN.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 diff --git a/addons/web_graph/static/lib/flotr2/lib/bean.js b/addons/web_graph/static/lib/flotr2/lib/bean.js index 6e6e3ef4eb5..1a854771006 100644 --- a/addons/web_graph/static/lib/flotr2/lib/bean.js +++ b/addons/web_graph/static/lib/flotr2/lib/bean.js @@ -9,9 +9,7 @@ */ /*global module:true, define:true*/ !function (name, context, definition) { - if (typeof module !== 'undefined') module.exports = definition(name, context); - else if (typeof define === 'function' && typeof define.amd === 'object') define(definition); - else context[name] = definition(name, context); + context[name] = definition(name, context); }('bean', this, function (name, context) { var win = window , old = context[name] diff --git a/addons/web_hello/i18n/ar.po b/addons/web_hello/i18n/ar.po index 067507856fe..933b9f8bd9f 100644 --- a/addons/web_hello/i18n/ar.po +++ b/addons/web_hello/i18n/ar.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" diff --git a/addons/web_hello/i18n/es_CR.po b/addons/web_hello/i18n/es_CR.po index cc1a06469ec..4c93888641a 100644 --- a/addons/web_hello/i18n/es_CR.po +++ b/addons/web_hello/i18n/es_CR.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" diff --git a/addons/web_hello/i18n/fr.po b/addons/web_hello/i18n/fr.po index 029ada82c70..1db28fcd669 100644 --- a/addons/web_hello/i18n/fr.po +++ b/addons/web_hello/i18n/fr.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" diff --git a/addons/web_hello/i18n/pt_BR.po b/addons/web_hello/i18n/pt_BR.po index d374091e09e..76a3d76ef42 100644 --- a/addons/web_hello/i18n/pt_BR.po +++ b/addons/web_hello/i18n/pt_BR.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" diff --git a/addons/web_kanban/i18n/ar.po b/addons/web_kanban/i18n/ar.po index ba734cf3f82..2b41c88af20 100644 --- a/addons/web_kanban/i18n/ar.po +++ b/addons/web_kanban/i18n/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/bg.po b/addons/web_kanban/i18n/bg.po index 000818fb9c7..060707f8971 100644 --- a/addons/web_kanban/i18n/bg.po +++ b/addons/web_kanban/i18n/bg.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/bn.po b/addons/web_kanban/i18n/bn.po index 2473660d416..545f20352c9 100644 --- a/addons/web_kanban/i18n/bn.po +++ b/addons/web_kanban/i18n/bn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/bs.po b/addons/web_kanban/i18n/bs.po index 0d208a70b37..e7078c96433 100644 --- a/addons/web_kanban/i18n/bs.po +++ b/addons/web_kanban/i18n/bs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/ca.po b/addons/web_kanban/i18n/ca.po index 93862e3d292..177a7d00799 100644 --- a/addons/web_kanban/i18n/ca.po +++ b/addons/web_kanban/i18n/ca.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/cs.po b/addons/web_kanban/i18n/cs.po index 9012c6f4560..f5d9f774a21 100644 --- a/addons/web_kanban/i18n/cs.po +++ b/addons/web_kanban/i18n/cs.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" "X-Poedit-Language: Czech\n" #. openerp-web diff --git a/addons/web_kanban/i18n/da.po b/addons/web_kanban/i18n/da.po index a14b5544337..48cc86e2236 100644 --- a/addons/web_kanban/i18n/da.po +++ b/addons/web_kanban/i18n/da.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/de.po b/addons/web_kanban/i18n/de.po index 794169a3e0e..a88a66d3a77 100644 --- a/addons/web_kanban/i18n/de.po +++ b/addons/web_kanban/i18n/de.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/en_GB.po b/addons/web_kanban/i18n/en_GB.po index e2a72bc19ca..38c82e62c7f 100644 --- a/addons/web_kanban/i18n/en_GB.po +++ b/addons/web_kanban/i18n/en_GB.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/es.po b/addons/web_kanban/i18n/es.po index d562b6bf82e..c065470b00e 100644 --- a/addons/web_kanban/i18n/es.po +++ b/addons/web_kanban/i18n/es.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/es_CL.po b/addons/web_kanban/i18n/es_CL.po index 55e598d7017..8a467e05508 100644 --- a/addons/web_kanban/i18n/es_CL.po +++ b/addons/web_kanban/i18n/es_CL.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/es_CR.po b/addons/web_kanban/i18n/es_CR.po index b7b851f14c7..1d434969d8f 100644 --- a/addons/web_kanban/i18n/es_CR.po +++ b/addons/web_kanban/i18n/es_CR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/es_EC.po b/addons/web_kanban/i18n/es_EC.po index afe3b25aeaf..ffdfc0083f8 100644 --- a/addons/web_kanban/i18n/es_EC.po +++ b/addons/web_kanban/i18n/es_EC.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/fa.po b/addons/web_kanban/i18n/fa.po index e24902448a1..8d97b5cd087 100644 --- a/addons/web_kanban/i18n/fa.po +++ b/addons/web_kanban/i18n/fa.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/fi.po b/addons/web_kanban/i18n/fi.po index fdfeea871ad..ca1b51564e9 100644 --- a/addons/web_kanban/i18n/fi.po +++ b/addons/web_kanban/i18n/fi.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/fr.po b/addons/web_kanban/i18n/fr.po index d31357bad62..a4e8b026287 100644 --- a/addons/web_kanban/i18n/fr.po +++ b/addons/web_kanban/i18n/fr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/gl.po b/addons/web_kanban/i18n/gl.po index 9ccd66c71eb..e03983179f6 100644 --- a/addons/web_kanban/i18n/gl.po +++ b/addons/web_kanban/i18n/gl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/gu.po b/addons/web_kanban/i18n/gu.po new file mode 100644 index 00000000000..0e82f736171 --- /dev/null +++ b/addons/web_kanban/i18n/gu.po @@ -0,0 +1,66 @@ +# Gujarati translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2012-07-02 09:06+0200\n" +"PO-Revision-Date: 2012-11-17 11:38+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: Gujarati <gu@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n" +"X-Generator: Launchpad (build 16278)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:293 +msgid "Undefined" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:471 +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:839 +msgid "Create: " +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:71 +msgid "Add" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:71 +msgid "or" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:72 +msgid "Cancel" +msgstr "" + +#~ msgid "Create" +#~ msgstr "બનાવો" diff --git a/addons/web_kanban/i18n/hr.po b/addons/web_kanban/i18n/hr.po index bfb80508047..4475b0596b9 100644 --- a/addons/web_kanban/i18n/hr.po +++ b/addons/web_kanban/i18n/hr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/hu.po b/addons/web_kanban/i18n/hu.po index 6392fa227fd..febf19037aa 100644 --- a/addons/web_kanban/i18n/hu.po +++ b/addons/web_kanban/i18n/hu.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/it.po b/addons/web_kanban/i18n/it.po index 71da09eac6a..4aad60e6cf4 100644 --- a/addons/web_kanban/i18n/it.po +++ b/addons/web_kanban/i18n/it.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/ja.po b/addons/web_kanban/i18n/ja.po index 61a6473fdb4..f054f40115f 100644 --- a/addons/web_kanban/i18n/ja.po +++ b/addons/web_kanban/i18n/ja.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/ka.po b/addons/web_kanban/i18n/ka.po index 4196dba39cb..d3ebdf522db 100644 --- a/addons/web_kanban/i18n/ka.po +++ b/addons/web_kanban/i18n/ka.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/lt.po b/addons/web_kanban/i18n/lt.po index 04f788195ac..e0f087dd442 100644 --- a/addons/web_kanban/i18n/lt.po +++ b/addons/web_kanban/i18n/lt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/mn.po b/addons/web_kanban/i18n/mn.po index 9afb4e45d93..573f278dd84 100644 --- a/addons/web_kanban/i18n/mn.po +++ b/addons/web_kanban/i18n/mn.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/nl.po b/addons/web_kanban/i18n/nl.po index ff3b7094b2b..3cb8c91034e 100644 --- a/addons/web_kanban/i18n/nl.po +++ b/addons/web_kanban/i18n/nl.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/nl_BE.po b/addons/web_kanban/i18n/nl_BE.po index b4b8fae14c9..347beeb76af 100644 --- a/addons/web_kanban/i18n/nl_BE.po +++ b/addons/web_kanban/i18n/nl_BE.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/pl.po b/addons/web_kanban/i18n/pl.po index 6c42bc5571b..c040e1c7ba0 100644 --- a/addons/web_kanban/i18n/pl.po +++ b/addons/web_kanban/i18n/pl.po @@ -14,13 +14,13 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 msgid "Kanban" -msgstr "" +msgstr "Kanban" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:293 @@ -64,3 +64,6 @@ msgstr "" #~ msgid "Create" #~ msgstr "Utwórz" + +#~ msgid "</tr><tr>" +#~ msgstr "</tr><tr>" diff --git a/addons/web_kanban/i18n/pt.po b/addons/web_kanban/i18n/pt.po index c8e0196d7ba..4747266805c 100644 --- a/addons/web_kanban/i18n/pt.po +++ b/addons/web_kanban/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/pt_BR.po b/addons/web_kanban/i18n/pt_BR.po index 1047c7e7725..c0b67986f3d 100644 --- a/addons/web_kanban/i18n/pt_BR.po +++ b/addons/web_kanban/i18n/pt_BR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/ro.po b/addons/web_kanban/i18n/ro.po index 27326621b10..acd190514b7 100644 --- a/addons/web_kanban/i18n/ro.po +++ b/addons/web_kanban/i18n/ro.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/ru.po b/addons/web_kanban/i18n/ru.po index a30f7c53997..03b3e9a9dfe 100644 --- a/addons/web_kanban/i18n/ru.po +++ b/addons/web_kanban/i18n/ru.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-27 05:15+0000\n" -"X-Generator: Launchpad (build 16194)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/sr@latin.po b/addons/web_kanban/i18n/sr@latin.po index 4ba839580e8..63c0887990b 100644 --- a/addons/web_kanban/i18n/sr@latin.po +++ b/addons/web_kanban/i18n/sr@latin.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/sv.po b/addons/web_kanban/i18n/sv.po index aff6a057656..77dd0d06cb2 100644 --- a/addons/web_kanban/i18n/sv.po +++ b/addons/web_kanban/i18n/sv.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/tr.po b/addons/web_kanban/i18n/tr.po index 4df30e4ee5e..80cb052e407 100644 --- a/addons/web_kanban/i18n/tr.po +++ b/addons/web_kanban/i18n/tr.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/zh_CN.po b/addons/web_kanban/i18n/zh_CN.po index 07c905699ad..1d543e0d06c 100644 --- a/addons/web_kanban/i18n/zh_CN.po +++ b/addons/web_kanban/i18n/zh_CN.po @@ -9,13 +9,13 @@ msgstr "" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "POT-Creation-Date: 2012-07-02 09:06+0200\n" "PO-Revision-Date: 2012-02-10 08:25+0000\n" -"Last-Translator: Jeff Wang <wjfonhand@hotmail.com>\n" +"Last-Translator: 开阖软件 Jeff Wang <jeff@osbzr.com>\n" "Language-Team: Chinese (Simplified) <zh_CN@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 105e074df1f..9b74462ee13 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -277,7 +277,7 @@ width: 100%; } .openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_column .oe_kanban_record { - float: left; + display: inline-block; padding: 2px; box-sizing: border-box; -moz-box-sizing: border-box; diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index fbc9e3d8568..b993b648691 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -264,7 +264,7 @@ width: 100% &.oe_kanban_ungrouped .oe_kanban_column .oe_kanban_record - float: left + display: inline-block padding: 2px box-sizing: border-box -moz-box-sizing: border-box diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index a4f51e81dd8..cd1ea74983f 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -27,6 +27,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.group_by = null; this.group_by_field = {}; this.grouped_by_m2o = false; + this.many2manys = []; this.state = { groups : {}, records : {} @@ -130,12 +131,11 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ } switch (node.tag) { case 'field': - if(this.fields_view.fields[ node.attrs['name'] ].type == 'many2many'){ - node.tag = 'div'; - node.attrs['class'] = 'oe_form_field oe_tags'; - node.attrs['model'] = this.fields_view.fields[node.attrs['name']].relation; - node.attrs['t-att-data'] = 'record.' + node.attrs['name'] + '.raw_value'; - }else { + if (this.fields_view.fields[node.attrs.name].type === 'many2many') { + this.many2manys.push(node.attrs.name); + node.tag = 'div'; + node.attrs['class'] = (node.attrs['class'] || '') + ' oe_form_field oe_tags'; + } else { node.tag = QWeb.prefix; node.attrs[QWeb.prefix + '-esc'] = 'record.' + node.attrs['name'] + '.value'; } @@ -388,7 +388,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ } else { this.$el.find('.oe_kanban_draghandle').removeClass('oe_kanban_draghandle'); } - instance.web_kanban.KanbanView.postprocessing_widget_many2many_tags(self); + this.postprocess_m2m_tags(); }, on_record_moved : function(record, old_group, old_index, new_group, new_index) { var self = this; @@ -470,44 +470,48 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.$el.find('.oe_view_nocontent').click(function() { create_nocontent.effect('bounce', {distance: 18, times: 5}, 150); }); - } -}); - -/* -* widget for list of tags/categories -* make the rpc request for all ids/model and insert value inside .oe_tags fields -*/ -instance.web_kanban.KanbanView.postprocessing_widget_many2many_tags = function(self){ - var model_list_id={}; - - // select all widget for the kanban view or the widget inside the record - self.$el.find(".oe_form_field.oe_tags").each(function(){ - var model = $(this).attr("model"); - if(model.length){ - var data = $(this).attr("data"); - var list = data.split(","); + }, - //select all id (per model) - if(!model_list_id[model]) model_list_id[model]=[]; - for(var t=0;t<list.length;t++) if(list[t]!="") model_list_id[model].push( list[t] ); + /* + * postprocessing of fields type many2many + * make the rpc request for all ids/model and insert value inside .oe_tags fields + */ + postprocess_m2m_tags: function() { + var self = this; + if (!this.many2manys.length) { + return; } - }); - // rpc and insert - for(var model in model_list_id){ - if(model_list_id[model].length>0){ - var block = self.$el.find(".oe_form_field.oe_tags[model='" + model + "']"); - var dataset = new instance.web.DataSetSearch(self, model, self.session.context); - dataset.name_get(_.uniq( model_list_id[model] )).done( - function(result) { - for(var t=0;t<result.length;t++){ - block.filter(function(){ return this.getAttribute("data").match(new RegExp('(^|,)'+result[t][0]+'(,|$)')); }) - .append('<span class="oe_tag" data-list_id="' + result[t][0] +'"">'+result[t][1]+'</span>'); + var relations = {}; + this.groups.forEach(function(group) { + group.records.forEach(function(record) { + self.many2manys.forEach(function(name) { + var field = record.record[name]; + var $el = record.$('.oe_form_field.oe_tags[name=' + name + ']'); + if (!relations[field.relation]) { + relations[field.relation] = { ids: [], elements: {}}; } - } - ); - } + var rel = relations[field.relation]; + field.raw_value.forEach(function(id) { + rel.ids.push(id); + if (!rel.elements[id]) { + rel.elements[id] = []; + } + rel.elements[id].push($el[0]); + }); + }); + }); + }); + _.each(relations, function(rel, rel_name) { + var dataset = new instance.web.DataSetSearch(self, rel_name, self.dataset.get_context()); + dataset.name_get(_.uniq(rel.ids)).done(function(result) { + result.forEach(function(nameget) { + $(rel.elements[nameget[0]]).append('<span class="oe_tag">' + _.str.escapeHTML(nameget[1]) + '</span>'); + }); + }); + }); } -} +}); + function get_class(name) { return new instance.web.Registry({'tmp' : name}).get_object("tmp"); @@ -946,7 +950,7 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({ self.$el.data('widget', self); self.bind_events(); self.group.compute_cards_auto_height(); - instance.web_kanban.KanbanView.postprocessing_widget_many2many_tags(self); + self.view.postprocess_m2m_tags(); } else { self.destroy(); } @@ -988,10 +992,10 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({ } else if (this.record[field] && ! this.record[field].value) { url = "/web/static/src/img/placeholder.png"; } else { - id = escape(JSON.stringify(id)); + id = JSON.stringify(id); if (options.preview_image) field = options.preview_image; - url = instance.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id; + url = this.session.url('/web/binary/image', {model: model, field: field, id: id}); if (cache !== undefined) { // Set the cache duration in seconds. url += '&cache=' + parseInt(cache, 10); diff --git a/addons/web_tests/i18n/es_CR.po b/addons/web_tests/i18n/es_CR.po index 8d2bfb39fe0..03a3decee15 100644 --- a/addons/web_tests/i18n/es_CR.po +++ b/addons/web_tests/i18n/es_CR.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" diff --git a/addons/web_tests/i18n/fr_CA.po b/addons/web_tests/i18n/fr_CA.po index 41dc4167edd..e5e6713348f 100644 --- a/addons/web_tests/i18n/fr_CA.po +++ b/addons/web_tests/i18n/fr_CA.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-15 05:09+0000\n" +"X-Generator: Launchpad (build 16265)\n" diff --git a/addons/web_tests_demo/__init__.py b/addons/web_tests_demo/__init__.py new file mode 100644 index 00000000000..137d472ec74 --- /dev/null +++ b/addons/web_tests_demo/__init__.py @@ -0,0 +1,14 @@ +from openerp.osv import orm, fields + +class TestObject(orm.Model): + _name = 'web_tests_demo.model' + + _columns = { + 'name': fields.char("Name", required=True), + 'thing': fields.char("Thing"), + 'other': fields.char("Other", required=True) + } + _defaults = { + 'other': "bob" + } + diff --git a/addons/web_tests_demo/__openerp__.py b/addons/web_tests_demo/__openerp__.py new file mode 100644 index 00000000000..7404ef6b4fc --- /dev/null +++ b/addons/web_tests_demo/__openerp__.py @@ -0,0 +1,8 @@ +{ + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'js': ['static/src/js/demo.js'], + 'test': ['static/test/demo.js'], + 'qweb': ['static/src/xml/demo.xml'], +} diff --git a/addons/web_tests_demo/static/src/js/demo.js b/addons/web_tests_demo/static/src/js/demo.js new file mode 100644 index 00000000000..b35b44b80f8 --- /dev/null +++ b/addons/web_tests_demo/static/src/js/demo.js @@ -0,0 +1,11 @@ +// static/src/js/demo.js +openerp.web_tests_demo = function (instance) { + instance.web_tests_demo = { + value_true: true, + SomeType: instance.web.Class.extend({ + init: function (value) { + this.value = value; + } + }) + }; +}; diff --git a/addons/web_tests_demo/static/src/xml/demo.xml b/addons/web_tests_demo/static/src/xml/demo.xml new file mode 100644 index 00000000000..1bd3862d70e --- /dev/null +++ b/addons/web_tests_demo/static/src/xml/demo.xml @@ -0,0 +1,7 @@ +<templates id="template" xml:space="preserve"> + <div t-name="DemoTemplate"> + <t t-foreach="5" t-as="value"> + <p><t t-esc="value"/></p> + </t> + </div> +</templates> diff --git a/addons/web_tests_demo/static/test/demo.js b/addons/web_tests_demo/static/test/demo.js new file mode 100644 index 00000000000..b2d54c83d68 --- /dev/null +++ b/addons/web_tests_demo/static/test/demo.js @@ -0,0 +1,102 @@ +openerp.testing.section('basic section', function (test) { + test('my first test', function () { + ok(true, "this test has run"); + }); + test('module content', function (instance) { + ok(instance.web_tests_demo.value_true, "should have a true value"); + var type_instance = new instance.web_tests_demo.SomeType(42); + strictEqual(type_instance.value, 42, "should have provided value"); + }); + test('DOM content', function (instance, $scratchpad) { + $scratchpad.html('<div><span class="foo bar">ok</span></div>'); + ok($scratchpad.find('span').hasClass('foo'), + "should have provided class"); + }); + test('clean scratchpad', function (instance, $scratchpad) { + ok(!$scratchpad.children().length, "should have no content"); + ok(!$scratchpad.text(), "should have no text"); + }); + + test('templates', {templates: true}, function (instance) { + var s = instance.web.qweb.render('DemoTemplate'); + var texts = $(s).find('p').map(function () { + return $(this).text(); + }).get(); + + deepEqual(texts, ['0', '1', '2', '3', '4']); + }); + + test('asynchronous', { + asserts: 1 + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.resolve(); + }, 100); + return d; + }); + test('unfail rejection', { + asserts: 1, + fail_on_rejection: false + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.reject(); + }, 100); + return d; + }); + + test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) { + mock('people.famous:name_search', function (args, kwargs) { + strictEqual(kwargs.name, 'bob'); + return [ + [1, "Microsoft Bob"], + [2, "Bob the Builder"], + [3, "Silent Bob"] + ]; + }); + return new instance.web.Model('people.famous') + .call('name_search', {name: 'bob'}).then(function (result) { + strictEqual(result.length, 3, "shoud return 3 people"); + strictEqual(result[0][1], "Microsoft Bob", + "the most famous bob should be Microsoft Bob"); + }); + }); + test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) { + var fetched_dbs = false, fetched_langs = false; + mock('/web/database/get_list', function () { + fetched_dbs = true; + return ['foo', 'bar', 'baz']; + }); + mock('/web/session/get_lang_list', function () { + fetched_langs = true; + return [['vo_IS', 'Hopelandic / Vonlenska']]; + }); + + // widget needs that or it blows up + instance.webclient = {toggle_bars: openerp.testing.noop}; + var dbm = new instance.web.DatabaseManager({}); + return dbm.appendTo($s).then(function () { + ok(fetched_dbs, "should have fetched databases"); + ok(fetched_langs, "should have fetched languages"); + deepEqual(dbm.db_list, ['foo', 'bar', 'baz']); + }); + }); + + test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) { + var Model = new instance.web.Model('web_tests_demo.model'); + return Model.call('create', [{name: "Bob"}]) + .then(function (id) { + return Model.call('read', [[id]]); + }).then(function (records) { + strictEqual(records.length, 1); + var record = records[0]; + strictEqual(record.name, "Bob"); + strictEqual(record.thing, false); + // default value + strictEqual(record.other, 'bob'); + }); + }); +}); |
