new controller for speaker notes
This commit is contained in:
parent
2b02f3a1f9
commit
97ee72549b
7 changed files with 180 additions and 144 deletions
4
dist/reveal.min.js
vendored
4
dist/reveal.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Constructor for the playback component, which displays
|
||||
* play/pause/progress controls.
|
||||
* UI component that lets the user control pause/resume
|
||||
* and see the progress of auto-slide playback.
|
||||
*
|
||||
* @param {HTMLElement} container The component will append
|
||||
* itself to this
|
||||
|
|
|
@ -13,6 +13,20 @@ export default class Fragments {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever the reveal.js config is updated.
|
||||
*/
|
||||
configure( config, oldConfig ) {
|
||||
|
||||
if( config.fragments === false ) {
|
||||
this.disable();
|
||||
}
|
||||
else if( oldConfig.fragments === false ) {
|
||||
this.enable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If fragments are disabled in the deck, they should all be
|
||||
* visible rather than stepped through.
|
||||
|
|
|
@ -21,6 +21,32 @@ export default class Keyboard {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the reveal.js config is updated.
|
||||
*/
|
||||
configure( config, oldConfig ) {
|
||||
|
||||
if( config.navigationMode === 'linear' ) {
|
||||
this.shortcuts['→ , ↓ , SPACE , N , L , J'] = 'Next slide';
|
||||
this.shortcuts['← , ↑ , P , H , K'] = 'Previous slide';
|
||||
}
|
||||
else {
|
||||
this.shortcuts['N , SPACE'] = 'Next slide';
|
||||
this.shortcuts['P'] = 'Previous slide';
|
||||
this.shortcuts['← , H'] = 'Navigate left';
|
||||
this.shortcuts['→ , L'] = 'Navigate right';
|
||||
this.shortcuts['↑ , K'] = 'Navigate up';
|
||||
this.shortcuts['↓ , J'] = 'Navigate down';
|
||||
}
|
||||
|
||||
this.shortcuts['Home , Shift ←'] = 'First slide';
|
||||
this.shortcuts['End , Shift →'] = 'Last slide';
|
||||
this.shortcuts['B , .'] = 'Pause';
|
||||
this.shortcuts['F'] = 'Fullscreen';
|
||||
this.shortcuts['ESC, O'] = 'Slide overview';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts listening for keyboard events.
|
||||
*/
|
||||
|
@ -73,32 +99,6 @@ export default class Keyboard {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates our keyboard shortcuts based on current settings.
|
||||
*/
|
||||
refreshSortcuts() {
|
||||
|
||||
if( this.Reveal.getConfig().navigationMode === 'linear' ) {
|
||||
this.shortcuts['→ , ↓ , SPACE , N , L , J'] = 'Next slide';
|
||||
this.shortcuts['← , ↑ , P , H , K'] = 'Previous slide';
|
||||
}
|
||||
else {
|
||||
this.shortcuts['N , SPACE'] = 'Next slide';
|
||||
this.shortcuts['P'] = 'Previous slide';
|
||||
this.shortcuts['← , H'] = 'Navigate left';
|
||||
this.shortcuts['→ , L'] = 'Navigate right';
|
||||
this.shortcuts['↑ , K'] = 'Navigate up';
|
||||
this.shortcuts['↓ , J'] = 'Navigate down';
|
||||
}
|
||||
|
||||
this.shortcuts['Home , Shift ←'] = 'First slide';
|
||||
this.shortcuts['End , Shift →'] = 'Last slide';
|
||||
this.shortcuts['B , .'] = 'Pause';
|
||||
this.shortcuts['F'] = 'Fullscreen';
|
||||
this.shortcuts['ESC, O'] = 'Slide overview';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Programmatically triggers a keyboard event
|
||||
*
|
||||
|
|
116
js/controllers/notes.js
Normal file
116
js/controllers/notes.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { extend, toArray } from '../utils/util.js'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class Notes {
|
||||
|
||||
constructor( Reveal ) {
|
||||
|
||||
this.Reveal = Reveal;
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
this.element = document.createElement( 'div' );
|
||||
this.element.className = 'speaker-notes';
|
||||
this.element.setAttribute( 'data-prevent-swipe', '' );
|
||||
this.element.setAttribute( 'tabindex', '0' );
|
||||
this.Reveal.getRevealElement().appendChild( this.element );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the reveal.js config is updated.
|
||||
*/
|
||||
configure( config, oldConfig ) {
|
||||
|
||||
if( config.showNotes ) {
|
||||
this.element.setAttribute( 'data-layout', typeof config.showNotes === 'string' ? config.showNotes : 'inline' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick up notes from the current slide and display them
|
||||
* to the viewer.
|
||||
*
|
||||
* @see {@link config.showNotes}
|
||||
*/
|
||||
update() {
|
||||
|
||||
if( this.Reveal.getConfig().showNotes && this.element && this.Reveal.getCurrentSlide() && !this.Reveal.print.isPrintingPDF() ) {
|
||||
|
||||
this.element.innerHTML = this.getSlideNotes() || '<span class="notes-placeholder">No notes on this slide.</span>';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the visibility of the speaker notes sidebar that
|
||||
* is used to share annotated slides. The notes sidebar is
|
||||
* only visible if showNotes is true and there are notes on
|
||||
* one or more slides in the deck.
|
||||
*/
|
||||
updateVisibility() {
|
||||
|
||||
if( this.Reveal.getConfig().showNotes && this.hasNotes() ) {
|
||||
this.Reveal.getRevealElement().classList.add( 'show-notes' );
|
||||
}
|
||||
else {
|
||||
this.Reveal.getRevealElement().classList.remove( 'show-notes' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are speaker notes for ANY slide in the
|
||||
* presentation.
|
||||
*/
|
||||
hasNotes() {
|
||||
|
||||
return this.Reveal.getSlidesElement().querySelectorAll( '[data-notes], aside.notes' ).length > 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this presentation is running inside of the
|
||||
* speaker notes window.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isSpeakerNotes() {
|
||||
|
||||
return !!window.location.search.match( /receiver/gi );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the speaker notes from a slide. Notes can be
|
||||
* defined in two ways:
|
||||
* 1. As a data-notes attribute on the slide <section>
|
||||
* 2. As an <aside class="notes"> inside of the slide
|
||||
*
|
||||
* @param {HTMLElement} [slide=currentSlide]
|
||||
* @return {(string|null)}
|
||||
*/
|
||||
getSlideNotes( slide = this.Reveal.getCurrentSlide() ) {
|
||||
|
||||
// Notes can be specified via the data-notes attribute...
|
||||
if( slide.hasAttribute( 'data-notes' ) ) {
|
||||
return slide.getAttribute( 'data-notes' );
|
||||
}
|
||||
|
||||
// ... or using an <aside class="notes"> element
|
||||
let notesElement = slide.querySelector( 'aside.notes' );
|
||||
if( notesElement ) {
|
||||
return notesElement.innerHTML;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ export default class SlideNumber {
|
|||
|
||||
}
|
||||
|
||||
createElement() {
|
||||
render() {
|
||||
|
||||
this.element = document.createElement( 'div' );
|
||||
this.element.className = 'slide-number';
|
||||
|
@ -18,12 +18,9 @@ export default class SlideNumber {
|
|||
}
|
||||
|
||||
/**
|
||||
* Shows or hides the slide number depending on the
|
||||
* current config and state.
|
||||
* Called when the reveal.js config is updated.
|
||||
*/
|
||||
refreshVisibility() {
|
||||
|
||||
let config = this.Reveal.getConfig();
|
||||
configure( config, oldConfig ) {
|
||||
|
||||
let slideNumberDisplay = 'none';
|
||||
if( config.slideNumber && !this.Reveal.isPrintingPDF() ) {
|
||||
|
|
125
js/reveal.js
125
js/reveal.js
|
@ -9,6 +9,7 @@ import Location from './controllers/location.js'
|
|||
import Plugins from './controllers/plugins.js'
|
||||
import Print from './controllers/print.js'
|
||||
import Touch from './controllers/touch.js'
|
||||
import Notes from './controllers/notes.js'
|
||||
import Playback from './components/playback.js'
|
||||
import defaultConfig from './config.js'
|
||||
import { isMobile, isChrome, isAndroid, supportsZoom } from './utils/device.js'
|
||||
|
@ -82,6 +83,7 @@ export default function( revealElement, options ) {
|
|||
plugins = new Plugins( Reveal ),
|
||||
print = new Print( Reveal ),
|
||||
touch = new Touch( Reveal ),
|
||||
notes = new Notes( Reveal ),
|
||||
|
||||
// CSS transform that is currently applied to the slides container,
|
||||
// split into two groups
|
||||
|
@ -236,12 +238,10 @@ export default function( revealElement, options ) {
|
|||
<button class="navigate-down" aria-label="below slide"><div class="controls-arrow"></div></button>` );
|
||||
|
||||
// Slide number
|
||||
slideNumber.createElement();
|
||||
slideNumber.render();
|
||||
|
||||
// Element containing notes that are visible to the audience
|
||||
dom.speakerNotes = createSingletonNode( dom.wrapper, 'div', 'speaker-notes', null );
|
||||
dom.speakerNotes.setAttribute( 'data-prevent-swipe', '' );
|
||||
dom.speakerNotes.setAttribute( 'tabindex', '0' );
|
||||
// Slide notes
|
||||
notes.render();
|
||||
|
||||
// Overlay graphic which is displayed during the paused mode
|
||||
dom.pauseOverlay = createSingletonNode( dom.wrapper, 'div', 'pause-overlay', config.controls ? '<button class="resume-button">Resume presentation</button>' : null );
|
||||
|
@ -452,10 +452,6 @@ export default function( revealElement, options ) {
|
|||
resume();
|
||||
}
|
||||
|
||||
if( config.showNotes ) {
|
||||
dom.speakerNotes.setAttribute( 'data-layout', typeof config.showNotes === 'string' ? config.showNotes : 'inline' );
|
||||
}
|
||||
|
||||
if( config.mouseWheel ) {
|
||||
document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
|
||||
document.addEventListener( 'mousewheel', onDocumentMouseScroll, false );
|
||||
|
@ -506,14 +502,6 @@ export default function( revealElement, options ) {
|
|||
autoSlidePaused = false;
|
||||
}
|
||||
|
||||
// Update the state of our fragments
|
||||
if( config.fragments === false ) {
|
||||
fragments.disable();
|
||||
}
|
||||
else if( oldConfig.fragments === false ) {
|
||||
fragments.enable();
|
||||
}
|
||||
|
||||
// Add the navigation mode to the DOM so we can adjust styling
|
||||
if( config.navigationMode !== 'default' ) {
|
||||
dom.wrapper.setAttribute( 'data-navigation-mode', config.navigationMode );
|
||||
|
@ -522,8 +510,10 @@ export default function( revealElement, options ) {
|
|||
dom.wrapper.removeAttribute( 'data-navigation-mode' );
|
||||
}
|
||||
|
||||
slideNumber.refreshVisibility();
|
||||
keyboard.refreshSortcuts();
|
||||
notes.configure( config, oldConfig );
|
||||
fragments.configure( config, oldConfig );
|
||||
slideNumber.configure( config, oldConfig );
|
||||
keyboard.configure( config, oldConfig );
|
||||
|
||||
sync();
|
||||
|
||||
|
@ -1409,11 +1399,10 @@ export default function( revealElement, options ) {
|
|||
|
||||
updateControls();
|
||||
updateProgress();
|
||||
updateNotes();
|
||||
|
||||
notes.update();
|
||||
backgrounds.update();
|
||||
backgrounds.updateParallax();
|
||||
|
||||
slideNumber.update();
|
||||
fragments.update();
|
||||
|
||||
|
@ -1475,9 +1464,9 @@ export default function( revealElement, options ) {
|
|||
updateControls();
|
||||
updateProgress();
|
||||
updateSlidesVisibility();
|
||||
updateNotesVisibility();
|
||||
updateNotes();
|
||||
|
||||
notes.update();
|
||||
notes.updateVisibility();
|
||||
backgrounds.update( true );
|
||||
slideNumber.update();
|
||||
slideContent.formatEmbeddedContent();
|
||||
|
@ -1514,7 +1503,7 @@ export default function( revealElement, options ) {
|
|||
slideContent.load( slide );
|
||||
|
||||
backgrounds.update();
|
||||
updateNotes();
|
||||
notes.update();
|
||||
|
||||
}
|
||||
|
||||
|
@ -1767,49 +1756,6 @@ export default function( revealElement, options ) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick up notes from the current slide and display them
|
||||
* to the viewer.
|
||||
*
|
||||
* @see {@link config.showNotes}
|
||||
*/
|
||||
function updateNotes() {
|
||||
|
||||
if( config.showNotes && dom.speakerNotes && currentSlide && !print.isPrintingPDF() ) {
|
||||
|
||||
dom.speakerNotes.innerHTML = getSlideNotes() || '<span class="notes-placeholder">No notes on this slide.</span>';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the visibility of the speaker notes sidebar that
|
||||
* is used to share annotated slides. The notes sidebar is
|
||||
* only visible if showNotes is true and there are notes on
|
||||
* one or more slides in the deck.
|
||||
*/
|
||||
function updateNotesVisibility() {
|
||||
|
||||
if( config.showNotes && hasNotes() ) {
|
||||
dom.wrapper.classList.add( 'show-notes' );
|
||||
}
|
||||
else {
|
||||
dom.wrapper.classList.remove( 'show-notes' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are speaker notes for ANY slide in the
|
||||
* presentation.
|
||||
*/
|
||||
function hasNotes() {
|
||||
|
||||
return dom.slides.querySelectorAll( '[data-notes], aside.notes' ).length > 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the progress bar to reflect the current slide.
|
||||
*/
|
||||
|
@ -2036,18 +1982,6 @@ export default function( revealElement, options ) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this presentation is running inside of the
|
||||
* speaker notes window.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isSpeakerNotes() {
|
||||
|
||||
return !!window.location.search.match( /receiver/gi );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the h/v location and fragment of the current,
|
||||
* or specified, slide.
|
||||
|
@ -2227,32 +2161,6 @@ export default function( revealElement, options ) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the speaker notes from a slide. Notes can be
|
||||
* defined in two ways:
|
||||
* 1. As a data-notes attribute on the slide <section>
|
||||
* 2. As an <aside class="notes"> inside of the slide
|
||||
*
|
||||
* @param {HTMLElement} [slide=currentSlide]
|
||||
* @return {(string|null)}
|
||||
*/
|
||||
function getSlideNotes( slide = currentSlide ) {
|
||||
|
||||
// Notes can be specified via the data-notes attribute...
|
||||
if( slide.hasAttribute( 'data-notes' ) ) {
|
||||
return slide.getAttribute( 'data-notes' );
|
||||
}
|
||||
|
||||
// ... or using an <aside class="notes"> element
|
||||
let notesElement = slide.querySelector( 'aside.notes' );
|
||||
if( notesElement ) {
|
||||
return notesElement.innerHTML;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current state of the presentation as
|
||||
* an object. This state can then be restored at any
|
||||
|
@ -2789,7 +2697,7 @@ export default function( revealElement, options ) {
|
|||
// State checks
|
||||
isPaused,
|
||||
isAutoSliding,
|
||||
isSpeakerNotes,
|
||||
isSpeakerNotes: notes.isSpeakerNotes.bind( notes ),
|
||||
isOverview: overview.isActive.bind( overview ),
|
||||
isPrintingPDF: print.isPrintingPDF.bind( print ),
|
||||
|
||||
|
@ -2832,7 +2740,7 @@ export default function( revealElement, options ) {
|
|||
getSlideBackground,
|
||||
|
||||
// Returns the speaker notes string for a slide, or null
|
||||
getSlideNotes,
|
||||
getSlideNotes: notes.getSlideNotes.bind( notes ),
|
||||
|
||||
// Returns an array with all horizontal/vertical slides in the deck
|
||||
getHorizontalSlides,
|
||||
|
@ -2876,7 +2784,7 @@ export default function( revealElement, options ) {
|
|||
// Helper method, retrieves query string as a key:value map
|
||||
getQueryHash,
|
||||
|
||||
// Returns the top-level DOM element
|
||||
// Returns reveal.js DOM elements
|
||||
getRevealElement: () => dom.wrapper || document.querySelector( '.reveal' ),
|
||||
getSlidesElement: () => dom.slides,
|
||||
getBackgroundsElement: () => dom.background,
|
||||
|
@ -2892,6 +2800,7 @@ export default function( revealElement, options ) {
|
|||
announceStatus,
|
||||
getStatusText,
|
||||
|
||||
print,
|
||||
location,
|
||||
overview,
|
||||
fragments,
|
||||
|
|
Loading…
Reference in a new issue