Unable to find the module [${module}], please check that the module
+ name is correct and the module is on OpenERP's path.
+<< Back to tests
+""")
+TESTING = Template(u"""
+
+<%def name="to_path(module, p)">/${module}/${p}%def>
+
+
+
+ OpenERP Web Tests
+
+
+
+
+
+
+
+
+
+
+
+% for module, jss, tests, templates in files:
+ % for js in jss:
+
+ % endfor
+ % if tests or templates:
+
+ % endif
+ % if tests:
+ % for test in tests:
+
+ % endfor
+ % endif
+% endfor
+
+""")
+
+class TestRunnerController(Controller):
+ _cp_path = '/web/tests'
+
+ @httprequest
+ def index(self, req, mod=None, **kwargs):
+ ms = module.get_modules()
+ manifests = dict(
+ (name, desc)
+ for name, desc in zip(ms, map(self.load_manifest, ms))
+ if desc # remove not-actually-openerp-modules
+ )
+
+ if not mod:
+ return NOMODULE_TEMPLATE.render(modules=(
+ (manifest['name'], name)
+ for name, manifest in manifests.iteritems()
+ if any(testfile.endswith('.js')
+ for testfile in manifest['test'])
+ ))
+ sorted_mods = module_topological_sort(dict(
+ (name, manifest.get('depends', []))
+ for name, manifest in manifests.iteritems()
+ ))
+ # to_load and to_test should be zippable lists of the same length.
+ # A falsy value in to_test indicate nothing to test at that index (just
+ # load the corresponding part of to_load)
+ to_test = sorted_mods
+ if mod != '*':
+ if mod not in manifests:
+ return req.not_found(NOTFOUND.render(module=mod))
+ idx = sorted_mods.index(mod)
+ to_test = [None] * len(sorted_mods)
+ to_test[idx] = mod
+
+ tests_candicates = [
+ filter(lambda path: path.endswith('.js'),
+ manifests[mod]['test'] if mod else [])
+ for mod in to_test]
+ # remove trailing test-less modules
+ tests = reversed(list(
+ itertools.dropwhile(
+ operator.not_,
+ reversed(tests_candicates))))
+
+ files = [
+ (mod, manifests[mod]['js'], tests, manifests[mod]['qweb'])
+ for mod, tests in itertools.izip(sorted_mods, tests)
+ ]
+
+ # if all three db_info parameters are present, send them to the page
+ db_info = dict((k, v) for k, v in kwargs.iteritems()
+ if k in ['source', 'supadmin', 'password'])
+ if len(db_info) != 3:
+ db_info = None
+
+ return TESTING.render(files=files, dependencies=json.dumps(
+ [name for name in sorted_mods
+ if module.get_module_resource(name, 'static')
+ if manifests[name]['js']]), db_info=json.dumps(db_info))
+
+ def load_manifest(self, name):
+ manifest = module.load_information_from_description_file(name)
+ if manifest:
+ path = module.get_module_path(name)
+ manifest['js'] = list(
+ self.expand_patterns(path, manifest.get('js', [])))
+ manifest['test'] = list(
+ self.expand_patterns(path, manifest.get('test', [])))
+ manifest['qweb'] = list(
+ self.expand_patterns(path, manifest.get('qweb', [])))
+ return manifest
+
+ def expand_patterns(self, root, patterns):
+ for pattern in patterns:
+ normalized_pattern = os.path.normpath(os.path.join(root, pattern))
+ for path in glob.glob(normalized_pattern):
+ # replace OS path separators (from join & normpath) by URI ones
+ yield path[len(root):].replace(os.path.sep, '/')
diff --git a/addons/web/doc/async.rst b/addons/web/doc/async.rst
index d597df0ddb0..6782fdac029 100644
--- a/addons/web/doc/async.rst
+++ b/addons/web/doc/async.rst
@@ -1,9 +1,6 @@
Asynchronous Operations
=======================
-This documentation is outdated as then() is now pipe. Please never copy api
-from other libraries just link to it.
-
As a language (and runtime), javascript is fundamentally
single-threaded. This means any blocking request or computation will
blocks the whole page (and, in older browsers, the software itself
@@ -46,8 +43,8 @@ directly to asynchronous methods is the ability to :ref:`compose them
Using deferreds
~~~~~~~~~~~~~~~
-deferreds have only one method of importance: :js:func:`Deferred.then`. This
-method is used to attach new callbacks to the deferred object.
+Deferreds's most important method is :js:func:`Deferred.then`. It is
+used to attach new callbacks to the deferred object.
* the first parameter attaches a success callback, called when the
deferred object is successfully resolved and provided with the
@@ -179,9 +176,9 @@ Deferred chaining
A second useful composition is starting an asynchronous operation as
the result of an other asynchronous operation, and wanting the result
-of both: :js:func:`Deferred.then` returns the deferred on which it was
-called, so handle e.g. OpenERP's search/read sequence with this would
-require something along the lines of:
+of both: with the tools described so far, handling e.g. OpenERP's
+search/read sequence with this would require something along the lines
+of:
.. code-block:: javascript
@@ -196,21 +193,14 @@ require something along the lines of:
While it doesn't look too bad for trivial code, this quickly gets
unwieldy.
-Instead, jQuery provides a tool to handle this kind of chains:
-:js:func:`Deferred.pipe`.
-
-:js:func:`~Deferred.pipe` has the same signature as
-:js:func:`~Deferred.then` and could be used in the same manner
-provided its return value was not used.
-
-It differs from :js:func:`~Deferred.then` in two ways: it returns a
-new promise object, not the one it was called with, and the return
-values of the callbacks is actually important to it: whichever
-callback is called,
+But :js:func:`~Deferred.then` also allows handling this kind of
+chains: it returns a new promise object, not the one it was called
+with, and the return values of the callbacks is actually important to
+it: whichever callback is called,
* If the callback is not set (not provided or left to null), the
resolution or rejection value(s) is simply forwarded to
- :js:func:`~Deferred.pipe`'s promise (it's essentially a noop)
+ :js:func:`~Deferred.then`'s promise (it's essentially a noop)
* If the callback is set and does not return an observable object (a
deferred or a promise), the value it returns (``undefined`` if it
@@ -218,7 +208,7 @@ callback is called,
.. code-block:: javascript
- promise.pipe(function () {
+ promise.then(function () {
console.log('called');
});
@@ -235,7 +225,7 @@ callback is called,
.. code-block:: javascript
- return Model.search(condition).pipe(function (ids) {
+ return Model.search(condition).then(function (ids) {
return Model.read(ids, fields);
});
@@ -244,12 +234,109 @@ callback is called,
will be resolved with ``read``'s resolution values if the chain
executes correctly.
-:js:func:`~Deferred.pipe` is also useful to adapt third-party
+:js:func:`~Deferred.then` is also useful to adapt third-party
promise-based APIs, in order to filter their resolution value counts
-for instance (to take advantage of :js:func:`when` 's special treatment
-of single-value promises).
+for instance (to take advantage of :js:func:`when` 's special
+treatment of single-value promises).
+jQuery.Deferred API
+~~~~~~~~~~~~~~~~~~~
+
+.. js:function:: when(deferreds…)
+
+ :param deferreds: deferred objects to multiplex
+ :returns: a multiplexed deferred
+ :rtype: :js:class:`Deferred`
+
+.. js:class:: Deferred
+
+ .. js:function:: Deferred.then(doneCallback[, failCallback])
+
+ Attaches new callbacks to the resolution or rejection of the
+ deferred object. Callbacks are executed in the order they are
+ attached to the deferred.
+
+ To provide only a failure callback, pass ``null`` as the
+ ``doneCallback``, to provide only a success callback the
+ second argument can just be ignored (and not passed at all).
+
+ Returns a new deferred which resolves to the result of the
+ corresponding callback, if a callback returns a deferred
+ itself that new deferred will be used as the resolution of the
+ chain.
+
+ :param doneCallback: function called when the deferred is resolved
+ :type doneCallback: Function
+ :param failCallback: function called when the deferred is rejected
+ :type failCallback: Function
+ :returns: the deferred object on which it was called
+ :rtype: :js:class:`Deferred`
+
+ .. js:function:: Deferred.done(doneCallback)
+
+ Attaches a new success callback to the deferred, shortcut for
+ ``deferred.then(doneCallback)``.
+
+ This is a jQuery extension to `CommonJS Promises/A`_ providing
+ little value over calling :js:func:`~Deferred.then` directly,
+ it should be avoided.
+
+ :param doneCallback: function called when the deferred is resolved
+ :type doneCallback: Function
+ :returns: the deferred object on which it was called
+ :rtype: :js:class:`Deferred`
+
+ .. js:function:: Deferred.fail(failCallback)
+
+ Attaches a new failure callback to the deferred, shortcut for
+ ``deferred.then(null, failCallback)``.
+
+ A second jQuery extension to `Promises/A `_. Although it provides more value than
+ :js:func:`~Deferred.done`, it still is not much and should be
+ avoided as well.
+
+ :param failCallback: function called when the deferred is rejected
+ :type failCallback: Function
+ :returns: the deferred object on which it was called
+ :rtype: :js:class:`Deferred`
+
+ .. js:function:: Deferred.promise()
+
+ Returns a read-only view of the deferred object, with all
+ mutators (resolve and reject) methods removed.
+
+ .. js:function:: Deferred.resolve(value…)
+
+ Called to resolve a deferred, any value provided will be
+ passed onto the success handlers of the deferred object.
+
+ Resolving a deferred which has already been resolved or
+ rejected has no effect.
+
+ .. js:function:: Deferred.reject(value…)
+
+ Called to reject (fail) a deferred, any value provided will be
+ passed onto the failure handler of the deferred object.
+
+ Rejecting a deferred which has already been resolved or
+ rejected has no effect.
+
+.. [#] or simply calling :js:class:`Deferred` as a function, the
+ result is the same
+
+.. [#] or not-promises, the `CommonJS Promises/B`_ role of
+ :js:func:`when` is to be able to treat values and promises
+ uniformly: :js:func:`when` will pass promises through directly,
+ but non-promise values and objects will be transformed into a
+ resolved promise (resolving themselves with the value itself).
+
+ jQuery's :js:func:`when` keeps this behavior making deferreds
+ easy to build from "static" values, or allowing defensive code
+ where expected promises are wrapped in :js:func:`when` just in
+ case.
+
.. _promises: http://en.wikipedia.org/wiki/Promise_(programming)
.. _jQuery's deferred: http://api.jquery.com/category/deferred-object/
.. _CommonJS Promises/A: http://wiki.commonjs.org/wiki/Promises/A
diff --git a/addons/web/doc/changelog-7.0.rst b/addons/web/doc/changelog-7.0.rst
index 96ed1ae18a2..b801c11b945 100644
--- a/addons/web/doc/changelog-7.0.rst
+++ b/addons/web/doc/changelog-7.0.rst
@@ -15,7 +15,7 @@ DataSet -> Model
----------------
The 6.1 ``DataSet`` API has been deprecated in favor of the smaller
-and more orthogonal :doc:`Model ` API, which more closely
+and more orthogonal :doc:`Model ` API, which more closely
matches the API in OpenERP Web's Python side and in OpenObject addons
and removes most stateful behavior of DataSet.
diff --git a/addons/web/doc/dev_client_action.rst b/addons/web/doc/client_action.rst
similarity index 100%
rename from addons/web/doc/dev_client_action.rst
rename to addons/web/doc/client_action.rst
diff --git a/addons/web/doc/conf.py b/addons/web/doc/conf.py
index ac5b8907e0e..54434190707 100644
--- a/addons/web/doc/conf.py
+++ b/addons/web/doc/conf.py
@@ -16,10 +16,9 @@ import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
sys.path.append(os.path.abspath('_themes'))
-sys.path.append(os.path.abspath('..'))
-sys.path.append(os.path.abspath('../openerp'))
+sys.path.insert(0, os.path.abspath('../addons'))
+sys.path.insert(0, os.path.abspath('..'))
# -- General configuration -----------------------------------------------------
@@ -43,7 +42,7 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
-project = u'OpenERP Server Developers Documentation'
+project = u'OpenERP Web Developers Documentation'
copyright = u'2012, OpenERP s.a.'
# The version info for the project you're documenting, acts as replacement for
@@ -53,7 +52,7 @@ copyright = u'2012, OpenERP s.a.'
# The short X.Y version.
version = '7.0'
# The full version, including alpha/beta/rc tags.
-release = '7.0b'
+release = '7.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -171,7 +170,7 @@ html_sidebars = {
#html_file_suffix = None
# Output file base name for HTML help builder.
-htmlhelp_basename = 'openerp-server-doc'
+htmlhelp_basename = 'openerp-web-doc'
# -- Options for LaTeX output --------------------------------------------------
@@ -190,7 +189,7 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'openerp-server-doc.tex', u'OpenERP Server Developers Documentation',
+ ('index', 'openerp-web-doc.tex', u'OpenERP Web Developers Documentation',
u'OpenERP s.a.', 'manual'),
]
@@ -220,7 +219,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- ('index', 'openerp-server-doc', u'OpenERP Server Developers Documentation',
+ ('index', 'openerp-web-doc', u'OpenERP Web Developers Documentation',
[u'OpenERP s.a.'], 1)
]
@@ -234,8 +233,8 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ('index', 'OpenERPServerDocumentation', u'OpenERP Server Developers Documentation',
- u'OpenERP s.a.', 'OpenERPServerDocumentation', 'Developers documentation for the openobject-server project.',
+ ('index', 'OpenERPWebDocumentation', u'OpenERP Web Developers Documentation',
+ u'OpenERP s.a.', 'OpenERPWebDocumentation', 'Developers documentation for the openerp-web project.',
'Miscellaneous'),
]
@@ -248,10 +247,12 @@ texinfo_documents = [
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
+todo_include_todos = True
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'python': ('http://docs.python.org/', None),
- 'openerpweb': ('http://doc.openerp.com/trunk/developers/web', None),
+ 'openerpserver': ('http://doc.openerp.com/trunk/developers/server', None),
'openerpdev': ('http://doc.openerp.com/trunk/developers', None),
+ 'openerpcommand': ('http://doc.openerp.com/trunk/developers/command', None),
}
diff --git a/addons/web/doc/internal_form.rst b/addons/web/doc/form_view.rst
similarity index 100%
rename from addons/web/doc/internal_form.rst
rename to addons/web/doc/form_view.rst
diff --git a/addons/web/doc/images/db-query.png b/addons/web/doc/images/db-query.png
new file mode 100644
index 00000000000..e063b724001
Binary files /dev/null and b/addons/web/doc/images/db-query.png differ
diff --git a/addons/web/doc/images/runner.png b/addons/web/doc/images/runner.png
new file mode 100644
index 00000000000..bd48e9d2922
Binary files /dev/null and b/addons/web/doc/images/runner.png differ
diff --git a/addons/web/doc/images/runner2.png b/addons/web/doc/images/runner2.png
new file mode 100644
index 00000000000..38ea2949cfc
Binary files /dev/null and b/addons/web/doc/images/runner2.png differ
diff --git a/addons/web/doc/images/tests.png b/addons/web/doc/images/tests.png
new file mode 100644
index 00000000000..84083d9e5ed
Binary files /dev/null and b/addons/web/doc/images/tests.png differ
diff --git a/addons/web/doc/images/tests2.png b/addons/web/doc/images/tests2.png
new file mode 100644
index 00000000000..c8a6f8ae9ee
Binary files /dev/null and b/addons/web/doc/images/tests2.png differ
diff --git a/addons/web/doc/images/tests3.png b/addons/web/doc/images/tests3.png
new file mode 100644
index 00000000000..247f70716af
Binary files /dev/null and b/addons/web/doc/images/tests3.png differ
diff --git a/addons/web/doc/index.rst b/addons/web/doc/index.rst
index b79762431fa..06534c50903 100644
--- a/addons/web/doc/index.rst
+++ b/addons/web/doc/index.rst
@@ -14,18 +14,18 @@ Contents:
presentation
async
- dev_rpc
- dev_widget
- dev_qweb
- dev_client_action
+ testing
- internal_form
- internal_list
- internal_search
+ widget
+ qweb
+ rpc
+ client_action
+ form_view
+ search_view
+ list_view
changelog-7.0
-
Indices and tables
==================
diff --git a/addons/web/doc/internal_list.rst b/addons/web/doc/list_view.rst
similarity index 99%
rename from addons/web/doc/internal_list.rst
rename to addons/web/doc/list_view.rst
index c1ed4dcde89..51188d95f7b 100644
--- a/addons/web/doc/internal_list.rst
+++ b/addons/web/doc/list_view.rst
@@ -451,7 +451,7 @@ formview, delegating instead to its
created.
The result should be a valid form view, see :doc:`Form Notes
- ` for various peculiarities of the form view
+ ` for various peculiarities of the form view
format.
:param editor: editor object asking for the view
diff --git a/addons/web/doc/dev_qweb.rst b/addons/web/doc/qweb.rst
similarity index 100%
rename from addons/web/doc/dev_qweb.rst
rename to addons/web/doc/qweb.rst
diff --git a/addons/web/doc/dev_rpc.rst b/addons/web/doc/rpc.rst
similarity index 100%
rename from addons/web/doc/dev_rpc.rst
rename to addons/web/doc/rpc.rst
diff --git a/addons/web/doc/internal_search.rst b/addons/web/doc/search_view.rst
similarity index 100%
rename from addons/web/doc/internal_search.rst
rename to addons/web/doc/search_view.rst
diff --git a/addons/web/doc/test-report.txt b/addons/web/doc/test-report.txt
new file mode 100644
index 00000000000..ce52618fe20
--- /dev/null
+++ b/addons/web/doc/test-report.txt
@@ -0,0 +1,25 @@
+test_empty_find (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok
+test_ids_shortcut (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok
+test_regular_find (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok
+web.testing.stack: direct, value, success ... ok
+web.testing.stack: direct, deferred, success ... ok
+web.testing.stack: direct, value, error ... ok
+web.testing.stack: direct, deferred, failure ... ok
+web.testing.stack: successful setup ... ok
+web.testing.stack: successful teardown ... ok
+web.testing.stack: successful setup and teardown ... ok
+
+[snip ~150 lines]
+
+test_convert_complex_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
+test_convert_complex_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
+test_convert_literal_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
+test_convert_literal_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
+test_retrieve_nonliteral_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
+test_retrieve_nonliteral_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
+
+----------------------------------------------------------------------
+Ran 181 tests in 15.706s
+
+OK
+
diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst
new file mode 100644
index 00000000000..600d379aa02
--- /dev/null
+++ b/addons/web/doc/testing.rst
@@ -0,0 +1,693 @@
+.. highlight:: javascript
+
+Testing in OpenERP Web
+======================
+
+Javascript Unit Testing
+-----------------------
+
+OpenERP Web 7.0 includes means to unit-test both the core code of
+OpenERP Web and your own javascript modules. On the javascript side,
+unit-testing is based on QUnit_ with a number of helpers and
+extensions for better integration with OpenERP.
+
+To see what the runner looks like, find (or start) an OpenERP server
+with the web client enabled, and navigate to ``/web/tests`` e.g. `on
+OpenERP's CI `_. This will
+show the runner selector, which lists all modules with javascript unit
+tests, and allows starting any of them (or all javascript tests in all
+modules at once).
+
+.. image:: ./images/runner.png
+ :align: center
+
+Clicking any runner button will launch the corresponding tests in the
+bundled QUnit_ runner:
+
+.. image:: ./images/tests.png
+ :align: center
+
+Writing a test case
+-------------------
+
+The first step is to list the test file(s). This is done through the
+``test`` key of the openerp manifest, by adding javascript files to it
+(next to the usual YAML files, if any):
+
+.. code-block:: python
+
+ {
+ 'name': "Demonstration of web/javascript tests",
+ 'category': 'Hidden',
+ 'depends': ['web'],
+ 'test': ['static/test/demo.js'],
+ }
+
+and to create the corresponding test file(s)
+
+.. note::
+
+ Test files which do not exist will be ignored, if all test files
+ of a module are ignored (can not be found), the test runner will
+ consider that the module has no javascript tests.
+
+After that, refreshing the runner selector will display the new module
+and allow running all of its (0 so far) tests:
+
+.. image:: ./images/runner2.png
+ :align: center
+
+The next step is to create a test case::
+
+ openerp.testing.section('basic section', function (test) {
+ test('my first test', function () {
+ ok(false, "this test has run");
+ });
+ });
+
+All testing helpers and structures live in the ``openerp.testing``
+module. OpenERP tests live in a :js:func:`~openerp.testing.section`,
+which is itself part of a module. The first argument to a section is
+the name of the section, the second one is the section body.
+
+:js:func:`test `, provided by the
+:js:func:`~openerp.testing.section` to the callback, is used to
+register a given test case which will be run whenever the test runner
+actually does its job. OpenERP Web test case use standard `QUnit
+assertions`_ within them.
+
+Launching the test runner at this point will run the test and display
+the corresponding assertion message, with red colors indicating the
+test failed:
+
+.. image:: ./images/tests2.png
+ :align: center
+
+Fixing the test (by replacing ``false`` to ``true`` in the assertion)
+will make it pass:
+
+.. image:: ./images/tests3.png
+ :align: center
+
+Assertions
+----------
+
+As noted above, OpenERP Web's tests use `qunit assertions`_. They are
+available globally (so they can just be called without references to
+anything). The following list is available:
+
+.. js:function:: ok(state[, message])
+
+ checks that ``state`` is truthy (in the javascript sense)
+
+.. js:function:: strictEqual(actual, expected[, message])
+
+ checks that the actual (produced by a method being tested) and
+ expected values are identical (roughly equivalent to ``ok(actual
+ === expected, message)``)
+
+.. js:function:: notStrictEqual(actual, expected[, message])
+
+ checks that the actual and expected values are *not* identical
+ (roughly equivalent to ``ok(actual !== expected, message)``)
+
+.. js:function:: deepEqual(actual, expected[, message])
+
+ deep comparison between actual and expected: recurse into
+ containers (objects and arrays) to ensure that they have the same
+ keys/number of elements, and the values match.
+
+.. js:function:: notDeepEqual(actual, expected[, message])
+
+ inverse operation to :js:func:`deepEqual`
+
+.. js:function:: throws(block[, expected][, message])
+
+ checks that, when called, the ``block`` throws an
+ error. Optionally validates that error against ``expected``.
+
+ :param Function block:
+ :param expected: if a regexp, checks that the thrown error's
+ message matches the regular expression. If an
+ error type, checks that the thrown error is of
+ that type.
+ :type expected: Error | RegExp
+
+.. js:function:: equal(actual, expected[, message])
+
+ checks that ``actual`` and ``expected`` are loosely equal, using
+ the ``==`` operator and its coercion rules.
+
+.. js:function:: notEqual(actual, expected[, message])
+
+ inverse operation to :js:func:`equal`
+
+Getting an OpenERP instance
+---------------------------
+
+The OpenERP instance is the base through which most OpenERP Web
+modules behaviors (functions, objects, …) are accessed. As a result,
+the test framework automatically builds one, and loads the module
+being tested and all of its dependencies inside it. This new instance
+is provided as the first positional parameter to your test
+cases. Let's observe by adding javascript code (not test code) to the
+test module:
+
+.. code-block:: python
+
+ {
+ 'name': "Demonstration of web/javascript tests",
+ 'category': 'Hidden',
+ 'depends': ['web'],
+ 'js': ['static/src/js/demo.js'],
+ 'test': ['static/test/demo.js'],
+ }
+
+::
+
+ // src/js/demo.js
+ openerp.web_tests_demo = function (instance) {
+ instance.web_tests_demo = {
+ value_true: true,
+ SomeType: instance.web.Class.extend({
+ init: function (value) {
+ this.value = value;
+ }
+ })
+ };
+ };
+
+and then adding a new test case, which simply checks that the
+``instance`` contains all the expected stuff we created in the
+module::
+
+ // test/demo.js
+ test('module content', function (instance) {
+ ok(instance.web_tests_demo.value_true, "should have a true value");
+ var type_instance = new instance.web_tests_demo.SomeType(42);
+ strictEqual(type_instance.value, 42, "should have provided value");
+ });
+
+DOM Scratchpad
+--------------
+
+As in the wider client, arbitrarily accessing document content is
+strongly discouraged during tests. But DOM access is still needed to
+e.g. fully initialize :js:class:`widgets <~openerp.web.Widget>` before
+testing them.
+
+Thus, a test case gets a DOM scratchpad as its second positional
+parameter, in a jQuery instance. That scratchpad is fully cleaned up
+before each test, and as long as it doesn't do anything outside the
+scratchpad your code can do whatever it wants::
+
+ // test/demo.js
+ test('DOM content', function (instance, $scratchpad) {
+ $scratchpad.html('
ok
');
+ ok($scratchpad.find('span').hasClass('foo'),
+ "should have provided class");
+ });
+ test('clean scratchpad', function (instance, $scratchpad) {
+ ok(!$scratchpad.children().length, "should have no content");
+ ok(!$scratchpad.text(), "should have no text");
+ });
+
+.. note::
+
+ The top-level element of the scratchpad is not cleaned up, test
+ cases can add text or DOM children but shoud not alter
+ ``$scratchpad`` itself.
+
+Loading templates
+-----------------
+
+To avoid the corresponding processing costs, by default templates are
+not loaded into QWeb. If you need to render e.g. widgets making use of
+QWeb templates, you can request their loading through the
+:js:attr:`~TestOptions.templates` option to the :js:func:`test case
+function `.
+
+This will automatically load all relevant templates in the instance's
+qweb before running the test case:
+
+.. code-block:: python
+
+ {
+ 'name': "Demonstration of web/javascript tests",
+ 'category': 'Hidden',
+ 'depends': ['web'],
+ 'js': ['static/src/js/demo.js'],
+ 'test': ['static/test/demo.js'],
+ 'qweb': ['static/src/xml/demo.xml'],
+ }
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+::
+
+ // test/demo.js
+ test('templates', {templates: true}, function (instance) {
+ var s = instance.web.qweb.render('DemoTemplate');
+ var texts = $(s).find('p').map(function () {
+ return $(this).text();
+ }).get();
+
+ deepEqual(texts, ['0', '1', '2', '3', '4']);
+ });
+
+Asynchronous cases
+------------------
+
+The test case examples so far are all synchronous, they execute from
+the first to the last line and once the last line has executed the
+test is done. But the web client is full of :doc:`asynchronous code
+`, and thus test cases need to be async-aware.
+
+This is done by returning a :js:class:`deferred ` from the
+case callback::
+
+ // test/demo.js
+ test('asynchronous', {
+ asserts: 1
+ }, function () {
+ var d = $.Deferred();
+ setTimeout(function () {
+ ok(true);
+ d.resolve();
+ }, 100);
+ return d;
+ });
+
+This example also uses the :js:class:`options parameter `
+to specify the number of assertions the case should expect, if less or
+more assertions are specified the case will count as failed.
+
+Asynchronous test cases *must* specify the number of assertions they
+will run. This allows more easily catching situations where e.g. the
+test architecture was not warned about asynchronous operations.
+
+.. note::
+
+ Asynchronous test cases also have a 2 seconds timeout: if the test
+ does not finish within 2 seconds, it will be considered
+ failed. This pretty much always means the test will not
+ resolve. This timeout *only* applies to the test itself, not to
+ the setup and teardown processes.
+
+.. note::
+
+ If the returned deferred is rejected, the test will be failed
+ unless :js:attr:`~TestOptions.fail_on_rejection` is set to
+ ``false``.
+
+RPC
+---
+
+An important subset of asynchronous test cases is test cases which
+need to perform (and chain, to an extent) RPC calls.
+
+.. note::
+
+ Because they are a subset of asynchronous cases, RPC cases must
+ also provide a valid :js:attr:`assertions count
+ `.
+
+By default, test cases will fail when trying to perform an RPC
+call. The ability to perform RPC calls must be explicitly requested by
+a test case (or its containing test suite) through
+:js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or
+``rpc``.
+
+Mock RPC
+++++++++
+
+The preferred (and fastest from a setup and execution time point of
+view) way to do RPC during tests is to mock the RPC calls: while
+setting up the test case, provide what the RPC responses "should" be,
+and only test the code between the "user" (the test itself) and the
+RPC call, before the call is effectively done.
+
+To do this, set the :js:attr:`rpc option ` to
+``mock``. This will add a third parameter to the test case callback:
+
+.. js:function:: mock(rpc_spec, handler)
+
+ Can be used in two different ways depending on the shape of the
+ first parameter:
+
+ * If it matches the pattern ``model:method`` (if it contains a
+ colon, essentially) the call will set up the mocking of an RPC
+ call straight to the OpenERP server (through XMLRPC) as
+ performed via e.g. :js:func:`openerp.web.Model.call`.
+
+ In that case, ``handler`` should be a function taking two
+ arguments ``args`` and ``kwargs``, matching the corresponding
+ arguments on the server side and should simply return the value
+ as if it were returned by the Python XMLRPC handler::
+
+ test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) {
+ // set up mocking
+ mock('people.famous:name_search', function (args, kwargs) {
+ strictEqual(kwargs.name, 'bob');
+ return [
+ [1, "Microsoft Bob"],
+ [2, "Bob the Builder"],
+ [3, "Silent Bob"]
+ ];
+ });
+
+ // actual test code
+ return new instance.web.Model('people.famous')
+ .call('name_search', {name: 'bob'}).then(function (result) {
+ strictEqual(result.length, 3, "shoud return 3 people");
+ strictEqual(result[0][1], "Microsoft Bob",
+ "the most famous bob should be Microsoft Bob");
+ });
+ });
+
+ * Otherwise, if it matches an absolute path (e.g. ``/a/b/c``) it
+ will mock a JSON-RPC call to a web client controller, such as
+ ``/web/webclient/translations``. In that case, the handler takes
+ a single ``params`` argument holding all of the parameters
+ provided over JSON-RPC.
+
+ As previously, the handler should simply return the result value
+ as if returned by the original JSON-RPC handler::
+
+ test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) {
+ var fetched_dbs = false, fetched_langs = false;
+ mock('/web/database/get_list', function () {
+ fetched_dbs = true;
+ return ['foo', 'bar', 'baz'];
+ });
+ mock('/web/session/get_lang_list', function () {
+ fetched_langs = true;
+ return [['vo_IS', 'Hopelandic / Vonlenska']];
+ });
+
+ // widget needs that or it blows up
+ instance.webclient = {toggle_bars: openerp.testing.noop};
+ var dbm = new instance.web.DatabaseManager({});
+ return dbm.appendTo($s).then(function () {
+ ok(fetched_dbs, "should have fetched databases");
+ ok(fetched_langs, "should have fetched languages");
+ deepEqual(dbm.db_list, ['foo', 'bar', 'baz']);
+ });
+ });
+
+.. note::
+
+ Mock handlers can contain assertions, these assertions should be
+ part of the assertions count (and if multiple calls are made to a
+ handler containing assertions, it multiplies the effective number
+ of assertions).
+
+.. _testing-rpc-rpc:
+
+Actual RPC
+++++++++++
+
+A more realistic (but significantly slower and more expensive) way to
+perform RPC calls is to perform actual calls to an actually running
+OpenERP server. To do this, set the :js:attr:`rpc option
+<~TestOptions.rpc>` to ``rpc``, it will not provide any new parameter
+but will enable actual RPC, and the automatic creation and destruction
+of databases (from a specified source) around tests.
+
+First, create a basic model we can test stuff with:
+
+.. code-block:: javascript
+
+ from openerp.osv import orm, fields
+
+ class TestObject(orm.Model):
+ _name = 'web_tests_demo.model'
+
+ _columns = {
+ 'name': fields.char("Name", required=True),
+ 'thing': fields.char("Thing"),
+ 'other': fields.char("Other", required=True)
+ }
+ _defaults = {
+ 'other': "bob"
+ }
+
+then the actual test::
+
+ test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) {
+ var Model = new instance.web.Model('web_tests_demo.model');
+ return Model.call('create', [{name: "Bob"}])
+ .then(function (id) {
+ return Model.call('read', [[id]]);
+ }).then(function (records) {
+ strictEqual(records.length, 1);
+ var record = records[0];
+ strictEqual(record.name, "Bob");
+ strictEqual(record.thing, false);
+ // default value
+ strictEqual(record.other, 'bob');
+ });
+ });
+
+This test looks like a "mock" RPC test but for the lack of mock
+response (and the different ``rpc`` type), however it has further
+ranging consequences in that it will copy an existing database to a
+new one, run the test in full on that temporary database and destroy
+the database, to simulate an isolated and transactional context and
+avoid affecting other tests. One of the consequences is that it takes
+a *long* time to run (5~10s, most of that time being spent waiting for
+a database duplication).
+
+Furthermore, as the test needs to clone a database, it also has to ask
+which database to clone, the database/super-admin password and the
+password of the ``admin`` user (in order to authenticate as said
+user). As a result, the first time the test runner encounters an
+``rpc: "rpc"`` test configuration it will produce the following
+prompt:
+
+.. image:: ./images/db-query.png
+ :align: center
+
+and stop the testing process until the necessary information has been
+provided.
+
+The prompt will only appear once per test run, all tests will use the
+same "source" database.
+
+.. note::
+
+ The handling of that information is currently rather brittle and
+ unchecked, incorrect values will likely crash the runner.
+
+.. note::
+
+ The runner does not currently store this information (for any
+ longer than a test run that is), the prompt will have to be filled
+ every time.
+
+Testing API
+-----------
+
+.. js:function:: openerp.testing.section(name[, options], body)
+
+ A test section, serves as shared namespace for related tests (for
+ constants or values to only set up once). The ``body`` function
+ should contain the tests themselves.
+
+ Note that the order in which tests are run is essentially
+ undefined, do *not* rely on it.
+
+ :param String name:
+ :param TestOptions options:
+ :param body:
+ :type body: Function<:js:func:`~openerp.testing.case`, void>
+
+.. js:function:: openerp.testing.case(name[, options], callback)
+
+ Registers a test case callback in the test runner, the callback
+ will only be run once the runner is started (or maybe not at all,
+ if the test is filtered out).
+
+ :param String name:
+ :param TestOptions options:
+ :param callback:
+ :type callback: Function>
+
+.. js:class:: TestOptions
+
+ the various options which can be passed to
+ :js:func:`~openerp.testing.section` or
+ :js:func:`~openerp.testing.case`. Except for
+ :js:attr:`~TestOptions.setup` and
+ :js:attr:`~TestOptions.teardown`, an option on
+ :js:func:`~openerp.testing.case` will overwrite the corresponding
+ option on :js:func:`~openerp.testing.section` so
+ e.g. :js:attr:`~TestOptions.rpc` can be set for a
+ :js:func:`~openerp.testing.section` and then differently set for
+ some :js:func:`~openerp.testing.case` of that
+ :js:func:`~openerp.testing.section`
+
+ .. js:attribute:: TestOptions.asserts
+
+ An integer, the number of assertions which should run during a
+ normal execution of the test. Mandatory for asynchronous tests.
+
+ .. js:attribute:: TestOptions.setup
+
+ Test case setup, run right before each test case. A section's
+ :js:func:`~TestOptions.setup` is run before the case's own, if
+ both are specified.
+
+ .. js:attribute:: TestOptions.teardown
+
+ Test case teardown, a case's :js:func:`~TestOptions.teardown`
+ is run before the corresponding section if both are present.
+
+ .. js:attribute:: TestOptions.fail_on_rejection
+
+ If the test is asynchronous and its resulting promise is
+ rejected, fail the test. Defaults to ``true``, set to
+ ``false`` to not fail the test in case of rejection::
+
+ // test/demo.js
+ test('unfail rejection', {
+ asserts: 1,
+ fail_on_rejection: false
+ }, function () {
+ var d = $.Deferred();
+ setTimeout(function () {
+ ok(true);
+ d.reject();
+ }, 100);
+ return d;
+ });
+
+ .. js:attribute:: TestOptions.rpc
+
+ RPC method to use during tests, one of ``"mock"`` or
+ ``"rpc"``. Any other value will disable RPC for the test (if
+ they were enabled by the suite for instance).
+
+ .. js:attribute:: TestOptions.templates
+
+ Whether the current module (and its dependencies)'s templates
+ should be loaded into QWeb before starting the test. A
+ boolean, ``false`` by default.
+
+The test runner can also use two global configuration values set
+directly on the ``window`` object:
+
+* ``oe_all_dependencies`` is an ``Array`` of all modules with a web
+ component, ordered by dependency (for a module ``A`` with
+ dependencies ``A'``, any module of ``A'`` must come before ``A`` in
+ the array)
+
+* ``oe_db_info`` is an object with 3 keys ``source``, ``supadmin`` and
+ ``password``. It is used to pre-configure :ref:`actual RPC
+ ` tests, to avoid a prompt being displayed
+ (especially for headless situations).
+
+Running through Python
+----------------------
+
+The web client includes the means to run these tests on the
+command-line (or in a CI system), but while actually running it is
+pretty simple the setup of the pre-requisite parts has some
+complexities.
+
+1. Install unittest2_ and QUnitSuite_ in your Python environment. Both
+ can trivially be installed via `pip `_ or
+ `easy_install
+ `_.
+
+ The former is the unit-testing framework used by OpenERP, the
+ latter is an adapter module to run qunit_ test suites and convert
+ their result into something unittest2_ can understand and report.
+
+2. Install PhantomJS_. It is a headless
+ browser which allows automating running and testing web
+ pages. QUnitSuite_ uses it to actually run the qunit_ test suite.
+
+ The PhantomJS_ website provides pre-built binaries for some
+ platforms, and your OS's package management probably provides it as
+ well.
+
+ If you're building PhantomJS_ from source, I recommend preparing
+ for some knitting time as it's not exactly fast (it needs to
+ compile both `Qt `_ and `Webkit
+ `_, both being pretty big projects).
+
+ .. note::
+
+ Because PhantomJS_ is webkit-based, it will not be able to test
+ if Firefox, Opera or Internet Explorer can correctly run the
+ test suite (and it is only an approximation for Safari and
+ Chrome). It is therefore recommended to *also* run the test
+ suites in actual browsers once in a while.
+
+ .. note::
+
+ The version of PhantomJS_ this was build through is 1.7,
+ previous versions *should* work but are not actually supported
+ (and tend to just segfault when something goes wrong in
+ PhantomJS_ itself so they're a pain to debug).
+
+3. Set up :ref:`OpenERP Command `,
+ which will be used to actually run the tests: running the qunit_
+ test suite requires a running server, so at this point OpenERP
+ Server isn't able to do it on its own during the building/testing
+ process.
+
+4. Install a new database with all relevant modules (all modules with
+ a web component at least), then restart the server
+
+ .. note::
+
+ For some tests, a source database needs to be duplicated. This
+ operation requires that there be no connection to the database
+ being duplicated, but OpenERP doesn't currently break
+ existing/outstanding connections, so restarting the server is
+ the simplest way to ensure everything is in the right state.
+
+5. Launch ``oe run-tests -d $DATABASE -mweb`` with the correct
+ addons-path specified (and replacing ``$DATABASE`` by the source
+ database you created above)
+
+ .. note::
+
+ If you leave out ``-mweb``, the runner will attempt to run all
+ the tests in all the modules, which may or may not work.
+
+If everything went correctly, you should now see a list of tests with
+(hopefully) ``ok`` next to their names, closing with a report of the
+number of tests run and the time it took:
+
+.. literalinclude:: test-report.txt
+ :language: text
+
+Congratulation, you have just performed a successful "offline" run of
+the OpenERP Web test suite.
+
+.. note::
+
+ Note that this runs all the Python tests for the ``web`` module,
+ but all the web tests for all of OpenERP. This can be surprising.
+
+.. _qunit: http://qunitjs.com/
+
+.. _qunit assertions: http://api.qunitjs.com/category/assert/
+
+.. _unittest2: http://pypi.python.org/pypi/unittest2
+
+.. _QUnitSuite: http://pypi.python.org/pypi/QUnitSuite/
+
+.. _PhantomJS: http://phantomjs.org/
diff --git a/addons/web/doc/dev_widget.rst b/addons/web/doc/widget.rst
similarity index 100%
rename from addons/web/doc/dev_widget.rst
rename to addons/web/doc/widget.rst
diff --git a/addons/web/http.py b/addons/web/http.py
index 1a636971fb5..fc80cb03864 100644
--- a/addons/web/http.py
+++ b/addons/web/http.py
@@ -11,6 +11,7 @@ import logging
import mimetypes
import os
import pprint
+import random
import sys
import tempfile
import threading
@@ -21,6 +22,7 @@ import urlparse
import uuid
import xmlrpclib
+import babel.core
import simplejson
import werkzeug.contrib.sessions
import werkzeug.datastructures
@@ -91,9 +93,25 @@ class WebRequest(object):
self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
self.session = self.httpsession.get(self.session_id)
if not self.session:
- self.httpsession[self.session_id] = self.session = session.OpenERPSession()
+ self.session = session.OpenERPSession()
+ self.httpsession[self.session_id] = self.session
self.context = self.params.pop('context', None)
- self.debug = self.params.pop('debug', False) != False
+ self.debug = self.params.pop('debug', False) is not False
+ # Determine self.lang
+ lang = self.params.get('lang', None)
+ if lang is None:
+ lang = self.session.eval_context(self.context).get('lang')
+ if lang is None:
+ lang = self.httprequest.cookies.get('lang')
+ if lang is None:
+ lang = self.httprequest.accept_languages.best
+ if lang is None:
+ lang = 'en_US'
+ # tranform 2 letters lang like 'en' into 5 letters like 'en_US'
+ lang = babel.core.LOCALE_ALIASES.get(lang, lang)
+ # we use _ as seprator where RFC2616 uses '-'
+ self.lang = lang.replace('-', '_')
+
class JsonRequest(WebRequest):
""" JSON-RPC2 over HTTP.
@@ -210,6 +228,10 @@ class JsonRequest(WebRequest):
_logger.debug("<--\n%s", pprint.pformat(response))
if jsonp:
+ # If we use jsonp, that's mean we are called from another host
+ # Some browser (IE and Safari) do no allow third party cookies
+ # We need then to manage http sessions manually.
+ response['httpsessionid'] = self.httpsession.sid
mime = 'application/javascript'
body = "%s(%s);" % (jsonp, simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder),)
else:
@@ -336,23 +358,13 @@ class Controller(object):
#----------------------------------------------------------
# Session context manager
#----------------------------------------------------------
-STORES = {}
-
@contextlib.contextmanager
-def session_context(request, storage_path, session_cookie='httpsessionid'):
- session_store, session_lock = STORES.get(storage_path, (None, None))
- if not session_store:
- session_store = werkzeug.contrib.sessions.FilesystemSessionStore( storage_path)
- session_lock = threading.Lock()
- STORES[storage_path] = session_store, session_lock
-
- sid = request.cookies.get(session_cookie)
+def session_context(request, session_store, session_lock, sid):
with session_lock:
if sid:
request.session = session_store.get(sid)
else:
request.session = session_store.new()
-
try:
yield request.session
finally:
@@ -404,6 +416,18 @@ def session_context(request, storage_path, session_cookie='httpsessionid'):
session_store.save(request.session)
+def session_gc(session_store):
+ if random.random() < 0.001:
+ # we keep session one week
+ last_week = time.time() - 60*60*24*7
+ for fname in os.listdir(session_store.path):
+ path = os.path.join(session_store.path, fname)
+ try:
+ if os.path.getmtime(path) < last_week:
+ os.unlink(path)
+ except OSError:
+ pass
+
#----------------------------------------------------------
# WSGI Application
#----------------------------------------------------------
@@ -434,26 +458,31 @@ class DisableCacheMiddleware(object):
start_response(status, new_headers)
return self.app(environ, start_wrapped)
+def session_path():
+ try:
+ username = getpass.getuser()
+ except Exception:
+ username = "unknown"
+ path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
+ if not os.path.exists(path):
+ os.mkdir(path, 0700)
+ return path
+
class Root(object):
"""Root WSGI application for the OpenERP Web Client.
"""
def __init__(self):
- self.httpsession_cookie = 'httpsessionid'
self.addons = {}
static_dirs = self._load_addons()
app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs)
self.dispatch = DisableCacheMiddleware(app)
- try:
- username = getpass.getuser()
- except Exception:
- username = "unknown"
- self.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
-
- if not os.path.exists(self.session_storage):
- os.mkdir(self.session_storage, 0700)
- _logger.debug('HTTP sessions stored in: %s', self.session_storage)
+ # Setup http sessions
+ path = session_path()
+ self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path)
+ self.session_lock = threading.Lock()
+ _logger.debug('HTTP sessions stored in: %s', path)
def __call__(self, environ, start_response):
""" Handle a WSGI request
@@ -476,8 +505,14 @@ class Root(object):
if not handler:
response = werkzeug.exceptions.NotFound()
else:
- with session_context(request, self.session_storage, self.httpsession_cookie) as session:
- result = handler( request)
+ sid = request.cookies.get('sid')
+ if not sid:
+ sid = request.args.get('sid')
+
+ session_gc(self.session_store)
+
+ with session_context(request, self.session_store, self.session_lock, sid) as session:
+ result = handler(request)
if isinstance(result, basestring):
headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
@@ -486,7 +521,7 @@ class Root(object):
response = result
if hasattr(response, 'set_cookie'):
- response.set_cookie(self.httpsession_cookie, session.sid)
+ response.set_cookie('sid', session.sid)
return response(environ, start_response)
@@ -530,7 +565,7 @@ class Root(object):
:rtype: ``Controller | None``
"""
if l:
- ps = '/' + '/'.join(l)
+ ps = '/' + '/'.join(filter(None, l))
method_name = 'index'
while ps:
c = controllers_path.get(ps)
diff --git a/addons/web/i18n/ar.po b/addons/web/i18n/ar.po
index e5d92071388..933e81f8772 100644
--- a/addons/web/i18n/ar.po
+++ b/addons/web/i18n/ar.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/bg.po b/addons/web/i18n/bg.po
index cb1ffd2c5ab..3cc1bb77ec8 100644
--- a/addons/web/i18n/bg.po
+++ b/addons/web/i18n/bg.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/bn.po b/addons/web/i18n/bn.po
index a1934f5346e..78d247805a3 100644
--- a/addons/web/i18n/bn.po
+++ b/addons/web/i18n/bn.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/bs.po b/addons/web/i18n/bs.po
index 525a46053bd..4ca035262f7 100644
--- a/addons/web/i18n/bs.po
+++ b/addons/web/i18n/bs.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ca.po b/addons/web/i18n/ca.po
index 8082c37717d..88fc0e32653 100644
--- a/addons/web/i18n/ca.po
+++ b/addons/web/i18n/ca.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/cs.po b/addons/web/i18n/cs.po
index a12beb474b9..ceb1015a763 100644
--- a/addons/web/i18n/cs.po
+++ b/addons/web/i18n/cs.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
"X-Poedit-Language: Czech\n"
#. openerp-web
diff --git a/addons/web/i18n/da.po b/addons/web/i18n/da.po
index 2f8d5ef4e36..a35bac7c918 100644
--- a/addons/web/i18n/da.po
+++ b/addons/web/i18n/da.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/de.po b/addons/web/i18n/de.po
index 078004291a0..552f1e30f1b 100644
--- a/addons/web/i18n/de.po
+++ b/addons/web/i18n/de.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/en_AU.po b/addons/web/i18n/en_AU.po
index bdcedadd13d..268be13bd10 100644
--- a/addons/web/i18n/en_AU.po
+++ b/addons/web/i18n/en_AU.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/en_GB.po b/addons/web/i18n/en_GB.po
index 59a4e42c925..48d5af11c8a 100644
--- a/addons/web/i18n/en_GB.po
+++ b/addons/web/i18n/en_GB.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/es.po b/addons/web/i18n/es.po
index 8a086ec3654..745ba60db93 100644
--- a/addons/web/i18n/es.po
+++ b/addons/web/i18n/es.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/es_CL.po b/addons/web/i18n/es_CL.po
index f52e92abcee..9c0839670f2 100644
--- a/addons/web/i18n/es_CL.po
+++ b/addons/web/i18n/es_CL.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/es_CR.po b/addons/web/i18n/es_CR.po
index c09f10df847..29b09fa3d6c 100644
--- a/addons/web/i18n/es_CR.po
+++ b/addons/web/i18n/es_CR.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
"Language: es\n"
#. openerp-web
diff --git a/addons/web/i18n/es_EC.po b/addons/web/i18n/es_EC.po
index 28de64fb3c2..2f834527232 100644
--- a/addons/web/i18n/es_EC.po
+++ b/addons/web/i18n/es_EC.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/et.po b/addons/web/i18n/et.po
index bc1e88e7cf9..fc4fd35beac 100644
--- a/addons/web/i18n/et.po
+++ b/addons/web/i18n/et.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/eu.po b/addons/web/i18n/eu.po
index 2f724a53987..1e4526e67cc 100644
--- a/addons/web/i18n/eu.po
+++ b/addons/web/i18n/eu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/fi.po b/addons/web/i18n/fi.po
index 9301615a6f5..ce97bef4c44 100644
--- a/addons/web/i18n/fi.po
+++ b/addons/web/i18n/fi.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/fr.po b/addons/web/i18n/fr.po
index bdcecc565d0..fdc3c87a399 100644
--- a/addons/web/i18n/fr.po
+++ b/addons/web/i18n/fr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/fr_CA.po b/addons/web/i18n/fr_CA.po
index 104237fcc96..63c777fed9c 100644
--- a/addons/web/i18n/fr_CA.po
+++ b/addons/web/i18n/fr_CA.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/gl.po b/addons/web/i18n/gl.po
index 82804e9a00b..e6a8a84970d 100644
--- a/addons/web/i18n/gl.po
+++ b/addons/web/i18n/gl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/gu.po b/addons/web/i18n/gu.po
index 0e9bb980006..eed6596d47d 100644
--- a/addons/web/i18n/gu.po
+++ b/addons/web/i18n/gu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/hi.po b/addons/web/i18n/hi.po
index 4ded6cef521..c3fec02900b 100644
--- a/addons/web/i18n/hi.po
+++ b/addons/web/i18n/hi.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/hr.po b/addons/web/i18n/hr.po
index 6ce16f5bda3..774b006975c 100644
--- a/addons/web/i18n/hr.po
+++ b/addons/web/i18n/hr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/hu.po b/addons/web/i18n/hu.po
index cea5493c029..9587dbd3081 100644
--- a/addons/web/i18n/hu.po
+++ b/addons/web/i18n/hu.po
@@ -9,13 +9,13 @@ msgstr ""
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
"PO-Revision-Date: 2012-10-26 12:17+0000\n"
-"Last-Translator: Herczeg Péter \n"
+"Last-Translator: Herczeg Péter \n"
"Language-Team: Hungarian \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-27 05:15+0000\n"
-"X-Generator: Launchpad (build 16194)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/id.po b/addons/web/i18n/id.po
index b681859b55a..12509847ba3 100644
--- a/addons/web/i18n/id.po
+++ b/addons/web/i18n/id.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/it.po b/addons/web/i18n/it.po
index 7df8f4c27bb..6f0f9025e18 100644
--- a/addons/web/i18n/it.po
+++ b/addons/web/i18n/it.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-23 05:05+0000\n"
-"X-Generator: Launchpad (build 16179)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ja.po b/addons/web/i18n/ja.po
index 3da4bb12ac5..ae6f58716ba 100644
--- a/addons/web/i18n/ja.po
+++ b/addons/web/i18n/ja.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ka.po b/addons/web/i18n/ka.po
index 1abd1880405..7c64ddb5ec9 100644
--- a/addons/web/i18n/ka.po
+++ b/addons/web/i18n/ka.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/lt.po b/addons/web/i18n/lt.po
index 195c0f3c82c..ecbe6ec4085 100644
--- a/addons/web/i18n/lt.po
+++ b/addons/web/i18n/lt.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-22 04:46+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
@@ -66,7 +66,7 @@ msgstr ""
#. openerp-web
#: addons/web/static/src/js/chrome.js:499
msgid "Restored"
-msgstr ""
+msgstr "Atkurta"
#. openerp-web
#: addons/web/static/src/js/chrome.js:499
@@ -253,7 +253,7 @@ msgstr ""
#: addons/web/static/src/js/formats.js:139
#, python-format
msgid "(%d records)"
-msgstr ""
+msgstr "(%d įrašai(-ų))"
#. openerp-web
#: addons/web/static/src/js/formats.js:325
@@ -265,7 +265,7 @@ msgstr "Atsisiųsti"
#: addons/web/static/src/js/formats.js:330
#, python-format
msgid "Download \"%s\""
-msgstr ""
+msgstr "Parsisiųsti \"%s\""
#. openerp-web
#: addons/web/static/src/js/search.js:437
@@ -527,12 +527,12 @@ msgstr "Forma"
#: addons/web/static/src/xml/base.xml:763
#: addons/web/static/src/xml/base.xml:1714
msgid "Delete"
-msgstr ""
+msgstr "Ištrinti"
#. openerp-web
#: addons/web/static/src/xml/base.xml:762
msgid "Duplicate"
-msgstr ""
+msgstr "Sukurti kopiją"
#. openerp-web
#: addons/web/static/src/js/view_form.js:133
@@ -589,12 +589,12 @@ msgstr ""
#: addons/web/static/src/js/view_form.js:2238
#, python-format
msgid " Create \"%s\""
-msgstr ""
+msgstr " Sukurti \"%s\""
#. openerp-web
#: addons/web/static/src/js/view_form.js:2244
msgid " Create and Edit..."
-msgstr ""
+msgstr " Sukurti ir redaguoti..."
#. openerp-web
#: addons/web/static/src/js/view_form.js:2277
@@ -606,7 +606,7 @@ msgstr "Paieška: "
#: addons/web/static/src/js/view_form.js:2277
#: addons/web/static/src/js/view_form.js:2765
msgid "Create: "
-msgstr ""
+msgstr "Sukurti "
#. openerp-web
#: addons/web/static/src/js/view_form.js:2062
@@ -668,7 +668,7 @@ msgstr "Grupė"
#. openerp-web
#: addons/web/static/src/js/view_list.js:549
msgid "Do you really want to remove these records?"
-msgstr ""
+msgstr "Ar tikrai norite ištrinti šiuos įrašus?"
#. openerp-web
#: addons/web/static/src/js/views.js:925
@@ -813,25 +813,25 @@ msgstr ""
#. openerp-web
#: addons/web/static/src/xml/base.xml:297
msgid "Invalid username or password"
-msgstr ""
+msgstr "Neteisingas naudotojo vardas arba slaptažodis"
#. openerp-web
#: addons/web/static/src/xml/base.xml:116
#: addons/web/static/src/xml/base.xml:150
#: addons/web/static/src/xml/base.xml:301
msgid "Database:"
-msgstr ""
+msgstr "Duomenų bazė:"
#. openerp-web
#: addons/web/static/src/xml/base.xml:306
msgid "Username"
-msgstr ""
+msgstr "Naudotojas"
#. openerp-web
#: addons/web/static/src/xml/base.xml:308
#: addons/web/static/src/xml/base.xml:331
msgid "Password"
-msgstr ""
+msgstr "Slaptažodis"
#. openerp-web
#: addons/web/static/src/xml/base.xml:310
@@ -870,17 +870,17 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:195
#: addons/web/static/src/xml/base.xml:330
msgid "Restore"
-msgstr ""
+msgstr "Atkurti"
#. openerp-web
#: addons/web/static/src/xml/base.xml:332
msgid "Back to Login"
-msgstr ""
+msgstr "Grįžti į prisijungimo langą"
#. openerp-web
#: addons/web/static/src/xml/base.xml:61
msgid "CREATE DATABASE"
-msgstr ""
+msgstr "SUKURTI DUOMENŲ BAZĘ"
#. openerp-web
#: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211
@@ -922,7 +922,7 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:162
#: addons/web/static/src/xml/base.xml:187
msgid "Master Password:"
-msgstr ""
+msgstr "Pagrindinis slaptažodis"
#. openerp-web
#: addons/web/static/src/xml/base.xml:143
@@ -932,7 +932,7 @@ msgstr ""
#. openerp-web
#: addons/web/static/src/xml/base.xml:175
msgid "RESTORE DATABASE"
-msgstr ""
+msgstr "ATKURTI DUOMENŲ BAZĘ"
#. openerp-web
#: addons/web/static/src/xml/base.xml:182
@@ -1012,17 +1012,17 @@ msgstr "OpenERP.com"
#. openerp-web
#: addons/web/static/src/xml/base.xml:1720
msgid "Old Password:"
-msgstr ""
+msgstr "Esamas slaptažodis:"
#. openerp-web
#: addons/web/static/src/xml/base.xml:1725
msgid "New Password:"
-msgstr ""
+msgstr "Naujas slaptažodis:"
#. openerp-web
#: addons/web/static/src/xml/base.xml:1730
msgid "Confirm Password:"
-msgstr ""
+msgstr "Patvirtinti slaptažodį:"
#. openerp-web
#: addons/web/static/src/xml/base.xml:390
@@ -1254,7 +1254,7 @@ msgstr ""
#: addons/web/static/src/xml/base.xml:1222
#: addons/web/static/src/xml/base.xml:1279
msgid "Clear"
-msgstr ""
+msgstr "Išvalyti"
#. openerp-web
#: addons/web/static/src/xml/base.xml:1179
@@ -1408,12 +1408,12 @@ msgstr ""
#. openerp-web
#: addons/web/static/src/xml/base.xml:1509
msgid "Save & New"
-msgstr ""
+msgstr "Išsaugoti ir sukurti naują"
#. openerp-web
#: addons/web/static/src/xml/base.xml:1510
msgid "Save & Close"
-msgstr ""
+msgstr "Išsaugoti ir uždaryti"
#. openerp-web
#: addons/web/static/src/xml/base.xml:1617
@@ -1572,9 +1572,6 @@ msgstr ""
#~ msgid "Advanced Filters"
#~ msgstr "Išplėstiniai filtrai"
-#~ msgid "Other Options"
-#~ msgstr "Kiti nustatymai"
-
#~ msgid "OK"
#~ msgstr "Gerai"
@@ -1602,3 +1599,22 @@ msgstr ""
#~ msgid "Reports"
#~ msgstr "Ataskaitos"
+
+#~ msgid "Other Options"
+#~ msgstr "Kitos parinktys"
+
+#~ msgid "LOGOUT"
+#~ msgstr "ATSIJUNGTI"
+
+#~ msgid "Create..."
+#~ msgstr "Sukurti..."
+
+#~ msgid "Search"
+#~ msgstr "Ieškoti"
+
+#~ msgid "Search..."
+#~ msgstr "Ieškoti..."
+
+#, python-format
+#~ msgid "[%(first_record)d to %(last_record)d] of %(records_count)d"
+#~ msgstr "[%(first_record)d iki %(last_record)d] iš %(records_count)d"
diff --git a/addons/web/i18n/mk.po b/addons/web/i18n/mk.po
index 62bef3d0015..30db39b4dfc 100644
--- a/addons/web/i18n/mk.po
+++ b/addons/web/i18n/mk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/mn.po b/addons/web/i18n/mn.po
index a862954b815..3ee9a552022 100644
--- a/addons/web/i18n/mn.po
+++ b/addons/web/i18n/mn.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/nb.po b/addons/web/i18n/nb.po
index f47de43b3cf..0b44af2712d 100644
--- a/addons/web/i18n/nb.po
+++ b/addons/web/i18n/nb.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/nl.po b/addons/web/i18n/nl.po
index 49631585157..eb80e4586ba 100644
--- a/addons/web/i18n/nl.po
+++ b/addons/web/i18n/nl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/nl_BE.po b/addons/web/i18n/nl_BE.po
index b3be018903b..04e45611f2d 100644
--- a/addons/web/i18n/nl_BE.po
+++ b/addons/web/i18n/nl_BE.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/pl.po b/addons/web/i18n/pl.po
index d5d854768d0..25cf2862611 100644
--- a/addons/web/i18n/pl.po
+++ b/addons/web/i18n/pl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
@@ -243,17 +243,19 @@ msgid ""
"Destination fields should only be selected once, some fields are selected "
"more than once:"
msgstr ""
+"Pola docelowe muszą być wybierane tylko raz. niektóre inne pola mogą być "
+"wybierane więcej niż raz:"
#. openerp-web
#: addons/web/static/src/js/data_import.js:386
msgid "*Required Fields are not selected :"
-msgstr ""
+msgstr "*Wymagane pola nie zostały wybrane :"
#. openerp-web
#: addons/web/static/src/js/formats.js:139
#, python-format
msgid "(%d records)"
-msgstr ""
+msgstr "(%d rekordów)"
#. openerp-web
#: addons/web/static/src/js/formats.js:325
diff --git a/addons/web/i18n/pt.po b/addons/web/i18n/pt.po
index 3bf3fa6062d..95f3c546400 100644
--- a/addons/web/i18n/pt.po
+++ b/addons/web/i18n/pt.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/pt_BR.po b/addons/web/i18n/pt_BR.po
index d950e97938c..6f14bf1f547 100644
--- a/addons/web/i18n/pt_BR.po
+++ b/addons/web/i18n/pt_BR.po
@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ro.po b/addons/web/i18n/ro.po
index 934e2e77f63..6a77472b1e4 100644
--- a/addons/web/i18n/ro.po
+++ b/addons/web/i18n/ro.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ru.po b/addons/web/i18n/ru.po
index ed5735602d0..341f683e953 100644
--- a/addons/web/i18n/ru.po
+++ b/addons/web/i18n/ru.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-11-02 05:20+0000\n"
-"X-Generator: Launchpad (build 16218)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sk.po b/addons/web/i18n/sk.po
index 39bdd647453..12b5d5a1c56 100644
--- a/addons/web/i18n/sk.po
+++ b/addons/web/i18n/sk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sl.po b/addons/web/i18n/sl.po
index 687742a1775..0c745f42d41 100644
--- a/addons/web/i18n/sl.po
+++ b/addons/web/i18n/sl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-11-02 05:20+0000\n"
-"X-Generator: Launchpad (build 16218)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sq.po b/addons/web/i18n/sq.po
index df11fea07c0..357e83e2bcf 100644
--- a/addons/web/i18n/sq.po
+++ b/addons/web/i18n/sq.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:02+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:07+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sr@latin.po b/addons/web/i18n/sr@latin.po
index f52bea117d6..9fc0e685c54 100644
--- a/addons/web/i18n/sr@latin.po
+++ b/addons/web/i18n/sr@latin.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sv.po b/addons/web/i18n/sv.po
index 64fc3c7e767..db6d9f7ae88 100644
--- a/addons/web/i18n/sv.po
+++ b/addons/web/i18n/sv.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/tr.po b/addons/web/i18n/tr.po
index 2467938d84d..9c5554bc028 100644
--- a/addons/web/i18n/tr.po
+++ b/addons/web/i18n/tr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/uk.po b/addons/web/i18n/uk.po
index 2b981ebf178..553beb5d123 100644
--- a/addons/web/i18n/uk.po
+++ b/addons/web/i18n/uk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/zh_CN.po b/addons/web/i18n/zh_CN.po
index 09a7d041b88..e66a5742745 100644
--- a/addons/web/i18n/zh_CN.po
+++ b/addons/web/i18n/zh_CN.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-11-07 04:55+0000\n"
-"X-Generator: Launchpad (build 16232)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/zh_TW.po b/addons/web/i18n/zh_TW.po
index b803a5c04c3..b07bc75ae31 100644
--- a/addons/web/i18n/zh_TW.po
+++ b/addons/web/i18n/zh_TW.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-21 05:03+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-11-15 05:08+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js b/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js
index 5929d591261..e978042f21b 100644
--- a/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js
+++ b/addons/web/static/lib/jquery.tipsy/jquery.tipsy.js
@@ -27,7 +27,8 @@
var $tip = this.tip();
$tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
- $tip[0].className = 'tipsy openerp oe_tooltip '; // reset classname in case of dynamic gravity
+ $tip[0].className = 'tipsy '; // reset classname in case of dynamic gravity
+ $tip.openerpClass('oe_tooltip');
$tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body);
var pos = $.extend({}, this.$element.offset(), {
diff --git a/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css b/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css
index a06e9447afc..f19c56caed1 100644
--- a/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css
+++ b/addons/web/static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css
@@ -1115,7 +1115,7 @@ body .ui-tooltip { border-width:2px; }
/*** Input field styling from Bootstrap **/
- input, textarea {
+/* input, textarea {
-webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
-moz-transition: border linear 0.2s, box-shadow linear 0.2s;
-ms-transition: border linear 0.2s, box-shadow linear 0.2s;
@@ -1137,12 +1137,12 @@ input[type=file]:focus, input[type=checkbox]:focus, select:focus {
-moz-box-shadow: none;
box-shadow: none;
outline: 1px dotted #666;
-}
+}*/
-input[type="text"],
-input[type="password"],
+/*input[type="text"],
+input[type="password"],*/
.ui-autocomplete-input,
-textarea,
+/*textarea,*/
.uneditable-input {
display: inline-block;
padding: 4px;
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 2b9a5bd92f3..d7d8d732762 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -20,20 +20,6 @@
font-style: normal;
}
-@media print {
- .oe_topbar, .oe_leftbar, .oe_loading {
- display: none !important;
- }
-}
-.openerp.openerp_webclient_container {
- height: 100%;
-}
-
-.text-tag .text-button {
- height: auto !important;
- min-height: 16px;
-}
-
.openerp {
padding: 0;
margin: 0;
@@ -46,6 +32,9 @@
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
*/
}
+.openerp.openerp_webclient_container {
+ height: 100%;
+}
.openerp :-moz-placeholder {
color: #afafb6 !important;
font-style: italic !important;
@@ -197,6 +186,10 @@
.openerp .oe_bounce_container {
display: inline-block;
}
+.openerp .text-tag .text-button {
+ height: auto !important;
+ min-height: 16px;
+}
.openerp .ui-tabs {
position: static;
}
@@ -1153,6 +1146,7 @@
height: 40px;
width: 157px;
margin: 14px 0;
+ border: 0;
}
.openerp .oe_footer {
position: fixed;
@@ -2323,16 +2317,16 @@
text-align: justify;
}
.openerp .oe_form_editable .oe_form .oe_form_field_integer input {
- width: 6em !important;
+ width: 6em;
}
.openerp .oe_form_editable .oe_form .oe_form_field_float input {
- width: 7em !important;
+ width: 7em;
}
.openerp .oe_form_editable .oe_form .oe_form_field_date input {
- width: 7.5em !important;
+ width: 7.5em;
}
.openerp .oe_form_editable .oe_form .oe_form_field_datetime input {
- width: 11.5em !important;
+ width: 11.5em;
}
.openerp .oe_hidden_input_file {
position: relative;
@@ -2378,6 +2372,77 @@
.openerp .oe_form .oe_form_field_image:hover .oe_form_field_image_controls {
display: block;
}
+.openerp .oe_fileupload {
+ display: inline-block;
+ clear: both;
+ width: 100%;
+}
+.openerp .oe_fileupload .oe_add {
+ float: left;
+ position: relative;
+ width: 100%;
+ left: 2px;
+ top: 7px;
+}
+.openerp .oe_fileupload .oe_add button {
+ display: inline;
+ height: 24px;
+ font-size: 12px;
+ line-height: 12px;
+ vertical-align: middle;
+}
+.openerp .oe_fileupload .oe_add button.oe_attach {
+ width: 24px;
+ overflow: hidden;
+ width: 24px;
+ overflow: hidden;
+ background: transparent;
+ color: #7c7bad;
+ box-shadow: none;
+ border: none;
+ text-shadow: none;
+}
+.openerp .oe_fileupload .oe_add button.oe_attach .oe_e {
+ position: relative;
+ top: -1px;
+ left: -9px;
+}
+.openerp .oe_fileupload .oe_add input.oe_form_binary_file {
+ display: inline-block;
+ margin-left: -5px;
+ height: 28px;
+ width: 52px;
+ margin-top: -26px;
+}
+.openerp .oe_fileupload .oe_add .oe_attach_label {
+ color: #7c7bad;
+ margin-left: -3px;
+}
+.openerp .oe_fileupload .oe_attachments {
+ margin-bottom: 4px;
+ margin-right: 0px;
+ font-size: 12px;
+ border-radius: 2px;
+ border: solid 1px rgba(124, 123, 173, 0.14);
+}
+.openerp .oe_fileupload .oe_attachments .oe_attachment {
+ padding: 2px;
+ padding-left: 4px;
+ padding-right: 4px;
+}
+.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e {
+ font-size: 23px;
+ margin-top: -5px;
+}
+.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e:hover {
+ text-decoration: none;
+}
+.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(odd) {
+ background: white;
+}
+.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(even) {
+ background: #f4f5fa;
+}
.openerp .oe_form_field_many2one td:first-child {
position: relative;
}
@@ -2391,6 +2456,9 @@
float: right;
padding-left: 2px;
}
+.openerp .oe_form_field_many2one input {
+ padding-right: 13px;
+}
.openerp.ui-autocomplete li.oe_m2o_dropdown_option a {
font-style: italic;
padding-left: 2em;
@@ -2595,32 +2663,33 @@
top: 5px;
}
.openerp .oe_list.oe_list_editable.oe_editing .oe_m2o_cm_button {
- display: none;
+ line-height: 19px;
+}
+.openerp .oe_list.oe_list_editable.oe_editing .oe_input_icon {
+ margin-top: 5px;
+}
+.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field {
+ min-width: 0;
+ max-width: none;
}
.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea {
height: 27px;
-}
-.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea {
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
border: 1px solid #aaaaff;
margin: 0;
}
+.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field select {
+ min-width: 0;
+}
.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_float input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_view_integer input {
text-align: right;
width: 100% !important;
}
-.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime > span, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date > span {
- width: 100% !important;
-}
.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime input.oe_datepicker_master, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date input.oe_datepicker_master {
width: 100% !important;
}
-.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field .oe_form_field_float, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field .oe_form_view_integer, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date {
- min-width: 0 !important;
- max-width: none !important;
-}
.openerp .oe_list_group_name {
white-space: nowrap;
}
@@ -2685,6 +2754,9 @@
text-align: right !important;
max-width: 100px;
}
+.openerp .oe_list_content td.oe_list_field_date, .openerp .oe_list_content th.oe_list_header_date {
+ min-width: 6em;
+}
.openerp .oe_list_content > thead {
border-bottom: 2px solid #cacaca;
background: #eeeeee;
@@ -2752,6 +2824,10 @@
.openerp .oe_list_content > tbody > tr > td.oe_list_checkbox:first-child:after, .openerp .oe_list_content > tbody > tr th.oe_list_checkbox:first-child:after {
border-width: 0;
}
+.openerp .oe_list_content > tbody > tr > td.oe_list_field_boolean input {
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+}
.openerp .oe_list_content > tbody > tr:nth-child(odd) {
background-color: #f0f0fa;
background-color: #f0f0fa;
@@ -2899,78 +2975,6 @@
color: #333333;
}
-.openerp .oe_fileupload {
- display: inline-block;
- clear: both;
- width: 100%;
-}
-.openerp .oe_fileupload .oe_add {
- float: left;
- position: relative;
- width: 100%;
- left: 2px;
- top: 7px;
-}
-.openerp .oe_fileupload .oe_add button {
- display: inline;
- height: 24px;
- font-size: 12px;
- line-height: 12px;
- vertical-align: middle;
-}
-.openerp .oe_fileupload .oe_add button.oe_attach {
- width: 24px;
- overflow: hidden;
- width: 24px;
- overflow: hidden;
- background: transparent;
- color: #7c7bad;
- box-shadow: none;
- border: none;
- text-shadow: none;
-}
-.openerp .oe_fileupload .oe_add button.oe_attach .oe_e {
- position: relative;
- top: -1px;
- left: -9px;
-}
-.openerp .oe_fileupload .oe_add input.oe_form_binary_file {
- display: inline-block;
- margin-left: -5px;
- height: 28px;
- width: 52px;
- margin-top: -26px;
-}
-.openerp .oe_fileupload .oe_add .oe_attach_label {
- color: #7c7bad;
- margin-left: -3px;
-}
-.openerp .oe_fileupload .oe_attachments {
- margin-bottom: 4px;
- margin-right: 0px;
- font-size: 12px;
- border-radius: 2px;
- border: solid 1px rgba(124, 123, 173, 0.14);
-}
-.openerp .oe_fileupload .oe_attachments .oe_attachment {
- padding: 2px;
- padding-left: 4px;
- padding-right: 4px;
-}
-.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e {
- font-size: 23px;
- margin-top: -5px;
-}
-.openerp .oe_fileupload .oe_attachments .oe_attachment .oe_e:hover {
- text-decoration: none;
-}
-.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(odd) {
- background: white;
-}
-.openerp .oe_fileupload .oe_attachments .oe_attachment:nth-child(even) {
- background: #f4f5fa;
-}
-
.kitten-mode-activated {
background-image: url(http://placekitten.com/g/1365/769);
background-size: cover;
@@ -3081,8 +3085,8 @@ div.res {
.openerp {
text-shadow: none;
}
- .openerp .oe_header_row, .openerp ul.oe_header, .openerp div.oe_mail_thread_action, .openerp .oe_mail_recthread_actions, .openerp .oe_button_box, .openerp .oe_form button, .openerp button.oe_invite, .openerp .oe_form header, .openerp .openerp .oe_notebook > li.ui-state-default {
- display: none;
+ .openerp .oe_header_row, .openerp ul.oe_header, .openerp div.oe_mail_thread_action, .openerp .oe_mail_recthread_actions, .openerp .oe_button_box, .openerp .oe_form button, .openerp button.oe_invite, .openerp .oe_form header, .openerp .openerp .oe_notebook > li.ui-state-default, .openerp .oe_topbar, .openerp .oe_leftbar, .openerp .oe_loading {
+ display: none !important;
}
.openerp .oe_list_content button, .openerp .oe_list_content input[type=checkbox] {
visibility: hidden;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index dc550a3ad9f..c349d3c0eff 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -140,18 +140,6 @@ $sheet-padding: 16px
// }}}
-@media print
- .oe_topbar, .oe_leftbar, .oe_loading
- display: none !important
-
-.openerp.openerp_webclient_container
- height: 100%
-
-// jQueryUI css bug fixing
-.text-tag .text-button
- height: auto !important
- min-height: 16px
-
.openerp
// Global style {{{
padding: 0
@@ -161,6 +149,8 @@ $sheet-padding: 16px
font-size: 13px
background: white
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5)
+ &.openerp_webclient_container
+ height: 100%
// }}}
//Placeholder style{{{
\:-moz-placeholder
@@ -254,6 +244,11 @@ $sheet-padding: 16px
.oe_bounce_container
display: inline-block
+ // Bug lp:1051746
+ .text-tag .text-button
+ height: auto !important
+ min-height: 16px
+
// bug noted in jquery ui CSS doesn't seem to occur in IE9,
// so remove position:relative
.ui-tabs
@@ -943,6 +938,7 @@ $sheet-padding: 16px
height: 40px
width: 157px
margin: 14px 0
+ border: 0
.oe_footer
position: fixed
bottom: 0
@@ -1852,13 +1848,13 @@ $sheet-padding: 16px
.oe_form_editable
.oe_form
.oe_form_field_integer input
- width: 6em !important
+ width: 6em
.oe_form_field_float input
- width: 7em !important
+ width: 7em
.oe_form_field_date input
- width: 7.5em !important
+ width: 7.5em
.oe_form_field_datetime input
- width: 11.5em !important
+ width: 11.5em
// }}}
// FormView.fields_binary {{{
/* http://www.quirksmode.org/dom/inputfile.html
@@ -1901,6 +1897,64 @@ $sheet-padding: 16px
@include box-sizing(border)
&:hover .oe_form_field_image_controls
display: block
+ .oe_fileupload
+ display: inline-block
+ clear: both
+ width: 100%
+ .oe_add
+ float: left
+ position: relative
+ width: 100%
+ left: +2px
+ top: +7px
+ button
+ display: inline
+ height: 24px
+ font-size: 12px
+ line-height: 12px
+ vertical-align: middle
+ button.oe_attach
+ width: 24px
+ overflow: hidden
+ width: 24px
+ overflow: hidden
+ background: transparent
+ color: #7C7BAD
+ box-shadow: none
+ border: none
+ text-shadow: none
+ .oe_e
+ position: relative
+ top: -1px
+ left: -9px
+ input.oe_form_binary_file
+ display: inline-block
+ margin-left: -5px
+ height: 28px
+ width: 52px
+ margin-top: -26px
+ .oe_attach_label
+ color: #7C7BAD
+ margin-left: -3px
+ .oe_attachments
+ margin-bottom: 4px
+ margin-right: 0px
+ font-size: 12px
+ border-radius: 2px
+ border: solid 1px rgba(124,123,173,0.14)
+ .oe_attachment
+ padding: 2px
+ padding-left: 4px
+ padding-right: 4px
+ .oe_e
+ font-size: 23px
+ margin-top: -5px
+ .oe_e:hover
+ text-decoration: none
+ .oe_attachment:nth-child(odd)
+ background: white
+ .oe_attachment:nth-child(even)
+ background: #F4F5FA
// }}}
// FormView.many2one {{{
.oe_form_field_many2one
@@ -1914,6 +1968,8 @@ $sheet-padding: 16px
line-height: 14px
float: right
padding-left: 2px
+ input
+ padding-right: 13px
&.ui-autocomplete
li.oe_m2o_dropdown_option a
font-style: italic
@@ -2056,26 +2112,26 @@ $sheet-padding: 16px
.oe_m2o_drop_down_button
top: 5px
.oe_m2o_cm_button
- display: none
+ line-height: 19px
+ .oe_input_icon
+ margin-top: 5px
.oe_form_field
+ min-width: 0
+ max-width: none
input, textarea
height: $row-height
- input, textarea
@include radius(0)
border: 1px solid #aaf
margin: 0
+ input, textarea, select
+ min-width: 0
&.oe_form_field_float,&.oe_form_view_integer
input
text-align: right
width: 100% !important
&.oe_form_field_datetime,&.oe_form_field_date
- > span
- width: 100% !important
input.oe_datepicker_master
width: 100% !important
- .oe_form_field_float,.oe_form_view_integer,&.oe_form_field_datetime,&.oe_form_field_date
- min-width: 0 !important
- max-width: none !important
.oe_list_group_name
white-space: nowrap
// }}}
@@ -2134,6 +2190,8 @@ $sheet-padding: 16px
td.oe_number
text-align: right !important
max-width: 100px
+ td.oe_list_field_date, th.oe_list_header_date
+ min-width: 6em
> thead
border-bottom: 2px solid #cacaca
background: #eee
@@ -2183,6 +2241,8 @@ $sheet-padding: 16px
width: 17px
&:after
border-width: 0
+ > td.oe_list_field_boolean input
+ @include opacity()
> tr:nth-child(odd)
background-color: #f0f0fa
@include vertical-gradient(#f0f0fa, #eeeef6)
@@ -2297,67 +2357,6 @@ $sheet-padding: 16px
float: right
color: #333
// }}}
-
-.openerp
- .oe_fileupload
- display: inline-block
- clear: both
- width: 100%
- .oe_add
- float: left
- position: relative
- width: 100%
- left: +2px
- top: +7px
- button
- display: inline
- height: 24px
- font-size: 12px
- line-height: 12px
- vertical-align: middle
- button.oe_attach
- width: 24px
- overflow: hidden
- width: 24px
- overflow: hidden
- background: transparent
- color: #7C7BAD
- box-shadow: none
- border: none
- text-shadow: none
- .oe_e
- position: relative
- top: -1px
- left: -9px
- input.oe_form_binary_file
- display: inline-block
- margin-left: -5px
- height: 28px
- width: 52px
- margin-top: -26px
- .oe_attach_label
- color: #7C7BAD
- margin-left: -3px
- .oe_attachments
- margin-bottom: 4px
- margin-right: 0px
- font-size: 12px
- border-radius: 2px
- border: solid 1px rgba(124,123,173,0.14)
- .oe_attachment
- padding: 2px
- padding-left: 4px
- padding-right: 4px
- .oe_e
- font-size: 23px
- margin-top: -5px
- .oe_e:hover
- text-decoration: none
- .oe_attachment:nth-child(odd)
- background: white
- .oe_attachment:nth-child(even)
- background: #F4F5FA
-
// Kitten Mode {{{
.kitten-mode-activated
background-image: url(http://placekitten.com/g/1365/769)
@@ -2367,11 +2366,13 @@ $sheet-padding: 16px
opacity: 0.70
// }}}
+// jQueryUI top level {{{
// The jQuery-ui overlay and Autocomplete are outside the .openerp div, please don't add indentation !!!
div.ui-widget-overlay
background: black
@include opacity(0.3)
-
+// TODO: I think only the overlay is problematic, the other top level widgets should use $.fn.openerpClass()
+// eg: $el.autocomplete().openerpClass();
.ui-widget
font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif
color: #4c4c4c
@@ -2398,6 +2399,7 @@ div.ui-widget-overlay
.ui-corner-all
@include radius(3px)
+// }}}
.resolution
width: 350px
@@ -2443,11 +2445,11 @@ div.res
font-size: 10px
padding-right: 5px
-
@media print
.openerp
- .oe_header_row, ul.oe_header, div.oe_mail_thread_action, .oe_mail_recthread_actions, .oe_button_box, .oe_form button, button.oe_invite, .oe_form header, .openerp .oe_notebook > li.ui-state-default
- display: none
+ .oe_header_row, ul.oe_header, div.oe_mail_thread_action, .oe_mail_recthread_actions, .oe_button_box, .oe_form button, button.oe_invite, .oe_form header, .openerp .oe_notebook > li.ui-state-default, .oe_topbar, .oe_leftbar, .oe_loading
+ // We use !important here because jQuery adds @style = display: block on elements when using $.fn.show()
+ display: none !important
.oe_list_content
button, input[type=checkbox]
visibility: hidden
@@ -2473,5 +2475,7 @@ div.res
background: none
.openerp div.oe_mail_wall
overflow: hidden !important
+// }}}
+
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 05ce709e80a..631a7f8c6f5 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -19,12 +19,14 @@
/**
* OpenERP instance constructor
*
- * @param {Array} modules list of modules to initialize
+ * @param {Array|String} modules list of modules to initialize
*/
init: function(modules) {
- // By default only web will be loaded, the rest will be by loaded
- // by openerp.web.Session on the first session_authenticate
- modules = _.union(['web'], modules || []);
+ if (modules === "fuck your shit, don't load anything you cunt") {
+ modules = [];
+ } else {
+ modules = _.union(['web'], modules || []);
+ }
var new_instance = {
// links to the global openerp
_openerp: openerp,
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 7fac7bdad6d..0db21f2397f 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -48,7 +48,7 @@ instance.web.Notification = instance.web.Widget.extend({
*/
instance.web.dialog = function(element) {
var result = element.dialog.apply(element, _.rest(_.toArray(arguments)));
- result.dialog("widget").addClass("openerp");
+ result.dialog("widget").openerpClass();
return result;
};
@@ -190,7 +190,14 @@ instance.web.Dialog = instance.web.Widget.extend({
});
instance.web.CrashManager = instance.web.Class.extend({
+ init: function() {
+ this.active = true;
+ },
+
rpc_error: function(error) {
+ if (!this.active) {
+ return;
+ }
if (error.data.fault_code) {
var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
if (split.length > 1) {
@@ -205,6 +212,9 @@ instance.web.CrashManager = instance.web.Class.extend({
}
},
show_warning: function(error) {
+ if (!this.active) {
+ return;
+ }
instance.web.dialog($('