mirror of https://github.com/OCA/web.git
Merge pull request #740 from PESOL/11.0-mig-web_responsive
[MIG] [11.0] web_responsivepull/747/head
commit
2fbc61fa40
|
@ -0,0 +1,96 @@
|
|||
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg
|
||||
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
|
||||
:alt: License: LGPL-3
|
||||
|
||||
==============
|
||||
Web Responsive
|
||||
==============
|
||||
|
||||
This module provides a mobile compliant interface for Odoo Community web.
|
||||
|
||||
Features:
|
||||
|
||||
* New navigation with an App drawer
|
||||
* Keyboard shortcuts for easier navigation
|
||||
* Display kanban views for small screens if an action or field One2x
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Keyboard Shortcuts
|
||||
------------------
|
||||
|
||||
The following keyboard shortcuts are implemented:
|
||||
|
||||
* Toggle App Drawer - `ActionKey <https://en.wikipedia.org/wiki/Access_key#Access_in_different_browsers>` + ``A``
|
||||
* Navigate Apps Drawer - Arrow Keys
|
||||
* Type to select App Links
|
||||
* ``esc`` to close App Drawer
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/162/10.0
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
Note: Data added to the footer ``support_branding`` is not shown while using
|
||||
this module.
|
||||
|
||||
* Provide full menu search feature instead of just App search
|
||||
* Drag drawer from left to open in mobile
|
||||
* Figure out how to test focus on hidden elements for keyboard nav tests
|
||||
* If you resize the window, body gets a wrong ``overflow: auto`` css property
|
||||
and you need to refresh your view or open/close the app drawer to fix that.
|
||||
* Override LESS styling to allow for responsive widget layouts
|
||||
* Adding ``oe_main_menu_navbar`` ID to the top navigation bar triggers some
|
||||
great styles, but also `JavaScript that causes issues on mobile
|
||||
<https://github.com/OCA/web/pull/446#issuecomment-254827880>`_
|
||||
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues
|
||||
<https://github.com/OCA/web/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.
|
||||
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Dave Lasley <dave@laslabs.com>
|
||||
* Jairo Llopis <jairo.llopis@tecnativa.com>
|
||||
* Dennis Sluijk <d.sluijk@onestein.nl>
|
||||
* Sergio Teruel <sergio.teruel@tecnativa.com>
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
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.
|
||||
|
||||
To contribute to this module, please visit https://odoo-community.org.
|
|
@ -0,0 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016-2017 LasLabs Inc.
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
{
|
||||
"name": "Web Responsive",
|
||||
"summary": "It provides a mobile compliant interface for Odoo Community "
|
||||
"web",
|
||||
"version": "11.0.1.0.0",
|
||||
"category": "Website",
|
||||
"website": "https://laslabs.com/",
|
||||
"author": "LasLabs, Tecnativa, Odoo Community Association (OCA)",
|
||||
"license": "LGPL-3",
|
||||
"installable": True,
|
||||
"depends": [
|
||||
'web',
|
||||
],
|
||||
"data": [
|
||||
'views/assets.xml',
|
||||
'views/web.xml',
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/form_view.xml',
|
||||
'static/src/xml/navbar.xml',
|
||||
],
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * web_responsive
|
||||
#
|
||||
# Translators:
|
||||
# Niki Waibel <niki.waibel@gmail.com>, 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: 2017-02-03 01:37+0000\n"
|
||||
"Last-Translator: Niki Waibel <niki.waibel@gmail.com>, 2017\n"
|
||||
"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
|
||||
msgstr "<span class=\"sr-only\">App Ordner umschalten</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle Navigation</span>"
|
||||
msgstr "<span class=\"sr-only\">Navigation umschalten</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "Apps"
|
||||
msgstr "Apps"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "More <b class=\"caret\"/>"
|
||||
msgstr "Mehr <b class=\"caret\"/>"
|
|
@ -0,0 +1,39 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * web_responsive
|
||||
#
|
||||
# Translators:
|
||||
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-12-23 02:13+0000\n"
|
||||
"PO-Revision-Date: 2016-12-23 02:13+0000\n"
|
||||
"Last-Translator: Pedro M. Baeza <pedro.baeza@gmail.com>, 2016\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
|
||||
msgstr "<span class=\"sr-only\">Mostrar/ocultar selector de aplicaciones</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle Navigation</span>"
|
||||
msgstr "<span class=\"sr-only\">Mostrar/Ocultar navegación</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "Apps"
|
||||
msgstr "Aplicaciones"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "More <b class=\"caret\"/>"
|
||||
msgstr "Más <b class=\"caret\"/>"
|
|
@ -0,0 +1,39 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * web_responsive
|
||||
#
|
||||
# Translators:
|
||||
# Bole <bole@dajmi5.com>, 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 <bole@dajmi5.com>, 2017\n"
|
||||
"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: hr\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
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
|
||||
msgstr "<span class=\"sr-only\">Izmjeni izbornik aplikacije</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle Navigation</span>"
|
||||
msgstr "<span class=\"sr-only\">Izmjeni navigaciju</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "Apps"
|
||||
msgstr "Apikacije"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "More <b class=\"caret\"/>"
|
||||
msgstr "Više <b class=\"caret\"/>"
|
|
@ -0,0 +1,39 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * web_responsive
|
||||
#
|
||||
# Translators:
|
||||
# Rodrigo de Almeida Sottomaior Macedo <rmsolucoeseminformatic4@gmail.com>, 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: 2017-06-22 08:27+0000\n"
|
||||
"Last-Translator: Rodrigo de Almeida Sottomaior Macedo <rmsolucoeseminformatic4@gmail.com>, 2017\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/teams/23907/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
|
||||
msgstr "<span class=\"sr-only\">Aplicativo Desenhador Alternativo</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.webclient_bootstrap
|
||||
msgid "<span class=\"sr-only\">Toggle Navigation</span>"
|
||||
msgstr "<span class=\"sr-only\">Navegação Alternativa</span>"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "Apps"
|
||||
msgstr "Aplicativos"
|
||||
|
||||
#. module: web_responsive
|
||||
#: model:ir.ui.view,arch_db:web_responsive.menu
|
||||
msgid "More <b class=\"caret\"/>"
|
||||
msgstr "Mais <b class=\"caret\"/>"
|
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -0,0 +1,510 @@
|
|||
/*!
|
||||
* jquery-drawer v3.2.0
|
||||
* Flexible drawer menu using jQuery, iScroll and CSS.
|
||||
* http://git.blivesta.com/drawer
|
||||
* License : MIT
|
||||
* Author : blivesta <design@blivesta.com> (http://blivesta.com/)
|
||||
*/
|
||||
|
||||
/*!------------------------------------*\
|
||||
Base
|
||||
\*!------------------------------------*/
|
||||
.drawer-nav {
|
||||
position: fixed;
|
||||
z-index: 101;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
width: 16.25rem;
|
||||
height: 100%;
|
||||
color: #222;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.drawer-brand {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
line-height: 3.75rem;
|
||||
display: block;
|
||||
padding-right: .75rem;
|
||||
padding-left: .75rem;
|
||||
text-decoration: none;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.drawer-menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.drawer-menu-item {
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
padding: .75rem;
|
||||
text-decoration: none;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.drawer-menu-item:hover {
|
||||
text-decoration: underline;
|
||||
color: #555;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/*! overlay */
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.drawer-open .drawer-overlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* XXX: local patch waiting for:
|
||||
https://github.com/blivesta/drawer/pull/36
|
||||
*/
|
||||
.drawer-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
/* end local patch */
|
||||
|
||||
/*!------------------------------------*\
|
||||
Top
|
||||
\*!------------------------------------*/
|
||||
.drawer--top .drawer-nav {
|
||||
top: -100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
-webkit-transition: top .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
transition: top .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
}
|
||||
|
||||
.drawer--top.drawer-open .drawer-nav {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.drawer--top .drawer-hamburger,
|
||||
.drawer--top.drawer-open .drawer-hamburger {
|
||||
right: 0;
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Left
|
||||
\*!------------------------------------*/
|
||||
.drawer--left .drawer-nav {
|
||||
left: -16.25rem;
|
||||
-webkit-transition: left .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
transition: left .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
}
|
||||
|
||||
.drawer--left.drawer-open .drawer-nav,
|
||||
.drawer--left .drawer-hamburger,
|
||||
.drawer--left.drawer-open .drawer-navbar .drawer-hamburger {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.drawer--left.drawer-open .drawer-hamburger {
|
||||
left: 16.25rem;
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Right
|
||||
\*!------------------------------------*/
|
||||
.drawer--right .drawer-nav {
|
||||
right: -16.25rem;
|
||||
-webkit-transition: right .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
transition: right .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
}
|
||||
|
||||
.drawer--right.drawer-open .drawer-nav,
|
||||
.drawer--right .drawer-hamburger,
|
||||
.drawer--right.drawer-open .drawer-navbar .drawer-hamburger {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.drawer--right.drawer-open .drawer-hamburger {
|
||||
right: 16.25rem;
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Hamburger
|
||||
\*!------------------------------------*/
|
||||
.drawer-hamburger {
|
||||
position: fixed;
|
||||
z-index: 104;
|
||||
top: 0;
|
||||
display: block;
|
||||
box-sizing: content-box;
|
||||
width: 2rem;
|
||||
padding: 0;
|
||||
padding-top: 18px;
|
||||
padding-right: .75rem;
|
||||
padding-bottom: 30px;
|
||||
padding-left: .75rem;
|
||||
-webkit-transition: all .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
transition: all .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.drawer-hamburger:hover {
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.drawer-hamburger-icon {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.drawer-hamburger-icon,
|
||||
.drawer-hamburger-icon:before,
|
||||
.drawer-hamburger-icon:after {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
-webkit-transition: all .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
transition: all .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.drawer-hamburger-icon:before,
|
||||
.drawer-hamburger-icon:after {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
.drawer-hamburger-icon:after {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.drawer-open .drawer-hamburger-icon {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.drawer-open .drawer-hamburger-icon:before,
|
||||
.drawer-open .drawer-hamburger-icon:after {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.drawer-open .drawer-hamburger-icon:before {
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.drawer-open .drawer-hamburger-icon:after {
|
||||
-webkit-transform: rotate(-45deg);
|
||||
-ms-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
accessibility
|
||||
\*!------------------------------------*/
|
||||
|
||||
/*!
|
||||
* Only display content to screen readers
|
||||
* See: http://a11yproject.com/posts/how-to-hide-content
|
||||
*/
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Use in conjunction with .sr-only to only display content when it's focused.
|
||||
* Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
|
||||
* Credit: HTML5 Boilerplate
|
||||
*/
|
||||
.sr-only-focusable:active,
|
||||
.sr-only-focusable:focus {
|
||||
position: static;
|
||||
overflow: visible;
|
||||
clip: auto;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Sidebar
|
||||
\*!------------------------------------*/
|
||||
.drawer--sidebar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.drawer--sidebar .drawer-contents {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
@media (min-width: 64em) {
|
||||
.drawer--sidebar .drawer-hamburger {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.drawer--sidebar .drawer-nav {
|
||||
display: block;
|
||||
-webkit-transform: none;
|
||||
-ms-transform: none;
|
||||
transform: none;
|
||||
position: fixed;
|
||||
width: 12.5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*! Left */
|
||||
.drawer--sidebar.drawer--left .drawer-nav {
|
||||
left: 0;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.drawer--sidebar.drawer--left .drawer-contents {
|
||||
margin-left: 12.5rem;
|
||||
}
|
||||
|
||||
/*! Right */
|
||||
.drawer--sidebar.drawer--right .drawer-nav {
|
||||
right: 0;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.drawer--sidebar.drawer--right .drawer-contents {
|
||||
margin-right: 12.5rem;
|
||||
}
|
||||
|
||||
/*! container */
|
||||
.drawer--sidebar .drawer-container {
|
||||
max-width: 48rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 75em) {
|
||||
.drawer--sidebar .drawer-nav {
|
||||
width: 16.25rem;
|
||||
}
|
||||
|
||||
.drawer--sidebar.drawer--left .drawer-contents {
|
||||
margin-left: 16.25rem;
|
||||
}
|
||||
|
||||
.drawer--sidebar.drawer--right .drawer-contents {
|
||||
margin-right: 16.25rem;
|
||||
}
|
||||
|
||||
/*! container */
|
||||
.drawer--sidebar .drawer-container {
|
||||
max-width: 60rem;
|
||||
}
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Navbar
|
||||
\*!------------------------------------*/
|
||||
.drawer--navbarTopGutter {
|
||||
padding-top: 3.75rem;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-navbar-header {
|
||||
border-bottom: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.drawer-navbar {
|
||||
z-index: 102;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*! .drawer-navbar modifier */
|
||||
.drawer-navbar--fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.drawer-navbar-header {
|
||||
position: relative;
|
||||
z-index: 102;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 3.75rem;
|
||||
padding: 0 .75rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-brand {
|
||||
line-height: 3.75rem;
|
||||
display: inline-block;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-brand:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-nav {
|
||||
padding-top: 3.75rem;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-menu {
|
||||
padding-bottom: 7.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 64em) {
|
||||
.drawer-navbar {
|
||||
height: 3.75rem;
|
||||
border-bottom: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-navbar-header {
|
||||
position: relative;
|
||||
display: block;
|
||||
float: left;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-menu--right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-menu li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-menu-item {
|
||||
line-height: 3.75rem;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-hamburger {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-nav {
|
||||
position: relative;
|
||||
left: 0;
|
||||
overflow: visible;
|
||||
width: auto;
|
||||
height: 3.75rem;
|
||||
padding-top: 0;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-menu {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*! dropdown */
|
||||
.drawer-navbar .drawer-dropdown-menu {
|
||||
position: absolute;
|
||||
width: 16.25rem;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.drawer-navbar .drawer-dropdown-menu-item {
|
||||
padding-left: .75rem;
|
||||
}
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Dropdown
|
||||
\*!------------------------------------*/
|
||||
.drawer-dropdown-menu {
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.drawer-dropdown-menu > li {
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.drawer-dropdown-menu-item {
|
||||
line-height: 3.75rem;
|
||||
display: block;
|
||||
padding: 0;
|
||||
padding-right: .75rem;
|
||||
padding-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.drawer-dropdown-menu-item:hover {
|
||||
text-decoration: underline;
|
||||
color: #555;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/*! open */
|
||||
.drawer-dropdown.open > .drawer-dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*! drawer-caret */
|
||||
.drawer-dropdown .drawer-caret {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 4px;
|
||||
-webkit-transition: opacity .2s ease, -webkit-transform .2s ease;
|
||||
transition: opacity .2s ease, -webkit-transform .2s ease;
|
||||
transition: transform .2s ease, opacity .2s ease;
|
||||
transition: transform .2s ease, opacity .2s ease, -webkit-transform .2s ease;
|
||||
-webkit-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
vertical-align: middle;
|
||||
border-top: 4px solid;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
/*! open */
|
||||
.drawer-dropdown.open .drawer-caret {
|
||||
-webkit-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
/*!------------------------------------*\
|
||||
Container
|
||||
\*!------------------------------------*/
|
||||
.drawer-container {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 64em) {
|
||||
.drawer-container {
|
||||
max-width: 60rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 75em) {
|
||||
.drawer-container {
|
||||
max-width: 70rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*!
|
||||
* jquery-drawer v3.2.0
|
||||
* Flexible drawer menu using jQuery, iScroll and CSS.
|
||||
* http://git.blivesta.com/drawer
|
||||
* License : MIT
|
||||
* Author : blivesta <design@blivesta.com> (http://blivesta.com/)
|
||||
*/
|
||||
|
||||
;(function umd(factory) {
|
||||
'use strict';
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
module.exports = factory(require('jquery'));
|
||||
} else {
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function Drawer($) {
|
||||
'use strict';
|
||||
var namespace = 'drawer';
|
||||
var touches = typeof document.ontouchstart != 'undefined';
|
||||
var __ = {
|
||||
init: function init(options) {
|
||||
options = $.extend({
|
||||
iscroll: {
|
||||
mouseWheel: true,
|
||||
preventDefault: false
|
||||
},
|
||||
showOverlay: true
|
||||
}, options);
|
||||
|
||||
__.settings = {
|
||||
state: false,
|
||||
events: {
|
||||
opened: 'drawer.opened',
|
||||
closed: 'drawer.closed'
|
||||
},
|
||||
dropdownEvents: {
|
||||
opened: 'shown.bs.dropdown',
|
||||
closed: 'hidden.bs.dropdown'
|
||||
}
|
||||
};
|
||||
|
||||
__.settings.class = $.extend({
|
||||
nav: 'drawer-nav',
|
||||
toggle: 'drawer-toggle',
|
||||
overlay: 'drawer-overlay',
|
||||
open: 'drawer-open',
|
||||
close: 'drawer-close',
|
||||
dropdown: 'drawer-dropdown'
|
||||
}, options.class);
|
||||
|
||||
return this.each(function instantiateDrawer() {
|
||||
var _this = this;
|
||||
var $this = $(this);
|
||||
var data = $this.data(namespace);
|
||||
|
||||
if (!data) {
|
||||
options = $.extend({}, options);
|
||||
$this.data(namespace, { options: options });
|
||||
|
||||
__.refresh.call(_this);
|
||||
|
||||
if (options.showOverlay) {
|
||||
__.addOverlay.call(_this);
|
||||
}
|
||||
|
||||
$('.' + __.settings.class.toggle).on('click.' + namespace, function toggle() {
|
||||
__.toggle.call(_this);
|
||||
return _this.iScroll.refresh();
|
||||
});
|
||||
|
||||
$(window).resize(function close() {
|
||||
__.close.call(_this);
|
||||
return _this.iScroll.refresh();
|
||||
});
|
||||
|
||||
$('.' + __.settings.class.dropdown)
|
||||
.on(__.settings.dropdownEvents.opened + ' ' + __.settings.dropdownEvents.closed, function onOpenedOrClosed() {
|
||||
return _this.iScroll.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
}); // end each
|
||||
},
|
||||
|
||||
refresh: function refresh() {
|
||||
this.iScroll = new IScroll(
|
||||
'.' + __.settings.class.nav,
|
||||
$(this).data(namespace).options.iscroll
|
||||
);
|
||||
},
|
||||
|
||||
addOverlay: function addOverlay() {
|
||||
var _this = this;
|
||||
var $this = $(this);
|
||||
var $overlay = $('<div>').addClass(__.settings.class.overlay + ' ' + __.settings.class.toggle);
|
||||
|
||||
return $this.append($overlay);
|
||||
},
|
||||
|
||||
toggle: function toggle() {
|
||||
var _this = this;
|
||||
|
||||
if (__.settings.state) {
|
||||
return __.close.call(_this);
|
||||
} else {
|
||||
return __.open.call(_this);
|
||||
}
|
||||
},
|
||||
|
||||
open: function open() {
|
||||
var $this = $(this);
|
||||
|
||||
if (touches) {
|
||||
$this.on('touchmove.' + namespace, function disableTouch(event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
return $this
|
||||
.removeClass(__.settings.class.close)
|
||||
.addClass(__.settings.class.open)
|
||||
// XXX: local patch waiting for:
|
||||
// https://github.com/blivesta/drawer/pull/36
|
||||
//.css({ 'overflow': 'hidden' })
|
||||
// end local patch
|
||||
.drawerCallback(function triggerOpenedListeners() {
|
||||
__.settings.state = true;
|
||||
$this.trigger(__.settings.events.opened);
|
||||
});
|
||||
},
|
||||
|
||||
close: function close() {
|
||||
var $this = $(this);
|
||||
|
||||
if (touches) $this.off('touchmove.' + namespace);
|
||||
|
||||
return $this
|
||||
.removeClass(__.settings.class.open)
|
||||
.addClass(__.settings.class.close)
|
||||
// XXX: local patch waiting for:
|
||||
// https://github.com/blivesta/drawer/pull/36
|
||||
//.css("overflow", "auto")
|
||||
// end local patch
|
||||
.drawerCallback(function triggerClosedListeners() {
|
||||
__.settings.state = false;
|
||||
$this.trigger(__.settings.events.closed);
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function destroy() {
|
||||
return this.each(function destroyEach() {
|
||||
var $this = $(this);
|
||||
$(window).off('.' + namespace);
|
||||
$this.removeData(namespace);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.drawerCallback = function drawerCallback(callback) {
|
||||
var end = 'transitionend webkitTransitionEnd';
|
||||
return this.each(function setAnimationEndHandler() {
|
||||
var $this = $(this);
|
||||
$this.on(end, function invokeCallbackOnAnimationEnd() {
|
||||
$this.off(end);
|
||||
return callback.call(this);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.drawer = function drawer(method) {
|
||||
if (__[method]) {
|
||||
return __[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return __.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist on jQuery.' + namespace);
|
||||
}
|
||||
};
|
||||
|
||||
}));
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,313 @@
|
|||
/* Copyright 2016 LasLabs Inc.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
odoo.define('web_responsive', function(require) {
|
||||
'use strict';
|
||||
|
||||
var Menu = require('web.Menu');
|
||||
var Class = require('web.Class');
|
||||
var SearchView = require('web.SearchView');
|
||||
var core = require('web.core');
|
||||
var config = require('web.config');
|
||||
var FieldOne2Many = core.form_widget_registry.get('one2many');
|
||||
var ViewManager = require('web.ViewManager');
|
||||
|
||||
Menu.include({
|
||||
|
||||
// Force all_outside to prevent app icons from going into more menu
|
||||
reflow: function() {
|
||||
this._super('all_outside');
|
||||
},
|
||||
|
||||
/* Overload to collapse unwanted visible submenus
|
||||
* @param allow_open bool Switch to allow submenus to be opened
|
||||
*/
|
||||
open_menu: function(id, allowOpen) {
|
||||
this._super(id);
|
||||
if (allowOpen) {
|
||||
return;
|
||||
};
|
||||
var $clicked_menu = this.$secondary_menus.find('a[data-menu=' + id + ']');
|
||||
$clicked_menu.parents('.oe_secondary_submenu').css('display', '');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
SearchView.include({
|
||||
|
||||
// Prevent focus of search field on mobile devices
|
||||
toggle_visibility: function(is_visible) {
|
||||
$('div.oe_searchview_input').last().one(
|
||||
'focus', $.proxy(this.preventMobileFocus, this));
|
||||
return this._super(is_visible);
|
||||
},
|
||||
|
||||
// It prevents focusing of search el on mobile
|
||||
preventMobileFocus: function(event) {
|
||||
if (this.isMobile()) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
// For lack of Modernizr, TouchEvent will do
|
||||
isMobile: function() {
|
||||
try {
|
||||
document.createEvent('TouchEvent');
|
||||
return true;
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var AppDrawer = Class.extend({
|
||||
|
||||
LEFT: 'left',
|
||||
RIGHT: 'right',
|
||||
UP: 'up',
|
||||
DOWN: 'down',
|
||||
|
||||
isOpen: false,
|
||||
keyBuffer: '',
|
||||
keyBufferTime: 500,
|
||||
keyBufferTimeoutEvent: false,
|
||||
dropdownHeightFactor: 0.90,
|
||||
initialized: false,
|
||||
|
||||
init: function() {
|
||||
this.directionCodes = {
|
||||
'left': this.LEFT,
|
||||
'right': this.RIGHT,
|
||||
'up': this.UP,
|
||||
'pageup': this.UP,
|
||||
'down': this.DOWN,
|
||||
'pagedown': this.DOWN,
|
||||
'+': this.RIGHT,
|
||||
'-': this.LEFT
|
||||
};
|
||||
this.initDrawer();
|
||||
var $clickZones = $('.odoo_webclient_container, ' +
|
||||
'a.oe_menu_leaf, ' +
|
||||
'a.oe_menu_toggler, ' +
|
||||
'a.oe_logo, ' +
|
||||
'i.oe_logo_edit'
|
||||
);
|
||||
$clickZones.click($.proxy(this.handleClickZones, this));
|
||||
core.bus.on('resize', this, this.handleWindowResize);
|
||||
core.bus.on('keydown', this, this.handleNavKeys);
|
||||
},
|
||||
|
||||
// It provides initialization handlers for Drawer
|
||||
initDrawer: function() {
|
||||
this.$el = $('.drawer');
|
||||
this.$el.drawer();
|
||||
this.$el.one('drawer.opened', $.proxy(this.onDrawerOpen, this));
|
||||
this.$el.on('drawer.opened', function setIScrollProbes() {
|
||||
var onIScroll = function() {
|
||||
var transform = this.iScroll.y ? this.iScroll.y * -1 : 0;
|
||||
$(this).find('#appDrawerAppPanelHead').css(
|
||||
'transform', 'matrix(1, 0, 0, 1, 0, ' + transform + ')'
|
||||
);
|
||||
};
|
||||
this.iScroll.options.probeType = 2;
|
||||
this.iScroll.on('scroll', $.proxy(onIScroll, this));
|
||||
});
|
||||
this.initialized = true;
|
||||
},
|
||||
|
||||
// It provides handlers to hide drawer when "unfocused"
|
||||
handleClickZones: function() {
|
||||
this.$el.drawer('close');
|
||||
$('.o_sub_menu_content')
|
||||
.parent()
|
||||
.collapse('hide');
|
||||
},
|
||||
|
||||
// It resizes bootstrap dropdowns for screen
|
||||
handleWindowResize: function() {
|
||||
$('.dropdown-scrollable').css(
|
||||
'max-height', $(window).height() * this.dropdownHeightFactor
|
||||
);
|
||||
},
|
||||
|
||||
// It provides keyboard shortcuts for app drawer nav
|
||||
handleNavKeys: function(e) {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
var directionCode = $.hotkeys.specialKeys[e.keyCode.toString()];
|
||||
if (Object.keys(this.directionCodes).indexOf(directionCode) !== -1) {
|
||||
var $link = this.findAdjacentAppLink(
|
||||
this.$el.find('a:first, a:focus').last(),
|
||||
this.directionCodes[directionCode]
|
||||
);
|
||||
this.selectAppLink($link);
|
||||
} else if ($.hotkeys.specialKeys[e.keyCode.toString()] === 'esc') {
|
||||
this.handleClickZones();
|
||||
} else {
|
||||
var buffer = this.handleKeyBuffer(e.keyCode);
|
||||
this.selectAppLink(this.searchAppLinks(buffer));
|
||||
}
|
||||
},
|
||||
|
||||
/* It adds to keybuffer, sets expire timer, and returns buffer
|
||||
* @returns str of current buffer
|
||||
*/
|
||||
handleKeyBuffer: function(keyCode) {
|
||||
this.keyBuffer += String.fromCharCode(keyCode);
|
||||
if (this.keyBufferTimeoutEvent) {
|
||||
clearTimeout(this.keyBufferTimeoutEvent);
|
||||
}
|
||||
this.keyBufferTimeoutEvent = setTimeout(
|
||||
$.proxy(this.clearKeyBuffer, this),
|
||||
this.keyBufferTime
|
||||
);
|
||||
return this.keyBuffer;
|
||||
},
|
||||
|
||||
clearKeyBuffer: function() {
|
||||
this.keyBuffer = '';
|
||||
},
|
||||
|
||||
/* It performs close actions
|
||||
* @fires ``drawer.closed`` to the ``core.bus``
|
||||
* @listens ``drawer.opened`` and sends to onDrawerOpen
|
||||
*/
|
||||
onDrawerClose: function() {
|
||||
core.bus.trigger('drawer.closed');
|
||||
this.$el.one('drawer.opened', $.proxy(this.onDrawerOpen, this));
|
||||
this.isOpen = false;
|
||||
// Remove inline style inserted by drawer.js
|
||||
this.$el.css("overflow", "");
|
||||
},
|
||||
|
||||
/* It finds app links and register event handlers
|
||||
* @fires ``drawer.opened`` to the ``core.bus``
|
||||
* @listens ``drawer.closed`` and sends to :meth:``onDrawerClose``
|
||||
*/
|
||||
onDrawerOpen: function() {
|
||||
this.$appLinks = $('.app-drawer-icon-app').parent();
|
||||
this.selectAppLink($(this.$appLinks[0]));
|
||||
this.$el.one('drawer.closed', $.proxy(this.onDrawerClose, this));
|
||||
core.bus.trigger('drawer.opened');
|
||||
this.isOpen = true;
|
||||
},
|
||||
|
||||
// It selects an app link visibly
|
||||
selectAppLink: function($appLink) {
|
||||
if ($appLink) {
|
||||
$appLink.focus();
|
||||
}
|
||||
},
|
||||
|
||||
/* It returns first App Link by its name according to query
|
||||
* @param query str to search
|
||||
* @return jQuery obj
|
||||
*/
|
||||
searchAppLinks: function(query) {
|
||||
return this.$appLinks.filter(function() {
|
||||
return $(this).data('menuName').toUpperCase().startsWith(query);
|
||||
}).first();
|
||||
},
|
||||
|
||||
/* It returns the link adjacent to $appLink in provided direction.
|
||||
* It also handles edge cases in the following ways:
|
||||
* * Moves to last link if LEFT on first
|
||||
* * Moves to first link if PREV on last
|
||||
* * Moves to first link of following row if RIGHT on last in row
|
||||
* * Moves to last link of previous row if LEFT on first in row
|
||||
* * Moves to top link in same column if DOWN on bottom row
|
||||
* * Moves to bottom link in same column if UP on top row
|
||||
* @param $appLink jQuery obj of App icon link
|
||||
* @param direction str of direction to go (constants LEFT, UP, etc.)
|
||||
* @return jQuery obj for adjacent applink
|
||||
*/
|
||||
findAdjacentAppLink: function($appLink, direction) {
|
||||
|
||||
var obj = [],
|
||||
$objs = this.$appLinks;
|
||||
|
||||
switch (direction) {
|
||||
case this.LEFT:
|
||||
obj = $objs[$objs.index($appLink) - 1];
|
||||
if (!obj) {
|
||||
obj = $objs[$objs.length - 1];
|
||||
}
|
||||
break;
|
||||
case this.RIGHT:
|
||||
obj = $objs[$objs.index($appLink) + 1];
|
||||
if (!obj) {
|
||||
obj = $objs[0];
|
||||
}
|
||||
break;
|
||||
case this.UP:
|
||||
$objs = this.getRowObjs($appLink, this.$appLinks);
|
||||
obj = $objs[$objs.index($appLink) - 1];
|
||||
if (!obj) {
|
||||
obj = $objs[$objs.length - 1];
|
||||
}
|
||||
break;
|
||||
case this.DOWN:
|
||||
$objs = this.getRowObjs($appLink, this.$appLinks);
|
||||
obj = $objs[$objs.index($appLink) + 1];
|
||||
if (!obj) {
|
||||
obj = $objs[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (obj.length) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return $(obj);
|
||||
|
||||
},
|
||||
|
||||
/* It returns els in the same row
|
||||
* @param @obj jQuery object to get row for
|
||||
* @param $grid jQuery objects representing grid
|
||||
* @return $objs jQuery objects of row
|
||||
*/
|
||||
getRowObjs: function($obj, $grid) {
|
||||
// Filter by object which middle lies within left/right bounds
|
||||
function filterWithin(left, right) {
|
||||
return function() {
|
||||
var $this = $(this),
|
||||
thisMiddle = $this.offset().left + $this.width() / 2;
|
||||
return thisMiddle >= left && thisMiddle <= right;
|
||||
};
|
||||
}
|
||||
var left = $obj.offset().left,
|
||||
right = left + $obj.outerWidth();
|
||||
return $grid.filter(filterWithin(left, right));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// It inits a new AppDrawer when the web client is ready
|
||||
core.bus.on('web_client_ready', null, function() {
|
||||
new AppDrawer();
|
||||
});
|
||||
|
||||
// if we are in small screen change default view to kanban if exists
|
||||
ViewManager.include({
|
||||
get_default_view: function() {
|
||||
var default_view = this._super()
|
||||
if (config.device.size_class <= config.device.SIZES.XS &&
|
||||
default_view.type !== 'kanban' &&
|
||||
this.views.kanban) {
|
||||
default_view.type = 'kanban';
|
||||
};
|
||||
return default_view;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
'AppDrawer': AppDrawer,
|
||||
'SearchView': SearchView,
|
||||
'Menu': Menu,
|
||||
'ViewManager': ViewManager,
|
||||
};
|
||||
|
||||
});
|
|
@ -0,0 +1,115 @@
|
|||
/* Copyright 2016 LasLabs Inc.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
.app-drawer-nav {
|
||||
border-color: @dropdown-border;
|
||||
background-color: @dropdown-bg;
|
||||
border: 1px solid @dropdown-fallback-border; // IE8 fallback
|
||||
border: 1px solid @dropdown-border;
|
||||
-webkit-border-radius: @border-radius-base;
|
||||
-moz-border-radius: @border-radius-base;
|
||||
border-radius: @border-radius-base;
|
||||
.box-shadow(0 6px 12px rgba(0, 0, 0, .175));
|
||||
background-clip: padding-box;
|
||||
z-index: 10000;
|
||||
|
||||
.o_tooltip {
|
||||
z-index: 1051;
|
||||
}
|
||||
|
||||
.oe_logo {
|
||||
margin-top: -11px;
|
||||
position: relative;
|
||||
img {
|
||||
height: @app-drawer-title-height;
|
||||
}
|
||||
.oe_logo_edit {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
display: none;
|
||||
color: @odoo-list-footer-bg-color;
|
||||
background: rgba(37,37,37,0.9);
|
||||
}
|
||||
&:hover .oe_logo_edit_admin {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-left {
|
||||
width: 100%;
|
||||
|
||||
li {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.app-drawer-title {
|
||||
float: none;
|
||||
font-weight: bold; // Bold titles for apps in the app-drawer
|
||||
}
|
||||
|
||||
.app-drawer-panel-title {
|
||||
line-height: 16px;
|
||||
> .drawer-toggle {
|
||||
padding-top: 17px;
|
||||
padding-bottom: 17px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.app-drawer-icon-app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
max-width: @app-drawer-icon-size;
|
||||
max-height: @app-drawer-icon-size;
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
padding-top: @app-drawer-title-height;
|
||||
}
|
||||
|
||||
#appDrawerAppPanelHead {
|
||||
position: absolute;
|
||||
height: @app-drawer-title-height;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.drawer-nav {
|
||||
width: @app-drawer-width;
|
||||
}
|
||||
|
||||
.drawer--left .drawer-nav {
|
||||
left: -@app-drawer-width;
|
||||
}
|
||||
|
||||
.drawer--left.drawer-open .drawer-hamburger {
|
||||
left: @app-drawer-width;
|
||||
}
|
||||
|
||||
.drawer--right .drawer-nav {
|
||||
right: -@app-drawer-width;
|
||||
}
|
||||
|
||||
.drawer-open .oe-right-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.drawer-closed .oe-right-toolbar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* App Drawer Toggle */
|
||||
|
||||
.app-drawer-toggle {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.app-drawer-toggle.navbar-toggle {
|
||||
margin-left: 1em;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/* Copyright 2016 Ponto Suprimentos Ltda.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
.o_form_view {
|
||||
// Form must fill 100% width in any size
|
||||
.o_form_sheet_bg {
|
||||
padding: @sheet-padding;
|
||||
|
||||
.o_form_sheet {
|
||||
min-width: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm-max) {
|
||||
padding: 0;
|
||||
|
||||
.o_form_sheet {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No overflowing buttons or titles
|
||||
.oe_button_box, .oe_title {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs) {
|
||||
.o_form_field > .o_form_input_dropdown {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
.o_group {
|
||||
&.o_inner_group > tbody > tr > td {
|
||||
.note-editor > .note-toolbar {
|
||||
// prevent wysiwyg editor buttons from expanding the screen
|
||||
white-space: initial;
|
||||
}
|
||||
}
|
||||
// reduce form maximum columns for smaller screens
|
||||
@media (max-width: @screen-xs-max) {
|
||||
.o-generate-groups(12);
|
||||
.o-generate-groups(@n, @i: 1) when (@i =< @n) {
|
||||
.o_group_col_@{i} {
|
||||
width: 100%;
|
||||
}
|
||||
.o-generate-groups(@n, @i + 1);
|
||||
}
|
||||
}
|
||||
// break field label into a separate line from field on small screens
|
||||
@media (max-width: @screen-xs) {
|
||||
&.o_inner_group {
|
||||
display: block;
|
||||
> tbody {
|
||||
display: block;
|
||||
> tr {
|
||||
margin-top: 8px;
|
||||
.o-flex-display();
|
||||
.o-flex-flow(row, wrap);
|
||||
> td {
|
||||
.o-flex(1, 0, auto);
|
||||
padding: 0;
|
||||
display: block;
|
||||
padding: 0;
|
||||
// odoo adds a `style="width: 100%"` by javascript
|
||||
// directly on the tag so we need `!important` here:
|
||||
width: auto!important;
|
||||
max-width: 100%;
|
||||
&.o_td_label {
|
||||
border-right: 0;
|
||||
// keep 6% space on line to fit checkboxes
|
||||
// see above about `!important`
|
||||
width: 94%!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make image editing controls always available, instead of depending on resolution or hover
|
||||
.o_form_field_image > .o_form_image_controls {
|
||||
position: initial;
|
||||
opacity: 1;
|
||||
> .fa {
|
||||
width: 50%;
|
||||
padding: 6px;
|
||||
margin: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
> .fa.o_select_file_button {
|
||||
background: @odoo-brand-primary;
|
||||
}
|
||||
> .fa.o_clear_file_button {
|
||||
background: @brand-danger;
|
||||
}
|
||||
}
|
||||
|
||||
// Adapt chatter widget to small viewports
|
||||
.oe_chatter {
|
||||
min-width: inherit;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/* Copyright 2016 LasLabs Inc.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
// Do not fix the search part, it's too big for small screens
|
||||
@media (max-width: @screen-sm-max) {
|
||||
overflow: inherit;
|
||||
.odoo {
|
||||
.oe-view-manager {
|
||||
overflow: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.o_cp_switch_buttons {
|
||||
.active {
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.o_sub_menu {
|
||||
.o_sub_menu_logo {
|
||||
display: none;
|
||||
}
|
||||
.o_sub_menu_footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.o_tooltip.active {
|
||||
z-index: 1051;
|
||||
}
|
||||
|
||||
.o_web_client {
|
||||
>.o_main {
|
||||
overflow: auto;
|
||||
> .o_main_content {
|
||||
overflow: initial;
|
||||
> .o_content {
|
||||
@media (max-width: @screen-xs-max) {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
@media (min-width: @screen-sm-min) {
|
||||
// .o_content is the one to display horizontal scrolling in
|
||||
// case of wide tables
|
||||
.table-responsive {
|
||||
overflow-x: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm-max) {
|
||||
.o_control_panel {
|
||||
// Remove z-index from CP buttons so it doesn't overlap the menu
|
||||
.btn-group > .btn.active {
|
||||
z-index: initial;
|
||||
}
|
||||
|
||||
// Better horizontal space usage for buttons
|
||||
justify-content: space-between;
|
||||
.o_cp_left, .o_cp_right {
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.o_search_options > .o_dropdown {
|
||||
&.hidden-xs {
|
||||
// No other way to display "Group By" button :(
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
// Hack to hide text and display larger icons
|
||||
> .btn {
|
||||
font-size: 0;
|
||||
> .fa {
|
||||
font-size: @odoo-font-size-base * 1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_chat_window {
|
||||
z-index: 1000;
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/* Copyright 2016 LasLabs Inc.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
header {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
> .main-nav {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
|
||||
.navbar-systray {
|
||||
white-space: nowrap;
|
||||
@media (max-width: @screen-xs-max) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 56px;
|
||||
}
|
||||
> .oe_user_menu_placeholder > li > a {
|
||||
> .oe_topbar_avatar {
|
||||
border-radius: 50%;
|
||||
margin-top: -8px;
|
||||
max-height: 36px;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
}
|
||||
.oe_topbar_name {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
@media (max-width: @screen-xs-max) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.caret {
|
||||
position: relative;
|
||||
top: -3.5px;
|
||||
}
|
||||
}
|
||||
.o_switch_company_menu {
|
||||
.oe_topbar_name {
|
||||
@media (max-width: @screen-xs-max) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .oe_systray > li > a {
|
||||
.fa {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.caret {
|
||||
position: relative;
|
||||
top: 0.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
float: right;
|
||||
> li {
|
||||
float: left;
|
||||
}
|
||||
@media (max-width: @screen-xs-max) {
|
||||
.navbar-nav .open .dropdown-menu {
|
||||
position: fixed;
|
||||
top: 46px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
float: left;
|
||||
background-color: @odoo-view-background-color;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container-fluid:before, .container-fluid:after, .navbar-collapse:before, .navbar-collapse:after {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
> .container-fluid {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@media (max-width: @screen-xs-max) {
|
||||
> .navbar-collapse {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
&.collapsing {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .navbar-header {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
> .drawer-toggle, .navbar-toggle {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0px;
|
||||
border-radius: 0px;
|
||||
> i.fa, div.fa {
|
||||
padding: 17px 14px 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_sub_menu > .o_sub_menu_content > .oe_secondary_menu {
|
||||
ul.dropdown-menu > li.dropdown-header {
|
||||
color: @odoo-view-background-color;
|
||||
text-decoration: none;
|
||||
background-color: @odoo-main-color-muted;
|
||||
font-weight: bold;
|
||||
}
|
||||
@media (min-width: @screen-sm-min) {
|
||||
height: @navbar-height;
|
||||
}
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
> li {
|
||||
@media (min-width: @screen-sm-min) {
|
||||
height: @navbar-height;
|
||||
}
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
&.app-name {
|
||||
display: block;
|
||||
padding: 7px 8px;
|
||||
> .oe_menu_text {
|
||||
font-size: 20px;
|
||||
}
|
||||
@media (min-width: @screen-sm-min) {
|
||||
padding: 8.5px 12px;
|
||||
}
|
||||
}
|
||||
> a {
|
||||
margin: 0;
|
||||
@media (min-width: @screen-sm-min) {
|
||||
height: @navbar-height;
|
||||
padding: 14px 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .navbar-right.o_menu_systray {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
> ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
> li > a {
|
||||
margin: 0;
|
||||
padding: 13px 8px;
|
||||
height: @navbar-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: @navbar-padding-horizontal / 2;
|
||||
}
|
||||
|
||||
ul.nav > li > a {
|
||||
padding: @app-drawer-navbar-padding-vertical @app-drawer-padding-horizontal;
|
||||
}
|
||||
|
||||
.o_planner_systray > .progress {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.navbar-collapse.collapse {
|
||||
@media (min-width: @screen-sm-min) {
|
||||
padding-bottom: @app-drawer-navbar-padding-vertical;
|
||||
padding-top: @app-drawer-navbar-padding-vertical;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-scrollable {
|
||||
overflow-x: hidden;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* Copyright 2016 LasLabs Inc.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
// App Drawer / Icons
|
||||
@app-drawer-icon-size: 6em;
|
||||
@app-drawer-icon-margin: 1em;
|
||||
@app-drawer-width: 80%;
|
||||
@app-drawer-title-height: 54px;
|
||||
|
||||
// Navbar
|
||||
@navbar-height: 46px;
|
||||
@app-drawer-navbar-height: @navbar-height / 2;
|
||||
@app-drawer-navbar-padding-vertical: @navbar-padding-vertical / 2;
|
||||
@app-drawer-padding-horizontal: @navbar-padding-horizontal / 2;
|
||||
|
||||
// Drawer Toggle
|
||||
@drawer-toggle-height: @navbar-height;
|
||||
@drawer-toggle-width: @navbar-height;
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017 LasLabs Inc.
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
-->
|
||||
|
||||
<templates id="form_view" xml:space="preserve">
|
||||
|
||||
<t t-extend="FormView.buttons">
|
||||
<t t-jquery="button[accesskey='a']" t-operation="attributes">
|
||||
<attribute name="accesskey">e</attribute>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
|
||||
|
||||
<template>
|
||||
<t t-extend="SwitchCompanyMenu">
|
||||
<t t-jquery=".oe_topbar_name" t-operation="before">
|
||||
<i class="fa fa-building visible-xs-inline-block"/>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
|
@ -0,0 +1,278 @@
|
|||
/* Copyright 2016 LasLabs Inc.
|
||||
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
|
||||
|
||||
odoo.define_section('web_responsive', ['web_responsive'], function(test) {
|
||||
"use strict";
|
||||
|
||||
// It provides a base drawer compatible interface for testing
|
||||
self.initInterface = function(AppDrawer) {
|
||||
|
||||
var $el = $('<div class="drawer drawer--left">');
|
||||
$el.append(
|
||||
$('<header role="banner">')
|
||||
.append(
|
||||
$('<button class="drawer-toggle"><span class="drawer-hamburger-icon">')
|
||||
)
|
||||
.append(
|
||||
$('<nav class="drawer-nav"><ul class="drawer-menu"><li class="drawer-menu-item">')
|
||||
)
|
||||
.append(
|
||||
$('<div class="panel-title" id="appDrawerAppPanelHead">')
|
||||
)
|
||||
).append($('<main role="main">'));
|
||||
|
||||
self.$clickZone = $('<a class="oe_menu_leaf">');
|
||||
|
||||
self.$secondaryMenu = $('<div><div class="o_sub_menu_content">');
|
||||
|
||||
self.$dropdown = $('<div class="dropdown-scrollable">');
|
||||
|
||||
$el.append(self.$clickZone)
|
||||
.append(self.$secondaryMenu)
|
||||
.append(self.$dropdown);
|
||||
|
||||
var $document = $("#qunit-fixture");
|
||||
$document.append($el);
|
||||
|
||||
self.drawer = new AppDrawer.AppDrawer();
|
||||
|
||||
return $document;
|
||||
|
||||
};
|
||||
|
||||
self.linkGrid = function() {
|
||||
for(var i=0; i < 3; i++){
|
||||
self.drawer.$el.append(
|
||||
$('<div class="row">').append(
|
||||
$('<a class="col-md-6" id="a_' + i + '"><span class="app-drawer-icon-app /></a>' +
|
||||
'<a class="col-md-6" id="b_' + i + '"><span class="app-drawer-icon-app /></a>'
|
||||
)
|
||||
)
|
||||
);
|
||||
self.drawer.$appLinks = $('a.col-md-6');
|
||||
}
|
||||
};
|
||||
|
||||
test('It should set initialized after success init',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
assert.ok(self.drawer.initialized);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should close drawer after click on clickZone',
|
||||
{asserts: 1},
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.$clickZone.click();
|
||||
var d = $.Deferred();
|
||||
setTimeout(function() {
|
||||
assert.ok(self.drawer.$el.hasClass('drawer-close'));
|
||||
d.resolve();
|
||||
}, 100);
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should collapse open secondary menus during handleClickZones',
|
||||
{asserts: 1},
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.$clickZone.click();
|
||||
var d = $.Deferred();
|
||||
setTimeout(function() {
|
||||
assert.equal(self.$secondaryMenu.attr('aria-expanded'), 'false');
|
||||
d.resolve();
|
||||
}, 100);
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should update max-height on scrollable dropdowns',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.drawer.handleWindowResize();
|
||||
var height = $(window).height() * self.drawer.dropdownHeightFactor;
|
||||
assert.equal(
|
||||
self.$dropdown.css('max-height'),
|
||||
height + 'px'
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should return keybuffer + new key',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.drawer.keyBuffer = 'TES';
|
||||
var res = self.drawer.handleKeyBuffer(84);
|
||||
assert.equal(res, 'TEST');
|
||||
}
|
||||
);
|
||||
|
||||
test('It should clear keybuffer after timeout',
|
||||
{asserts: 1},
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.drawer.keyBuffer = 'TES';
|
||||
self.drawer.keyBufferTime = 10;
|
||||
self.drawer.handleKeyBuffer(84);
|
||||
var d = $.Deferred();
|
||||
setTimeout(function() {
|
||||
assert.equal(self.drawer.keyBuffer, "");
|
||||
d.resolve();
|
||||
}, 100);
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should trigger core bus event for drawer close',
|
||||
['web.core'], {asserts: 1},
|
||||
function(assert, AppDrawer, core) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.drawer.onDrawerOpen();
|
||||
var d = $.Deferred();
|
||||
core.bus.on('drawer.closed', this, function() {
|
||||
assert.ok(true);
|
||||
d.resolve();
|
||||
});
|
||||
self.drawer.$el.trigger({type: 'drawer.closed'});
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should set isOpen to false when closing',
|
||||
{asserts: 1},
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.drawer.onDrawerOpen();
|
||||
var d = $.Deferred();
|
||||
setTimeout(function() {
|
||||
assert.equal(self.drawer.isOpen, false);
|
||||
d.resolve();
|
||||
});
|
||||
self.drawer.$el.trigger({type: 'drawer.closed'});
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should set isOpen to true when opening',
|
||||
{asserts: 1},
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
var d = $.Deferred();
|
||||
self.drawer.$el.trigger({type: 'drawer.opened'});
|
||||
setTimeout(function() {
|
||||
assert.ok(self.drawer.isOpen);
|
||||
d.resolve();
|
||||
});
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should trigger core bus event for drawer open',
|
||||
['web.core'], {asserts: 1},
|
||||
function(assert, AppDrawer, core) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.drawer.onDrawerOpen();
|
||||
var d = $.Deferred();
|
||||
core.bus.on('drawer.opened', this, function() {
|
||||
assert.ok(true);
|
||||
d.resolve();
|
||||
});
|
||||
self.drawer.$el.trigger({type: 'drawer.opened'});
|
||||
return d;
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose link to right',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#a_1'),
|
||||
$expect = $('#a_2'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.RIGHT
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose link to left',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#a_2'),
|
||||
$expect = $('#a_1'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.LEFT
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose link above',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#a_1'),
|
||||
$expect = $('#a_0'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.UP
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose link below',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#a_1'),
|
||||
$expect = $('#a_2'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.DOWN
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose first link if next on last',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#b_2'),
|
||||
$expect = $('#a_0'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.RIGHT
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose bottom link if up on top',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#a_0'),
|
||||
$expect = $('#a_2'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.UP
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
test('It should choose top link if down on bottom',
|
||||
function(assert, AppDrawer) {
|
||||
self.initInterface(AppDrawer);
|
||||
self.linkGrid();
|
||||
var $appLink = $('#a_2'),
|
||||
$expect = $('#a_0'),
|
||||
$res = self.drawer.findAdjacentAppLink(
|
||||
$appLink, self.drawer.DOWN
|
||||
);
|
||||
assert.equal($res[0].id, $expect[0].id);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 LasLabs Inc.
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo.tests import HttpCase
|
||||
|
||||
|
||||
class TestUi(HttpCase):
|
||||
|
||||
def test_ui_web(self):
|
||||
"""Test backend tests."""
|
||||
self.phantom_js(
|
||||
"/web/tests?module=web_responsive",
|
||||
"",
|
||||
login="admin",
|
||||
)
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2016 LasLabs Inc.
|
||||
@author Dave Lasley <dave@laslabs.com>
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
<template id="assets_backend" name="Open Mobile Assets" inherit_id="web.assets_backend">
|
||||
<xpath expr=".">
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="/web_responsive/static/lib/css/drawer.3.2.0.css"
|
||||
/>
|
||||
<link rel="stylesheet"
|
||||
href="/web_responsive/static/src/less/main.less"
|
||||
/>
|
||||
<link rel="stylesheet"
|
||||
href="/web_responsive/static/src/less/navbar.less"
|
||||
/>
|
||||
<link rel="stylesheet"
|
||||
href="/web_responsive/static/src/less/app_drawer.less"
|
||||
/>
|
||||
<link rel="stylesheet"
|
||||
href="/web_responsive/static/src/less/form_view.less"
|
||||
/>
|
||||
<link rel="stylesheet"
|
||||
href="/web_responsive/static/src/less/variables.less"
|
||||
/>
|
||||
<script type="application/javascript"
|
||||
src="/web_responsive/static/lib/js/iscroll-probe.5.2.0.js"
|
||||
/>
|
||||
<script type="application/javascript"
|
||||
src="/web_responsive/static/lib/js/drawer.3.2.0.js"
|
||||
/>
|
||||
<script type="application/javascript"
|
||||
src="/web_responsive/static/src/js/web_responsive.js"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="qunit_suite" inherit_id="web.qunit_suite">
|
||||
<xpath expr="//t[@t-set='head']" position="inside">
|
||||
<script type="application/javascript"
|
||||
src="/web_responsive/static/tests/js/web_responsive.js"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
|
@ -0,0 +1,254 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2016 LasLabs Inc.
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<template id="webclient_bootstrap"
|
||||
inherit_id="web.webclient_bootstrap"
|
||||
name="App Drawer - Web Client"
|
||||
>
|
||||
|
||||
<xpath expr="//div[@contains('class', 'o_sub_menu')]" position="replace" />
|
||||
|
||||
<xpath expr="//t[@t-set='head']" position="inside">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="cleartype" content="on" />
|
||||
<meta name="MobileOptimized" content="320" />
|
||||
<meta name="HandheldFriendly" content="True" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//nav[@id='oe_main_menu_navbar']" position="replace">
|
||||
|
||||
<t t-set="body_classname" t-value="'drawer drawer--left o_web_client'" />
|
||||
|
||||
<header role="banner">
|
||||
<nav id="odooAppDrawer" class="app-drawer-nav drawer-nav" role="navigation">
|
||||
<t t-call="web.menu" />
|
||||
</nav>
|
||||
|
||||
<nav class="navbar navbar-default main-nav"
|
||||
role="navigation"
|
||||
groups="base.group_user,base.group_portal"
|
||||
>
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="navbar-header">
|
||||
|
||||
<a class="drawer-toggle navbar-collapse collapse btn btn-default app-drawer-toggle"
|
||||
accesskey="A"
|
||||
>
|
||||
<span class="sr-only">Toggle App Drawer</span>
|
||||
<i class="fa fa-th fa-lg app-drawer-icon-open"
|
||||
t-translation="off"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<button type="button"
|
||||
class="app-drawer-toggle drawer-toggle pull-left navbar-toggle collapsed"
|
||||
>
|
||||
<span class="sr-only">Toggle App Drawer</span>
|
||||
<div class="fa fa-th fa-lg app-drawer-icon-open" />
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
id="odooMenuBarToggle"
|
||||
class="navbar-toggle collapsed pull-right"
|
||||
data-toggle="collapse"
|
||||
data-target="#odooMenuBarNav"
|
||||
>
|
||||
<span class="sr-only">Toggle Navigation</span>
|
||||
<i class="fa fa-bars fa-lg"
|
||||
t-translation="off"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse"
|
||||
id="odooMenuBarNav"
|
||||
data-parent="#odooMenuBarToggle"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<div class="o_sub_menu"
|
||||
groups="base.group_user,base.group_portal"
|
||||
>
|
||||
<t t-call="web.menu_secondary" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav navbar-nav navbar-right navbar-systray o_menu_systray">
|
||||
<ul class="nav navbar-nav navbar-right navbar-systray-item oe_user_menu_placeholder"/>
|
||||
<ul class="nav navbar-nav navbar-right navbar-systray-item oe_systray"/>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
|
||||
<template id="menu_secondary"
|
||||
inherit_id="web.menu_secondary"
|
||||
name="App Drawer - Secondary Menu"
|
||||
>
|
||||
|
||||
<xpath expr="//div[@class='o_sub_menu_content']/t" position="replace">
|
||||
|
||||
<t t-foreach="menu_data['children']" t-as="menu">
|
||||
<ul style="display: none"
|
||||
class="oe_secondary_menu nav navbar-nav"
|
||||
t-att-data-menu-parent="menu['id']">
|
||||
<li class="app-name">
|
||||
<span class="oe_menu_text">
|
||||
<t t-esc="menu['name']"/>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<t t-call="web.menu_secondary_submenu" />
|
||||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
|
||||
<template id="menu_secondary_submenu"
|
||||
inherit_id="web.menu_secondary_submenu"
|
||||
name="App Drawer - Secondary Submenu"
|
||||
>
|
||||
|
||||
<xpath expr="//ul" position="replace">
|
||||
|
||||
<t t-foreach="menu['children']" t-as="menu">
|
||||
<t t-if="menu['children']">
|
||||
<li t-attf-class="{{ 'dropdown-header' if submenu else '' }}">
|
||||
<t t-if="submenu">
|
||||
<t t-esc="menu['name']" />
|
||||
<t t-call="web.menu_secondary_submenu">
|
||||
<t t-set="submenu" t-value="True" />
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="not submenu">
|
||||
<a class="dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<t t-esc="menu['name']" />
|
||||
<span class="caret" />
|
||||
</a>
|
||||
<ul t-if="menu['children']"
|
||||
t-attf-class="dropdown-menu oe_secondary_submenu dropdown-scrollable"
|
||||
>
|
||||
<t t-call="web.menu_secondary_submenu">
|
||||
<t t-set="submenu" t-value="True" />
|
||||
</t>
|
||||
</ul>
|
||||
</t>
|
||||
</li>
|
||||
</t>
|
||||
<t t-if="not menu['children']">
|
||||
<li>
|
||||
<t t-call="web.menu_link" />
|
||||
</li>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
|
||||
<template id="menu_link"
|
||||
inherit_id="web.menu_link"
|
||||
name="App Drawer - Menu Link"
|
||||
>
|
||||
|
||||
<xpath expr="//a" position="attributes">
|
||||
<attribute name="t-att-data-menu-name">menu['name']</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//span[@class='oe_menu_text']" position="replace">
|
||||
<t t-if="display_images">
|
||||
<img t-attf-src="/web/image/ir.ui.menu/{{ menu['id'] }}/web_icon_data"
|
||||
class="app-drawer-icon-app img-rounded"
|
||||
t-att-alt="menu['name']"
|
||||
t-att-title="menu['name']"
|
||||
/>
|
||||
<p class="app-drawer-title text-center">
|
||||
<t t-esc="menu['name']" />
|
||||
</p>
|
||||
</t>
|
||||
<t t-if="not display_images">
|
||||
<span class="oe_menu_text">
|
||||
<t t-esc="menu['name']" />
|
||||
</span>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
|
||||
<template id="menu"
|
||||
inherit_id="web.menu"
|
||||
name="App Drawer - Menu"
|
||||
>
|
||||
|
||||
<xpath expr="//ul[contains(@class, 'oe_systray')]" position="replace" />
|
||||
|
||||
<xpath expr="//ul[contains(@class, 'oe_user_menu_placeholder')]" position="replace" />
|
||||
|
||||
<xpath expr="//ul[contains(@class, 'oe_application_menu_placeholder')]" position="replace">
|
||||
|
||||
<div class="panel-default app-drawer-app-panel" id="appDrawerAppMenu">
|
||||
<div class="panel-heading" id="appDrawerAppPanelHead">
|
||||
<div class="col-xs-6">
|
||||
<h4 class="app-drawer-panel-title pull-left">
|
||||
<a class="app-drawer-icon-close drawer-toggle">
|
||||
<i class="fa fa-lg fa-chevron-left"
|
||||
t-translation="off"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Apps
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<a class="oe_logo pull-right" t-attf-href="/web?{{ keep_query() }}">
|
||||
<i class="fa fa-pencil-square-o oe_logo_edit"
|
||||
aria-hidden="true"
|
||||
t-translation="off"
|
||||
/>
|
||||
<img src='/web/binary/company_logo'/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body" id="appDrawerAppPanelBody">
|
||||
<ul class="row list-unstyled oe_application_menu_placeholder"
|
||||
style="display: none;">
|
||||
<li t-foreach="menu_data['children']" t-as="menu"
|
||||
class="col-xs-6 col-sm-4 col-md-3 col-lg-2 text-center mt16">
|
||||
<t t-call="web.menu_link">
|
||||
<t t-set="display_images" t-value="1" />
|
||||
</t>
|
||||
</li>
|
||||
<li id="menu_more_container" class="dropdown" style="display: none;">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a>
|
||||
<ul id="menu_more" class="dropdown-menu"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
Loading…
Reference in New Issue