On touchscreens add content overlay for opened menu (#3088)
* Overflow:hidden on touchscreen when modal-open * Do not display menu by default on touchscreens * Add content overlay on touchscreens when menu is opened * Fix zIndex overlay for search infos * On touchscreens close menu on swipe left Co-authored-by: kimsible <kimsible@users.noreply.github.com>
This commit is contained in:
parent
30d55e75ca
commit
245b9d27bc
|
@ -180,8 +180,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||
|
||||
eventsObs.pipe(
|
||||
filter((e: Event): e is GuardsCheckStart => e instanceof GuardsCheckStart),
|
||||
filter(() => this.screenService.isInSmallView())
|
||||
).subscribe(() => this.menu.isMenuDisplayed = false) // User clicked on a link in the menu, change the page
|
||||
filter(() => this.screenService.isInSmallView() || !!this.screenService.isInTouchScreen())
|
||||
).subscribe(() => this.menu.setMenuDisplay(false)) // User clicked on a link in the menu, change the page
|
||||
}
|
||||
|
||||
private injectBroadcastMessage () {
|
||||
|
|
|
@ -12,22 +12,45 @@ export class MenuService {
|
|||
constructor (
|
||||
private screenService: ScreenService
|
||||
) {
|
||||
// Do not display menu on small screens
|
||||
if (this.screenService.isInSmallView()) {
|
||||
this.isMenuDisplayed = false
|
||||
// Do not display menu on small or touch screens
|
||||
if (this.screenService.isInSmallView() || this.screenService.isInTouchScreen()) {
|
||||
this.setMenuDisplay(false)
|
||||
}
|
||||
|
||||
this.handleWindowResize()
|
||||
}
|
||||
|
||||
toggleMenu () {
|
||||
this.setMenuDisplay(!this.isMenuDisplayed)
|
||||
this.isMenuChangedByUser = true
|
||||
}
|
||||
|
||||
setMenuDisplay (display: boolean) {
|
||||
this.isMenuDisplayed = display
|
||||
|
||||
// On touch screens, lock body scroll and display content overlay when memu is opened
|
||||
if (this.screenService.isInTouchScreen()) {
|
||||
if (this.isMenuDisplayed) {
|
||||
document.body.classList.add('menu-open')
|
||||
this.screenService.onFingerSwipe('left', () => { this.setMenuDisplay(false) })
|
||||
} else {
|
||||
document.body.classList.remove('menu-open')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onResize () {
|
||||
this.isMenuDisplayed = window.innerWidth >= 800 && !this.isMenuChangedByUser
|
||||
}
|
||||
|
||||
private handleWindowResize () {
|
||||
// On touch screens, do not handle window resize event since opened menu is handled with a content overlay
|
||||
if (this.screenService.isInTouchScreen()) {
|
||||
return
|
||||
}
|
||||
|
||||
fromEvent(window, 'resize')
|
||||
.pipe(debounceTime(200))
|
||||
.subscribe(() => this.onResize())
|
||||
}
|
||||
|
||||
toggleMenu () {
|
||||
this.isMenuDisplayed = !this.isMenuDisplayed
|
||||
this.isMenuChangedByUser = true
|
||||
}
|
||||
|
||||
onResize () {
|
||||
this.isMenuDisplayed = window.innerWidth >= 800 && !this.isMenuChangedByUser
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ abstract class MenuGuard implements CanActivate, CanDeactivate<any> {
|
|||
// small screens already have the site-wide onResize from screenService
|
||||
// > medium screens have enough space to fit the administrative menus
|
||||
if (!this.screen.isInMobileView() && this.screen.isInMediumView()) {
|
||||
this.menu.isMenuDisplayed = this.display
|
||||
this.menu.setMenuDisplay(this.display)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -54,6 +54,64 @@ export class ScreenService {
|
|||
return this.windowInnerWidth
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/2264072/detect-a-finger-swipe-through-javascript-on-the-iphone-and-android
|
||||
onFingerSwipe (direction: 'left' | 'right' | 'up' | 'down', action: () => void, removeEventOnEnd = true) {
|
||||
let touchDownClientX: number
|
||||
let touchDownClientY: number
|
||||
|
||||
const onTouchStart = (event: TouchEvent) => {
|
||||
const firstTouch = event.touches[0]
|
||||
touchDownClientX = firstTouch.clientX
|
||||
touchDownClientY = firstTouch.clientY
|
||||
}
|
||||
|
||||
const onTouchMove = (event: TouchEvent) => {
|
||||
if (!touchDownClientX || !touchDownClientY) {
|
||||
return
|
||||
}
|
||||
|
||||
const touchUpClientX = event.touches[0].clientX
|
||||
const touchUpClientY = event.touches[0].clientY
|
||||
|
||||
const touchClientX = Math.abs(touchDownClientX - touchUpClientX)
|
||||
const touchClientY = Math.abs(touchDownClientY - touchUpClientY)
|
||||
|
||||
if (touchClientX > touchClientY) {
|
||||
if (touchClientX > 0) {
|
||||
if (direction === 'left') {
|
||||
if (removeEventOnEnd) this.removeFingerSwipeEventListener(onTouchStart, onTouchMove)
|
||||
action()
|
||||
}
|
||||
} else {
|
||||
if (direction === 'right') {
|
||||
if (removeEventOnEnd) this.removeFingerSwipeEventListener(onTouchStart, onTouchMove)
|
||||
action()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (touchClientY > 0) {
|
||||
if (direction === 'up') {
|
||||
if (removeEventOnEnd) this.removeFingerSwipeEventListener(onTouchStart, onTouchMove)
|
||||
action()
|
||||
}
|
||||
} else {
|
||||
if (direction === 'down') {
|
||||
if (removeEventOnEnd) this.removeFingerSwipeEventListener(onTouchStart, onTouchMove)
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('touchstart', onTouchStart, false)
|
||||
document.addEventListener('touchmove', onTouchMove, false)
|
||||
}
|
||||
|
||||
private removeFingerSwipeEventListener (onTouchStart: (event: TouchEvent) => void, onTouchMove: (event: TouchEvent) => void) {
|
||||
document.removeEventListener('touchstart', onTouchStart)
|
||||
document.removeEventListener('touchmove', onTouchMove)
|
||||
}
|
||||
|
||||
private refreshWindowInnerWidth () {
|
||||
this.lastFunctionCallTime = new Date().getTime()
|
||||
|
||||
|
|
|
@ -150,6 +150,29 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
|
|||
width: 100vw; // Make sure the content fits all the available width
|
||||
}
|
||||
|
||||
// On touchscreen devices, simply overflow: hidden to avoid detached overlay on scroll
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.modal-open, .menu-open {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
// On touchscreen devices display content overlay when opened menu
|
||||
.menu-open {
|
||||
.main-col {
|
||||
&::before {
|
||||
background-color: black;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
opacity: 0.75;
|
||||
content: '';
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: z('header') - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nav customizations
|
||||
.nav .nav-link {
|
||||
display: flex !important;
|
||||
|
|
Loading…
Reference in New Issue