Browse Source

[FIX] web_responsive: Fix several issues

* one2many tags now not hidden behind inputs.
* Drawer icons now with much better look.
* No overflow bug in small views when closing drawer.
* Documented it when resizing viewport. (+1 squashed commit)
* Whitespace cleanup.
pull/396/head
Jairo Llopis 8 years ago
committed by Dave Lasley
parent
commit
11e44ef265
  1. 2
      web_app_drawer/README.rst
  2. 76
      web_app_drawer/static/src/js/web_app_drawer.js
  3. 23
      web_app_drawer/static/src/less/app_drawer.less
  4. 10
      web_app_drawer/static/src/less/main.less
  5. 7
      web_app_drawer/static/src/less/navbar.less
  6. 4
      web_app_drawer/static/src/less/variables.less
  7. 77
      web_app_drawer/views/web.xml

2
web_app_drawer/README.rst

@ -39,6 +39,8 @@ Known issues / Roadmap
* Provide keyboard navigation to secondary (top) menu * Provide keyboard navigation to secondary (top) menu
* Drag drawer from left to open in mobile * Drag drawer from left to open in mobile
* Figure out how to test focus on hidden elements for keyboard nav tests * 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.
Bug Tracker Bug Tracker
=========== ===========

76
web_app_drawer/static/src/js/web_app_drawer.js

@ -3,20 +3,20 @@
odoo.define('web_app_drawer', function(require) { odoo.define('web_app_drawer', function(require) {
'use strict'; 'use strict';
var $ = require('$'); var $ = require('$');
var Menu = require('web.Menu'); var Menu = require('web.Menu');
var Class = require('web.Class'); var Class = require('web.Class');
var SearchView = require('web.SearchView'); var SearchView = require('web.SearchView');
var core = require('web.core'); var core = require('web.core');
Menu.include({ Menu.include({
// Force all_outside to prevent app icons from going into more menu // Force all_outside to prevent app icons from going into more menu
reflow: function() { reflow: function() {
this._super('all_outside'); this._super('all_outside');
}, },
/* Overload to collapse unwanted visible submenus /* Overload to collapse unwanted visible submenus
* @param allow_open bool Switch to allow submenus to be opened * @param allow_open bool Switch to allow submenus to be opened
*/ */
@ -26,25 +26,25 @@ odoo.define('web_app_drawer', function(require) {
var $clicked_menu = this.$secondary_menus.find('a[data-menu=' + id + ']'); var $clicked_menu = this.$secondary_menus.find('a[data-menu=' + id + ']');
$clicked_menu.parents('.oe_secondary_submenu').css('display', ''); $clicked_menu.parents('.oe_secondary_submenu').css('display', '');
}, },
}); });
SearchView.include({ SearchView.include({
// Prevent focus of search field on mobile devices // Prevent focus of search field on mobile devices
toggle_visibility: function (is_visible) { toggle_visibility: function (is_visible) {
$('div.oe_searchview_input').last()
$('div.oe_searchview_input').last()
.one('focus', $.proxy(this.preventMobileFocus, this)); .one('focus', $.proxy(this.preventMobileFocus, this));
return this._super(is_visible); return this._super(is_visible);
}, },
// It prevents focusing of search el on mobile // It prevents focusing of search el on mobile
preventMobileFocus: function(event) { preventMobileFocus: function(event) {
if (this.isMobile()) { if (this.isMobile()) {
event.preventDefault(); event.preventDefault();
} }
}, },
// For lack of Modernizr, TouchEvent will do // For lack of Modernizr, TouchEvent will do
isMobile: function () { isMobile: function () {
try{ try{
@ -54,23 +54,23 @@ odoo.define('web_app_drawer', function(require) {
return false; return false;
} }
}, },
}); });
var AppDrawer = Class.extend({ var AppDrawer = Class.extend({
LEFT: 'left', LEFT: 'left',
RIGHT: 'right', RIGHT: 'right',
UP: 'up', UP: 'up',
DOWN: 'down', DOWN: 'down',
isOpen: false, isOpen: false,
keyBuffer: '', keyBuffer: '',
keyBufferTime: 500, keyBufferTime: 500,
keyBufferTimeoutEvent: false, keyBufferTimeoutEvent: false,
dropdownHeightFactor: 0.90, dropdownHeightFactor: 0.90,
initialized: false, initialized: false,
init: function() { init: function() {
this.directionCodes = { this.directionCodes = {
'left': this.LEFT, 'left': this.LEFT,
@ -91,7 +91,7 @@ odoo.define('web_app_drawer', function(require) {
core.bus.on('resize', this, this.handleWindowResize); core.bus.on('resize', this, this.handleWindowResize);
core.bus.on('keydown', this, this.handleNavKeys); core.bus.on('keydown', this, this.handleNavKeys);
}, },
// It provides initialization handlers for Drawer // It provides initialization handlers for Drawer
initDrawer: function() { initDrawer: function() {
this.$el = $('.drawer'); this.$el = $('.drawer');
@ -109,7 +109,7 @@ odoo.define('web_app_drawer', function(require) {
}); });
this.initialized = true; this.initialized = true;
}, },
// It provides handlers to hide drawer when "unfocused" // It provides handlers to hide drawer when "unfocused"
handleClickZones: function() { handleClickZones: function() {
this.$el.drawer('close'); this.$el.drawer('close');
@ -117,14 +117,14 @@ odoo.define('web_app_drawer', function(require) {
.parent() .parent()
.collapse('hide'); .collapse('hide');
}, },
// It resizes bootstrap dropdowns for screen // It resizes bootstrap dropdowns for screen
handleWindowResize: function() { handleWindowResize: function() {
$('.dropdown-scrollable').css( $('.dropdown-scrollable').css(
'max-height', $(window).height() * this.dropdownHeightFactor 'max-height', $(window).height() * this.dropdownHeightFactor
); );
}, },
// It provides keyboard shortcuts for app drawer nav // It provides keyboard shortcuts for app drawer nav
handleNavKeys: function(e) { handleNavKeys: function(e) {
if (!this.isOpen){ if (!this.isOpen){
@ -144,7 +144,7 @@ odoo.define('web_app_drawer', function(require) {
this.selectAppLink(this.searchAppLinks(buffer)); this.selectAppLink(this.searchAppLinks(buffer));
} }
}, },
/* It adds to keybuffer, sets expire timer, and returns buffer /* It adds to keybuffer, sets expire timer, and returns buffer
* @returns str of current buffer * @returns str of current buffer
*/ */
@ -159,11 +159,11 @@ odoo.define('web_app_drawer', function(require) {
); );
return this.keyBuffer; return this.keyBuffer;
}, },
clearKeyBuffer: function() { clearKeyBuffer: function() {
this.keyBuffer = ''; this.keyBuffer = '';
}, },
/* It performs close actions /* It performs close actions
* @fires ``drawer.closed`` to the ``core.bus`` * @fires ``drawer.closed`` to the ``core.bus``
* @listens ``drawer.opened`` and sends to onDrawerOpen * @listens ``drawer.opened`` and sends to onDrawerOpen
@ -172,8 +172,10 @@ odoo.define('web_app_drawer', function(require) {
core.bus.trigger('drawer.closed'); core.bus.trigger('drawer.closed');
this.$el.one('drawer.opened', $.proxy(this.onDrawerOpen, this)); this.$el.one('drawer.opened', $.proxy(this.onDrawerOpen, this));
this.isOpen = false; this.isOpen = false;
// Remove inline style inserted by drawer.js
this.$el.css("overflow", "");
}, },
/* It finds app links and register event handlers /* It finds app links and register event handlers
* @fires ``drawer.opened`` to the ``core.bus`` * @fires ``drawer.opened`` to the ``core.bus``
* @listens ``drawer.closed`` and sends to :meth:``onDrawerClose`` * @listens ``drawer.closed`` and sends to :meth:``onDrawerClose``
@ -185,14 +187,14 @@ odoo.define('web_app_drawer', function(require) {
core.bus.trigger('drawer.opened'); core.bus.trigger('drawer.opened');
this.isOpen = true; this.isOpen = true;
}, },
// It selects an app link visibly
// It selects an app link visibly
selectAppLink: function($appLink) { selectAppLink: function($appLink) {
if ($appLink) { if ($appLink) {
$appLink.focus(); $appLink.focus();
} }
}, },
/* It returns first App Link by its name according to query /* It returns first App Link by its name according to query
* @param query str to search * @param query str to search
* @return jQuery obj * @return jQuery obj
@ -202,7 +204,7 @@ odoo.define('web_app_drawer', function(require) {
return $(this).data('menuName').toUpperCase().startsWith(query); return $(this).data('menuName').toUpperCase().startsWith(query);
}).first(); }).first();
}, },
/* It returns the link adjacent to $appLink in provided direction. /* It returns the link adjacent to $appLink in provided direction.
* It also handles edge cases in the following ways: * It also handles edge cases in the following ways:
* * Moves to last link if LEFT on first * * Moves to last link if LEFT on first
@ -216,10 +218,10 @@ odoo.define('web_app_drawer', function(require) {
* @return jQuery obj for adjacent applink * @return jQuery obj for adjacent applink
*/ */
findAdjacentAppLink: function($appLink, direction) { findAdjacentAppLink: function($appLink, direction) {
var obj = [], var obj = [],
$objs = this.$appLinks; $objs = this.$appLinks;
switch(direction){ switch(direction){
case this.LEFT: case this.LEFT:
obj = $objs[$objs.index($appLink) - 1]; obj = $objs[$objs.index($appLink) - 1];
@ -248,15 +250,15 @@ odoo.define('web_app_drawer', function(require) {
} }
break; break;
} }
if (obj.length) { if (obj.length) {
event.preventDefault(); event.preventDefault();
} }
return $(obj); return $(obj);
}, },
/* It returns els in the same row /* It returns els in the same row
* @param @obj jQuery object to get row for * @param @obj jQuery object to get row for
* @param $grid jQuery objects representing grid * @param $grid jQuery objects representing grid
@ -275,18 +277,18 @@ odoo.define('web_app_drawer', function(require) {
right = left + $obj.outerWidth(); right = left + $obj.outerWidth();
return $grid.filter(filterWithin(left, right)); return $grid.filter(filterWithin(left, right));
}, },
}); });
// It inits a new AppDrawer when the web client is ready // It inits a new AppDrawer when the web client is ready
core.bus.on('web_client_ready', null, function () { core.bus.on('web_client_ready', null, function () {
new AppDrawer(); new AppDrawer();
}); });
return { return {
'AppDrawer': AppDrawer, 'AppDrawer': AppDrawer,
'SearchView': SearchView, 'SearchView': SearchView,
'Menu': Menu, 'Menu': Menu,
}; };
}); });

23
web_app_drawer/static/src/less/app_drawer.less

@ -13,29 +13,30 @@
background-clip: padding-box; background-clip: padding-box;
.navbar-left { .navbar-left {
width: 100%; width: 100%;
li { li {
padding: 0; padding: 0;
} }
} }
.app-drawer-title { .app-drawer-title {
float: none; float: none;
} }
.app-drawer-panel-title { .app-drawer-panel-title {
margin-top: 4px; margin-top: 4px;
} }
.app-drawer-icon-app { .app-drawer-icon-app {
height: @app-drawer-icon-size;
width: @app-drawer-icon-size;
margin: @app-drawer-icon-margin;
height: 100%;
width: 100%;
max-width: @app-drawer-icon-size;
max-height: @app-drawer-icon-size;
object-fit: contain;
object-position: center;
} }
.panel-body { .panel-body {
padding-top: @app-drawer-title-height; padding-top: @app-drawer-title-height;
} }
@ -46,7 +47,7 @@
width: 100%; width: 100%;
z-index: 9999; z-index: 9999;
} }
} }
.drawer-nav { .drawer-nav {

10
web_app_drawer/static/src/less/main.less

@ -4,6 +4,16 @@
body { body {
width: 100%; width: 100%;
height: 100%; height: 100%;
// Do not fix the search part, it's too big for small screens
@media (max-width: @screen-sm-max) {
overflow: inherit;
.openerp {
.oe-view-manager {
overflow: inherit;
}
}
}
} }
main { main {

7
web_app_drawer/static/src/less/navbar.less

@ -27,12 +27,7 @@ a.navbar-collapse.collapse {
overflow-x: hidden; overflow-x: hidden;
} }
.badge {
position: absolute;
right: @app-drawer-padding-horizontal;
}
@media (max-width: @screen-sm - 1px) {
@media (max-width: @screen-xs-max) {
#odooMenuBarNav[aria-expanded="false"] { #odooMenuBarNav[aria-expanded="false"] {
/* Hack to hide the visibly expanded mobile menu on load. */ /* Hack to hide the visibly expanded mobile menu on load. */
position: absolute; position: absolute;

4
web_app_drawer/static/src/less/variables.less

@ -2,14 +2,12 @@
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
// App Drawer / Icons // App Drawer / Icons
@app-drawer-icon-size: 7em;
@app-drawer-icon-size: 6em;
@app-drawer-icon-margin: 1em; @app-drawer-icon-margin: 1em;
@app-drawer-width: 80%; @app-drawer-width: 80%;
@app-drawer-title-height: @navbar-height; @app-drawer-title-height: @navbar-height;
// Navbar // Navbar
@app-drawer-navbar-height: @navbar-height / 2; @app-drawer-navbar-height: @navbar-height / 2;
@app-drawer-navbar-padding-vertical: @navbar-padding-vertical / 2; @app-drawer-navbar-padding-vertical: @navbar-padding-vertical / 2;
@app-drawer-padding-horizontal: @navbar-padding-horizontal / 2; @app-drawer-padding-horizontal: @navbar-padding-horizontal / 2;

77
web_app_drawer/views/web.xml

@ -11,9 +11,9 @@
inherit_id="web.webclient_bootstrap" inherit_id="web.webclient_bootstrap"
name="App Drawer - Web Client" name="App Drawer - Web Client"
> >
<xpath expr="//div[@class='oe_leftbar']" position="replace" /> <xpath expr="//div[@class='oe_leftbar']" position="replace" />
<xpath expr="//t[@t-set='head']" position="inside"> <xpath expr="//t[@t-set='head']" position="inside">
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="cleartype" content="on" /> <meta http-equiv="cleartype" content="on" />
@ -22,39 +22,39 @@
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
</xpath> </xpath>
<xpath expr="//nav[@id='oe_main_menu_navbar']" position="replace"> <xpath expr="//nav[@id='oe_main_menu_navbar']" position="replace">
<t t-set="body_classname" t-value="'drawer drawer--left'" /> <t t-set="body_classname" t-value="'drawer drawer--left'" />
<header role="banner"> <header role="banner">
<nav id="odooAppDrawer" class="app-drawer-nav drawer-nav" role="navigation"> <nav id="odooAppDrawer" class="app-drawer-nav drawer-nav" role="navigation">
<t t-call="web.menu" /> <t t-call="web.menu" />
</nav> </nav>
<nav class="navbar navbar-default main-nav" <nav class="navbar navbar-default main-nav"
role="navigation" role="navigation"
groups="base.group_user,base.group_portal" groups="base.group_user,base.group_portal"
> >
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">
<a href="#" <a href="#"
class="drawer-toggle pull-left navbar-collapse collapse btn btn-default app-drawer-toggle"
class="drawer-toggle navbar-collapse collapse btn btn-default app-drawer-toggle"
accesskey="A" accesskey="A"
> >
<span class="sr-only">Toggle App Drawer</span> <span class="sr-only">Toggle App Drawer</span>
<i class="fa fa-th fa-lg app-drawer-icon-open" /> <i class="fa fa-th fa-lg app-drawer-icon-open" />
</a> </a>
<button type="button" <button type="button"
class="app-drawer-toggle drawer-toggle pull-left navbar-toggle collapsed" class="app-drawer-toggle drawer-toggle pull-left navbar-toggle collapsed"
> >
<span class="sr-only">Toggle App Drawer</span> <span class="sr-only">Toggle App Drawer</span>
<i class="fa fa-th fa-lg app-drawer-icon-open" />
<div class="fa fa-th fa-lg app-drawer-icon-open" />
</button> </button>
<button type="button" <button type="button"
id="odooMenuBarToggle" id="odooMenuBarToggle"
class="navbar-toggle collapsed pull-right" class="navbar-toggle collapsed pull-right"
@ -64,9 +64,9 @@
<span class="sr-only">Toggle Navigation</span> <span class="sr-only">Toggle Navigation</span>
<i class="fa fa-bars fa-lg" /> <i class="fa fa-bars fa-lg" />
</button> </button>
</div> </div>
<div class="collapse navbar-collapse text-center" <div class="collapse navbar-collapse text-center"
id="odooMenuBarNav" id="odooMenuBarNav"
data-parent="#odooMenuBarToggle" data-parent="#odooMenuBarToggle"
@ -88,41 +88,41 @@
</div> </div>
</div> </div>
</nav> </nav>
</header> </header>
</xpath> </xpath>
</template> </template>
<template id="menu_secondary" <template id="menu_secondary"
inherit_id="web.menu_secondary" inherit_id="web.menu_secondary"
name="App Drawer - Secondary Menu" name="App Drawer - Secondary Menu"
> >
<xpath expr="//a[@class='oe_logo']" position="replace" /> <xpath expr="//a[@class='oe_logo']" position="replace" />
<xpath expr="//div[@class='oe_footer']" position="replace" /> <xpath expr="//div[@class='oe_footer']" position="replace" />
<xpath expr="//div[@class='oe_secondary_menus_container']/t" position="replace"> <xpath expr="//div[@class='oe_secondary_menus_container']/t" position="replace">
<t t-foreach="menu_data['children']" t-as="menu"> <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']"> <ul style="display: none" class="oe_secondary_menu nav navbar-nav" t-att-data-menu-parent="menu['id']">
<t t-call="web.menu_secondary_submenu" /> <t t-call="web.menu_secondary_submenu" />
</ul> </ul>
</t> </t>
</xpath> </xpath>
</template> </template>
<template id="menu_secondary_submenu" <template id="menu_secondary_submenu"
inherit_id="web.menu_secondary_submenu" inherit_id="web.menu_secondary_submenu"
name="App Drawer - Secondary Submenu" name="App Drawer - Secondary Submenu"
> >
<xpath expr="//ul" position="replace"> <xpath expr="//ul" position="replace">
<t t-foreach="menu['children']" t-as="menu"> <t t-foreach="menu['children']" t-as="menu">
<t t-if="menu['children']"> <t t-if="menu['children']">
<li t-attf-class="{{ 'dropdown-header' if submenu else '' }}"> <li t-attf-class="{{ 'dropdown-header' if submenu else '' }}">
@ -159,20 +159,20 @@
</li> </li>
</t> </t>
</t> </t>
</xpath> </xpath>
</template> </template>
<template id="menu_link" <template id="menu_link"
inherit_id="web.menu_link" inherit_id="web.menu_link"
name="App Drawer - Menu Link" name="App Drawer - Menu Link"
> >
<xpath expr="//a" position="attributes"> <xpath expr="//a" position="attributes">
<attribute name="t-att-data-menu-name">menu['name']</attribute> <attribute name="t-att-data-menu-name">menu['name']</attribute>
</xpath> </xpath>
<xpath expr="//span[@class='oe_menu_text']" position="replace"> <xpath expr="//span[@class='oe_menu_text']" position="replace">
<t t-if="display_images"> <t t-if="display_images">
<img t-attf-src="/web/image/ir.ui.menu/{{ menu['id'] }}/web_icon_data" <img t-attf-src="/web/image/ir.ui.menu/{{ menu['id'] }}/web_icon_data"
@ -190,20 +190,20 @@
</span> </span>
</t> </t>
</xpath> </xpath>
</template> </template>
<template id="menu" <template id="menu"
inherit_id="web.menu" inherit_id="web.menu"
name="App Drawer - Menu" name="App Drawer - Menu"
> >
<xpath expr="//ul[contains(@class, 'oe_systray')]" position="replace" /> <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_user_menu_placeholder')]" position="replace" />
<xpath expr="//ul[contains(@class, 'oe_application_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-default app-drawer-app-panel" id="appDrawerAppMenu">
<div class="panel-heading" id="appDrawerAppPanelHead"> <div class="panel-heading" id="appDrawerAppPanelHead">
<h4 class="app-drawer-panel-title"> <h4 class="app-drawer-panel-title">
@ -214,8 +214,10 @@
</h4> </h4>
</div> </div>
<div class="panel-body" id="appDrawerAppPanelBody"> <div class="panel-body" id="appDrawerAppPanelBody">
<ul class="nav navbar-nav navbar-left 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">
<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-call="web.menu_link">
<t t-set="display_images" t-value="1" /> <t t-set="display_images" t-value="1" />
</t> </t>
@ -227,10 +229,7 @@
</ul> </ul>
</div> </div>
</div> </div>
</xpath> </xpath>
</template> </template>
</odoo> </odoo>
Loading…
Cancel
Save