Commit 664beff7 authored by Hakim El Hattab's avatar Hakim El Hattab
Browse files

add focus controller, manages keyboard focus across multiple embedded decks

parent 57107ebe
This diff is collapsed.
This diff is collapsed.
......@@ -57,6 +57,15 @@
</div>
</div>
<style>
.reveal {
border: 4px solid #ccc;
}
.reveal.focused {
border-color: #94b5ff;
}
</style>
<script src="../dist/reveal.js"></script>
<script src="../dist/plugin/highlight.js"></script>
<script src="../dist/plugin/markdown.js"></script>
......@@ -65,7 +74,8 @@
let deck1 = new Reveal( document.querySelector( '.deck1' ), {
embedded: true,
keyboard: false,
progress: false,
keyboardCondition: 'focused',
plugins: [ RevealHighlight ]
} );
deck1.on( 'slidechanged', () => {
......@@ -75,7 +85,8 @@
let deck2 = new Reveal( document.querySelector( '.deck2' ), {
embedded: true,
keyboard: true,
progress: false,
keyboardCondition: 'focused',
plugins: [ RevealMarkdown, RevealMath ]
} );
deck2.initialize().then( () => {
......
/**
* Manages focus when a presentation is embedded. This
* helps us only capture keyboard from the presentation
* a user is currently interacting with in a page where
* multiple presentations are embedded.
*/
const STATE_FOCUS = 'focus';
const STATE_BLUR = 'blur';
export default class Focus {
constructor( Reveal ) {
this.Reveal = Reveal;
this.onRevealPointerDown = this.onRevealPointerDown.bind( this );
this.onDocumentPointerDown = this.onDocumentPointerDown.bind( this );
}
/**
* Called when the reveal.js config is updated.
*/
configure( config, oldConfig ) {
if( config.embedded ) {
this.blur();
}
else {
this.focus();
this.unbind();
}
}
bind() {
if( this.Reveal.getConfig().embedded ) {
this.Reveal.getRevealElement().addEventListener( 'pointerdown', this.onRevealPointerDown, false );
}
}
unbind() {
this.Reveal.getRevealElement().removeEventListener( 'pointerdown', this.onRevealPointerDown, false );
document.removeEventListener( 'pointerdown', this.onDocumentPointerDown, false );
}
focus() {
if( this.state !== STATE_FOCUS ) {
this.Reveal.getRevealElement().classList.add( 'focused' );
document.addEventListener( 'pointerdown', this.onDocumentPointerDown, false );
}
this.state = STATE_FOCUS;
}
blur() {
if( this.state !== STATE_BLUR ) {
this.Reveal.getRevealElement().classList.remove( 'focused' );
document.removeEventListener( 'pointerdown', this.onDocumentPointerDown, false );
}
this.state = STATE_BLUR;
}
isFocused() {
return this.state === STATE_FOCUS;
}
onRevealPointerDown( event ) {
this.focus();
}
onDocumentPointerDown( event ) {
let revealElement = event.target.closest( '.reveal' );
if( !revealElement || revealElement !== this.Reveal.getRevealElement() ) {
this.blur();
}
}
}
\ No newline at end of file
......@@ -151,6 +151,12 @@ export default class Keyboard {
return true;
}
// If keyboardCondition is set, only capture keyboard events
// for embedded decks when they are focused
if( config.keyboardCondition === 'focused' && !this.Reveal.isFocused() ) {
return true;
}
// Shorthand
let keyCode = event.keyCode;
......
......@@ -12,6 +12,7 @@ import Pointer from './controllers/pointer.js'
import Plugins from './controllers/plugins.js'
import Print from './controllers/print.js'
import Touch from './controllers/touch.js'
import Focus from './controllers/focus.js'
import Notes from './controllers/notes.js'
import Playback from './components/playback.js'
import defaultConfig from './config.js'
......@@ -111,6 +112,7 @@ export default function( revealElement, options ) {
pointer = new Pointer( Reveal ),
plugins = new Plugins( Reveal ),
print = new Print( Reveal ),
focus = new Focus( Reveal ),
touch = new Touch( Reveal ),
notes = new Notes( Reveal );
......@@ -464,6 +466,7 @@ export default function( revealElement, options ) {
}
notes.configure( config, oldConfig );
focus.configure( config, oldConfig );
pointer.configure( config, oldConfig );
controls.configure( config, oldConfig );
progress.configure( config, oldConfig );
......@@ -489,6 +492,7 @@ export default function( revealElement, options ) {
if( config.progress ) progress.bind();
if( config.respondToHashChanges ) location.bind();
controls.bind();
focus.bind();
dom.slides.addEventListener( 'transitionend', onTransitionEnd, false );
dom.pauseOverlay.addEventListener( 'click', resume, false );
......@@ -507,6 +511,7 @@ export default function( revealElement, options ) {
eventsAreBound = false;
touch.unbind();
focus.unbind();
keyboard.unbind();
controls.unbind();
progress.unbind();
......@@ -2438,6 +2443,7 @@ export default function( revealElement, options ) {
isAutoSliding,
isSpeakerNotes: notes.isSpeakerNotesWindow.bind( notes ),
isOverview: overview.isActive.bind( overview ),
isFocused: focus.isFocused.bind( focus ),
isPrintingPDF: print.isPrintingPDF.bind( print ),
// Checks if reveal.js has been loaded and is ready for use
......@@ -2548,6 +2554,7 @@ export default function( revealElement, options ) {
// Controllers
print,
focus,
progress,
controls,
location,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment