diff --git a/setup/web_responsive/odoo/addons/web_responsive b/setup/web_responsive/odoo/addons/web_responsive new file mode 120000 index 000000000..a084a42d2 --- /dev/null +++ b/setup/web_responsive/odoo/addons/web_responsive @@ -0,0 +1 @@ +../../../../web_responsive \ No newline at end of file diff --git a/setup/web_responsive/setup.py b/setup/web_responsive/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/web_responsive/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_responsive/README.rst b/web_responsive/README.rst new file mode 100644 index 000000000..c7015f43e --- /dev/null +++ b/web_responsive/README.rst @@ -0,0 +1,207 @@ +============== +Web Responsive +============== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/14.0/web_responsive + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_responsive + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/162/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds responsiveness to web backend. + +Features for all devices: + +* New navigation with an app drawer + + .. image:: https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif + +* Quick menu search from the app drawer + + .. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif + +Features for mobile: + +* App-specific submenus are shown on full screen when toggling them from the + "hamburger" menu + + .. image:: https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif + +* View type picker dropdown displays confortably + + .. image:: https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif + +* Top app bar is always visible, but the control panel is hidden when + scrolling down, to save some vaulable vertical space + + .. image:: https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif + +* Form status bar action and status buttons are collapsed in dropdowns. + Other control panel buttons use icons to save space. + + .. image:: https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif + +* Breadcrumbs navigation is collapsed with a "back arrow" button. + + .. image:: https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif + +* Search panel is hidden on small screens. + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/search_panel.gif + +Features for computers: + +* Keyboard shortcuts for easier navigation, **using ``Alt + Shift + [key]``** + combination instead of just ``Alt + [key]``. + See https://github.com/odoo/odoo/issues/30068 to understand why. + + .. image:: https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png + + +* Autofocus on search menu box when opening the drawer + + .. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif + +* Set chatter on the side of the screen, optional per user + + .. image:: https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif + +* Full width form sheets + + .. image:: https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png + +* Sticky chatter topbar + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/chatter_topbar.gif + +* AppMenu waits for action finished to show the view + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/appmenu.gif + +* Sticky header & footer in list view + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/listview.gif + +* Sticky statusbar in form view + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/formview.gif + +* Followers and send button is displayed on mobile. Avatar is hidden. + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/chatter.gif + +* When the chatter is configured on the side part, the document viewer fills that + part for side-by-side reading instead of full screen. You can still put it on full + width preview clicking on the new maximize button. + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/document_viewer.gif + +* Bigger checkboxes in list view + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/big_checkboxes.gif + +* Scrollable dropdowns + + .. image:: https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/dropdown_scroll.gif + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +The following keyboard shortcuts are implemented: + +* Navigate app search results - Arrow keys +* Choose app result - ``Enter`` +* ``Esc`` to close app drawer + +Known issues / Roadmap +====================== + +* To view the full experience in a device, the page must be loaded with the + device screen size. This means that, if you change the size of your browser, + you should reload the web client to get the full experience for that + new size. This is Odoo's own limitation. +* Kanban mobile/desktop mode switch on screen resize. F.x. when rotating a device + to landscape orientation. +* App navigation with keyboard. +* Handle long titles on forms in a better way + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* LasLabs +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* Dave Lasley +* Jairo Llopis +* Dennis Sluijk +* Sergio Teruel +* Alexandre Díaz +* Mathias Markl +* Iván Todorovich +* Sergey Shebanin + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-Yajo| image:: https://github.com/Yajo.png?size=40px + :target: https://github.com/Yajo + :alt: Yajo +.. |maintainer-Tardo| image:: https://github.com/Tardo.png?size=40px + :target: https://github.com/Tardo + :alt: Tardo + +Current `maintainers `__: + +|maintainer-Yajo| |maintainer-Tardo| + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_responsive/__init__.py b/web_responsive/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/web_responsive/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_responsive/__manifest__.py b/web_responsive/__manifest__.py new file mode 100644 index 000000000..10919c198 --- /dev/null +++ b/web_responsive/__manifest__.py @@ -0,0 +1,30 @@ +# Copyright 2016-2017 LasLabs Inc. +# Copyright 2017-2018 Tecnativa - Jairo Llopis +# Copyright 2018-2019 Tecnativa - Alexandre Díaz +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Web Responsive", + "summary": "Responsive web client, community-supported", + "version": "14.0.1.0.0", + "category": "Website", + "website": "https://github.com/OCA/web", + "author": "LasLabs, Tecnativa, " "Odoo Community Association (OCA)", + "license": "LGPL-3", + "installable": True, + "depends": ["web", "mail"], + "development_status": "Production/Stable", + "maintainers": ["Yajo", "Tardo"], + "data": ["views/assets.xml", "views/res_users.xml", "views/web.xml"], + "qweb": [ + "static/src/xml/apps.xml", + "static/src/xml/form_buttons.xml", + "static/src/xml/menu.xml", + "static/src/xml/navbar.xml", + "static/src/xml/attachment_viewer.xml", + "static/src/xml/discuss.xml", + "static/src/xml/control_panel.xml", + "static/src/xml/search_panel.xml", + ], + "sequence": 1, +} diff --git a/web_responsive/i18n/ar.po b/web_responsive/i18n/ar.po new file mode 100644 index 000000000..a936b52fa --- /dev/null +++ b/web_responsive/i18n/ar.po @@ -0,0 +1,140 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-07 15:08+0000\n" +"Last-Translator: Waleed Mohsen \n" +"Language-Team: none\n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "موقع الدردشة" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "إغلاق" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "إنشاء" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "تجاهل" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "تعديل" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "تكبير" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "تصغير" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "عادي" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "اجراءات سريعة" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "حفظ" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "بحث في القوائم..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "جانبي" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "المستخدمون" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "false" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" +"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" diff --git a/web_responsive/i18n/ca.po b/web_responsive/i18n/ca.po new file mode 100644 index 000000000..cd0f1d88a --- /dev/null +++ b/web_responsive/i18n/ca.po @@ -0,0 +1,137 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-02-02 22:13+0000\n" +"Last-Translator: eduardgm \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Posició del chatter" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "Tancar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Crear" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Editar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximitzar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimitzar" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "Normal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Accions ràpides" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Guardar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Cercar menús..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Lateral" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Usuaris" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "fals" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" diff --git a/web_responsive/i18n/da.po b/web_responsive/i18n/da.po new file mode 100644 index 000000000..88f0cc9eb --- /dev/null +++ b/web_responsive/i18n/da.po @@ -0,0 +1,155 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-09-02 05:11+0000\n" +"Last-Translator: Hans Henrik Gabelgaard \n" +"Language-Team: none\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.1.1\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Log position" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Side" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Brugere" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" + +#~ msgid "Toggle App Drawer" +#~ msgstr "Skift App skuffe" + +#~ msgid "Toggle Navigation" +#~ msgstr "Skift navigation" + +#~ msgid "Apps" +#~ msgstr "Applikationer" + +#~ msgid "More" +#~ msgstr "Mere" + +#~ msgid "More " +#~ msgstr "Mere " + +#~ msgid "Task" +#~ msgstr "Opgave" diff --git a/web_responsive/i18n/de.po b/web_responsive/i18n/de.po new file mode 100644 index 000000000..71908de37 --- /dev/null +++ b/web_responsive/i18n/de.po @@ -0,0 +1,152 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Niki Waibel , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-02-03 01:37+0000\n" +"PO-Revision-Date: 2021-02-18 15:45+0000\n" +"Last-Translator: Janik Vonrotz \n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Chatter-Position" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "Schließen" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Erstellen" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Verwerfen" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Ändern" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "maximieren" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "minimieren" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "normal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Schnell-Aktion" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Speichern" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Such-Menü" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Seitlich" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Benutzer" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" + +#~ msgid "Toggle App Drawer" +#~ msgstr "App Ordner umschalten" + +#~ msgid "Toggle Navigation" +#~ msgstr "Navigation umschalten" + +#~ msgid "Apps" +#~ msgstr "Apps" + +#~ msgid "More " +#~ msgstr "Mehr " diff --git a/web_responsive/i18n/es.po b/web_responsive/i18n/es.po new file mode 100644 index 000000000..c86799469 --- /dev/null +++ b/web_responsive/i18n/es.po @@ -0,0 +1,141 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Pedro M. Baeza , 2016 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-10 10:49+0000\n" +"PO-Revision-Date: 2021-02-17 14:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Posición del chatter" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "Cerrar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Crear" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Editar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximizar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimizar" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "Normal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Acciones rápidas" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Guardar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Buscar menús..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "Turno" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Lateral" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Usuarios" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "falso" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" diff --git a/web_responsive/i18n/fr.po b/web_responsive/i18n/fr.po new file mode 100644 index 000000000..ff04b8c3c --- /dev/null +++ b/web_responsive/i18n/fr.po @@ -0,0 +1,137 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-07-22 12:19+0000\n" +"Last-Translator: c2cdidier \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Position du Chatter" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "Fermer" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Créer" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Annuler" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Editer" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximiser" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimiser" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "Normal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Actions rapides" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Sauvegarder" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Rechercher dans les menus..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "À coté" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Utilisateurs" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" diff --git a/web_responsive/i18n/hr.po b/web_responsive/i18n/hr.po new file mode 100644 index 000000000..f3ac4732e --- /dev/null +++ b/web_responsive/i18n/hr.po @@ -0,0 +1,152 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Bole , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-28 18:03+0000\n" +"PO-Revision-Date: 2017-04-28 18:03+0000\n" +"Last-Translator: Bole , 2017\n" +"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" + +#~ msgid "Toggle App Drawer" +#~ msgstr "Izmjeni izbornik aplikacije" + +#~ msgid "Toggle Navigation" +#~ msgstr "Izmjeni navigaciju" + +#~ msgid "Apps" +#~ msgstr "Apikacije" + +#~ msgid "More " +#~ msgstr "Više " diff --git a/web_responsive/i18n/nl.po b/web_responsive/i18n/nl.po new file mode 100644 index 000000000..c926b62a4 --- /dev/null +++ b/web_responsive/i18n/nl.po @@ -0,0 +1,137 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-11 13:08+0000\n" +"Last-Translator: Dennis Sluijk \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Chatter Positie" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "Sluit" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Aanmaken" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Negeren" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Bewerken" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximaliseren" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimaliseren" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "Normaal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Snelle Acties" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Opslaan" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Zoek menu's..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Aan de zijkant" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Gebruikers" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" diff --git a/web_responsive/i18n/pt.po b/web_responsive/i18n/pt.po new file mode 100644 index 000000000..34cbb7065 --- /dev/null +++ b/web_responsive/i18n/pt.po @@ -0,0 +1,137 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-08-12 11:44+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.7.1\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Posição do Chatter" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Criar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Editar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "Normal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Ações rápidas" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Gravar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Procurar menus..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Lateralizado" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Utilizadores" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" diff --git a/web_responsive/i18n/pt_BR.po b/web_responsive/i18n/pt_BR.po new file mode 100644 index 000000000..5f2aad580 --- /dev/null +++ b/web_responsive/i18n/pt_BR.po @@ -0,0 +1,157 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Rodrigo de Almeida Sottomaior Macedo , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-22 08:27+0000\n" +"PO-Revision-Date: 2020-03-21 21:13+0000\n" +"Last-Translator: Rodrigo Macedo \n" +"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/" +"teams/23907/pt_BR/)\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "Posição do Chatter" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "Fechar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "Criar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "Editar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximizar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimizar" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "Normal" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "Ações rápidas" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "Salvar" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Pesquisar menus..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "Frente e verso" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "Usuários" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "falso" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" +"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" + +#~ msgid "Toggle App Drawer" +#~ msgstr "Aplicativo Desenhador Alternativo" + +#~ msgid "Toggle Navigation" +#~ msgstr "Navegação Alternativa" + +#~ msgid "Apps" +#~ msgstr "Aplicativos" + +#~ msgid "HTTP routing" +#~ msgstr "roteamento HTTP" + +#~ msgid "More " +#~ msgstr "Mais " diff --git a/web_responsive/i18n/web_responsive.pot b/web_responsive/i18n/web_responsive.pot new file mode 100644 index 000000000..84a29138e --- /dev/null +++ b/web_responsive/i18n/web_responsive.pot @@ -0,0 +1,161 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#, python-format +msgid "Edit" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/control_panel.xml:0 +#: code:addons/web_responsive/static/src/xml/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0 +#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0 +#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#, python-format +msgid "Quick actions" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/control_panel.xml:0 +#: code:addons/web_responsive/static/src/xml/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/control_panel.xml:0 +#: code:addons/web_responsive/static/src/xml/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0 +#, python-format +msgid "Today" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/js/kanban_renderer_mobile.js:0 +#, python-format +msgid "Undefined" +msgstr "" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" diff --git a/web_responsive/i18n/zh_CN.po b/web_responsive/i18n/zh_CN.po new file mode 100644 index 000000000..54a44e85f --- /dev/null +++ b/web_responsive/i18n/zh_CN.po @@ -0,0 +1,139 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-07-08 05:19+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#. module: web_responsive +#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position +msgid "Chatter Position" +msgstr "聊天位置" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Close" +msgstr "关闭" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Create" +msgstr "创建" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Discard" +msgstr "丢弃" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Edit" +msgstr "编辑" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "最大化" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "最小化" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal +msgid "Normal" +msgstr "正常" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Quick actions" +msgstr "快捷方式" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/form_view.xml:0 +#, python-format +msgid "Save" +msgstr "保存" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#, python-format +msgid "Search menus..." +msgstr "搜索菜单..." + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/menu.xml:0 +#, python-format +msgid "Shift" +msgstr "" + +#. module: web_responsive +#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided +msgid "Sided" +msgstr "侧面" + +#. module: web_responsive +#: model:ir.model,name:web_responsive.model_res_users +msgid "Users" +msgstr "用户" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/discuss.xml:0 +#, python-format +msgid "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" +msgstr "" +"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/apps.xml:0 +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "false" +msgstr "false" + +#. module: web_responsive +#. openerp-web +#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0 +#, python-format +msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +msgstr "" +"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" diff --git a/web_responsive/models/__init__.py b/web_responsive/models/__init__.py new file mode 100644 index 000000000..883516533 --- /dev/null +++ b/web_responsive/models/__init__.py @@ -0,0 +1 @@ +from . import res_users diff --git a/web_responsive/models/res_users.py b/web_responsive/models/res_users.py new file mode 100644 index 000000000..5247df678 --- /dev/null +++ b/web_responsive/models/res_users.py @@ -0,0 +1,27 @@ +# Copyright 2018-2019 Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + chatter_position = fields.Selection( + [("normal", "Normal"), ("sided", "Sided")], + string="Chatter Position", + default="sided", + ) + + def __init__(self, pool, cr): + """Override of __init__ to add access rights. + Access rights are disabled by default, but allowed on some specific + fields defined in self.SELF_{READ/WRITE}ABLE_FIELDS. + """ + super().__init__(pool, cr) + # duplicate list to avoid modifying the original reference + type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS) + type(self).SELF_WRITEABLE_FIELDS.extend(["chatter_position"]) + # duplicate list to avoid modifying the original reference + type(self).SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS) + type(self).SELF_READABLE_FIELDS.extend(["chatter_position"]) diff --git a/web_responsive/readme/CONTRIBUTORS.rst b/web_responsive/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..ca52594ac --- /dev/null +++ b/web_responsive/readme/CONTRIBUTORS.rst @@ -0,0 +1,8 @@ +* Dave Lasley +* Jairo Llopis +* Dennis Sluijk +* Sergio Teruel +* Alexandre Díaz +* Mathias Markl +* Iván Todorovich +* Sergey Shebanin diff --git a/web_responsive/readme/DESCRIPTION.rst b/web_responsive/readme/DESCRIPTION.rst new file mode 100644 index 000000000..87a1b3dc8 --- /dev/null +++ b/web_responsive/readme/DESCRIPTION.rst @@ -0,0 +1,95 @@ +This module adds responsiveness to web backend. + +Features for all devices: + +* New navigation with an app drawer + + .. image:: https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif + +* Quick menu search from the app drawer + + .. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif + +Features for mobile: + +* App-specific submenus are shown on full screen when toggling them from the + "hamburger" menu + + .. image:: https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif + +* View type picker dropdown displays confortably + + .. image:: https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif + +* Top app bar is always visible, but the control panel is hidden when + scrolling down, to save some vaulable vertical space + + .. image:: https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif + +* Form status bar action and status buttons are collapsed in dropdowns. + Other control panel buttons use icons to save space. + + .. image:: https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif + +* Breadcrumbs navigation is collapsed with a "back arrow" button. + + .. image:: https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif + +* Search panel is hidden on small screens. + + .. image:: ../static/img/search_panel.gif + +Features for computers: + +* Keyboard shortcuts for easier navigation, **using ``Alt + Shift + [key]``** + combination instead of just ``Alt + [key]``. + See https://github.com/odoo/odoo/issues/30068 to understand why. + + .. image:: https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png + + +* Autofocus on search menu box when opening the drawer + + .. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif + +* Set chatter on the side of the screen, optional per user + + .. image:: https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif + +* Full width form sheets + + .. image:: https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png + +* Sticky chatter topbar + + .. image:: ../static/img/chatter_topbar.gif + +* AppMenu waits for action finished to show the view + + .. image:: ../static/img/appmenu.gif + +* Sticky header & footer in list view + + .. image:: ../static/img/listview.gif + +* Sticky statusbar in form view + + .. image:: ../static/img/formview.gif + +* Followers and send button is displayed on mobile. Avatar is hidden. + + .. image:: ../static/img/chatter.gif + +* When the chatter is configured on the side part, the document viewer fills that + part for side-by-side reading instead of full screen. You can still put it on full + width preview clicking on the new maximize button. + + .. image:: ../static/img/document_viewer.gif + +* Bigger checkboxes in list view + + .. image:: ../static/img/big_checkboxes.gif + +* Scrollable dropdowns + + .. image:: ../static/img/dropdown_scroll.gif diff --git a/web_responsive/readme/ROADMAP.rst b/web_responsive/readme/ROADMAP.rst new file mode 100644 index 000000000..389c1ec26 --- /dev/null +++ b/web_responsive/readme/ROADMAP.rst @@ -0,0 +1,7 @@ +* To view the full experience in a device, the page must be loaded with the + device screen size. This means that, if you change the size of your browser, + you should reload the web client to get the full experience for that + new size. This is Odoo's own limitation. +* App navigation with keyboard. +* Handle long titles on forms in a better way +* Standard sticky headers seems to not work properly on iOS Safari/Chrome (see #1626). diff --git a/web_responsive/readme/USAGE.rst b/web_responsive/readme/USAGE.rst new file mode 100644 index 000000000..ef87cbe59 --- /dev/null +++ b/web_responsive/readme/USAGE.rst @@ -0,0 +1,5 @@ +The following keyboard shortcuts are implemented: + +* Navigate app search results - Arrow keys +* Choose app result - ``Enter`` +* ``Esc`` to close app drawer diff --git a/web_responsive/static/description/icon.png b/web_responsive/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/web_responsive/static/description/icon.png differ diff --git a/web_responsive/static/description/index.html b/web_responsive/static/description/index.html new file mode 100644 index 000000000..0efefb318 --- /dev/null +++ b/web_responsive/static/description/index.html @@ -0,0 +1,528 @@ + + + + + + +Web Responsive + + + +
+

Web Responsive

+ + +

Production/Stable License: LGPL-3 OCA/web Translate me on Weblate Try me on Runbot

+

This module adds responsiveness to web backend.

+

Features for all devices:

+
    +
  • New navigation with an app drawer

    +https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif +
  • +
  • Quick menu search from the app drawer

    +https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif +
  • +
+

Features for mobile:

+
    +
  • App-specific submenus are shown on full screen when toggling them from the +“hamburger” menu

    +https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif +
  • +
  • View type picker dropdown displays confortably

    +https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif +
  • +
  • Top app bar is always visible, but the control panel is hidden when +scrolling down, to save some vaulable vertical space

    +https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif +
  • +
  • Form status bar action and status buttons are collapsed in dropdowns. +Other control panel buttons use icons to save space.

    +https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif +
  • +
  • Breadcrumbs navigation is collapsed with a “back arrow” button.

    +https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif +
  • +
  • Search panel is hidden on small screens.

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/search_panel.gif +
  • +
+

Features for computers:

+
    +
  • Keyboard shortcuts for easier navigation, using ``Alt + Shift + [key]`` +combination instead of just Alt + [key]. +See https://github.com/odoo/odoo/issues/30068 to understand why.

    +https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png +
  • +
  • Autofocus on search menu box when opening the drawer

    +https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif +
  • +
  • Set chatter on the side of the screen, optional per user

    +https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif +
  • +
  • Full width form sheets

    +https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png +
  • +
  • Sticky chatter topbar

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/chatter_topbar.gif +
  • +
  • AppMenu waits for action finished to show the view

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/appmenu.gif +
  • +
  • Sticky header & footer in list view

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/listview.gif +
  • +
  • Sticky statusbar in form view

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/formview.gif +
  • +
  • Followers and send button is displayed on mobile. Avatar is hidden.

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/chatter.gif +
  • +
  • When the chatter is configured on the side part, the document viewer fills that +part for side-by-side reading instead of full screen. You can still put it on full +width preview clicking on the new maximize button.

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/document_viewer.gif +
  • +
  • Bigger checkboxes in list view

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/big_checkboxes.gif +
  • +
  • Scrollable dropdowns

    +https://raw.githubusercontent.com/OCA/web/13.0/web_responsive/static/img/dropdown_scroll.gif +
  • +
+

Table of contents

+ +
+

Usage

+

The following keyboard shortcuts are implemented:

+
    +
  • Navigate app search results - Arrow keys
  • +
  • Choose app result - Enter
  • +
  • Esc to close app drawer
  • +
+
+
+

Known issues / Roadmap

+
    +
  • To view the full experience in a device, the page must be loaded with the +device screen size. This means that, if you change the size of your browser, +you should reload the web client to get the full experience for that +new size. This is Odoo’s own limitation.
  • +
  • App navigation with keyboard.
  • +
  • Handle long titles on forms in a better way
  • +
  • Standard sticky headers seems to not work properly on iOS Safari/Chrome (see #1626).
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • LasLabs
  • +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainers:

+

Yajo Tardo

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_responsive/static/img/appmenu.gif b/web_responsive/static/img/appmenu.gif new file mode 100644 index 000000000..411937bc2 Binary files /dev/null and b/web_responsive/static/img/appmenu.gif differ diff --git a/web_responsive/static/img/big_checkboxes.gif b/web_responsive/static/img/big_checkboxes.gif new file mode 100644 index 000000000..a3469203a Binary files /dev/null and b/web_responsive/static/img/big_checkboxes.gif differ diff --git a/web_responsive/static/img/chatter.gif b/web_responsive/static/img/chatter.gif new file mode 100644 index 000000000..0a2af93d2 Binary files /dev/null and b/web_responsive/static/img/chatter.gif differ diff --git a/web_responsive/static/img/chatter_topbar.gif b/web_responsive/static/img/chatter_topbar.gif new file mode 100644 index 000000000..e0522c5a9 Binary files /dev/null and b/web_responsive/static/img/chatter_topbar.gif differ diff --git a/web_responsive/static/img/document_viewer.gif b/web_responsive/static/img/document_viewer.gif new file mode 100644 index 000000000..70b0cb864 Binary files /dev/null and b/web_responsive/static/img/document_viewer.gif differ diff --git a/web_responsive/static/img/dropdown_scroll.gif b/web_responsive/static/img/dropdown_scroll.gif new file mode 100644 index 000000000..9f3b6c092 Binary files /dev/null and b/web_responsive/static/img/dropdown_scroll.gif differ diff --git a/web_responsive/static/img/formview.gif b/web_responsive/static/img/formview.gif new file mode 100644 index 000000000..688bbc9f9 Binary files /dev/null and b/web_responsive/static/img/formview.gif differ diff --git a/web_responsive/static/img/listview.gif b/web_responsive/static/img/listview.gif new file mode 100644 index 000000000..ebdcac8a9 Binary files /dev/null and b/web_responsive/static/img/listview.gif differ diff --git a/web_responsive/static/img/search_panel.gif b/web_responsive/static/img/search_panel.gif new file mode 100644 index 000000000..17bef476e Binary files /dev/null and b/web_responsive/static/img/search_panel.gif differ diff --git a/web_responsive/static/src/css/kanban_view_mobile.scss b/web_responsive/static/src/css/kanban_view_mobile.scss new file mode 100644 index 000000000..76d86d09d --- /dev/null +++ b/web_responsive/static/src/css/kanban_view_mobile.scss @@ -0,0 +1,97 @@ +@include media-breakpoint-down(sm) { + .o_kanban_view.o_kanban_grouped { + display: block; + position: relative; + overflow-x: hidden; + &.o_renderer_with_searchpanel { + width: 100%; + } + + .o_kanban_mobile_tabs_container { + position: sticky; + display: flex; + justify-content: space-between; + width: 100%; + top: 0; + z-index: 1; + background-color: #5e5e5e; + + .o_kanban_mobile_add_column { + height: $o-kanban-mobile-tabs-height; + padding: 10px; + border-left: grey 1px solid; + color: white; + font-size: 14px; + } + + .o_kanban_mobile_tabs { + position: relative; + display: flex; + width: 100%; + height: $o-kanban-mobile-tabs-height; + overflow-x: auto; + + .o_kanban_mobile_tab { + height: $o-kanban-mobile-tabs-height; + padding: 10px 20px; + font-size: 14px; + color: white; + + &.o_current { + font-weight: bold; + border-bottom: 3px solid $o-brand-primary; + } + + .o_column_title { + white-space: nowrap; + text-transform: uppercase; + } + } + } + } + .o_kanban_columns_content { + position: relative; + } + // [class] to get same specificity as elsewhere (kanban_view.less) + &[class] .o_kanban_group:not(.o_column_folded) { + @include o-position-absolute( + $top: $o-kanban-mobile-tabs-height, + $left: 0, + $bottom: 0 + ); + width: 100%; + padding: 0; + margin-left: 0; // override the margin-left: -1px of the desktop mode + border: none; + + &.o_current { + position: inherit; + top: 0; + + &.o_kanban_no_records { + // set a default height for clarity when embedded in another view + min-height: $o-kanban-mobile-empty-height; + } + } + + .o_kanban_header { + display: none; + } + .o_kanban_record, + .o_kanban_quick_create { + border: none; + border-bottom: 1px solid lightgray; + padding: 10px 16px; + margin: 0; + } + } + } + .o_kanban_view .o_column_quick_create { + .o_quick_create_folded { + display: none !important; + } + .o_quick_create_unfolded { + width: 100%; + } + } +} diff --git a/web_responsive/static/src/css/search_view_mobile.scss b/web_responsive/static/src/css/search_view_mobile.scss new file mode 100644 index 000000000..06762e4b0 --- /dev/null +++ b/web_responsive/static/src/css/search_view_mobile.scss @@ -0,0 +1,109 @@ +.o_web_client { + .o_mobile_search { + position: fixed; + top: 0; + left: 0; + bottom: 0; + padding: 0; + width: 100%; + background-color: white; + z-index: $zindex-modal; + overflow: auto; + .o_mobile_search_header { + height: 46px; + margin-bottom: 10px; + width: 100%; + background-color: $o-brand-odoo; + color: white; + span:active { + background-color: darken($o-brand-primary, 10%); + } + span { + cursor: pointer; + } + } + .o_searchview_input_container { + display: flex; + padding: 15px 20px 0 20px; + position: relative; + .o_searchview_input { + width: 100%; + margin-bottom: 15px; + border-bottom: 1px solid $o-brand-secondary; + } + .o_searchview_facet { + border-radius: 10px; + display: inline-flex; + order: 1; + .o_searchview_facet_label { + border-radius: 2em 0em 0em 2em; + } + } + .o_searchview_autocomplete { + top: 100%; + > li { + margin: 5px 0px; + } + } + } + .o_mobile_search_filter { + padding-bottom: 15%; + .o_dropdown { + width: 100%; + margin: 15px 5px 0px 5px; + border: solid 1px darken(gray("200"), 20%); + } + .o_dropdown_toggler_btn { + width: 100%; + text-align: left; + + &:after { + display: none; + } + } + + // We disable the backdrop in this case because it prevents any + // interaction outside of a dropdown while it is open. + .dropdown-backdrop { + z-index: -1; + } + .dropdown-menu { + // Here we use !important because of popper js adding custom style + // to element so to override it use !important + position: relative !important; + width: 100% !important; + transform: translate3d(0, 0, 0) !important; + box-shadow: none; + border: none; + color: gray("600"); + .divider { + margin: 0px; + } + > li > a { + padding: 10px 26px; + } + } + } + .o_mobile_search_show_result { + padding: 10px; + font-size: 15px; + } + } +} +// Search panel +@include media-breakpoint-down(sm) { + .o_controller_with_searchpanel { + display: block; + .o_search_panel { + height: auto; + padding: 8px; + border-left: 1px solid $gray-300; + section { + padding: 0px 16px; + } + } + .o_search_panel_summary { + cursor: pointer; + } + } +} diff --git a/web_responsive/static/src/css/web_responsive.scss b/web_responsive/static/src/css/web_responsive.scss new file mode 100644 index 000000000..a1a7d332a --- /dev/null +++ b/web_responsive/static/src/css/web_responsive.scss @@ -0,0 +1,918 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$chatter_zone_width: 35%; + +@mixin full-screen-dropdown { + border: none; + box-shadow: none; + display: flex; + flex-direction: column; + height: calc(100vh - #{$o-navbar-height}); + position: fixed; + margin: 0; + width: 100vw; + z-index: 100; + // Inline style will override our `top`, so we need !important here + top: $o-navbar-height !important; + transform: none !important; +} + +// Support for long titles +@include media-breakpoint-up(md) { + .o_form_view .oe_button_box + .oe_title, + .o_form_view .oe_button_box + .oe_avatar + .oe_title { + /* Button-box has a hardcoded width of 132px per button and have three columns */ + width: calc(100% - 450px); + } +} + +// Main navbar (with apps menu, user menu, debug menu...) +@include media-breakpoint-down(sm) { + .o_main_navbar { + // This allows to have a sane layout for mobiles + display: flex; + + // Remove clutter to only have small icons that fit in a small screen + > .dropdown { + display: flex; + + .navbar-toggler { + color: gray("white"); + } + + .o_menu_sections, + .o_menu_systray { + padding: 0; + } + } + + // Whitespace before systray icons + .o_menu_systray { + margin-left: auto; + } + + // Hide big things + .o_menu_brand, + .o_menu_sections, + .oe_topbar_name { + display: none; + } + + // Fix toggler button padding + .o-menu-toggle { + cursor: pointer; + padding: 0 $o-horizontal-padding; + } + + // Custom fullscreen layout when showing submenus + .o_menu_sections.show { + @include full-screen-dropdown(); + background-color: $dropdown-bg; + overflow: auto; + + .show { + display: flex; + flex-direction: column; + + .dropdown-menu { + margin-left: 1rem; + min-width: auto; + width: calc(100vw - 2rem); + } + } + + > li, + .o_menu_entry_lvl_1, + .o_menu_header_lvl_1 { + // Homogeneous background color + background-color: $dropdown-bg; + color: $dropdown-link-color; + + &:hover { + background-color: $dropdown-link-hover-bg; + color: $dropdown-link-hover-color; + } + + // Disable the .o-no-caret class effect, to display the caret + &.o-no-caret::after { + content: ""; + } + + // Fix a strange glitch leaving headers invisible + .dropdown-header { + color: $dropdown-header-color; + } + } + } + + // Custom fullscreen layout for systray items + .o_mail_systray_dropdown.show { + @include full-screen-dropdown(); + + // Fix stretchy images + .o_mail_preview_image { + align-items: center; + display: flex; + flex-direction: row; + + img { + display: block; + height: auto; + } + } + } + + // Higher height for dropdown items, for those with sausage fingers + .dropdown-menu .dropdown-item { + padding: { + bottom: 0.5rem; + top: 0.5rem; + } + } + } +} +.o_main_navbar { + color: color-yiq($o-brand-odoo); + + > ul > li > a, + > ul > li > label { + color: color-yiq($o-brand-odoo); + } + .dropdown-menu.show { + max-height: calc(100vh - #{$o-navbar-height}); + } +} +// Iconized full screen apps menu +.o_menu_apps { + user-select: none; + + a.full { + width: $o-navbar-height; + text-align: center; + } + + .dropdown-menu.show { + opacity: 1; + visibility: visible; + } + + .dropdown-menu { + @include full-screen-dropdown(); + + opacity: 0; + visibility: hidden; + transition: visibility 100ms ease, opacity 100ms ease; + background: url("../img/home-menu-bg-overlay.svg"), + linear-gradient( + to bottom, + $o-brand-odoo, + desaturate(lighten($o-brand-odoo, 20%), 15) + ); + background-size: cover; + border-radius: 0; + // Display apps in a grid + align-content: flex-start; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + + @include media-breakpoint-up(lg) { + padding: { + left: calc((100vw - 850px) / 2); + right: calc((100vw - 850px) / 2); + } + } + + .o_app { + align-items: center; + display: flex; + padding: 10px 0; + border-radius: 4px; + flex-direction: column; + justify-content: flex-start; + background: none; + transition: 300ms ease; + transition-property: background-color; + + img { + box-shadow: none; + transition: 300ms ease; + transition-property: box-shadow, transform; + } + + &:focus { + background-color: rgba(gray("white"), 0.05); + } + + // Size depends on screen + width: 33.33333333%; + @include media-breakpoint-up(sm) { + width: 25%; + } + @include media-breakpoint-up(md) { + width: 16.6666666%; + } + } + + .o_app:hover img { + transform: translateY(-3px); + box-shadow: 0 9px 12px -4px rgba(gray("black"), 0.3); + } + + // Hide app icons when searching + .has-results ~ .o_app { + display: none; + } + + .o-app-icon { + height: auto; + max-width: 6rem; + } + + .o-app-name { + color: gray("white"); + margin-top: 4px; + font-size: 1.25rem; + text-shadow: 1px 1px 1px rgba(gray("black"), 0.4); + } + // Search input for menus + .form-row { + width: 100%; + } + + .o-menu-search-result { + align-items: center; + background-position: left; + background-repeat: no-repeat; + background-size: contain; + cursor: pointer; + padding-left: 3rem; + white-space: normal; + } + + .search-container { + padding-top: 1rem; + padding-bottom: 1.5rem; + + .search-input { + margin-bottom: 0 !important; + padding: 0; + + .input-group { + box-shadow: inset 0 1px 0 rgba(gray("white"), 0.1), + 0 1px 0 rgba(gray("black"), 0.1); + text-shadow: 0 1px 0 rgba(gray("black"), 0.5); + border-radius: 4px; + padding: 0.4rem 0.8rem; + background-color: rgba(gray("white"), 0.1); + + @include media-breakpoint-up(md) { + padding: 0.8rem 1.2rem; + } + + .input-group-prepend { + span.fa { + color: gray("white"); + font-size: 1.5rem; + margin-right: 1rem; + padding-top: 1px; + } + } + + .form-control { + height: 2rem; + background: none; + border: none; + color: gray("white"); + display: block; + padding: 1px 2px 2px 2px; + box-shadow: none; + + &::placeholder { + color: gray("white"); + opacity: 0.5; + } + } + } + } + } + // Allow to scroll only on results, keeping static search box above + .search-container.has-results { + height: 100%; + .search-results { + max-height: calc(100vh - 47px - 6em); + overflow-y: hidden; + overflow-x: scroll; + overflow: auto; + background: url("../img/home-menu-bg-overlay.svg"), + linear-gradient(to bottom, gray("200"), gray("white")); + background-position: center; + background-size: cover; + } + } + } +} + +// Scroll all but top bar +html .o_web_client .o_action_manager .o_action { + @include media-breakpoint-down(sm) { + overflow: auto; + + .o_content { + overflow: visible; + } + } + + max-width: 100%; +} + +// Make enough space for search panel filters buttons +.o_control_panel { + // There is no media breakpoint for XL upper bound + @include media-breakpoint-up(lg) { + @media (max-width: 1360px) { + .o_cp_top_left, + .o_cp_bottom_left { + width: 40%; + } + .o_cp_top_right, + .o_cp_bottom_right { + width: 60%; + } + } + } + // For FULL HD devices + @media (min-width: 1900px) { + .o_cp_top_left, + .o_cp_bottom_left { + width: 60%; + } + .o_cp_top_right, + .o_cp_bottom_right { + width: 40%; + } + } + @include media-breakpoint-only(md) { + .o_search_options_hide_labels .o_dropdown_title { + display: none; + } + } + .o_cp_bottom_right { + height: 30px; + } +} + +// Mobile Control panel (breadcrumbs, search box, buttons...) +@include media-breakpoint-down(sm) { + .o_control_panel { + // Avoid horizontal scrolling of control panel. + // It doesn't work on iOS Safari, but it looks similar as + // without this patch. With this patch it looks better for + // other browsers. + position: sticky; + left: 0; + z-index: 3; + + // Arrange buttons to use space better + .o_cp_top_left, + .o_cp_top_right { + flex: 1 1 100%; + } + + .o_cp_top_left { + flex-basis: 80%; + } + + .o_cp_top_right { + flex-basis: 20%; + } + + .o_cp_bottom { + position: relative; // Necessary for dropdown menu positioning + display: block; + margin: 0; + } + + .o_cp_bottom_left { + float: left; + margin: 5px 0; + } + + .o_cp_bottom_right { + float: right; + height: 30px; + padding-left: 10px; + margin: 5px 0; + } + + .o_cp_bottom_right, + .o_cp_pager { + white-space: nowrap; + } + .o_cp_pager { + margin-bottom: 0; + } + + .o_cp_bottom_left > .o_cp_action_menus { + padding-right: 0; + .o_dropdown_title, + .fa-chevron-right, + .fa-chevron-down { + display: none; + } + .o_dropdown_toggler_btn { + margin: 0px 2px; + } + @include media-breakpoint-down(xs) { + .o_dropdown { + position: static; + } + .dropdown-menu { + right: 0; + left: 0; + top: 35px; + } + } + } + + // Hide all but 2 last breadcrumbs, and render 2nd-to-last as arrow + .breadcrumb-item { + &:not(.active) { + padding-left: 0; + } + + &::before { + content: none; + padding-right: 0; + } + + &:nth-last-of-type(1n + 3) { + display: none; + } + + &:nth-last-of-type(2) { + &::before { + color: var(--primary); + content: "\f060"; // .fa-arrow-left + cursor: pointer; + font-family: FontAwesome; + } + + a { + display: none; + } + } + } + + // Ellipsize long breadcrumbs + .breadcrumb { + max-width: 100%; + text-overflow: ellipsis; + } + + // In case you install `mail`, there is a mess on BS vs inline styles + // we need to fix + .o_cp_buttons .btn.d-block:not(.d-none) { + display: inline-block !important; + } + + .o_searchview { + padding: 1px 0px 3px 0px; + &.o_searchview_mobile { + cursor: pointer; + } + &.o_searchview_quick { + display: flex; + flex: 1 1 auto; + align-items: center; + .o_searchview_input_container { + flex: 1 1 auto; + } + } + } + } + .o_calendar_view .o_calendar_widget { + .fc-timeGridDay-view .fc-axis, + .fc-timeGridWeek-view .fc-axis { + padding-left: 0px; + } + .fc-dayGridMonth-view { + padding-left: 0px; + .fc-week-number { + display: none; + } + } + .fc-dayGridYear-view { + padding-left: 0px; + > .fc-month-container > .fc-month { + width: 100%; + } + } + .fc-timeGridDay-view .fc-widget-header { + margin: 0 4px; + } + .fc-timeGridWeek-view .fc-widget-header { + word-spacing: 4em; + white-space: normal; + text-align: center; + } + } + .o_base_settings .o_setting_container { + display: block; + .settings_tab { + flex-flow: row nowrap; + padding-top: 0px; + .tab { + padding-right: 16px; + } + .selected { + background-color: #212529; + box-shadow: inset 0 -5px #7c7bad; + } + } + } +} + +// Normal views +.o_content, +.modal-content { + max-width: 100%; + + // Form views + .o_form_view { + .o_form_sheet { + max-width: calc(100% - 32px); + overflow-x: auto; + } + + .o_FormRenderer_chatterContainer { + padding-top: 0; + .o_Activity_info { + flex-wrap: wrap; + } + .o_ActivityBox_title { + margin-bottom: 0; + } + .o_MessageList_separatorDate { + padding-bottom: 0; + } + } + // Sided chatter scrolling behavior + .o_Chatter { + height: fit-content; + .o_Chatter_fixedPanel { + position: sticky; + top: 0; + z-index: 1; + background-color: white; + padding-bottom: 10px; + } + .o_Chatter_scrollPanel { + overflow: initial; + } + } + + // Sticky statusbar + .o_form_statusbar { + position: sticky; + top: 0; + z-index: 2; + } + + // Support for long title (with ellipsis) + .oe_title { + span.o_field_widget:not(.oe_inline) { + max-width: 100%; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + width: initial; + &:active { + white-space: normal; + } + } + } + + @include media-breakpoint-down(sm) { + min-width: auto; + + // More buttons border + .oe_button_box { + .o_dropdown_more { + button:last-child { + border-right: 1px solid gray("400"); + } + } + } + + // Avoid overflow on forms with title and/or button box + .oe_title { + max-width: 100%; + } + + .oe_button_box + .oe_title, + .oe_button_box + .oe_avatar + .oe_title { + width: 100%; + } + + // Avoid overflow on modals + .o_form_sheet { + min-width: auto; + } + + // Render website inputs properly in phones + .o_group .o_field_widget.o_text_overflow { + // Overrides another !important + width: auto !important; + } + + // Make all input groups vertical + .o_group_col_6 { + width: 100%; + } + + // Statusbar buttons dropdown for mobiles + .o_statusbar_buttons_dropdown { + border: { + bottom: 0; + radius: 0; + top: 0; + } + height: 100%; + } + .o_statusbar_buttons.dropdown-menu > .btn { + border-radius: 0; + border: 0; + width: 100%; + margin-bottom: 0.2rem; + + &:last-child { + margin-bottom: 0; + } + } + + .o_statusbar_status { + // Arrow from rightmost button exceeds allowed width + .o_arrow_button:first-child::before { + content: none; + display: none; + } + } + + // Full width in form sheets + .o_form_sheet, + .o_FormRenderer_chatterContainer { + min-width: auto; + max-width: 98%; + } + + // Settings pages + .app_settings_block { + .row { + margin: 0; + } + } + + .o_FormRenderer_chatterContainer { + padding-top: initial; + + // Display send button on small screens + .o_thread_composer { + padding-left: $o-mail-thread-avatar-size * 0.5; + + .o_composer_button_send { + display: initial !important; // Forced in core + } + .o_chatter_avatar { + display: none; + } + } + + .o_chatter_topbar { + > .o_topbar_right_area { + flex: 1 0 auto; + flex-wrap: wrap; + max-width: 100%; + + // Display followers on small screens + .o_followers { + display: initial !important; // Forced in core + + @include media-breakpoint-down(xs) { + padding-bottom: 50px; + } + } + } + } + } + } + } + + // Sided chatter, if user wants + .o_chatter_position_sided & { + @include media-breakpoint-up(lg) { + .o_form_view:not(.o_form_nosheet) { + display: flex; + flex-flow: row nowrap; + height: 100%; + + .o_form_sheet_bg { + flex: 1 1 auto; + overflow: auto; + + > .o_form_sheet { + min-width: unset; + } + } + + .o_FormRenderer_chatterContainer { + border-left: 1px solid gray("400"); + flex: 0 0 $chatter_zone_width; + max-width: initial; + min-width: initial; + overflow: auto; + + .o_chatter_header_container { + padding-top: $grid-gutter-width * 0.5; + top: 0; + position: sticky; + background-color: $o-view-background-color; + z-index: 1; + + // Scrollable input text to avoid hide conversation & buttons + .o_composer_text_field { + max-height: 120px; + overflow-y: auto !important; /* Forced because Odoo uses inline style */ + } + .o_attachments_list { + overflow: auto; + max-height: $o-mail-attachment-image-size * 3; + margin-top: 0.4em; + } + .o_attachments_previews { + overflow: auto; + max-height: $o-mail-attachment-image-size * 6; + } + } + } + } + } + } +} + +// Sticky Header & Footer in List View +.o_list_view { + .table-responsive { + .o_list_table { + // th & td are here for compatibility with chrome + thead tr:nth-child(1) th { + position: sticky; + top: 0; + z-index: 1; + } + thead tr:nth-child(1) th { + background-color: $o-list-footer-bg-color; + } + tfoot, + tfoot tr:nth-child(1) td { + position: sticky; + bottom: 0; + } + tfoot tr:nth-child(1) td { + background-color: $o-list-footer-bg-color; + } + } + } +} + +// Big checkboxes +.o_list_view { + .custom-checkbox:not(.o_boolean_toggle) { + margin-right: 10px; + + .custom-control-label { + top: -6px; + + &::after { + width: 24px; + height: 24px; + } + &::before { + outline: none !important; + border: 1px solid #4c4c4c; + width: 24px; + height: 24px; + } + } + } +} + +// Waiting Cursor +.oe_wait { + cursor: progress; +} + +// Attachment Viewer +.o_web_client.o_chatter_position_sided .o_Dialog_AttachmentViewer { + /* Show sided viewer on large screens */ + @include media-breakpoint-up(lg) { + position: static; + .o_AttachmentViewer_main { + padding-bottom: 20px; + } + .o_AttachmentViewer { + // On-top of navbar + z-index: 10; + position: absolute; + right: 0; + top: 0; + bottom: 0; + margin-left: auto; + background-color: rgba(0, 0, 0, 0.7); + + .o_AttachmentViewer_name { + display: contents; + } + + width: $chatter_zone_width; + &.o_AttachmentViewer_maximized { + width: 100%; + } + + /* Show/Hide control buttons (next, prev, etc..) */ + &:hover .o_AttachmentViewer_buttonNavigation, + &:hover .o_AttachmentViewer_toolbar { + display: flex; + } + .o_AttachmentViewer_buttonNavigation, + .o_AttachmentViewer_toolbar { + display: none; + } + .o_AttachmentViewer_viewIframe { + width: 95%; + } + } + } + @include media-breakpoint-down(md) { + .o_AttachmentViewer_headerItemButtonMinimize, + .o_AttachmentViewer_headerItemButtonMaximize { + display: none; + } + } +} +/* Attachment Viewer Max/Min buttons only are useful in sided mode */ +.o_web_client:not(.o_chatter_position_sided) { + .o_AttachmentViewer_headerItemButtonMinimize, + .o_AttachmentViewer_headerItemButtonMaximize { + display: none; + } +} + +.o_control_panel { + // Filter Menu + // Cut long filters names in the filters menu + .o_filter_menu { + .o_menu_item { + width: auto; + @include media-breakpoint-up(md) { + max-width: 250px; + } + a { + overflow: hidden; + text-overflow: ellipsis; + } + } + } + // Enable scroll on dropdowns + .o_cp_buttons .dropdown-menu { + max-height: 70vh; + overflow-y: auto; + overflow-x: hidden; + } + // Dropdown with buttons to switch the view type + .o_cp_switch_buttons.show { + .dropdown-menu { + align-content: center; + display: flex; + flex-direction: row; + justify-content: space-around; + padding: 0; + + .btn { + border: { + bottom: 0; + radius: 0; + top: 0; + } + font-size: 1.3em; + } + } + } +} + +// Shortcut table ui improvement +.o_shortcut_table { + width: 100%; +} diff --git a/web_responsive/static/src/img/home-menu-bg-overlay.svg b/web_responsive/static/src/img/home-menu-bg-overlay.svg new file mode 100644 index 000000000..b9fe251bc --- /dev/null +++ b/web_responsive/static/src/img/home-menu-bg-overlay.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/web_responsive/static/src/js/kanban_renderer_mobile.js b/web_responsive/static/src/js/kanban_renderer_mobile.js new file mode 100644 index 000000000..5c62db757 --- /dev/null +++ b/web_responsive/static/src/js/kanban_renderer_mobile.js @@ -0,0 +1,494 @@ +odoo.define("web_responsive.KanbanRendererMobile", function (require) { + "use strict"; + + /** + * The purpose of this file is to improve the UX of grouped kanban views in + * mobile. It includes the KanbanRenderer (in mobile only) to only display one + * column full width, and enables the swipe to browse to the other columns. + * Moreover, records in columns are lazy-loaded. + */ + + var config = require("web.config"); + var core = require("web.core"); + var KanbanRenderer = require("web.KanbanRenderer"); + var KanbanView = require("web.KanbanView"); + var KanbanQuickCreate = require("web.kanban_column_quick_create"); + + var _t = core._t; + var qweb = core.qweb; + + if (!config.device.isMobile) { + return; + } + + KanbanQuickCreate.include({ + init() { + this._super.apply(this, arguments); + this.isMobile = true; + }, + }); + + KanbanView.include({ + init() { + this._super.apply(this, arguments); + this.jsLibs.push("/web/static/lib/jquery.touchSwipe/jquery.touchSwipe.js"); + }, + }); + + KanbanRenderer.include({ + custom_events: _.extend({}, KanbanRenderer.prototype.custom_events || {}, { + quick_create_column_created: "_onColumnAdded", + }), + events: _.extend({}, KanbanRenderer.prototype.events, { + "click .o_kanban_mobile_tab": "_onMobileTabClicked", + "click .o_kanban_mobile_add_column": "_onMobileQuickCreateClicked", + }), + ANIMATE: true, // Allows to disable animations for the tests + /** + * @override + */ + init: function () { + this._super.apply(this, arguments); + this.activeColumnIndex = 0; // Index of the currently displayed column + this._scrollPosition = null; + }, + /** + * As this renderer defines its own scrolling area (the column in grouped + * mode), we override this hook to restore the scroll position like it was + * when the renderer has been last detached. + * + * @override + */ + on_attach_callback: function () { + if ( + this._scrollPosition && + this.state.groupedBy.length && + this.widgets.length + ) { + var $column = this.widgets[this.activeColumnIndex].$el; + $column.scrollLeft(this._scrollPosition.left); + $column.scrollTop(this._scrollPosition.top); + } + this._computeTabPosition(); + this._super.apply(this, arguments); + }, + /** + * As this renderer defines its own scrolling area (the column in grouped + * mode), we override this hook to store the scroll position, so that we can + * restore it if the renderer is re-attached to the DOM later. + * + * @override + */ + on_detach_callback: function () { + if (this.state.groupedBy.length && this.widgets.length) { + var $column = this.widgets[this.activeColumnIndex].$el; + this._scrollPosition = { + left: $column.scrollLeft(), + top: $column.scrollTop(), + }; + } else { + this._scrollPosition = null; + } + this._super.apply(this, arguments); + }, + + // -------------------------------------------------------------------------- + // Public + // -------------------------------------------------------------------------- + + /** + * Displays the quick create record in the active column + * override to open quick create record in current active column + * + * @override + * @returns {Promise} + */ + addQuickCreate: function () { + if (this._canCreateColumn() && !this.quickCreate.folded) { + this._onMobileQuickCreateClicked(); + } + return this.widgets[this.activeColumnIndex].addQuickCreate(); + }, + + /** + * Overrides to restore the left property and the scrollTop on the updated + * column, and to enable the swipe handlers + * + * @override + */ + updateColumn: function (localID) { + var index = _.findIndex(this.widgets, {db_id: localID}); + var $column = this.widgets[index].$el; + var scrollTop = $column.scrollTop(); + return ( + this._super + .apply(this, arguments) + .then(() => this._layoutUpdate(false)) + // Required when clicking on 'Load More' + .then(() => $column.scrollTop(scrollTop)) + .then(() => this._enableSwipe()) + ); + }, + + // -------------------------------------------------------------------------- + // Private + // -------------------------------------------------------------------------- + + /** + * Check if we use the quick create on mobile + * @returns {Boolean} + * @private + */ + _canCreateColumn: function () { + return this.quickCreateEnabled && this.quickCreate && this.widgets.length; + }, + + /** + * Update the columns positions + * + * @private + * @param {Boolean} [animate=false] set to true to animate + */ + _computeColumnPosition: function (animate) { + if (this.widgets.length) { + // Check rtl to compute correct css value + const rtl = _t.database.parameters.direction === "rtl"; + + // Display all o_kanban_group + this.$(".o_kanban_group").show(); + + const $columnAfter = this._toNode( + this.widgets.filter( + (widget, index) => index > this.activeColumnIndex + ) + ); + const promiseAfter = this._updateColumnCss( + $columnAfter, + rtl ? {right: "100%"} : {left: "100%"}, + animate + ); + + const $columnBefore = this._toNode( + this.widgets.filter( + (widget, index) => index < this.activeColumnIndex + ) + ); + const promiseBefore = this._updateColumnCss( + $columnBefore, + rtl ? {right: "-100%"} : {left: "-100%"}, + animate + ); + + const $columnCurrent = this._toNode( + this.widgets.filter( + (widget, index) => index === this.activeColumnIndex + ) + ); + const promiseCurrent = this._updateColumnCss( + $columnCurrent, + rtl ? {right: "0%"} : {left: "0%"}, + animate + ); + + promiseAfter + .then(promiseBefore) + .then(promiseCurrent) + .then(() => { + $columnAfter.hide(); + $columnBefore.hide(); + }); + } + }, + + /** + * Define the o_current class to the current selected kanban (column & tab) + * + * @private + */ + _computeCurrentColumn: function () { + if (this.widgets.length) { + var column = this.widgets[this.activeColumnIndex]; + if (!column) { + return; + } + var columnID = column.id || column.db_id; + this.$( + ".o_kanban_mobile_tab.o_current, .o_kanban_group.o_current" + ).removeClass("o_current"); + this.$( + '.o_kanban_group[data-id="' + + columnID + + '"], ' + + '.o_kanban_mobile_tab[data-id="' + + columnID + + '"]' + ).addClass("o_current"); + } + }, + + /** + * Update the tabs positions + * + * @private + */ + _computeTabPosition: function () { + this._computeTabJustification(); + this._computeTabScrollPosition(); + }, + + /** + * Update the tabs positions + * + * @private + */ + _computeTabScrollPosition: function () { + if (this.widgets.length) { + var lastItemIndex = this.widgets.length - 1; + var moveToIndex = this.activeColumnIndex; + var scrollToLeft = 0; + for (var i = 0; i < moveToIndex; i++) { + var columnWidth = this._getTabWidth(this.widgets[i]); + // Apply + if (moveToIndex !== lastItemIndex && i === moveToIndex - 1) { + var partialWidth = 0.75; + scrollToLeft += columnWidth * partialWidth; + } else { + scrollToLeft += columnWidth; + } + } + // Apply the scroll x on the tabs + // XXX in case of RTL, should we use scrollRight? + this.$(".o_kanban_mobile_tabs").scrollLeft(scrollToLeft); + } + }, + + /** + * Compute the justify content of the kanban tab headers + * + * @private + */ + _computeTabJustification: function () { + if (this.widgets.length) { + var self = this; + // Use to compute the sum of the width of all tab + var widthChilds = this.widgets.reduce(function (total, column) { + return total + self._getTabWidth(column); + }, 0); + // Apply a space around between child if the parent length is higher then the sum of the child width + var $tabs = this.$(".o_kanban_mobile_tabs"); + $tabs.toggleClass( + "justify-content-between", + $tabs.outerWidth() >= widthChilds + ); + } + }, + + /** + * Enables swipe event on the current column + * + * @private + */ + _enableSwipe: function () { + var self = this; + var step = _t.database.parameters.direction === "rtl" ? -1 : 1; + this.$el.swipe({ + excludedElements: ".o_kanban_mobile_tabs", + swipeLeft: function () { + var moveToIndex = self.activeColumnIndex + step; + if (moveToIndex < self.widgets.length) { + self._moveToGroup(moveToIndex, self.ANIMATE); + } + }, + swipeRight: function () { + var moveToIndex = self.activeColumnIndex - step; + if (moveToIndex > -1) { + self._moveToGroup(moveToIndex, self.ANIMATE); + } + }, + }); + }, + + /** + * Retrieve the outerWidth of a given widget column + * + * @param {KanbanColumn} column + * @returns {integer} outerWidth of the found column + * @private + */ + _getTabWidth: function (column) { + var columnID = column.id || column.db_id; + return this.$( + '.o_kanban_mobile_tab[data-id="' + columnID + '"]' + ).outerWidth(); + }, + + /** + * Update the kanban layout + * + * @private + * @param {Boolean} [animate=false] set to true to animate + */ + _layoutUpdate: function (animate) { + this._computeCurrentColumn(); + this._computeTabPosition(); + this._computeColumnPosition(animate); + this._enableSwipe(); + }, + + /** + * Moves to the given kanban column + * + * @private + * @param {integer} moveToIndex index of the column to move to + * @param {Boolean} [animate=false] set to true to animate + * @returns {Promise} resolved when the new current group has been loaded + * and displayed + */ + _moveToGroup: function (moveToIndex, animate) { + var self = this; + if (moveToIndex >= 0 && moveToIndex < this.widgets.length) { + this.activeColumnIndex = moveToIndex; + } + var column = this.widgets[this.activeColumnIndex]; + this._enableSwipe(); + if (!column.data.isOpen) { + this.trigger_up("column_toggle_fold", { + db_id: column.db_id, + onSuccess: () => self._layoutUpdate(animate), + }); + } else { + this._layoutUpdate(animate); + } + return Promise.resolve(); + }, + /** + * @override + * @private + */ + _renderExampleBackground: function () { + // Override to avoid display of example background + }, + /** + * @override + * @private + */ + _renderGrouped: function (fragment) { + var self = this; + var newFragment = document.createDocumentFragment(); + this._super.apply(this, [newFragment]); + this.defs.push( + Promise.all(this.defs).then(function () { + var data = []; + _.each(self.state.data, function (group) { + if (!group.value) { + group = _.extend({}, group, {value: _t("Undefined")}); + data.unshift(group); + } else { + data.push(group); + } + }); + + var kanbanColumnContainer = document.createElement("div"); + kanbanColumnContainer.classList.add("o_kanban_columns_content"); + kanbanColumnContainer.appendChild(newFragment); + fragment.appendChild(kanbanColumnContainer); + $( + qweb.render("KanbanView.MobileTabs", { + data: data, + quickCreateEnabled: self._canCreateColumn(), + }) + ).prependTo(fragment); + }) + ); + }, + + /** + * @override + * @private + */ + _renderView: function () { + var self = this; + return this._super.apply(this, arguments).then(function () { + if (self.state.groupedBy.length) { + // Force first column for kanban view, because the groupedBy can be changed + return self._moveToGroup(0); + } + if (self._canCreateColumn()) { + self._onMobileQuickCreateClicked(); + } + return Promise.resolve(); + }); + }, + + /** + * Retrieve the Jquery node (.o_kanban_group) for a list of a given widgets + * + * @private + * @param widgets + * @returns {jQuery} the matching .o_kanban_group widgets + */ + _toNode: function (widgets) { + const selectorCss = widgets + .map( + (widget) => + '.o_kanban_group[data-id="' + (widget.id || widget.db_id) + '"]' + ) + .join(", "); + return this.$(selectorCss); + }, + + /** + * Update the given column to the updated positions + * + * @private + * @param $column The jquery column + * @param cssProperties Use to update column + * @param {Boolean} [animate=false] set to true to animate + * @returns {Promise} + */ + _updateColumnCss: function ($column, cssProperties, animate) { + if (animate) { + return new Promise((resolve) => + $column.animate(cssProperties, "fast", resolve) + ); + } + $column.css(cssProperties); + return Promise.resolve(); + }, + + // -------------------------------------------------------------------------- + // Handlers + // -------------------------------------------------------------------------- + + /** + * @private + */ + _onColumnAdded: function () { + this._computeTabPosition(); + if (this._canCreateColumn() && !this.quickCreate.folded) { + this.quickCreate.toggleFold(); + } + }, + + /** + * @private + */ + _onMobileQuickCreateClicked: function (event) { + if (event) { + event.stopPropagation(); + } + this.$(".o_kanban_group").toggle(); + this.quickCreate.toggleFold(); + }, + /** + * @private + * @param {MouseEvent} event + */ + _onMobileTabClicked: function (event) { + if (this._canCreateColumn() && !this.quickCreate.folded) { + this.quickCreate.toggleFold(); + } + this._moveToGroup($(event.currentTarget).index(), true); + }, + }); +}); diff --git a/web_responsive/static/src/js/web_responsive.js b/web_responsive/static/src/js/web_responsive.js new file mode 100644 index 000000000..5151a3039 --- /dev/null +++ b/web_responsive/static/src/js/web_responsive.js @@ -0,0 +1,629 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2018 Tecnativa - Sergey Shebanin + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +odoo.define("web_responsive", function (require) { + "use strict"; + + const ActionManager = require("web.ActionManager"); + const AbstractWebClient = require("web.AbstractWebClient"); + const AppsMenu = require("web.AppsMenu"); + const BasicController = require("web.BasicController"); + const config = require("web.config"); + const core = require("web.core"); + const FormRenderer = require("web.FormRenderer"); + const Menu = require("web.Menu"); + const RelationalFields = require("web.relational_fields"); + const ListRenderer = require("web.ListRenderer"); + const CalendarRenderer = require("web.CalendarRenderer"); + const patchMixin = require("web.patchMixin"); + const AttachmentViewer = require("mail/static/src/components/attachment_viewer/attachment_viewer.js"); + const PatchableAttachmentViewer = patchMixin(AttachmentViewer); + const ControlPanel = require("web.ControlPanel"); + const SearchPanel = require("web/static/src/js/views/search_panel.js"); + /* global owl */ + const {QWeb, Context} = owl; + const {useState, useContext} = owl.hooks; + + /* Hide AppDrawer in desktop and mobile modes. + * To avoid delays in pages with a lot of DOM nodes we make + * sub-groups' with 'querySelector' to improve the performance. + */ + function closeAppDrawer() { + _.defer(function () { + // Need close AppDrawer? + var menu_apps_dropdown = document.querySelector(".o_menu_apps .dropdown"); + $(menu_apps_dropdown) + .has(".dropdown-menu.show") + .find("> a") + .dropdown("toggle"); + // Need close Sections Menu? + // TODO: Change to 'hide' in modern Bootstrap >4.1 + var menu_sections = document.querySelector( + ".o_menu_sections li.show .dropdown-toggle" + ); + $(menu_sections).dropdown("toggle"); + // Need close Mobile? + var menu_sections_mobile = document.querySelector(".o_menu_sections.show"); + $(menu_sections_mobile).collapse("hide"); + }); + } + + /** + * Reduce menu data to a searchable format understandable by fuzzy.js + * + * `AppsMenu.init()` gets `menuData` in a format similar to this (only + * relevant data is shown): + * + * ```js + * { + * [...], + * children: [ + * // This is a menu entry: + * { + * action: "ir.actions.client,94", // Or `false` + * children: [... similar to above "children" key], + * name: "Actions", + * parent_id: [146, "Settings/Technical/Actions"], // Or `false` + * }, + * ... + * ] + * } + * ``` + * + * This format is very hard to process to search matches, and it would + * slow down the search algorithm, so we reduce it with this method to be + * able to later implement a simpler search. + * + * @param {Object} memo + * Reference to current result object, passed on recursive calls. + * + * @param {Object} menu + * A menu entry, as described above. + * + * @returns {Object} + * Reduced object, without entries that have no action, and with a + * format like this: + * + * ```js + * { + * "Discuss": {Menu entry Object}, + * "Settings": {Menu entry Object}, + * "Settings/Technical/Actions/Actions": {Menu entry Object}, + * ... + * } + * ``` + */ + function findNames(memo, menu) { + if (menu.action) { + var key = menu.parent_id ? menu.parent_id[1] + "/" : ""; + memo[key + menu.name] = menu; + } + if (menu.children.length) { + _.reduce(menu.children, findNames, memo); + } + return memo; + } + + AppsMenu.include({ + events: _.extend( + { + "keydown .search-input input": "_searchResultsNavigate", + "input .search-input input": "_searchMenusSchedule", + "click .o-menu-search-result": "_searchResultChosen", + "shown.bs.dropdown": "_searchFocus", + "hidden.bs.dropdown": "_searchReset", + "hide.bs.dropdown": "_hideAppsMenu", + }, + AppsMenu.prototype.events + ), + + /** + * Rescue some menu data stripped out in original method. + * + * @override + */ + init: function (parent, menuData) { + this._super.apply(this, arguments); + // Keep base64 icon for main menus + for (const n in this._apps) { + this._apps[n].web_icon_data = menuData.children[n].web_icon_data; + } + // Store menu data in a format searchable by fuzzy.js + this._searchableMenus = _.reduce(menuData.children, findNames, {}); + // Search only after timeout, for fast typers + this._search_def = false; + }, + + /** + * @override + */ + start: function () { + this.$search_container = this.$(".search-container"); + this.$search_input = this.$(".search-input input"); + this.$search_results = this.$(".search-results"); + return this._super.apply(this, arguments); + }, + + /** + * Prevent the menu from being opened twice + * + * @override + */ + _onAppsMenuItemClicked: function (ev) { + this._super.apply(this, arguments); + ev.preventDefault(); + ev.stopPropagation(); + }, + + /** + * Get all info for a given menu. + * + * @param {String} key + * Full path to requested menu. + * + * @returns {Object} + * Menu definition, plus extra needed keys. + */ + _menuInfo: function (key) { + const original = this._searchableMenus[key]; + return _.extend( + { + action_id: parseInt(original.action.split(",")[1], 10), + }, + original + ); + }, + + /** + * Autofocus on search field on big screens. + */ + _searchFocus: function () { + if (!config.device.isMobile) { + // This timeout is necessary since the menu has a 100ms fading animation + setTimeout(() => this.$search_input.focus(), 100); + } + }, + + /** + * Reset search input and results + */ + _searchReset: function () { + this.$search_container.removeClass("has-results"); + this.$search_results.empty(); + this.$search_input.val(""); + }, + + /** + * Schedule a search on current menu items. + */ + _searchMenusSchedule: function () { + this._search_def = new Promise((resolve) => { + setTimeout(resolve, 50); + }); + this._search_def.then(this._searchMenus.bind(this)); + }, + + /** + * Search among available menu items, and render that search. + */ + _searchMenus: function () { + const query = this.$search_input.val(); + if (query === "") { + this.$search_container.removeClass("has-results"); + this.$search_results.empty(); + return; + } + var results = fuzzy.filter(query, _.keys(this._searchableMenus), { + pre: "", + post: "", + }); + this.$search_container.toggleClass("has-results", Boolean(results.length)); + this.$search_results.html( + core.qweb.render("web_responsive.MenuSearchResults", { + results: results, + widget: this, + }) + ); + }, + + /** + * Use chooses a search result, so we navigate to that menu + * + * @param {jQuery.Event} event + */ + _searchResultChosen: function (event) { + event.preventDefault(); + event.stopPropagation(); + const $result = $(event.currentTarget), + text = $result.text().trim(), + data = $result.data(), + suffix = ~text.indexOf("/") ? "/" : ""; + // Load the menu view + this.trigger_up("menu_clicked", { + action_id: data.actionId, + id: data.menuId, + previous_menu_id: data.parentId, + }); + // Find app that owns the chosen menu + const app = _.find(this._apps, function (_app) { + return text.indexOf(_app.name + suffix) === 0; + }); + // Update navbar menus + core.bus.trigger("change_menu_section", app.menuID); + }, + + /** + * Navigate among search results + * + * @param {jQuery.Event} event + */ + _searchResultsNavigate: function (event) { + // Find current results and active element (1st by default) + const all = this.$search_results.find(".o-menu-search-result"), + pre_focused = all.filter(".active") || $(all[0]); + let offset = all.index(pre_focused), + key = event.key; + // Keyboard navigation only supports search results + if (!all.length) { + return; + } + // Transform tab presses in arrow presses + if (key === "Tab") { + event.preventDefault(); + key = event.shiftKey ? "ArrowUp" : "ArrowDown"; + } + switch (key) { + // Pressing enter is the same as clicking on the active element + case "Enter": + pre_focused.click(); + break; + // Navigate up or down + case "ArrowUp": + offset--; + break; + case "ArrowDown": + offset++; + break; + default: + // Other keys are useless in this event + return; + } + // Allow looping on results + if (offset < 0) { + offset = all.length + offset; + } else if (offset >= all.length) { + offset -= all.length; + } + // Switch active element + const new_focused = $(all[offset]); + pre_focused.removeClass("active"); + new_focused.addClass("active"); + this.$search_results.scrollTo(new_focused, { + offset: { + top: this.$search_results.height() * -0.5, + }, + }); + }, + + /* + * Control if AppDrawer can be closed + */ + _hideAppsMenu: function () { + return !this.$("input").is(":focus"); + }, + }); + + BasicController.include({ + /** + * Close the AppDrawer if the data set is dirty and a discard dialog + * is opened + * + * @override + */ + canBeDiscarded: function (recordID) { + if (this.model.isDirty(recordID || this.handle)) { + closeAppDrawer(); + } + return this._super.apply(this, arguments); + }, + }); + + Menu.include({ + events: _.extend( + { + // Clicking a hamburger menu item should close the hamburger + "click .o_menu_sections [role=menuitem]": "_onClickMenuItem", + // Opening any dropdown in the navbar should hide the hamburger + "show.bs.dropdown .o_menu_systray, .o_menu_apps": "_hideMobileSubmenus", + }, + Menu.prototype.events + ), + + start: function () { + this.$menu_toggle = this.$(".o-menu-toggle"); + return this._super.apply(this, arguments); + }, + + /** + * Hide menus for current app if you're in mobile + */ + _hideMobileSubmenus: function () { + if ( + config.device.isMobile && + this.$menu_toggle.is(":visible") && + this.$section_placeholder.is(":visible") + ) { + this.$section_placeholder.collapse("hide"); + } + }, + + /** + * Prevent hide the menu (should be closed when action is loaded) + * + * @param {ClickEvent} ev + */ + _onClickMenuItem: function (ev) { + ev.stopPropagation(); + }, + + /** + * No menu brand in mobiles + * + * @override + */ + _updateMenuBrand: function () { + if (!config.device.isMobile) { + return this._super.apply(this, arguments); + } + }, + }); + + RelationalFields.FieldStatus.include({ + /** + * Fold all on mobiles. + * + * @override + */ + _setState: function () { + this._super.apply(this, arguments); + if (config.device.isMobile) { + _.map(this.status_information, (value) => { + value.fold = true; + }); + } + }, + }); + + // Sticky Column Selector + ListRenderer.include({ + _renderView: function () { + const self = this; + return this._super.apply(this, arguments).then(() => { + const $col_selector = self.$el.find( + ".o_optional_columns_dropdown_toggle" + ); + if ($col_selector.length !== 0) { + const $th = self.$el.find("thead>tr:first>th:last"); + $col_selector.appendTo($th); + } + }); + }, + + _onToggleOptionalColumnDropdown: function (ev) { + // FIXME: For some strange reason the 'stopPropagation' call + // in the main method don't work. Invoking here the same method + // does the expected behavior... O_O! + // This prevents the action of sorting the column from being + // launched. + ev.stopPropagation(); + this._super.apply(this, arguments); + }, + }); + + // Responsive view "action" buttons + FormRenderer.include({ + /** + * In mobiles, put all statusbar buttons in a dropdown. + * + * @override + */ + _renderHeaderButtons: function () { + const $buttons = this._super.apply(this, arguments); + if ( + !config.device.isMobile || + $buttons.children("button:not(.o_invisible_modifier)").length <= 2 + ) { + return $buttons; + } + + // $buttons must be appended by JS because all events are bound + const $dropdown = $( + core.qweb.render("web_responsive.MenuStatusbarButtons") + ); + $buttons.addClass("dropdown-menu").appendTo($dropdown); + return $dropdown; + }, + }); + + CalendarRenderer.include({ + _getFullCalendarOptions: function () { + var options = this._super.apply(this, arguments); + if (config.device.isMobile) { + options.views.dayGridMonth.columnHeaderFormat = "ddd"; + } + return options; + }, + }); + + // Hide AppDrawer or Menu when the action has been completed + ActionManager.include({ + /** + * @override + */ + _appendController: function () { + this._super.apply(this, arguments); + closeAppDrawer(); + }, + }); + + /** + * Use ALT+SHIFT instead of ALT as hotkey triggerer. + * + * HACK https://github.com/odoo/odoo/issues/30068 - See it to know why. + * + * Cannot patch in `KeyboardNavigationMixin` directly because it's a mixin, + * not a `Class`, and altering a mixin's `prototype` doesn't alter it where + * it has already been used. + * + * Instead, we provide an additional mixin to be used wherever you need to + * enable this behavior. + */ + var KeyboardNavigationShiftAltMixin = { + /** + * Alter the key event to require pressing Shift. + * + * This will produce a mocked event object where it will seem that + * `Alt` is not pressed if `Shift` is not pressed. + * + * The reason for this is that original upstream code, found in + * `KeyboardNavigationMixin` is very hardcoded against the `Alt` key, + * so it is more maintainable to mock its input than to rewrite it + * completely. + * + * @param {keyEvent} keyEvent + * Original event object + * + * @returns {keyEvent} + * Altered event object + */ + _shiftPressed: function (keyEvent) { + const alt = keyEvent.altKey || keyEvent.key === "Alt", + newEvent = _.extend({}, keyEvent), + shift = keyEvent.shiftKey || keyEvent.key === "Shift"; + // Mock event to make it seem like Alt is not pressed + if (alt && !shift) { + newEvent.altKey = false; + if (newEvent.key === "Alt") { + newEvent.key = "Shift"; + } + } + return newEvent; + }, + + _onKeyDown: function (keyDownEvent) { + return this._super(this._shiftPressed(keyDownEvent)); + }, + + _onKeyUp: function (keyUpEvent) { + return this._super(this._shiftPressed(keyUpEvent)); + }, + }; + + // Include the SHIFT+ALT mixin wherever + // `KeyboardNavigationMixin` is used upstream + AbstractWebClient.include(KeyboardNavigationShiftAltMixin); + + // TODO: use default odoo device context when it will be realized + const deviceContext = new Context({ + isMobile: config.device.isMobile, + size_class: config.device.size_class, + SIZES: config.device.SIZES, + }); + window.addEventListener( + "resize", + owl.utils.debounce(() => { + const state = deviceContext.state; + if (state.isMobile !== config.device.isMobile) { + state.isMobile = !state.isMobile; + } + if (state.size_class !== config.device.size_class) { + state.size_class = config.device.size_class; + } + }, 15) + ); + // Patch attachment viewer to add min/max buttons capability + PatchableAttachmentViewer.patch("web_responsive.AttachmentViewer", (T) => { + class AttachmentViewerPatchResponsive extends T { + constructor() { + super(...arguments); + this.state = useState({ + maximized: false, + }); + } + // Disable auto-close to allow to use form in edit mode. + isCloseable() { + return false; + } + } + return AttachmentViewerPatchResponsive; + }); + QWeb.components.AttachmentViewer = PatchableAttachmentViewer; + + // Patch control panel to add states for mobile quick search + ControlPanel.patch("web_responsive.ControlPanelMobile", (T) => { + class ControlPanelPatchResponsive extends T { + constructor() { + super(...arguments); + this.state = useState({ + mobileSearchMode: "", + }); + this.device = useContext(deviceContext); + } + } + return ControlPanelPatchResponsive; + }); + // Patch search panel to add functionality for mobile view + SearchPanel.patch("web_responsive.SearchPanelMobile", (T) => { + class SearchPanelPatchResponsive extends T { + constructor() { + super(...arguments); + this.state.mobileSearch = false; + this.device = useContext(deviceContext); + } + getActiveSummary() { + const selection = []; + for (const filter of this.model.get("sections")) { + let filterValues = []; + if (filter.type === "category") { + if (filter.activeValueId) { + const parentIds = this._getAncestorValueIds( + filter, + filter.activeValueId + ); + filterValues = [...parentIds, filter.activeValueId].map( + (valueId) => filter.values.get(valueId).display_name + ); + } + } else { + let values = []; + if (filter.groups) { + values = [ + ...filter.groups.values().map((g) => g.values), + ].flat(); + } + if (filter.values) { + values = [...filter.values.values()]; + } + filterValues = values + .filter((v) => v.checked) + .map((v) => v.display_name); + } + if (filterValues.length) { + selection.push({ + values: filterValues, + icon: filter.icon, + color: filter.color, + type: filter.type, + }); + } + } + return selection; + } + } + return SearchPanelPatchResponsive; + }); + return { + deviceContext: deviceContext, + }; +}); diff --git a/web_responsive/static/src/xml/apps.xml b/web_responsive/static/src/xml/apps.xml new file mode 100644 index 000000000..d9e409853 --- /dev/null +++ b/web_responsive/static/src/xml/apps.xml @@ -0,0 +1,69 @@ + + + diff --git a/web_responsive/static/src/xml/attachment_viewer.xml b/web_responsive/static/src/xml/attachment_viewer.xml new file mode 100644 index 000000000..928a1e4bf --- /dev/null +++ b/web_responsive/static/src/xml/attachment_viewer.xml @@ -0,0 +1,47 @@ + + + diff --git a/web_responsive/static/src/xml/control_panel.xml b/web_responsive/static/src/xml/control_panel.xml new file mode 100644 index 000000000..d7d0f9c34 --- /dev/null +++ b/web_responsive/static/src/xml/control_panel.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + device.isMobile and state.mobileSearchMode == 'quick' ? 'o_hidden' : '' + + + !device.isMobile + device.size_class == device.SIZES.MD ? 'o_search_options_hide_labels' : '' + + + + + + diff --git a/web_responsive/static/src/xml/discuss.xml b/web_responsive/static/src/xml/discuss.xml new file mode 100644 index 000000000..0789dee01 --- /dev/null +++ b/web_responsive/static/src/xml/discuss.xml @@ -0,0 +1,16 @@ + + + diff --git a/web_responsive/static/src/xml/form_buttons.xml b/web_responsive/static/src/xml/form_buttons.xml new file mode 100644 index 000000000..2e860965b --- /dev/null +++ b/web_responsive/static/src/xml/form_buttons.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + e + + + + d + + + + + + Edit + + + + + + Create + + + + + + Save + + + + + + Discard + + + + + + + + + + + + + + + + d + + + + + + Create + + + + + + Save + + + + + + Discard + + + + + + + + + Today + + + + diff --git a/web_responsive/static/src/xml/menu.xml b/web_responsive/static/src/xml/menu.xml new file mode 100644 index 000000000..075cd49db --- /dev/null +++ b/web_responsive/static/src/xml/menu.xml @@ -0,0 +1,11 @@ + + +
+ + + Shift + +
+
diff --git a/web_responsive/static/src/xml/navbar.xml b/web_responsive/static/src/xml/navbar.xml new file mode 100644 index 000000000..1d9654ab3 --- /dev/null +++ b/web_responsive/static/src/xml/navbar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/web_responsive/static/src/xml/search_panel.xml b/web_responsive/static/src/xml/search_panel.xml new file mode 100644 index 000000000..a1cc9db9b --- /dev/null +++ b/web_responsive/static/src/xml/search_panel.xml @@ -0,0 +1,53 @@ + + + + + +
+
+ + + + + + + All +
+
+
+ + +
+ + + FILTER + +
+ +
+ SEE RESULT +
+
+ + diff --git a/web_responsive/tests/__init__.py b/web_responsive/tests/__init__.py new file mode 100644 index 000000000..03c963d72 --- /dev/null +++ b/web_responsive/tests/__init__.py @@ -0,0 +1 @@ +from . import test_res_users diff --git a/web_responsive/tests/test_res_users.py b/web_responsive/tests/test_res_users.py new file mode 100644 index 000000000..07619ef22 --- /dev/null +++ b/web_responsive/tests/test_res_users.py @@ -0,0 +1,13 @@ +# Copyright 2018 Alexandre Díaz +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo.tests import common + + +class TestResUsers(common.TransactionCase): + def test_chatter_position_wr(self): + user_public = self.env.ref("base.public_user") + + self.assertEqual(user_public.chatter_position, "sided") + user_public.with_user(user_public).write({"chatter_position": "normal"}) + self.assertEqual(user_public.chatter_position, "normal") diff --git a/web_responsive/views/assets.xml b/web_responsive/views/assets.xml new file mode 100644 index 000000000..291ef6705 --- /dev/null +++ b/web_responsive/views/assets.xml @@ -0,0 +1,38 @@ + + + +