Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Fullscreen classes are now removed when pressing escape #927

Merged
merged 1 commit into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<html>
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href='./preview.css' />
<link rel="stylesheet" href='./annotations.css' />
<script src='https://cdn01.boxcdn.net/polyfills/core-js/2.5.3/core.min.js'></script>
Expand Down
89 changes: 45 additions & 44 deletions src/lib/Fullscreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import fscreen from 'fscreen';
import { CLASS_FULLSCREEN, CLASS_FULLSCREEN_UNSUPPORTED } from './constants';

class Fullscreen extends EventEmitter {
/** {HTMLElement} - The element used as the root for fullscreen mode */
fullscreenElement;

/**
* [constructor]
*
Expand All @@ -17,31 +20,28 @@ class Fullscreen extends EventEmitter {
/**
* Binds DOM listeners for Fullscreen.
*
* @protected
* @return {void}
*/
bindDOMListeners() {
// as of now (1/12/18) fullscreenchange is not universally adopted, fscreen will
// detect and add the appropriate vendor prefixed event
// The fullscreenchange event is not universally supported, but fscreen will
// detect and add the appropriate vendor-prefixed event
fscreen.addEventListener('fullscreenchange', this.fullscreenchangeHandler);
}

/**
* Unbinds DOM listeners for Fullscreen.
*
* @protected
* @return {void}
*/
unbindDOMListeners() {
// as of now (1/12/18) fullscreenchange is not universally adopted, fscreen will
// detect and add the appropriate vendor prefixed event
// The fullscreenchange event is not universally supported, but fscreen will
// detect and add the appropriate vendor-prefixed event
fscreen.removeEventListener('fullscreenchange', this.fullscreenchangeHandler);
}

/**
* [destructor]
*
* @protected
* @return {void}
*/
destroy() {
Expand All @@ -52,7 +52,6 @@ class Fullscreen extends EventEmitter {
/**
* Returns true if the browser supports fullscreen natively
*
* @private
* @return {boolean} Fullscreen supported or not
*/
isSupported() {
Expand All @@ -62,45 +61,62 @@ class Fullscreen extends EventEmitter {
/**
* Return true if full screen is active
*
* @public
* @param {HTMLElement} [element] - fullscreen element
* @param {HTMLElement} [el] - fullscreen element
* @return {boolean} In fullscreen or not
*/
isFullscreen(element) {
isFullscreen(el) {
if (this.isSupported()) {
return !!fscreen.fullscreenElement;
}

return element instanceof HTMLElement && element.classList.contains(CLASS_FULLSCREEN);
return el && el.classList.contains(CLASS_FULLSCREEN);
}

/**
* Fires events when the fullscreen state changes
* Handles fullscreen change events from fscreen
*
* @private
* @return {void}
*/
fullscreenchangeHandler = () => {
if (this.isFullscreen()) {
this.focusFullscreenElement();
this.emit('enter');
const { fullscreenElement } = fscreen;

if (fullscreenElement) {
this.fullscreenEnterHandler(fullscreenElement);
} else {
this.emit('exit');
this.fullscreenExitHandler();
}
};

/**
* Focuses the element
* Handles fullscreen enter events
*
* @private
* @param {HTMLElement} el - fullscreen element
* @return {void}
*/
focusFullscreenElement = () => {
// Focus on the fullscreen element so keyboard
// events are triggered without an extra click
fscreen.fullscreenElement.focus();
};
fullscreenEnterHandler(el) {
this.fullscreenElement = el;
this.fullscreenElement.classList.add(CLASS_FULLSCREEN);
this.fullscreenElement.focus();

if (!this.isSupported()) {
this.fullscreenElement.classList.add(CLASS_FULLSCREEN_UNSUPPORTED);
}

this.emit('enter');
}

/**
* Handles fullscreen exit events
*
* @return {void}
*/
fullscreenExitHandler() {
this.fullscreenElement.classList.remove(CLASS_FULLSCREEN);
this.fullscreenElement.classList.remove(CLASS_FULLSCREEN_UNSUPPORTED);
this.fullscreenElement = null;

this.emit('exit');
}

/**
* Enter fullscreen mode
Expand All @@ -109,50 +125,35 @@ class Fullscreen extends EventEmitter {
* @return {void}
*/
enter(el = document.documentElement) {
if (el instanceof HTMLElement) {
el.classList.add(CLASS_FULLSCREEN);

if (!this.isSupported()) {
el.classList.add(CLASS_FULLSCREEN_UNSUPPORTED);
}
}

if (this.isSupported()) {
fscreen.requestFullscreenFunction(el).call(el, Element.ALLOW_KEYBOARD_INPUT);
} else {
this.emit('enter');
this.fullscreenEnterHandler(el);
}
}

/**
* Exit fullscreen mode
*
* @param {HTMLElement} el - fullscreen element
* @return {void}
*/
exit(el = document.documentElement) {
if (el instanceof HTMLElement) {
el.classList.remove(CLASS_FULLSCREEN);
el.classList.remove(CLASS_FULLSCREEN_UNSUPPORTED);
}

exit() {
if (this.isSupported()) {
fscreen.exitFullscreen();
} else {
this.emit('exit');
this.fullscreenExitHandler();
}
}

/**
* Toggle fullscreen mode
*
* @public
* @param {HTMLElement} el - fullscreen element
* @return {void}
*/
toggle(el = document.documentElement) {
if (this.isFullscreen(el)) {
this.exit(el);
this.exit();
} else {
this.enter(el);
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/PageControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class PageControls extends EventEmitter {
const nextPageButtonEl = this.controlsEl.querySelector(`.${NEXT_PAGE}`);

// Safari disables keyboard input in fullscreen before Safari 10.1
const isSafariFullscreen = Browser.getName() === 'Safari' && fullscreen.isFullscreen(this.controlsEl);
const isSafariFullscreen = Browser.getName() === 'Safari' && fullscreen.isFullscreen();

// Disable page number selector if there is only one page or less
if (pageNumButtonEl) {
Expand Down
128 changes: 59 additions & 69 deletions src/lib/__tests__/Fullscreen-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,121 +39,111 @@ describe('lib/Fullscreen', () => {
});
});

describe('fullscreenchangeHandler()', () => {
before(() => {
fixture.setBase('src/lib');
});

beforeEach(() => {
fixture.load('__tests__/Fullscreen-test.html');
});

afterEach(() => {
fixture.cleanup();
});

it('should emit enter if we are entering fullscreen and if true fullscreen is supported', () => {
sandbox.stub(fullscreen, 'isSupported').returns(true);
sandbox.stub(fullscreen, 'isFullscreen').returns(true);
describe('fullscreenEnterHandler()', () => {
it('should add the fullscreen class and focus the element', () => {
const element = document.createElement('div');
sandbox.stub(element, 'focus');
sandbox.stub(fullscreen, 'emit');
sandbox.stub(fullscreen, 'focusFullscreenElement');

fullscreen.fullscreenchangeHandler();
fullscreen.fullscreenEnterHandler(element);

expect(element.classList.contains(CLASS_FULLSCREEN)).to.be.true;
expect(element.focus).to.have.been.called;
expect(fullscreen.emit).to.have.been.calledWith('enter');
expect(fullscreen.focusFullscreenElement).to.have.been.called;
});
});

it('should emit exit if we are exiting fullscreen and if true fullscreen is supported', () => {
sandbox.stub(fullscreen, 'isSupported').returns(true);
sandbox.stub(fullscreen, 'isFullscreen').returns(false);
describe('fullscreenExitHandler()', () => {
it('should remove the fullscreen class and not focus the element', () => {
const element = document.createElement('div');
element.classList.add(CLASS_FULLSCREEN);
sandbox.stub(element, 'focus');
sandbox.stub(fullscreen, 'emit');
sandbox.stub(fullscreen, 'focusFullscreenElement');
sandbox.stub(fullscreen, 'fullscreenElement').value(element);

fullscreen.fullscreenchangeHandler();
fullscreen.fullscreenExitHandler();

expect(element.classList.contains(CLASS_FULLSCREEN)).to.be.false;
expect(element.focus).not.to.have.been.called;
expect(fullscreen.emit).to.have.been.calledWith('exit');
expect(fullscreen.focusFullscreenElement).not.to.have.been.called;
});
});

it('should emit enter if we are entering fullscreen and if true fullscreen is not supported', () => {
sandbox.stub(fullscreen, 'isSupported').returns(false);
describe('enter()', () => {
beforeEach(() => {
sandbox.stub(fullscreen, 'fullscreenEnterHandler');
sandbox.stub(fullscreen, 'isFullscreen').returns(true);
sandbox.stub(fullscreen, 'emit');
sandbox.stub(fullscreen, 'focusFullscreenElement');

fullscreen.fullscreenchangeHandler();

expect(fullscreen.emit).to.have.been.calledWith('enter');
});

it('should emit exit if we are exiting fullscreen and if true fullscreen is not supported', () => {
sandbox.stub(fullscreen, 'isSupported').returns(false);
sandbox.stub(fullscreen, 'isFullscreen').returns(false);
sandbox.stub(fullscreen, 'emit');

fullscreen.fullscreenchangeHandler();

expect(fullscreen.emit).to.have.been.calledWith('exit');
});
});
it('should trigger native requestFullscreen handler if not in fullscreen and true fullscreen is supported', () => {
const fullscreenStub = sandbox.stub();
sandbox.stub(fscreen, 'requestFullscreenFunction').returns(fullscreenStub);
sandbox.stub(fullscreen, 'isSupported').returns(true);

describe('enter', () => {
it('should add the fullscreen class', () => {
const element = document.createElement('div');

fullscreen.enter(element);

expect(element.classList.contains(CLASS_FULLSCREEN)).to.be.true;
expect(fullscreenStub).to.have.been.calledWith(Element.ALLOW_KEYBOARD_INPUT);
});
});

describe('exit', () => {
it('should remove the fullscreen class', () => {
const element = document.createElement('div');
element.classList.add(CLASS_FULLSCREEN);
it('should trigger the fullscreenEnterHandler immediately if true fullscreen is not supported', () => {
sandbox.stub(fullscreen, 'isSupported').returns(false);

const element = document.createElement('div');
fullscreen.enter(element);

expect(element.classList.contains(CLASS_FULLSCREEN)).to.be.true;
expect(fullscreen.fullscreenEnterHandler).to.have.been.called;
});
});

describe('toggle()', () => {
describe('exit()', () => {
beforeEach(() => {
sandbox.stub(fullscreen, 'fullscreenElement').value(document.createElement('div'));
sandbox.stub(fullscreen, 'fullscreenExitHandler');
sandbox.stub(fullscreen, 'isFullscreen').returns(true);
});

it('should trigger native exitFullscreen handler if in fullscreen and true fullscreen is supported', () => {
const exitFullscreen = sinon.stub();
sandbox.stub(fscreen, 'exitFullscreen').value(exitFullscreen);
sandbox.stub(fullscreen, 'isSupported').returns(true);
sandbox.stub(fullscreen, 'isFullscreen').returns(true);

fullscreen.toggle({});
fullscreen.exit();

expect(exitFullscreen).to.have.been.called;
});

it('should trigger native requestFullscreen handler if not in fullscreen and true fullscreen is supported', () => {
it('should trigger the fullscreenExitHandler immediately if true fullscreen is not supported', () => {
sandbox.stub(fullscreen, 'isSupported').returns(false);

fullscreen.exit();

expect(fullscreen.fullscreenExitHandler).to.have.been.called;
});
});

describe('toggle()', () => {
beforeEach(() => {
sandbox.stub(fullscreen, 'enter');
sandbox.stub(fullscreen, 'exit');
sandbox.stub(fullscreen, 'isSupported').returns(false);
});

it('should call enter if not already in fullscreen', () => {
const element = document.createElement('div');
const fullscreenStub = sandbox.stub();
sandbox.stub(fscreen, 'requestFullscreenFunction').returns(fullscreenStub);
sandbox.stub(fullscreen, 'isSupported').returns(true);
sandbox.stub(fullscreen, 'isFullscreen').returns(false);

fullscreen.toggle(element);

expect(fullscreenStub).to.have.been.calledWith(Element.ALLOW_KEYBOARD_INPUT);
expect(fullscreen.enter).to.have.been.called;
});
});

describe('focusFullscreenElement()', () => {
it('should focus the element when event is passed in', () => {
it('should call exit if already in fullscreen', () => {
const element = document.createElement('div');
sandbox.stub(element, 'focus');
sandbox.stub(fscreen, 'fullscreenElement').value(element);
element.classList.add(CLASS_FULLSCREEN);

fullscreen.toggle(element);
fullscreen.focusFullscreenElement();

expect(fscreen.fullscreenElement.focus.called).to.be.true;
expect(fullscreen.exit).to.have.been.called;
});
});
});
Loading