diff options
| author | Amit Patel (OpenERP) <apa@tinyerp.com> | 2012-07-27 10:58:09 +0530 |
|---|---|---|
| committer | Amit Patel (OpenERP) <apa@tinyerp.com> | 2012-07-27 10:58:09 +0530 |
| commit | 5aee509a3b7585e32e1273e1925d1d25762e89fe (patch) | |
| tree | d6b494809e2d1eab9e8a9553fe4984eba9b79cb3 | |
| parent | ff71d6d1ade22e9e1299f81a6a05043466de26ba (diff) | |
| parent | 9128e37231194592b6468ffa7922bbb39b5d7a33 (diff) | |
[MERGE]
bzr revid: apa@tinyerp.com-20120727052809-oezzaxn0qikgtkli
26 files changed, 2857 insertions, 506 deletions
diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 9e8e258dedc..4051e607e21 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -20,6 +20,7 @@ "static/lib/jquery.form/jquery.form.js", "static/lib/jquery.validate/jquery.validate.js", "static/lib/jquery.ba-bbq/jquery.ba-bbq.js", + "static/lib/spinjs/spin.js", "static/lib/jquery.blockUI/jquery.blockUI.js", "static/lib/jquery.ui/js/jquery-ui-1.8.17.custom.min.js", "static/lib/jquery.ui.timepicker/js/jquery-ui-timepicker-addon.js", diff --git a/addons/web/common/http.py b/addons/web/common/http.py index bb87d719bad..a70ef53a91c 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -425,8 +425,8 @@ class DisableCacheMiddleware(object): def start_wrapped(status, headers): referer = environ.get('HTTP_REFERER', '') parsed = urlparse.urlparse(referer) - debug = not urlparse.parse_qs(parsed.query).has_key('debug') - filtered_headers = [(k,v) for k,v in headers if not (k=='Last-Modified' or (debug and k=='Cache-Control'))] + debug = parsed.query.count('debug') >= 1 + filtered_headers = [(k,v) for k,v in headers if not (k=='Last-Modified' or (debug and (k=='Cache-Control' or k=='Expires')))] if debug: filtered_headers.append(('Cache-Control', 'no-cache')) start_response(status, filtered_headers) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 7f9710f8aa6..da034aa88b6 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -194,9 +194,12 @@ class WebClient(openerpweb.Controller): if mods is not None: path += '?mods=' + mods return [path] - # old code to force cache reloading - #return ['%s?debug=%s' % (wp, os.path.getmtime(fp)) for fp, wp in self.manifest_glob(req, mods, extension)] - return [el[1] for el in self.manifest_glob(req, mods, extension)] + no_sugar = req.httprequest.environ["QUERY_STRING"].count("no_sugar") >= 1 + no_sugar = no_sugar or req.httprequest.environ.get('HTTP_REFERER', '').count("no_sugar") >= 1 + if not no_sugar: + return ['%s?debug=%s' % (wp, os.path.getmtime(fp)) for fp, wp in self.manifest_glob(req, mods, extension)] + else: + return [el[1] for el in self.manifest_glob(req, mods, extension)] @openerpweb.jsonrequest def csslist(self, req, mods=None): diff --git a/addons/web/i18n/fr_CA.po b/addons/web/i18n/fr_CA.po new file mode 100644 index 00000000000..327e221c0e9 --- /dev/null +++ b/addons/web/i18n/fr_CA.po @@ -0,0 +1,1563 @@ +# French (Canada) translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2012-07-02 09:06+0200\n" +"PO-Revision-Date: 2012-07-25 03:30+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: French (Canada) <fr_CA@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-07-26 04:50+0000\n" +"X-Generator: Launchpad (build 15679)\n" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:176 +#: addons/web/static/src/js/chrome.js:202 +#: addons/web/static/src/js/chrome.js:380 +#: addons/web/static/src/js/view_form.js:457 +#: addons/web/static/src/js/view_form.js:1292 +#: addons/web/static/src/xml/base.xml:1701 +msgid "Ok" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:184 +msgid "Send OpenERP Enterprise Report" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:198 +msgid "Dont send" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1119 +msgid "Client Error" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:260 +#, python-format +msgid "Loading (%d)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:292 +msgid "Invalid database name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:455 +msgid "Backed" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:456 +msgid "Database backed up successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:499 +msgid "Restored" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:499 +msgid "Database restored successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:783 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1735 +msgid "Change Password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:759 +#: addons/web/static/src/xml/base.xml:356 +msgid "Preferences" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:763 +msgid "Change password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:762 +#: addons/web/static/src/js/search.js:241 +#: addons/web/static/src/js/search.js:300 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1287 +#: addons/web/static/src/xml/base.xml:743 +#: addons/web/static/src/xml/base.xml:1502 +#: addons/web/static/src/xml/base.xml:1512 +#: addons/web/static/src/xml/base.xml:1521 +msgid "Cancel" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:764 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:967 addons/web/static/src/xml/base.xml:742 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1520 +msgid "Save" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:680 +#: addons/web/static/src/xml/base.xml:359 +msgid "About" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1052 +msgid "OpenERP - Unsupported/Community Version" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:619 +msgid "less than a minute ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:620 +msgid "about a minute ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:621 +#, python-format +msgid "%d minutes ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:622 +msgid "about an hour ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:623 +#, python-format +msgid "%d hours ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:624 +msgid "a day ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:625 +#, python-format +msgid "%d days ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:626 +msgid "about a month ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:627 +#, python-format +msgid "%d months ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:628 +msgid "about a year ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/coresetup.js:629 +#, python-format +msgid "%d years ago" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:6 +msgid "Export Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:19 +#: addons/web/static/src/js/data_import.js:70 +#: addons/web/static/src/js/view_editor.js:49 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:734 +#: addons/web/static/src/js/view_form.js:3298 +#: addons/web/static/src/js/views.js:968 +msgid "Close" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:20 +msgid "Export To File" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:126 +msgid "Please enter save field list name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:362 +msgid "Please select fields to save export list..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:375 +msgid "Please select fields to export..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:34 +msgid "Import Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:71 +msgid "Import File" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:106 +msgid "External ID" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:346 +msgid "" +"Destination fields should only be selected once, some fields are selected " +"more than once:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:383 +msgid "*Required Fields are not selected :" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:139 +#, python-format +msgid "(%d records)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:325 +#: addons/web/static/src/js/view_page.js:268 +msgid "Download" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:330 +#, python-format +msgid "Download \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:437 +msgid "Invalid Search" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:437 +msgid "triggered from search view" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:528 +#, python-format +msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:948 +#, python-format +msgid "Filter on: %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:999 +msgid "Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1108 +#, python-format +msgid "Group by: %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1132 +msgid "GroupBy" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1267 +#, python-format +msgid "Search %(field)s for: %(value)s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:869 +msgid "not a valid integer" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:883 +msgid "not a valid number" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:962 +#: addons/web/static/src/xml/base.xml:973 +msgid "Yes" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:963 +msgid "No" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1416 +#, python-format +msgid "Search %(field)s at: %(value)s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1286 +msgid "Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1762 +msgid "Advanced" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1853 +#, python-format +msgid "%(field)s %(operator)s \"%(value)s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1341 +msgid "contains" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1342 +msgid "doesn't contain" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1343 +#: addons/web/static/src/js/search.js:1359 +#: addons/web/static/src/js/search.js:1380 +#: addons/web/static/src/js/search.js:1401 +#: addons/web/static/src/js/search.js:1424 +msgid "is equal to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1381 +#: addons/web/static/src/js/search.js:1402 +#: addons/web/static/src/js/search.js:1425 +msgid "is not equal to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1361 +#: addons/web/static/src/js/search.js:1382 +#: addons/web/static/src/js/search.js:1403 +#: addons/web/static/src/js/search.js:1426 +msgid "greater than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1362 +#: addons/web/static/src/js/search.js:1383 +#: addons/web/static/src/js/search.js:1404 +#: addons/web/static/src/js/search.js:1427 +msgid "less than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1363 +#: addons/web/static/src/js/search.js:1384 +#: addons/web/static/src/js/search.js:1405 +#: addons/web/static/src/js/search.js:1428 +msgid "greater or equal than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1364 +#: addons/web/static/src/js/search.js:1385 +#: addons/web/static/src/js/search.js:1406 +#: addons/web/static/src/js/search.js:1429 +msgid "less or equal than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1419 +#: addons/web/static/src/js/search.js:1444 +msgid "is" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1445 +msgid "is not" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1459 +msgid "is true" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1460 +msgid "is false" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:20 +#, python-format +msgid "Manage Views (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:46 +#: addons/web/static/src/js/view_list.js:17 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:761 +msgid "Create" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:47 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:760 +msgid "Edit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:48 +#: addons/web/static/src/xml/base.xml:1653 +msgid "Remove" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:71 +#, python-format +msgid "Create a view (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:168 +msgid "Do you really want to remove this view?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:364 +#, python-format +msgid "View Editor %d - %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:367 +msgid "Inherited View" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:371 +msgid "Do you really wants to create an inherited view here?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:381 +msgid "Preview" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:501 +msgid "Do you really want to remove this node?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 +msgid "Properties" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 +msgid "Update" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:16 +#: addons/web/static/src/js/view_form.js:210 +msgid "Form" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:763 +#: addons/web/static/src/xml/base.xml:1714 +msgid "Delete" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:762 +msgid "Duplicate" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:133 +#: addons/web/static/src/js/view_form.js:728 +msgid "Set Default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:59 +msgid "Do you really want to delete this record?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:508 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:735 +msgid "Save default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:867 +#, python-format +msgid "Unknown operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:875 +#, python-format +msgid "Unknown field %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:913 +#, python-format +msgid "Unsupported operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1284 +msgid "Confirm" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2193 +msgid "<em> Search More...</em>" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2211 +#, python-format +msgid "<em> Create \"<strong>%s</strong>\"</em>" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2217 +msgid "<em> Create and Edit...</em>" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2250 +#: addons/web/static/src/js/views.js:680 +msgid "Search: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2250 +#: addons/web/static/src/js/view_form.js:2738 +msgid "Create: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2040 +#: addons/web/static/src/js/view_form.js:2766 +#: addons/web/static/src/js/view_form.js:2991 +msgid "Open: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2911 +#: addons/web/static/src/xml/base.xml:755 +#: addons/web/static/src/xml/base.xml:777 +#: addons/web/static/src/xml/base.xml:1652 +msgid "Add" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2971 +msgid "Add: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:4230 +msgid "Save As..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:4230 +msgid "The field is empty, there's nothing to save !" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:8 +msgid "List" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:277 +msgid "Unlimited" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:819 +#: addons/web/static/src/xml/base.xml:1742 +msgid "Import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:822 +#: addons/web/static/src/xml/base.xml:1612 +msgid "Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:374 +msgid "Group" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:549 +msgid "Do you really want to remove these records?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:925 +msgid "Warning" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:716 +msgid "You must select at least one record." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1243 +msgid "Undefined" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1342 +#, python-format +msgid "%(page)d/%(page_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_tree.js:11 +msgid "Tree" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:570 addons/web/static/src/xml/base.xml:480 +msgid "Fields View Get" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:578 +#, python-format +msgid "View Log (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:605 +#, python-format +msgid "Model %s fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:615 addons/web/static/src/xml/base.xml:482 +msgid "Manage Views" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:616 +msgid "Could not find current view declaration" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:716 +msgid "Print" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:717 +msgid "Attachment" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:718 addons/web/static/src/xml/base.xml:276 +msgid "More" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:810 +msgid "Translate" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:812 +msgid "Technical translation" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:924 +msgid "You must choose at least one record." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:875 +msgid "Uploading..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:885 +msgid "Do you really want to delete this attachment ?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:962 +msgid "Translations" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:52 +msgid "Loading..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "" +"Your version of OpenERP is unsupported. Support & maintenance services are " +"available here:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "OpenERP Entreprise" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:256 +msgid "OpenERP Enterprise Contract." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:257 +msgid "Your report will be sent to the OpenERP Enterprise team." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:259 +msgid "Summary:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:263 +msgid "Description:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:267 +msgid "What you did:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:297 +msgid "Invalid username or password" +msgstr "" + +#. 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 "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:306 +msgid "Username" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 +msgid "Password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:310 +msgid "Log in" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:314 +msgid "Manage Databases" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +msgid "Powered by" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1819 +msgid "OpenERP" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 +msgid "Drop" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 +msgid "Backup" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 +msgid "Restore" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:332 +msgid "Back to Login" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:61 +msgid "CREATE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211 +msgid "Master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:72 addons/web/static/src/xml/base.xml:191 +msgid "New database name:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:77 +msgid "Load Demonstration data:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:81 +msgid "Default language:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:91 +msgid "Admin password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:95 +msgid "Confirm password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:109 +msgid "DROP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 +msgid "Master Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:143 +msgid "BACKUP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:175 +msgid "RESTORE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:182 +msgid "File:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:204 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:216 +msgid "New master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:221 +msgid "Confirm new master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:325 +msgid "About OpenERP" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:327 +msgid "Log out" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:333 +msgid "Activate the developer mode" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1820 +msgid "Version" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1821 +msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1822 +msgid "OpenERP is a trademark of the" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1823 +msgid "OpenERP SA Company" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1825 +msgid "Licenced under the terms of" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1826 +msgid "GNU Affero General Public License" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1828 +msgid "For more information visit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1829 +msgid "OpenERP.com" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1720 +msgid "Old Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1725 +msgid "New Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1730 +msgid "Confirm Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:390 +msgid "Open" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:390 +msgid "ERP" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:477 +msgid "Debug View#" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:478 +msgid "View Log (perm_read)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:450 +msgid "Toggle Form Layout Outline" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:479 +msgid "View Fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1300 +msgid "Manage Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:483 +msgid "View" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:484 +msgid "Edit SearchView" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:485 +msgid "Edit Action" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:486 +msgid "Edit Workflow" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:491 +msgid "ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:494 +msgid "XML ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:497 +msgid "Creation User:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:500 +msgid "Creation Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:503 +msgid "Latest Modification by:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:506 +msgid "Latest Modification Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:518 +msgid "Delete this attachment" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:523 +msgid "/web/binary/upload_attachment" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:527 +msgid "Add..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:622 +#: addons/web/static/src/xml/base.xml:687 +msgid "or" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:687 +msgid "Discard" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:806 +msgid "Default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:823 +msgid "Condition:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:842 +msgid "Only you" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:849 +msgid "All users" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:856 +msgid "Unhandled widget" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:936 +msgid "(nolabel)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:941 +msgid "Field:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:945 +msgid "Object:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:949 +msgid "Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:953 +msgid "Widget:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:957 +msgid "Size:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:961 +msgid "Context:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:965 +msgid "Domain:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:910 +#: addons/web/static/src/xml/base.xml:969 +msgid "Modifiers:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:973 +msgid "Change default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:977 +msgid "On change:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:981 +msgid "Relation:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:985 +msgid "Selection:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1040 +msgid "Open this resource" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1063 +msgid "Select date" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:948 +msgid "Open Resource" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1162 +#: addons/web/static/src/xml/base.xml:1205 +msgid "Set Image" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1620 +#: addons/web/static/src/xml/base.xml:1170 +#: addons/web/static/src/xml/base.xml:1220 +#: addons/web/static/src/xml/base.xml:1222 +#: addons/web/static/src/xml/base.xml:1279 +msgid "Clear" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1179 +#: addons/web/static/src/xml/base.xml:1230 +msgid "Uploading ..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1066 +msgid "width: 83px;" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1501 +msgid "Select" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1214 +#: addons/web/static/src/xml/base.xml:1216 +msgid "Save As" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1245 +msgid "Button" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1248 +msgid "(no string)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1255 +msgid "Special:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1260 +msgid "Button Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1264 +msgid "Method:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1268 +msgid "Action ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:542 +msgid "Field" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1205 +msgid "Advanced Search..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1287 +msgid "-- Filters --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1296 +msgid "-- Actions --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1297 +msgid "Add Advanced Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1298 +msgid "Save Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1305 +msgid "Filter Name:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1307 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1376 +msgid "Custom Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1379 +msgid "Save current filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1381 +msgid "Filter name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1383 +msgid "Share with all users" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:298 +#: addons/web/static/src/xml/base.xml:1299 +msgid "Add to Dashboard" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1394 +msgid "Title of new Dashboard item" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1395 +msgid "save" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1399 +msgid "Select Dashboard to add this filter to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1406 +msgid "Advanced Search" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1411 +msgid "Add a condition" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1412 +msgid "Apply" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1509 +msgid "Save & New" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1510 +msgid "Save & Close" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1617 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1624 +msgid "Export Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1626 +msgid "Import Compatible Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1627 +msgid "Export all Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1630 +msgid "Export Formats" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1636 +msgid "Available fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1638 +msgid "Fields to export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1640 +msgid "Save fields list" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1654 +msgid "Remove All" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1666 +msgid "Name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1699 +msgid "Save as:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1706 +msgid "Saved exports:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1748 +msgid "1. Import a .CSV file" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1749 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1753 +msgid "CSV File:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1756 +msgid "2. Check your file format" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1759 +msgid "Import Options" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1763 +msgid "Does your file have titles?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1769 +msgid "Separator:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1771 +msgid "Delimiter:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1775 +msgid "Encoding:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1778 +msgid "UTF-8" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1779 +msgid "Latin 1" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1782 +msgid "Lines to skip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1782 +msgid "" +"For use if CSV files have titles on multiple lines, skips more than a single " +"line during import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1713 +msgid "--- Don't Import ---" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1809 +msgid "The import failed due to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1811 +msgid "Here is a preview of the file we could not import:" +msgstr "" diff --git a/addons/web/static/lib/spinjs/spin.js b/addons/web/static/lib/spinjs/spin.js new file mode 100644 index 00000000000..d8e21786a1f --- /dev/null +++ b/addons/web/static/lib/spinjs/spin.js @@ -0,0 +1,306 @@ +//fgnass.github.com/spin.js#v1.2.5 +(function(window, document, undefined) { + +/** + * Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de] + * Licensed under the MIT license + */ + + var prefixes = ['webkit', 'Moz', 'ms', 'O']; /* Vendor prefixes */ + var animations = {}; /* Animation rules keyed by their name */ + var useCssAnimations; + + /** + * Utility function to create elements. If no tag name is given, + * a DIV is created. Optionally properties can be passed. + */ + function createEl(tag, prop) { + var el = document.createElement(tag || 'div'); + var n; + + for(n in prop) { + el[n] = prop[n]; + } + return el; + } + + /** + * Appends children and returns the parent. + */ + function ins(parent /* child1, child2, ...*/) { + for (var i=1, n=arguments.length; i<n; i++) { + parent.appendChild(arguments[i]); + } + return parent; + } + + /** + * Insert a new stylesheet to hold the @keyframe or VML rules. + */ + var sheet = function() { + var el = createEl('style'); + ins(document.getElementsByTagName('head')[0], el); + return el.sheet || el.styleSheet; + }(); + + /** + * Creates an opacity keyframe animation rule and returns its name. + * Since most mobile Webkits have timing issues with animation-delay, + * we create separate rules for each line/segment. + */ + function addAnimation(alpha, trail, i, lines) { + var name = ['opacity', trail, ~~(alpha*100), i, lines].join('-'); + var start = 0.01 + i/lines*100; + var z = Math.max(1-(1-alpha)/trail*(100-start) , alpha); + var prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase(); + var pre = prefix && '-'+prefix+'-' || ''; + + if (!animations[name]) { + sheet.insertRule( + '@' + pre + 'keyframes ' + name + '{' + + '0%{opacity:'+z+'}' + + start + '%{opacity:'+ alpha + '}' + + (start+0.01) + '%{opacity:1}' + + (start+trail)%100 + '%{opacity:'+ alpha + '}' + + '100%{opacity:'+ z + '}' + + '}', 0); + animations[name] = 1; + } + return name; + } + + /** + * Tries various vendor prefixes and returns the first supported property. + **/ + function vendor(el, prop) { + var s = el.style; + var pp; + var i; + + if(s[prop] !== undefined) return prop; + prop = prop.charAt(0).toUpperCase() + prop.slice(1); + for(i=0; i<prefixes.length; i++) { + pp = prefixes[i]+prop; + if(s[pp] !== undefined) return pp; + } + } + + /** + * Sets multiple style properties at once. + */ + function css(el, prop) { + for (var n in prop) { + el.style[vendor(el, n)||n] = prop[n]; + } + return el; + } + + /** + * Fills in default values. + */ + function merge(obj) { + for (var i=1; i < arguments.length; i++) { + var def = arguments[i]; + for (var n in def) { + if (obj[n] === undefined) obj[n] = def[n]; + } + } + return obj; + } + + /** + * Returns the absolute page-offset of the given element. + */ + function pos(el) { + var o = {x:el.offsetLeft, y:el.offsetTop}; + while((el = el.offsetParent)) { + o.x+=el.offsetLeft; + o.y+=el.offsetTop; + } + return o; + } + + var defaults = { + lines: 12, // The number of lines to draw + length: 7, // The length of each line + width: 5, // The line thickness + radius: 10, // The radius of the inner circle + rotate: 0, // rotation offset + color: '#000', // #rgb or #rrggbb + speed: 1, // Rounds per second + trail: 100, // Afterglow percentage + opacity: 1/4, // Opacity of the lines + fps: 20, // Frames per second when using setTimeout() + zIndex: 2e9, // Use a high z-index by default + className: 'spinner', // CSS class to assign to the element + top: 'auto', // center vertically + left: 'auto' // center horizontally + }; + + /** The constructor */ + var Spinner = function Spinner(o) { + if (!this.spin) return new Spinner(o); + this.opts = merge(o || {}, Spinner.defaults, defaults); + }; + + Spinner.defaults = {}; + merge(Spinner.prototype, { + spin: function(target) { + this.stop(); + var self = this; + var o = self.opts; + var el = self.el = css(createEl(0, {className: o.className}), {position: 'relative', zIndex: o.zIndex}); + var mid = o.radius+o.length+o.width; + var ep; // element position + var tp; // target position + + if (target) { + target.insertBefore(el, target.firstChild||null); + tp = pos(target); + ep = pos(el); + css(el, { + left: (o.left == 'auto' ? tp.x-ep.x + (target.offsetWidth >> 1) : o.left+mid) + 'px', + top: (o.top == 'auto' ? tp.y-ep.y + (target.offsetHeight >> 1) : o.top+mid) + 'px' + }); + } + + el.setAttribute('aria-role', 'progressbar'); + self.lines(el, self.opts); + + if (!useCssAnimations) { + // No CSS animation support, use setTimeout() instead + var i = 0; + var fps = o.fps; + var f = fps/o.speed; + var ostep = (1-o.opacity)/(f*o.trail / 100); + var astep = f/o.lines; + + !function anim() { + i++; + for (var s=o.lines; s; s--) { + var alpha = Math.max(1-(i+s*astep)%f * ostep, o.opacity); + self.opacity(el, o.lines-s, alpha, o); + } + self.timeout = self.el && setTimeout(anim, ~~(1000/fps)); + }(); + } + return self; + }, + stop: function() { + var el = this.el; + if (el) { + clearTimeout(this.timeout); + if (el.parentNode) el.parentNode.removeChild(el); + this.el = undefined; + } + return this; + }, + lines: function(el, o) { + var i = 0; + var seg; + + function fill(color, shadow) { + return css(createEl(), { + position: 'absolute', + width: (o.length+o.width) + 'px', + height: o.width + 'px', + background: color, + boxShadow: shadow, + transformOrigin: 'left', + transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)', + borderRadius: (o.width>>1) + 'px' + }); + } + for (; i < o.lines; i++) { + seg = css(createEl(), { + position: 'absolute', + top: 1+~(o.width/2) + 'px', + transform: o.hwaccel ? 'translate3d(0,0,0)' : '', + opacity: o.opacity, + animation: useCssAnimations && addAnimation(o.opacity, o.trail, i, o.lines) + ' ' + 1/o.speed + 's linear infinite' + }); + if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'})); + ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)'))); + } + return el; + }, + opacity: function(el, i, val) { + if (i < el.childNodes.length) el.childNodes[i].style.opacity = val; + } + }); + + ///////////////////////////////////////////////////////////////////////// + // VML rendering for IE + ///////////////////////////////////////////////////////////////////////// + + /** + * Check and init VML support + */ + !function() { + + function vml(tag, attr) { + return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr); + } + + var s = css(createEl('group'), {behavior: 'url(#default#VML)'}); + + if (!vendor(s, 'transform') && s.adj) { + + // VML support detected. Insert CSS rule ... + sheet.addRule('.spin-vml', 'behavior:url(#default#VML)'); + + Spinner.prototype.lines = function(el, o) { + var r = o.length+o.width; + var s = 2*r; + + function grp() { + return css(vml('group', {coordsize: s +' '+s, coordorigin: -r +' '+-r}), {width: s, height: s}); + } + + var margin = -(o.width+o.length)*2+'px'; + var g = css(grp(), {position: 'absolute', top: margin, left: margin}); + + var i; + + function seg(i, dx, filter) { + ins(g, + ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}), + ins(css(vml('roundrect', {arcsize: 1}), { + width: r, + height: o.width, + left: o.radius, + top: -o.width>>1, + filter: filter + }), + vml('fill', {color: o.color, opacity: o.opacity}), + vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change + ) + ) + ); + } + + if (o.shadow) { + for (i = 1; i <= o.lines; i++) { + seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)'); + } + } + for (i = 1; i <= o.lines; i++) seg(i); + return ins(el, g); + }; + Spinner.prototype.opacity = function(el, i, val, o) { + var c = el.firstChild; + o = o.shadow && o.lines || 0; + if (c && i+o < c.childNodes.length) { + c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild; + if (c) c.opacity = val; + } + }; + } + else { + useCssAnimations = vendor(s, 'animation'); + } + }(); + + window.Spinner = Spinner; + +})(window, document);
\ No newline at end of file diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 2e26de30d5f..1e59897cd86 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,4 @@ -@charset "UTF-8"; +@charset "utf-8"; @font-face { font-family: "mnmliconsRegular"; src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot"); @@ -20,6 +20,50 @@ font-style: normal; } +@-moz-keyframes bounce { + 0% { + -moz-transform: scale(0); + opacity: 0; + } + + 50% { + -moz-transform: scale(1.3); + opacity: 0.4; + } + + 75% { + -moz-transform: scale(0.9); + opacity: 0.7; + } + + 100% { + -moz-transform: scale(1); + opacity: 1; + } +} + +@-webkit-keyframes bounce { + 0% { + -webkit-transform: scale(0); + opacity: 0; + } + + 50% { + -webkit-transform: scale(1.3); + opacity: 0.4; + } + + 75% { + -webkit-transform: scale(0.9); + opacity: 0.7; + } + + 100% { + -webkit-transform: scale(1); + opacity: 1; + } +} + .openerp.openerp_webclient_container { height: 100%; position: relative; @@ -186,6 +230,11 @@ .openerp .ui-menu .ui-menu-item a.ui-state-active { background: #f0f0fa; } +.openerp div.ui-widget-overlay { + background: black; + filter: alpha(opacity=30); + opacity: 0.3; +} .openerp.ui-dialog { display: none; padding: 6px; @@ -267,6 +316,45 @@ color: black; text-decoration: none; } +.openerp.ui-dialog .oe_about { + background-color: white; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=); + -moz-border-radius: 0 0 2px 2px; + -webkit-border-radius: 0 0 2px 2px; + border-radius: 0 0 2px 2px; +} +.openerp.ui-dialog .oe_about a { + color: #8a89ba; +} +.openerp.ui-dialog .oe_about a:hover { + text-decoration: underline; +} +.openerp.ui-dialog .oe_about .oe_logo { + margin-left: -6px; +} +.openerp.ui-dialog .oe_about .oe_bottom { + position: absolute; + top: 50%; + left: 0; + right: 0; + bottom: 0; + text-shadow: 0 1px 1px #999999; + background-color: #b41616; + background-image: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606)); + background-image: -webkit-linear-gradient(top, #b41616, #600606); + background-image: -moz-linear-gradient(top, #b41616, #600606); + background-image: -ms-linear-gradient(top, #b41616, #600606); + background-image: -o-linear-gradient(top, #b41616, #600606); + background-image: linear-gradient(to bottom, #b41616, #600606); + color: #eeeeee; + padding: 0 16px; + -moz-border-radius: 0 0 2px 2px; + -webkit-border-radius: 0 0 2px 2px; + border-radius: 0 0 2px 2px; +} +.openerp.ui-dialog .oe_about .oe_bottom a { + color: #eeeeee; +} .openerp.ui-dialog.oe_act_window .ui-dialog-content { padding: 0px; } @@ -458,6 +546,10 @@ .openerp .oe_webclient .oe_star_on { color: gold; } +.openerp .oe_bounce { + -moz-animation: bounce 0.4s linear; + -webkit-animation: bounce 0.4s linear; +} .openerp .oe_tag { border-radius: 2px; -webkit-box-sizing: border-box; @@ -584,7 +676,7 @@ z-index: 1; border: 1px solid #afafb6; background: white; - padding: 6px 0; + padding: 4px 0; min-width: 140px; text-align: left; -moz-border-radius: 3px; @@ -599,6 +691,7 @@ float: none; display: block; position: relative; + padding: 2px 8px; } .openerp .oe_dropdown_menu > li:hover { background-color: #f0f0fa; @@ -615,7 +708,6 @@ .openerp .oe_dropdown_menu > li > a { white-space: nowrap; display: block; - padding: 4px 15px; color: #4c4c4c; text-decoration: none; } @@ -711,7 +803,7 @@ z-index: 1050; } .openerp .oe_login { - background: url("/web/static/src/img/pattern.png") repeat; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=); text-align: center; font-size: 14px; height: 100%; @@ -945,11 +1037,12 @@ } .openerp .oe_topbar .oe_dropdown_menu li { float: none; + padding: 3px 12px; } .openerp .oe_topbar .oe_dropdown_menu li a { color: #eeeeee; } -.openerp .oe_topbar .oe_dropdown_menu li a:hover { +.openerp .oe_topbar .oe_dropdown_menu li:hover { background-color: #292929; background-image: -webkit-gradient(linear, left top, left bottom, from(#292929), to(#191919)); background-image: -webkit-linear-gradient(top, #292929, #191919); @@ -1229,6 +1322,9 @@ .openerp .oe_view_manager .oe_view_manager_pager { line-height: 26px; } +.openerp .oe_view_manager .oe_view_manager_pager .oe_list_pager_single_page .oe_pager_group { + display: none; +} .openerp .oe_view_manager .oe_pager_value { float: left; margin-right: 8px; @@ -1408,20 +1504,31 @@ filter: alpha(opacity=50); opacity: 0.5; } -.openerp .oe_searchview .oe_searchview_facets { - min-height: 22px; +.openerp .oe_searchview .oe_searchview_search { + font-size: 1px; + letter-spacing: -1px; + color: transparent; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; + position: absolute; + left: 3px; + top: 1px; + padding: 0; + border: none; + background: transparent; } -.openerp .oe_searchview .oe_searchview_facets:before { - color: #cccccc; - font-family: "mnmliconsRegular"; +.openerp .oe_searchview .oe_searchview_search:before { + font: 21px "mnmliconsRegular"; content: "r"; - font-size: 130%; - display: inline; - position: relative; - left: 6px; - top: 2px; color: #a3a3a3; - padding-right: 4px; +} +.openerp .oe_searchview .oe_searchview_facets { + min-height: 22px; + margin-left: 15px; } .openerp .oe_searchview .oe_searchview_facets * { vertical-align: top; @@ -1437,7 +1544,7 @@ outline: none; } .openerp .oe_searchview .oe_searchview_facets .oe_searchview_input { - padding: 0 3px; + padding: 0 0 0 6px; } .openerp .oe_searchview .oe_searchview_facets .oe_searchview_facet { position: relative; @@ -1600,14 +1707,14 @@ .openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section li:hover { background-color: #f0f0fa; } -.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section form { +.openerp .oe_searchview .oe_searchview_drawer form { margin-left: 12px; } -.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section form p { +.openerp .oe_searchview .oe_searchview_drawer form p { margin: 4px 0; line-height: 18px; } -.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section form button { +.openerp .oe_searchview .oe_searchview_drawer form button { margin: 0 0 8px 0; } .openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom { @@ -2180,7 +2287,7 @@ height: auto; line-height: 16px; } -.openerp .oe_form_field_one2many .oe_list_buttons.oe_editing .oe_list_save { +.openerp .oe_form_field_one2many .oe_list_buttons.oe_editing .oe_list_save, .openerp .oe_form_field_many2many .oe_list_buttons.oe_editing .oe_list_save { visibility: hidden; } .openerp .oe_form .oe_form_field_many2many > .oe_list .oe_list_pager_single_page { @@ -2266,9 +2373,6 @@ padding: 3px 6px; white-space: pre-line; } -.openerp .oe_list_content > tbody > tr > td.oe_list_field_cell progress { - width: 100%; -} .openerp .oe_list_content > tbody > tr > td > button, .openerp .oe_list_content > tbody > tr > th > button { border: none; background: transparent; @@ -2315,6 +2419,58 @@ .openerp .oe_list_content .numeric input { text-align: right; } +.openerp .tree_header { + background-color: #f0f0f0; + border-bottom: 1px solid #cacaca; + color: #4c4c4c; + padding: 5px; + height: 25px; +} +.openerp .tree_header button { + float: right; + height: 27px; + margin-right: 5px; +} +.openerp .oe-treeview-table { + width: 100%; + background-color: white; + border-spacing: 0; +} +.openerp .oe-treeview-table th { + padding: 10px; + color: #4c4c4c; + font-weight: bold; + background-color: #f0f0f0; + border-bottom: 2px solid #cacaca; +} +.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td { + cursor: pointer; + border-right: 1px dotted #afafb6; + vertical-align: top; + text-align: left; + border-bottom: 1px solid #cfcccc; +} +.openerp .oe-treeview-table tr:hover { + background-color: #e0e0f8; +} +.openerp .oe-treeview-table .oe-number { + text-align: right !important; +} +.openerp .oe-treeview-table span { + font-size: 90%; + font-weight: normal; + white-space: nowrap; + display: block; +} +.openerp .oe-treeview-table .treeview-tr.oe-treeview-first { + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; +} +.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first { + background-image: url(/web/static/src/img/collapse.gif); +} +.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span { + margin-left: 16px; +} .openerp .oe_trad_field.touched { border: 1px solid green !important; } @@ -2380,59 +2536,6 @@ color: #333333; } -.openerp .tree_header { - background-color: #f0f0f0; - border-bottom: 1px solid #cacaca; - color: #4c4c4c; - padding: 5px; - height: 25px; -} -.openerp .tree_header button { - float: right; - height: 27px; - margin-right: 5px; -} -.openerp .oe-treeview-table { - width: 100%; - background-color: white; - border-spacing: 0; -} -.openerp .oe-treeview-table th { - padding: 10px; - color: #4c4c4c; - font-weight: bold; - background-color: #f0f0f0; - border-bottom: 2px solid #cacaca; -} -.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td { - cursor: pointer; - border-right: 1px dotted #afafb6; - vertical-align: top; - text-align: left; - border-bottom: 1px solid #cfcccc; -} -.openerp .oe-treeview-table tr:hover { - background-color: #e0e0f8; -} -.openerp .oe-treeview-table .oe-number { - text-align: right !important; -} -.openerp .oe-treeview-table span { - font-size: 90%; - font-weight: normal; - white-space: nowrap; - display: block; -} -.openerp .oe-treeview-table .treeview-tr.oe-treeview-first { - background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; -} -.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first { - background-image: url(/web/static/src/img/collapse.gif); -} -.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span { - margin-left: 16px; -} - .kitten-mode-activated { background-image: url(http://placekitten.com/g/1365/769); background-size: cover; @@ -2441,22 +2544,3 @@ .kitten-mode-activated > * { opacity: 0.7; } -.kitten-mode-activated .oe_footer a { - background-image: url(http://www.risacher.com/la-rache/zfiles/la-rache.png); - font-size: 1px; - letter-spacing: -1px; - color: transparent; - display: inline-block; - height: 15px; - width: 80px; - vertical-align: top; -} -.kitten-mode-activated .oe_footer a span { - display: none; -} - -div.ui-widget-overlay { - background: black; - filter: alpha(opacity=30); - opacity: 0.3; -} diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index c4314923867..3bb52497454 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -97,6 +97,35 @@ $sheet-max-width: 860px color: $color // }}} +// CSS animation bounces {{{ +@-moz-keyframes bounce + 0% + -moz-transform: scale(0) + opacity: 0 + 50% + -moz-transform: scale(1.3) + opacity: 0.4 + 75% + -moz-transform: scale(0.9) + opacity: 0.7 + 100% + -moz-transform: scale(1) + opacity: 1 + +@-webkit-keyframes bounce + 0% + -webkit-transform: scale(0) + opacity: 0 + 50% + -webkit-transform: scale(1.3) + opacity: 0.4 + 75% + -webkit-transform: scale(0.9) + opacity: 0.7 + 100% + -webkit-transform: scale(1) + opacity: 1 +// }}} .openerp.openerp_webclient_container height: 100% @@ -200,7 +229,9 @@ $sheet-max-width: 860px width: auto a.ui-state-active background: #f0f0fa - + div.ui-widget-overlay + background: black + @include opacity(0.3) // Modal box &.ui-dialog display: none @@ -255,6 +286,29 @@ $sheet-max-width: 860px &:hover color: black text-decoration: none + .oe_about + background-color: white + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=) + @include radius(0 0 2px 2px) + a + color: #8A89BA + &:hover + text-decoration: underline + .oe_logo + margin-left: -6px + .oe_bottom + position: absolute + top: 50% + left: 0 + right: 0 + bottom: 0 + text-shadow: 0 1px 1px #999999 + @include vertical-gradient(#b41616, #600606) + color: #eee + padding: 0 16px + @include radius(0 0 2px 2px) + a + color: #eee &.ui-dialog.oe_act_window .ui-dialog-content @@ -367,6 +421,9 @@ $sheet-max-width: 860px text-decoration: none .oe_star_on color: gold + .oe_bounce + -moz-animation: bounce .40s linear + -webkit-animation: bounce .40s linear // }}} // Tags (for many2many tags, among others) {{{ .oe_tag @@ -469,7 +526,7 @@ $sheet-max-width: 860px z-index: 1 border: 1px solid #afafb6 background: white - padding: 6px 0 + padding: 4px 0 min-width: 140px text-align: left @include radius(3px) @@ -482,10 +539,10 @@ $sheet-max-width: 860px float: none display: block position: relative + padding: 2px 8px > a white-space: nowrap display: block - padding: 4px 15px color: #4c4c4c text-decoration: none &:hover @@ -566,7 +623,7 @@ $sheet-max-width: 860px // }}} // Login {{{ .oe_login - background: url("/web/static/src/img/pattern.png") repeat + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=) text-align: center font-size: 14px height: 100% @@ -734,11 +791,12 @@ $sheet-max-width: 860px @include background-clip() li float: none + padding: 3px 12px a color: #eee - &:hover - @include vertical-gradient(#292929, #191919) - @include box-shadow(none) + &:hover + @include vertical-gradient(#292929, #191919) + @include box-shadow(none) // }}} // Webclient.leftbar {{{ @@ -958,6 +1016,8 @@ $sheet-max-width: 860px // ViewManager.pager {{{ .oe_view_manager_pager line-height: 26px + .oe_list_pager_single_page .oe_pager_group + display: none .oe_pager_value float: left margin-right: 8px @@ -1101,19 +1161,20 @@ $sheet-max-width: 860px border-right: 5px solid transparent @include opacity() + .oe_searchview_search + @include text-to-icon("r", #a3a3a3) + @include box-shadow(none) + @include radius(0) + position: absolute + left: 3px + top: 1px + padding: 0 + border: none + background: transparent + .oe_searchview_facets min-height: 22px - &:before - color: #ccc - font-family: "mnmliconsRegular" - content: "r" - font-size: 130% - display: inline - position: relative - left: 6px - top: 2px - color: #a3a3a3 - padding-right: 4px + margin-left: 15px * vertical-align: top display: inline-block @@ -1125,7 +1186,7 @@ $sheet-max-width: 860px &:focus outline: none .oe_searchview_input - padding: 0 3px + padding: 0 0 0 6px .oe_searchview_facet position: relative cursor: pointer @@ -1247,13 +1308,13 @@ $sheet-max-width: 860px // after oe_selected so background color is not overridden &:hover background-color: $hover-background - form - margin-left: 12px - p - margin: 4px 0 - line-height: 18px - button - margin: 0 0 8px 0 + form + margin-left: 12px + p + margin: 4px 0 + line-height: 18px + button + margin: 0 0 8px 0 .oe_searchview_custom padding: 0 8px 8px 8px form @@ -1821,6 +1882,49 @@ $sheet-max-width: 860px input text-align: right // }}} + // Tree view {{{ + .tree_header + background-color: #f0f0f0 + border-bottom: 1px solid #cacaca + color: #4c4c4c + padding: 5px + height: 25px + button + float: right + height: 27px + margin-right: 5px + .oe-treeview-table + width: 100% + background-color: white + border-spacing: 0 + th + padding: 10px + color: #4c4c4c + font-weight: bold + background-color: #f0f0f0 + border-bottom: 2px solid #cacaca + .treeview-tr, .treeview-td + cursor: pointer + border-right: 1px dotted #afafb6 + vertical-align: top + text-align: left + border-bottom: 1px solid #cfcccc + tr:hover + background-color: #e0e0f8 + .oe-number + text-align: right !important + span + font-size: 90% + font-weight: normal + white-space: nowrap + display: block + .treeview-tr.oe-treeview-first + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat + .oe_open .treeview-tr.oe-treeview-first + background-image: url(/web/static/src/img/collapse.gif) + .treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span + margin-left: 16px + // }}} // Translation {{{ .oe_trad_field.touched border: 1px solid green !important @@ -1878,49 +1982,6 @@ $sheet-max-width: 860px float: right color: #333 // }}} -//Tree view -.openerp - .tree_header - background-color: #f0f0f0 - border-bottom: 1px solid #cacaca - color: #4c4c4c - padding: 5px - height: 25px - button - float: right - height: 27px - margin-right: 5px - .oe-treeview-table - width: 100% - background-color: white - border-spacing: 0 - th - padding: 10px - color: #4c4c4c - font-weight: bold - background-color: #f0f0f0 - border-bottom: 2px solid #cacaca - .treeview-tr, .treeview-td - cursor: pointer - border-right: 1px dotted #afafb6 - vertical-align: top - text-align: left - border-bottom: 1px solid #cfcccc - tr:hover - background-color: #e0e0f8 - .oe-number - text-align: right !important - span - font-size: 90% - font-weight: normal - white-space: nowrap - display: block - .treeview-tr.oe-treeview-first - background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat - .oe_open .treeview-tr.oe-treeview-first - background-image: url(/web/static/src/img/collapse.gif) - .treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span - margin-left: 16px // Kitten Mode {{{ .kitten-mode-activated background-image: url(http://placekitten.com/g/1365/769) @@ -1931,8 +1992,6 @@ $sheet-max-width: 860px // }}} -div.ui-widget-overlay - background: black - @include opacity(0.3) + // au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css" // vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker: diff --git a/addons/web/static/src/img/pattern.png b/addons/web/static/src/img/pattern.png Binary files differdeleted file mode 100644 index 7e3a2b37834..00000000000 --- a/addons/web/static/src/img/pattern.png +++ /dev/null diff --git a/addons/web/static/src/img/throbber2.gif b/addons/web/static/src/img/throbber2.gif Binary files differdeleted file mode 100644 index 5d2057ae0e7..00000000000 --- a/addons/web/static/src/img/throbber2.gif +++ /dev/null diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 71010ef6d74..a1759397e21 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -257,7 +257,7 @@ instance.web.Loading = instance.web.Widget.extend({ // Block UI after 3s this.long_running_timer = setTimeout(function () { self.blocked_ui = true; - $.blockUI(); + instance.web.blockUI(); }, 3000); } @@ -276,7 +276,7 @@ instance.web.Loading = instance.web.Widget.extend({ // Don't unblock if blocked by somebody else if (self.blocked_ui) { this.blocked_ui = false; - $.unblockUI(); + instance.web.unblockUI(); } this.$element.fadeOut(); this.getParent().$element.removeClass('oe_wait'); @@ -287,7 +287,7 @@ instance.web.Loading = instance.web.Widget.extend({ instance.web.DatabaseManager = instance.web.Widget.extend({ init: function(parent) { this._super(parent); - this.unblockUIFunction = $.unblockUI; + this.unblockUIFunction = instance.web.unblockUI; $.validator.addMethod('matches', function (s, _, re) { return new RegExp(re).test(s); }, _t("Invalid database name")); @@ -354,16 +354,16 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ * from unblocking the UI */ blockUI: function () { - $.blockUI(); - $.unblockUI = function () {}; + instance.web.blockUI(); + instance.web.unblockUI = function () {}; }, /** * Reinstates $.unblockUI so third parties can play with blockUI, and * unblocks the UI */ unblockUI: function () { - $.unblockUI = this.unblockUIFunction; - $.unblockUI(); + instance.web.unblockUI = this.unblockUIFunction; + instance.web.unblockUI(); }, /** * Displays an error dialog resulting from the various RPC communications @@ -387,8 +387,16 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ var fields = $(form).serializeArray(); self.rpc("/web/database/create", {'fields': fields}, function(result) { var form_obj = self.to_object(fields); - self.getParent().do_login( form_obj['db_name'], 'admin', form_obj['create_admin_pwd']); - self.destroy(); + var client_action = { + type: 'ir.actions.client', + tag: 'login', + params: { + 'db': form_obj['db_name'], + 'login': 'admin', + 'password': form_obj['create_admin_pwd'], + }, + }; + self.do_action(client_action); }); }, @@ -473,19 +481,22 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ }); }, do_exit: function () { + this.do_action("login"); } }); +instance.web.client_actions.add("database_manager", "instance.web.DatabaseManager"); instance.web.Login = instance.web.Widget.extend({ template: "Login", remember_credentials: true, _db_list: null, - init: function(parent) { + init: function(parent, params) { this._super(parent); this.has_local_storage = typeof(localStorage) != 'undefined'; this.selected_db = null; this.selected_login = null; + this.params = params; if (this.has_local_storage && this.remember_credentials) { this.selected_db = localStorage.getItem('last_db_login_success'); @@ -495,26 +506,17 @@ instance.web.Login = instance.web.Widget.extend({ } } }, - open_db_manager: function(){ - var self = this; - self.$element.find('.oe_login_bottom').hide(); - self.$element.find('.oe_login_pane').hide(); - self.databasemanager = new instance.web.DatabaseManager(self); - self.databasemanager.appendTo(self.$element); - self.databasemanager.do_exit.add_last(function() { - self.databasemanager.destroy(); - self.$element.find('.oe_login_bottom').show(); - self.$element.find('.oe_login_pane').show(); - self.load_db_list(true).then(self.on_db_list_loaded); - }); - }, start: function() { var self = this; self.$element.find("form").submit(self.on_submit); self.$element.find('.oe_login_manage_db').click(function() { - self.open_db_manager(); + self.do_action("database_manager"); + }); + return self.load_db_list().then(self.on_db_list_loaded).then(function() { + if(self.params) { + self.do_login(self.params.db, self.params.login, self.params.password); + } }); - return self.load_db_list().then(self.on_db_list_loaded); }, load_db_list: function (force) { var d = $.when(), self = this; @@ -535,7 +537,7 @@ instance.web.Login = instance.web.Widget.extend({ var dbdiv = this.$element.find('div.oe_login_dbpane'); this.$element.find("[name=db]").replaceWith(instance.web.qweb.render('Login.dblist', { db_list: list, selected_db: this.selected_db})); if(list.length === 0) { - self.open_db_manager(); + this.do_action("database_manager"); } else if(list && list.length === 1) { dbdiv.hide(); } else { @@ -582,13 +584,14 @@ instance.web.Login = instance.web.Widget.extend({ localStorage.setItem('last_password_login_success', ''); } } - self.trigger("login"); + self.trigger('login_successful'); },function () { self.$(".oe_login_pane").fadeIn("fast"); self.$element.addClass("oe_login_invalid"); }); } }); +instance.web.client_actions.add("login", "instance.web.Login"); instance.web.Menu = instance.web.Widget.extend({ template: 'Menu', @@ -864,7 +867,7 @@ instance.web.UserMenu = instance.web.Widget.extend({ window.location.href, 'debug'); }); instance.web.dialog($help, {autoOpen: true, - modal: true, width: 960, title: _t("About")}); + modal: true, width: 580, height: 290, resizable: false, title: _t("About")}); }); }, }); @@ -893,7 +896,7 @@ instance.web.Client = instance.web.Widget.extend({ this.$element.on('click', '.oe_dropdown_toggle', function(ev) { ev.preventDefault(); var $toggle = $(this); - var $menu = $toggle.find('.oe_dropdown_menu'); + var $menu = $toggle.parent().find('.oe_dropdown_menu'); var state = $menu.is('.oe_opened'); setTimeout(function() { // Do not alter propagation @@ -903,7 +906,7 @@ instance.web.Client = instance.web.Widget.extend({ var doc_width = $(document).width(); var offset = $menu.offset(); var menu_width = $menu.width(); - var x = doc_width - offset.left - menu_width - 15; + var x = doc_width - offset.left - menu_width - 2; if (x < 0) { $menu.offset({ left: offset.left + x }).width(menu_width); } @@ -964,19 +967,15 @@ instance.web.WebClient = instance.web.Client.extend({ data: {debug: file + ':' + line} }); }; - // TODO: deprecate and use login client action - self.login = new instance.web.Login(self); - self.login.on("login",self,self.show_application); }, show_login: function() { - var self = this; - self.$('.oe_topbar').hide(); - self.login.appendTo(self.$element); + this.$('.oe_topbar').hide(); + this.action_manager.do_action("login"); + this.action_manager.inner_widget.on('login_successful', this, this.show_application); }, show_application: function() { var self = this; self.$('.oe_topbar').show(); - self.login.$element.hide(); self.menu = new instance.web.Menu(self); self.menu.replace(this.$element.find('.oe_menu_placeholder')); self.menu.on('menu_click', this, this.on_menu_action); @@ -1057,6 +1056,7 @@ instance.web.WebClient = instance.web.Client.extend({ }, do_push_state: function(state) { this.set_title(state.title); + delete state.title; var url = '#' + $.param(state); this._current_state = _.clone(state); $.bbq.pushState(url); @@ -1083,10 +1083,13 @@ instance.web.WebClient = instance.web.Client.extend({ } }, set_content_full_screen: function(fullscreen) { - if (fullscreen) + if (fullscreen) { $(".oe_webclient", this.$element).addClass("oe_content_full_screen"); - else + $("body").css({'overflow-y':'hidden'}); + } else { $(".oe_webclient", this.$element).removeClass("oe_content_full_screen"); + $("body").css({'overflow-y':'scroll'}); + } } }); diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js index 1ed4c4788e3..a092b670ef1 100644 --- a/addons/web/static/src/js/corelib.js +++ b/addons/web/static/src/js/corelib.js @@ -378,7 +378,8 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, { instance.web.EventDispatcherMixin.init.call(this); this.__getterSetterInternalMap = {}; }, - set: function(map) { + set: function(map, options) { + options = options || {}; var self = this; var changed = false; _.each(map, function(val, key) { @@ -387,10 +388,11 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, { return; changed = true; self.__getterSetterInternalMap[key] = val; - self.trigger("change:" + key, self, { - oldValue: tmp, - newValue: val - }); + if (! options.silent) + self.trigger("change:" + key, self, { + oldValue: tmp, + newValue: val + }); }); if (changed) self.trigger("change", self); diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index a5a62b9bcc1..24441dc509f 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -550,7 +550,39 @@ $.async_when = function() { /** Setup blockui */ if ($.blockUI) { $.blockUI.defaults.baseZ = 1100; - $.blockUI.defaults.message = '<img src="/web/static/src/img/throbber2.gif">'; + $.blockUI.defaults.message = '<div class="oe_blockui_spin" style="height: 50px">'; + $.blockUI.defaults.css.border = '0'; + $.blockUI.defaults.css["background-color"] = ''; + $.blockUI.spinners = []; +} +instance.web.blockUI = function() { + var tmp = $.blockUI.apply($, arguments); + var target = $(".oe_blockui_spin")[0]; + var opts = { + lines: 13, // The number of lines to draw + length: 7, // The length of each line + width: 4, // The line thickness + radius: 10, // The radius of the inner circle + rotate: 0, // The rotation offset + color: '#FFF', // #rgb or #rrggbb + speed: 1, // Rounds per second + trail: 60, // Afterglow percentage + shadow: false, // Whether to render a shadow + hwaccel: false, // Whether to use hardware acceleration + className: 'spinner', // The CSS class to assign to the spinner + zIndex: 2e9, // The z-index (defaults to 2000000000) + top: 'auto', // Top position relative to parent in px + left: 'auto' // Left position relative to parent in px + }; + var spinner = new Spinner(opts).spin(target); + $.blockUI.spinners.push(spinner); + return tmp; +} +instance.web.unblockUI = function() { + _.each($.blockUI.spinners, function(el) { + el.stop(); + }); + return $.unblockUI.apply($, arguments); } /** Setup default session */ diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js index ebe82ddb4b4..f8e669e1b4a 100644 --- a/addons/web/static/src/js/data_export.js +++ b/addons/web/static/src/js/data_export.js @@ -376,7 +376,7 @@ instance.web.DataExport = instance.web.Dialog.extend({ exported_fields.unshift({name: 'id', label: 'External ID'}); var export_format = this.$element.find("#export_format").val(); - $.blockUI(); + instance.web.blockUI(); this.session.get_file({ url: '/web/export/' + export_format, data: {data: JSON.stringify({ @@ -387,7 +387,7 @@ instance.web.DataExport = instance.web.Dialog.extend({ import_compat: Boolean( this.$element.find("#import_compat").val()) })}, - complete: $.unblockUI + complete: instance.web.unblockUI }); }, close: function() { diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 504510ef133..c3e7ad72dcb 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -330,6 +330,12 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea }); } + // Launch a search on clicking the oe_searchview_search button + this.$element.on('click', 'button.oe_searchview_search', function (e) { + e.stopImmediatePropagation(); + self.do_search(); + }); + this.$element.on('keydown', '.oe_searchview_input, .oe_searchview_facet', function (e) { switch(e.which) { @@ -510,7 +516,16 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea this.$element.addClass('oe_focused'); }, childBlurred: function () { - this.$element.removeClass('oe_focused'); + var val = this.$element.val(); + this.$element.val(''); + var complete = this.$element.data('autocomplete'); + if ((val && complete.term === undefined) || complete.previous !== undefined) { + throw new Error("new jquery.ui version altering implementation" + + " details relied on"); + } + delete complete.term; + this.$element.removeClass('oe_focused') + .trigger('blur'); }, /** * @@ -1475,7 +1490,17 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({ facet_for: function (value) { var self = this; if (value instanceof Array) { - return $.when(facet_from(this, value)); + if (value.length === 2 && _.isString(value[1])) { + return $.when(facet_from(this, value)); + } + if (value.length > 1) { + // more than one search_default m2o id? Should we OR them? + throw new Error( + _("M2O search fields do not currently handle multiple default values")); + } + // there are many cases of {search_default_$m2ofield: [id]}, need + // to handle this as if it were a single value. + value = value[0]; } return this.model.call('name_get', [value], {}).pipe(function (names) { if (_(names).isEmpty()) { return null; } diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 677b7cf7c4e..7f802be2100 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -33,6 +33,11 @@ instance.web.form.FieldManagerMixin = { }; instance.web.views.add('form', 'instance.web.FormView'); +/** + * Properties: + * - actual_mode: always "view", "edit" or "create". Read-only property. Determines + * the mode used by the view. + */ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerMixin, { /** * Indicates that this view is not searchable, and thus that no search @@ -55,6 +60,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM * @property {instance.web.Registry} registry=instance.web.form.widgets widgets registry for this form view instance */ init: function(parent, dataset, view_id, options) { + var self = this; this._super(parent); this.set_default_options(options); this.dataset = dataset; @@ -82,6 +88,13 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.__blur_timeout = null; this.rendering_engine = new instance.web.form.FormRenderingEngine(this); this.qweb = null; // A QWeb instance will be created if the view is a QWeb template + self.set({actual_mode: self.options.initial_mode}); + this.has_been_loaded.then(function() { + self.on("change:actual_mode", self, self.check_actual_mode); + self.check_actual_mode(); + self.on("change:actual_mode", self, self.init_pager); + self.init_pager(); + }); }, destroy: function() { _.each(this.get_widgets(), function(w) { @@ -125,17 +138,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.$buttons.on('click','.oe_form_button_save',this.on_button_save); this.$buttons.on('click','.oe_form_button_cancel',this.on_button_cancel); - this.$pager = $(QWeb.render("FormView.pager", {'widget':self})); - if (this.options.$pager) { - this.$pager.appendTo(this.options.$pager); - } else { - this.$element.find('.oe_form_pager').replaceWith(this.$pager); - } - this.$pager.on('click','a[data-pager-action]',function() { - var action = $(this).data('pager-action'); - self.on_pager_action(action); - }); - this.$sidebar = this.options.$sidebar || this.$element.find('.oe_form_sidebar'); if (!this.sidebar && this.options.$sidebar) { this.sidebar = new instance.web.Sidebar(this); @@ -149,8 +151,15 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM { label: _t('Set Default'), callback: function (item) { self.open_defaults_dialog(); } }, ]); } - this.on("change:mode", this, this.switch_mode); - this.set({mode: this.options.initial_mode}); + + // Add bounce effect on button 'Edit' when click on readonly page view. + this.$element.find(".oe_form_field, .oe_form_group_cell").on('click', function (e) { + if(self.get("actual_mode") == "view") { + var $button = self.options.$buttons.find(".oe_form_button_edit"); + $button.wrap('<div>').css('margin-right','4px').addClass('oe_left oe_bounce'); + } + }); + this.has_been_loaded.resolve(); return $.when(); }, @@ -275,7 +284,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } return shown.pipe(function() { if (options.editable) { - self.set({mode: "edit"}); + self.to_edit_mode(); } self.$element.css('visibility', 'visible'); }); @@ -300,6 +309,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return $.Deferred().reject(); } this.datarecord = record; + this._actualize_mode(); this.set({ 'title' : record.id ? record.name : "New record" }); if (this.qweb) { @@ -377,6 +387,24 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.reload(); } }, + init_pager: function() { + var self = this; + if (this.$pager) + this.$pager.remove(); + if (this.get("actual_mode") === "create") + return; + this.$pager = $(QWeb.render("FormView.pager", {'widget':self})); + if (this.options.$pager) { + this.$pager.appendTo(this.options.$pager); + } else { + this.$element.find('.oe_form_pager').replaceWith(this.$pager); + } + this.$pager.on('click','a[data-pager-action]',function() { + var action = $(this).data('pager-action'); + self.on_pager_action(action); + }); + this.do_update_pager(); + }, do_update_pager: function(hide_index) { var index = hide_index ? '-' : this.dataset.index + 1; this.$pager.find('button').prop('disabled', this.dataset.ids.length < 2).end() @@ -576,9 +604,32 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return $.Deferred().reject(); } }, - switch_mode: function() { + /** + * Ask the view to switch to view mode if possible. The view may not do it + * if the current record is not yet saved. It will then stay in create mode. + */ + to_view_mode: function() { + this._actualize_mode("view"); + }, + /** + * Ask the view to switch to edit mode if possible. The view may not do it + * if the current record is not yet saved. It will then stay in create mode. + */ + to_edit_mode: function() { + this._actualize_mode("edit"); + }, + /** + * Reactualize actual_mode. + */ + _actualize_mode: function(switch_to) { + var mode = switch_to || this.get("actual_mode"); + if (! this.datarecord.id) + mode = "create"; + this.set({actual_mode: mode}); + }, + check_actual_mode: function(source, options) { var self = this; - if(this.get("mode") == "view") { + if(this.get("actual_mode") === "view") { self.$element.removeClass('oe_form_editable').addClass('oe_form_readonly'); self.$buttons.find('.oe_form_buttons_edit').hide(); self.$buttons.find('.oe_form_buttons_view').show(); @@ -596,11 +647,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); var fields_order = self.fields_order.slice(0); if (self.default_focus_field) { - fields_order.unshift(self.default_focus_field); + fields_order.unshift(self.default_focus_field.name); } for (var i = 0; i < fields_order.length; i += 1) { var field = self.fields[fields_order[i]]; - if (!field.get('effective_invisible') && !field.get('effective_readonly') && field.focus() !== false) { + if (!field.get('effective_invisible') && !field.get('effective_readonly')) { + field.focus(); break; } } @@ -609,19 +661,19 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM on_button_save: function() { var self = this; return this.do_save().then(function(result) { - self.set({mode: "view"}); + self.to_view_mode(); }); }, on_button_cancel: function(event) { if (this.can_be_discarded()) { - this.set({mode: "view"}); + this.to_view_mode(); this.on_record_loaded(this.datarecord); } return false; }, on_button_new: function() { var self = this; - this.set({mode: "edit"}); + this.to_edit_mode(); return $.when(this.has_been_loaded).pipe(function() { if (self.can_be_discarded()) { return self.load_defaults(); @@ -629,7 +681,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); }, on_button_edit: function() { - return this.set({mode: "edit"}); + return this.to_edit_mode(); }, on_button_create: function() { this.dataset.index = null; @@ -642,7 +694,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) { return self.on_created({ result : new_id }); }).then(function() { - return self.set({mode: "edit"}); + return self.to_edit_mode(); }).then(function() { def.resolve(); }); @@ -935,7 +987,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM register_field: function(field, name) { this.fields[name] = field; this.fields_order.push(name); - if (field.node.attrs.default_focus == '1') { + if (JSON.parse(field.node.attrs.default_focus || "0")) { this.default_focus_field = field; } @@ -957,7 +1009,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return this.fields_view.fields[field_name]; }, is_create_mode: function() { - return !this.datarecord.id; + return this.get("actual_mode") === "create"; }, open_translate_dialog: function(field) { return this._super(field); @@ -1641,10 +1693,13 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ this._super(view, node); this.force_disabled = false; this.string = (this.node.attrs.string || '').replace(/_/g, ''); - if (this.node.attrs.default_focus == '1') { + if (JSON.parse(this.node.attrs.default_focus || "0")) { // TODO fme: provide enter key binding to widgets this.view.default_focus_button = this; } + if (this.node.attrs.icon && (! /\//.test(this.node.attrs.icon))) { + this.node.attrs.icon = '/web/static/src/img/icons/' + this.node.attrs.icon + '.png'; + } this.view.on('view_content_has_changed', this, this.check_disable); }, start: function() { @@ -2818,10 +2873,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc if (follow) link += "<br />"; } - this.$element.find('a') + var $link = this.$element.find('.oe_form_uri') .unbind('click') - .html(link) - .click(function () { + .html(link); + if (! this.get_definition_options().no_open) + $link.click(function () { self.do_action({ type: 'ir.actions.act_window', res_model: self.field.relation, @@ -2979,6 +3035,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ } if(view.view_type === "list") { _.extend(view.options, { + addable: null, selectable: self.multi_selection, sortable: false, import_enabled: false, @@ -2986,7 +3043,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ }); if (self.get("effective_readonly")) { _.extend(view.options, { - addable: null, deletable: null, reorderable: false, }); @@ -3027,8 +3083,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ this.viewmanager.on_controller_inited.add_last(function(view_type, controller) { controller.o2m = self; if (view_type == "list") { - if (self.get("effective_readonly")) - controller.set_editable(false); + if (self.get("effective_readonly")) { + controller.on('edit:before', self, function (e) { + e.cancel = true; + }); + } } else if (view_type === "form") { if (self.get("effective_readonly")) { $(".oe_form_buttons", controller.$element).children().remove(); @@ -3301,7 +3360,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ .value(); }, do_add_record: function () { - if (this.options.editable) { + if (this.editable()) { this._super.apply(this, arguments); } else { var self = this; @@ -3408,6 +3467,34 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ this._super.apply(this, arguments); } }); +instance.web.form.One2ManyList = instance.web.ListView.List.extend({ + pad_table_to: function (count) { + this._super(count > 0 ? count - 1 : 0); + + // magical invocation of wtf does that do + if (this.view.o2m.get('effective_readonly')) { + return; + } + + var self = this; + var columns = _(this.columns).filter(function (column) { + return column.invisible !== '1'; + }).length; + if (this.options.selectable) { columns++; } + if (this.options.deletable) { columns++; } + var $cell = $('<td>', { + colspan: columns, + 'class': 'oe_form_field_one2many_list_row_add' + }).text(_t("Add a row")) + .click(function (e) { + e.preventDefault(); + e.stopPropagation(); + self.view.do_add_record(); + }); + this.$current.append( + $('<tr>').append($cell)) + } +}); instance.web.form.One2ManyFormView = instance.web.FormView.extend({ form_template: 'One2Many.formview', @@ -3535,12 +3622,13 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in render_value: function() { var self = this; var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.view.dataset.get_context()); + var values = self.get("value") var handle_names = function(data) { var indexed = {}; _.each(data, function(el) { indexed[el[0]] = el; }); - data = _.map(self.get("value"), function(el) { return indexed[el]; }); + data = _.map(values, function(el) { return indexed[el]; }); if (! self.get("effective_readonly")) { self.tags.containerElement().children().remove(); $("textarea", self.$element).css("padding-left", "3px"); @@ -3549,8 +3637,8 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in self.$element.html(QWeb.render("FieldMany2ManyTag", {elements: data})); } }; - if (! self.get('values') || self.get('values').length > 0) { - this._display_orderer.add(dataset.name_get(self.get("value"))).then(handle_names); + if (! values || values.length > 0) { + this._display_orderer.add(dataset.name_get(values)).then(handle_names); } else { handle_names([]); } @@ -4108,10 +4196,12 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend self.dataset, false, _.extend({'deletable': false, 'selectable': !self.options.disable_multiple_selection, - 'read_only': true, 'import_enabled': false, '$buttons': self.$buttonpane, }, self.options.list_view_options || {})); + self.view_list.on('edit:before', self, function (e) { + e.cancel = true; + }); self.view_list.popup = self; self.view_list.appendTo($(".oe_popup_list", self.$element)).pipe(function() { self.view_list.do_show(); @@ -4343,7 +4433,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. //link.target = '_blank'; link.href = "data:application/octet-stream;base64," + value; } else { - $.blockUI(); + instance.web.blockUI(); this.session.get_file({ url: '/web/binary/saveas_ajax', data: {data: JSON.stringify({ @@ -4353,7 +4443,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. filename_field: (this.node.attrs.filename || ''), context: this.view.dataset.get_context() })}, - complete: $.unblockUI, + complete: instance.web.unblockUI, error: instance.webclient.crashmanager.on_rpc_error }); ev.stopPropagation(); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index f68f1354099..9c7bf88db1a 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -21,9 +21,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi // whether the view rows can be reordered (via vertical drag & drop) 'reorderable': true, 'action_buttons': true, - // if true, the view can't be editable, ignoring the view's and the context's - // instructions - 'read_only': false, // if true, the 'Import', 'Export', etc... buttons will be shown 'import_enabled': true, }, @@ -360,6 +357,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi { label: _t('Delete'), callback: this.do_delete_selected }, ]); this.sidebar.add_toolbar(this.fields_view.toolbar); + this.sidebar.$element.hide(); } }, /** @@ -378,6 +376,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi var total = dataset.size(); var limit = this.limit() || total; + this.$pager.toggle(total !== 0); this.$pager.toggleClass('oe_list_pager_single_page', (total <= limit)); var spager = '-'; if (total) { @@ -496,9 +495,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi }, do_show: function () { this._super(); - if (this.sidebar) { - this.sidebar.$element.show(); - } if (this.$buttons) { this.$buttons.show(); } @@ -937,7 +933,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. '[data-id=' + record.get('id') + ']'); var index = $row.data('index'); $row.remove(); - self.refresh_zebra(index); }, 'reset': function () { return self.on_records_reset(); }, 'change': function (event, record, attribute, value, old_value) { @@ -972,8 +967,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. '[data-id=' + previous_record.get('id') + ']'); $new_row.insertAfter($previous_sibling); } - - self.refresh_zebra(index, 1); } }; _(this.record_callbacks).each(function (callback, event) { @@ -1113,7 +1106,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. this.$current .children('tr:not([data-id])').remove().end() .append(new Array(count - this.records.length + 1).join(row)); - this.refresh_zebra(this.records.length); }, /** * Gets the ids of all currently selected records, if any @@ -1187,25 +1179,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. render_cell: function () { return self.render_cell.apply(self, arguments); } }); - }, - /** - * Fixes fixes the even/odd classes - * - * @param {Number} [from_index] index from which to resequence - * @param {Number} [offset = 0] selection offset for DOM, in case there are rows to ignore in the table - */ - refresh_zebra: function (from_index, offset) { - offset = offset || 0; - from_index = from_index || 0; - var dom_offset = offset + from_index; - var sel = dom_offset ? ':gt(' + (dom_offset - 1) + ')' : null; - this.$current.children(sel).each(function (i, e) { - var index = from_index + i; - // reset record-index accelerators on rows and even/odd - var even = index%2 === 0; - $(e).toggleClass('even', even) - .toggleClass('odd', !even); - }); } }); instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.web.ListView.Groups# */{ @@ -1538,8 +1511,6 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we }(dataset, record.get('id'), seq)); record.set('sequence', seq); } - - list.refresh_zebra(); } }); }, diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index 56df125c98b..ca889f68d8d 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -12,6 +12,8 @@ openerp.web.list_editable = function (instance) { var self = this; this._super.apply(this, arguments); + this._force_editability = null; + this._context_editable = false; this.editor = this.make_editor(); // Stores records of {field, cell}, allows for re-rendering fields // depending on cell state during and after resize events @@ -37,6 +39,11 @@ openerp.web.list_editable = function (instance) { } }); + this.on('edit:before', this, function (event) { + if (!self.editable() || self.editor.is_editing()) { + event.cancel = true; + } + }); this.on('edit:after', this, function () { self.$element.add(self.$buttons).addClass('oe_editing'); }); @@ -62,26 +69,16 @@ openerp.web.list_editable = function (instance) { do_edit: function (index, id, dataset) { _.extend(this.dataset, dataset); }, - /** - * Sets editability status for the list, based on defaults, view - * architecture and the provided flag, if any. - * - * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom". - */ - set_editable: function (force) { - // TODO: fix handling of editability status to be simpler & clearer & more coherent - // If ``force``, set editability to bottom - // otherwise rely on view default - // view' @editable is handled separately as we have not yet - // fetched and processed the view at this point. - this.options.editable = ( - ! this.options.read_only && ((force && "bottom") || this.defaults.editable)); + editable: function () { + return this.fields_view.arch.attrs.editable + || this._context_editable + || this.options.editable; }, /** * Replace do_search to handle editability process */ do_search: function(domain, context, group_by) { - this.set_editable(context['set_editable']); + this._context_editable = !!context.set_editable; this._super.apply(this, arguments); }, /** @@ -89,7 +86,7 @@ openerp.web.list_editable = function (instance) { * as an editable row at the top or bottom of the list) */ do_add_record: function () { - if (this.options.editable) { + if (this.editable()) { this.$element.find('table:first').show(); this.$element.find('.oe_view_nocontent').remove(); this.start_edition(); @@ -103,9 +100,8 @@ openerp.web.list_editable = function (instance) { this.editor.destroy(); } // tree/@editable takes priority on everything else if present. - this.options.editable = ! this.options.read_only && (data.arch.attrs.editable || this.options.editable); var result = this._super(data, grouped); - if (this.options.editable) { + if (this.editable()) { // FIXME: any hook available to ensure this is only done once? this.$buttons .off('click', '.oe_list_save') @@ -202,12 +198,20 @@ openerp.web.list_editable = function (instance) { return; } + // FIXME: need better way to get the field back from bubbling (delegated) DOM events somehow + field.$element.attr('data-fieldname', field_name); self.fields_for_resize.push({field: field, cell: cell}); }, options).pipe(function () { $recordRow.addClass('oe_edition'); self.resize_fields(); return record.attributes; }); + }).fail(function () { + // if the start_edition event is cancelled and it was a + // creation, remove the newly-created empty record + if (!record.get('id')) { + self.records.remove(record); + } }); }); }, @@ -377,7 +381,7 @@ openerp.web.list_editable = function (instance) { return this.reload_record(record); }, prepends_on_create: function () { - return this.options.editable === 'top'; + return this.editable() === 'top'; }, setup_events: function () { var self = this; @@ -399,18 +403,20 @@ openerp.web.list_editable = function (instance) { * * @private * @param {String} [next_record='succ'] method to call on the records collection to get the next record to edit + * @param {Object} [options] + * @param {String} [options.focus_field] * @return {*} */ - _next: function (next_record) { + _next: function (next_record, options) { next_record = next_record || 'succ'; var self = this; return this.save_edition().pipe(function (saveInfo) { if (saveInfo.created) { return self.start_edition(); } - return self.start_edition( - self.records[next_record]( - saveInfo.record, {wraparound: true})); + var record = self.records[next_record]( + saveInfo.record, {wraparound: true}); + return self.start_edition(record, options); }); }, keyup_ENTER: function () { @@ -419,46 +425,142 @@ openerp.web.list_editable = function (instance) { keyup_ESCAPE: function () { return this.cancel_edition(); }, + /** + * Gets the selection range (start, end) for the provided element, + * returns ``null`` if it can't get a range. + * + * @private + */ _text_selection_range: function (el) { - if (el.selectionStart !== undefined) { + var selectionStart; + try { + selectionStart = el.selectionStart; + } catch (e) { + // radio or checkbox throw on selectionStart access + return null; + } + if (selectionStart !== undefined) { return { - start: el.selectionStart, + start: selectionStart, end: el.selectionEnd }; - } else if(document.body.createTextRange) { + } else if (document.body.createTextRange) { throw new Error("Implement text range handling for MSIE"); var sel = document.body.createTextRange(); if (sel.parentElement() === el) { } } + // Element without selection ranges (select, div/@contenteditable) + return null; }, _text_cursor: function (el) { var selection = this._text_selection_range(el); - if (selection.start !== selection.end) { + if (!selection) { return null; } - return selection.start; + if (selection.start !== selection.end) { + return {position: null, collapsed: false}; + } + return {position: selection.start, collapsed: true}; }, - keydown_UP: function (e) { + /** + * Checks if the cursor is at the start of the provided el + * + * @param {HTMLInputElement | HTMLTextAreaElement} + * @returns {Boolean} + * @private + */ + _at_start: function (cursor, el) { + return cursor.collapsed && (cursor.position === 0); + }, + /** + * Checks if the cursor is at the end of the provided el + * + * @param {HTMLInputElement | HTMLTextAreaElement} + * @returns {Boolean} + * @private + */ + _at_end: function (cursor, el) { + return cursor.collapsed && (cursor.position === el.value.length); + }, + /** + * @param DOMEvent event + * @param {String} record_direction direction to move into to get the next record (pred | succ) + * @param {Function} is_valid_move whether the edition should be moved to the next record + * @private + */ + _key_move_record: function (event, record_direction, is_valid_move) { if (!this.editor.is_editing('edit')) { return $.when(); } - // FIXME: assumes editable widgets are input-type elements - var index = this._text_cursor(e.target); - // If selecting or not at the start of the input - if (index === null || index !== 0) { return $.when(); } + var cursor = this._text_cursor(event.target); + // if text-based input (has a cursor) + // and selecting (not collapsed) or not at a field boundary + // don't move to the next record + if (cursor && !is_valid_move(event.target, cursor)) { return $.when(); } - e.preventDefault(); - return this._next('pred'); + event.preventDefault(); + var source_field = $(event.target).closest('[data-fieldname]') + .attr('data-fieldname'); + return this._next(record_direction, {focus_field: source_field}); + + }, + keydown_UP: function (e) { + var self = this; + return this._key_move_record(e, 'pred', function (el, cursor) { + return self._at_start(cursor, el); + }); }, keydown_DOWN: function (e) { - if (!this.editor.is_editing('edit')) { return $.when(); } - // FIXME: assumes editable widgets are input-type elements - var index = this._text_cursor(e.target); - // If selecting or not at the end of the input - if (index === null || index !== e.target.value.length) { return $.when(); } + var self = this; + return this._key_move_record(e, 'succ', function (el, cursor) { + return self._at_end(cursor, el); + }); + }, - e.preventDefault(); - return this._next(); + keydown_LEFT: function (e) { + // If the cursor is at the beginning of the field + var source_field = $(e.target).closest('[data-fieldname]') + .attr('data-fieldname'); + var cursor = this._text_cursor(e.target); + if (cursor && !this._at_start(cursor, e.target)) { return $.when(); } + + var fields_order = this.editor.form.fields_order; + var field_index = _(fields_order).indexOf(source_field); + + // Look for the closest visible form field to the left + var fields = this.editor.form.fields; + var field; + do { + if (--field_index < 0) { return $.when(); } + + field = fields[fields_order[field_index]]; + } while (!field.$element.is(':visible')); + + // and focus it + field.focus(); + return $.when(); + }, + keydown_RIGHT: function (e) { + // same as above, but with cursor at the end of the field and + // looking for new fields at the right + var source_field = $(e.target).closest('[data-fieldname]') + .attr('data-fieldname'); + var cursor = this._text_cursor(e.target); + if (cursor && !this._at_end(cursor, e.target)) { return $.when(); } + + var fields_order = this.editor.form.fields_order; + var field_index = _(fields_order).indexOf(source_field); + + var fields = this.editor.form.fields; + var field; + do { + if (++field_index >= fields_order.length) { return $.when(); } + + field = fields[fields_order[field_index]]; + } while (!field.$element.is(':visible')); + + field.focus(); + return $.when(); }, keydown_TAB: function (e) { var form = this.editor.form; @@ -642,7 +744,7 @@ openerp.web.list_editable = function (instance) { instance.web.ListView.List.include(/** @lends instance.web.ListView.List# */{ row_clicked: function (event) { - if (!this.options.editable) { + if (!this.view.editable()) { return this._super.apply(this, arguments); } var record_id = $(event.currentTarget).data('id'); diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index ccf34576a1a..10f44a54f11 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -120,7 +120,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ if (this.getParent() && this.getParent().do_push_state) { if (this.inner_action) { state['title'] = this.inner_action.name; - state['model'] = this.inner_action.res_model; + if(this.inner_action.type == 'ir.actions.act_window') { + state['model'] = this.inner_action.res_model; + } if (this.inner_action.id) { state['action_id'] = this.inner_action.id; } @@ -178,7 +180,10 @@ instance.web.ActionManager = instance.web.Widget.extend({ }); }, do_action: function(action, on_close) { - if (_.isNumber(action) || _.isString(action)) { + if (_.isString(action) && instance.web.client_actions.contains(action)) { + var action_client = { type: "ir.actions.client", tag: action }; + return this.do_action(action_client); + } else if (_.isNumber(action) || _.isString(action)) { var self = this; return self.rpc("/web/action/load", { action_id: action }, function(result) { self.do_action(result.result, on_close); @@ -209,21 +214,30 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog_stop(); this.clear_breadcrumbs(); }, - ir_actions_act_window: function (action, on_close) { - var self = this; - if (_(['base.module.upgrade', 'base.setup.installer']) - .contains(action.res_model)) { - var old_close = on_close; - on_close = function () { - instance.webclient.do_reload().then(old_close); - }; + + do_ir_actions_common: function(action, on_close) { + var self = this, klass, widget, add_breadcrumb; + if (action.type === 'ir.actions.client') { + var ClientWidget = instance.web.client_actions.get_object(action.tag); + widget = new ClientWidget(this, action.params); + klass = 'oe_act_client'; + add_breadcrumb = function() { + self.push_breadcrumb({ + widget: widget, + title: action.name + }); + } + } else { + widget = new instance.web.ViewManagerAction(this, action); + klass = 'oe_act_window'; + add_breadcrumb = widget.add_breadcrumb } if (action.target === 'new') { if (this.dialog === null) { // These buttons will be overwrited by <footer> if any this.dialog = new instance.web.Dialog(this, { buttons: { "Close": function() { $(this).dialog("close"); }}, - dialogClass: 'oe_act_window' + dialogClass: klass }); if(on_close) this.dialog.on_close.add(on_close); @@ -231,7 +245,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog_widget.destroy(); } this.dialog.dialog_title = action.name; - this.dialog_widget = new instance.web.ViewManagerAction(this, action); + this.dialog_widget = widget; this.dialog_widget.appendTo(this.dialog.$element); this.dialog.open(); } else { @@ -242,11 +256,34 @@ instance.web.ActionManager = instance.web.Widget.extend({ }); } this.inner_action = action; - var inner_widget = this.inner_widget = new instance.web.ViewManagerAction(this, action); - inner_widget.add_breadcrumb(); + this.inner_widget = widget; + add_breadcrumb(); this.inner_widget.appendTo(this.$element); } }, + + ir_actions_act_window: function (action, on_close) { + var self = this; + if (_(['base.module.upgrade', 'base.setup.installer']) + .contains(action.res_model)) { + var old_close = on_close; + on_close = function () { + instance.webclient.do_reload().then(old_close); + }; + } + if (action.target !== 'new') { + if(action.menu_id) { + this.dialog_stop(); + return this.getParent().do_action(action, function () { + instance.webclient.menu.open_menu(action.menu_id); + }); + } + } + return this.do_ir_actions_common(action, on_close); + }, + ir_actions_client: function (action, on_close) { + return this.do_ir_actions_common(action, on_close); + }, ir_actions_act_window_close: function (action, on_closed) { if (!this.dialog && on_closed) { on_closed(); @@ -262,19 +299,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ self.do_action(action, on_closed) }); }, - ir_actions_client: function (action) { - this.dialog_stop(); - var ClientWidget = instance.web.client_actions.get_object(action.tag); - this.inner_widget = new ClientWidget(this, action.params); - this.push_breadcrumb({ - widget: this.inner_widget, - title: action.name - }); - this.inner_widget.appendTo(this.$element); - }, ir_actions_report_xml: function(action, on_closed) { var self = this; - $.blockUI(); + instance.web.blockUI(); self.rpc("/web/session/eval_domain_and_context", { contexts: [action.context], domains: [] @@ -284,7 +311,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ self.session.get_file({ url: '/web/report', data: {action: JSON.stringify(action)}, - complete: $.unblockUI, + complete: instance.web.unblockUI, success: function(){ if (!self.dialog && on_closed) { on_closed(); @@ -841,7 +868,7 @@ instance.web.Sidebar = instance.web.Widget.extend({ } else { self.do_attachement_update(self.dataset, self.model_id); } - $.unblockUI(); + instance.web.unblockUI(); }); }, start: function() { @@ -980,7 +1007,7 @@ instance.web.Sidebar = instance.web.Widget.extend({ $e.parent().find('input[type=file]').prop('disabled', true); $e.parent().find('button').prop('disabled', true).find('img, span').toggle(); this.$('.oe_sidebar_add_attachment span').text(_t('Uploading...')); - $.blockUI(); + instance.web.blockUI(); } }, on_attachment_delete: function(e) { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index ed63b5fbfbe..29670c8e7de 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -329,21 +329,20 @@ </span> </t> <t t-name="UserMenu.about"> - <div> - <a class="oe_activate_debug_mode" href="?debug" style="float:right; font-size: 80%;">Activate the developer mode</a> - <h1 style="margin:0;">OpenERP</h1> - <h3 style="margin:15px 0;padding:0;">Version <t t-esc="version_info.version"/></h3> - <p> - Copyright © 2004-TODAY OpenERP SA. All Rights Reserved.<br /> - OpenERP is a trademark of the <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP SA Company</a>. - </p> - <p> - Licenced under the terms of <a target="_blank" href="http://www.gnu.org/licenses/agpl.html" style="text-decoration: underline;">GNU Affero General Public License</a> - </p> - <p> - For more information visit <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP.com</a> - </p> + + <div class="oe_about"> + <a class="oe_activate_debug_mode oe_right" href="?debug">Activate the developer mode</a> + <img class="oe_logo" src="/web/static/src/img/logo2.png"/> + <h3>Version <t t-esc="version_info.version"/></h3> + + <div class="oe_bottom"> + <p>Copyright © 2004-TODAY OpenERP SA. All Rights Reserved.<br /> + OpenERP is a trademark of the <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP SA Company</a>.</p> + <p>Licenced under the terms of <a target="_blank" href="http://www.gnu.org/licenses/agpl.html" style="text-decoration: underline;">GNU Affero General Public License</a></p> + <p>For more information visit <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP.com</a></p> + </div> </div> + </t> <t t-name="UserMenu.password"> <form name="change_password_form" method="POST"> @@ -519,25 +518,25 @@ <div class="oe_form_dropdown_section"> <button class="oe_dropdown_toggle oe_dropdown_arrow"> <t t-esc="section.label"/> - <ul class="oe_dropdown_menu"> - <li t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname"> - <a class="oe_sidebar_action_a" t-att-title="item.title" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url" target="_blank"> - <t t-raw="item.label"/> - </a> - <a t-if="section.name == 'files'" class="oe_sidebar_delete_item" t-att-data-id="item.id" title="Delete this attachment">x</a> - </li> - <li t-if="section.name == 'files'" class="oe_sidebar_add_attachment"> - <t t-call="HiddenInputFile"> - <t t-set="fileupload_id" t-value="widget.fileupload_id"/> - <t t-set="fileupload_action">/web/binary/upload_attachment</t> - <input type="hidden" name="model" t-att-value="widget.dataset and widget.dataset.model"/> - <input type="hidden" name="id" t-att-value="widget.model_id"/> - <input type="hidden" name="session_id" t-att-value="widget.session.session_id"/> - <span>Add...</span> - </t> - </li> - </ul> </button> + <ul class="oe_dropdown_menu"> + <li t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname"> + <a class="oe_sidebar_action_a" t-att-title="item.title" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url" target="_blank"> + <t t-raw="item.label"/> + </a> + <a t-if="section.name == 'files'" class="oe_sidebar_delete_item" t-att-data-id="item.id" title="Delete this attachment">x</a> + </li> + <li t-if="section.name == 'files'" class="oe_sidebar_add_attachment"> + <t t-call="HiddenInputFile"> + <t t-set="fileupload_id" t-value="widget.fileupload_id"/> + <t t-set="fileupload_action">/web/binary/upload_attachment</t> + <input type="hidden" name="model" t-att-value="widget.dataset and widget.dataset.model"/> + <input type="hidden" name="id" t-att-value="widget.model_id"/> + <input type="hidden" name="session_id" t-att-value="widget.session.session_id"/> + <span>Add...</span> + </t> + </li> + </ul> </div> </t> </div> @@ -646,17 +645,14 @@ <t t-name="ListView.rows" t-foreach="records.length" t-as="index"> <t t-call="ListView.row"> <t t-set="record" t-value="records.at(index)"/> - <t t-set="row_parity" t-value="index_parity"/> </t> </t> -<tr t-name="ListView.row" t-att-class="row_parity" +<tr t-name="ListView.row" t-att-data-id="record.get('id')" t-att-style="view.style_for(record)"> <t t-set="asData" t-value="record.toForm().data"/> <t t-foreach="columns" t-as="column"> - <td t-if="column.meta"> - - </td> + <td t-if="column.meta"> </td> </t> <th t-if="options.selectable" class="oe_list_record_selector" width="1"> <t t-set="checked" t-value="options.select_view_id == record.get('id') ? 'checked' : null"/> @@ -675,7 +671,6 @@ <button type="button" name="delete" class="oe_i">d</button> </td> </tr> - <t t-extend="ListView.buttons"> <t t-jquery="button.oe_list_add" t-operation="after"> <button class="oe_button oe_list_save oe_highlight" @@ -685,6 +680,15 @@ <a href="#" class="oe_bold oe_list_discard">discard</a> </t> </t> +<t t-extend="ListView.row"> + <!-- adds back padding to row being rendered after edition, if necessary + (if not deletable add back padding), otherwise the row being added is + missing columns + --> + <t t-jquery="> :last" t-operation="after"> + <td t-if="edited and !options.deletable" class="oe-listview-padding"/> + </t> +</t> <t t-name="FormView"> <div class="oe_formview"> @@ -956,11 +960,13 @@ <t t-name="FieldMany2One"> <span class="oe_form_field oe_form_field_many2one oe_form_field_with_button" t-att-style="widget.node.attrs.style"> <t t-if="widget.get('effective_readonly')"> - <a href="#" class="oe_form_uri"/> + <a t-if="! widget.get_definition_options().no_open" href="#" class="oe_form_uri"/> + <span t-if="widget.get_definition_options().no_open" href="#" class="oe_form_uri"/> <span class="oe_form_m2o_follow"/> </t> <t t-if="!widget.get('effective_readonly')"> - <a href="#" tabindex="-1" class="oe_m2o_cm_button oe_e oe_right">/</a> + <a t-if="! widget.get_definition_options().no_open" href="#" tabindex="-1" + class="oe_m2o_cm_button oe_e oe_right">/</a> <div> <input type="text" t-att-id="widget.id_for_label" @@ -975,7 +981,6 @@ </t> </span> </t> -<!-- Collection of m2m tags --> <t t-name="FieldMany2ManyTags"> <div class="oe_form_field oe_tags" t-att-style="widget.node.attrs.style"> <t t-if="! widget.get('effective_readonly')"> @@ -984,7 +989,6 @@ </t> </div> </t> -<!-- Individual m2m tag element --> <t t-name="FieldMany2ManyTag"> <t t-set="i" t-value="0"/> <t t-foreach="elements" t-as="el"> @@ -1132,7 +1136,7 @@ t-att-style="widget.node.attrs.style" t-att-tabindex="widget.node.attrs.tabindex" t-att-autofocus="widget.node.attrs.autofocus"> - <img t-if="widget.node.attrs.icon" t-att-src="_s + '/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/> + <img t-if="widget.node.attrs.icon" t-att-src="_s + widget.node.attrs.icon" width="16" height="16"/> <span t-if="widget.string"><t t-esc="widget.string"/></span> </button> </t> @@ -1190,6 +1194,41 @@ </table> </t> +<t t-name="AbstractFormPopup.render"> + <div> + <table style="width:100%"> + <tr style="width:100%"> + <td style="width:100%"> + <div class="oe_popup_search" style="width:100%"></div> + </td> + </tr> + <tr style="width:100%"> + <td style="width:100%"> + <div class="oe_popup_list" style="width:100%"></div> + </td> + </tr> + </table> + <div class="oe_popup_form" style="width:100%"></div> + </div> +</t> +<t t-name="SelectCreatePopup.search.buttons"> + <t t-if="! widget.options.disable_multiple_selection"> + <button type="button" class="oe_button oe_selectcreatepopup-search-select" disabled="disabled">Select</button> + or + </t> + <a class="oe_button oe_selectcreatepopup-search-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a> +</t> +<t t-name="AbstractFormPopup.buttons"> + <t t-if="! multi_select"> + <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save</button> + </t> + <t t-if="multi_select"> + <button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save & New</button> + <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save & Close</button> + </t> + or <a class="oe_button oe_abstractformpopup-form-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Discard</a> +</t> + <t t-name="One2Many.viewmanager" t-extend="ViewManager"> <t t-jquery=".oe-view-manager-header"> this.attr('t-if', 'views.length != 1'); @@ -1220,6 +1259,8 @@ <div class="oe_searchview_clear"/> <div class="oe_searchview_unfold_drawer" title="Advanced Search..."/> <div class="oe_searchview_drawer"/> + <button type="button" class="oe_searchview_search" + title="Search Again">Search</button> </div> <div t-name="SearchView.InputView" @@ -1240,7 +1281,6 @@ <span t-name="SearchView.FacetView.Value" class="oe_facet_value"> <t t-esc="widget.model.get('label')"/> </span> - <t t-name="SearchView.managed-filters"> <option class="oe_search_filters_title" value="">Filters</option> <optgroup label="-- Filters --"> @@ -1265,7 +1305,6 @@ <p>(Any existing filter with the same name will be replaced)</p> </div> </t> - <t t-name="SearchView.render_lines"> <table class="oe_search_render_line" border="0" cellspacing="0" cellpadding="0" t-foreach="lines" t-as="line"> @@ -1407,8 +1446,8 @@ <div t-name="SearchView.addtodashboard" class="oe_searchview_dashboard"> <h4>Add to Dashboard</h4> <form> - <input placeholder ="Title of new Dashboard item" title = "Title of new Dashboard item" type="text"/> - <button class="oe_apply" type="submit">save</button> + <p><input placeholder ="Title of new Dashboard item" title = "Title of new Dashboard item" type="text"/></p> + <button class="oe_apply" type="submit">Save</button> </form> </div> <t t-name="SearchView.addtodashboard.selection"> @@ -1462,49 +1501,6 @@ </t> </select> </t> -<t t-name="AbstractFormPopup.render"> - <div> - <table style="width:100%"> - <tr style="width:100%"> - <td style="width:100%"> - <div class="oe_popup_search" style="width:100%"></div> - </td> - </tr> - <tr style="width:100%"> - <td style="width:100%"> - <div class="oe_popup_list" style="width:100%"></div> - </td> - </tr> - </table> - <div class="oe_popup_form" style="width:100%"></div> - </div> -</t> -<t t-name="SelectCreatePopup.search.buttons"> - <t t-if="! widget.options.disable_multiple_selection"> - <button type="button" class="oe_button oe_selectcreatepopup-search-select" disabled="disabled">Select</button> - or - </t> - <a class="oe_button oe_selectcreatepopup-search-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a> -</t> -<t t-name="AbstractFormPopup.buttons"> - <t t-if="! multi_select"> - <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save</button> - </t> - <t t-if="multi_select"> - <button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save & New</button> - <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save & Close</button> - </t> - or <a class="oe_button oe_abstractformpopup-form-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a> -</t> -<t t-extend="ListView.row"> - <!-- adds back padding to row being rendered after edition, if necessary - (if not deletable add back padding), otherwise the row being added is - missing columns - --> - <t t-jquery="> :last" t-operation="after"> - <td t-if="edited and !options.deletable" class="oe-listview-padding"/> - </t> -</t> <t t-name="view_editor"> <table class="oe_view_editor"> @@ -1569,6 +1565,7 @@ <t t-name="vieweditor_boolean"> <input type="checkbox" t-att-id="widget.name"/> </t> + <t t-name="ExportView"> <a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a> </t> diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 5a7c1b84067..5830cb33e0f 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -1,3 +1,4 @@ +@charset "utf-8"; .openerp .oe_kanban_view { background: url(/web/static/src/img/form_sheetbg.png); height: inherit; @@ -49,7 +50,7 @@ .openerp .oe_kanban_view .oe_kanban_group_title { font-size: 16px; font-weight: bold; - min-height: 30px; + min-height: 32px; color: #333333; text-shadow: 0 1px 0 white; } @@ -359,6 +360,9 @@ .openerp .oe_kanban_view .oe_kanban_card .oe_dropdown_kanban { margin-top: 4px; } +.openerp .oe_kanban_view .oe_kanban_card .oe_dropdown_kanban .oe_kanban_project_times li { + float: left; +} .openerp .oe_kanban_view .oe_kanban_star { float: left; position: inline-block; @@ -401,9 +405,6 @@ position: relative; top: 2px; } -.openerp .oe_kanban_view .oe_kanban_project_times li { - float: left; -} .openerp .oe_kanban_view .oe_kanban_status { position: relative; top: 4px; @@ -471,30 +472,25 @@ visibility: hidden; } .openerp .oe_kanban_view .oe_kanban_colorpicker { - padding: 3px 6px; white-space: nowrap; } .openerp .oe_kanban_view .oe_kanban_colorpicker li { float: left; + margin: 0; + padding: 0; } .openerp .oe_kanban_view .oe_kanban_colorpicker li a { display: inline-block; - width: 18px; - height: 18px; + width: 16px; + height: 16px; border: 1px solid white; } .openerp .oe_kanban_view .oe_kanban_colorpicker li a:hover { border: 1px solid gray !important; } .openerp .oe_kanban_view .oe_kanban_colorpicker li:first-child a { - margin-top: 1px; - height: 16px; border: 1px solid #cccccc; } -.openerp .oe_kanban_view .oe_kanban_colorpicker li:first-child a:hover { - margin-top: 0px; - height: 18px; -} .openerp .oe_kanban_view .oe_kanban_color_0 { background-color: white; } @@ -530,3 +526,44 @@ padding: 0px; background: white; } + +.openerp .oe_popup_form .oe_kanban_buttons .oe_highlight { + color: #404040; + background: none; +} +.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight { + background-color: #efefef; + background-image: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)); + background-image: -webkit-linear-gradient(top, #efefef, #d8d8d8); + background-image: -moz-linear-gradient(top, #efefef, #d8d8d8); + background-image: -ms-linear-gradient(top, #efefef, #d8d8d8); + background-image: -o-linear-gradient(top, #efefef, #d8d8d8); + background-image: linear-gradient(to bottom, #efefef, #d8d8d8); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; +} +.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight:active { + background-color: #e3e3e3; + background-image: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f6f6f6)); + background-image: -webkit-linear-gradient(top, #e3e3e3, #f6f6f6); + background-image: -moz-linear-gradient(top, #e3e3e3, #f6f6f6); + background-image: -ms-linear-gradient(top, #e3e3e3, #f6f6f6); + background-image: -o-linear-gradient(top, #e3e3e3, #f6f6f6); + background-image: linear-gradient(to bottom, #e3e3e3, #f6f6f6); + -moz-box-shadow: none; + -webkit-box-shadow: none; + -box-shadow: none; +} +.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight:hover { + background-color: #f6f6f6; + background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); + background-image: -webkit-linear-gradient(top, #f6f6f6, #e3e3e3); + background-image: -moz-linear-gradient(top, #f6f6f6, #e3e3e3); + background-image: -ms-linear-gradient(top, #f6f6f6, #e3e3e3); + background-image: -o-linear-gradient(top, #f6f6f6, #e3e3e3); + background-image: linear-gradient(to bottom, #f6f6f6, #e3e3e3); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; +} diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index cea95f2ce53..44b3251c8fb 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -1,6 +1,15 @@ @charset "utf-8" // Mixins {{{ +@mixin vertical-gradient($startColor: #555, $endColor: #333) + background-color: $startColor + background-image: -webkit-gradient(linear, left top, left bottom, from($startColor), to($endColor)) /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient(top, $startColor, $endColor) /* Chrome 10+, Saf5.1+, iOS 5+ */ + background-image: -moz-linear-gradient(top, $startColor, $endColor) /* FF3.6 */ + background-image: -ms-linear-gradient(top, $startColor, $endColor) /* IE10 */ + background-image: -o-linear-gradient(top, $startColor, $endColor) /* Opera 11.10+ */ + background-image: linear-gradient(to bottom, $startColor, $endColor) + @mixin radial-gradient($gradient) background-position: center center background-image: -webkit-radial-gradient(circle, $gradient) @@ -64,7 +73,7 @@ .oe_kanban_group_title font-size: 16px font-weight: bold - min-height: 30px + min-height: 32px color: #333333 text-shadow: 0 1px 0 white > span @@ -307,6 +316,10 @@ text-decoration: none .oe_dropdown_kanban margin-top: 4px + .oe_kanban_project_times + li + float: left + .oe_kanban_star float: left position: inline-block @@ -337,9 +350,6 @@ position: relative top: 2px - .oe_kanban_project_times li - float: left - .oe_kanban_status position: relative top: 4px @@ -387,24 +397,20 @@ // }}} // KanbanColorPicker {{{ .oe_kanban_colorpicker - padding: 3px 6px white-space: nowrap .oe_kanban_colorpicker li float: left + margin: 0 + padding: 0 a display: inline-block - width: 18px - height: 18px + width: 16px + height: 16px border: 1px solid white a:hover border: 1px solid gray !important .oe_kanban_colorpicker li:first-child a - margin-top: 1px - height: 16px border: 1px solid #ccc - &:hover - margin-top: 0px - height: 18px // }}} // KanbanColors {{{ .oe_kanban_color_0 @@ -442,5 +448,22 @@ padding: 0px background: #ffffff +.openerp + .oe_popup_form + .oe_kanban_buttons + .oe_highlight + color: #404040 + background: none + button.oe_highlight + @include vertical-gradient(#efefef, #d8d8d8) + @include box-shadow((0 1px 2px rgba(0, 0, 0, .1), 0 1px 1px rgba(255, 255, 255, .8) inset)) + button.oe_highlight:active + @include vertical-gradient(#e3e3e3, #f6f6f6) + @include box-shadow(none) + button.oe_highlight:hover + @include vertical-gradient(#f6f6f6, #e3e3e3) + @include box-shadow((0 1px 2px rgba(0, 0, 0, .1), 0 1px 1px rgba(255, 255, 255, .8) inset)) + + // au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css" // vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker: diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 5a22b9e5ba5..cd12953adcd 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -420,6 +420,15 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({ self.quick.appendTo($(".oe_kanban_group_list_header", self.$records)); self.quick.focus(); }); + // Add bounce effect on image '+' of kanban header when click on empty space of kanban grouped column. + var add_btn = this.$element.find('.oe_kanban_add'); + this.$records.click(function (ev) { + if (ev.target == ev.currentTarget) { + if (!self.state.folded) { + add_btn.wrap('<div>').addClass('oe_bounce'); + } + } + }); this.$records.find('.oe_kanban_show_more').click(this.do_show_more); if (this.state.folded) { this.do_toggle_fold(); diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml index 7eb453371b2..820189c7b27 100644 --- a/addons/web_kanban/static/src/xml/web_kanban.xml +++ b/addons/web_kanban/static/src/xml/web_kanban.xml @@ -13,7 +13,7 @@ <div t-name="KanbanView.buttons" class="oe_kanban_buttons"> <t t-if="widget.options.action_buttons !== false"> <t t-if="widget._is_create_enabled()"> - <button type="button" class="oe_button oe_kanban_button_new oe_highlight oe_form_button_hi"> + <button type="button" class="oe_kanban_button_new oe_highlight"> <t t-esc="widget.options.create_text || _t('Create')"/> </button> </t> diff --git a/addons/web_process/i18n/nb.po b/addons/web_process/i18n/nb.po index 021bbfbf3f4..977d690db7d 100644 --- a/addons/web_process/i18n/nb.po +++ b/addons/web_process/i18n/nb.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "POT-Creation-Date: 2012-07-02 09:06+0200\n" -"PO-Revision-Date: 2012-03-29 11:39+0000\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2012-07-24 06:25+0000\n" +"Last-Translator: Tor Syversen <sol-moe@online.no>\n" "Language-Team: Norwegian Bokmal <nb@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-07-03 05:55+0000\n" -"X-Generator: Launchpad (build 15531)\n" +"X-Launchpad-Export-Date: 2012-07-25 04:52+0000\n" +"X-Generator: Launchpad (build 15679)\n" #. openerp-web #: addons/web_process/static/src/js/process.js:261 @@ -85,12 +85,12 @@ msgstr "Notater:" #. openerp-web #: addons/web_process/static/src/xml/web_process.xml:59 msgid "Last modified by:" -msgstr "" +msgstr "Sist revidert av:" #. openerp-web #: addons/web_process/static/src/xml/web_process.xml:59 msgid "N/A" -msgstr "" +msgstr "N/A" #. openerp-web #: addons/web_process/static/src/xml/web_process.xml:62 @@ -105,7 +105,7 @@ msgstr "" #. openerp-web #: addons/web_process/static/src/xml/web_process.xml:88 msgid "Select Process" -msgstr "" +msgstr "Velg prosess" #. openerp-web #: addons/web_process/static/src/xml/web_process.xml:98 @@ -115,4 +115,4 @@ msgstr "Velg" #. openerp-web #: addons/web_process/static/src/xml/web_process.xml:109 msgid "Edit Process" -msgstr "" +msgstr "Rediger prosess" diff --git a/doc/form-notes.rst b/doc/form-notes.rst index fc450a336e1..98d4a4de67e 100644 --- a/doc/form-notes.rst +++ b/doc/form-notes.rst @@ -47,3 +47,9 @@ Undocumented stuff * What is the difference between ``readonly`` and ``effective_readonly``? + +* No facilities for DOM events handling/delegations e.g. handling + keyup/keydown/keypress from a form fields into the form's user. + + * Also no way to reverse from a DOM node (e.g. DOMEvent#target) back to a + form view field easily diff --git a/doc/list-view.rst b/doc/list-view.rst index 0d67c27f963..83925d82f46 100644 --- a/doc/list-view.rst +++ b/doc/list-view.rst @@ -87,34 +87,37 @@ List view edition is an extension to the base listview providing the capability of inline record edition by delegating to an embedded form view. -.. todo:: - - cleanup options and settings for editability configuration. Right - now there are: - - ``defaults.editable`` +Editability status +++++++++++++++++++ - ``null``, ``"top"`` or ``"bottom"``, generally broken and - useless +The editability status of a list view can be queried through the +:js:func:`~openerp.web.ListView.editable` method, will return a falsy +value if the listview is not currently editable. - ``context.set_editable`` +The editability status is based on three flags: - forces ``options.editable`` to ``"bottom"`` +``tree/@editable`` - ``view.arch.attrs.editable`` + If present, can be either ``"top"`` or ``"bottom"``. Either will + make the list view editable, with new records being respectively + created at the top or at the bottom of the view. - same as ``defaults.editable``, but applied separately (after - reloading the view), if absent delegates to - ``options.editable`` which may have been set previously. +``context.set_editable`` - ``options.read_only`` + Boolean flag extracted from a search context (during the + :js:func:`~openerp.web.ListView.do_search`` handler), ``true`` + will make the view editable (from the top), ``false`` or the + absence of the flag is a noop. - force options.editable to false, or something? +``defaults.editable`` - .. note:: can probably be replaced by cancelling ``edit:before`` + Like ``tree/@editable``, one of absent (``null``)), ``"top"`` or + ``"bottom"``, fallback for the list view if none of the previous + two flags are set. - and :js:func:`~openerp.web.ListView.set_editable` which - ultimately behaves weird-as-fuck-ly. +These three flags can only *make* a listview editable, they can *not* +override a previously set flag. To do that, a listview user should +instead cancel :ref:`the edit:before event <listview-edit-before>`. The editable list view module adds a number of methods to the list view, on top of implementing the :js:class:`EditorDelegate` protocol: @@ -219,6 +222,14 @@ view provides a number of dedicated events to its lifecycle. abort its current behavior as soon as possible, and rollback any state modification. + Generally speaking, an event should only be cancelled (by + setting the ``cancel`` flag to ``true``), uncancelling an + event is undefined as event handlers are executed on a + first-come-first-serve basis and later handlers may + re-cancel an uncancelled event. + +.. _listview-edit-before: + ``edit:before`` *cancellable* Invoked before the list view starts editing a record. |
