summaryrefslogtreecommitdiff
path: root/addons/web
diff options
context:
space:
mode:
authorVo Minh Thu <vmt@openerp.com>2012-01-16 12:06:31 +0100
committerVo Minh Thu <vmt@openerp.com>2012-01-16 12:06:31 +0100
commit3203d264aecd751a8c261cea4f72fa323a3098be (patch)
tree93cdf7c89795b809963ef08a68d84d293cf41a7a /addons/web
parent1497062ba1dbfd814c69fa4250c4eb6a09a5206a (diff)
parent064a50bcde5f1c65a17f4feb42348b5809081085 (diff)
[MERGE] merged trunk.
bzr revid: vmt@openerp.com-20120116110631-lrzp6uxsjki7by22
Diffstat (limited to 'addons/web')
-rw-r--r--addons/web/__init__.py7
-rw-r--r--addons/web/common/http.py4
-rw-r--r--addons/web/common/openerplib/main.py18
-rw-r--r--addons/web/common/release.py2
-rw-r--r--addons/web/common/session.py1
-rw-r--r--addons/web/controllers/main.py60
-rw-r--r--addons/web/po/ar.po10
-rw-r--r--addons/web/po/de.po8
-rw-r--r--addons/web/po/pt_BR.po317
-rw-r--r--addons/web/po/ru.po268
-rw-r--r--addons/web/po/zh_CN.po32
-rw-r--r--addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js8
-rw-r--r--addons/web/static/src/css/base.css27
-rw-r--r--addons/web/static/src/js/chrome.js115
-rw-r--r--addons/web/static/src/js/core.js71
-rw-r--r--addons/web/static/src/js/data.js55
-rw-r--r--addons/web/static/src/js/data_export.js35
-rw-r--r--addons/web/static/src/js/data_import.js2
-rw-r--r--addons/web/static/src/js/formats.js65
-rw-r--r--addons/web/static/src/js/view_editor.js29
-rw-r--r--addons/web/static/src/js/view_form.js145
-rw-r--r--addons/web/static/src/js/view_list.js63
-rw-r--r--addons/web/static/src/js/view_list_editable.js9
-rw-r--r--addons/web/static/src/js/view_page.js7
-rw-r--r--addons/web/static/src/js/view_tree.js4
-rw-r--r--addons/web/static/src/js/views.js197
-rw-r--r--addons/web/static/src/xml/base.xml29
-rw-r--r--addons/web/static/test/formats.js11
-rw-r--r--addons/web/static/test/list-utils.js20
-rw-r--r--addons/web/static/test/test.html1
30 files changed, 917 insertions, 703 deletions
diff --git a/addons/web/__init__.py b/addons/web/__init__.py
index 06e7fa1f0e3..b09c8c213bc 100644
--- a/addons/web/__init__.py
+++ b/addons/web/__init__.py
@@ -12,11 +12,16 @@ def wsgi_postload():
import openerp
import os
import tempfile
+ import getpass
_logger.info("embedded mode")
o = Options()
o.dbfilter = openerp.tools.config['dbfilter']
o.server_wide_modules = openerp.conf.server_wide_modules or ['web']
- o.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions")
+ try:
+ username = getpass.getuser()
+ except Exception:
+ username = "unknown"
+ o.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
o.addons_path = openerp.modules.module.ad_paths
o.serve_static = True
o.backend = 'local'
diff --git a/addons/web/common/http.py b/addons/web/common/http.py
index f3ac8d0bcd9..17ccfb63d8a 100644
--- a/addons/web/common/http.py
+++ b/addons/web/common/http.py
@@ -10,6 +10,7 @@ import os
import pprint
import sys
import threading
+import time
import traceback
import urllib
import uuid
@@ -331,8 +332,9 @@ def session_context(request, storage_path, session_cookie='sessionid'):
if (isinstance(value, session.OpenERPSession)
and not value._uid
and not value.jsonp_requests
+ and value._creation_time + (60*5) < time.time() # FIXME do not use a fixed value
):
- _logger.info('remove session %s: %r', key, value.jsonp_requests)
+ _logger.debug('remove session %s', key)
del request.session[key]
with session_lock:
diff --git a/addons/web/common/openerplib/main.py b/addons/web/common/openerplib/main.py
index 2cbf9692063..93c2d1da69d 100644
--- a/addons/web/common/openerplib/main.py
+++ b/addons/web/common/openerplib/main.py
@@ -50,15 +50,6 @@ class Connector(object):
__logger = _getChildLogger(_logger, 'connector')
- def __init__(self, hostname, port):
- """
- Initilize by specifying an hostname and a port.
- :param hostname: Host name of the server.
- :param port: Port for the connection to the server.
- """
- self.hostname = hostname
- self.port = port
-
def get_service(self, service_name):
"""
Returns a Service instance to allow easy manipulation of one of the services offered by the remote server.
@@ -81,8 +72,7 @@ class XmlRPCConnector(Connector):
:param hostname: The hostname of the computer holding the instance of OpenERP.
:param port: The port used by the OpenERP instance for XMLRPC (default to 8069).
"""
- Connector.__init__(self, hostname, port)
- self.url = 'http://%s:%d/xmlrpc' % (self.hostname, self.port)
+ self.url = 'http://%s:%d/xmlrpc' % (hostname, port)
def send(self, service_name, method, *args):
url = '%s/%s' % (self.url, service_name)
@@ -97,9 +87,9 @@ class XmlRPCSConnector(XmlRPCConnector):
__logger = _getChildLogger(_logger, 'connector.xmlrpcs')
- def __init__(self, hostname, port=8071):
+ def __init__(self, hostname, port=8069):
super(XmlRPCSConnector, self).__init__(hostname, port)
- self.url = 'https://%s:%d/xmlrpc' % (self.hostname, self.port)
+ self.url = 'https://%s:%d/xmlrpc' % (hostname, port)
class Service(object):
"""
@@ -294,7 +284,7 @@ def get_connector(hostname=None, protocol="xmlrpc", port="auto"):
:param port: The number of the port. Defaults to auto.
"""
if port == 'auto':
- port = 8069 if protocol=="xmlrpc" else 8071
+ port = 8069
if protocol == "xmlrpc":
return XmlRPCConnector(hostname, port)
elif protocol == "xmlrpcs":
diff --git a/addons/web/common/release.py b/addons/web/common/release.py
index 47570c032bb..fdc30ee33d7 100644
--- a/addons/web/common/release.py
+++ b/addons/web/common/release.py
@@ -1,5 +1,5 @@
name = 'openerp-web'
-version = '6.1.0 alpha'
+version = '6.1rc1'
description = "Web Client of OpenERP, the Enterprise Management Software"
long_description = "OpenERP Web is the web client of the OpenERP, a free enterprise management software"
author = "OpenERP SA"
diff --git a/addons/web/common/session.py b/addons/web/common/session.py
index ac0489b2ff3..ca23a08da4a 100644
--- a/addons/web/common/session.py
+++ b/addons/web/common/session.py
@@ -29,6 +29,7 @@ class OpenERPSession(object):
round-tripped to the client browser.
"""
def __init__(self):
+ self._creation_time = time.time()
self.config = None
self._db = False
self._uid = False
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index e8760eca203..3a23556794a 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -18,6 +18,10 @@ from cStringIO import StringIO
import babel.messages.pofile
import werkzeug.utils
+try:
+ import xlwt
+except ImportError:
+ xlwt = None
from .. import common
openerpweb = common.http
@@ -33,6 +37,9 @@ def concat_xml(file_list):
concat: concatenation of file content
timestamp: max(os.path.getmtime of file_list)
"""
+ if not file_list:
+ return '', None
+
root = None
files_timestamp = 0
for fname in file_list:
@@ -52,12 +59,15 @@ def concat_xml(file_list):
return ElementTree.tostring(root, 'utf-8'), files_timestamp
-def concat_files(file_list, reader=None):
+def concat_files(file_list, reader=None, intersperse=""):
""" Concatenate file content
return (concat,timestamp)
concat: concatenation of file content, read by `reader`
timestamp: max(os.path.getmtime of file_list)
"""
+ if not file_list:
+ return '', None
+
if reader is None:
def reader(f):
with open(f) as fp:
@@ -71,7 +81,7 @@ def concat_files(file_list, reader=None):
files_timestamp = ftime
files_content.append(reader(fname))
- files_concat = "".join(files_content)
+ files_concat = intersperse.join(files_content)
return files_concat,files_timestamp
html_template = """<!DOCTYPE html>
@@ -176,7 +186,7 @@ class WebClient(openerpweb.Controller):
@openerpweb.httprequest
def js(self, req, mods=None):
files = [f[0] for f in self.manifest_glob(req, mods, 'js')]
- content,timestamp = concat_files(files)
+ content, timestamp = concat_files(files, intersperse=';')
# TODO use timestamp to set Last mofified date and E-tag
return req.make_response(content, [('Content-Type', 'application/javascript')])
@@ -427,7 +437,7 @@ class Session(openerpweb.Controller):
@openerpweb.jsonrequest
def modules(self, req):
# Compute available candidates module
- loadable = openerpweb.addons_manifest.iterkeys()
+ loadable = openerpweb.addons_manifest
loaded = req.config.server_wide_modules
candidates = [mod for mod in loadable if mod not in loaded]
@@ -1184,23 +1194,40 @@ class Binary(openerpweb.Controller):
return open(os.path.join(addons_path, 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
@openerpweb.httprequest
- def saveas(self, req, model, id, field, fieldname, **kw):
+ def saveas(self, req, model, field, id=None, filename_field=None, **kw):
+ """ Download link for files stored as binary fields.
+
+ If the ``id`` parameter is omitted, fetches the default value for the
+ binary field (via ``default_get``), otherwise fetches the field for
+ that precise record.
+
+ :param req: OpenERP request
+ :type req: :class:`web.common.http.HttpRequest`
+ :param str model: name of the model to fetch the binary from
+ :param str field: binary field
+ :param str id: id of the record from which to fetch the binary
+ :param str filename_field: field holding the file's name, if any
+ :returns: :class:`werkzeug.wrappers.Response`
+ """
Model = req.session.model(model)
context = req.session.eval_context(req.context)
+ fields = [field]
+ if filename_field:
+ fields.append(filename_field)
if id:
- res = Model.read([int(id)], [field, fieldname], context)[0]
+ res = Model.read([int(id)], fields, context)[0]
else:
- res = Model.default_get([field, fieldname], context)
+ res = Model.default_get(fields, context)
filecontent = base64.b64decode(res.get(field, ''))
if not filecontent:
return req.not_found()
else:
filename = '%s_%s' % (model.replace('.', '_'), id)
- if fieldname:
- filename = res.get(fieldname, '') or filename
+ if filename_field:
+ filename = res.get(filename_field, '') or filename
return req.make_response(filecontent,
[('Content-Type', 'application/octet-stream'),
- ('Content-Disposition', 'attachment; filename=' + filename)])
+ ('Content-Disposition', 'attachment; filename="%s"' % filename)])
@openerpweb.httprequest
def upload(self, req, callback, ufile):
@@ -1240,6 +1267,7 @@ class Binary(openerpweb.Controller):
attachment_id = Model.create({
'name': ufile.filename,
'datas': base64.encodestring(ufile.read()),
+ 'datas_fname': ufile.filename,
'res_model': model,
'res_id': int(id)
}, context)
@@ -1290,7 +1318,7 @@ class Export(View):
for path, controller in openerpweb.controllers_path.iteritems()
if path.startswith(self._cp_path)
if hasattr(controller, 'fmt')
- ], key=operator.itemgetter(1))
+ ], key=operator.itemgetter("label"))
def fields_get(self, req, model):
Model = req.session.model(model)
@@ -1466,7 +1494,7 @@ class Export(View):
class CSVExport(Export):
_cp_path = '/web/export/csv'
- fmt = ('csv', 'CSV')
+ fmt = {'tag': 'csv', 'label': 'CSV'}
@property
def content_type(self):
@@ -1501,7 +1529,11 @@ class CSVExport(Export):
class ExcelExport(Export):
_cp_path = '/web/export/xls'
- fmt = ('xls', 'Excel')
+ fmt = {
+ 'tag': 'xls',
+ 'label': 'Excel',
+ 'error': None if xlwt else "XLWT required"
+ }
@property
def content_type(self):
@@ -1511,8 +1543,6 @@ class ExcelExport(Export):
return base + '.xls'
def from_data(self, fields, rows):
- import xlwt
-
workbook = xlwt.Workbook()
worksheet = workbook.add_sheet('Sheet 1')
diff --git a/addons/web/po/ar.po b/addons/web/po/ar.po
index dba4f6ffb8b..e52b58ca375 100644
--- a/addons/web/po/ar.po
+++ b/addons/web/po/ar.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-12-20 18:48+0100\n"
-"PO-Revision-Date: 2012-01-08 20:20+0000\n"
+"PO-Revision-Date: 2012-01-13 21:31+0000\n"
"Last-Translator: kifcaliph <Unknown>\n"
"Language-Team: Arabic <ar@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-01-09 05:08+0000\n"
-"X-Generator: Launchpad (build 14640)\n"
+"X-Launchpad-Export-Date: 2012-01-14 05:40+0000\n"
+"X-Generator: Launchpad (build 14664)\n"
#: addons/web/static/src/js/chrome.js:162
#: addons/web/static/src/js/chrome.js:175
@@ -727,11 +727,11 @@ msgstr "خيار:"
#: addons/web/static/src/xml/base.xml:0
msgid "["
-msgstr "]"
+msgstr "["
#: addons/web/static/src/xml/base.xml:0
msgid "]"
-msgstr "["
+msgstr "]"
#: addons/web/static/src/xml/base.xml:0
msgid "-"
diff --git a/addons/web/po/de.po b/addons/web/po/de.po
index 18f69022ef8..bfbb97fa7dc 100644
--- a/addons/web/po/de.po
+++ b/addons/web/po/de.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-12-20 18:48+0100\n"
-"PO-Revision-Date: 2011-12-26 13:55+0000\n"
+"PO-Revision-Date: 2012-01-12 17:29+0000\n"
"Last-Translator: Ferdinand @ Camptocamp <Unknown>\n"
"Language-Team: German <de@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-01-04 05:17+0000\n"
-"X-Generator: Launchpad (build 14616)\n"
+"X-Launchpad-Export-Date: 2012-01-13 05:01+0000\n"
+"X-Generator: Launchpad (build 14664)\n"
#: addons/web/static/src/js/chrome.js:162
#: addons/web/static/src/js/chrome.js:175
@@ -666,7 +666,7 @@ msgstr "/"
#: addons/web/static/src/xml/base.xml:0
msgid "Duplicate"
-msgstr "Kopieren"
+msgstr "Duplizieren"
#: addons/web/static/src/xml/base.xml:0
msgid "Unhandled widget"
diff --git a/addons/web/po/pt_BR.po b/addons/web/po/pt_BR.po
index 5246b219971..4be0c66826c 100644
--- a/addons/web/po/pt_BR.po
+++ b/addons/web/po/pt_BR.po
@@ -8,14 +8,15 @@ msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-12-20 18:48+0100\n"
-"PO-Revision-Date: 2011-11-12 18:57+0000\n"
-"Last-Translator: Cristiano Gavião <Unknown>\n"
+"PO-Revision-Date: 2012-01-15 02:47+0000\n"
+"Last-Translator: Renato Lima - http://www.akretion.com "
+"<renatonlima@gmail.com>\n"
"Language-Team: Brazilian Portuguese <pt_BR@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-01-04 05:17+0000\n"
-"X-Generator: Launchpad (build 14616)\n"
+"X-Launchpad-Export-Date: 2012-01-16 05:27+0000\n"
+"X-Generator: Launchpad (build 14664)\n"
#: addons/web/static/src/js/chrome.js:162
#: addons/web/static/src/js/chrome.js:175
@@ -28,15 +29,15 @@ msgstr "Ok"
#: addons/web/static/src/js/chrome.js:668
msgid "About"
-msgstr ""
+msgstr "Sobre"
#: addons/web/static/src/js/chrome.js:748
msgid "Preferences"
-msgstr ""
+msgstr "Preferências"
#: addons/web/static/src/js/chrome.js:752
msgid "Change password"
-msgstr ""
+msgstr "Alterar Senha"
#: addons/web/static/src/js/chrome.js:753
#: addons/web/static/src/js/search.js:235
@@ -53,15 +54,15 @@ msgstr "Cancelar"
#: addons/web/static/src/js/view_editor.js:75
#: addons/web/static/src/js/views.js:871 addons/web/static/src/xml/base.xml:0
msgid "Save"
-msgstr ""
+msgstr "Salvar"
#: addons/web/static/src/js/chrome.js:774 addons/web/static/src/xml/base.xml:0
msgid "Change Password"
-msgstr ""
+msgstr "Alterar Senha"
#: addons/web/static/src/js/data_export.js:6
msgid "Export Data"
-msgstr ""
+msgstr "Exportar Dados"
#: addons/web/static/src/js/data_export.js:23
#: addons/web/static/src/js/data_import.js:73
@@ -74,36 +75,36 @@ msgstr "Fechar"
#: addons/web/static/src/js/data_export.js:24
msgid "Export To File"
-msgstr ""
+msgstr "Exportar para Arquivo"
#: addons/web/static/src/js/data_import.js:34
msgid "Import Data"
-msgstr ""
+msgstr "Importar Dados"
#: addons/web/static/src/js/data_import.js:74
msgid "Import File"
-msgstr ""
+msgstr "Importar Arquivo"
#: addons/web/static/src/js/data_import.js:109
msgid "External ID"
-msgstr ""
+msgstr "ID Externo"
#: addons/web/static/src/js/search.js:233
msgid "Filter Entry"
-msgstr ""
+msgstr "Filtrar Entrada"
#: addons/web/static/src/js/search.js:238
#: addons/web/static/src/js/search.js:279
msgid "OK"
-msgstr ""
+msgstr "OK"
#: addons/web/static/src/js/search.js:274 addons/web/static/src/xml/base.xml:0
msgid "Add to Dashboard"
-msgstr ""
+msgstr "Adicionar ao Dashboard"
#: addons/web/static/src/js/search.js:403
msgid "Invalid Search"
-msgstr ""
+msgstr "Pesquisa Inválida"
#: addons/web/static/src/js/search.js:403
msgid "triggered from search view"
@@ -112,31 +113,31 @@ msgstr ""
#: addons/web/static/src/js/search.js:490
#, python-format
msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s"
-msgstr ""
+msgstr "Valor incorreto para campo %(fieldname)s: [%(value)s] é %(message)s"
#: addons/web/static/src/js/search.js:822
msgid "not a valid integer"
-msgstr ""
+msgstr "Não é um número inteiro"
#: addons/web/static/src/js/search.js:836
msgid "not a valid number"
-msgstr ""
+msgstr "Não é um número válido"
#: addons/web/static/src/js/search.js:898
msgid "Yes"
-msgstr ""
+msgstr "Sim"
#: addons/web/static/src/js/search.js:899
msgid "No"
-msgstr ""
+msgstr "Não"
#: addons/web/static/src/js/search.js:1252
msgid "contains"
-msgstr ""
+msgstr "Contém"
#: addons/web/static/src/js/search.js:1253
msgid "doesn't contain"
-msgstr ""
+msgstr "Não contém"
#: addons/web/static/src/js/search.js:1254
#: addons/web/static/src/js/search.js:1269
@@ -144,7 +145,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1309
#: addons/web/static/src/js/search.js:1331
msgid "is equal to"
-msgstr ""
+msgstr "É igual a"
#: addons/web/static/src/js/search.js:1255
#: addons/web/static/src/js/search.js:1270
@@ -152,7 +153,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1310
#: addons/web/static/src/js/search.js:1332
msgid "is not equal to"
-msgstr ""
+msgstr "É diferente de"
#: addons/web/static/src/js/search.js:1256
#: addons/web/static/src/js/search.js:1271
@@ -160,7 +161,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1311
#: addons/web/static/src/js/search.js:1333
msgid "greater than"
-msgstr ""
+msgstr "Maior que"
#: addons/web/static/src/js/search.js:1257
#: addons/web/static/src/js/search.js:1272
@@ -168,7 +169,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1312
#: addons/web/static/src/js/search.js:1334
msgid "less than"
-msgstr ""
+msgstr "Menor que"
#: addons/web/static/src/js/search.js:1258
#: addons/web/static/src/js/search.js:1273
@@ -176,7 +177,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1313
#: addons/web/static/src/js/search.js:1335
msgid "greater or equal than"
-msgstr ""
+msgstr "Maior ou igual que"
#: addons/web/static/src/js/search.js:1259
#: addons/web/static/src/js/search.js:1274
@@ -184,28 +185,28 @@ msgstr ""
#: addons/web/static/src/js/search.js:1314
#: addons/web/static/src/js/search.js:1336
msgid "less or equal than"
-msgstr ""
+msgstr "Menor ou igual que"
#: addons/web/static/src/js/search.js:1325
#: addons/web/static/src/js/search.js:1350
msgid "is"
-msgstr ""
+msgstr "É"
#: addons/web/static/src/js/search.js:1351
msgid "is not"
-msgstr ""
+msgstr "Não é"
#: addons/web/static/src/js/search.js:1364
msgid "is true"
-msgstr ""
+msgstr "Verdadeiro"
#: addons/web/static/src/js/search.js:1365
msgid "is false"
-msgstr ""
+msgstr "Falso"
#: addons/web/static/src/js/view_editor.js:42
msgid "ViewEditor"
-msgstr ""
+msgstr "Editor de Visão"
#: addons/web/static/src/js/view_editor.js:46
#: addons/web/static/src/js/view_list.js:17
@@ -216,7 +217,7 @@ msgstr "Criar"
#: addons/web/static/src/js/view_editor.js:47
#: addons/web/static/src/xml/base.xml:0
msgid "Edit"
-msgstr ""
+msgstr "Editar"
#: addons/web/static/src/js/view_editor.js:48
#: addons/web/static/src/xml/base.xml:0
@@ -226,38 +227,38 @@ msgstr "Remover"
#: addons/web/static/src/js/view_editor.js:71
#, python-format
msgid "Create a view (%s)"
-msgstr ""
+msgstr "Criar a visão (%s)"
#: addons/web/static/src/js/view_editor.js:170
msgid "Do you really want to remove this view?"
-msgstr ""
+msgstr "Deseja remover essa visão?"
#: addons/web/static/src/js/view_editor.js:367
#, python-format
msgid "View Editor %d - %s"
-msgstr ""
+msgstr "Editar Visão %d - %s"
#: addons/web/static/src/js/view_editor.js:371
msgid "Preview"
-msgstr ""
+msgstr "Pré-visualizar"
#: addons/web/static/src/js/view_editor.js:442
msgid "Do you really want to remove this node?"
-msgstr ""
+msgstr "Deseja remover esse nó?"
#: addons/web/static/src/js/view_editor.js:756
#: addons/web/static/src/js/view_editor.js:883
msgid "Properties"
-msgstr ""
+msgstr "Propriedades"
#: addons/web/static/src/js/view_editor.js:760
#: addons/web/static/src/js/view_editor.js:887
msgid "Update"
-msgstr ""
+msgstr "Atualizar"
#: addons/web/static/src/js/view_form.js:17
msgid "Form"
-msgstr ""
+msgstr "Formulário"
#: addons/web/static/src/js/view_form.js:401
msgid ""
@@ -266,16 +267,16 @@ msgstr "Aviso, o registro foi modificado, suas alterações serão descartadas."
#: addons/web/static/src/js/view_form.js:612
msgid "Attachments"
-msgstr ""
+msgstr "Anexos"
#: addons/web/static/src/js/view_form.js:650
#, python-format
msgid "Do you really want to delete the attachment %s?"
-msgstr ""
+msgstr "Deseja remover esse anexo %s?"
#: addons/web/static/src/js/view_form.js:1075
msgid "Confirm"
-msgstr ""
+msgstr "Confirmar"
#: addons/web/static/src/js/view_form.js:1838
msgid "<em>   Search More...</em>"
@@ -284,11 +285,11 @@ msgstr "<em>   Procurar Mais...</em>"
#: addons/web/static/src/js/view_form.js:1851
#, python-format
msgid "<em>   Create \"<strong>%s</strong>\"</em>"
-msgstr ""
+msgstr "<em>   Criar \"<strong>%s</strong>\"</em>"
#: addons/web/static/src/js/view_form.js:1857
msgid "<em>   Create and Edit...</em>"
-msgstr ""
+msgstr "<em>   Criar e Editar...</em>"
#: addons/web/static/src/js/view_form.js:2404
#: addons/web/static/src/xml/base.xml:0
@@ -297,72 +298,72 @@ msgstr "Adicionar"
#: addons/web/static/src/js/view_list.js:8
msgid "List"
-msgstr ""
+msgstr "Lista"
#: addons/web/static/src/js/view_list.js:269
msgid "Unlimited"
-msgstr ""
+msgstr "Ilimitado"
#: addons/web/static/src/js/view_list.js:516
msgid "Do you really want to remove these records?"
-msgstr ""
+msgstr "Deseja remover esse registro?"
#: addons/web/static/src/js/view_list.js:1202
msgid "Undefined"
-msgstr ""
+msgstr "Indefinida"
#: addons/web/static/src/js/view_page.js:8
msgid "Page"
-msgstr ""
+msgstr "Página"
#: addons/web/static/src/js/view_page.js:52
msgid "Do you really want to delete this record?"
-msgstr ""
+msgstr "Deseja remover esse registro?"
#: addons/web/static/src/js/view_page.js:227
msgid "Download"
-msgstr ""
+msgstr "Download"
#: addons/web/static/src/js/view_tree.js:11
msgid "Tree"
-msgstr ""
+msgstr "Árvore"
#: addons/web/static/src/js/views.js:590
msgid "Search: "
-msgstr ""
+msgstr "Pesquisar: "
#: addons/web/static/src/js/views.js:710
msgid "Customize"
-msgstr ""
+msgstr "Customizar"
#: addons/web/static/src/js/views.js:713
msgid "Manage Views"
-msgstr ""
+msgstr "Administrar Visões"
#: addons/web/static/src/js/views.js:715 addons/web/static/src/js/views.js:719
#: addons/web/static/src/js/views.js:724
msgid "Manage views of the current object"
-msgstr ""
+msgstr "Adminsitrar visões do objeto atual"
#: addons/web/static/src/js/views.js:717
msgid "Edit Workflow"
-msgstr ""
+msgstr "Editar Workflow"
#: addons/web/static/src/js/views.js:722
msgid "Customize Object"
-msgstr ""
+msgstr "Customizar Objeto"
#: addons/web/static/src/js/views.js:726
msgid "Translate"
-msgstr ""
+msgstr "Traduzir"
#: addons/web/static/src/js/views.js:728
msgid "Technical translation"
-msgstr ""
+msgstr "Tradução Técnica"
#: addons/web/static/src/js/views.js:733
msgid "Other Options"
-msgstr ""
+msgstr "Outras Opções"
#: addons/web/static/src/js/views.js:736 addons/web/static/src/xml/base.xml:0
msgid "Import"
@@ -374,55 +375,55 @@ msgstr "Exportar"
#: addons/web/static/src/js/views.js:742
msgid "View Log"
-msgstr ""
+msgstr "Vizualizar Log"
#: addons/web/static/src/js/views.js:751
msgid "Reports"
-msgstr ""
+msgstr "Relatórios"
#: addons/web/static/src/js/views.js:751
msgid "Actions"
-msgstr ""
+msgstr "Ações"
#: addons/web/static/src/js/views.js:751
msgid "Links"
-msgstr ""
+msgstr "Links"
#: addons/web/static/src/js/views.js:831
msgid "You must choose at least one record."
-msgstr ""
+msgstr "Você deve escolher pelo menos um registro."
#: addons/web/static/src/js/views.js:832
msgid "Warning"
-msgstr ""
+msgstr "Atenção"
#: addons/web/static/src/js/views.js:866
msgid "Translations"
-msgstr ""
+msgstr "Traduções"
#: addons/web/static/src/xml/base.xml:0
msgid "x"
-msgstr ""
+msgstr "x"
#: addons/web/static/src/xml/base.xml:0
msgid "#{title}"
-msgstr ""
+msgstr "#{title}"
#: addons/web/static/src/xml/base.xml:0
msgid "#{text}"
-msgstr ""
+msgstr "#{text}"
#: addons/web/static/src/xml/base.xml:0
msgid "Powered by"
-msgstr ""
+msgstr "Desenvolvido Por"
#: addons/web/static/src/xml/base.xml:0
msgid "openerp.com"
-msgstr ""
+msgstr "openerp.com"
#: addons/web/static/src/xml/base.xml:0
msgid "."
-msgstr ""
+msgstr "."
#: addons/web/static/src/xml/base.xml:0
msgid "Loading..."
@@ -450,15 +451,15 @@ msgstr "Voltar ao Login"
#: addons/web/static/src/xml/base.xml:0
msgid "CREATE DATABASE"
-msgstr ""
+msgstr "CRIAR BANCO DE DADOS"
#: addons/web/static/src/xml/base.xml:0
msgid "Master password:"
-msgstr "Senha mestre"
+msgstr "Senha Super Admin:"
#: addons/web/static/src/xml/base.xml:0
msgid "New database name:"
-msgstr "Nome da nova base de dados:"
+msgstr "Nome do Novo banco de dados:"
#: addons/web/static/src/xml/base.xml:0
msgid "Load Demonstration data:"
@@ -470,31 +471,31 @@ msgstr "Idioma padrão:"
#: addons/web/static/src/xml/base.xml:0
msgid "Admin password:"
-msgstr "Senha de Administrador"
+msgstr "Senha do Administrador"
#: addons/web/static/src/xml/base.xml:0
msgid "Confirm password:"
-msgstr "Confirme a senha:"
+msgstr "Confirmar Senha:"
#: addons/web/static/src/xml/base.xml:0
msgid "DROP DATABASE"
-msgstr ""
+msgstr "EXCLUIR BANCO DE DADOS"
#: addons/web/static/src/xml/base.xml:0
msgid "Database:"
-msgstr "Base de dados:"
+msgstr "Banco de Dados:"
#: addons/web/static/src/xml/base.xml:0
msgid "Master Password:"
-msgstr "Senha Mestre"
+msgstr "Senha do Super Admin"
#: addons/web/static/src/xml/base.xml:0
msgid "BACKUP DATABASE"
-msgstr ""
+msgstr "BACKUP"
#: addons/web/static/src/xml/base.xml:0
msgid "RESTORE DATABASE"
-msgstr ""
+msgstr "RESTAURAR BANCO DE DADOS"
#: addons/web/static/src/xml/base.xml:0
msgid "File:"
@@ -502,15 +503,15 @@ msgstr "Arquivo:"
#: addons/web/static/src/xml/base.xml:0
msgid "CHANGE MASTER PASSWORD"
-msgstr ""
+msgstr "ALTERAR SENHA DO SUPER ADMIN"
#: addons/web/static/src/xml/base.xml:0
msgid "New master password:"
-msgstr "Nova senha mestre:"
+msgstr "Nova Senha do Super Admin:"
#: addons/web/static/src/xml/base.xml:0
msgid "Confirm new master password:"
-msgstr "Confirme nova senha mestre"
+msgstr "Confirme a Senha do Super Admin:"
#: addons/web/static/src/xml/base.xml:0
msgid "User:"
@@ -522,7 +523,7 @@ msgstr "Senha:"
#: addons/web/static/src/xml/base.xml:0
msgid "Database"
-msgstr "Base de dados"
+msgstr "Bando de Dados"
#: addons/web/static/src/xml/base.xml:0
msgid "Login"
@@ -542,11 +543,11 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:0
msgid "OpenERP's vision to be:"
-msgstr "OpenERP vislumbra ser:"
+msgstr "Visão do OpenERP"
#: addons/web/static/src/xml/base.xml:0
msgid "Full featured"
-msgstr ""
+msgstr "Todos os recursos"
#: addons/web/static/src/xml/base.xml:0
msgid ""
@@ -576,14 +577,16 @@ msgstr "Uso Amigável"
msgid ""
"In order to be productive, people need clean and easy to use interface."
msgstr ""
+"Para serem produtivas, as pessoas precisam de uma interface limpa e fácil de "
+"usar."
#: addons/web/static/src/xml/base.xml:0
msgid "("
-msgstr ""
+msgstr "("
#: addons/web/static/src/xml/base.xml:0
msgid ")"
-msgstr ""
+msgstr ")"
#: addons/web/static/src/xml/base.xml:0
msgid "LOGOUT"
@@ -591,35 +594,35 @@ msgstr "DESCONECTAR"
#: addons/web/static/src/xml/base.xml:0
msgid "&laquo;"
-msgstr ""
+msgstr "&laquo;"
#: addons/web/static/src/xml/base.xml:0
msgid "&raquo;"
-msgstr ""
+msgstr "&raquo;"
#: addons/web/static/src/xml/base.xml:0
msgid "oe_secondary_menu_item"
-msgstr ""
+msgstr "oe_secondary_menu_item"
#: addons/web/static/src/xml/base.xml:0
msgid "oe_secondary_submenu_item"
-msgstr ""
+msgstr "oe_secondary_submenu_item"
#: addons/web/static/src/xml/base.xml:0
msgid "Hide this tip"
-msgstr "Esconder dica"
+msgstr "Desativar esta dica"
#: addons/web/static/src/xml/base.xml:0
msgid "Disable all tips"
-msgstr "Desligar todas as dicas"
+msgstr "Desativar todas as dicas"
#: addons/web/static/src/xml/base.xml:0
msgid "More…"
-msgstr ""
+msgstr "Mais..."
#: addons/web/static/src/xml/base.xml:0
msgid "Debug View#"
-msgstr ""
+msgstr "Visão de Depuração#"
#: addons/web/static/src/xml/base.xml:0
msgid "- Fields View Get"
@@ -627,27 +630,27 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:0
msgid "- Edit"
-msgstr ""
+msgstr "Editar"
#: addons/web/static/src/xml/base.xml:0
msgid "View"
-msgstr ""
+msgstr "Visão"
#: addons/web/static/src/xml/base.xml:0
msgid "- Edit SearchView"
-msgstr ""
+msgstr "- Editar Visão de Busca"
#: addons/web/static/src/xml/base.xml:0
msgid "- Edit Action"
-msgstr ""
+msgstr "- Editar Ação"
#: addons/web/static/src/xml/base.xml:0
msgid "Field"
-msgstr ""
+msgstr "Campo"
#: addons/web/static/src/xml/base.xml:0
msgid ":"
-msgstr ""
+msgstr ":"
#: addons/web/static/src/xml/base.xml:0
msgid "Delete"
@@ -655,11 +658,11 @@ msgstr "Excluir"
#: addons/web/static/src/xml/base.xml:0
msgid "0"
-msgstr ""
+msgstr "0"
#: addons/web/static/src/xml/base.xml:0
msgid "/"
-msgstr ""
+msgstr "/"
#: addons/web/static/src/xml/base.xml:0
msgid "Duplicate"
@@ -675,75 +678,75 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:0
msgid "\""
-msgstr ""
+msgstr "\""
#: addons/web/static/src/xml/base.xml:0
msgid "Modifiers:"
-msgstr ""
+msgstr "Modificadores:"
#: addons/web/static/src/xml/base.xml:0
msgid "?"
-msgstr ""
+msgstr "?"
#: addons/web/static/src/xml/base.xml:0
msgid "(nolabel)"
-msgstr ""
+msgstr "(nolabel)"
#: addons/web/static/src/xml/base.xml:0
msgid "Field:"
-msgstr ""
+msgstr "Campo:"
#: addons/web/static/src/xml/base.xml:0
msgid "Object:"
-msgstr ""
+msgstr "Objeto:"
#: addons/web/static/src/xml/base.xml:0
msgid "Type:"
-msgstr ""
+msgstr "Tipo:"
#: addons/web/static/src/xml/base.xml:0
msgid "Widget:"
-msgstr ""
+msgstr "Componente:"
#: addons/web/static/src/xml/base.xml:0
msgid "Size:"
-msgstr ""
+msgstr "Tamanho:"
#: addons/web/static/src/xml/base.xml:0
msgid "Context:"
-msgstr ""
+msgstr "Contexto:"
#: addons/web/static/src/xml/base.xml:0
msgid "Domain:"
-msgstr ""
+msgstr "Domínio:"
#: addons/web/static/src/xml/base.xml:0
msgid "On change:"
-msgstr ""
+msgstr "Ao alterar:"
#: addons/web/static/src/xml/base.xml:0
msgid "Relation:"
-msgstr ""
+msgstr "Relação:"
#: addons/web/static/src/xml/base.xml:0
msgid "Selection:"
-msgstr ""
+msgstr "Seleção:"
#: addons/web/static/src/xml/base.xml:0
msgid "["
-msgstr ""
+msgstr "["
#: addons/web/static/src/xml/base.xml:0
msgid "]"
-msgstr ""
+msgstr "]"
#: addons/web/static/src/xml/base.xml:0
msgid "-"
-msgstr ""
+msgstr "-"
#: addons/web/static/src/xml/base.xml:0
msgid "#"
-msgstr ""
+msgstr "#"
#: addons/web/static/src/xml/base.xml:0
msgid "Open..."
@@ -763,7 +766,7 @@ msgstr "..."
#: addons/web/static/src/xml/base.xml:0
msgid "Uploading ..."
-msgstr "Transferindo ..."
+msgstr "Tranferindo..."
#: addons/web/static/src/xml/base.xml:0
msgid "Select"
@@ -771,7 +774,7 @@ msgstr "Selecionar"
#: addons/web/static/src/xml/base.xml:0
msgid "Save As"
-msgstr "Salvar como"
+msgstr "Salvar Como"
#: addons/web/static/src/xml/base.xml:0
msgid "Clear"
@@ -779,7 +782,7 @@ msgstr "Limpar"
#: addons/web/static/src/xml/base.xml:0
msgid "Button"
-msgstr ""
+msgstr "Botão"
#: addons/web/static/src/xml/base.xml:0
msgid "(no string)"
@@ -787,23 +790,23 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:0
msgid "Special:"
-msgstr ""
+msgstr "Especial:"
#: addons/web/static/src/xml/base.xml:0
msgid "Button Type:"
-msgstr ""
+msgstr "Tipo do Botão:"
#: addons/web/static/src/xml/base.xml:0
msgid "Method:"
-msgstr ""
+msgstr "Método:"
#: addons/web/static/src/xml/base.xml:0
msgid "Action ID:"
-msgstr ""
+msgstr "ID da Ação:"
#: addons/web/static/src/xml/base.xml:0
msgid "Search"
-msgstr ""
+msgstr "Pesquisar"
#: addons/web/static/src/xml/base.xml:0
msgid "Advanced Filter"
@@ -811,7 +814,7 @@ msgstr "Filtro Avançado"
#: addons/web/static/src/xml/base.xml:0
msgid "Save Filter"
-msgstr "Salvar filtro"
+msgstr "Salvar Filtro"
#: addons/web/static/src/xml/base.xml:0
msgid "Manage Filters"
@@ -827,15 +830,15 @@ msgstr "(Qualquer filtro existente com o mesmo nome será substituído)"
#: addons/web/static/src/xml/base.xml:0
msgid "Select Dashboard to add this filter to:"
-msgstr ""
+msgstr "Selecione o Dashboard para adicionar esse filtro para:"
#: addons/web/static/src/xml/base.xml:0
msgid "Title of new Dashboard item:"
-msgstr ""
+msgstr "Título do novo Dashboard:"
#: addons/web/static/src/xml/base.xml:0
msgid "Advanced Filters"
-msgstr ""
+msgstr "Filtros Avançados"
#: addons/web/static/src/xml/base.xml:0
msgid "Any of the following conditions must match"
@@ -919,19 +922,19 @@ msgstr "Salvar como:"
#: addons/web/static/src/xml/base.xml:0
msgid "Saved exports:"
-msgstr ""
+msgstr "Exportações salvas"
#: addons/web/static/src/xml/base.xml:0
msgid "Old Password:"
-msgstr "Senha antiga"
+msgstr "Senha Anterior"
#: addons/web/static/src/xml/base.xml:0
msgid "New Password:"
-msgstr "Nova Senha:"
+msgstr "Nova Senha"
#: addons/web/static/src/xml/base.xml:0
msgid "Confirm Password:"
-msgstr ""
+msgstr "Confirmar Senha:"
#: addons/web/static/src/xml/base.xml:0
msgid "1. Import a .CSV file"
@@ -945,7 +948,7 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:0
msgid "CSV File:"
-msgstr "Arquivo CSV."
+msgstr "Arquivo CSV:"
#: addons/web/static/src/xml/base.xml:0
msgid "2. Check your file format"
@@ -953,11 +956,11 @@ msgstr "Verifique seu formato de arquivo"
#: addons/web/static/src/xml/base.xml:0
msgid "Import Options"
-msgstr ""
+msgstr "Opções de importação"
#: addons/web/static/src/xml/base.xml:0
msgid "Does your file have titles?"
-msgstr ""
+msgstr "O seu arquivo tem títulos?"
#: addons/web/static/src/xml/base.xml:0
msgid "Separator:"
@@ -985,11 +988,11 @@ msgstr "Linhas para ignorar"
#: addons/web/static/src/xml/base.xml:0
msgid "The import failed due to:"
-msgstr ""
+msgstr "A importação falhou devido a:"
#: addons/web/static/src/xml/base.xml:0
msgid "Here is a preview of the file we could not import:"
-msgstr ""
+msgstr "Aqui está uma visualização do arquivo que não pode ser importado:"
#: addons/web/static/src/xml/base.xml:0
msgid "OpenERP Web"
@@ -1001,7 +1004,7 @@ msgstr "Versão"
#: addons/web/static/src/xml/base.xml:0
msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved."
-msgstr ""
+msgstr "Copyright © 2011-TODAY OpenERP SA. Todos Direitos Reservados."
#: addons/web/static/src/xml/base.xml:0
msgid "OpenERP is a trademark of the"
@@ -1009,7 +1012,7 @@ msgstr "OpenERP é uma marca de"
#: addons/web/static/src/xml/base.xml:0
msgid "OpenERP SA Company"
-msgstr ""
+msgstr "Empresa OpenERP SA"
#: addons/web/static/src/xml/base.xml:0
msgid "Licenced under the terms of"
@@ -1017,7 +1020,7 @@ msgstr "Licenciado sobre os termos de"
#: addons/web/static/src/xml/base.xml:0
msgid "GNU Affero General Public License"
-msgstr ""
+msgstr "Licença Pública Geral GNU Affero"
#: addons/web/static/src/xml/base.xml:0
msgid "About OpenERP"
@@ -1054,3 +1057,5 @@ msgid ""
"Depending on your needs, OpenERP is available through a web or application "
"client."
msgstr ""
+"Dependendo de suas necessidades, OpenERP está disponível através da web ou "
+"de uma aplicação cliente."
diff --git a/addons/web/po/ru.po b/addons/web/po/ru.po
index beecb0203c1..f218d259876 100644
--- a/addons/web/po/ru.po
+++ b/addons/web/po/ru.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-12-20 18:48+0100\n"
-"PO-Revision-Date: 2011-12-06 08:05+0000\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"PO-Revision-Date: 2012-01-13 12:50+0000\n"
+"Last-Translator: Aleksei Motsik <Unknown>\n"
"Language-Team: Russian <ru@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-01-04 05:17+0000\n"
-"X-Generator: Launchpad (build 14616)\n"
+"X-Launchpad-Export-Date: 2012-01-14 05:40+0000\n"
+"X-Generator: Launchpad (build 14664)\n"
#: addons/web/static/src/js/chrome.js:162
#: addons/web/static/src/js/chrome.js:175
@@ -24,19 +24,19 @@ msgstr ""
#: addons/web/static/src/js/view_form.js:1078
#: addons/web/static/src/xml/base.xml:0
msgid "Ok"
-msgstr ""
+msgstr "Ок"
#: addons/web/static/src/js/chrome.js:668
msgid "About"
-msgstr ""
+msgstr "О программе"
#: addons/web/static/src/js/chrome.js:748
msgid "Preferences"
-msgstr ""
+msgstr "Настройки"
#: addons/web/static/src/js/chrome.js:752
msgid "Change password"
-msgstr ""
+msgstr "Изменить пароль"
#: addons/web/static/src/js/chrome.js:753
#: addons/web/static/src/js/search.js:235
@@ -47,21 +47,21 @@ msgstr ""
#: addons/web/static/src/js/view_form.js:1085
#: addons/web/static/src/xml/base.xml:0
msgid "Cancel"
-msgstr ""
+msgstr "Отмена"
#: addons/web/static/src/js/chrome.js:754
#: addons/web/static/src/js/view_editor.js:75
#: addons/web/static/src/js/views.js:871 addons/web/static/src/xml/base.xml:0
msgid "Save"
-msgstr ""
+msgstr "Сохранить"
#: addons/web/static/src/js/chrome.js:774 addons/web/static/src/xml/base.xml:0
msgid "Change Password"
-msgstr ""
+msgstr "Изменить пароль"
#: addons/web/static/src/js/data_export.js:6
msgid "Export Data"
-msgstr ""
+msgstr "Экспорт данных"
#: addons/web/static/src/js/data_export.js:23
#: addons/web/static/src/js/data_import.js:73
@@ -70,40 +70,40 @@ msgstr ""
#: addons/web/static/src/js/view_form.js:2775
#: addons/web/static/src/js/views.js:872
msgid "Close"
-msgstr ""
+msgstr "Закрыть"
#: addons/web/static/src/js/data_export.js:24
msgid "Export To File"
-msgstr ""
+msgstr "Экспортировать в файл"
#: addons/web/static/src/js/data_import.js:34
msgid "Import Data"
-msgstr ""
+msgstr "Импорт данных"
#: addons/web/static/src/js/data_import.js:74
msgid "Import File"
-msgstr ""
+msgstr "Импортировать файл"
#: addons/web/static/src/js/data_import.js:109
msgid "External ID"
-msgstr ""
+msgstr "Внешний идентификатор"
#: addons/web/static/src/js/search.js:233
msgid "Filter Entry"
-msgstr ""
+msgstr "Входящий фильтр"
#: addons/web/static/src/js/search.js:238
#: addons/web/static/src/js/search.js:279
msgid "OK"
-msgstr ""
+msgstr "OK"
#: addons/web/static/src/js/search.js:274 addons/web/static/src/xml/base.xml:0
msgid "Add to Dashboard"
-msgstr ""
+msgstr "Добавить на Панель"
#: addons/web/static/src/js/search.js:403
msgid "Invalid Search"
-msgstr ""
+msgstr "Ошибка поиска"
#: addons/web/static/src/js/search.js:403
msgid "triggered from search view"
@@ -113,30 +113,31 @@ msgstr ""
#, python-format
msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s"
msgstr ""
+"Некорректное значение для поля %(fieldname)s: [%(value)s] в %(message)s"
#: addons/web/static/src/js/search.js:822
msgid "not a valid integer"
-msgstr ""
+msgstr "не является целым числом"
#: addons/web/static/src/js/search.js:836
msgid "not a valid number"
-msgstr ""
+msgstr "не является числом"
#: addons/web/static/src/js/search.js:898
msgid "Yes"
-msgstr ""
+msgstr "Да"
#: addons/web/static/src/js/search.js:899
msgid "No"
-msgstr ""
+msgstr "Нет"
#: addons/web/static/src/js/search.js:1252
msgid "contains"
-msgstr ""
+msgstr "содержит"
#: addons/web/static/src/js/search.js:1253
msgid "doesn't contain"
-msgstr ""
+msgstr "не содержит"
#: addons/web/static/src/js/search.js:1254
#: addons/web/static/src/js/search.js:1269
@@ -144,7 +145,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1309
#: addons/web/static/src/js/search.js:1331
msgid "is equal to"
-msgstr ""
+msgstr "соответствует"
#: addons/web/static/src/js/search.js:1255
#: addons/web/static/src/js/search.js:1270
@@ -152,7 +153,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1310
#: addons/web/static/src/js/search.js:1332
msgid "is not equal to"
-msgstr ""
+msgstr "не соответствует"
#: addons/web/static/src/js/search.js:1256
#: addons/web/static/src/js/search.js:1271
@@ -160,7 +161,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1311
#: addons/web/static/src/js/search.js:1333
msgid "greater than"
-msgstr ""
+msgstr "больше чем"
#: addons/web/static/src/js/search.js:1257
#: addons/web/static/src/js/search.js:1272
@@ -168,7 +169,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1312
#: addons/web/static/src/js/search.js:1334
msgid "less than"
-msgstr ""
+msgstr "меньше чем"
#: addons/web/static/src/js/search.js:1258
#: addons/web/static/src/js/search.js:1273
@@ -176,7 +177,7 @@ msgstr ""
#: addons/web/static/src/js/search.js:1313
#: addons/web/static/src/js/search.js:1335
msgid "greater or equal than"
-msgstr ""
+msgstr "больше или равен"
#: addons/web/static/src/js/search.js:1259
#: addons/web/static/src/js/search.js:1274
@@ -184,432 +185,437 @@ msgstr ""
#: addons/web/static/src/js/search.js:1314
#: addons/web/static/src/js/search.js:1336
msgid "less or equal than"
-msgstr ""
+msgstr "меньше или равен"
#: addons/web/static/src/js/search.js:1325
#: addons/web/static/src/js/search.js:1350
msgid "is"
-msgstr ""
+msgstr "-"
#: addons/web/static/src/js/search.js:1351
msgid "is not"
-msgstr ""
+msgstr "не"
#: addons/web/static/src/js/search.js:1364
msgid "is true"
-msgstr ""
+msgstr "истинно"
#: addons/web/static/src/js/search.js:1365
msgid "is false"
-msgstr ""
+msgstr "ложно"
#: addons/web/static/src/js/view_editor.js:42
msgid "ViewEditor"
-msgstr ""
+msgstr "Редактор Видов"
#: addons/web/static/src/js/view_editor.js:46
#: addons/web/static/src/js/view_list.js:17
#: addons/web/static/src/xml/base.xml:0
msgid "Create"
-msgstr ""
+msgstr "Создать"
#: addons/web/static/src/js/view_editor.js:47
#: addons/web/static/src/xml/base.xml:0
msgid "Edit"
-msgstr ""
+msgstr "Изменить"
#: addons/web/static/src/js/view_editor.js:48
#: addons/web/static/src/xml/base.xml:0
msgid "Remove"
-msgstr ""
+msgstr "Удалить"
#: addons/web/static/src/js/view_editor.js:71
#, python-format
msgid "Create a view (%s)"
-msgstr ""
+msgstr "Создать вид (%s)"
#: addons/web/static/src/js/view_editor.js:170
msgid "Do you really want to remove this view?"
-msgstr ""
+msgstr "Вы действительно хотите удалить этот Вид?"
#: addons/web/static/src/js/view_editor.js:367
#, python-format
msgid "View Editor %d - %s"
-msgstr ""
+msgstr "Редактор Вида %d - %s"
#: addons/web/static/src/js/view_editor.js:371
msgid "Preview"
-msgstr ""
+msgstr "Предпросмотр"
#: addons/web/static/src/js/view_editor.js:442
msgid "Do you really want to remove this node?"
-msgstr ""
+msgstr "Вы действительно хотите удалить этот Узел?"
#: addons/web/static/src/js/view_editor.js:756
#: addons/web/static/src/js/view_editor.js:883
msgid "Properties"
-msgstr ""
+msgstr "Свойства"
#: addons/web/static/src/js/view_editor.js:760
#: addons/web/static/src/js/view_editor.js:887
msgid "Update"
-msgstr ""
+msgstr "Обновить"
#: addons/web/static/src/js/view_form.js:17
msgid "Form"
-msgstr ""
+msgstr "Форма"
#: addons/web/static/src/js/view_form.js:401
msgid ""
"Warning, the record has been modified, your changes will be discarded."
-msgstr ""
+msgstr "Внимание. Эта запись была изменена. Ваши изменения будут потеряны."
#: addons/web/static/src/js/view_form.js:612
msgid "Attachments"
-msgstr ""
+msgstr "Вложения"
#: addons/web/static/src/js/view_form.js:650
#, python-format
msgid "Do you really want to delete the attachment %s?"
-msgstr ""
+msgstr "Вы действительно хотите удалить вложение %s?"
#: addons/web/static/src/js/view_form.js:1075
msgid "Confirm"
-msgstr ""
+msgstr "Подтвердить"
#: addons/web/static/src/js/view_form.js:1838
msgid "<em>   Search More...</em>"
-msgstr ""
+msgstr "<em>   Найти еще...</em>"
#: addons/web/static/src/js/view_form.js:1851
#, python-format
msgid "<em>   Create \"<strong>%s</strong>\"</em>"
-msgstr ""
+msgstr "<em>   Создать \"<strong>%s</strong>\"</em>"
#: addons/web/static/src/js/view_form.js:1857
msgid "<em>   Create and Edit...</em>"
-msgstr ""
+msgstr "<em>   Создать и Изменить...</em>"
#: addons/web/static/src/js/view_form.js:2404
#: addons/web/static/src/xml/base.xml:0
msgid "Add"
-msgstr ""
+msgstr "Добавить"
#: addons/web/static/src/js/view_list.js:8
msgid "List"
-msgstr ""
+msgstr "Список"
#: addons/web/static/src/js/view_list.js:269
msgid "Unlimited"
-msgstr ""
+msgstr "Неограниченно"
#: addons/web/static/src/js/view_list.js:516
msgid "Do you really want to remove these records?"
-msgstr ""
+msgstr "Вы действительно хотите удалить эту Запись?"
#: addons/web/static/src/js/view_list.js:1202
msgid "Undefined"
-msgstr ""
+msgstr "Не определено"
#: addons/web/static/src/js/view_page.js:8
msgid "Page"
-msgstr ""
+msgstr "Страница"
#: addons/web/static/src/js/view_page.js:52
msgid "Do you really want to delete this record?"
-msgstr ""
+msgstr "Вы действительно хотите удалить эту Запись?"
#: addons/web/static/src/js/view_page.js:227
msgid "Download"
-msgstr ""
+msgstr "Загрузить"
#: addons/web/static/src/js/view_tree.js:11
msgid "Tree"
-msgstr ""
+msgstr "Дерево"
#: addons/web/static/src/js/views.js:590
msgid "Search: "
-msgstr ""
+msgstr "Найти: "
#: addons/web/static/src/js/views.js:710
msgid "Customize"
-msgstr ""
+msgstr "Настроить"
#: addons/web/static/src/js/views.js:713
msgid "Manage Views"
-msgstr ""
+msgstr "Управление Видами"
#: addons/web/static/src/js/views.js:715 addons/web/static/src/js/views.js:719
#: addons/web/static/src/js/views.js:724
msgid "Manage views of the current object"
-msgstr ""
+msgstr "Управление Видами текущего объекта"
#: addons/web/static/src/js/views.js:717
msgid "Edit Workflow"
-msgstr ""
+msgstr "Редактировать Процесс"
#: addons/web/static/src/js/views.js:722
msgid "Customize Object"
-msgstr ""
+msgstr "Настроить Объект"
#: addons/web/static/src/js/views.js:726
msgid "Translate"
-msgstr ""
+msgstr "Перевести"
#: addons/web/static/src/js/views.js:728
msgid "Technical translation"
-msgstr ""
+msgstr "Технический перевод"
#: addons/web/static/src/js/views.js:733
msgid "Other Options"
-msgstr ""
+msgstr "Прочие Настройки"
#: addons/web/static/src/js/views.js:736 addons/web/static/src/xml/base.xml:0
msgid "Import"
-msgstr ""
+msgstr "Импорт"
#: addons/web/static/src/js/views.js:739 addons/web/static/src/xml/base.xml:0
msgid "Export"
-msgstr ""
+msgstr "Экспорт"
#: addons/web/static/src/js/views.js:742
msgid "View Log"
-msgstr ""
+msgstr "Просмотреть журнал"
#: addons/web/static/src/js/views.js:751
msgid "Reports"
-msgstr ""
+msgstr "Отчёты"
#: addons/web/static/src/js/views.js:751
msgid "Actions"
-msgstr ""
+msgstr "Действия"
#: addons/web/static/src/js/views.js:751
msgid "Links"
-msgstr ""
+msgstr "Связи"
#: addons/web/static/src/js/views.js:831
msgid "You must choose at least one record."
-msgstr ""
+msgstr "Вы должны выбрать хотя-бы одну запись."
#: addons/web/static/src/js/views.js:832
msgid "Warning"
-msgstr ""
+msgstr "Внимание"
#: addons/web/static/src/js/views.js:866
msgid "Translations"
-msgstr ""
+msgstr "Переводы"
#: addons/web/static/src/xml/base.xml:0
msgid "x"
-msgstr ""
+msgstr "x"
#: addons/web/static/src/xml/base.xml:0
msgid "#{title}"
-msgstr ""
+msgstr "#{title}"
#: addons/web/static/src/xml/base.xml:0
msgid "#{text}"
-msgstr ""
+msgstr "#{text}"
#: addons/web/static/src/xml/base.xml:0
msgid "Powered by"
-msgstr ""
+msgstr "На базе"
#: addons/web/static/src/xml/base.xml:0
msgid "openerp.com"
-msgstr ""
+msgstr "openerp.com"
#: addons/web/static/src/xml/base.xml:0
msgid "."
-msgstr ""
+msgstr "."
#: addons/web/static/src/xml/base.xml:0
msgid "Loading..."
-msgstr ""
+msgstr "Загрузка..."
#: addons/web/static/src/xml/base.xml:0
msgid "Drop"
-msgstr ""
+msgstr "Удалить"
#: addons/web/static/src/xml/base.xml:0
msgid "Backup"
-msgstr ""
+msgstr "Создать Резервную Копию"
#: addons/web/static/src/xml/base.xml:0
msgid "Restore"
-msgstr ""
+msgstr "Востановить"
#: addons/web/static/src/xml/base.xml:0
msgid "Password"
-msgstr ""
+msgstr "Пароль"
#: addons/web/static/src/xml/base.xml:0
msgid "Back to Login"
-msgstr ""
+msgstr "Вернутся к Авторизации"
#: addons/web/static/src/xml/base.xml:0
msgid "CREATE DATABASE"
-msgstr ""
+msgstr "СОЗДАТЬ БАЗУ ДАННЫХ"
#: addons/web/static/src/xml/base.xml:0
msgid "Master password:"
-msgstr ""
+msgstr "Мастер пароль:"
#: addons/web/static/src/xml/base.xml:0
msgid "New database name:"
-msgstr ""
+msgstr "Название новой базы данных:"
#: addons/web/static/src/xml/base.xml:0
msgid "Load Demonstration data:"
-msgstr ""
+msgstr "Загрузить Демонстрационные данные:"
#: addons/web/static/src/xml/base.xml:0
msgid "Default language:"
-msgstr ""
+msgstr "Язык по умолчанию:"
#: addons/web/static/src/xml/base.xml:0
msgid "Admin password:"
-msgstr ""
+msgstr "Пароль Администратора:"
#: addons/web/static/src/xml/base.xml:0
msgid "Confirm password:"
-msgstr ""
+msgstr "Подтверждение пароля:"
#: addons/web/static/src/xml/base.xml:0
msgid "DROP DATABASE"
-msgstr ""
+msgstr "УДАЛИТЬ БАЗУ ДАННЫХ"
#: addons/web/static/src/xml/base.xml:0
msgid "Database:"
-msgstr ""
+msgstr "База данных:"
#: addons/web/static/src/xml/base.xml:0
msgid "Master Password:"
-msgstr ""
+msgstr "Мастер Пароль:"
#: addons/web/static/src/xml/base.xml:0
msgid "BACKUP DATABASE"
-msgstr ""
+msgstr "РЕЗЕРВНАЯ КОПИЯ БД"
#: addons/web/static/src/xml/base.xml:0
msgid "RESTORE DATABASE"
-msgstr ""
+msgstr "ВОССТАНОВИТЬ БД"
#: addons/web/static/src/xml/base.xml:0
msgid "File:"
-msgstr ""
+msgstr "Файл:"
#: addons/web/static/src/xml/base.xml:0
msgid "CHANGE MASTER PASSWORD"
-msgstr ""
+msgstr "ИЗМЕНИТЬ МАСТЕР ПАРОЛЬ"
#: addons/web/static/src/xml/base.xml:0
msgid "New master password:"
-msgstr ""
+msgstr "Новый Мастер Пароль:"
#: addons/web/static/src/xml/base.xml:0
msgid "Confirm new master password:"
-msgstr ""
+msgstr "Подтверждение Мастер Пароля:"
#: addons/web/static/src/xml/base.xml:0
msgid "User:"
-msgstr ""
+msgstr "Пользователь:"
#: addons/web/static/src/xml/base.xml:0
msgid "Password:"
-msgstr ""
+msgstr "Пароль:"
#: addons/web/static/src/xml/base.xml:0
msgid "Database"
-msgstr ""
+msgstr "База данных"
#: addons/web/static/src/xml/base.xml:0
msgid "Login"
-msgstr ""
+msgstr "Авторизация"
#: addons/web/static/src/xml/base.xml:0
msgid "Bad username or password"
-msgstr ""
+msgstr "Неверное имя пользователя или пароль"
#: addons/web/static/src/xml/base.xml:0
msgid ""
"We think that daily job activities can be more intuitive, efficient, "
"automated, .. and even fun."
msgstr ""
+"Мы считаем, что повседневная деятельность может быть более простой, "
+"эффективной, автоматизированной... и даже веселой."
#: addons/web/static/src/xml/base.xml:0
msgid "OpenERP's vision to be:"
-msgstr ""
+msgstr "OpenERP's видение"
#: addons/web/static/src/xml/base.xml:0
msgid "Full featured"
-msgstr ""
+msgstr "Полнофункциональный"
#: addons/web/static/src/xml/base.xml:0
msgid ""
"Today's enterprise challenges are multiple. We provide one module for each "
"need."
msgstr ""
+"Настоящее бросает вызов Предприятиям. Мы предоставляем один модуль для "
+"удовлетворения всех потребностей."
#: addons/web/static/src/xml/base.xml:0
msgid "Open Source"
-msgstr ""
+msgstr "Открытое ПО"
#: addons/web/static/src/xml/base.xml:0
msgid ""
"To Build a great product, we rely on the knowledge of thousands of "
"contributors."
msgstr ""
+"Для создать отличного продукта, мы опирались на знания тысяч участников."
#: addons/web/static/src/xml/base.xml:0
msgid "User Friendly"
-msgstr ""
+msgstr "Дружественный"
#: addons/web/static/src/xml/base.xml:0
msgid ""
"In order to be productive, people need clean and easy to use interface."
-msgstr ""
+msgstr "Для продуктивной работы, людям необходим легкий и простой интерфейс."
#: addons/web/static/src/xml/base.xml:0
msgid "("
-msgstr ""
+msgstr "("
#: addons/web/static/src/xml/base.xml:0
msgid ")"
-msgstr ""
+msgstr ")"
#: addons/web/static/src/xml/base.xml:0
msgid "LOGOUT"
-msgstr ""
+msgstr "ВЫЙТИ"
#: addons/web/static/src/xml/base.xml:0
msgid "&laquo;"
-msgstr ""
+msgstr "&laquo;"
#: addons/web/static/src/xml/base.xml:0
msgid "&raquo;"
-msgstr ""
+msgstr "&raquo;"
#: addons/web/static/src/xml/base.xml:0
msgid "oe_secondary_menu_item"
-msgstr ""
+msgstr "oe_secondary_menu_item"
#: addons/web/static/src/xml/base.xml:0
msgid "oe_secondary_submenu_item"
-msgstr ""
+msgstr "oe_secondary_submenu_item"
#: addons/web/static/src/xml/base.xml:0
msgid "Hide this tip"
-msgstr ""
+msgstr "Скрыть подсказку"
#: addons/web/static/src/xml/base.xml:0
msgid "Disable all tips"
-msgstr ""
+msgstr "Отключить все подсказки"
#: addons/web/static/src/xml/base.xml:0
msgid "More…"
-msgstr ""
+msgstr "Больше..."
#: addons/web/static/src/xml/base.xml:0
msgid "Debug View#"
diff --git a/addons/web/po/zh_CN.po b/addons/web/po/zh_CN.po
index 536a3761360..087c66bd3b3 100644
--- a/addons/web/po/zh_CN.po
+++ b/addons/web/po/zh_CN.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-12-20 18:48+0100\n"
-"PO-Revision-Date: 2012-01-07 15:30+0000\n"
+"PO-Revision-Date: 2012-01-12 05:44+0000\n"
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.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-01-08 05:27+0000\n"
-"X-Generator: Launchpad (build 14640)\n"
+"X-Launchpad-Export-Date: 2012-01-13 05:01+0000\n"
+"X-Generator: Launchpad (build 14664)\n"
#: addons/web/static/src/js/chrome.js:162
#: addons/web/static/src/js/chrome.js:175
@@ -358,7 +358,7 @@ msgstr "翻译"
#: addons/web/static/src/js/views.js:728
msgid "Technical translation"
-msgstr ""
+msgstr "技术翻译"
#: addons/web/static/src/js/views.js:733
msgid "Other Options"
@@ -585,19 +585,19 @@ msgstr "注销"
#: addons/web/static/src/xml/base.xml:0
msgid "&laquo;"
-msgstr ""
+msgstr "&laquo;"
#: addons/web/static/src/xml/base.xml:0
msgid "&raquo;"
-msgstr ""
+msgstr "&raquo;"
#: addons/web/static/src/xml/base.xml:0
msgid "oe_secondary_menu_item"
-msgstr ""
+msgstr "oe_secondary_menu_item"
#: addons/web/static/src/xml/base.xml:0
msgid "oe_secondary_submenu_item"
-msgstr ""
+msgstr "oe_secondary_submenu_item"
#: addons/web/static/src/xml/base.xml:0
msgid "Hide this tip"
@@ -661,7 +661,7 @@ msgstr "复制"
#: addons/web/static/src/xml/base.xml:0
msgid "Unhandled widget"
-msgstr ""
+msgstr "未处理的窗口部件"
#: addons/web/static/src/xml/base.xml:0
msgid "Notebook Page \""
@@ -725,19 +725,19 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:0
msgid "["
-msgstr ""
+msgstr "["
#: addons/web/static/src/xml/base.xml:0
msgid "]"
-msgstr ""
+msgstr "]"
#: addons/web/static/src/xml/base.xml:0
msgid "-"
-msgstr ""
+msgstr "-"
#: addons/web/static/src/xml/base.xml:0
msgid "#"
-msgstr ""
+msgstr "#"
#: addons/web/static/src/xml/base.xml:0
msgid "Open..."
@@ -817,7 +817,7 @@ msgstr "过滤器名称:"
#: addons/web/static/src/xml/base.xml:0
msgid "(Any existing filter with the same name will be replaced)"
-msgstr ""
+msgstr "(任何已存在的同名过滤器都会被替换)"
#: addons/web/static/src/xml/base.xml:0
msgid "Select Dashboard to add this filter to:"
@@ -866,6 +866,8 @@ msgid ""
" You can export all data or only the fields that can be "
"reimported after modification."
msgstr ""
+"此向导将导出所有符合当前搜索条件的数据到 CSV 文件。\n"
+" 您也可以导出所有数据或选择在修改了 CSV 文件以后还能够重新导入的那些字段。"
#: addons/web/static/src/xml/base.xml:0
msgid "Export Type:"
@@ -1007,7 +1009,7 @@ msgstr "OpenERP SA 公司"
#: addons/web/static/src/xml/base.xml:0
msgid "Licenced under the terms of"
-msgstr ""
+msgstr "采用的授权协议"
#: addons/web/static/src/xml/base.xml:0
msgid "GNU Affero General Public License"
diff --git a/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js b/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js
index 2356f3b606b..47f542e5d39 100644
--- a/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js
+++ b/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js
@@ -65,8 +65,10 @@
display(index,this,e,options);
return false;
};
- $(this).bind('contextmenu', callback);
- if(options.leftClickToo) {
+ if (!options.noRightClick) {
+ $(this).bind('contextmenu', callback);
+ }
+ if (options.leftClickToo || options.noRightClick) {
$(this).click(callback);
}
return this
@@ -123,4 +125,4 @@
})(jQuery);
$( function() {
$('div.contextMenu').hide()
-}); \ No newline at end of file
+});
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index df6d78e8aa5..d4bd7a6ff1b 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -437,6 +437,7 @@ label.error {
position: absolute;
cursor: pointer;
border-left: 1px solid #282828;
+ border-bottom: 1px solid #282828;
width: 21px;
height: 21px;
z-index: 10;
@@ -518,6 +519,11 @@ label.error {
.openerp a.oe_secondary_submenu_item {
padding: 0 5px 2px 10px;
}
+.openerp a.oe_secondary_submenu_item,
+.openerp a.oe_secondary_menu_item {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
.openerp a.oe_secondary_submenu_item:hover,
.openerp a.oe_secondary_submenu_item.leaf.active {
display: block;
@@ -2033,6 +2039,7 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
.openerp .oe_vm_switch_form,
.openerp .oe_vm_switch_page,
+.openerp .oe_vm_switch_tree,
.openerp .oe_vm_switch_list,
.openerp .oe_vm_switch_graph,
.openerp .oe_vm_switch_gantt,
@@ -2049,6 +2056,7 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
.openerp .oe_vm_switch_form span,
.openerp .oe_vm_switch_page span,
+.openerp .oe_vm_switch_tree span,
.openerp .oe_vm_switch_list span,
.openerp .oe_vm_switch_graph span,
.openerp .oe_vm_switch_gantt span,
@@ -2068,6 +2076,16 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
background-position: 0px -21px;
}
+.openerp .oe_vm_switch_tree {
+ background-position: 0px 0px;
+}
+.openerp .oe_vm_switch_tree:active,
+.openerp .oe_vm_switch_tree:hover,
+.openerp .oe_vm_switch_tree:focus,
+.openerp .oe_vm_switch_tree[disabled="disabled"] {
+ background-position: 0px -21px;
+}
+
.openerp .oe_vm_switch_form {
background-position: -22px 0px;
}
@@ -2078,6 +2096,15 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
background-position: -22px -21px;
}
+.openerp .oe_vm_switch_page {
+ background-position: -22px 0px;
+}
+.openerp .oe_vm_switch_page:active,
+.openerp .oe_vm_switch_page:hover,
+.openerp .oe_vm_switch_page:focus,
+.openerp .oe_vm_switch_page[disabled="disabled"] {
+ background-position: -22px -21px;
+}
.openerp .oe_vm_switch_graph {
background-position: -44px 0px;
}
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 34b413526f0..39bc0181e16 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -36,7 +36,7 @@ openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Not
});
-openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# */{
+openerp.web.Dialog = openerp.web.Widget.extend(/** @lends openerp.web.Dialog# */{
dialog_title: "",
identifier_prefix: 'dialog',
/**
@@ -44,11 +44,14 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog#
* @extends openerp.web.OldWidget
*
* @param parent
- * @param dialog_options
+ * @param options
*/
- init: function (parent, dialog_options) {
+ init: function (parent, options, content) {
var self = this;
this._super(parent);
+ if (content) {
+ this.$element = content instanceof $ ? content : $(content);
+ }
this.dialog_options = {
modal: true,
destroy_on_close: true,
@@ -57,10 +60,9 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog#
max_width: '95%',
height: 'auto',
min_height: 0,
- max_height: '95%',
+ max_height: this.get_height('100%') - 140,
autoOpen: false,
position: [false, 50],
- autoResize : 'auto',
buttons: {},
beforeClose: function () { self.on_close(); },
resizeStop: this.on_resized
@@ -70,31 +72,29 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog#
this.dialog_options.buttons[f.substr(10)] = this[f];
}
}
- if (dialog_options) {
- this.set_options(dialog_options);
- }
- },
- set_options: function(options) {
- options = options || {};
- options.width = this.get_width(options.width || this.dialog_options.width);
- options.min_width = this.get_width(options.min_width || this.dialog_options.min_width);
- options.max_width = this.get_width(options.max_width || this.dialog_options.max_width);
- options.height = this.get_height(options.height || this.dialog_options.height);
- options.min_height = this.get_height(options.min_height || this.dialog_options.min_height);
- options.max_height = this.get_height(options.max_height || this.dialog_options.max_height);
-
- if (options.width !== 'auto') {
- if (options.width > options.max_width) options.width = options.max_width;
- if (options.width < options.min_width) options.width = options.min_width;
+ if (options) {
+ _.extend(this.dialog_options, options);
}
- if (options.height !== 'auto') {
- if (options.height > options.max_height) options.height = options.max_height;
- if (options.height < options.min_height) options.height = options.min_height;
+ if (this.dialog_options.autoOpen) {
+ this.open();
+ } else {
+ this.$element.dialog(this.get_options());
}
- if (!options.title && this.dialog_title) {
- options.title = this.dialog_title;
+ },
+ get_options: function(options) {
+ var self = this,
+ o = _.extend({}, this.dialog_options, options || {});
+ _.each(['width', 'height'], function(unit) {
+ o[unit] = self['get_' + unit](o[unit]);
+ o['min_' + unit] = self['get_' + unit](o['min_' + unit] || 0);
+ o['max_' + unit] = self['get_' + unit](o['max_' + unit] || 0);
+ if (o[unit] !== 'auto' && o['min_' + unit] && o[unit] < o['min_' + unit]) o[unit] = o['min_' + unit];
+ if (o[unit] !== 'auto' && o['max_' + unit] && o[unit] > o['max_' + unit]) o[unit] = o['max_' + unit];
+ });
+ if (!o.title && this.dialog_title) {
+ o.title = this.dialog_title;
}
- _.extend(this.dialog_options, options);
+ return o;
},
get_width: function(val) {
return this.get_size(val.toString(), $(window.top).width());
@@ -111,18 +111,16 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog#
return parseInt(val, 10);
}
},
- start: function () {
- this.$element.dialog(this.dialog_options);
- this._super();
- return this;
- },
- open: function(dialog_options) {
+ open: function(options) {
// TODO fme: bind window on resize
if (this.template) {
this.$element.html(this.render());
}
- this.set_options(dialog_options);
- this.$element.dialog(this.dialog_options).dialog('open');
+ var o = this.get_options(options);
+ this.$element.dialog(o).dialog('open');
+ if (o.height === 'auto' && o.max_height) {
+ this.$element.css({ 'max-height': o.max_height, 'overflow-y': 'auto' });
+ }
return this;
},
close: function() {
@@ -134,9 +132,7 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog#
}
},
on_resized: function() {
- if (openerp.connection.debug) {
- console.log("Dialog resized to %d x %d", this.$element.width(), this.$element.height());
- }
+ //openerp.log("Dialog resized to %d x %d", this.$element.width(), this.$element.height());
},
stop: function () {
// Destroy widget
@@ -179,7 +175,7 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({
var buttons = {};
if (openerp.connection.openerp_entreprise) {
buttons[_t("Send OpenERP Enterprise Report")] = function() {
- $this = $(this);
+ var $this = $(this);
var issuename = $('#issuename').val();
var explanation = $('#explanation').val();
var remark = $('#remark').val();
@@ -202,13 +198,12 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({
}
var dialog = new openerp.web.Dialog(this, {
title: "OpenERP " + _.str.capitalize(this.error.type),
- autoOpen: true,
width: '80%',
height: '50%',
min_width: '800px',
min_height: '600px',
buttons: buttons
- }).start();
+ }).open();
dialog.$element.html(QWeb.render('CrashManagerError', {session: openerp.connection, error: error}));
},
});
@@ -481,7 +476,10 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
error: error[1]
});
},
- complete: $.proxy(self, 'unblockUI')
+ complete: function() {
+ self.unblockUI();
+ self.do_notify(_t("Backed"), _t("Database backed up successfully"));
+ }
});
}
});
@@ -517,7 +515,10 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
})
}
},
- complete: $.proxy(self, 'unblockUI')
+ complete: function() {
+ self.unblockUI();
+ self.do_notify(_t("Restored"), _t("Database restored successfully"));
+ }
});
}
});
@@ -688,6 +689,11 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
var self = this;
self.rpc("/web/webclient/version_info", {}).then(function(res) {
var $help = $(QWeb.render("About-Page", {version_info: res}));
+ $help.find('a.oe_activate_debug_mode').click(function (e) {
+ e.preventDefault();
+ window.location = $.param.querystring(
+ window.location.href, 'debug');
+ });
$help.dialog({autoOpen: true,
modal: true, width: 960, title: _t("About")});
});
@@ -771,20 +777,20 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
title: _t("Preferences"),
width: '700px',
buttons: [
- {text: _t("Change password"), click: function(){ self.change_password(); }},
{text: _t("Cancel"), click: function(){ $(this).dialog('destroy'); }},
+ {text: _t("Change password"), click: function(){ self.change_password(); }},
{text: _t("Save"), click: function(){
var inner_viewmanager = action_manager.inner_viewmanager;
inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save()
.then(function() {
self.dialog.stop();
+ // needs to refresh interface in case language changed
window.location.reload();
});
}
}
]
- });
- this.dialog.start().open();
+ }).open();
action_manager.appendTo(this.dialog);
action_manager.render(this.dialog);
},
@@ -794,8 +800,7 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
this.dialog = new openerp.web.Dialog(this, {
title: _t("Change Password"),
width : 'auto'
- });
- this.dialog.start().open();
+ }).open();
this.dialog.$element.html(QWeb.render("Change_Pwd", self));
this.dialog.$element.find("form[name=change_password_form]").validate({
submitHandler: function (form) {
@@ -1102,11 +1107,11 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
self.$table = $(QWeb.render("Interface", {}));
self.$element.append(self.$table);
self.header = new openerp.web.Header(self);
- self.header.on_logout.add(self.on_logout);
- self.header.on_action.add(self.on_menu_action);
+ self.header.on_logout.add(this.proxy('on_logout'));
+ self.header.on_action.add(this.proxy('on_menu_action'));
self.header.appendTo($("#oe_header"));
self.menu = new openerp.web.Menu(self, "oe_menu", "oe_secondary_menu");
- self.menu.on_action.add(self.on_menu_action);
+ self.menu.on_action.add(this.proxy('on_menu_action'));
self.menu.start();
},
show_common: function() {
@@ -1124,7 +1129,11 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
this.$element.children().remove();
},
do_reload: function() {
- return this.session.session_init().pipe(_.bind(function() {this.menu.do_reload();}, this));
+ var self = this;
+ return this.session.session_reload().pipe(function () {
+ openerp.connection.load_modules(true).pipe(
+ self.menu.proxy('do_reload')); });
+
},
do_notify: function() {
var n = this.notification;
@@ -1175,7 +1184,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
self.menu.on_menu_click(null, action.menu_id);
});
}
- },
+ }
});
openerp.web.EmbeddedClient = openerp.web.Widget.extend({
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index 819385288a7..b36e576ae47 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -348,6 +348,31 @@ openerp.web.CallbackEnabled = openerp.web.Class.extend(/** @lends openerp.web.Ca
}
}
}
+ },
+ /**
+ * 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.
+ *
+ * @param {String} method_name name of the method to invoke
+ * @returns {Function} proxied method
+ */
+ proxy: function (method_name) {
+ var self = this;
+ return function () {
+ return self[method_name].apply(self, arguments);
+ }
}
});
@@ -547,7 +572,24 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
var self = this;
// TODO: session store in cookie should be optional
this.session_id = this.get_cookie('session_id');
- return this.rpc("/web/session/get_session_info", {}).pipe(function(result) {
+ return this.session_reload().pipe(function(result) {
+ var modules = openerp._modules.join(',');
+ var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb);
+ if(self.session_is_valid()) {
+ return deferred.pipe(function() { return self.load_modules(); });
+ }
+ return deferred;
+ });
+ },
+ /**
+ * (re)loads the content of a session: db name, username, user id, session
+ * context and status of the support contract
+ *
+ * @returns {$.Deferred} deferred indicating the session is done reloading
+ */
+ session_reload: function () {
+ var self = this;
+ return this.rpc("/web/session/get_session_info", {}).then(function(result) {
// If immediately follows a login (triggered by trying to restore
// an invalid session or no session at all), refresh session data
// (should not change, but just in case...)
@@ -558,12 +600,6 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
user_context: result.context,
openerp_entreprise: result.openerp_entreprise
});
- var modules = openerp._modules.join(',');
- var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb);
- if(self.session_is_valid()) {
- return deferred.pipe(function() { self.load_modules(); });
- }
- return deferred;
});
},
session_is_valid: function() {
@@ -640,26 +676,31 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
},
/**
* Load additional web addons of that instance and init them
+ *
+ * @param {Boolean} [no_session_valid_signal=false] prevents load_module from triggering ``on_session_valid``.
*/
- load_modules: function() {
+ load_modules: function(no_session_valid_signal) {
var self = this;
return this.rpc('/web/session/modules', {}).pipe(function(result) {
- self.module_list = result;
var lang = self.user_context.lang;
var params = { mods: ["web"].concat(result), lang: lang};
- var modules = self.module_list.join(',');
+ var to_load = _.difference(result, self.module_list).join(',');
+ self.module_list = result;
return $.when(
- self.rpc('/web/webclient/csslist', {mods: modules}, self.do_load_css),
- self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb),
+ self.rpc('/web/webclient/csslist', {mods: to_load}, self.do_load_css),
+ self.rpc('/web/webclient/qweblist', {mods: to_load}).pipe(self.do_load_qweb),
self.rpc('/web/webclient/translations', params).pipe(function(trans) {
openerp.web._t.database.set_bundle(trans);
var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"];
- return self.rpc('/web/webclient/jslist', {mods: modules}).pipe(function(files) {
+ return self.rpc('/web/webclient/jslist', {mods: to_load}).pipe(function(files) {
return self.do_load_js(file_list.concat(files));
});
})
).then(function() {
- self.on_session_valid();
+ self.on_modules_loaded();
+ if (!no_session_valid_signal) {
+ self.on_session_valid();
+ }
});
});
},
@@ -692,7 +733,6 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
var head = document.head || document.getElementsByTagName('head')[0];
head.appendChild(tag);
} else {
- self.on_modules_loaded();
d.resolve();
}
return d;
@@ -702,6 +742,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
_.each(files, function(file) {
self.qweb_mutex.exec(function() {
return self.rpc('/web/proxy/load', {path: file}).pipe(function(xml) {
+ if (!xml) { return; }
openerp.web.qweb.add_template(_.str.trim(xml));
});
});
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index c24325a9327..447b95d17cf 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -293,16 +293,16 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
*
* @param {Array} ids identifiers of the records to read
* @param {Array} fields fields to read and return, by default all fields are returned
- * @param {Function} callback function called with read result
* @returns {$.Deferred}
*/
- read_ids: function (ids, fields, callback) {
+ read_ids: function (ids, fields, options) {
+ var options = options || {};
return this.rpc('/web/dataset/get', {
model: this.model,
ids: ids,
fields: fields,
- context: this.get_context()
- }, callback);
+ context: this.get_context(options.context)
+ });
},
/**
* Read a slice of the records represented by this DataSet, based on its
@@ -312,26 +312,25 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
* @params {Object} options
* @param {Number} [options.offset=0] The index from which selected records should be returned
* @param {Number} [options.limit=null] The maximum number of records to return
- * @param {Function} callback function called with read_slice result
* @returns {$.Deferred}
*/
- read_slice: function (fields, options, callback) {
- return null;
+ read_slice: function (fields, options) {
+ return null;
},
/**
* Reads the current dataset record (from its index)
*
* @params {Array} [fields] fields to read and return, by default all fields are returned
- * @params {Function} callback function called with read_index result
+ * @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
* @returns {$.Deferred}
*/
- read_index: function (fields, callback) {
- var def = $.Deferred().then(callback);
+ read_index: function (fields, options) {
+ var def = $.Deferred();
if (_.isEmpty(this.ids)) {
def.reject();
} else {
fields = fields || false;
- this.read_ids([this.ids[this.index]], fields).then(function(records) {
+ this.read_ids([this.ids[this.index]], fields, options).then(function(records) {
def.resolve(records[0]);
}, function() {
def.reject.apply(def, arguments);
@@ -343,15 +342,16 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
* Reads default values for the current model
*
* @param {Array} [fields] fields to get default values for, by default all defaults are read
- * @param {Function} callback function called with default_get result
+ * @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
* @returns {$.Deferred}
*/
- default_get: function(fields, callback) {
+ default_get: function(fields, options) {
+ var options = options || {};
return this.rpc('/web/dataset/default_get', {
model: this.model,
fields: fields,
- context: this.get_context()
- }, callback);
+ context: this.get_context(options.context)
+ });
},
/**
* Creates a new record in db
@@ -422,7 +422,7 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
* @param {Number} [domain_index] index of a domain to evaluate in the args array
* @param {Number} [context_index] index of a context to evaluate in the args array
* @param {Function} callback
- * @param {Function }error_callback
+ * @param {Function} error_callback
* @returns {$.Deferred}
*/
call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) {
@@ -503,14 +503,14 @@ openerp.web.DataSetStatic = openerp.web.DataSet.extend({
// all local records
this.ids = ids || [];
},
- read_slice: function (fields, options, callback) {
+ read_slice: function (fields, options) {
// TODO remove fields from options
var self = this,
offset = options.offset || 0,
limit = options.limit || false,
fields = fields || false;
var end_pos = limit && limit !== -1 ? offset + limit : this.ids.length;
- return this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
+ return this.read_ids(this.ids.slice(offset, end_pos), fields);
},
set_ids: function (ids) {
this.ids = ids;
@@ -557,10 +557,9 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
* @param {Array} [options.domain] domain data to add to the request payload, ANDed with the dataset's domain
* @param {Number} [options.offset=0] The index from which selected records should be returned
* @param {Number} [options.limit=null] The maximum number of records to return
- * @param {Function} callback function called with read_slice result
* @returns {$.Deferred}
*/
- read_slice: function (fields, options, callback) {
+ read_slice: function (fields, options) {
var self = this;
var options = options || {};
var offset = options.offset || 0;
@@ -576,7 +575,7 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
self.ids = result.ids;
self.offset = offset;
return result.records;
- }).then(callback);
+ });
},
get_domain: function (other_domain) {
if (other_domain) {
@@ -630,8 +629,8 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
this.reset_ids([]);
this.last_default_get = {};
},
- default_get: function(fields, callback) {
- return this._super(fields).then(this.on_default_get).then(callback);
+ default_get: function(fields, options) {
+ return this._super(fields, options).then(this.on_default_get);
},
on_default_get: function(res) {
this.last_default_get = res;
@@ -699,7 +698,7 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
this.delete_all = false;
},
on_change: function() {},
- read_ids: function (ids, fields, callback) {
+ read_ids: function (ids, fields, options) {
var self = this;
var to_get = [];
_.each(ids, function(id) {
@@ -713,7 +712,7 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
to_get.push(id);
}
});
- var completion = $.Deferred().then(callback);
+ var completion = $.Deferred();
var return_records = function() {
var records = _.map(ids, function(id) {
return _.extend({}, _.detect(self.cache, function(c) {return c.id === id;}).values, {"id": id});
@@ -726,7 +725,7 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
completion.resolve(records);
};
if(to_get.length > 0) {
- var rpc_promise = this._super(to_get, fields, function(records) {
+ var rpc_promise = this._super(to_get, fields, options).then(function(records) {
_.each(records, function(record, index) {
var id = to_get[index];
var cached = _.detect(self.cache, function(x) {return x.id === id;});
@@ -775,8 +774,8 @@ openerp.web.ProxyDataSet = openerp.web.DataSetSearch.extend({
return this._super.apply(this, arguments);
}
},
- default_get: function(fields, callback) {
- return this._super(fields, callback).then(this.on_default_get);
+ default_get: function(fields, options) {
+ return this._super(fields, options).then(this.on_default_get);
},
on_default_get: function(result) {},
create: function(data, callback, error_callback) {
diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js
index 78dc3bef1f9..78be735edc7 100644
--- a/addons/web/static/src/js/data_export.js
+++ b/addons/web/static/src/js/data_export.js
@@ -63,7 +63,15 @@ openerp.web.DataExport = openerp.web.Dialog.extend({
do_setup_export_formats: function (formats) {
var $fmts = this.$element.find('#export_format');
_(formats).each(function (format) {
- $fmts.append(new Option(format[1], format[0]));
+ var opt = new Option(format.label, format.tag);
+ if (format.error) {
+ opt.disabled = true;
+ opt.replaceChild(
+ document.createTextNode(
+ _.str.sprintf("%s — %s", format.label, format.error)),
+ opt.childNodes[0])
+ }
+ $fmts.append(opt);
});
},
show_exports_list: function() {
@@ -74,7 +82,7 @@ openerp.web.DataExport = openerp.web.Dialog.extend({
}
return this.exports.read_slice(['name'], {
domain: [['resource', '=', this.dataset.model]]
- }, function (export_list) {
+ }).then(function (export_list) {
if (!export_list.length) {
return;
}
@@ -114,7 +122,7 @@ openerp.web.DataExport = openerp.web.Dialog.extend({
if (value) {
self.do_save_export_list(value);
} else {
- alert("Pleae Enter Save Field List Name");
+ alert(_t("Please enter save field list name"));
}
});
} else {
@@ -349,24 +357,27 @@ openerp.web.DataExport = openerp.web.Dialog.extend({
export_field.push($(this).val());
});
if (!export_field.length) {
- alert('Please select fields to save export list...');
+ alert(_t("Please select fields to save export list..."));
}
return export_field;
},
on_click_export_data: function() {
- $.blockUI(this.$element);
- var exported_fields = [], self = this;
- this.$element.find("#fields_list option").each(function() {
- var fieldname = self.records[$(this).val()];
- exported_fields.push({name: fieldname, label: $(this).text()});
- });
+ var self = this;
+ var exported_fields = this.$element.find('#fields_list option').map(function () {
+ var name = self.records[this.value] || this.value
+ // DOM property is textContent, but IE8 only knows innerText
+ return {name: this.value,
+ label: this.textContent || this.innerText};
+ }).get();
+
if (_.isEmpty(exported_fields)) {
- alert('Please select fields to export...');
+ alert(_t("Please select fields to export..."));
return;
}
exported_fields.unshift({name: 'id', label: 'External ID'});
var export_format = this.$element.find("#export_format").val();
+ $.blockUI();
this.session.get_file({
url: '/web/export/' + export_format,
data: {data: JSON.stringify({
@@ -375,7 +386,7 @@ openerp.web.DataExport = openerp.web.Dialog.extend({
ids: this.dataset.ids,
domain: this.dataset.domain,
import_compat: Boolean(
- this.$element.find("#import_compat").val())
+ this.$element.find("#import_compat").val())
})},
complete: $.unblockUI
});
diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js
index 2b252454869..18870ca2157 100644
--- a/addons/web/static/src/js/data_import.js
+++ b/addons/web/static/src/js/data_import.js
@@ -83,7 +83,7 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
'fields_get', [], function (fields) {
self.graft_fields(fields);
self.ready.push(new openerp.web.DataSet(self, self.model)
- .default_get(_.pluck(self.fields, 'id'), function (fields) {
+ .default_get(_.pluck(self.fields, 'id')).then(function (fields) {
_.each(fields, function(val, key) {
if (val) {
self.fields_with_defaults.push(key);
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index 37d1e4cf7b5..7f220d0aa54 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -102,10 +102,6 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
return _.str.sprintf("%02d:%02d",
Math.floor(value),
Math.round((value % 1) * 60));
- case 'progressbar':
- return _.str.sprintf(
- '<progress value="%.2f" max="100.0">%.2f%%</progress>',
- value, value);
case 'many2one':
// name_get value format
return value[1];
@@ -237,7 +233,15 @@ openerp.web.auto_date_to_str = function(value, type) {
};
/**
- * Formats a provided cell based on its field type
+ * Formats a provided cell based on its field type. Most of the field types
+ * return a correctly formatted value, but some tags and fields are
+ * special-cased in their handling:
+ *
+ * * buttons will return an actual ``<button>`` tag with a bunch of error handling
+ *
+ * * boolean fields will return a checkbox input, potentially disabled
+ *
+ * * binary fields will return a link to download the binary data as a file
*
* @param {Object} row_data record whose values should be displayed in the cell
* @param {Object} column column descriptor
@@ -245,15 +249,21 @@ openerp.web.auto_date_to_str = function(value, type) {
* @param {String} column.type widget type for a field control
* @param {String} [column.string] button label
* @param {String} [column.icon] button icon
- * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
- * @param {Boolean} [process_modifiers=true] should the modifiers be computed ?
+ * @param {Object} [options]
+ * @param {String} [options.value_if_empty=''] what to display if the field's value is ``false``
+ * @param {Boolean} [options.process_modifiers=true] should the modifiers be computed ?
+ * @param {String} [options.model] current record's model
+ * @param {Number} [options.id] current record's id
+ *
*/
-openerp.web.format_cell = function (row_data, column, value_if_empty, process_modifiers) {
+openerp.web.format_cell = function (row_data, column, options) {
+ options = options || {};
var attrs = {};
- if (process_modifiers !== false) {
+ if (options.process_modifiers !== false) {
attrs = column.modifiers_for(row_data);
}
if (attrs.invisible) { return ''; }
+
if (column.tag === 'button') {
return _.template('<button type="button" title="<%-title%>" <%=additional_attributes%> >' +
'<img src="<%-prefix%>/web/static/src/img/icons/<%-icon%>.png" alt="<%-alt%>"/>' +
@@ -263,14 +273,41 @@ openerp.web.format_cell = function (row_data, column, value_if_empty, process_mo
'disabled="disabled" class="oe-listview-button-disabled"' : '',
prefix: openerp.connection.prefix,
icon: column.icon,
- alt: column.string || '',
+ alt: column.string || ''
});
}
if (!row_data[column.id]) {
- return value_if_empty === undefined ? '' : value_if_empty;
+ return options.value_if_empty === undefined ? '' : options.value_if_empty;
}
- return openerp.web.format_value(
- row_data[column.id].value, column, value_if_empty);
+
+ switch (column.widget || column.type) {
+ case "boolean":
+ return _.str.sprintf('<input type="checkbox" %s disabled="disabled"/>',
+ row_data[column.id].value ? 'checked="checked"' : '');
+ case "binary":
+ var text = _t("Download"),
+ download_url = _.str.sprintf('/web/binary/saveas?session_id=%s&model=%s&field=%s&id=%d', openerp.connection.session_id, options.model, column.id, options.id);
+ if (column.filename) {
+ download_url += '&filename_field=' + column.filename;
+ if (row_data[column.filename]) {
+ text = _.str.sprintf(_t("Download \"%s\""), openerp.web.format_value(
+ row_data[column.filename].value, {type: 'char'}));
+ }
+ }
+ return _.template('<a href="<%-href%>"><%-text%></a> (%<-size%>)', {
+ text: text,
+ href: download_url,
+ size: row_data[column.id].value
+ });
+ case 'progressbar':
+ return _.template(
+ '<progress value="<%-value%>" max="100"><%-value%>%</progress>', {
+ value: row_data[column.id].value
+ });
+ }
+
+ return _.escape(openerp.web.format_value(
+ row_data[column.id].value, column, options.value_if_empty));
}
-
+
};
diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js
index 649f324744d..bf920380ff9 100644
--- a/addons/web/static/src/js/view_editor.js
+++ b/addons/web/static/src/js/view_editor.js
@@ -16,9 +16,10 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
this.init_view_editor();
},
init_view_editor: function() {
- var self = this;
+ var self = this,
+ action_title = _.str.sprintf(_t("Manage Views (%s)"), this.model);
var action = {
- name: _.str.sprintf("Manage Views (%s)", this.model),
+ name: action_title,
context: this.session.user_context,
domain: [["model", "=", this.model]],
res_model: 'ir.ui.view',
@@ -38,7 +39,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
};
this.view_edit_dialog = new openerp.web.Dialog(this, {
- title: _t("ViewEditor"),
+ title: action_title,
width: 850,
buttons: [
{text: _t("Create"), click: function() { self.on_create_view(); }},
@@ -46,7 +47,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
{text: _t("Remove"), click: function() { self.do_delete_view(); }},
{text: _t("Close"), click: function() { self.view_edit_dialog.close(); }}
]
- }).start().open();
+ }).open();
this.main_view_id = this.parent.fields_view.view_id;
this.action_manager = new openerp.web.ActionManager(this);
this.action_manager.appendTo(this.view_edit_dialog);
@@ -91,8 +92,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}},
{text: _t("Cancel"), click: function () { self.create_view_dialog.close(); }}
]
- });
- this.create_view_dialog.start().open();
+ }).open();
var view_widget = [{'name': 'view_name', 'string':'View Name', 'type': 'char', 'required': true, 'value' : this.model + '.custom_' + Math.round(Math.random() * 1000)},
{'name': 'view_type', 'string': 'View Type', 'type': 'selection', 'required': true, 'value': 'Form', 'selection': [['',''],['tree', 'Tree'],['form', 'Form'],['graph', 'Graph'],['calendar', 'Calender']]},
{'name': 'proirity', 'string': 'Priority', 'type': 'float', 'required': true, 'value':'16'}];
@@ -124,7 +124,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
});
if (field_name) {
- model_dataset.read_slice(['name','field_id'], {"domain": [['model','=',self.model]]}, function(records) {
+ model_dataset.read_slice(['name','field_id'], {"domain": [['model','=',self.model]]}).then(function(records) {
if (records) {view_string = records[0].name;}
var arch = _.str.sprintf("<?xml version='1.0'?>\n<%s string='%s'>\n\t<field name='%s'/>\n</%s>", values.view_type, view_string, field_name, values.view_type);
var vals = {'model': self.model, 'name': values.view_name, 'priority': values.priority, 'type': values.view_type, 'arch': arch};
@@ -227,12 +227,12 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
get_arch: function() {
var self = this;
var view_arch_list = [];
- this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], function(arch) {
+ this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type']).then(function(arch) {
if (arch.length) {
var arch_object = self.parse_xml(arch[0].arch, self.main_view_id);
self.main_view_type = arch[0].type == 'tree'? 'list': arch[0].type;
view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch});
- self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}, function(result) {
+ self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}).then(function(result) {
_.each(result, function(res) {
view_arch_list.push({"view_id": res.id, "arch": res.arch});
self.inherit_view(arch_object, res);
@@ -381,7 +381,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
self.edit_xml_dialog.close();
}}
]
- }).start().open();
+ }).open();
var no_property_att = [];
_.each(_PROPERTIES, function(val, key) {
if (! val.length) no_property_att.push(key);
@@ -768,8 +768,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}},
{text: _t("Cancel"), click: function () { self.edit_node_dialog.close(); }}
]
- });
- this.edit_node_dialog.start().open();
+ }).open();
var _PROPERTIES_ATTRIBUTES = {
'name' : {'name':'name', 'string': 'Name', 'type': 'char'},
'string' : {'name':'string', 'string': 'String', 'type': 'char'},
@@ -895,7 +894,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}},
{text: _t("Cancel"), click: function() { self.add_node_dialog.close(); }}
]
- }).start().open();
+ }).open();
this.add_node_dialog.$element.append('<table id="rec_table" style="width:420px" class="oe_forms"><tbody><tr></tbody></table>');
var table_selector = self.add_node_dialog.$element.find('table[id=rec_table] tbody');
_.each(render_list, function(node) {
@@ -915,7 +914,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
table_selector.find("td[id^=]").attr("width","100px");
self.add_node_dialog.$element.find('#new_field').click(function() {
model_data = new openerp.web.DataSetSearch(self,'ir.model', null, null);
- model_data.read_slice([], {domain: [['model','=', self.model]]}, function(result) {
+ model_data.read_slice([], {domain: [['model','=', self.model]]}).then(function(result) {
self.render_new_field(result[0].id);
});
});
@@ -939,7 +938,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
controller.do_set_readonly.add_last(function(){
action_manager.stop();
new_fields_name = new openerp.web.DataSetSearch(self,'ir.model.fields', null, null);
- new_fields_name.read_ids([controller.datarecord.id], ['name'], function(result) {
+ new_fields_name.read_ids([controller.datarecord.id], ['name']).then(function(result) {
self.add_node_dialog.$element.find('select[id=field_value]').append($("<option selected></option>").attr("value", result[0].name).text(result[0].name));
_.detect(self.add_widget,function(widget){
widget.name == "field_value"? widget.selection.push(result[0].name): false;
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 4505fe671e4..ebe1ca26785 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -50,10 +50,10 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
_.defaults(this.options, {
"not_interactible_on_create": false
});
- this.mutating_lock = $.Deferred();
- this.initial_mutating_lock = this.mutating_lock;
- this.on_change_lock = $.Deferred().resolve();
- this.reload_lock = $.Deferred().resolve();
+ this.is_initialized = $.Deferred();
+ this.mutating_mutex = new $.Mutex();
+ this.on_change_mutex = new $.Mutex();
+ this.reload_mutex = new $.Mutex();
},
start: function() {
this._super();
@@ -136,17 +136,19 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
do_show: function () {
var self = this;
- this.$element.hide();
+ this.$element.show().css('visibility', 'hidden');
return this.has_been_loaded.pipe(function() {
var result;
if (self.dataset.index === null) {
// null index means we should start a new record
result = self.on_button_new();
} else {
- result = self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_record_loaded);
+ result = self.dataset.read_index(_.keys(self.fields_view.fields), {
+ context : { 'bin_size' : true }
+ }).pipe(self.on_record_loaded);
}
result.pipe(function() {
- self.$element.show();
+ self.$element.css('visibility', 'visible');
});
if (self.sidebar) {
self.sidebar.$element.show();
@@ -189,7 +191,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
});
}
self.on_form_changed();
- self.initial_mutating_lock.resolve();
+ self.is_initialized.resolve();
self.show_invalid = true;
self.do_update_pager(record.id == null);
if (self.sidebar) {
@@ -207,6 +209,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
for (var w in this.widgets) {
w = this.widgets[w];
w.process_modifiers();
+ if (w.field) {
+ w.validate();
+ }
w.update_dom();
}
},
@@ -255,7 +260,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
'None': function () {return null;},
'context': function (i) {
context_index = i;
- var ctx = widget.build_context ? widget.build_context() : {};
+ var ctx = new openerp.web.CompoundContext(self.dataset.get_context(), widget.build_context() ? widget.build_context() : {});
return ctx;
}
};
@@ -306,7 +311,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
},
do_onchange: function(widget, processed) {
var self = this;
- var act = function() {
+ return this.on_change_mutex.exec(function() {
try {
processed = processed || [];
var on_change = widget.node.attrs.on_change;
@@ -333,9 +338,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
console.error(e);
return $.Deferred().reject();
}
- };
- this.on_change_lock = this.on_change_lock.pipe(act, act);
- return this.on_change_lock;
+ });
},
on_processed_onchange: function(response, processed) {
try {
@@ -417,10 +420,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
*/
do_save: function(success, prepend_on_create) {
var self = this;
- var action = function() {
+ return this.mutating_mutex.exec(function() { return self.is_initialized.pipe(function() {
try {
- if (!self.initial_mutating_lock.isResolved() && !self.initial_mutating_lock.isRejected())
- return;
var form_invalid = false,
values = {},
first_invalid_field = null;
@@ -446,15 +447,15 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
} else {
var save_deferral;
if (!self.datarecord.id) {
- console.log("FormView(", self, ") : About to create", values);
+ //console.log("FormView(", self, ") : About to create", values);
save_deferral = self.dataset.create(values).pipe(function(r) {
return self.on_created(r, undefined, prepend_on_create);
}, null);
} else if (_.isEmpty(values)) {
- console.log("FormView(", self, ") : Nothing to save");
+ //console.log("FormView(", self, ") : Nothing to save");
save_deferral = $.Deferred().resolve({}).promise();
} else {
- console.log("FormView(", self, ") : About to save", values);
+ //console.log("FormView(", self, ") : About to save", values);
save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
return self.on_saved(r);
}, null);
@@ -465,9 +466,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
console.error(e);
return $.Deferred().reject();
}
- };
- this.mutating_lock = this.mutating_lock.pipe(action, action);
- return this.mutating_lock;
+ });});
},
on_invalid: function() {
var msg = "<ul>";
@@ -518,7 +517,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (this.sidebar) {
this.sidebar.attachments.do_update();
}
- openerp.log("The record has been created with id #" + this.datarecord.id);
+ //openerp.log("The record has been created with id #" + this.datarecord.id);
this.reload();
return $.when(_.extend(r, {created: true})).then(success);
}
@@ -528,15 +527,15 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
},
reload: function() {
var self = this;
- var act = function() {
+ return this.reload_mutex.exec(function() {
if (self.dataset.index == null || self.dataset.index < 0) {
return $.when(self.on_button_new());
} else {
- return self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_record_loaded);
+ return self.dataset.read_index(_.keys(self.fields_view.fields), {
+ context : { 'bin_size' : true }
+ }).pipe(self.on_record_loaded);
}
- };
- this.reload_lock = this.reload_lock.pipe(act, act);
- return this.reload_lock;
+ });
},
get_fields_values: function(blacklist) {
blacklist = blacklist || [];
@@ -633,7 +632,7 @@ openerp.web.form.SidebarAttachments = openerp.web.Widget.extend({
['res_model', '=', this.view.dataset.model],
['res_id', '=', this.view.datarecord.id],
['type', 'in', ['binary', 'url']]
- ])).read_slice(['name', 'url', 'type'], {}, this.on_attachments_loaded);
+ ])).read_slice(['name', 'url', 'type'], {}).then(this.on_attachments_loaded);
}
},
on_attachments_loaded: function(attachments) {
@@ -834,23 +833,17 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.
* the fields'context with the action's context.
*/
build_context: function(blacklist) {
- var f_context = (this.field || {}).context || {};
- if (!!f_context.__ref || true) { //TODO: remove true
- var fields_values = this._build_eval_context(blacklist);
- f_context = new openerp.web.CompoundContext(f_context).set_eval_context(fields_values);
- }
- // maybe the default_get should only be used when we do a default_get?
- var v_contexts = _.compact([this.node.attrs.default_get || null,
- this.node.attrs.context || null]);
- var v_context = new openerp.web.CompoundContext();
- _.each(v_contexts, function(x) {v_context.add(x);});
- if (_.detect(v_contexts, function(x) {return !!x.__ref;}) || true) { //TODO: remove true
+ // only use the model's context if there is not context on the node
+ var v_context = this.node.attrs.context;
+ if (! v_context) {
+ v_context = (this.field || {}).context || {};
+ }
+
+ if (v_context.__ref || true) { //TODO: remove true
var fields_values = this._build_eval_context(blacklist);
- v_context.set_eval_context(fields_values);
+ v_context = new openerp.web.CompoundContext(v_context).set_eval_context(fields_values);
}
- // if there is a context on the node, overrides the model's context
- var ctx = v_contexts.length > 0 ? v_context : f_context;
- return ctx;
+ return v_context;
},
build_domain: function() {
var f_domain = this.field.domain || [];
@@ -1272,7 +1265,12 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
validate: function() {
this.invalid = false;
},
- focus: function() {
+ focus: function($element) {
+ if ($element) {
+ setTimeout(function() {
+ $element.focus();
+ }, 50);
+ }
},
reset: function() {
this.dirty = false;
@@ -1319,8 +1317,8 @@ openerp.web.form.FieldChar = openerp.web.form.Field.extend({
this.invalid = true;
}
},
- focus: function() {
- this.$element.find('input').focus();
+ focus: function($element) {
+ this._super($element || this.$element.find('input:first'));
}
});
@@ -1444,9 +1442,6 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({
}
}
},
- focus: function() {
- this.$input.focus();
- },
parse_client: function(v) {
return openerp.web.parse_value(v, {"widget": this.type_of_date});
},
@@ -1491,8 +1486,8 @@ openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
validate: function() {
this.invalid = !this.datewidget.is_valid(this.required);
},
- focus: function() {
- this.datewidget.focus();
+ focus: function($element) {
+ this._super($element || this.datewidget.$input);
}
});
@@ -1535,8 +1530,8 @@ openerp.web.form.FieldText = openerp.web.form.Field.extend({
this.invalid = true;
}
},
- focus: function() {
- this.$element.find('textarea').focus();
+ focus: function($element) {
+ this._super($element || this.$element.find('textarea:first'));
},
do_resize: function(max_height) {
max_height = parseInt(max_height, 10);
@@ -1582,8 +1577,8 @@ openerp.web.form.FieldBoolean = openerp.web.form.Field.extend({
this._super.apply(this, arguments);
this.$element.find('input').prop('disabled', this.readonly);
},
- focus: function() {
- this.$element.find('input').focus();
+ focus: function($element) {
+ this._super($element || this.$element.find('input:first'));
}
});
@@ -1602,7 +1597,8 @@ openerp.web.form.FieldProgressBar = openerp.web.form.Field.extend({
if (isNaN(show_value)) {
show_value = 0;
}
- this.$element.find('div').progressbar('option', 'value', show_value).find('span').html(show_value + '%');
+ var formatted_value = openerp.web.format_value(show_value, { type : 'float' }, '0');
+ this.$element.find('div').progressbar('option', 'value', show_value).find('span').html(formatted_value + '%');
}
});
@@ -1669,8 +1665,8 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
var value = this.values[this.$element.find('select')[0].selectedIndex];
this.invalid = !(value && !(this.required && value[0] === false));
},
- focus: function() {
- this.$element.find('select').focus();
+ focus: function($element) {
+ this._super($element || this.$element.find('select:first'));
}
});
@@ -1708,15 +1704,11 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
openerp.web.form.dialog = function(content, options) {
options = _.extend({
- autoOpen: true,
width: '90%',
- height: '90%',
- min_width: '800px',
- min_height: '600px'
+ height: 'auto',
+ min_width: '800px'
}, options || {});
- options.autoOpen = true;
- var dialog = new openerp.web.Dialog(null, options);
- dialog.$element = $(content).dialog(dialog.dialog_options);
+ var dialog = new openerp.web.Dialog(null, options, content).open();
return dialog.$element;
};
@@ -1776,7 +1768,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
self.open_related(self.related_entries[i]);
};
});
- var cmenu = self.$menu_btn.contextMenu(self.cm_id, {'leftClickToo': true,
+ var cmenu = self.$menu_btn.contextMenu(self.cm_id, {'noRightClick': true,
bindings: bindings, itemStyle: {"color": ""},
onContextMenu: function() {
if(self.value) {
@@ -1796,7 +1788,6 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
});
});
var ctx_callback = function(e) {init_context_menu_def.resolve(e); e.preventDefault()};
- this.$menu_btn.bind('contextmenu', ctx_callback);
this.$menu_btn.click(ctx_callback);
// some behavior for input
@@ -2026,8 +2017,8 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
self.do_action(result.result);
});
},
- focus: function () {
- this.$input.focus();
+ focus: function ($element) {
+ this._super($element || this.$input);
},
update_dom: function() {
this._super.apply(this, arguments);
@@ -2306,6 +2297,9 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
this.viewmanager.views[this.viewmanager.active_view].controller) {
var view = this.viewmanager.views[this.viewmanager.active_view].controller;
if (this.viewmanager.active_view === "form") {
+ if (!view.is_initialized.isResolved()) {
+ return false;
+ }
var res = $.when(view.do_save());
if (!res.isResolved() && !res.isRejected()) {
console.warn("Asynchronous get_value() is not supported in form view.");
@@ -2437,7 +2431,10 @@ openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({
form_template: 'One2Many.formview',
on_loaded: function(data) {
this._super(data);
- this.$form_header.find('button.oe_form_button_create').click(this.on_button_new);
+ var self = this;
+ this.$form_header.find('button.oe_form_button_create').click(function() {
+ self.do_save().then(self.on_button_new);
+ });
}
});
@@ -2753,7 +2750,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save-new");
$nbutton.click(function() {
$.when(self.view_form.do_save()).then(function() {
- self.view_form.reload_lock.then(function() {
+ self.view_form.reload_mutex.exec(function() {
self.view_form.on_button_new();
});
});
@@ -2761,7 +2758,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save");
$nbutton.click(function() {
$.when(self.view_form.do_save()).then(function() {
- self.view_form.reload_lock.then(function() {
+ self.view_form.reload_mutex.exec(function() {
self.check_exit();
});
});
@@ -3023,7 +3020,7 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({
on_save_as: function() {
var url = '/web/binary/saveas?session_id=' + this.session.session_id + '&model=' +
this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name +
- '&fieldname=' + (this.node.attrs.filename || '') + '&t=' + (new Date().getTime());
+ '&filename_field=' + (this.node.attrs.filename || '') + '&t=' + (new Date().getTime());
window.open(url);
},
on_clear: function() {
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 2ab1152a0fa..aa970c31649 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -217,11 +217,11 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
});
this.$element.find('.oe-list-add')
- .click(this.do_add_record)
+ .click(this.proxy('do_add_record'))
.attr('disabled', grouped && this.options.editable);
this.$element.find('.oe-list-delete')
.attr('disabled', true)
- .click(this.do_delete_selected);
+ .click(this.proxy('do_delete_selected'));
this.$element.find('thead').delegate('th.oe-sortable[data-id]', 'click', function (e) {
e.stopPropagation();
@@ -512,7 +512,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
this.no_leaf = !!context['group_by_no_leaf'];
this.reload_view(!!group_by, context).then(
- $.proxy(this, 'reload_content'));
+ this.proxy('reload_content'));
},
/**
* Handles the signal to delete lines from the records list
@@ -685,6 +685,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
this.display_aggregates(aggregates);
},
display_aggregates: function (aggregation) {
+ var self = this;
var $footer_cells = this.$element.find('.oe-list-footer');
_(this.aggregate_columns).each(function (column) {
if (!column['function']) {
@@ -692,7 +693,9 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
}
$footer_cells.filter(_.str.sprintf('[data-field=%s]', column.id))
- .html(openerp.web.format_cell(aggregation, column, undefined, false));
+ .html(openerp.web.format_cell(aggregation, column, {
+ process_modifiers: false
+ }));
});
},
get_selected_ids: function() {
@@ -792,7 +795,7 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
$row.remove();
self.refresh_zebra(index);
},
- 'reset': $.proxy(this, 'on_records_reset'),
+ 'reset': function () { return self.on_records_reset(); },
'change': function (event, record) {
var $row = self.$current.find('[data-id=' + record.get('id') + ']');
$row.replaceWith(self.render_record(record));
@@ -846,6 +849,9 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
return self.reload_record(self.records.get(record_id));
}]);
})
+ .delegate('a', 'click', function (e) {
+ e.stopPropagation();
+ })
.delegate('tr', 'click', function (e) {
e.stopPropagation();
var row_id = self.row_id(e.currentTarget);
@@ -905,16 +911,22 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
});
}
}
- return openerp.web.format_cell(record.toForm().data, column);
+ return openerp.web.format_cell(record.toForm().data, column, {
+ model: this.dataset.model,
+ id: record.get('id')
+ });
},
render: function () {
+ var self = this;
if (this.$current) {
this.$current.remove();
}
this.$current = this.$_element.clone(true);
this.$current.empty().append(
QWeb.render('ListView.rows', _.extend({
- render_cell: $.proxy(this, 'render_cell')}, this)));
+ render_cell: function () {
+ return self.render_cell.apply(self, arguments); }
+ }, this)));
this.pad_table_to(5);
},
pad_table_to: function (count) {
@@ -1007,14 +1019,13 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
[record.get('id')],
_.pluck(_(this.columns).filter(function (r) {
return r.tag === 'field';
- }), 'name'),
- function (records) {
- _(records[0]).each(function (value, key) {
- record.set(key, value, {silent: true});
- });
- record.trigger('change', record);
- }
- );
+ }), 'name')
+ ).then(function (records) {
+ _(records[0]).each(function (value, key) {
+ record.set(key, value, {silent: true});
+ });
+ record.trigger('change', record);
+ });
},
/**
* Renders a list record to HTML
@@ -1030,7 +1041,8 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
record: record,
row_parity: (index % 2 === 0) ? 'even' : 'odd',
view: this.view,
- render_cell: $.proxy(this, 'render_cell')
+ render_cell: function () {
+ return this.render_cell.apply(this, arguments); }
});
},
/**
@@ -1084,7 +1096,9 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
this.page = 0;
- this.records.bind('reset', $.proxy(this, 'on_records_reset'));
+ var self = this;
+ this.records.bind('reset', function () {
+ return self.on_records_reset(); });
},
make_fragment: function () {
return document.createDocumentFragment();
@@ -1211,7 +1225,10 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
return column.id === group.grouped_on; });
try {
$group_column.html(openerp.web.format_cell(
- row_data, group_column, _t("Undefined"), false));
+ row_data, group_column, {
+ value_if_empty: _t("Undefined"),
+ process_modifiers: false
+ }));
} catch (e) {
$group_column.html(row_data[group_column.id].value);
}
@@ -1232,6 +1249,9 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
if (self.options.selectable) {
$row.append('<td>');
}
+ if (self.options.isClarkGable) {
+ $row.append('<td>');
+ }
_(self.columns).chain()
.filter(function (column) {return !column.invisible;})
.each(function (column) {
@@ -1286,9 +1306,9 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
page = this.datagroup.openable ? this.page : view.page;
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
- var options = { offset: page * limit, limit: limit };
+ var options = { offset: page * limit, limit: limit, context: {bin_size: true} };
//TODO xmo: investigate why we need to put the setTimeout
- $.async_when().then(function() {dataset.read_slice(fields, options , function (records) {
+ $.async_when().then(function() {dataset.read_slice(fields, options).then(function (records) {
// FIXME: ignominious hacks, parents (aka form view) should not send two ListView#reload_content concurrently
if (self.records.length) {
self.records.reset(null, {silent: true});
@@ -1674,6 +1694,7 @@ var Collection = openerp.web.Class.extend(/** @lends Collection# */{
proxy.reset();
});
this._proxies = {};
+ _(this.records).invoke('unbind', null, this._onRecordEvent);
this.length = 0;
this.records = [];
this._byId = {};
@@ -1692,7 +1713,6 @@ var Collection = openerp.web.Class.extend(/** @lends Collection# */{
* @returns this
*/
remove: function (record) {
- var self = this;
var index = _(this.records).indexOf(record);
if (index === -1) {
_(this._proxies).each(function (proxy) {
@@ -1701,6 +1721,7 @@ var Collection = openerp.web.Class.extend(/** @lends Collection# */{
return this;
}
+ record.unbind(null, this._onRecordEvent);
this.records.splice(index, 1);
delete this._byId[record.get('id')];
this.length--;
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index daf708104e8..a26626d8630 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -211,7 +211,8 @@ openerp.web.list_editable = function (openerp) {
.delegate('button', 'keyup', function (e) {
e.stopImmediatePropagation();
})
- .keyup($.proxy(self, 'on_row_keyup'));
+ .keyup(function () {
+ return self.on_row_keyup.apply(self, arguments); });
if (row) {
$new_row.replaceAll(row);
} else if (self.options.editable) {
@@ -359,7 +360,8 @@ openerp.web.list_editable = function (openerp) {
this.render_row_as_form();
},
render_record: function (record) {
- var index = this.records.indexOf(record);
+ var index = this.records.indexOf(record),
+ self = this;
// FIXME: context dict should probably be extracted cleanly
return QWeb.render('ListView.row', {
columns: this.columns,
@@ -367,7 +369,8 @@ openerp.web.list_editable = function (openerp) {
record: record,
row_parity: (index % 2 === 0) ? 'even' : 'odd',
view: this.view,
- render_cell: $.proxy(this, 'render_cell'),
+ render_cell: function () {
+ return self.render_cell.apply(self, arguments); },
edited: !!this.edition_form
});
}
diff --git a/addons/web/static/src/js/view_page.js b/addons/web/static/src/js/view_page.js
index 6ac5bc9f72b..d3ee79effca 100644
--- a/addons/web/static/src/js/view_page.js
+++ b/addons/web/static/src/js/view_page.js
@@ -208,6 +208,12 @@ openerp.web.page = function (openerp) {
openerp.web.page.FieldOne2ManyReadonly = openerp.web.form.FieldOne2Many.extend({
force_readonly: true
});
+ openerp.web.page.FieldBinaryImageReaonly = openerp.web.form.FieldBinaryImage.extend({
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('.oe-binary').hide();
+ }
+ });
openerp.web.page.FieldBinaryFileReadonly = openerp.web.form.FieldBinary.extend({
template: 'FieldURI.readonly',
start: function() {
@@ -249,5 +255,6 @@ openerp.web.page = function (openerp) {
'integer': 'openerp.web.page.FieldCharReadonly',
'float_time': 'openerp.web.page.FieldCharReadonly',
'binary': 'openerp.web.page.FieldBinaryFileReadonly',
+ 'image': 'openerp.web.page.FieldBinaryImageReaonly'
});
};
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index 528a31c7869..902b5a99526 100644
--- a/addons/web/static/src/js/view_tree.js
+++ b/addons/web/static/src/js/view_tree.js
@@ -86,7 +86,7 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
'toolbar': has_toolbar
}));
- this.dataset.read_slice(this.fields_list(), {}, function (records) {
+ this.dataset.read_slice(this.fields_list()).then(function(records) {
if (!has_toolbar) {
// WARNING: will do a second read on the same ids, but only on
// first load so not very important
@@ -192,7 +192,7 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
getdata: function (id, children_ids) {
var self = this;
- self.dataset.read_ids(children_ids, this.fields_list(), function (records) {
+ self.dataset.read_ids(children_ids, this.fields_list()).then(function(records) {
_(records).each(function (record) {
self.records[record.id] = record;
});
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 060d12e39b6..cc108837f88 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -128,19 +128,18 @@ session.web.ActionManager = session.web.Widget.extend({
.contains(action.res_model)) {
var old_close = on_close;
on_close = function () {
- session.webclient.do_reload();
- if (old_close) { old_close(); }
+ session.webclient.do_reload().then(old_close);
};
}
if (action.target === 'new') {
if (this.dialog == null) {
- this.dialog = new session.web.Dialog(this, { title: action.name, width: '80%' });
+ this.dialog = new session.web.Dialog(this, { width: '80%' });
if(on_close)
this.dialog.on_close.add(on_close);
- this.dialog.start();
} else {
this.dialog_viewmanager.stop();
}
+ this.dialog.dialog_title = action.name;
this.dialog_viewmanager = new session.web.ViewManagerAction(this, action);
this.dialog_viewmanager.appendTo(this.dialog.$element);
this.dialog.open();
@@ -356,9 +355,12 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
on_prev_view: function (created) {
var current_view = this.views_history.pop();
var previous_view = this.views_history[this.views_history.length - 1];
- // APR special case: "If creation mode from list (and only from a list),
- // after saving, go to page view (don't come back in list)"
if (created && current_view === 'form' && previous_view === 'list') {
+ // APR special case: "If creation mode from list (and only from a list),
+ // after saving, go to page view (don't come back in list)"
+ return this.on_mode_switch('page');
+ } else if (created && !previous_view && this.action && this.action.flags.default_view === 'form') {
+ // APR special case: "If creation from dashboard, we have no previous view
return this.on_mode_switch('page');
}
return this.on_mode_switch(previous_view, true);
@@ -515,7 +517,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
}
});
if (!(self.action.id in self.session.hidden_menutips)) {
- Users.read_ids([this.session.uid], ['menu_tips'], function(users) {
+ Users.read_ids([this.session.uid], ['menu_tips']).then(function(users) {
var user = users[0];
if (!(user && user.id === self.session.uid)) {
return;
@@ -539,41 +541,70 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
return manager_ready;
},
on_debug_changed: function (evt) {
- var $sel = $(evt.currentTarget),
+ var self = this,
+ $sel = $(evt.currentTarget),
$option = $sel.find('option:selected'),
- val = $sel.val();
+ val = $sel.val(),
+ current_view = this.views[this.active_view].controller;
switch (val) {
case 'fvg':
- $('<pre>').text(session.web.json_node_to_xml(
- this.views[this.active_view].controller.fields_view.arch, true)
- ).dialog({ width: '95%'});
+ var dialog = new session.web.Dialog(this, { title: _t("Fields View Get"), width: '95%' }).open();
+ $('<pre>').text(session.web.json_node_to_xml(current_view.fields_view.arch, true)).appendTo(dialog.$element);
break;
- case 'edit':
- var model = $option.data('model'),
- id = $option.data('id'),
- domain = $option.data('domain'),
- action = {
- res_model : model,
- type : 'ir.actions.act_window',
- view_type : 'form',
- view_mode : 'form',
- target : 'new',
- flags : {
- action_buttons : true,
- form : {
- resize_textareas : true
+ case 'fields':
+ this.dataset.call_and_eval(
+ 'fields_get', [false, {}], null, 1).then(function (fields) {
+ var $root = $('<dl>');
+ _(fields).each(function (attributes, name) {
+ $root.append($('<dt>').append($('<h4>').text(name)));
+ var $attrs = $('<dl>').appendTo(
+ $('<dd>').appendTo($root));
+ _(attributes).each(function (def, name) {
+ if (def instanceof Object) {
+ def = JSON.stringify(def);
}
- }
- };
- if (id) {
- action.res_id = id,
- action.views = [[false, 'form']];
- } else if (domain) {
- action.views = [[false, 'list'], [false, 'form']];
- action.domain = domain;
- action.flags.views_switcher = true;
+ $attrs
+ .append($('<dt>').text(name))
+ .append($('<dd style="white-space: pre-wrap;">').text(def));
+ });
+ });
+ new session.web.Dialog(self, {
+ title: _.str.sprintf(_t("Model %s fields"),
+ self.dataset.model),
+ width: '95%'}, $root).open();
+ });
+ break;
+ case 'customize_object':
+ this.rpc('/web/dataset/search_read', {
+ model: 'ir.model',
+ fields: ['id'],
+ domain: [['model', '=', this.dataset.model]]
+ }, function (result) {
+ self.do_edit_resource('ir.model', result.ids[0], {
+ name : _t("Customize Object") });
+ });
+ break;
+ case 'manage_views':
+ if (current_view.fields_view && current_view.fields_view.arch) {
+ var view_editor = new session.web.ViewEditor(current_view, current_view.$element, this.dataset, current_view.fields_view.arch);
+ view_editor.start();
+ } else {
+ this.do_warn(_t("Manage Views"),
+ _t("Could not find current view declaration"));
}
- this.do_action(action);
+ break;
+ case 'edit_workflow':
+ return this.do_action({
+ res_model : 'workflow',
+ domain : [['osv', '=', this.dataset.model]],
+ views: [[false, 'list'], [false, 'form'], [false, 'diagram']],
+ type : 'ir.actions.act_window',
+ view_type : 'list',
+ view_mode : 'list'
+ });
+ break;
+ case 'edit':
+ this.do_edit_resource($option.data('model'), $option.data('id'), { name : $option.text() });
break;
default:
if (val) {
@@ -582,6 +613,24 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
}
evt.currentTarget.selectedIndex = 0;
},
+ do_edit_resource: function(model, id, action) {
+ var action = _.extend({
+ res_model : model,
+ res_id : id,
+ type : 'ir.actions.act_window',
+ view_type : 'form',
+ view_mode : 'form',
+ views : [[false, 'form']],
+ target : 'new',
+ flags : {
+ action_buttons : true,
+ form : {
+ resize_textareas : true
+ }
+ }
+ }, action || {});
+ this.do_action(action);
+ },
on_mode_switch: function (view_type, no_store) {
var self = this;
@@ -729,26 +778,11 @@ session.web.Sidebar = session.web.Widget.extend({
action = view_manager.action;
if (this.session.uid === 1) {
this.add_section(_t('Customize'), 'customize');
- this.add_items('customize', [
- {
- label: _t("Manage Views"),
- callback: view.on_sidebar_manage_views,
- title: _t("Manage views of the current object")
- }, {
- label: _t("Edit Workflow"),
- callback: view.on_sidebar_edit_workflow,
- title: _t("Manage views of the current object"),
- classname: 'oe_sidebar_edit_workflow'
- }, {
- label: _t("Customize Object"),
- callback: view.on_sidebar_customize_object,
- title: _t("Manage views of the current object")
- }, {
- label: _t("Translate"),
- callback: view.on_sidebar_translate,
- title: _t("Technical translation")
- }
- ]);
+ this.add_items('customize', [{
+ label: _t("Translate"),
+ callback: view.on_sidebar_translate,
+ title: _t("Technical translation")
+ }]);
}
this.add_section(_t('Other Options'), 'other');
@@ -907,7 +941,7 @@ session.web.TranslateDialog = session.web.Dialog.extend({
this.languages = null;
this.languages_loaded = $.Deferred();
(new session.web.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(),
- [['translatable', '=', '1']])).read_slice(['code', 'name'], { sort: 'id' }, this.on_languages_loaded);
+ [['translatable', '=', '1']])).read_slice(['code', 'name'], { sort: 'id' }).then(this.on_languages_loaded);
},
start: function() {
var self = this;
@@ -1132,34 +1166,6 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
set_common_sidebar_sections: function(sidebar) {
sidebar.add_default_sections();
},
- on_sidebar_manage_views: function() {
- if (this.fields_view && this.fields_view.arch) {
- var view_editor = new session.web.ViewEditor(this, this.$element, this.dataset, this.fields_view.arch);
- view_editor.start();
- } else {
- this.do_warn("Manage Views", "Could not find current view declaration");
- }
- },
- on_sidebar_edit_workflow: function() {
- return this.do_action({
- res_model : 'workflow',
- domain : [['osv', '=', this.dataset.model]],
- views: [[false, 'list'], [false, 'form']],
- type : 'ir.actions.act_window',
- view_type : "list",
- view_mode : "list"
- });
- },
- on_sidebar_customize_object: function() {
- var self = this;
- this.rpc('/web/dataset/search_read', {
- model: 'ir.model',
- fields: ['id'],
- domain: [['model', '=', self.dataset.model]]
- }, function (result) {
- self.on_sidebar_edit_resource('ir.model', result.ids[0]);
- });
- },
on_sidebar_import: function() {
var import_view = new session.web.DataImport(this, this.dataset);
import_view.start();
@@ -1178,27 +1184,6 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
view_mode : "list"
});
},
- on_sidebar_edit_resource: function(model, id, domain) {
- var action = {
- res_model : model,
- type : 'ir.actions.act_window',
- view_type : 'form',
- view_mode : 'form',
- target : 'new',
- flags : {
- action_buttons : true
- }
- }
- if (id) {
- action.res_id = id,
- action.views = [[false, 'form']];
- } else if (domain) {
- action.views = [[false, 'list'], [false, 'form']];
- action.domain = domain;
- action.flags.views_switcher = true;
- }
- this.do_action(action);
- },
on_sidebar_view_log: function() {
},
sidebar_context: function () {
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 7238124ef49..5158fda62c2 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -470,10 +470,16 @@
</t>
<t t-name="ViewManagerDebug">
<option value="">Debug View#<t t-esc="view.fields_view.view_id"/></option>
- <option value="fvg"> - Fields View Get</option>
- <option value="edit" data-model="ir.ui.view" t-att-data-id="view.fields_view.view_id"> - Edit <t t-esc="_.str.capitalize(view.fields_view.type)"/>View</option>
- <option t-if="view_manager.searchview" value="edit" data-model="ir.ui.view" t-att-data-id="view_manager.searchview.view_id"> - Edit SearchView</option>
- <option t-if="view_manager.action" value="edit" t-att-data-model="view_manager.action.type" t-att-data-id="view_manager.action.id"> - Edit Action</option>
+ <option value="fvg">Fields View Get</option>
+ <option value="fields">View Fields</option>
+ <t t-if="view_manager.session.uid === 1">
+ <option value="manage_views">Manage Views</option>
+ <option value="edit" data-model="ir.ui.view" t-att-data-id="view.fields_view.view_id">Edit <t t-esc="_.str.capitalize(view.fields_view.type)"/>View</option>
+ <option t-if="view_manager.searchview" value="edit" data-model="ir.ui.view" t-att-data-id="view_manager.searchview.view_id">Edit SearchView</option>
+ <option t-if="view_manager.action" value="edit" t-att-data-model="view_manager.action.type" t-att-data-id="view_manager.action.id">Edit Action</option>
+ <option value="customize_object">Customize Object</option>
+ <option value="edit_workflow">Edit Workflow</option>
+ </t>
</t>
<t t-extend="ViewManager" t-name="One2Many.viewmanager">
<t t-jquery="span.oe_view_title_text" t-operation="replace"/>
@@ -743,7 +749,7 @@
<li t-foreach="attachments" t-as="attachment">
<t t-if="attachment.type == 'binary'" t-set="attachment.url" t-value="_s + '/web/binary/saveas?session_id='
+ session.session_id + '&amp;model=ir.attachment&amp;id=' + attachment.id
- + '&amp;field=datas&amp;fieldname=name&amp;t=' + (new Date().getTime())"/>
+ + '&amp;field=datas&amp;filename_field=name&amp;t=' + (new Date().getTime())"/>
<a class="oe-sidebar-attachments-link" t-att-href="attachment.url" target="_blank">
<t t-esc="attachment.name"/>
</a>
@@ -1411,14 +1417,10 @@
<button type="button" class="oe_button oe_formopenpopup-form-close">Cancel</button>
</t>
<t t-extend="ListView.row">
- <!-- adds front & back padding to row being rendered after edition, if
- necessary (if not selectable add front padding and if not deletable
- add back padding), otherwise the row being added is missing columns
+ <!-- adds back padding to row being rendered after edition, if necessary
+ (if not deletable add back padding), otherwise the row being added is
+ missing columns
-->
- <t t-jquery="&gt; :first" t-operation="before">
- <td t-if="edited and !options.selectable" class="oe-listview-padding"/>
- <td t-if="edited and !options.isClarkGable" class="oe-listview-padding"/>
- </t>
<t t-jquery="&gt; :last" t-operation="after">
<td t-if="edited and !options.deletable" class="oe-listview-padding"/>
</t>
@@ -1644,7 +1646,7 @@
<t t-name="ImportDataView">
<form name="import_data" id="import_data" action="" method="post" enctype="multipart/form-data"
class="oe-import oe-import-no-result">
- <input type="hidden" name="session_id" t-att-value="session.session_id"/>
+ <input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
<h2 class="separator horizontal">1. Import a .CSV file</h2>
<p>Select a .CSV file to import. If you need a sample of file to import,
you should use the export tool with the "Import Compatible" option.
@@ -1715,6 +1717,7 @@
<t t-name="About-Page">
<div>
+ <a class="oe_activate_debug_mode" href="?debug">Debug mode</a>
<h1>OpenERP Web</h1>
<h3 style="padding:0 5px 5px">Version <t t-esc="version_info.version"/></h3>
<p>
diff --git a/addons/web/static/test/formats.js b/addons/web/static/test/formats.js
index 69557e98d5e..b841d12a6b2 100644
--- a/addons/web/static/test/formats.js
+++ b/addons/web/static/test/formats.js
@@ -61,6 +61,17 @@ $(document).ready(function () {
var str = openerp.web.format_value(date, {type:"time"});
equal(str, date.toString("HH:mm:ss"));
});
+ test("format_float_time", function () {
+ strictEqual(
+ openerp.web.format_value(1.0, {type:'float', widget:'float_time'}),
+ '01:00');
+ strictEqual(
+ openerp.web.format_value(0.9853, {type:'float', widget:'float_time'}),
+ '00:59');
+ strictEqual(
+ openerp.web.format_value(0.0085, {type:'float', widget:'float_time'}),
+ '00:01');
+ });
test("format_float", function () {
var fl = 12.1234;
var str = openerp.web.format_value(fl, {type:"float"});
diff --git a/addons/web/static/test/list-utils.js b/addons/web/static/test/list-utils.js
index f71da82a560..8cc34454cd5 100644
--- a/addons/web/static/test/list-utils.js
+++ b/addons/web/static/test/list-utils.js
@@ -170,6 +170,16 @@ $(document).ready(function () {
equal(c.get(2), undefined);
strictEqual(c.at(1).get('value'), 20);
});
+ test('Remove unbind', function () {
+ var changed = false,
+ c = new openerp.web.list.Collection([ {id: 1, value: 5} ]);
+ c.bind('change', function () { changed = true; });
+ var record = c.get(1);
+ c.remove(record);
+ record.set('value', 42);
+ ok(!changed, 'removed records should not trigger events in their ' +
+ 'parent collection');
+ });
test('Reset', function () {
var event, obj, c = new openerp.web.list.Collection([
{id: 1, value: 5},
@@ -190,6 +200,16 @@ $(document).ready(function () {
strictEqual(c.length, 1);
strictEqual(c.get(42).get('value'), 55);
});
+ test('Reset unbind', function () {
+ var changed = false,
+ c = new openerp.web.list.Collection([ {id: 1, value: 5} ]);
+ c.bind('change', function () { changed = true; });
+ var record = c.get(1);
+ c.reset();
+ record.set('value', 42);
+ ok(!changed, 'removed records should not trigger events in their ' +
+ 'parent collection');
+ });
test('Events propagation', function () {
var values = [];
diff --git a/addons/web/static/test/test.html b/addons/web/static/test/test.html
index b1018bc00ca..da06aba2364 100644
--- a/addons/web/static/test/test.html
+++ b/addons/web/static/test/test.html
@@ -14,6 +14,7 @@
<!-- jquery -->
<script src="/web/static/lib/jquery/jquery-1.6.4.js"></script>
<script src="/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.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>