From b8c776d452adba6bb389f06959d8a677653e8d55 Mon Sep 17 00:00:00 2001 From: Jeremy Press Date: Mon, 31 Jul 2017 09:50:21 -0700 Subject: [PATCH] New: Add pseudo fullscreen to mobile Safari (#246) * New: Add pseudo fullscreen to mobile Safari --- src/lib/Controls.scss | 1 + src/lib/_common.scss | 11 +++++++ src/lib/constants.js | 1 + src/lib/viewers/BaseViewer.js | 28 +++++++++++------- src/lib/viewers/__tests__/BaseViewer-test.js | 30 ++++++++++++++++++++ src/lib/viewers/doc/DocBaseViewer.js | 2 +- 6 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/lib/Controls.scss b/src/lib/Controls.scss index c95334896..2ea3831c0 100644 --- a/src/lib/Controls.scss +++ b/src/lib/Controls.scss @@ -41,6 +41,7 @@ opacity: .7; outline: 0; padding: 0; + // disables non-standard gestures such as double-tap to zoom touch-action: manipulation; user-select: none; width: 48px; diff --git a/src/lib/_common.scss b/src/lib/_common.scss index 33946fe53..462eda12c 100644 --- a/src/lib/_common.scss +++ b/src/lib/_common.scss @@ -25,6 +25,8 @@ $header-height: 48px; overflow: hidden; padding: 0; position: relative; + // disables non-standard gestures such as double-tap to zoom + touch-action: manipulation; width: 100%; a { @@ -131,6 +133,15 @@ $header-height: 48px; right: 0; top: 0; + // Pseudo fullscreen for iOS Safari which doesn't support the fullscreen API + &.bp-fullscreen-unsupported { + bottom: 0; + left: 0; + position: fixed; + right: 0; + top: 0; + } + &.bp-dark { background-color: $black; } diff --git a/src/lib/constants.js b/src/lib/constants.js index 3e234eac2..77b16d700 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -29,6 +29,7 @@ export const CLASS_BOX_PREVIEW_TOGGLE_OVERLAY = 'bp-toggle-overlay'; export const CLASS_BOX_PREVIEW_THEME_DARK = 'bp-theme-dark'; export const CLASS_ELEM_KEYBOARD_FOCUS = 'bp-has-keyboard-focus'; export const CLASS_FULLSCREEN = 'bp-is-fullscreen'; +export const CLASS_FULLSCREEN_UNSUPPORTED = 'bp-fullscreen-unsupported'; export const CLASS_INVISIBLE = 'bp-is-invisible'; export const CLASS_IS_VISIBLE = 'bp-is-visible'; export const CLASS_IS_SCROLLABLE = 'bp-is-scrollable'; diff --git a/src/lib/viewers/BaseViewer.js b/src/lib/viewers/BaseViewer.js index bb64723f5..b29692946 100644 --- a/src/lib/viewers/BaseViewer.js +++ b/src/lib/viewers/BaseViewer.js @@ -17,6 +17,7 @@ import Browser from '../Browser'; import { PERMISSION_ANNOTATE, CLASS_FULLSCREEN, + CLASS_FULLSCREEN_UNSUPPORTED, CLASS_HIDDEN, CLASS_BOX_PREVIEW_MOBILE, SELECTOR_BOX_PREVIEW, @@ -329,17 +330,9 @@ class BaseViewer extends EventEmitter { */ addCommonListeners() { // Attach common full screen event listeners - /* istanbul ignore next */ - fullscreen.addListener('enter', () => { - this.containerEl.classList.add(CLASS_FULLSCREEN); - this.resize(); - }); + fullscreen.addListener('enter', this.onFullscreenToggled); - /* istanbul ignore next */ - fullscreen.addListener('exit', () => { - this.containerEl.classList.remove(CLASS_FULLSCREEN); - this.resize(); - }); + fullscreen.addListener('exit', this.onFullscreenToggled); // Add a resize handler for the window document.defaultView.addEventListener('resize', this.debouncedResizeHandler); @@ -357,6 +350,7 @@ class BaseViewer extends EventEmitter { /** * Enters or exits fullscreen + * * @protected * @return {void} */ @@ -364,6 +358,20 @@ class BaseViewer extends EventEmitter { fullscreen.toggle(this.containerEl); } + /** + * Applies appropriate styles and resizes the document depending on fullscreen state + * + * @return {void} + */ + onFullscreenToggled() { + this.containerEl.classList.toggle(CLASS_FULLSCREEN); + if (!fullscreen.isSupported()) { + this.containerEl.classList.toggle(CLASS_FULLSCREEN_UNSUPPORTED); + } + + this.resize(); + } + /** * Resizing logic * diff --git a/src/lib/viewers/__tests__/BaseViewer-test.js b/src/lib/viewers/__tests__/BaseViewer-test.js index 39ce8cc41..a3f132fa9 100644 --- a/src/lib/viewers/__tests__/BaseViewer-test.js +++ b/src/lib/viewers/__tests__/BaseViewer-test.js @@ -322,6 +322,36 @@ describe('lib/viewers/BaseViewer', () => { }); }); + describe('onFullscreenToggled()', () => { + beforeEach(() => { + base.containerEl = document.createElement('div'); + sandbox.stub(fullscreen, 'isSupported').returns(false); + sandbox.stub(base, 'resize'); + + }); + + it('should toggle the fullscreen class', () => { + base.onFullscreenToggled(); + expect(base.containerEl.classList.contains(constants.CLASS_FULLSCREEN)).to.be.true; + + base.onFullscreenToggled(); + expect(base.containerEl.classList.contains(constants.CLASS_FULLSCREEN)).to.be.false; + }); + + it('should toggle the unsupported class if the browser does not support the fullscreen API', () => { + base.onFullscreenToggled(); + expect(base.containerEl.classList.contains(constants.CLASS_FULLSCREEN_UNSUPPORTED)).to.be.true; + + base.onFullscreenToggled(); + expect(base.containerEl.classList.contains(constants.CLASS_FULLSCREEN_UNSUPPORTED)).to.be.false; + }); + + it('should resize the viewer', () => { + base.onFullscreenToggled(); + expect(base.resize).to.be.called; + }); + }); + describe('resize()', () => { it('should broadcast resize event', () => { sandbox.stub(base, 'emit'); diff --git a/src/lib/viewers/doc/DocBaseViewer.js b/src/lib/viewers/doc/DocBaseViewer.js index 816b69373..28e4dcbcf 100644 --- a/src/lib/viewers/doc/DocBaseViewer.js +++ b/src/lib/viewers/doc/DocBaseViewer.js @@ -361,7 +361,7 @@ class DocBaseViewer extends BaseViewer { const previousPageButtonEl = this.containerEl.querySelector('.bp-previous-page'); const nextPageButtonEl = this.containerEl.querySelector('.bp-next-page'); - // Safari disables keyboard input in fullscreen + // Safari disables keyboard input in fullscreen before Safari 10.1 const isSafariFullscreen = Browser.getName() === 'Safari' && fullscreen.isFullscreen(this.containerEl); // Disable page number selector if there is only one page or less