summaryrefslogtreecommitdiffstats
path: root/geschichte/js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--geschichte/js/components/playback.js165
-rw-r--r--geschichte/js/config.js300
-rw-r--r--geschichte/js/controllers/autoanimate.js640
-rw-r--r--geschichte/js/controllers/backgrounds.js406
-rw-r--r--geschichte/js/controllers/controls.js266
-rw-r--r--geschichte/js/controllers/focus.js103
-rw-r--r--geschichte/js/controllers/fragments.js376
-rw-r--r--geschichte/js/controllers/jumptoslide.js170
-rw-r--r--geschichte/js/controllers/keyboard.js399
-rw-r--r--geschichte/js/controllers/location.js245
-rw-r--r--geschichte/js/controllers/notes.js120
-rw-r--r--geschichte/js/controllers/overview.js255
-rw-r--r--geschichte/js/controllers/plugins.js254
-rw-r--r--geschichte/js/controllers/pointer.js129
-rw-r--r--geschichte/js/controllers/print.js237
-rw-r--r--geschichte/js/controllers/progress.js110
-rw-r--r--geschichte/js/controllers/slidecontent.js480
-rw-r--r--geschichte/js/controllers/slidenumber.js132
-rw-r--r--geschichte/js/controllers/touch.js263
-rw-r--r--geschichte/js/index.js58
-rw-r--r--geschichte/js/reveal.js2836
-rw-r--r--geschichte/js/utils/color.js77
-rw-r--r--geschichte/js/utils/constants.js10
-rw-r--r--geschichte/js/utils/device.js8
-rw-r--r--geschichte/js/utils/loader.js46
-rw-r--r--geschichte/js/utils/util.js313
26 files changed, 0 insertions, 8398 deletions
diff --git a/geschichte/js/components/playback.js b/geschichte/js/components/playback.js
deleted file mode 100644
index 06fa7ba..0000000
--- a/geschichte/js/components/playback.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * UI component that lets the use control auto-slide
- * playback via play/pause.
- */
-export default class Playback {
-
- /**
- * @param {HTMLElement} container The component will append
- * itself to this
- * @param {function} progressCheck A method which will be
- * called frequently to get the current playback progress on
- * a range of 0-1
- */
- constructor( container, progressCheck ) {
-
- // Cosmetics
- this.diameter = 100;
- this.diameter2 = this.diameter/2;
- this.thickness = 6;
-
- // Flags if we are currently playing
- this.playing = false;
-
- // Current progress on a 0-1 range
- this.progress = 0;
-
- // Used to loop the animation smoothly
- this.progressOffset = 1;
-
- this.container = container;
- this.progressCheck = progressCheck;
-
- this.canvas = document.createElement( 'canvas' );
- this.canvas.className = 'playback';
- this.canvas.width = this.diameter;
- this.canvas.height = this.diameter;
- this.canvas.style.width = this.diameter2 + 'px';
- this.canvas.style.height = this.diameter2 + 'px';
- this.context = this.canvas.getContext( '2d' );
-
- this.container.appendChild( this.canvas );
-
- this.render();
-
- }
-
- setPlaying( value ) {
-
- const wasPlaying = this.playing;
-
- this.playing = value;
-
- // Start repainting if we weren't already
- if( !wasPlaying && this.playing ) {
- this.animate();
- }
- else {
- this.render();
- }
-
- }
-
- animate() {
-
- const progressBefore = this.progress;
-
- this.progress = this.progressCheck();
-
- // When we loop, offset the progress so that it eases
- // smoothly rather than immediately resetting
- if( progressBefore > 0.8 && this.progress < 0.2 ) {
- this.progressOffset = this.progress;
- }
-
- this.render();
-
- if( this.playing ) {
- requestAnimationFrame( this.animate.bind( this ) );
- }
-
- }
-
- /**
- * Renders the current progress and playback state.
- */
- render() {
-
- let progress = this.playing ? this.progress : 0,
- radius = ( this.diameter2 ) - this.thickness,
- x = this.diameter2,
- y = this.diameter2,
- iconSize = 28;
-
- // Ease towards 1
- this.progressOffset += ( 1 - this.progressOffset ) * 0.1;
-
- const endAngle = ( - Math.PI / 2 ) + ( progress * ( Math.PI * 2 ) );
- const startAngle = ( - Math.PI / 2 ) + ( this.progressOffset * ( Math.PI * 2 ) );
-
- this.context.save();
- this.context.clearRect( 0, 0, this.diameter, this.diameter );
-
- // Solid background color
- this.context.beginPath();
- this.context.arc( x, y, radius + 4, 0, Math.PI * 2, false );
- this.context.fillStyle = 'rgba( 0, 0, 0, 0.4 )';
- this.context.fill();
-
- // Draw progress track
- this.context.beginPath();
- this.context.arc( x, y, radius, 0, Math.PI * 2, false );
- this.context.lineWidth = this.thickness;
- this.context.strokeStyle = 'rgba( 255, 255, 255, 0.2 )';
- this.context.stroke();
-
- if( this.playing ) {
- // Draw progress on top of track
- this.context.beginPath();
- this.context.arc( x, y, radius, startAngle, endAngle, false );
- this.context.lineWidth = this.thickness;
- this.context.strokeStyle = '#fff';
- this.context.stroke();
- }
-
- this.context.translate( x - ( iconSize / 2 ), y - ( iconSize / 2 ) );
-
- // Draw play/pause icons
- if( this.playing ) {
- this.context.fillStyle = '#fff';
- this.context.fillRect( 0, 0, iconSize / 2 - 4, iconSize );
- this.context.fillRect( iconSize / 2 + 4, 0, iconSize / 2 - 4, iconSize );
- }
- else {
- this.context.beginPath();
- this.context.translate( 4, 0 );
- this.context.moveTo( 0, 0 );
- this.context.lineTo( iconSize - 4, iconSize / 2 );
- this.context.lineTo( 0, iconSize );
- this.context.fillStyle = '#fff';
- this.context.fill();
- }
-
- this.context.restore();
-
- }
-
- on( type, listener ) {
- this.canvas.addEventListener( type, listener, false );
- }
-
- off( type, listener ) {
- this.canvas.removeEventListener( type, listener, false );
- }
-
- destroy() {
-
- this.playing = false;
-
- if( this.canvas.parentNode ) {
- this.container.removeChild( this.canvas );
- }
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/config.js b/geschichte/js/config.js
deleted file mode 100644
index 8b7a883..0000000
--- a/geschichte/js/config.js
+++ /dev/null
@@ -1,300 +0,0 @@
-/**
- * The default reveal.js config object.
- */
-export default {
-
- // The "normal" size of the presentation, aspect ratio will be preserved
- // when the presentation is scaled to fit different resolutions
- width: 960,
- height: 700,
-
- // Factor of the display size that should remain empty around the content
- margin: 0.04,
-
- // Bounds for smallest/largest possible scale to apply to content
- minScale: 0.2,
- maxScale: 2.0,
-
- // Display presentation control arrows
- controls: true,
-
- // Help the user learn the controls by providing hints, for example by
- // bouncing the down arrow when they first encounter a vertical slide
- controlsTutorial: true,
-
- // Determines where controls appear, "edges" or "bottom-right"
- controlsLayout: 'bottom-right',
-
- // Visibility rule for backwards navigation arrows; "faded", "hidden"
- // or "visible"
- controlsBackArrows: 'faded',
-
- // Display a presentation progress bar
- progress: true,
-
- // Display the page number of the current slide
- // - true: Show slide number
- // - false: Hide slide number
- //
- // Can optionally be set as a string that specifies the number formatting:
- // - "h.v": Horizontal . vertical slide number (default)
- // - "h/v": Horizontal / vertical slide number
- // - "c": Flattened slide number
- // - "c/t": Flattened slide number / total slides
- //
- // Alternatively, you can provide a function that returns the slide
- // number for the current slide. The function should take in a slide
- // object and return an array with one string [slideNumber] or
- // three strings [n1,delimiter,n2]. See #formatSlideNumber().
- slideNumber: false,
-
- // Can be used to limit the contexts in which the slide number appears
- // - "all": Always show the slide number
- // - "print": Only when printing to PDF
- // - "speaker": Only in the speaker view
- showSlideNumber: 'all',
-
- // Use 1 based indexing for # links to match slide number (default is zero
- // based)
- hashOneBasedIndex: false,
-
- // Add the current slide number to the URL hash so that reloading the
- // page/copying the URL will return you to the same slide
- hash: false,
-
- // Flags if we should monitor the hash and change slides accordingly
- respondToHashChanges: true,
-
- // Enable support for jump-to-slide navigation shortcuts
- jumpToSlide: true,
-
- // Push each slide change to the browser history. Implies `hash: true`
- history: false,
-
- // Enable keyboard shortcuts for navigation
- keyboard: true,
-
- // Optional function that blocks keyboard events when retuning false
- //
- // If you set this to 'focused', we will only capture keyboard events
- // for embedded decks when they are in focus
- keyboardCondition: null,
-
- // Disables the default reveal.js slide layout (scaling and centering)
- // so that you can use custom CSS layout
- disableLayout: false,
-
- // Enable the slide overview mode
- overview: true,
-
- // Vertical centering of slides
- center: true,
-
- // Enables touch navigation on devices with touch input
- touch: true,
-
- // Loop the presentation
- loop: false,
-
- // Change the presentation direction to be RTL
- rtl: false,
-
- // Changes the behavior of our navigation directions.
- //
- // "default"
- // Left/right arrow keys step between horizontal slides, up/down
- // arrow keys step between vertical slides. Space key steps through
- // all slides (both horizontal and vertical).
- //
- // "linear"
- // Removes the up/down arrows. Left/right arrows step through all
- // slides (both horizontal and vertical).
- //
- // "grid"
- // When this is enabled, stepping left/right from a vertical stack
- // to an adjacent vertical stack will land you at the same vertical
- // index.
- //
- // Consider a deck with six slides ordered in two vertical stacks:
- // 1.1 2.1
- // 1.2 2.2
- // 1.3 2.3
- //
- // If you're on slide 1.3 and navigate right, you will normally move
- // from 1.3 -> 2.1. If "grid" is used, the same navigation takes you
- // from 1.3 -> 2.3.
- navigationMode: 'default',
-
- // Randomizes the order of slides each time the presentation loads
- shuffle: false,
-
- // Turns fragments on and off globally
- fragments: true,
-
- // Flags whether to include the current fragment in the URL,
- // so that reloading brings you to the same fragment position
- fragmentInURL: true,
-
- // Flags if the presentation is running in an embedded mode,
- // i.e. contained within a limited portion of the screen
- embedded: false,
-
- // Flags if we should show a help overlay when the question-mark
- // key is pressed
- help: true,
-
- // Flags if it should be possible to pause the presentation (blackout)
- pause: true,
-
- // Flags if speaker notes should be visible to all viewers
- showNotes: false,
-
- // Flags if slides with data-visibility="hidden" should be kep visible
- showHiddenSlides: false,
-
- // Global override for autoplaying embedded media (video/audio/iframe)
- // - null: Media will only autoplay if data-autoplay is present
- // - true: All media will autoplay, regardless of individual setting
- // - false: No media will autoplay, regardless of individual setting
- autoPlayMedia: null,
-
- // Global override for preloading lazy-loaded iframes
- // - null: Iframes with data-src AND data-preload will be loaded when within
- // the viewDistance, iframes with only data-src will be loaded when visible
- // - true: All iframes with data-src will be loaded when within the viewDistance
- // - false: All iframes with data-src will be loaded only when visible
- preloadIframes: null,
-
- // Can be used to globally disable auto-animation
- autoAnimate: true,
-
- // Optionally provide a custom element matcher that will be
- // used to dictate which elements we can animate between.
- autoAnimateMatcher: null,
-
- // Default settings for our auto-animate transitions, can be
- // overridden per-slide or per-element via data arguments
- autoAnimateEasing: 'ease',
- autoAnimateDuration: 1.0,
- autoAnimateUnmatched: true,
-
- // CSS properties that can be auto-animated. Position & scale
- // is matched separately so there's no need to include styles
- // like top/right/bottom/left, width/height or margin.
- autoAnimateStyles: [
- 'opacity',
- 'color',
- 'background-color',
- 'padding',
- 'font-size',
- 'line-height',
- 'letter-spacing',
- 'border-width',
- 'border-color',
- 'border-radius',
- 'outline',
- 'outline-offset'
- ],
-
- // Controls automatic progression to the next slide
- // - 0: Auto-sliding only happens if the data-autoslide HTML attribute
- // is present on the current slide or fragment
- // - 1+: All slides will progress automatically at the given interval
- // - false: No auto-sliding, even if data-autoslide is present
- autoSlide: 0,
-
- // Stop auto-sliding after user input
- autoSlideStoppable: true,
-
- // Use this method for navigation when auto-sliding (defaults to navigateNext)
- autoSlideMethod: null,
-
- // Specify the average time in seconds that you think you will spend
- // presenting each slide. This is used to show a pacing timer in the
- // speaker view
- defaultTiming: null,
-
- // Enable slide navigation via mouse wheel
- mouseWheel: false,
-
- // Opens links in an iframe preview overlay
- // Add `data-preview-link` and `data-preview-link="false"` to customise each link
- // individually
- previewLinks: false,
-
- // Exposes the reveal.js API through window.postMessage
- postMessage: true,
-
- // Dispatches all reveal.js events to the parent window through postMessage
- postMessageEvents: false,
-
- // Focuses body when page changes visibility to ensure keyboard shortcuts work
- focusBodyOnPageVisibilityChange: true,
-
- // Transition style
- transition: 'slide', // none/fade/slide/convex/concave/zoom
-
- // Transition speed
- transitionSpeed: 'default', // default/fast/slow
-
- // Transition style for full page slide backgrounds
- backgroundTransition: 'fade', // none/fade/slide/convex/concave/zoom
-
- // Parallax background image
- parallaxBackgroundImage: '', // CSS syntax, e.g. "a.jpg"
-
- // Parallax background size
- parallaxBackgroundSize: '', // CSS syntax, e.g. "3000px 2000px"
-
- // Parallax background repeat
- parallaxBackgroundRepeat: '', // repeat/repeat-x/repeat-y/no-repeat/initial/inherit
-
- // Parallax background position
- parallaxBackgroundPosition: '', // CSS syntax, e.g. "top left"
-
- // Amount of pixels to move the parallax background per slide step
- parallaxBackgroundHorizontal: null,
- parallaxBackgroundVertical: null,
-
- // The maximum number of pages a single slide can expand onto when printing
- // to PDF, unlimited by default
- pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY,
-
- // Prints each fragment on a separate slide
- pdfSeparateFragments: true,
-
- // Offset used to reduce the height of content within exported PDF pages.
- // This exists to account for environment differences based on how you
- // print to PDF. CLI printing options, like phantomjs and wkpdf, can end
- // on precisely the total height of the document whereas in-browser
- // printing has to end one pixel before.
- pdfPageHeightOffset: -1,
-
- // Number of slides away from the current that are visible
- viewDistance: 3,
-
- // Number of slides away from the current that are visible on mobile
- // devices. It is advisable to set this to a lower number than
- // viewDistance in order to save resources.
- mobileViewDistance: 2,
-
- // The display mode that will be used to show slides
- display: 'block',
-
- // Hide cursor if inactive
- hideInactiveCursor: true,
-
- // Time before the cursor is hidden (in ms)
- hideCursorTime: 5000,
-
- // Should we automatmically sort and set indices for fragments
- // at each sync? (See Reveal.sync)
- sortFragmentsOnSync: true,
-
- // Script dependencies to load
- dependencies: [],
-
- // Plugin objects to register and use for this presentation
- plugins: []
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/autoanimate.js b/geschichte/js/controllers/autoanimate.js
deleted file mode 100644
index 3fd2c99..0000000
--- a/geschichte/js/controllers/autoanimate.js
+++ /dev/null
@@ -1,640 +0,0 @@
-import { queryAll, extend, createStyleSheet, matches, closest } from '../utils/util.js'
-import { FRAGMENT_STYLE_REGEX } from '../utils/constants.js'
-
-// Counter used to generate unique IDs for auto-animated elements
-let autoAnimateCounter = 0;
-
-/**
- * Automatically animates matching elements across
- * slides with the [data-auto-animate] attribute.
- */
-export default class AutoAnimate {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- }
-
- /**
- * Runs an auto-animation between the given slides.
- *
- * @param {HTMLElement} fromSlide
- * @param {HTMLElement} toSlide
- */
- run( fromSlide, toSlide ) {
-
- // Clean up after prior animations
- this.reset();
-
- let allSlides = this.Reveal.getSlides();
- let toSlideIndex = allSlides.indexOf( toSlide );
- let fromSlideIndex = allSlides.indexOf( fromSlide );
-
- // Ensure that both slides are auto-animate targets with the same data-auto-animate-id value
- // (including null if absent on both) and that data-auto-animate-restart isn't set on the
- // physically latter slide (independent of slide direction)
- if( fromSlide.hasAttribute( 'data-auto-animate' ) && toSlide.hasAttribute( 'data-auto-animate' )
- && fromSlide.getAttribute( 'data-auto-animate-id' ) === toSlide.getAttribute( 'data-auto-animate-id' )
- && !( toSlideIndex > fromSlideIndex ? toSlide : fromSlide ).hasAttribute( 'data-auto-animate-restart' ) ) {
-
- // Create a new auto-animate sheet
- this.autoAnimateStyleSheet = this.autoAnimateStyleSheet || createStyleSheet();
-
- let animationOptions = this.getAutoAnimateOptions( toSlide );
-
- // Set our starting state
- fromSlide.dataset.autoAnimate = 'pending';
- toSlide.dataset.autoAnimate = 'pending';
-
- // Flag the navigation direction, needed for fragment buildup
- animationOptions.slideDirection = toSlideIndex > fromSlideIndex ? 'forward' : 'backward';
-
- // If the from-slide is hidden because it has moved outside
- // the view distance, we need to temporarily show it while
- // measuring
- let fromSlideIsHidden = fromSlide.style.display === 'none';
- if( fromSlideIsHidden ) fromSlide.style.display = this.Reveal.getConfig().display;
-
- // Inject our auto-animate styles for this transition
- let css = this.getAutoAnimatableElements( fromSlide, toSlide ).map( elements => {
- return this.autoAnimateElements( elements.from, elements.to, elements.options || {}, animationOptions, autoAnimateCounter++ );
- } );
-
- if( fromSlideIsHidden ) fromSlide.style.display = 'none';
-
- // Animate unmatched elements, if enabled
- if( toSlide.dataset.autoAnimateUnmatched !== 'false' && this.Reveal.getConfig().autoAnimateUnmatched === true ) {
-
- // Our default timings for unmatched elements
- let defaultUnmatchedDuration = animationOptions.duration * 0.8,
- defaultUnmatchedDelay = animationOptions.duration * 0.2;
-
- this.getUnmatchedAutoAnimateElements( toSlide ).forEach( unmatchedElement => {
-
- let unmatchedOptions = this.getAutoAnimateOptions( unmatchedElement, animationOptions );
- let id = 'unmatched';
-
- // If there is a duration or delay set specifically for this
- // element our unmatched elements should adhere to those
- if( unmatchedOptions.duration !== animationOptions.duration || unmatchedOptions.delay !== animationOptions.delay ) {
- id = 'unmatched-' + autoAnimateCounter++;
- css.push( `[data-auto-animate="running"] [data-auto-animate-target="${id}"] { transition: opacity ${unmatchedOptions.duration}s ease ${unmatchedOptions.delay}s; }` );
- }
-
- unmatchedElement.dataset.autoAnimateTarget = id;
-
- }, this );
-
- // Our default transition for unmatched elements
- css.push( `[data-auto-animate="running"] [data-auto-animate-target="unmatched"] { transition: opacity ${defaultUnmatchedDuration}s ease ${defaultUnmatchedDelay}s; }` );
-
- }
-
- // Setting the whole chunk of CSS at once is the most
- // efficient way to do this. Using sheet.insertRule
- // is multiple factors slower.
- this.autoAnimateStyleSheet.innerHTML = css.join( '' );
-
- // Start the animation next cycle
- requestAnimationFrame( () => {
- if( this.autoAnimateStyleSheet ) {
- // This forces our newly injected styles to be applied in Firefox
- getComputedStyle( this.autoAnimateStyleSheet ).fontWeight;
-
- toSlide.dataset.autoAnimate = 'running';
- }
- } );
-
- this.Reveal.dispatchEvent({
- type: 'autoanimate',
- data: {
- fromSlide,
- toSlide,
- sheet: this.autoAnimateStyleSheet
- }
- });
-
- }
-
- }
-
- /**
- * Rolls back all changes that we've made to the DOM so
- * that as part of animating.
- */
- reset() {
-
- // Reset slides
- queryAll( this.Reveal.getRevealElement(), '[data-auto-animate]:not([data-auto-animate=""])' ).forEach( element => {
- element.dataset.autoAnimate = '';
- } );
-
- // Reset elements
- queryAll( this.Reveal.getRevealElement(), '[data-auto-animate-target]' ).forEach( element => {
- delete element.dataset.autoAnimateTarget;
- } );
-
- // Remove the animation sheet
- if( this.autoAnimateStyleSheet && this.autoAnimateStyleSheet.parentNode ) {
- this.autoAnimateStyleSheet.parentNode.removeChild( this.autoAnimateStyleSheet );
- this.autoAnimateStyleSheet = null;
- }
-
- }
-
- /**
- * Creates a FLIP animation where the `to` element starts out
- * in the `from` element position and animates to its original
- * state.
- *
- * @param {HTMLElement} from
- * @param {HTMLElement} to
- * @param {Object} elementOptions Options for this element pair
- * @param {Object} animationOptions Options set at the slide level
- * @param {String} id Unique ID that we can use to identify this
- * auto-animate element in the DOM
- */
- autoAnimateElements( from, to, elementOptions, animationOptions, id ) {
-
- // 'from' elements are given a data-auto-animate-target with no value,
- // 'to' elements are are given a data-auto-animate-target with an ID
- from.dataset.autoAnimateTarget = '';
- to.dataset.autoAnimateTarget = id;
-
- // Each element may override any of the auto-animate options
- // like transition easing, duration and delay via data-attributes
- let options = this.getAutoAnimateOptions( to, animationOptions );
-
- // If we're using a custom element matcher the element options
- // may contain additional transition overrides
- if( typeof elementOptions.delay !== 'undefined' ) options.delay = elementOptions.delay;
- if( typeof elementOptions.duration !== 'undefined' ) options.duration = elementOptions.duration;
- if( typeof elementOptions.easing !== 'undefined' ) options.easing = elementOptions.easing;
-
- let fromProps = this.getAutoAnimatableProperties( 'from', from, elementOptions ),
- toProps = this.getAutoAnimatableProperties( 'to', to, elementOptions );
-
- // Maintain fragment visibility for matching elements when
- // we're navigating forwards, this way the viewer won't need
- // to step through the same fragments twice
- if( to.classList.contains( 'fragment' ) ) {
-
- // Don't auto-animate the opacity of fragments to avoid
- // conflicts with fragment animations
- delete toProps.styles['opacity'];
-
- if( from.classList.contains( 'fragment' ) ) {
-
- let fromFragmentStyle = ( from.className.match( FRAGMENT_STYLE_REGEX ) || [''] )[0];
- let toFragmentStyle = ( to.className.match( FRAGMENT_STYLE_REGEX ) || [''] )[0];
-
- // Only skip the fragment if the fragment animation style
- // remains unchanged
- if( fromFragmentStyle === toFragmentStyle && animationOptions.slideDirection === 'forward' ) {
- to.classList.add( 'visible', 'disabled' );
- }
-
- }
-
- }
-
- // If translation and/or scaling are enabled, css transform
- // the 'to' element so that it matches the position and size
- // of the 'from' element
- if( elementOptions.translate !== false || elementOptions.scale !== false ) {
-
- let presentationScale = this.Reveal.getScale();
-
- let delta = {
- x: ( fromProps.x - toProps.x ) / presentationScale,
- y: ( fromProps.y - toProps.y ) / presentationScale,
- scaleX: fromProps.width / toProps.width,
- scaleY: fromProps.height / toProps.height
- };
-
- // Limit decimal points to avoid 0.0001px blur and stutter
- delta.x = Math.round( delta.x * 1000 ) / 1000;
- delta.y = Math.round( delta.y * 1000 ) / 1000;
- delta.scaleX = Math.round( delta.scaleX * 1000 ) / 1000;
- delta.scaleX = Math.round( delta.scaleX * 1000 ) / 1000;
-
- let translate = elementOptions.translate !== false && ( delta.x !== 0 || delta.y !== 0 ),
- scale = elementOptions.scale !== false && ( delta.scaleX !== 0 || delta.scaleY !== 0 );
-
- // No need to transform if nothing's changed
- if( translate || scale ) {
-
- let transform = [];
-
- if( translate ) transform.push( `translate(${delta.x}px, ${delta.y}px)` );
- if( scale ) transform.push( `scale(${delta.scaleX}, ${delta.scaleY})` );
-
- fromProps.styles['transform'] = transform.join( ' ' );
- fromProps.styles['transform-origin'] = 'top left';
-
- toProps.styles['transform'] = 'none';
-
- }
-
- }
-
- // Delete all unchanged 'to' styles
- for( let propertyName in toProps.styles ) {
- const toValue = toProps.styles[propertyName];
- const fromValue = fromProps.styles[propertyName];
-
- if( toValue === fromValue ) {
- delete toProps.styles[propertyName];
- }
- else {
- // If these property values were set via a custom matcher providing
- // an explicit 'from' and/or 'to' value, we always inject those values.
- if( toValue.explicitValue === true ) {
- toProps.styles[propertyName] = toValue.value;
- }
-
- if( fromValue.explicitValue === true ) {
- fromProps.styles[propertyName] = fromValue.value;
- }
- }
- }
-
- let css = '';
-
- let toStyleProperties = Object.keys( toProps.styles );
-
- // Only create animate this element IF at least one style
- // property has changed
- if( toStyleProperties.length > 0 ) {
-
- // Instantly move to the 'from' state
- fromProps.styles['transition'] = 'none';
-
- // Animate towards the 'to' state
- toProps.styles['transition'] = `all ${options.duration}s ${options.easing} ${options.delay}s`;
- toProps.styles['transition-property'] = toStyleProperties.join( ', ' );
- toProps.styles['will-change'] = toStyleProperties.join( ', ' );
-
- // Build up our custom CSS. We need to override inline styles
- // so we need to make our styles vErY IMPORTANT!1!!
- let fromCSS = Object.keys( fromProps.styles ).map( propertyName => {
- return propertyName + ': ' + fromProps.styles[propertyName] + ' !important;';
- } ).join( '' );
-
- let toCSS = Object.keys( toProps.styles ).map( propertyName => {
- return propertyName + ': ' + toProps.styles[propertyName] + ' !important;';
- } ).join( '' );
-
- css = '[data-auto-animate-target="'+ id +'"] {'+ fromCSS +'}' +
- '[data-auto-animate="running"] [data-auto-animate-target="'+ id +'"] {'+ toCSS +'}';
-
- }
-
- return css;
-
- }
-
- /**
- * Returns the auto-animate options for the given element.
- *
- * @param {HTMLElement} element Element to pick up options
- * from, either a slide or an animation target
- * @param {Object} [inheritedOptions] Optional set of existing
- * options
- */
- getAutoAnimateOptions( element, inheritedOptions ) {
-
- let options = {
- easing: this.Reveal.getConfig().autoAnimateEasing,
- duration: this.Reveal.getConfig().autoAnimateDuration,
- delay: 0
- };
-
- options = extend( options, inheritedOptions );
-
- // Inherit options from parent elements
- if( element.parentNode ) {
- let autoAnimatedParent = closest( element.parentNode, '[data-auto-animate-target]' );
- if( autoAnimatedParent ) {
- options = this.getAutoAnimateOptions( autoAnimatedParent, options );
- }
- }
-
- if( element.dataset.autoAnimateEasing ) {
- options.easing = element.dataset.autoAnimateEasing;
- }
-
- if( element.dataset.autoAnimateDuration ) {
- options.duration = parseFloat( element.dataset.autoAnimateDuration );
- }
-
- if( element.dataset.autoAnimateDelay ) {
- options.delay = parseFloat( element.dataset.autoAnimateDelay );
- }
-
- return options;
-
- }
-
- /**
- * Returns an object containing all of the properties
- * that can be auto-animated for the given element and
- * their current computed values.
- *
- * @param {String} direction 'from' or 'to'
- */
- getAutoAnimatableProperties( direction, element, elementOptions ) {
-
- let config = this.Reveal.getConfig();
-
- let properties = { styles: [] };
-
- // Position and size
- if( elementOptions.translate !== false || elementOptions.scale !== false ) {
- let bounds;
-
- // Custom auto-animate may optionally return a custom tailored
- // measurement function
- if( typeof elementOptions.measure === 'function' ) {
- bounds = elementOptions.measure( element );
- }
- else {
- if( config.center ) {
- // More precise, but breaks when used in combination
- // with zoom for scaling the deck ¯\_(ツ)_/¯
- bounds = element.getBoundingClientRect();
- }
- else {
- let scale = this.Reveal.getScale();
- bounds = {
- x: element.offsetLeft * scale,
- y: element.offsetTop * scale,
- width: element.offsetWidth * scale,
- height: element.offsetHeight * scale
- };
- }
- }
-
- properties.x = bounds.x;
- properties.y = bounds.y;
- properties.width = bounds.width;
- properties.height = bounds.height;
- }
-
- const computedStyles = getComputedStyle( element );
-
- // CSS styles
- ( elementOptions.styles || config.autoAnimateStyles ).forEach( style => {
- let value;
-
- // `style` is either the property name directly, or an object
- // definition of a style property
- if( typeof style === 'string' ) style = { property: style };
-
- if( typeof style.from !== 'undefined' && direction === 'from' ) {
- value = { value: style.from, explicitValue: true };
- }
- else if( typeof style.to !== 'undefined' && direction === 'to' ) {
- value = { value: style.to, explicitValue: true };
- }
- else {
- // Use a unitless value for line-height so that it inherits properly
- if( style.property === 'line-height' ) {
- value = parseFloat( computedStyles['line-height'] ) / parseFloat( computedStyles['font-size'] );
- }
-
- if( isNaN(value) ) {
- value = computedStyles[style.property];
- }
- }
-
- if( value !== '' ) {
- properties.styles[style.property] = value;
- }
- } );
-
- return properties;
-
- }
-
- /**
- * Get a list of all element pairs that we can animate
- * between the given slides.
- *
- * @param {HTMLElement} fromSlide
- * @param {HTMLElement} toSlide
- *
- * @return {Array} Each value is an array where [0] is
- * the element we're animating from and [1] is the
- * element we're animating to
- */
- getAutoAnimatableElements( fromSlide, toSlide ) {
-
- let matcher = typeof this.Reveal.getConfig().autoAnimateMatcher === 'function' ? this.Reveal.getConfig().autoAnimateMatcher : this.getAutoAnimatePairs;
-
- let pairs = matcher.call( this, fromSlide, toSlide );
-
- let reserved = [];
-
- // Remove duplicate pairs
- return pairs.filter( ( pair, index ) => {
- if( reserved.indexOf( pair.to ) === -1 ) {
- reserved.push( pair.to );
- return true;
- }
- } );
-
- }
-
- /**
- * Identifies matching elements between slides.
- *
- * You can specify a custom matcher function by using
- * the `autoAnimateMatcher` config option.
- */
- getAutoAnimatePairs( fromSlide, toSlide ) {
-
- let pairs = [];
-
- const codeNodes = 'pre';
- const textNodes = 'h1, h2, h3, h4, h5, h6, p, li';
- const mediaNodes = 'img, video, iframe';
-
- // Explicit matches via data-id
- this.findAutoAnimateMatches( pairs, fromSlide, toSlide, '[data-id]', node => {
- return node.nodeName + ':::' + node.getAttribute( 'data-id' );
- } );
-
- // Text
- this.findAutoAnimateMatches( pairs, fromSlide, toSlide, textNodes, node => {
- return node.nodeName + ':::' + node.innerText;
- } );
-
- // Media
- this.findAutoAnimateMatches( pairs, fromSlide, toSlide, mediaNodes, node => {
- return node.nodeName + ':::' + ( node.getAttribute( 'src' ) || node.getAttribute( 'data-src' ) );
- } );
-
- // Code
- this.findAutoAnimateMatches( pairs, fromSlide, toSlide, codeNodes, node => {
- return node.nodeName + ':::' + node.innerText;
- } );
-
- pairs.forEach( pair => {
- // Disable scale transformations on text nodes, we transition
- // each individual text property instead
- if( matches( pair.from, textNodes ) ) {
- pair.options = { scale: false };
- }
- // Animate individual lines of code
- else if( matches( pair.from, codeNodes ) ) {
-
- // Transition the code block's width and height instead of scaling
- // to prevent its content from being squished
- pair.options = { scale: false, styles: [ 'width', 'height' ] };
-
- // Lines of code
- this.findAutoAnimateMatches( pairs, pair.from, pair.to, '.hljs .hljs-ln-code', node => {
- return node.textContent;
- }, {
- scale: false,
- styles: [],
- measure: this.getLocalBoundingBox.bind( this )
- } );
-
- // Line numbers
- this.findAutoAnimateMatches( pairs, pair.from, pair.to, '.hljs .hljs-ln-numbers[data-line-number]', node => {
- return node.getAttribute( 'data-line-number' );
- }, {
- scale: false,
- styles: [ 'width' ],
- measure: this.getLocalBoundingBox.bind( this )
- } );
-
- }
-
- }, this );
-
- return pairs;
-
- }
-
- /**
- * Helper method which returns a bounding box based on
- * the given elements offset coordinates.
- *
- * @param {HTMLElement} element
- * @return {Object} x, y, width, height
- */
- getLocalBoundingBox( element ) {
-
- const presentationScale = this.Reveal.getScale();
-
- return {
- x: Math.round( ( element.offsetLeft * presentationScale ) * 100 ) / 100,
- y: Math.round( ( element.offsetTop * presentationScale ) * 100 ) / 100,
- width: Math.round( ( element.offsetWidth * presentationScale ) * 100 ) / 100,
- height: Math.round( ( element.offsetHeight * presentationScale ) * 100 ) / 100
- };
-
- }
-
- /**
- * Finds matching elements between two slides.
- *
- * @param {Array} pairs List of pairs to push matches to
- * @param {HTMLElement} fromScope Scope within the from element exists
- * @param {HTMLElement} toScope Scope within the to element exists
- * @param {String} selector CSS selector of the element to match
- * @param {Function} serializer A function that accepts an element and returns
- * a stringified ID based on its contents
- * @param {Object} animationOptions Optional config options for this pair
- */
- findAutoAnimateMatches( pairs, fromScope, toScope, selector, serializer, animationOptions ) {
-
- let fromMatches = {};
- let toMatches = {};
-
- [].slice.call( fromScope.querySelectorAll( selector ) ).forEach( ( element, i ) => {
- const key = serializer( element );
- if( typeof key === 'string' && key.length ) {
- fromMatches[key] = fromMatches[key] || [];
- fromMatches[key].push( element );
- }
- } );
-
- [].slice.call( toScope.querySelectorAll( selector ) ).forEach( ( element, i ) => {
- const key = serializer( element );
- toMatches[key] = toMatches[key] || [];
- toMatches[key].push( element );
-
- let fromElement;
-
- // Retrieve the 'from' element
- if( fromMatches[key] ) {
- const primaryIndex = toMatches[key].length - 1;
- const secondaryIndex = fromMatches[key].length - 1;
-
- // If there are multiple identical from elements, retrieve
- // the one at the same index as our to-element.
- if( fromMatches[key][ primaryIndex ] ) {
- fromElement = fromMatches[key][ primaryIndex ];
- fromMatches[key][ primaryIndex ] = null;
- }
- // If there are no matching from-elements at the same index,
- // use the last one.
- else if( fromMatches[key][ secondaryIndex ] ) {
- fromElement = fromMatches[key][ secondaryIndex ];
- fromMatches[key][ secondaryIndex ] = null;
- }
- }
-
- // If we've got a matching pair, push it to the list of pairs
- if( fromElement ) {
- pairs.push({
- from: fromElement,
- to: element,
- options: animationOptions
- });
- }
- } );
-
- }
-
- /**
- * Returns a all elements within the given scope that should
- * be considered unmatched in an auto-animate transition. If
- * fading of unmatched elements is turned on, these elements
- * will fade when going between auto-animate slides.
- *
- * Note that parents of auto-animate targets are NOT considered
- * unmatched since fading them would break the auto-animation.
- *
- * @param {HTMLElement} rootElement
- * @return {Array}
- */
- getUnmatchedAutoAnimateElements( rootElement ) {
-
- return [].slice.call( rootElement.children ).reduce( ( result, element ) => {
-
- const containsAnimatedElements = element.querySelector( '[data-auto-animate-target]' );
-
- // The element is unmatched if
- // - It is not an auto-animate target
- // - It does not contain any auto-animate targets
- if( !element.hasAttribute( 'data-auto-animate-target' ) && !containsAnimatedElements ) {
- result.push( element );
- }
-
- if( element.querySelector( '[data-auto-animate-target]' ) ) {
- result = result.concat( this.getUnmatchedAutoAnimateElements( element ) );
- }
-
- return result;
-
- }, [] );
-
- }
-
-}
diff --git a/geschichte/js/controllers/backgrounds.js b/geschichte/js/controllers/backgrounds.js
deleted file mode 100644
index f906269..0000000
--- a/geschichte/js/controllers/backgrounds.js
+++ /dev/null
@@ -1,406 +0,0 @@
-import { queryAll } from '../utils/util.js'
-import { colorToRgb, colorBrightness } from '../utils/color.js'
-
-/**
- * Creates and updates slide backgrounds.
- */
-export default class Backgrounds {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- }
-
- render() {
-
- this.element = document.createElement( 'div' );
- this.element.className = 'backgrounds';
- this.Reveal.getRevealElement().appendChild( this.element );
-
- }
-
- /**
- * Creates the slide background elements and appends them
- * to the background container. One element is created per
- * slide no matter if the given slide has visible background.
- */
- create() {
-
- // Clear prior backgrounds
- this.element.innerHTML = '';
- this.element.classList.add( 'no-transition' );
-
- // Iterate over all horizontal slides
- this.Reveal.getHorizontalSlides().forEach( slideh => {
-
- let backgroundStack = this.createBackground( slideh, this.element );
-
- // Iterate over all vertical slides
- queryAll( slideh, 'section' ).forEach( slidev => {
-
- this.createBackground( slidev, backgroundStack );
-
- backgroundStack.classList.add( 'stack' );
-
- } );
-
- } );
-
- // Add parallax background if specified
- if( this.Reveal.getConfig().parallaxBackgroundImage ) {
-
- this.element.style.backgroundImage = 'url("' + this.Reveal.getConfig().parallaxBackgroundImage + '")';
- this.element.style.backgroundSize = this.Reveal.getConfig().parallaxBackgroundSize;
- this.element.style.backgroundRepeat = this.Reveal.getConfig().parallaxBackgroundRepeat;
- this.element.style.backgroundPosition = this.Reveal.getConfig().parallaxBackgroundPosition;
-
- // Make sure the below properties are set on the element - these properties are
- // needed for proper transitions to be set on the element via CSS. To remove
- // annoying background slide-in effect when the presentation starts, apply
- // these properties after short time delay
- setTimeout( () => {
- this.Reveal.getRevealElement().classList.add( 'has-parallax-background' );
- }, 1 );
-
- }
- else {
-
- this.element.style.backgroundImage = '';
- this.Reveal.getRevealElement().classList.remove( 'has-parallax-background' );
-
- }
-
- }
-
- /**
- * Creates a background for the given slide.
- *
- * @param {HTMLElement} slide
- * @param {HTMLElement} container The element that the background
- * should be appended to
- * @return {HTMLElement} New background div
- */
- createBackground( slide, container ) {
-
- // Main slide background element
- let element = document.createElement( 'div' );
- element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );
-
- // Inner background element that wraps images/videos/iframes
- let contentElement = document.createElement( 'div' );
- contentElement.className = 'slide-background-content';
-
- element.appendChild( contentElement );
- container.appendChild( element );
-
- slide.slideBackgroundElement = element;
- slide.slideBackgroundContentElement = contentElement;
-
- // Syncs the background to reflect all current background settings
- this.sync( slide );
-
- return element;
-
- }
-
- /**
- * Renders all of the visual properties of a slide background
- * based on the various background attributes.
- *
- * @param {HTMLElement} slide
- */
- sync( slide ) {
-
- const element = slide.slideBackgroundElement,
- contentElement = slide.slideBackgroundContentElement;
-
- const data = {
- background: slide.getAttribute( 'data-background' ),
- backgroundSize: slide.getAttribute( 'data-background-size' ),
- backgroundImage: slide.getAttribute( 'data-background-image' ),
- backgroundVideo: slide.getAttribute( 'data-background-video' ),
- backgroundIframe: slide.getAttribute( 'data-background-iframe' ),
- backgroundColor: slide.getAttribute( 'data-background-color' ),
- backgroundGradient: slide.getAttribute( 'data-background-gradient' ),
- backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
- backgroundPosition: slide.getAttribute( 'data-background-position' ),
- backgroundTransition: slide.getAttribute( 'data-background-transition' ),
- backgroundOpacity: slide.getAttribute( 'data-background-opacity' ),
- };
-
- const dataPreload = slide.hasAttribute( 'data-preload' );
-
- // Reset the prior background state in case this is not the
- // initial sync
- slide.classList.remove( 'has-dark-background' );
- slide.classList.remove( 'has-light-background' );
-
- element.removeAttribute( 'data-loaded' );
- element.removeAttribute( 'data-background-hash' );
- element.removeAttribute( 'data-background-size' );
- element.removeAttribute( 'data-background-transition' );
- element.style.backgroundColor = '';
-
- contentElement.style.backgroundSize = '';
- contentElement.style.backgroundRepeat = '';
- contentElement.style.backgroundPosition = '';
- contentElement.style.backgroundImage = '';
- contentElement.style.opacity = '';
- contentElement.innerHTML = '';
-
- if( data.background ) {
- // Auto-wrap image urls in url(...)
- if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp|webp)([?#\s]|$)/gi.test( data.background ) ) {
- slide.setAttribute( 'data-background-image', data.background );
- }
- else {
- element.style.background = data.background;
- }
- }
-
- // Create a hash for this combination of background settings.
- // This is used to determine when two slide backgrounds are
- // the same.
- if( data.background || data.backgroundColor || data.backgroundGradient || data.backgroundImage || data.backgroundVideo || data.backgroundIframe ) {
- element.setAttribute( 'data-background-hash', data.background +
- data.backgroundSize +
- data.backgroundImage +
- data.backgroundVideo +
- data.backgroundIframe +
- data.backgroundColor +
- data.backgroundGradient +
- data.backgroundRepeat +
- data.backgroundPosition +
- data.backgroundTransition +
- data.backgroundOpacity );
- }
-
- // Additional and optional background properties
- if( data.backgroundSize ) element.setAttribute( 'data-background-size', data.backgroundSize );
- if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
- if( data.backgroundGradient ) element.style.backgroundImage = data.backgroundGradient;
- if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
-
- if( dataPreload ) element.setAttribute( 'data-preload', '' );
-
- // Background image options are set on the content wrapper
- if( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize;
- if( data.backgroundRepeat ) contentElement.style.backgroundRepeat = data.backgroundRepeat;
- if( data.backgroundPosition ) contentElement.style.backgroundPosition = data.backgroundPosition;
- if( data.backgroundOpacity ) contentElement.style.opacity = data.backgroundOpacity;
-
- // If this slide has a background color, we add a class that
- // signals if it is light or dark. If the slide has no background
- // color, no class will be added
- let contrastColor = data.backgroundColor;
-
- // If no bg color was found, or it cannot be converted by colorToRgb, check the computed background
- if( !contrastColor || !colorToRgb( contrastColor ) ) {
- let computedBackgroundStyle = window.getComputedStyle( element );
- if( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) {
- contrastColor = computedBackgroundStyle.backgroundColor;
- }
- }
-
- if( contrastColor ) {
- const rgb = colorToRgb( contrastColor );
-
- // Ignore fully transparent backgrounds. Some browsers return
- // rgba(0,0,0,0) when reading the computed background color of
- // an element with no background
- if( rgb && rgb.a !== 0 ) {
- if( colorBrightness( contrastColor ) < 128 ) {
- slide.classList.add( 'has-dark-background' );
- }
- else {
- slide.classList.add( 'has-light-background' );
- }
- }
- }
-
- }
-
- /**
- * Updates the background elements to reflect the current
- * slide.
- *
- * @param {boolean} includeAll If true, the backgrounds of
- * all vertical slides (not just the present) will be updated.
- */
- update( includeAll = false ) {
-
- let currentSlide = this.Reveal.getCurrentSlide();
- let indices = this.Reveal.getIndices();
-
- let currentBackground = null;
-
- // Reverse past/future classes when in RTL mode
- let horizontalPast = this.Reveal.getConfig().rtl ? 'future' : 'past',
- horizontalFuture = this.Reveal.getConfig().rtl ? 'past' : 'future';
-
- // Update the classes of all backgrounds to match the
- // states of their slides (past/present/future)
- Array.from( this.element.childNodes ).forEach( ( backgroundh, h ) => {
-
- backgroundh.classList.remove( 'past', 'present', 'future' );
-
- if( h < indices.h ) {
- backgroundh.classList.add( horizontalPast );
- }
- else if ( h > indices.h ) {
- backgroundh.classList.add( horizontalFuture );
- }
- else {
- backgroundh.classList.add( 'present' );
-
- // Store a reference to the current background element
- currentBackground = backgroundh;
- }
-
- if( includeAll || h === indices.h ) {
- queryAll( backgroundh, '.slide-background' ).forEach( ( backgroundv, v ) => {
-
- backgroundv.classList.remove( 'past', 'present', 'future' );
-
- if( v < indices.v ) {
- backgroundv.classList.add( 'past' );
- }
- else if ( v > indices.v ) {
- backgroundv.classList.add( 'future' );
- }
- else {
- backgroundv.classList.add( 'present' );
-
- // Only if this is the present horizontal and vertical slide
- if( h === indices.h ) currentBackground = backgroundv;
- }
-
- } );
- }
-
- } );
-
- // Stop content inside of previous backgrounds
- if( this.previousBackground ) {
-
- this.Reveal.slideContent.stopEmbeddedContent( this.previousBackground, { unloadIframes: !this.Reveal.slideContent.shouldPreload( this.previousBackground ) } );
-
- }
-
- // Start content in the current background
- if( currentBackground ) {
-
- this.Reveal.slideContent.startEmbeddedContent( currentBackground );
-
- let currentBackgroundContent = currentBackground.querySelector( '.slide-background-content' );
- if( currentBackgroundContent ) {
-
- let backgroundImageURL = currentBackgroundContent.style.backgroundImage || '';
-
- // Restart GIFs (doesn't work in Firefox)
- if( /\.gif/i.test( backgroundImageURL ) ) {
- currentBackgroundContent.style.backgroundImage = '';
- window.getComputedStyle( currentBackgroundContent ).opacity;
- currentBackgroundContent.style.backgroundImage = backgroundImageURL;
- }
-
- }
-
- // Don't transition between identical backgrounds. This
- // prevents unwanted flicker.
- let previousBackgroundHash = this.previousBackground ? this.previousBackground.getAttribute( 'data-background-hash' ) : null;
- let currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' );
- if( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== this.previousBackground ) {
- this.element.classList.add( 'no-transition' );
- }
-
- this.previousBackground = currentBackground;
-
- }
-
- // If there's a background brightness flag for this slide,
- // bubble it to the .reveal container
- if( currentSlide ) {
- [ 'has-light-background', 'has-dark-background' ].forEach( classToBubble => {
- if( currentSlide.classList.contains( classToBubble ) ) {
- this.Reveal.getRevealElement().classList.add( classToBubble );
- }
- else {
- this.Reveal.getRevealElement().classList.remove( classToBubble );
- }
- }, this );
- }
-
- // Allow the first background to apply without transition
- setTimeout( () => {
- this.element.classList.remove( 'no-transition' );
- }, 1 );
-
- }
-
- /**
- * Updates the position of the parallax background based
- * on the current slide index.
- */
- updateParallax() {
-
- let indices = this.Reveal.getIndices();
-
- if( this.Reveal.getConfig().parallaxBackgroundImage ) {
-
- let horizontalSlides = this.Reveal.getHorizontalSlides(),
- verticalSlides = this.Reveal.getVerticalSlides();
-
- let backgroundSize = this.element.style.backgroundSize.split( ' ' ),
- backgroundWidth, backgroundHeight;
-
- if( backgroundSize.length === 1 ) {
- backgroundWidth = backgroundHeight = parseInt( backgroundSize[0], 10 );
- }
- else {
- backgroundWidth = parseInt( backgroundSize[0], 10 );
- backgroundHeight = parseInt( backgroundSize[1], 10 );
- }
-
- let slideWidth = this.element.offsetWidth,
- horizontalSlideCount = horizontalSlides.length,
- horizontalOffsetMultiplier,
- horizontalOffset;
-
- if( typeof this.Reveal.getConfig().parallaxBackgroundHorizontal === 'number' ) {
- horizontalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundHorizontal;
- }
- else {
- horizontalOffsetMultiplier = horizontalSlideCount > 1 ? ( backgroundWidth - slideWidth ) / ( horizontalSlideCount-1 ) : 0;
- }
-
- horizontalOffset = horizontalOffsetMultiplier * indices.h * -1;
-
- let slideHeight = this.element.offsetHeight,
- verticalSlideCount = verticalSlides.length,
- verticalOffsetMultiplier,
- verticalOffset;
-
- if( typeof this.Reveal.getConfig().parallaxBackgroundVertical === 'number' ) {
- verticalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundVertical;
- }
- else {
- verticalOffsetMultiplier = ( backgroundHeight - slideHeight ) / ( verticalSlideCount-1 );
- }
-
- verticalOffset = verticalSlideCount > 0 ? verticalOffsetMultiplier * indices.v : 0;
-
- this.element.style.backgroundPosition = horizontalOffset + 'px ' + -verticalOffset + 'px';
-
- }
-
- }
-
- destroy() {
-
- this.element.remove();
-
- }
-
-}
diff --git a/geschichte/js/controllers/controls.js b/geschichte/js/controllers/controls.js
deleted file mode 100644
index 734eb17..0000000
--- a/geschichte/js/controllers/controls.js
+++ /dev/null
@@ -1,266 +0,0 @@
-import { queryAll } from '../utils/util.js'
-import { isAndroid } from '../utils/device.js'
-
-/**
- * Manages our presentation controls. This includes both
- * the built-in control arrows as well as event monitoring
- * of any elements within the presentation with either of the
- * following helper classes:
- * - .navigate-up
- * - .navigate-right
- * - .navigate-down
- * - .navigate-left
- * - .navigate-next
- * - .navigate-prev
- */
-export default class Controls {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- this.onNavigateLeftClicked = this.onNavigateLeftClicked.bind( this );
- this.onNavigateRightClicked = this.onNavigateRightClicked.bind( this );
- this.onNavigateUpClicked = this.onNavigateUpClicked.bind( this );
- this.onNavigateDownClicked = this.onNavigateDownClicked.bind( this );
- this.onNavigatePrevClicked = this.onNavigatePrevClicked.bind( this );
- this.onNavigateNextClicked = this.onNavigateNextClicked.bind( this );
-
- }
-
- render() {
-
- const rtl = this.Reveal.getConfig().rtl;
- const revealElement = this.Reveal.getRevealElement();
-
- this.element = document.createElement( 'aside' );
- this.element.className = 'controls';
- this.element.innerHTML =
- `<button class="navigate-left" aria-label="${ rtl ? 'next slide' : 'previous slide' }"><div class="controls-arrow"></div></button>
- <button class="navigate-right" aria-label="${ rtl ? 'previous slide' : 'next slide' }"><div class="controls-arrow"></div></button>
- <button class="navigate-up" aria-label="above slide"><div class="controls-arrow"></div></button>
- <button class="navigate-down" aria-label="below slide"><div class="controls-arrow"></div></button>`;
-
- this.Reveal.getRevealElement().appendChild( this.element );
-
- // There can be multiple instances of controls throughout the page
- this.controlsLeft = queryAll( revealElement, '.navigate-left' );
- this.controlsRight = queryAll( revealElement, '.navigate-right' );
- this.controlsUp = queryAll( revealElement, '.navigate-up' );
- this.controlsDown = queryAll( revealElement, '.navigate-down' );
- this.controlsPrev = queryAll( revealElement, '.navigate-prev' );
- this.controlsNext = queryAll( revealElement, '.navigate-next' );
-
- // The left, right and down arrows in the standard reveal.js controls
- this.controlsRightArrow = this.element.querySelector( '.navigate-right' );
- this.controlsLeftArrow = this.element.querySelector( '.navigate-left' );
- this.controlsDownArrow = this.element.querySelector( '.navigate-down' );
-
- }
-
- /**
- * Called when the reveal.js config is updated.
- */
- configure( config, oldConfig ) {
-
- this.element.style.display = config.controls ? 'block' : 'none';
-
- this.element.setAttribute( 'data-controls-layout', config.controlsLayout );
- this.element.setAttribute( 'data-controls-back-arrows', config.controlsBackArrows );
-
- }
-
- bind() {
-
- // Listen to both touch and click events, in case the device
- // supports both
- let pointerEvents = [ 'touchstart', 'click' ];
-
- // Only support touch for Android, fixes double navigations in
- // stock browser
- if( isAndroid ) {
- pointerEvents = [ 'touchstart' ];
- }
-
- pointerEvents.forEach( eventName => {
- this.controlsLeft.forEach( el => el.addEventListener( eventName, this.onNavigateLeftClicked, false ) );
- this.controlsRight.forEach( el => el.addEventListener( eventName, this.onNavigateRightClicked, false ) );
- this.controlsUp.forEach( el => el.addEventListener( eventName, this.onNavigateUpClicked, false ) );
- this.controlsDown.forEach( el => el.addEventListener( eventName, this.onNavigateDownClicked, false ) );
- this.controlsPrev.forEach( el => el.addEventListener( eventName, this.onNavigatePrevClicked, false ) );
- this.controlsNext.forEach( el => el.addEventListener( eventName, this.onNavigateNextClicked, false ) );
- } );
-
- }
-
- unbind() {
-
- [ 'touchstart', 'click' ].forEach( eventName => {
- this.controlsLeft.forEach( el => el.removeEventListener( eventName, this.onNavigateLeftClicked, false ) );
- this.controlsRight.forEach( el => el.removeEventListener( eventName, this.onNavigateRightClicked, false ) );
- this.controlsUp.forEach( el => el.removeEventListener( eventName, this.onNavigateUpClicked, false ) );
- this.controlsDown.forEach( el => el.removeEventListener( eventName, this.onNavigateDownClicked, false ) );
- this.controlsPrev.forEach( el => el.removeEventListener( eventName, this.onNavigatePrevClicked, false ) );
- this.controlsNext.forEach( el => el.removeEventListener( eventName, this.onNavigateNextClicked, false ) );
- } );
-
- }
-
- /**
- * Updates the state of all control/navigation arrows.
- */
- update() {
-
- let routes = this.Reveal.availableRoutes();
-
- // Remove the 'enabled' class from all directions
- [...this.controlsLeft, ...this.controlsRight, ...this.controlsUp, ...this.controlsDown, ...this.controlsPrev, ...this.controlsNext].forEach( node => {
- node.classList.remove( 'enabled', 'fragmented' );
-
- // Set 'disabled' attribute on all directions
- node.setAttribute( 'disabled', 'disabled' );
- } );
-
- // Add the 'enabled' class to the available routes; remove 'disabled' attribute to enable buttons
- if( routes.left ) this.controlsLeft.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( routes.right ) this.controlsRight.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( routes.up ) this.controlsUp.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( routes.down ) this.controlsDown.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
-
- // Prev/next buttons
- if( routes.left || routes.up ) this.controlsPrev.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( routes.right || routes.down ) this.controlsNext.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
-
- // Highlight fragment directions
- let currentSlide = this.Reveal.getCurrentSlide();
- if( currentSlide ) {
-
- let fragmentsRoutes = this.Reveal.fragments.availableRoutes();
-
- // Always apply fragment decorator to prev/next buttons
- if( fragmentsRoutes.prev ) this.controlsPrev.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( fragmentsRoutes.next ) this.controlsNext.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
-
- // Apply fragment decorators to directional buttons based on
- // what slide axis they are in
- if( this.Reveal.isVerticalSlide( currentSlide ) ) {
- if( fragmentsRoutes.prev ) this.controlsUp.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( fragmentsRoutes.next ) this.controlsDown.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
- }
- else {
- if( fragmentsRoutes.prev ) this.controlsLeft.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
- if( fragmentsRoutes.next ) this.controlsRight.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
- }
-
- }
-
- if( this.Reveal.getConfig().controlsTutorial ) {
-
- let indices = this.Reveal.getIndices();
-
- // Highlight control arrows with an animation to ensure
- // that the viewer knows how to navigate
- if( !this.Reveal.hasNavigatedVertically() && routes.down ) {
- this.controlsDownArrow.classList.add( 'highlight' );
- }
- else {
- this.controlsDownArrow.classList.remove( 'highlight' );
-
- if( this.Reveal.getConfig().rtl ) {
-
- if( !this.Reveal.hasNavigatedHorizontally() && routes.left && indices.v === 0 ) {
- this.controlsLeftArrow.classList.add( 'highlight' );
- }
- else {
- this.controlsLeftArrow.classList.remove( 'highlight' );
- }
-
- } else {
-
- if( !this.Reveal.hasNavigatedHorizontally() && routes.right && indices.v === 0 ) {
- this.controlsRightArrow.classList.add( 'highlight' );
- }
- else {
- this.controlsRightArrow.classList.remove( 'highlight' );
- }
- }
- }
- }
- }
-
- destroy() {
-
- this.unbind();
- this.element.remove();
-
- }
-
- /**
- * Event handlers for navigation control buttons.
- */
- onNavigateLeftClicked( event ) {
-
- event.preventDefault();
- this.Reveal.onUserInput();
-
- if( this.Reveal.getConfig().navigationMode === 'linear' ) {
- this.Reveal.prev();
- }
- else {
- this.Reveal.left();
- }
-
- }
-
- onNavigateRightClicked( event ) {
-
- event.preventDefault();
- this.Reveal.onUserInput();
-
- if( this.Reveal.getConfig().navigationMode === 'linear' ) {
- this.Reveal.next();
- }
- else {
- this.Reveal.right();
- }
-
- }
-
- onNavigateUpClicked( event ) {
-
- event.preventDefault();
- this.Reveal.onUserInput();
-
- this.Reveal.up();
-
- }
-
- onNavigateDownClicked( event ) {
-
- event.preventDefault();
- this.Reveal.onUserInput();
-
- this.Reveal.down();
-
- }
-
- onNavigatePrevClicked( event ) {
-
- event.preventDefault();
- this.Reveal.onUserInput();
-
- this.Reveal.prev();
-
- }
-
- onNavigateNextClicked( event ) {
-
- event.preventDefault();
- this.Reveal.onUserInput();
-
- this.Reveal.next();
-
- }
-
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/focus.js b/geschichte/js/controllers/focus.js
deleted file mode 100644
index 3e68c3f..0000000
--- a/geschichte/js/controllers/focus.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import { closest } from '../utils/util.js'
-
-/**
- * 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;
-
- }
-
- destroy() {
-
- this.Reveal.getRevealElement().classList.remove( 'focused' );
-
- }
-
- onRevealPointerDown( event ) {
-
- this.focus();
-
- }
-
- onDocumentPointerDown( event ) {
-
- let revealElement = closest( event.target, '.reveal' );
- if( !revealElement || revealElement !== this.Reveal.getRevealElement() ) {
- this.blur();
- }
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/fragments.js b/geschichte/js/controllers/fragments.js
deleted file mode 100644
index 796c168..0000000
--- a/geschichte/js/controllers/fragments.js
+++ /dev/null
@@ -1,376 +0,0 @@
-import { extend, queryAll } from '../utils/util.js'
-
-/**
- * Handles sorting and navigation of slide fragments.
- * Fragments are elements within a slide that are
- * revealed/animated incrementally.
- */
-export default class Fragments {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- }
-
- /**
- * Called when 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.
- */
- disable() {
-
- queryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => {
- element.classList.add( 'visible' );
- element.classList.remove( 'current-fragment' );
- } );
-
- }
-
- /**
- * Reverse of #disable(). Only called if fragments have
- * previously been disabled.
- */
- enable() {
-
- queryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => {
- element.classList.remove( 'visible' );
- element.classList.remove( 'current-fragment' );
- } );
-
- }
-
- /**
- * Returns an object describing the available fragment
- * directions.
- *
- * @return {{prev: boolean, next: boolean}}
- */
- availableRoutes() {
-
- let currentSlide = this.Reveal.getCurrentSlide();
- if( currentSlide && this.Reveal.getConfig().fragments ) {
- let fragments = currentSlide.querySelectorAll( '.fragment:not(.disabled)' );
- let hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.disabled):not(.visible)' );
-
- return {
- prev: fragments.length - hiddenFragments.length > 0,
- next: !!hiddenFragments.length
- };
- }
- else {
- return { prev: false, next: false };
- }
-
- }
-
- /**
- * Return a sorted fragments list, ordered by an increasing
- * "data-fragment-index" attribute.
- *
- * Fragments will be revealed in the order that they are returned by
- * this function, so you can use the index attributes to control the
- * order of fragment appearance.
- *
- * To maintain a sensible default fragment order, fragments are presumed
- * to be passed in document order. This function adds a "fragment-index"
- * attribute to each node if such an attribute is not already present,
- * and sets that attribute to an integer value which is the position of
- * the fragment within the fragments list.
- *
- * @param {object[]|*} fragments
- * @param {boolean} grouped If true the returned array will contain
- * nested arrays for all fragments with the same index
- * @return {object[]} sorted Sorted array of fragments
- */
- sort( fragments, grouped = false ) {
-
- fragments = Array.from( fragments );
-
- let ordered = [],
- unordered = [],
- sorted = [];
-
- // Group ordered and unordered elements
- fragments.forEach( fragment => {
- if( fragment.hasAttribute( 'data-fragment-index' ) ) {
- let index = parseInt( fragment.getAttribute( 'data-fragment-index' ), 10 );
-
- if( !ordered[index] ) {
- ordered[index] = [];
- }
-
- ordered[index].push( fragment );
- }
- else {
- unordered.push( [ fragment ] );
- }
- } );
-
- // Append fragments without explicit indices in their
- // DOM order
- ordered = ordered.concat( unordered );
-
- // Manually count the index up per group to ensure there
- // are no gaps
- let index = 0;
-
- // Push all fragments in their sorted order to an array,
- // this flattens the groups
- ordered.forEach( group => {
- group.forEach( fragment => {
- sorted.push( fragment );
- fragment.setAttribute( 'data-fragment-index', index );
- } );
-
- index ++;
- } );
-
- return grouped === true ? ordered : sorted;
-
- }
-
- /**
- * Sorts and formats all of fragments in the
- * presentation.
- */
- sortAll() {
-
- this.Reveal.getHorizontalSlides().forEach( horizontalSlide => {
-
- let verticalSlides = queryAll( horizontalSlide, 'section' );
- verticalSlides.forEach( ( verticalSlide, y ) => {
-
- this.sort( verticalSlide.querySelectorAll( '.fragment' ) );
-
- }, this );
-
- if( verticalSlides.length === 0 ) this.sort( horizontalSlide.querySelectorAll( '.fragment' ) );
-
- } );
-
- }
-
- /**
- * Refreshes the fragments on the current slide so that they
- * have the appropriate classes (.visible + .current-fragment).
- *
- * @param {number} [index] The index of the current fragment
- * @param {array} [fragments] Array containing all fragments
- * in the current slide
- *
- * @return {{shown: array, hidden: array}}
- */
- update( index, fragments ) {
-
- let changedFragments = {
- shown: [],
- hidden: []
- };
-
- let currentSlide = this.Reveal.getCurrentSlide();
- if( currentSlide && this.Reveal.getConfig().fragments ) {
-
- fragments = fragments || this.sort( currentSlide.querySelectorAll( '.fragment' ) );
-
- if( fragments.length ) {
-
- let maxIndex = 0;
-
- if( typeof index !== 'number' ) {
- let currentFragment = this.sort( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop();
- if( currentFragment ) {
- index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
- }
- }
-
- Array.from( fragments ).forEach( ( el, i ) => {
-
- if( el.hasAttribute( 'data-fragment-index' ) ) {
- i = parseInt( el.getAttribute( 'data-fragment-index' ), 10 );
- }
-
- maxIndex = Math.max( maxIndex, i );
-
- // Visible fragments
- if( i <= index ) {
- let wasVisible = el.classList.contains( 'visible' )
- el.classList.add( 'visible' );
- el.classList.remove( 'current-fragment' );
-
- if( i === index ) {
- // Announce the fragments one by one to the Screen Reader
- this.Reveal.announceStatus( this.Reveal.getStatusText( el ) );
-
- el.classList.add( 'current-fragment' );
- this.Reveal.slideContent.startEmbeddedContent( el );
- }
-
- if( !wasVisible ) {
- changedFragments.shown.push( el )
- this.Reveal.dispatchEvent({
- target: el,
- type: 'visible',
- bubbles: false
- });
- }
- }
- // Hidden fragments
- else {
- let wasVisible = el.classList.contains( 'visible' )
- el.classList.remove( 'visible' );
- el.classList.remove( 'current-fragment' );
-
- if( wasVisible ) {
- this.Reveal.slideContent.stopEmbeddedContent( el );
- changedFragments.hidden.push( el );
- this.Reveal.dispatchEvent({
- target: el,
- type: 'hidden',
- bubbles: false
- });
- }
- }
-
- } );
-
- // Write the current fragment index to the slide <section>.
- // This can be used by end users to apply styles based on
- // the current fragment index.
- index = typeof index === 'number' ? index : -1;
- index = Math.max( Math.min( index, maxIndex ), -1 );
- currentSlide.setAttribute( 'data-fragment', index );
-
- }
-
- }
-
- return changedFragments;
-
- }
-
- /**
- * Formats the fragments on the given slide so that they have
- * valid indices. Call this if fragments are changed in the DOM
- * after reveal.js has already initialized.
- *
- * @param {HTMLElement} slide
- * @return {Array} a list of the HTML fragments that were synced
- */
- sync( slide = this.Reveal.getCurrentSlide() ) {
-
- return this.sort( slide.querySelectorAll( '.fragment' ) );
-
- }
-
- /**
- * Navigate to the specified slide fragment.
- *
- * @param {?number} index The index of the fragment that
- * should be shown, -1 means all are invisible
- * @param {number} offset Integer offset to apply to the
- * fragment index
- *
- * @return {boolean} true if a change was made in any
- * fragments visibility as part of this call
- */
- goto( index, offset = 0 ) {
-
- let currentSlide = this.Reveal.getCurrentSlide();
- if( currentSlide && this.Reveal.getConfig().fragments ) {
-
- let fragments = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled)' ) );
- if( fragments.length ) {
-
- // If no index is specified, find the current
- if( typeof index !== 'number' ) {
- let lastVisibleFragment = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled).visible' ) ).pop();
-
- if( lastVisibleFragment ) {
- index = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
- }
- else {
- index = -1;
- }
- }
-
- // Apply the offset if there is one
- index += offset;
-
- let changedFragments = this.update( index, fragments );
-
- if( changedFragments.hidden.length ) {
- this.Reveal.dispatchEvent({
- type: 'fragmenthidden',
- data: {
- fragment: changedFragments.hidden[0],
- fragments: changedFragments.hidden
- }
- });
- }
-
- if( changedFragments.shown.length ) {
- this.Reveal.dispatchEvent({
- type: 'fragmentshown',
- data: {
- fragment: changedFragments.shown[0],
- fragments: changedFragments.shown
- }
- });
- }
-
- this.Reveal.controls.update();
- this.Reveal.progress.update();
-
- if( this.Reveal.getConfig().fragmentInURL ) {
- this.Reveal.location.writeURL();
- }
-
- return !!( changedFragments.shown.length || changedFragments.hidden.length );
-
- }
-
- }
-
- return false;
-
- }
-
- /**
- * Navigate to the next slide fragment.
- *
- * @return {boolean} true if there was a next fragment,
- * false otherwise
- */
- next() {
-
- return this.goto( null, 1 );
-
- }
-
- /**
- * Navigate to the previous slide fragment.
- *
- * @return {boolean} true if there was a previous fragment,
- * false otherwise
- */
- prev() {
-
- return this.goto( null, -1 );
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/jumptoslide.js b/geschichte/js/controllers/jumptoslide.js
deleted file mode 100644
index cf2de99..0000000
--- a/geschichte/js/controllers/jumptoslide.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * Makes it possible to jump to a slide by entering its
- * slide number or id.
- */
-export default class JumpToSlide {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- this.onInput = this.onInput.bind( this );
- this.onBlur = this.onBlur.bind( this );
- this.onKeyDown = this.onKeyDown.bind( this );
-
- }
-
- render() {
-
- this.element = document.createElement( 'div' );
- this.element.className = 'jump-to-slide';
-
- this.jumpInput = document.createElement( 'input' );
- this.jumpInput.type = 'text';
- this.jumpInput.className = 'jump-to-slide-input';
- this.jumpInput.placeholder = 'Jump to slide';
- this.jumpInput.addEventListener( 'input', this.onInput );
- this.jumpInput.addEventListener( 'keydown', this.onKeyDown );
- this.jumpInput.addEventListener( 'blur', this.onBlur );
-
- this.element.appendChild( this.jumpInput );
-
- }
-
- show() {
-
- this.indicesOnShow = this.Reveal.getIndices();
-
- this.Reveal.getRevealElement().appendChild( this.element );
- this.jumpInput.focus();
-
- }
-
- hide() {
-
- if( this.isVisible() ) {
- this.element.remove();
- this.jumpInput.value = '';
-
- clearTimeout( this.jumpTimeout );
- delete this.jumpTimeout;
- }
-
- }
-
- isVisible() {
-
- return !!this.element.parentNode;
-
- }
-
- /**
- * Parses the current input and jumps to the given slide.
- */
- jump() {
-
- clearTimeout( this.jumpTimeout );
- delete this.jumpTimeout;
-
- const query = this.jumpInput.value.trim( '' );
- let indices = this.Reveal.location.getIndicesFromHash( query, { oneBasedIndex: true } );
-
- // If no valid index was found and the input query is a
- // string, fall back on a simple search
- if( !indices && /\S+/i.test( query ) && query.length > 1 ) {
- indices = this.search( query );
- }
-
- if( indices && query !== '' ) {
- this.Reveal.slide( indices.h, indices.v, indices.f );
- return true;
- }
- else {
- this.Reveal.slide( this.indicesOnShow.h, this.indicesOnShow.v, this.indicesOnShow.f );
- return false;
- }
-
- }
-
- jumpAfter( delay ) {
-
- clearTimeout( this.jumpTimeout );
- this.jumpTimeout = setTimeout( () => this.jump(), delay );
-
- }
-
- /**
- * A lofi search that looks for the given query in all
- * of our slides and returns the first match.
- */
- search( query ) {
-
- const regex = new RegExp( '\\b' + query.trim() + '\\b', 'i' );
-
- const slide = this.Reveal.getSlides().find( ( slide ) => {
- return regex.test( slide.innerText );
- } );
-
- if( slide ) {
- return this.Reveal.getIndices( slide );
- }
- else {
- return null;
- }
-
- }
-
- /**
- * Reverts back to the slide we were on when jump to slide was
- * invoked.
- */
- cancel() {
-
- this.Reveal.slide( this.indicesOnShow.h, this.indicesOnShow.v, this.indicesOnShow.f );
- this.hide();
-
- }
-
- confirm() {
-
- this.jump();
- this.hide();
-
- }
-
- destroy() {
-
- this.jumpInput.removeEventListener( 'input', this.onInput );
- this.jumpInput.removeEventListener( 'keydown', this.onKeyDown );
- this.jumpInput.removeEventListener( 'blur', this.onBlur );
-
- this.element.remove();
-
- }
-
- onKeyDown( event ) {
-
- if( event.keyCode === 13 ) {
- this.confirm();
- }
- else if( event.keyCode === 27 ) {
- this.cancel();
-
- event.stopImmediatePropagation();
- }
-
- }
-
- onInput( event ) {
-
- this.jumpAfter( 200 );
-
- }
-
- onBlur() {
-
- setTimeout( () => this.hide(), 1 );
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/keyboard.js b/geschichte/js/controllers/keyboard.js
deleted file mode 100644
index e3bff7a..0000000
--- a/geschichte/js/controllers/keyboard.js
+++ /dev/null
@@ -1,399 +0,0 @@
-import { enterFullscreen } from '../utils/util.js'
-
-/**
- * Handles all reveal.js keyboard interactions.
- */
-export default class Keyboard {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- // A key:value map of keyboard keys and descriptions of
- // the actions they trigger
- this.shortcuts = {};
-
- // Holds custom key code mappings
- this.bindings = {};
-
- this.onDocumentKeyDown = this.onDocumentKeyDown.bind( this );
- this.onDocumentKeyPress = this.onDocumentKeyPress.bind( this );
-
- }
-
- /**
- * Called when the reveal.js config is updated.
- */
- configure( config, oldConfig ) {
-
- if( config.navigationMode === 'linear' ) {
- this.shortcuts['&#8594; , &#8595; , SPACE , N , L , J'] = 'Next slide';
- this.shortcuts['&#8592; , &#8593; , P , H , K'] = 'Previous slide';
- }
- else {
- this.shortcuts['N , SPACE'] = 'Next slide';
- this.shortcuts['P , Shift SPACE'] = 'Previous slide';
- this.shortcuts['&#8592; , H'] = 'Navigate left';
- this.shortcuts['&#8594; , L'] = 'Navigate right';
- this.shortcuts['&#8593; , K'] = 'Navigate up';
- this.shortcuts['&#8595; , J'] = 'Navigate down';
- }
-
- this.shortcuts['Alt + &#8592;/&#8593/&#8594;/&#8595;'] = 'Navigate without fragments';
- this.shortcuts['Shift + &#8592;/&#8593/&#8594;/&#8595;'] = 'Jump to first/last slide';
- this.shortcuts['B , .'] = 'Pause';
- this.shortcuts['F'] = 'Fullscreen';
- this.shortcuts['G'] = 'Jump to slide';
- this.shortcuts['ESC, O'] = 'Slide overview';
-
- }
-
- /**
- * Starts listening for keyboard events.
- */
- bind() {
-
- document.addEventListener( 'keydown', this.onDocumentKeyDown, false );
- document.addEventListener( 'keypress', this.onDocumentKeyPress, false );
-
- }
-
- /**
- * Stops listening for keyboard events.
- */
- unbind() {
-
- document.removeEventListener( 'keydown', this.onDocumentKeyDown, false );
- document.removeEventListener( 'keypress', this.onDocumentKeyPress, false );
-
- }
-
- /**
- * Add a custom key binding with optional description to
- * be added to the help screen.
- */
- addKeyBinding( binding, callback ) {
-
- if( typeof binding === 'object' && binding.keyCode ) {
- this.bindings[binding.keyCode] = {
- callback: callback,
- key: binding.key,
- description: binding.description
- };
- }
- else {
- this.bindings[binding] = {
- callback: callback,
- key: null,
- description: null
- };
- }
-
- }
-
- /**
- * Removes the specified custom key binding.
- */
- removeKeyBinding( keyCode ) {
-
- delete this.bindings[keyCode];
-
- }
-
- /**
- * Programmatically triggers a keyboard event
- *
- * @param {int} keyCode
- */
- triggerKey( keyCode ) {
-
- this.onDocumentKeyDown( { keyCode } );
-
- }
-
- /**
- * Registers a new shortcut to include in the help overlay
- *
- * @param {String} key
- * @param {String} value
- */
- registerKeyboardShortcut( key, value ) {
-
- this.shortcuts[key] = value;
-
- }
-
- getShortcuts() {
-
- return this.shortcuts;
-
- }
-
- getBindings() {
-
- return this.bindings;
-
- }
-
- /**
- * Handler for the document level 'keypress' event.
- *
- * @param {object} event
- */
- onDocumentKeyPress( event ) {
-
- // Check if the pressed key is question mark
- if( event.shiftKey && event.charCode === 63 ) {
- this.Reveal.toggleHelp();
- }
-
- }
-
- /**
- * Handler for the document level 'keydown' event.
- *
- * @param {object} event
- */
- onDocumentKeyDown( event ) {
-
- let config = this.Reveal.getConfig();
-
- // If there's a condition specified and it returns false,
- // ignore this event
- if( typeof config.keyboardCondition === 'function' && config.keyboardCondition(event) === false ) {
- 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;
-
- // Remember if auto-sliding was paused so we can toggle it
- let autoSlideWasPaused = !this.Reveal.isAutoSliding();
-
- this.Reveal.onUserInput( event );
-
- // Is there a focused element that could be using the keyboard?
- let activeElementIsCE = document.activeElement && document.activeElement.isContentEditable === true;
- let activeElementIsInput = document.activeElement && document.activeElement.tagName && /input|textarea/i.test( document.activeElement.tagName );
- let activeElementIsNotes = document.activeElement && document.activeElement.className && /speaker-notes/i.test( document.activeElement.className);
-
- // Whitelist certain modifiers for slide navigation shortcuts
- let isNavigationKey = [32, 37, 38, 39, 40, 78, 80].indexOf( event.keyCode ) !== -1;
-
- // Prevent all other events when a modifier is pressed
- let unusedModifier = !( isNavigationKey && event.shiftKey || event.altKey ) &&
- ( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey );
-
- // Disregard the event if there's a focused element or a
- // keyboard modifier key is present
- if( activeElementIsCE || activeElementIsInput || activeElementIsNotes || unusedModifier ) return;
-
- // While paused only allow resume keyboard events; 'b', 'v', '.'
- let resumeKeyCodes = [66,86,190,191];
- let key;
-
- // Custom key bindings for togglePause should be able to resume
- if( typeof config.keyboard === 'object' ) {
- for( key in config.keyboard ) {
- if( config.keyboard[key] === 'togglePause' ) {
- resumeKeyCodes.push( parseInt( key, 10 ) );
- }
- }
- }
-
- if( this.Reveal.isPaused() && resumeKeyCodes.indexOf( keyCode ) === -1 ) {
- return false;
- }
-
- // Use linear navigation if we're configured to OR if
- // the presentation is one-dimensional
- let useLinearMode = config.navigationMode === 'linear' || !this.Reveal.hasHorizontalSlides() || !this.Reveal.hasVerticalSlides();
-
- let triggered = false;
-
- // 1. User defined key bindings
- if( typeof config.keyboard === 'object' ) {
-
- for( key in config.keyboard ) {
-
- // Check if this binding matches the pressed key
- if( parseInt( key, 10 ) === keyCode ) {
-
- let value = config.keyboard[ key ];
-
- // Callback function
- if( typeof value === 'function' ) {
- value.apply( null, [ event ] );
- }
- // String shortcuts to reveal.js API
- else if( typeof value === 'string' && typeof this.Reveal[ value ] === 'function' ) {
- this.Reveal[ value ].call();
- }
-
- triggered = true;
-
- }
-
- }
-
- }
-
- // 2. Registered custom key bindings
- if( triggered === false ) {
-
- for( key in this.bindings ) {
-
- // Check if this binding matches the pressed key
- if( parseInt( key, 10 ) === keyCode ) {
-
- let action = this.bindings[ key ].callback;
-
- // Callback function
- if( typeof action === 'function' ) {
- action.apply( null, [ event ] );
- }
- // String shortcuts to reveal.js API
- else if( typeof action === 'string' && typeof this.Reveal[ action ] === 'function' ) {
- this.Reveal[ action ].call();
- }
-
- triggered = true;
- }
- }
- }
-
- // 3. System defined key bindings
- if( triggered === false ) {
-
- // Assume true and try to prove false
- triggered = true;
-
- // P, PAGE UP
- if( keyCode === 80 || keyCode === 33 ) {
- this.Reveal.prev({skipFragments: event.altKey});
- }
- // N, PAGE DOWN
- else if( keyCode === 78 || keyCode === 34 ) {
- this.Reveal.next({skipFragments: event.altKey});
- }
- // H, LEFT
- else if( keyCode === 72 || keyCode === 37 ) {
- if( event.shiftKey ) {
- this.Reveal.slide( 0 );
- }
- else if( !this.Reveal.overview.isActive() && useLinearMode ) {
- this.Reveal.prev({skipFragments: event.altKey});
- }
- else {
- this.Reveal.left({skipFragments: event.altKey});
- }
- }
- // L, RIGHT
- else if( keyCode === 76 || keyCode === 39 ) {
- if( event.shiftKey ) {
- this.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 );
- }
- else if( !this.Reveal.overview.isActive() && useLinearMode ) {
- this.Reveal.next({skipFragments: event.altKey});
- }
- else {
- this.Reveal.right({skipFragments: event.altKey});
- }
- }
- // K, UP
- else if( keyCode === 75 || keyCode === 38 ) {
- if( event.shiftKey ) {
- this.Reveal.slide( undefined, 0 );
- }
- else if( !this.Reveal.overview.isActive() && useLinearMode ) {
- this.Reveal.prev({skipFragments: event.altKey});
- }
- else {
- this.Reveal.up({skipFragments: event.altKey});
- }
- }
- // J, DOWN
- else if( keyCode === 74 || keyCode === 40 ) {
- if( event.shiftKey ) {
- this.Reveal.slide( undefined, Number.MAX_VALUE );
- }
- else if( !this.Reveal.overview.isActive() && useLinearMode ) {
- this.Reveal.next({skipFragments: event.altKey});
- }
- else {
- this.Reveal.down({skipFragments: event.altKey});
- }
- }
- // HOME
- else if( keyCode === 36 ) {
- this.Reveal.slide( 0 );
- }
- // END
- else if( keyCode === 35 ) {
- this.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 );
- }
- // SPACE
- else if( keyCode === 32 ) {
- if( this.Reveal.overview.isActive() ) {
- this.Reveal.overview.deactivate();
- }
- if( event.shiftKey ) {
- this.Reveal.prev({skipFragments: event.altKey});
- }
- else {
- this.Reveal.next({skipFragments: event.altKey});
- }
- }
- // TWO-SPOT, SEMICOLON, B, V, PERIOD, LOGITECH PRESENTER TOOLS "BLACK SCREEN" BUTTON
- else if( keyCode === 58 || keyCode === 59 || keyCode === 66 || keyCode === 86 || keyCode === 190 || keyCode === 191 ) {
- this.Reveal.togglePause();
- }
- // F
- else if( keyCode === 70 ) {
- enterFullscreen( config.embedded ? this.Reveal.getViewportElement() : document.documentElement );
- }
- // A
- else if( keyCode === 65 ) {
- if ( config.autoSlideStoppable ) {
- this.Reveal.toggleAutoSlide( autoSlideWasPaused );
- }
- }
- // G
- else if( keyCode === 71 ) {
- if ( config.jumpToSlide ) {
- this.Reveal.toggleJumpToSlide();
- }
- }
- else {
- triggered = false;
- }
-
- }
-
- // If the input resulted in a triggered action we should prevent
- // the browsers default behavior
- if( triggered ) {
- event.preventDefault && event.preventDefault();
- }
- // ESC or O key
- else if( keyCode === 27 || keyCode === 79 ) {
- if( this.Reveal.closeOverlay() === false ) {
- this.Reveal.overview.toggle();
- }
-
- event.preventDefault && event.preventDefault();
- }
-
- // If auto-sliding is enabled we need to cue up
- // another timeout
- this.Reveal.cueAutoSlide();
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/location.js b/geschichte/js/controllers/location.js
deleted file mode 100644
index 6fa4829..0000000
--- a/geschichte/js/controllers/location.js
+++ /dev/null
@@ -1,245 +0,0 @@
-/**
- * Reads and writes the URL based on reveal.js' current state.
- */
-export default class Location {
-
- // The minimum number of milliseconds that must pass between
- // calls to history.replaceState
- MAX_REPLACE_STATE_FREQUENCY = 1000
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- // Delays updates to the URL due to a Chrome thumbnailer bug
- this.writeURLTimeout = 0;
-
- this.replaceStateTimestamp = 0;
-
- this.onWindowHashChange = this.onWindowHashChange.bind( this );
-
- }
-
- bind() {
-
- window.addEventListener( 'hashchange', this.onWindowHashChange, false );
-
- }
-
- unbind() {
-
- window.removeEventListener( 'hashchange', this.onWindowHashChange, false );
-
- }
-
- /**
- * Returns the slide indices for the given hash link.
- *
- * @param {string} [hash] the hash string that we want to
- * find the indices for
- *
- * @returns slide indices or null
- */
- getIndicesFromHash( hash=window.location.hash, options={} ) {
-
- // Attempt to parse the hash as either an index or name
- let name = hash.replace( /^#\/?/, '' );
- let bits = name.split( '/' );
-
- // If the first bit is not fully numeric and there is a name we
- // can assume that this is a named link
- if( !/^[0-9]*$/.test( bits[0] ) && name.length ) {
- let element;
-
- let f;
-
- // Parse named links with fragments (#/named-link/2)
- if( /\/[-\d]+$/g.test( name ) ) {
- f = parseInt( name.split( '/' ).pop(), 10 );
- f = isNaN(f) ? undefined : f;
- name = name.split( '/' ).shift();
- }
-
- // Ensure the named link is a valid HTML ID attribute
- try {
- element = document.getElementById( decodeURIComponent( name ) );
- }
- catch ( error ) { }
-
- if( element ) {
- return { ...this.Reveal.getIndices( element ), f };
- }
- }
- else {
- const config = this.Reveal.getConfig();
- let hashIndexBase = config.hashOneBasedIndex || options.oneBasedIndex ? 1 : 0;
-
- // Read the index components of the hash
- let h = ( parseInt( bits[0], 10 ) - hashIndexBase ) || 0,
- v = ( parseInt( bits[1], 10 ) - hashIndexBase ) || 0,
- f;
-
- if( config.fragmentInURL ) {
- f = parseInt( bits[2], 10 );
- if( isNaN( f ) ) {
- f = undefined;
- }
- }
-
- return { h, v, f };
- }
-
- // The hash couldn't be parsed or no matching named link was found
- return null
-
- }
-
- /**
- * Reads the current URL (hash) and navigates accordingly.
- */
- readURL() {
-
- const currentIndices = this.Reveal.getIndices();
- const newIndices = this.getIndicesFromHash();
-
- if( newIndices ) {
- if( ( newIndices.h !== currentIndices.h || newIndices.v !== currentIndices.v || newIndices.f !== undefined ) ) {
- this.Reveal.slide( newIndices.h, newIndices.v, newIndices.f );
- }
- }
- // If no new indices are available, we're trying to navigate to
- // a slide hash that does not exist
- else {
- this.Reveal.slide( currentIndices.h || 0, currentIndices.v || 0 );
- }
-
- }
-
- /**
- * Updates the page URL (hash) to reflect the current
- * state.
- *
- * @param {number} delay The time in ms to wait before
- * writing the hash
- */
- writeURL( delay ) {
-
- let config = this.Reveal.getConfig();
- let currentSlide = this.Reveal.getCurrentSlide();
-
- // Make sure there's never more than one timeout running
- clearTimeout( this.writeURLTimeout );
-
- // If a delay is specified, timeout this call
- if( typeof delay === 'number' ) {
- this.writeURLTimeout = setTimeout( this.writeURL, delay );
- }
- else if( currentSlide ) {
-
- let hash = this.getHash();
-
- // If we're configured to push to history OR the history
- // API is not available.
- if( config.history ) {
- window.location.hash = hash;
- }
- // If we're configured to reflect the current slide in the
- // URL without pushing to history.
- else if( config.hash ) {
- // If the hash is empty, don't add it to the URL
- if( hash === '/' ) {
- this.debouncedReplaceState( window.location.pathname + window.location.search );
- }
- else {
- this.debouncedReplaceState( '#' + hash );
- }
- }
- // UPDATE: The below nuking of all hash changes breaks
- // anchors on pages where reveal.js is running. Removed
- // in 4.0. Why was it here in the first place? ¯\_(ツ)_/¯
- //
- // If history and hash are both disabled, a hash may still
- // be added to the URL by clicking on a href with a hash
- // target. Counter this by always removing the hash.
- // else {
- // window.history.replaceState( null, null, window.location.pathname + window.location.search );
- // }
-
- }
-
- }
-
- replaceState( url ) {
-
- window.history.replaceState( null, null, url );
- this.replaceStateTimestamp = Date.now();
-
- }
-
- debouncedReplaceState( url ) {
-
- clearTimeout( this.replaceStateTimeout );
-
- if( Date.now() - this.replaceStateTimestamp > this.MAX_REPLACE_STATE_FREQUENCY ) {
- this.replaceState( url );
- }
- else {
- this.replaceStateTimeout = setTimeout( () => this.replaceState( url ), this.MAX_REPLACE_STATE_FREQUENCY );
- }
-
- }
-
- /**
- * Return a hash URL that will resolve to the given slide location.
- *
- * @param {HTMLElement} [slide=currentSlide] The slide to link to
- */
- getHash( slide ) {
-
- let url = '/';
-
- // Attempt to create a named link based on the slide's ID
- let s = slide || this.Reveal.getCurrentSlide();
- let id = s ? s.getAttribute( 'id' ) : null;
- if( id ) {
- id = encodeURIComponent( id );
- }
-
- let index = this.Reveal.getIndices( slide );
- if( !this.Reveal.getConfig().fragmentInURL ) {
- index.f = undefined;
- }
-
- // If the current slide has an ID, use that as a named link,
- // but we don't support named links with a fragment index
- if( typeof id === 'string' && id.length ) {
- url = '/' + id;
-
- // If there is also a fragment, append that at the end
- // of the named link, like: #/named-link/2
- if( index.f >= 0 ) url += '/' + index.f;
- }
- // Otherwise use the /h/v index
- else {
- let hashIndexBase = this.Reveal.getConfig().hashOneBasedIndex ? 1 : 0;
- if( index.h > 0 || index.v > 0 || index.f >= 0 ) url += index.h + hashIndexBase;
- if( index.v > 0 || index.f >= 0 ) url += '/' + (index.v + hashIndexBase );
- if( index.f >= 0 ) url += '/' + index.f;
- }
-
- return url;
-
- }
-
- /**
- * Handler for the window level 'hashchange' event.
- *
- * @param {object} [event]
- */
- onWindowHashChange( event ) {
-
- this.readURL();
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/notes.js b/geschichte/js/controllers/notes.js
deleted file mode 100644
index 7256425..0000000
--- a/geschichte/js/controllers/notes.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Handles the showing of speaker notes
- */
-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.print.isPrintingPDF() ) {
- 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}
- */
- isSpeakerNotesWindow() {
-
- 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. With <aside class="notes"> elements inside 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 <aside class="notes"> elements
- let notesElements = slide.querySelectorAll( 'aside.notes' );
- if( notesElements ) {
- return Array.from(notesElements).map( notesElement => notesElement.innerHTML ).join( '\n' );
- }
-
- return null;
-
- }
-
- destroy() {
-
- this.element.remove();
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/overview.js b/geschichte/js/controllers/overview.js
deleted file mode 100644
index 30e4c63..0000000
--- a/geschichte/js/controllers/overview.js
+++ /dev/null
@@ -1,255 +0,0 @@
-import { SLIDES_SELECTOR } from '../utils/constants.js'
-import { extend, queryAll, transformElement } from '../utils/util.js'
-
-/**
- * Handles all logic related to the overview mode
- * (birds-eye view of all slides).
- */
-export default class Overview {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- this.active = false;
-
- this.onSlideClicked = this.onSlideClicked.bind( this );
-
- }
-
- /**
- * Displays the overview of slides (quick nav) by scaling
- * down and arranging all slide elements.
- */
- activate() {
-
- // Only proceed if enabled in config
- if( this.Reveal.getConfig().overview && !this.isActive() ) {
-
- this.active = true;
-
- this.Reveal.getRevealElement().classList.add( 'overview' );
-
- // Don't auto-slide while in overview mode
- this.Reveal.cancelAutoSlide();
-
- // Move the backgrounds element into the slide container to
- // that the same scaling is applied
- this.Reveal.getSlidesElement().appendChild( this.Reveal.getBackgroundsElement() );
-
- // Clicking on an overview slide navigates to it
- queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( slide => {
- if( !slide.classList.contains( 'stack' ) ) {
- slide.addEventListener( 'click', this.onSlideClicked, true );
- }
- } );
-
- // Calculate slide sizes
- const margin = 70;
- const slideSize = this.Reveal.getComputedSlideSize();
- this.overviewSlideWidth = slideSize.width + margin;
- this.overviewSlideHeight = slideSize.height + margin;
-
- // Reverse in RTL mode
- if( this.Reveal.getConfig().rtl ) {
- this.overviewSlideWidth = -this.overviewSlideWidth;
- }
-
- this.Reveal.updateSlidesVisibility();
-
- this.layout();
- this.update();
-
- this.Reveal.layout();
-
- const indices = this.Reveal.getIndices();
-
- // Notify observers of the overview showing
- this.Reveal.dispatchEvent({
- type: 'overviewshown',
- data: {
- 'indexh': indices.h,
- 'indexv': indices.v,
- 'currentSlide': this.Reveal.getCurrentSlide()
- }
- });
-
- }
-
- }
-
- /**
- * Uses CSS transforms to position all slides in a grid for
- * display inside of the overview mode.
- */
- layout() {
-
- // Layout slides
- this.Reveal.getHorizontalSlides().forEach( ( hslide, h ) => {
- hslide.setAttribute( 'data-index-h', h );
- transformElement( hslide, 'translate3d(' + ( h * this.overviewSlideWidth ) + 'px, 0, 0)' );
-
- if( hslide.classList.contains( 'stack' ) ) {
-
- queryAll( hslide, 'section' ).forEach( ( vslide, v ) => {
- vslide.setAttribute( 'data-index-h', h );
- vslide.setAttribute( 'data-index-v', v );
-
- transformElement( vslide, 'translate3d(0, ' + ( v * this.overviewSlideHeight ) + 'px, 0)' );
- } );
-
- }
- } );
-
- // Layout slide backgrounds
- Array.from( this.Reveal.getBackgroundsElement().childNodes ).forEach( ( hbackground, h ) => {
- transformElement( hbackground, 'translate3d(' + ( h * this.overviewSlideWidth ) + 'px, 0, 0)' );
-
- queryAll( hbackground, '.slide-background' ).forEach( ( vbackground, v ) => {
- transformElement( vbackground, 'translate3d(0, ' + ( v * this.overviewSlideHeight ) + 'px, 0)' );
- } );
- } );
-
- }
-
- /**
- * Moves the overview viewport to the current slides.
- * Called each time the current slide changes.
- */
- update() {
-
- const vmin = Math.min( window.innerWidth, window.innerHeight );
- const scale = Math.max( vmin / 5, 150 ) / vmin;
- const indices = this.Reveal.getIndices();
-
- this.Reveal.transformSlides( {
- overview: [
- 'scale('+ scale +')',
- 'translateX('+ ( -indices.h * this.overviewSlideWidth ) +'px)',
- 'translateY('+ ( -indices.v * this.overviewSlideHeight ) +'px)'
- ].join( ' ' )
- } );
-
- }
-
- /**
- * Exits the slide overview and enters the currently
- * active slide.
- */
- deactivate() {
-
- // Only proceed if enabled in config
- if( this.Reveal.getConfig().overview ) {
-
- this.active = false;
-
- this.Reveal.getRevealElement().classList.remove( 'overview' );
-
- // Temporarily add a class so that transitions can do different things
- // depending on whether they are exiting/entering overview, or just
- // moving from slide to slide
- this.Reveal.getRevealElement().classList.add( 'overview-deactivating' );
-
- setTimeout( () => {
- this.Reveal.getRevealElement().classList.remove( 'overview-deactivating' );
- }, 1 );
-
- // Move the background element back out
- this.Reveal.getRevealElement().appendChild( this.Reveal.getBackgroundsElement() );
-
- // Clean up changes made to slides
- queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( slide => {
- transformElement( slide, '' );
-
- slide.removeEventListener( 'click', this.onSlideClicked, true );
- } );
-
- // Clean up changes made to backgrounds
- queryAll( this.Reveal.getBackgroundsElement(), '.slide-background' ).forEach( background => {
- transformElement( background, '' );
- } );
-
- this.Reveal.transformSlides( { overview: '' } );
-
- const indices = this.Reveal.getIndices();
-
- this.Reveal.slide( indices.h, indices.v );
- this.Reveal.layout();
- this.Reveal.cueAutoSlide();
-
- // Notify observers of the overview hiding
- this.Reveal.dispatchEvent({
- type: 'overviewhidden',
- data: {
- 'indexh': indices.h,
- 'indexv': indices.v,
- 'currentSlide': this.Reveal.getCurrentSlide()
- }
- });
-
- }
- }
-
- /**
- * Toggles the slide overview mode on and off.
- *
- * @param {Boolean} [override] Flag which overrides the
- * toggle logic and forcibly sets the desired state. True means
- * overview is open, false means it's closed.
- */
- toggle( override ) {
-
- if( typeof override === 'boolean' ) {
- override ? this.activate() : this.deactivate();
- }
- else {
- this.isActive() ? this.deactivate() : this.activate();
- }
-
- }
-
- /**
- * Checks if the overview is currently active.
- *
- * @return {Boolean} true if the overview is active,
- * false otherwise
- */
- isActive() {
-
- return this.active;
-
- }
-
- /**
- * Invoked when a slide is and we're in the overview.
- *
- * @param {object} event
- */
- onSlideClicked( event ) {
-
- if( this.isActive() ) {
- event.preventDefault();
-
- let element = event.target;
-
- while( element && !element.nodeName.match( /section/gi ) ) {
- element = element.parentNode;
- }
-
- if( element && !element.classList.contains( 'disabled' ) ) {
-
- this.deactivate();
-
- if( element.nodeName.match( /section/gi ) ) {
- let h = parseInt( element.getAttribute( 'data-index-h' ), 10 ),
- v = parseInt( element.getAttribute( 'data-index-v' ), 10 );
-
- this.Reveal.slide( h, v );
- }
-
- }
- }
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/plugins.js b/geschichte/js/controllers/plugins.js
deleted file mode 100644
index 88f57bf..0000000
--- a/geschichte/js/controllers/plugins.js
+++ /dev/null
@@ -1,254 +0,0 @@
-import { loadScript } from '../utils/loader.js'
-
-/**
- * Manages loading and registering of reveal.js plugins.
- */
-export default class Plugins {
-
- constructor( reveal ) {
-
- this.Reveal = reveal;
-
- // Flags our current state (idle -> loading -> loaded)
- this.state = 'idle';
-
- // An id:instance map of currently registered plugins
- this.registeredPlugins = {};
-
- this.asyncDependencies = [];
-
- }
-
- /**
- * Loads reveal.js dependencies, registers and
- * initializes plugins.
- *
- * Plugins are direct references to a reveal.js plugin
- * object that we register and initialize after any
- * synchronous dependencies have loaded.
- *
- * Dependencies are defined via the 'dependencies' config
- * option and will be loaded prior to starting reveal.js.
- * Some dependencies may have an 'async' flag, if so they
- * will load after reveal.js has been started up.
- */
- load( plugins, dependencies ) {
-
- this.state = 'loading';
-
- plugins.forEach( this.registerPlugin.bind( this ) );
-
- return new Promise( resolve => {
-
- let scripts = [],
- scriptsToLoad = 0;
-
- dependencies.forEach( s => {
- // Load if there's no condition or the condition is truthy
- if( !s.condition || s.condition() ) {
- if( s.async ) {
- this.asyncDependencies.push( s );
- }
- else {
- scripts.push( s );
- }
- }
- } );
-
- if( scripts.length ) {
- scriptsToLoad = scripts.length;
-
- const scriptLoadedCallback = (s) => {
- if( s && typeof s.callback === 'function' ) s.callback();
-
- if( --scriptsToLoad === 0 ) {
- this.initPlugins().then( resolve );
- }
- };
-
- // Load synchronous scripts
- scripts.forEach( s => {
- if( typeof s.id === 'string' ) {
- this.registerPlugin( s );
- scriptLoadedCallback( s );
- }
- else if( typeof s.src === 'string' ) {
- loadScript( s.src, () => scriptLoadedCallback(s) );
- }
- else {
- console.warn( 'Unrecognized plugin format', s );
- scriptLoadedCallback();
- }
- } );
- }
- else {
- this.initPlugins().then( resolve );
- }
-
- } );
-
- }
-
- /**
- * Initializes our plugins and waits for them to be ready
- * before proceeding.
- */
- initPlugins() {
-
- return new Promise( resolve => {
-
- let pluginValues = Object.values( this.registeredPlugins );
- let pluginsToInitialize = pluginValues.length;
-
- // If there are no plugins, skip this step
- if( pluginsToInitialize === 0 ) {
- this.loadAsync().then( resolve );
- }
- // ... otherwise initialize plugins
- else {
-
- let initNextPlugin;
-
- let afterPlugInitialized = () => {
- if( --pluginsToInitialize === 0 ) {
- this.loadAsync().then( resolve );
- }
- else {
- initNextPlugin();
- }
- };
-
- let i = 0;
-
- // Initialize plugins serially
- initNextPlugin = () => {
-
- let plugin = pluginValues[i++];
-
- // If the plugin has an 'init' method, invoke it
- if( typeof plugin.init === 'function' ) {
- let promise = plugin.init( this.Reveal );
-
- // If the plugin returned a Promise, wait for it
- if( promise && typeof promise.then === 'function' ) {
- promise.then( afterPlugInitialized );
- }
- else {
- afterPlugInitialized();
- }
- }
- else {
- afterPlugInitialized();
- }
-
- }
-
- initNextPlugin();
-
- }
-
- } )
-
- }
-
- /**
- * Loads all async reveal.js dependencies.
- */
- loadAsync() {
-
- this.state = 'loaded';
-
- if( this.asyncDependencies.length ) {
- this.asyncDependencies.forEach( s => {
- loadScript( s.src, s.callback );
- } );
- }
-
- return Promise.resolve();
-
- }
-
- /**
- * Registers a new plugin with this reveal.js instance.
- *
- * reveal.js waits for all registered plugins to initialize
- * before considering itself ready, as long as the plugin
- * is registered before calling `Reveal.initialize()`.
- */
- registerPlugin( plugin ) {
-
- // Backwards compatibility to make reveal.js ~3.9.0
- // plugins work with reveal.js 4.0.0
- if( arguments.length === 2 && typeof arguments[0] === 'string' ) {
- plugin = arguments[1];
- plugin.id = arguments[0];
- }
- // Plugin can optionally be a function which we call
- // to create an instance of the plugin
- else if( typeof plugin === 'function' ) {
- plugin = plugin();
- }
-
- let id = plugin.id;
-
- if( typeof id !== 'string' ) {
- console.warn( 'Unrecognized plugin format; can\'t find plugin.id', plugin );
- }
- else if( this.registeredPlugins[id] === undefined ) {
- this.registeredPlugins[id] = plugin;
-
- // If a plugin is registered after reveal.js is loaded,
- // initialize it right away
- if( this.state === 'loaded' && typeof plugin.init === 'function' ) {
- plugin.init( this.Reveal );
- }
- }
- else {
- console.warn( 'reveal.js: "'+ id +'" plugin has already been registered' );
- }
-
- }
-
- /**
- * Checks if a specific plugin has been registered.
- *
- * @param {String} id Unique plugin identifier
- */
- hasPlugin( id ) {
-
- return !!this.registeredPlugins[id];
-
- }
-
- /**
- * Returns the specific plugin instance, if a plugin
- * with the given ID has been registered.
- *
- * @param {String} id Unique plugin identifier
- */
- getPlugin( id ) {
-
- return this.registeredPlugins[id];
-
- }
-
- getRegisteredPlugins() {
-
- return this.registeredPlugins;
-
- }
-
- destroy() {
-
- Object.values( this.registeredPlugins ).forEach( plugin => {
- if( typeof plugin.destroy === 'function' ) {
- plugin.destroy();
- }
- } );
-
- this.registeredPlugins = {};
- this.asyncDependencies = [];
-
- }
-
-}
diff --git a/geschichte/js/controllers/pointer.js b/geschichte/js/controllers/pointer.js
deleted file mode 100644
index f632fce..0000000
--- a/geschichte/js/controllers/pointer.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * Handles hiding of the pointer/cursor when inactive.
- */
-export default class Pointer {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- // Throttles mouse wheel navigation
- this.lastMouseWheelStep = 0;
-
- // Is the mouse pointer currently hidden from view
- this.cursorHidden = false;
-
- // Timeout used to determine when the cursor is inactive
- this.cursorInactiveTimeout = 0;
-
- this.onDocumentCursorActive = this.onDocumentCursorActive.bind( this );
- this.onDocumentMouseScroll = this.onDocumentMouseScroll.bind( this );
-
- }
-
- /**
- * Called when the reveal.js config is updated.
- */
- configure( config, oldConfig ) {
-
- if( config.mouseWheel ) {
- document.addEventListener( 'DOMMouseScroll', this.onDocumentMouseScroll, false ); // FF
- document.addEventListener( 'mousewheel', this.onDocumentMouseScroll, false );
- }
- else {
- document.removeEventListener( 'DOMMouseScroll', this.onDocumentMouseScroll, false ); // FF
- document.removeEventListener( 'mousewheel', this.onDocumentMouseScroll, false );
- }
-
- // Auto-hide the mouse pointer when its inactive
- if( config.hideInactiveCursor ) {
- document.addEventListener( 'mousemove', this.onDocumentCursorActive, false );
- document.addEventListener( 'mousedown', this.onDocumentCursorActive, false );
- }
- else {
- this.showCursor();
-
- document.removeEventListener( 'mousemove', this.onDocumentCursorActive, false );
- document.removeEventListener( 'mousedown', this.onDocumentCursorActive, false );
- }
-
- }
-
- /**
- * Shows the mouse pointer after it has been hidden with
- * #hideCursor.
- */
- showCursor() {
-
- if( this.cursorHidden ) {
- this.cursorHidden = false;
- this.Reveal.getRevealElement().style.cursor = '';
- }
-
- }
-
- /**
- * Hides the mouse pointer when it's on top of the .reveal
- * container.
- */
- hideCursor() {
-
- if( this.cursorHidden === false ) {
- this.cursorHidden = true;
- this.Reveal.getRevealElement().style.cursor = 'none';
- }
-
- }
-
- destroy() {
-
- this.showCursor();
-
- document.removeEventListener( 'DOMMouseScroll', this.onDocumentMouseScroll, false );
- document.removeEventListener( 'mousewheel', this.onDocumentMouseScroll, false );
- document.removeEventListener( 'mousemove', this.onDocumentCursorActive, false );
- document.removeEventListener( 'mousedown', this.onDocumentCursorActive, false );
-
- }
-
- /**
- * Called whenever there is mouse input at the document level
- * to determine if the cursor is active or not.
- *
- * @param {object} event
- */
- onDocumentCursorActive( event ) {
-
- this.showCursor();
-
- clearTimeout( this.cursorInactiveTimeout );
-
- this.cursorInactiveTimeout = setTimeout( this.hideCursor.bind( this ), this.Reveal.getConfig().hideCursorTime );
-
- }
-
- /**
- * Handles mouse wheel scrolling, throttled to avoid skipping
- * multiple slides.
- *
- * @param {object} event
- */
- onDocumentMouseScroll( event ) {
-
- if( Date.now() - this.lastMouseWheelStep > 1000 ) {
-
- this.lastMouseWheelStep = Date.now();
-
- let delta = event.detail || -event.wheelDelta;
- if( delta > 0 ) {
- this.Reveal.next();
- }
- else if( delta < 0 ) {
- this.Reveal.prev();
- }
-
- }
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/print.js b/geschichte/js/controllers/print.js
deleted file mode 100644
index 4214519..0000000
--- a/geschichte/js/controllers/print.js
+++ /dev/null
@@ -1,237 +0,0 @@
-import { SLIDES_SELECTOR } from '../utils/constants.js'
-import { queryAll, createStyleSheet } from '../utils/util.js'
-
-/**
- * Setups up our presentation for printing/exporting to PDF.
- */
-export default class Print {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- }
-
- /**
- * Configures the presentation for printing to a static
- * PDF.
- */
- async setupPDF() {
-
- const config = this.Reveal.getConfig();
- const slides = queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR )
-
- // Compute slide numbers now, before we start duplicating slides
- const injectPageNumbers = config.slideNumber && /all|print/i.test( config.showSlideNumber );
-
- const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
-
- // Dimensions of the PDF pages
- const pageWidth = Math.floor( slideSize.width * ( 1 + config.margin ) ),
- pageHeight = Math.floor( slideSize.height * ( 1 + config.margin ) );
-
- // Dimensions of slides within the pages
- const slideWidth = slideSize.width,
- slideHeight = slideSize.height;
-
- await new Promise( requestAnimationFrame );
-
- // Let the browser know what page size we want to print
- createStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0px;}' );
-
- // Limit the size of certain elements to the dimensions of the slide
- createStyleSheet( '.reveal section>img, .reveal section>video, .reveal section>iframe{max-width: '+ slideWidth +'px; max-height:'+ slideHeight +'px}' );
-
- document.documentElement.classList.add( 'print-pdf' );
- document.body.style.width = pageWidth + 'px';
- document.body.style.height = pageHeight + 'px';
-
- const viewportElement = document.querySelector( '.reveal-viewport' );
- let presentationBackground;
- if( viewportElement ) {
- const viewportStyles = window.getComputedStyle( viewportElement );
- if( viewportStyles && viewportStyles.background ) {
- presentationBackground = viewportStyles.background;
- }
- }
-
- // Make sure stretch elements fit on slide
- await new Promise( requestAnimationFrame );
- this.Reveal.layoutSlideContents( slideWidth, slideHeight );
-
- // Batch scrollHeight access to prevent layout thrashing
- await new Promise( requestAnimationFrame );
-
- const slideScrollHeights = slides.map( slide => slide.scrollHeight );
-
- const pages = [];
- const pageContainer = slides[0].parentNode;
- let slideNumber = 1;
-
- // Slide and slide background layout
- slides.forEach( function( slide, index ) {
-
- // Vertical stacks are not centred since their section
- // children will be
- if( slide.classList.contains( 'stack' ) === false ) {
- // Center the slide inside of the page, giving the slide some margin
- let left = ( pageWidth - slideWidth ) / 2;
- let top = ( pageHeight - slideHeight ) / 2;
-
- const contentHeight = slideScrollHeights[ index ];
- let numberOfPages = Math.max( Math.ceil( contentHeight / pageHeight ), 1 );
-
- // Adhere to configured pages per slide limit
- numberOfPages = Math.min( numberOfPages, config.pdfMaxPagesPerSlide );
-
- // Center slides vertically
- if( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) {
- top = Math.max( ( pageHeight - contentHeight ) / 2, 0 );
- }
-
- // Wrap the slide in a page element and hide its overflow
- // so that no page ever flows onto another
- const page = document.createElement( 'div' );
- pages.push( page );
-
- page.className = 'pdf-page';
- page.style.height = ( ( pageHeight + config.pdfPageHeightOffset ) * numberOfPages ) + 'px';
-
- // Copy the presentation-wide background to each individual
- // page when printing
- if( presentationBackground ) {
- page.style.background = presentationBackground;
- }
-
- page.appendChild( slide );
-
- // Position the slide inside of the page
- slide.style.left = left + 'px';
- slide.style.top = top + 'px';
- slide.style.width = slideWidth + 'px';
-
- this.Reveal.slideContent.layout( slide );
-
- if( slide.slideBackgroundElement ) {
- page.insertBefore( slide.slideBackgroundElement, slide );
- }
-
- // Inject notes if `showNotes` is enabled
- if( config.showNotes ) {
-
- // Are there notes for this slide?
- const notes = this.Reveal.getSlideNotes( slide );
- if( notes ) {
-
- const notesSpacing = 8;
- const notesLayout = typeof config.showNotes === 'string' ? config.showNotes : 'inline';
- const notesElement = document.createElement( 'div' );
- notesElement.classList.add( 'speaker-notes' );
- notesElement.classList.add( 'speaker-notes-pdf' );
- notesElement.setAttribute( 'data-layout', notesLayout );
- notesElement.innerHTML = notes;
-
- if( notesLayout === 'separate-page' ) {
- pages.push( notesElement );
- }
- else {
- notesElement.style.left = notesSpacing + 'px';
- notesElement.style.bottom = notesSpacing + 'px';
- notesElement.style.width = ( pageWidth - notesSpacing*2 ) + 'px';
- page.appendChild( notesElement );
- }
-
- }
-
- }
-
- // Inject page numbers if `slideNumbers` are enabled
- if( injectPageNumbers ) {
- const numberElement = document.createElement( 'div' );
- numberElement.classList.add( 'slide-number' );
- numberElement.classList.add( 'slide-number-pdf' );
- numberElement.innerHTML = slideNumber++;
- page.appendChild( numberElement );
- }
-
- // Copy page and show fragments one after another
- if( config.pdfSeparateFragments ) {
-
- // Each fragment 'group' is an array containing one or more
- // fragments. Multiple fragments that appear at the same time
- // are part of the same group.
- const fragmentGroups = this.Reveal.fragments.sort( page.querySelectorAll( '.fragment' ), true );
-
- let previousFragmentStep;
-
- fragmentGroups.forEach( function( fragments, index ) {
-
- // Remove 'current-fragment' from the previous group
- if( previousFragmentStep ) {
- previousFragmentStep.forEach( function( fragment ) {
- fragment.classList.remove( 'current-fragment' );
- } );
- }
-
- // Show the fragments for the current index
- fragments.forEach( function( fragment ) {
- fragment.classList.add( 'visible', 'current-fragment' );
- }, this );
-
- // Create a separate page for the current fragment state
- const clonedPage = page.cloneNode( true );
-
- // Inject unique page numbers for fragments
- if( injectPageNumbers ) {
- const numberElement = clonedPage.querySelector( '.slide-number-pdf' );
- const fragmentNumber = index + 1;
- numberElement.innerHTML += '.' + fragmentNumber;
- }
-
- pages.push( clonedPage );
-
- previousFragmentStep = fragments;
-
- }, this );
-
- // Reset the first/original page so that all fragments are hidden
- fragmentGroups.forEach( function( fragments ) {
- fragments.forEach( function( fragment ) {
- fragment.classList.remove( 'visible', 'current-fragment' );
- } );
- } );
-
- }
- // Show all fragments
- else {
- queryAll( page, '.fragment:not(.fade-out)' ).forEach( function( fragment ) {
- fragment.classList.add( 'visible' );
- } );
- }
-
- }
-
- }, this );
-
- await new Promise( requestAnimationFrame );
-
- pages.forEach( page => pageContainer.appendChild( page ) );
-
- // Re-run JS-based content layout after the slide is added to page DOM
- this.Reveal.slideContent.layout( this.Reveal.getSlidesElement() );
-
- // Notify subscribers that the PDF layout is good to go
- this.Reveal.dispatchEvent({ type: 'pdf-ready' });
-
- }
-
- /**
- * Checks if this instance is being used to print a PDF.
- */
- isPrintingPDF() {
-
- return ( /print-pdf/gi ).test( window.location.search );
-
- }
-
-}
diff --git a/geschichte/js/controllers/progress.js b/geschichte/js/controllers/progress.js
deleted file mode 100644
index 87e2aaf..0000000
--- a/geschichte/js/controllers/progress.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Creates a visual progress bar for the presentation.
- */
-export default class Progress {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- this.onProgressClicked = this.onProgressClicked.bind( this );
-
- }
-
- render() {
-
- this.element = document.createElement( 'div' );
- this.element.className = 'progress';
- this.Reveal.getRevealElement().appendChild( this.element );
-
- this.bar = document.createElement( 'span' );
- this.element.appendChild( this.bar );
-
- }
-
- /**
- * Called when the reveal.js config is updated.
- */
- configure( config, oldConfig ) {
-
- this.element.style.display = config.progress ? 'block' : 'none';
-
- }
-
- bind() {
-
- if( this.Reveal.getConfig().progress && this.element ) {
- this.element.addEventListener( 'click', this.onProgressClicked, false );
- }
-
- }
-
- unbind() {
-
- if ( this.Reveal.getConfig().progress && this.element ) {
- this.element.removeEventListener( 'click', this.onProgressClicked, false );
- }
-
- }
-
- /**
- * Updates the progress bar to reflect the current slide.
- */
- update() {
-
- // Update progress if enabled
- if( this.Reveal.getConfig().progress && this.bar ) {
-
- let scale = this.Reveal.getProgress();
-
- // Don't fill the progress bar if there's only one slide
- if( this.Reveal.getTotalSlides() < 2 ) {
- scale = 0;
- }
-
- this.bar.style.transform = 'scaleX('+ scale +')';
-
- }
-
- }
-
- getMaxWidth() {
-
- return this.Reveal.getRevealElement().offsetWidth;
-
- }
-
- /**
- * Clicking on the progress bar results in a navigation to the
- * closest approximate horizontal slide using this equation:
- *
- * ( clickX / presentationWidth ) * numberOfSlides
- *
- * @param {object} event
- */
- onProgressClicked( event ) {
-
- this.Reveal.onUserInput( event );
-
- event.preventDefault();
-
- let slides = this.Reveal.getSlides();
- let slidesTotal = slides.length;
- let slideIndex = Math.floor( ( event.clientX / this.getMaxWidth() ) * slidesTotal );
-
- if( this.Reveal.getConfig().rtl ) {
- slideIndex = slidesTotal - slideIndex;
- }
-
- let targetIndices = this.Reveal.getIndices(slides[slideIndex]);
- this.Reveal.slide( targetIndices.h, targetIndices.v );
-
- }
-
- destroy() {
-
- this.element.remove();
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/slidecontent.js b/geschichte/js/controllers/slidecontent.js
deleted file mode 100644
index 5462dbf..0000000
--- a/geschichte/js/controllers/slidecontent.js
+++ /dev/null
@@ -1,480 +0,0 @@
-import { extend, queryAll, closest, getMimeTypeFromFile, encodeRFC3986URI } from '../utils/util.js'
-import { isMobile } from '../utils/device.js'
-
-import fitty from 'fitty';
-
-/**
- * Handles loading, unloading and playback of slide
- * content such as images, videos and iframes.
- */
-export default class SlideContent {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- this.startEmbeddedIframe = this.startEmbeddedIframe.bind( this );
-
- }
-
- /**
- * Should the given element be preloaded?
- * Decides based on local element attributes and global config.
- *
- * @param {HTMLElement} element
- */
- shouldPreload( element ) {
-
- // Prefer an explicit global preload setting
- let preload = this.Reveal.getConfig().preloadIframes;
-
- // If no global setting is available, fall back on the element's
- // own preload setting
- if( typeof preload !== 'boolean' ) {
- preload = element.hasAttribute( 'data-preload' );
- }
-
- return preload;
- }
-
- /**
- * Called when the given slide is within the configured view
- * distance. Shows the slide element and loads any content
- * that is set to load lazily (data-src).
- *
- * @param {HTMLElement} slide Slide to show
- */
- load( slide, options = {} ) {
-
- // Show the slide element
- slide.style.display = this.Reveal.getConfig().display;
-
- // Media elements with data-src attributes
- queryAll( slide, 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ).forEach( element => {
- if( element.tagName !== 'IFRAME' || this.shouldPreload( element ) ) {
- element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
- element.setAttribute( 'data-lazy-loaded', '' );
- element.removeAttribute( 'data-src' );
- }
- } );
-
- // Media elements with <source> children
- queryAll( slide, 'video, audio' ).forEach( media => {
- let sources = 0;
-
- queryAll( media, 'source[data-src]' ).forEach( source => {
- source.setAttribute( 'src', source.getAttribute( 'data-src' ) );
- source.removeAttribute( 'data-src' );
- source.setAttribute( 'data-lazy-loaded', '' );
- sources += 1;
- } );
-
- // Enable inline video playback in mobile Safari
- if( isMobile && media.tagName === 'VIDEO' ) {
- media.setAttribute( 'playsinline', '' );
- }
-
- // If we rewrote sources for this video/audio element, we need
- // to manually tell it to load from its new origin
- if( sources > 0 ) {
- media.load();
- }
- } );
-
-
- // Show the corresponding background element
- let background = slide.slideBackgroundElement;
- if( background ) {
- background.style.display = 'block';
-
- let backgroundContent = slide.slideBackgroundContentElement;
- let backgroundIframe = slide.getAttribute( 'data-background-iframe' );
-
- // If the background contains media, load it
- if( background.hasAttribute( 'data-loaded' ) === false ) {
- background.setAttribute( 'data-loaded', 'true' );
-
- let backgroundImage = slide.getAttribute( 'data-background-image' ),
- backgroundVideo = slide.getAttribute( 'data-background-video' ),
- backgroundVideoLoop = slide.hasAttribute( 'data-background-video-loop' ),
- backgroundVideoMuted = slide.hasAttribute( 'data-background-video-muted' );
-
- // Images
- if( backgroundImage ) {
- // base64
- if( /^data:/.test( backgroundImage.trim() ) ) {
- backgroundContent.style.backgroundImage = `url(${backgroundImage.trim()})`;
- }
- // URL(s)
- else {
- backgroundContent.style.backgroundImage = backgroundImage.split( ',' ).map( background => {
- // Decode URL(s) that are already encoded first
- let decoded = decodeURI(background.trim());
- return `url(${encodeRFC3986URI(decoded)})`;
- }).join( ',' );
- }
- }
- // Videos
- else if ( backgroundVideo && !this.Reveal.isSpeakerNotes() ) {
- let video = document.createElement( 'video' );
-
- if( backgroundVideoLoop ) {
- video.setAttribute( 'loop', '' );
- }
-
- if( backgroundVideoMuted ) {
- video.muted = true;
- }
-
- // Enable inline playback in mobile Safari
- //
- // Mute is required for video to play when using
- // swipe gestures to navigate since they don't
- // count as direct user actions :'(
- if( isMobile ) {
- video.muted = true;
- video.setAttribute( 'playsinline', '' );
- }
-
- // Support comma separated lists of video sources
- backgroundVideo.split( ',' ).forEach( source => {
- let type = getMimeTypeFromFile( source );
- if( type ) {
- video.innerHTML += `<source src="${source}" type="${type}">`;
- }
- else {
- video.innerHTML += `<source src="${source}">`;
- }
- } );
-
- backgroundContent.appendChild( video );
- }
- // Iframes
- else if( backgroundIframe && options.excludeIframes !== true ) {
- let iframe = document.createElement( 'iframe' );
- iframe.setAttribute( 'allowfullscreen', '' );
- iframe.setAttribute( 'mozallowfullscreen', '' );
- iframe.setAttribute( 'webkitallowfullscreen', '' );
- iframe.setAttribute( 'allow', 'autoplay' );
-
- iframe.setAttribute( 'data-src', backgroundIframe );
-
- iframe.style.width = '100%';
- iframe.style.height = '100%';
- iframe.style.maxHeight = '100%';
- iframe.style.maxWidth = '100%';
-
- backgroundContent.appendChild( iframe );
- }
- }
-
- // Start loading preloadable iframes
- let backgroundIframeElement = backgroundContent.querySelector( 'iframe[data-src]' );
- if( backgroundIframeElement ) {
-
- // Check if this iframe is eligible to be preloaded
- if( this.shouldPreload( background ) && !/autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {
- if( backgroundIframeElement.getAttribute( 'src' ) !== backgroundIframe ) {
- backgroundIframeElement.setAttribute( 'src', backgroundIframe );
- }
- }
-
- }
-
- }
-
- this.layout( slide );
-
- }
-
- /**
- * Applies JS-dependent layout helpers for the scope.
- */
- layout( scopeElement ) {
-
- // Autosize text with the r-fit-text class based on the
- // size of its container. This needs to happen after the
- // slide is visible in order to measure the text.
- Array.from( scopeElement.querySelectorAll( '.r-fit-text' ) ).forEach( element => {
- fitty( element, {
- minSize: 24,
- maxSize: this.Reveal.getConfig().height * 0.8,
- observeMutations: false,
- observeWindow: false
- } );
- } );
-
- }
-
- /**
- * Unloads and hides the given slide. This is called when the
- * slide is moved outside of the configured view distance.
- *
- * @param {HTMLElement} slide
- */
- unload( slide ) {
-
- // Hide the slide element
- slide.style.display = 'none';
-
- // Hide the corresponding background element
- let background = this.Reveal.getSlideBackground( slide );
- if( background ) {
- background.style.display = 'none';
-
- // Unload any background iframes
- queryAll( background, 'iframe[src]' ).forEach( element => {
- element.removeAttribute( 'src' );
- } );
- }
-
- // Reset lazy-loaded media elements with src attributes
- queryAll( slide, 'video[data-lazy-loaded][src], audio[data-lazy-loaded][src], iframe[data-lazy-loaded][src]' ).forEach( element => {
- element.setAttribute( 'data-src', element.getAttribute( 'src' ) );
- element.removeAttribute( 'src' );
- } );
-
- // Reset lazy-loaded media elements with <source> children
- queryAll( slide, 'video[data-lazy-loaded] source[src], audio source[src]' ).forEach( source => {
- source.setAttribute( 'data-src', source.getAttribute( 'src' ) );
- source.removeAttribute( 'src' );
- } );
-
- }
-
- /**
- * Enforces origin-specific format rules for embedded media.
- */
- formatEmbeddedContent() {
-
- let _appendParamToIframeSource = ( sourceAttribute, sourceURL, param ) => {
- queryAll( this.Reveal.getSlidesElement(), 'iframe['+ sourceAttribute +'*="'+ sourceURL +'"]' ).forEach( el => {
- let src = el.getAttribute( sourceAttribute );
- if( src && src.indexOf( param ) === -1 ) {
- el.setAttribute( sourceAttribute, src + ( !/\?/.test( src ) ? '?' : '&' ) + param );
- }
- });
- };
-
- // YouTube frames must include "?enablejsapi=1"
- _appendParamToIframeSource( 'src', 'youtube.com/embed/', 'enablejsapi=1' );
- _appendParamToIframeSource( 'data-src', 'youtube.com/embed/', 'enablejsapi=1' );
-
- // Vimeo frames must include "?api=1"
- _appendParamToIframeSource( 'src', 'player.vimeo.com/', 'api=1' );
- _appendParamToIframeSource( 'data-src', 'player.vimeo.com/', 'api=1' );
-
- }
-
- /**
- * Start playback of any embedded content inside of
- * the given element.
- *
- * @param {HTMLElement} element
- */
- startEmbeddedContent( element ) {
-
- if( element && !this.Reveal.isSpeakerNotes() ) {
-
- // Restart GIFs
- queryAll( element, 'img[src$=".gif"]' ).forEach( el => {
- // Setting the same unchanged source like this was confirmed
- // to work in Chrome, FF & Safari
- el.setAttribute( 'src', el.getAttribute( 'src' ) );
- } );
-
- // HTML5 media elements
- queryAll( element, 'video, audio' ).forEach( el => {
- if( closest( el, '.fragment' ) && !closest( el, '.fragment.visible' ) ) {
- return;
- }
-
- // Prefer an explicit global autoplay setting
- let autoplay = this.Reveal.getConfig().autoPlayMedia;
-
- // If no global setting is available, fall back on the element's
- // own autoplay setting
- if( typeof autoplay !== 'boolean' ) {
- autoplay = el.hasAttribute( 'data-autoplay' ) || !!closest( el, '.slide-background' );
- }
-
- if( autoplay && typeof el.play === 'function' ) {
-
- // If the media is ready, start playback
- if( el.readyState > 1 ) {
- this.startEmbeddedMedia( { target: el } );
- }
- // Mobile devices never fire a loaded event so instead
- // of waiting, we initiate playback
- else if( isMobile ) {
- let promise = el.play();
-
- // If autoplay does not work, ensure that the controls are visible so
- // that the viewer can start the media on their own
- if( promise && typeof promise.catch === 'function' && el.controls === false ) {
- promise.catch( () => {
- el.controls = true;
-
- // Once the video does start playing, hide the controls again
- el.addEventListener( 'play', () => {
- el.controls = false;
- } );
- } );
- }
- }
- // If the media isn't loaded, wait before playing
- else {
- el.removeEventListener( 'loadeddata', this.startEmbeddedMedia ); // remove first to avoid dupes
- el.addEventListener( 'loadeddata', this.startEmbeddedMedia );
- }
-
- }
- } );
-
- // Normal iframes
- queryAll( element, 'iframe[src]' ).forEach( el => {
- if( closest( el, '.fragment' ) && !closest( el, '.fragment.visible' ) ) {
- return;
- }
-
- this.startEmbeddedIframe( { target: el } );
- } );
-
- // Lazy loading iframes
- queryAll( element, 'iframe[data-src]' ).forEach( el => {
- if( closest( el, '.fragment' ) && !closest( el, '.fragment.visible' ) ) {
- return;
- }
-
- if( el.getAttribute( 'src' ) !== el.getAttribute( 'data-src' ) ) {
- el.removeEventListener( 'load', this.startEmbeddedIframe ); // remove first to avoid dupes
- el.addEventListener( 'load', this.startEmbeddedIframe );
- el.setAttribute( 'src', el.getAttribute( 'data-src' ) );
- }
- } );
-
- }
-
- }
-
- /**
- * Starts playing an embedded video/audio element after
- * it has finished loading.
- *
- * @param {object} event
- */
- startEmbeddedMedia( event ) {
-
- let isAttachedToDOM = !!closest( event.target, 'html' ),
- isVisible = !!closest( event.target, '.present' );
-
- if( isAttachedToDOM && isVisible ) {
- event.target.currentTime = 0;
- event.target.play();
- }
-
- event.target.removeEventListener( 'loadeddata', this.startEmbeddedMedia );
-
- }
-
- /**
- * "Starts" the content of an embedded iframe using the
- * postMessage API.
- *
- * @param {object} event
- */
- startEmbeddedIframe( event ) {
-
- let iframe = event.target;
-
- if( iframe && iframe.contentWindow ) {
-
- let isAttachedToDOM = !!closest( event.target, 'html' ),
- isVisible = !!closest( event.target, '.present' );
-
- if( isAttachedToDOM && isVisible ) {
-
- // Prefer an explicit global autoplay setting
- let autoplay = this.Reveal.getConfig().autoPlayMedia;
-
- // If no global setting is available, fall back on the element's
- // own autoplay setting
- if( typeof autoplay !== 'boolean' ) {
- autoplay = iframe.hasAttribute( 'data-autoplay' ) || !!closest( iframe, '.slide-background' );
- }
-
- // YouTube postMessage API
- if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {
- iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' );
- }
- // Vimeo postMessage API
- else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {
- iframe.contentWindow.postMessage( '{"method":"play"}', '*' );
- }
- // Generic postMessage API
- else {
- iframe.contentWindow.postMessage( 'slide:start', '*' );
- }
-
- }
-
- }
-
- }
-
- /**
- * Stop playback of any embedded content inside of
- * the targeted slide.
- *
- * @param {HTMLElement} element
- */
- stopEmbeddedContent( element, options = {} ) {
-
- options = extend( {
- // Defaults
- unloadIframes: true
- }, options );
-
- if( element && element.parentNode ) {
- // HTML5 media elements
- queryAll( element, 'video, audio' ).forEach( el => {
- if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {
- el.setAttribute('data-paused-by-reveal', '');
- el.pause();
- }
- } );
-
- // Generic postMessage API for non-lazy loaded iframes
- queryAll( element, 'iframe' ).forEach( el => {
- if( el.contentWindow ) el.contentWindow.postMessage( 'slide:stop', '*' );
- el.removeEventListener( 'load', this.startEmbeddedIframe );
- });
-
- // YouTube postMessage API
- queryAll( element, 'iframe[src*="youtube.com/embed/"]' ).forEach( el => {
- if( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {
- el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' );
- }
- });
-
- // Vimeo postMessage API
- queryAll( element, 'iframe[src*="player.vimeo.com/"]' ).forEach( el => {
- if( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {
- el.contentWindow.postMessage( '{"method":"pause"}', '*' );
- }
- });
-
- if( options.unloadIframes === true ) {
- // Unload lazy-loaded iframes
- queryAll( element, 'iframe[data-src]' ).forEach( el => {
- // Only removing the src doesn't actually unload the frame
- // in all browsers (Firefox) so we set it to blank first
- el.setAttribute( 'src', 'about:blank' );
- el.removeAttribute( 'src' );
- } );
- }
- }
-
- }
-
-}
diff --git a/geschichte/js/controllers/slidenumber.js b/geschichte/js/controllers/slidenumber.js
deleted file mode 100644
index ff887ec..0000000
--- a/geschichte/js/controllers/slidenumber.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
- * Handles the display of reveal.js' optional slide number.
- */
-export default class SlideNumber {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- }
-
- render() {
-
- this.element = document.createElement( 'div' );
- this.element.className = 'slide-number';
- this.Reveal.getRevealElement().appendChild( this.element );
-
- }
-
- /**
- * Called when the reveal.js config is updated.
- */
- configure( config, oldConfig ) {
-
- let slideNumberDisplay = 'none';
- if( config.slideNumber && !this.Reveal.isPrintingPDF() ) {
- if( config.showSlideNumber === 'all' ) {
- slideNumberDisplay = 'block';
- }
- else if( config.showSlideNumber === 'speaker' && this.Reveal.isSpeakerNotes() ) {
- slideNumberDisplay = 'block';
- }
- }
-
- this.element.style.display = slideNumberDisplay;
-
- }
-
- /**
- * Updates the slide number to match the current slide.
- */
- update() {
-
- // Update slide number if enabled
- if( this.Reveal.getConfig().slideNumber && this.element ) {
- this.element.innerHTML = this.getSlideNumber();
- }
-
- }
-
- /**
- * Returns the HTML string corresponding to the current slide
- * number, including formatting.
- */
- getSlideNumber( slide = this.Reveal.getCurrentSlide() ) {
-
- let config = this.Reveal.getConfig();
- let value;
- let format = 'h.v';
-
- if ( typeof config.slideNumber === 'function' ) {
- value = config.slideNumber( slide );
- } else {
- // Check if a custom number format is available
- if( typeof config.slideNumber === 'string' ) {
- format = config.slideNumber;
- }
-
- // If there are ONLY vertical slides in this deck, always use
- // a flattened slide number
- if( !/c/.test( format ) && this.Reveal.getHorizontalSlides().length === 1 ) {
- format = 'c';
- }
-
- // Offset the current slide number by 1 to make it 1-indexed
- let horizontalOffset = slide && slide.dataset.visibility === 'uncounted' ? 0 : 1;
-
- value = [];
- switch( format ) {
- case 'c':
- value.push( this.Reveal.getSlidePastCount( slide ) + horizontalOffset );
- break;
- case 'c/t':
- value.push( this.Reveal.getSlidePastCount( slide ) + horizontalOffset, '/', this.Reveal.getTotalSlides() );
- break;
- default:
- let indices = this.Reveal.getIndices( slide );
- value.push( indices.h + horizontalOffset );
- let sep = format === 'h/v' ? '/' : '.';
- if( this.Reveal.isVerticalSlide( slide ) ) value.push( sep, indices.v + 1 );
- }
- }
-
- let url = '#' + this.Reveal.location.getHash( slide );
- return this.formatNumber( value[0], value[1], value[2], url );
-
- }
-
- /**
- * Applies HTML formatting to a slide number before it's
- * written to the DOM.
- *
- * @param {number} a Current slide
- * @param {string} delimiter Character to separate slide numbers
- * @param {(number|*)} b Total slides
- * @param {HTMLElement} [url='#'+locationHash()] The url to link to
- * @return {string} HTML string fragment
- */
- formatNumber( a, delimiter, b, url = '#' + this.Reveal.location.getHash() ) {
-
- if( typeof b === 'number' && !isNaN( b ) ) {
- return `<a href="${url}">
- <span class="slide-number-a">${a}</span>
- <span class="slide-number-delimiter">${delimiter}</span>
- <span class="slide-number-b">${b}</span>
- </a>`;
- }
- else {
- return `<a href="${url}">
- <span class="slide-number-a">${a}</span>
- </a>`;
- }
-
- }
-
- destroy() {
-
- this.element.remove();
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/controllers/touch.js b/geschichte/js/controllers/touch.js
deleted file mode 100644
index 5ac6a10..0000000
--- a/geschichte/js/controllers/touch.js
+++ /dev/null
@@ -1,263 +0,0 @@
-import { isAndroid } from '../utils/device.js'
-import { matches } from '../utils/util.js'
-
-const SWIPE_THRESHOLD = 40;
-
-/**
- * Controls all touch interactions and navigations for
- * a presentation.
- */
-export default class Touch {
-
- constructor( Reveal ) {
-
- this.Reveal = Reveal;
-
- // Holds information about the currently ongoing touch interaction
- this.touchStartX = 0;
- this.touchStartY = 0;
- this.touchStartCount = 0;
- this.touchCaptured = false;
-
- this.onPointerDown = this.onPointerDown.bind( this );
- this.onPointerMove = this.onPointerMove.bind( this );
- this.onPointerUp = this.onPointerUp.bind( this );
- this.onTouchStart = this.onTouchStart.bind( this );
- this.onTouchMove = this.onTouchMove.bind( this );
- this.onTouchEnd = this.onTouchEnd.bind( this );
-
- }
-
- /**
- *
- */
- bind() {
-
- let revealElement = this.Reveal.getRevealElement();
-
- if( 'onpointerdown' in window ) {
- // Use W3C pointer events
- revealElement.addEventListener( 'pointerdown', this.onPointerDown, false );
- revealElement.addEventListener( 'pointermove', this.onPointerMove, false );
- revealElement.addEventListener( 'pointerup', this.onPointerUp, false );
- }
- else if( window.navigator.msPointerEnabled ) {
- // IE 10 uses prefixed version of pointer events
- revealElement.addEventListener( 'MSPointerDown', this.onPointerDown, false );
- revealElement.addEventListener( 'MSPointerMove', this.onPointerMove, false );
- revealElement.addEventListener( 'MSPointerUp', this.onPointerUp, false );
- }
- else {
- // Fall back to touch events
- revealElement.addEventListener( 'touchstart', this.onTouchStart, false );
- revealElement.addEventListener( 'touchmove', this.onTouchMove, false );
- revealElement.addEventListener( 'touchend', this.onTouchEnd, false );
- }
-
- }
-
- /**
- *
- */
- unbind() {
-
- let revealElement = this.Reveal.getRevealElement();
-
- revealElement.removeEventListener( 'pointerdown', this.onPointerDown, false );
- revealElement.removeEventListener( 'pointermove', this.onPointerMove, false );
- revealElement.removeEventListener( 'pointerup', this.onPointerUp, false );
-
- revealElement.removeEventListener( 'MSPointerDown', this.onPointerDown, false );
- revealElement.removeEventListener( 'MSPointerMove', this.onPointerMove, false );
- revealElement.removeEventListener( 'MSPointerUp', this.onPointerUp, false );
-
- revealElement.removeEventListener( 'touchstart', this.onTouchStart, false );
- revealElement.removeEventListener( 'touchmove', this.onTouchMove, false );
- revealElement.removeEventListener( 'touchend', this.onTouchEnd, false );
-
- }
-
- /**
- * Checks if the target element prevents the triggering of
- * swipe navigation.
- */
- isSwipePrevented( target ) {
-
- // Prevent accidental swipes when scrubbing timelines
- if( matches( target, 'video, audio' ) ) return true;
-
- while( target && typeof target.hasAttribute === 'function' ) {
- if( target.hasAttribute( 'data-prevent-swipe' ) ) return true;
- target = target.parentNode;
- }
-
- return false;
-
- }
-
- /**
- * Handler for the 'touchstart' event, enables support for
- * swipe and pinch gestures.
- *
- * @param {object} event
- */
- onTouchStart( event ) {
-
- if( this.isSwipePrevented( event.target ) ) return true;
-
- this.touchStartX = event.touches[0].clientX;
- this.touchStartY = event.touches[0].clientY;
- this.touchStartCount = event.touches.length;
-
- }
-
- /**
- * Handler for the 'touchmove' event.
- *
- * @param {object} event
- */
- onTouchMove( event ) {
-
- if( this.isSwipePrevented( event.target ) ) return true;
-
- let config = this.Reveal.getConfig();
-
- // Each touch should only trigger one action
- if( !this.touchCaptured ) {
- this.Reveal.onUserInput( event );
-
- let currentX = event.touches[0].clientX;
- let currentY = event.touches[0].clientY;
-
- // There was only one touch point, look for a swipe
- if( event.touches.length === 1 && this.touchStartCount !== 2 ) {
-
- let availableRoutes = this.Reveal.availableRoutes({ includeFragments: true });
-
- let deltaX = currentX - this.touchStartX,
- deltaY = currentY - this.touchStartY;
-
- if( deltaX > SWIPE_THRESHOLD && Math.abs( deltaX ) > Math.abs( deltaY ) ) {
- this.touchCaptured = true;
- if( config.navigationMode === 'linear' ) {
- if( config.rtl ) {
- this.Reveal.next();
- }
- else {
- this.Reveal.prev();
- }
- }
- else {
- this.Reveal.left();
- }
- }
- else if( deltaX < -SWIPE_THRESHOLD && Math.abs( deltaX ) > Math.abs( deltaY ) ) {
- this.touchCaptured = true;
- if( config.navigationMode === 'linear' ) {
- if( config.rtl ) {
- this.Reveal.prev();
- }
- else {
- this.Reveal.next();
- }
- }
- else {
- this.Reveal.right();
- }
- }
- else if( deltaY > SWIPE_THRESHOLD && availableRoutes.up ) {
- this.touchCaptured = true;
- if( config.navigationMode === 'linear' ) {
- this.Reveal.prev();
- }
- else {
- this.Reveal.up();
- }
- }
- else if( deltaY < -SWIPE_THRESHOLD && availableRoutes.down ) {
- this.touchCaptured = true;
- if( config.navigationMode === 'linear' ) {
- this.Reveal.next();
- }
- else {
- this.Reveal.down();
- }
- }
-
- // If we're embedded, only block touch events if they have
- // triggered an action
- if( config.embedded ) {
- if( this.touchCaptured || this.Reveal.isVerticalSlide() ) {
- event.preventDefault();
- }
- }
- // Not embedded? Block them all to avoid needless tossing
- // around of the viewport in iOS
- else {
- event.preventDefault();
- }
-
- }
- }
- // There's a bug with swiping on some Android devices unless
- // the default action is always prevented
- else if( isAndroid ) {
- event.preventDefault();
- }
-
- }
-
- /**
- * Handler for the 'touchend' event.
- *
- * @param {object} event
- */
- onTouchEnd( event ) {
-
- this.touchCaptured = false;
-
- }
-
- /**
- * Convert pointer down to touch start.
- *
- * @param {object} event
- */
- onPointerDown( event ) {
-
- if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) {
- event.touches = [{ clientX: event.clientX, clientY: event.clientY }];
- this.onTouchStart( event );
- }
-
- }
-
- /**
- * Convert pointer move to touch move.
- *
- * @param {object} event
- */
- onPointerMove( event ) {
-
- if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) {
- event.touches = [{ clientX: event.clientX, clientY: event.clientY }];
- this.onTouchMove( event );
- }
-
- }
-
- /**
- * Convert pointer up to touch end.
- *
- * @param {object} event
- */
- onPointerUp( event ) {
-
- if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) {
- event.touches = [{ clientX: event.clientX, clientY: event.clientY }];
- this.onTouchEnd( event );
- }
-
- }
-
-} \ No newline at end of file
diff --git a/geschichte/js/index.js b/geschichte/js/index.js
deleted file mode 100644
index 57be501..0000000
--- a/geschichte/js/index.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import Deck, { VERSION } from './reveal.js'
-
-/**
- * Expose the Reveal class to the window. To create a
- * new instance:
- * let deck = new Reveal( document.querySelector( '.reveal' ), {
- * controls: false
- * } );
- * deck.initialize().then(() => {
- * // reveal.js is ready
- * });
- */
-let Reveal = Deck;
-
-
-/**
- * The below is a thin shell that mimics the pre 4.0
- * reveal.js API and ensures backwards compatibility.
- * This API only allows for one Reveal instance per
- * page, whereas the new API above lets you run many
- * presentations on the same page.
- *
- * Reveal.initialize( { controls: false } ).then(() => {
- * // reveal.js is ready
- * });
- */
-
-let enqueuedAPICalls = [];
-
-Reveal.initialize = options => {
-
- // Create our singleton reveal.js instance
- Object.assign( Reveal, new Deck( document.querySelector( '.reveal' ), options ) );
-
- // Invoke any enqueued API calls
- enqueuedAPICalls.map( method => method( Reveal ) );
-
- return Reveal.initialize();
-
-}
-
-/**
- * The pre 4.0 API let you add event listener before
- * initializing. We maintain the same behavior by
- * queuing up premature API calls and invoking all
- * of them when Reveal.initialize is called.
- */
-[ 'configure', 'on', 'off', 'addEventListener', 'removeEventListener', 'registerPlugin' ].forEach( method => {
- Reveal[method] = ( ...args ) => {
- enqueuedAPICalls.push( deck => deck[method].call( null, ...args ) );
- }
-} );
-
-Reveal.isReady = () => false;
-
-Reveal.VERSION = VERSION;
-
-export default Reveal; \ No newline at end of file
diff --git a/geschichte/js/reveal.js b/geschichte/js/reveal.js
deleted file mode 100644
index d74e429..0000000
--- a/geschichte/js/reveal.js
+++ /dev/null
@@ -1,2836 +0,0 @@
-import SlideContent from './controllers/slidecontent.js'
-import SlideNumber from './controllers/slidenumber.js'
-import JumpToSlide from './controllers/jumptoslide.js'
-import Backgrounds from './controllers/backgrounds.js'
-import AutoAnimate from './controllers/autoanimate.js'
-import Fragments from './controllers/fragments.js'
-import Overview from './controllers/overview.js'
-import Keyboard from './controllers/keyboard.js'
-import Location from './controllers/location.js'
-import Controls from './controllers/controls.js'
-import Progress from './controllers/progress.js'
-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'
-import * as Util from './utils/util.js'
-import * as Device from './utils/device.js'
-import {
- SLIDES_SELECTOR,
- HORIZONTAL_SLIDES_SELECTOR,
- VERTICAL_SLIDES_SELECTOR,
- POST_MESSAGE_METHOD_BLACKLIST
-} from './utils/constants.js'
-
-// The reveal.js version
-export const VERSION = '4.5.0';
-
-/**
- * reveal.js
- * https://revealjs.com
- * MIT licensed
- *
- * Copyright (C) 2011-2022 Hakim El Hattab, https://hakim.se
- */
-export default function( revealElement, options ) {
-
- // Support initialization with no args, one arg
- // [options] or two args [revealElement, options]
- if( arguments.length < 2 ) {
- options = arguments[0];
- revealElement = document.querySelector( '.reveal' );
- }
-
- const Reveal = {};
-
- // Configuration defaults, can be overridden at initialization time
- let config = {},
-
- // Flags if reveal.js is loaded (has dispatched the 'ready' event)
- ready = false,
-
- // The horizontal and vertical index of the currently active slide
- indexh,
- indexv,
-
- // The previous and current slide HTML elements
- previousSlide,
- currentSlide,
-
- // Remember which directions that the user has navigated towards
- navigationHistory = {
- hasNavigatedHorizontally: false,
- hasNavigatedVertically: false
- },
-
- // Slides may have a data-state attribute which we pick up and apply
- // as a class to the body. This list contains the combined state of
- // all current slides.
- state = [],
-
- // The current scale of the presentation (see width/height config)
- scale = 1,
-
- // CSS transform that is currently applied to the slides container,
- // split into two groups
- slidesTransform = { layout: '', overview: '' },
-
- // Cached references to DOM elements
- dom = {},
-
- // Flags if the interaction event listeners are bound
- eventsAreBound = false,
-
- // The current slide transition state; idle or running
- transition = 'idle',
-
- // The current auto-slide duration
- autoSlide = 0,
-
- // Auto slide properties
- autoSlidePlayer,
- autoSlideTimeout = 0,
- autoSlideStartTime = -1,
- autoSlidePaused = false,
-
- // Controllers for different aspects of our presentation. They're
- // all given direct references to this Reveal instance since there
- // may be multiple presentations running in parallel.
- slideContent = new SlideContent( Reveal ),
- slideNumber = new SlideNumber( Reveal ),
- jumpToSlide = new JumpToSlide( Reveal ),
- autoAnimate = new AutoAnimate( Reveal ),
- backgrounds = new Backgrounds( Reveal ),
- fragments = new Fragments( Reveal ),
- overview = new Overview( Reveal ),
- keyboard = new Keyboard( Reveal ),
- location = new Location( Reveal ),
- controls = new Controls( Reveal ),
- progress = new Progress( Reveal ),
- pointer = new Pointer( Reveal ),
- plugins = new Plugins( Reveal ),
- print = new Print( Reveal ),
- focus = new Focus( Reveal ),
- touch = new Touch( Reveal ),
- notes = new Notes( Reveal );
-
- /**
- * Starts up the presentation.
- */
- function initialize( initOptions ) {
-
- if( !revealElement ) throw 'Unable to find presentation root (<div class="reveal">).';
-
- // Cache references to key DOM elements
- dom.wrapper = revealElement;
- dom.slides = revealElement.querySelector( '.slides' );
-
- if( !dom.slides ) throw 'Unable to find slides container (<div class="slides">).';
-
- // Compose our config object in order of increasing precedence:
- // 1. Default reveal.js options
- // 2. Options provided via Reveal.configure() prior to
- // initialization
- // 3. Options passed to the Reveal constructor
- // 4. Options passed to Reveal.initialize
- // 5. Query params
- config = { ...defaultConfig, ...config, ...options, ...initOptions, ...Util.getQueryHash() };
-
- setViewport();
-
- // Force a layout when the whole page, incl fonts, has loaded
- window.addEventListener( 'load', layout, false );
-
- // Register plugins and load dependencies, then move on to #start()
- plugins.load( config.plugins, config.dependencies ).then( start );
-
- return new Promise( resolve => Reveal.on( 'ready', resolve ) );
-
- }
-
- /**
- * Encase the presentation in a reveal.js viewport. The
- * extent of the viewport differs based on configuration.
- */
- function setViewport() {
-
- // Embedded decks use the reveal element as their viewport
- if( config.embedded === true ) {
- dom.viewport = Util.closest( revealElement, '.reveal-viewport' ) || revealElement;
- }
- // Full-page decks use the body as their viewport
- else {
- dom.viewport = document.body;
- document.documentElement.classList.add( 'reveal-full-page' );
- }
-
- dom.viewport.classList.add( 'reveal-viewport' );
-
- }
-
- /**
- * Starts up reveal.js by binding input events and navigating
- * to the current URL deeplink if there is one.
- */
- function start() {
-
- ready = true;
-
- // Remove slides hidden with data-visibility
- removeHiddenSlides();
-
- // Make sure we've got all the DOM elements we need
- setupDOM();
-
- // Listen to messages posted to this window
- setupPostMessage();
-
- // Prevent the slides from being scrolled out of view
- setupScrollPrevention();
-
- // Adds bindings for fullscreen mode
- setupFullscreen();
-
- // Resets all vertical slides so that only the first is visible
- resetVerticalSlides();
-
- // Updates the presentation to match the current configuration values
- configure();
-
- // Read the initial hash
- location.readURL();
-
- // Create slide backgrounds
- backgrounds.update( true );
-
- // Notify listeners that the presentation is ready but use a 1ms
- // timeout to ensure it's not fired synchronously after #initialize()
- setTimeout( () => {
- // Enable transitions now that we're loaded
- dom.slides.classList.remove( 'no-transition' );
-
- dom.wrapper.classList.add( 'ready' );
-
- dispatchEvent({
- type: 'ready',
- data: {
- indexh,
- indexv,
- currentSlide
- }
- });
- }, 1 );
-
- // Special setup and config is required when printing to PDF
- if( print.isPrintingPDF() ) {
- removeEventListeners();
-
- // The document needs to have loaded for the PDF layout
- // measurements to be accurate
- if( document.readyState === 'complete' ) {
- print.setupPDF();
- }
- else {
- window.addEventListener( 'load', () => {
- print.setupPDF();
- } );
- }
- }
-
- }
-
- /**
- * Removes all slides with data-visibility="hidden". This
- * is done right before the rest of the presentation is
- * initialized.
- *
- * If you want to show all hidden slides, initialize
- * reveal.js with showHiddenSlides set to true.
- */
- function removeHiddenSlides() {
-
- if( !config.showHiddenSlides ) {
- Util.queryAll( dom.wrapper, 'section[data-visibility="hidden"]' ).forEach( slide => {
- slide.parentNode.removeChild( slide );
- } );
- }
-
- }
-
- /**
- * Finds and stores references to DOM elements which are
- * required by the presentation. If a required element is
- * not found, it is created.
- */
- function setupDOM() {
-
- // Prevent transitions while we're loading
- dom.slides.classList.add( 'no-transition' );
-
- if( Device.isMobile ) {
- dom.wrapper.classList.add( 'no-hover' );
- }
- else {
- dom.wrapper.classList.remove( 'no-hover' );
- }
-
- backgrounds.render();
- slideNumber.render();
- jumpToSlide.render();
- controls.render();
- progress.render();
- notes.render();
-
- // Overlay graphic which is displayed during the paused mode
- dom.pauseOverlay = Util.createSingletonNode( dom.wrapper, 'div', 'pause-overlay', config.controls ? '<button class="resume-button">Resume presentation</button>' : null );
-
- dom.statusElement = createStatusElement();
-
- dom.wrapper.setAttribute( 'role', 'application' );
- }
-
- /**
- * Creates a hidden div with role aria-live to announce the
- * current slide content. Hide the div off-screen to make it
- * available only to Assistive Technologies.
- *
- * @return {HTMLElement}
- */
- function createStatusElement() {
-
- let statusElement = dom.wrapper.querySelector( '.aria-status' );
- if( !statusElement ) {
- statusElement = document.createElement( 'div' );
- statusElement.style.position = 'absolute';
- statusElement.style.height = '1px';
- statusElement.style.width = '1px';
- statusElement.style.overflow = 'hidden';
- statusElement.style.clip = 'rect( 1px, 1px, 1px, 1px )';
- statusElement.classList.add( 'aria-status' );
- statusElement.setAttribute( 'aria-live', 'polite' );
- statusElement.setAttribute( 'aria-atomic','true' );
- dom.wrapper.appendChild( statusElement );
- }
- return statusElement;
-
- }
-
- /**
- * Announces the given text to screen readers.
- */
- function announceStatus( value ) {
-
- dom.statusElement.textContent = value;
-
- }
-
- /**
- * Converts the given HTML element into a string of text
- * that can be announced to a screen reader. Hidden
- * elements are excluded.
- */
- function getStatusText( node ) {
-
- let text = '';
-
- // Text node
- if( node.nodeType === 3 ) {
- text += node.textContent;
- }
- // Element node
- else if( node.nodeType === 1 ) {
-
- let isAriaHidden = node.getAttribute( 'aria-hidden' );
- let isDisplayHidden = window.getComputedStyle( node )['display'] === 'none';
- if( isAriaHidden !== 'true' && !isDisplayHidden ) {
-
- Array.from( node.childNodes ).forEach( child => {
- text += getStatusText( child );
- } );
-
- }
-
- }
-
- text = text.trim();
-
- return text === '' ? '' : text + ' ';
-
- }
-
- /**
- * This is an unfortunate necessity. Some actions – such as
- * an input field being focused in an iframe or using the
- * keyboard to expand text selection beyond the bounds of
- * a slide – can trigger our content to be pushed out of view.
- * This scrolling can not be prevented by hiding overflow in
- * CSS (we already do) so we have to resort to repeatedly
- * checking if the slides have been offset :(
- */
- function setupScrollPrevention() {
-
- setInterval( () => {
- if( dom.wrapper.scrollTop !== 0 || dom.wrapper.scrollLeft !== 0 ) {
- dom.wrapper.scrollTop = 0;
- dom.wrapper.scrollLeft = 0;
- }
- }, 1000 );
-
- }
-
- /**
- * After entering fullscreen we need to force a layout to
- * get our presentations to scale correctly. This behavior
- * is inconsistent across browsers but a force layout seems
- * to normalize it.
- */
- function setupFullscreen() {
-
- document.addEventListener( 'fullscreenchange', onFullscreenChange );
- document.addEventListener( 'webkitfullscreenchange', onFullscreenChange );
-
- }
-
- /**
- * Registers a listener to postMessage events, this makes it
- * possible to call all reveal.js API methods from another
- * window. For example:
- *
- * revealWindow.postMessage( JSON.stringify({
- * method: 'slide',
- * args: [ 2 ]
- * }), '*' );
- */
- function setupPostMessage() {
-
- if( config.postMessage ) {
- window.addEventListener( 'message', onPostMessage, false );
- }
-
- }
-
- /**
- * Applies the configuration settings from the config
- * object. May be called multiple times.
- *
- * @param {object} options
- */
- function configure( options ) {
-
- const oldConfig = { ...config }
-
- // New config options may be passed when this method
- // is invoked through the API after initialization
- if( typeof options === 'object' ) Util.extend( config, options );
-
- // Abort if reveal.js hasn't finished loading, config
- // changes will be applied automatically once ready
- if( Reveal.isReady() === false ) return;
-
- const numberOfSlides = dom.wrapper.querySelectorAll( SLIDES_SELECTOR ).length;
-
- // The transition is added as a class on the .reveal element
- dom.wrapper.classList.remove( oldConfig.transition );
- dom.wrapper.classList.add( config.transition );
-
- dom.wrapper.setAttribute( 'data-transition-speed', config.transitionSpeed );
- dom.wrapper.setAttribute( 'data-background-transition', config.backgroundTransition );
-
- // Expose our configured slide dimensions as custom props
- dom.viewport.style.setProperty( '--slide-width', config.width + 'px' );
- dom.viewport.style.setProperty( '--slide-height', config.height + 'px' );
-
- if( config.shuffle ) {
- shuffle();
- }
-
- Util.toggleClass( dom.wrapper, 'embedded', config.embedded );
- Util.toggleClass( dom.wrapper, 'rtl', config.rtl );
- Util.toggleClass( dom.wrapper, 'center', config.center );
-
- // Exit the paused mode if it was configured off
- if( config.pause === false ) {
- resume();
- }
-
- // Iframe link previews
- if( config.previewLinks ) {
- enablePreviewLinks();
- disablePreviewLinks( '[data-preview-link=false]' );
- }
- else {
- disablePreviewLinks();
- enablePreviewLinks( '[data-preview-link]:not([data-preview-link=false])' );
- }
-
- // Reset all changes made by auto-animations
- autoAnimate.reset();
-
- // Remove existing auto-slide controls
- if( autoSlidePlayer ) {
- autoSlidePlayer.destroy();
- autoSlidePlayer = null;
- }
-
- // Generate auto-slide controls if needed
- if( numberOfSlides > 1 && config.autoSlide && config.autoSlideStoppable ) {
- autoSlidePlayer = new Playback( dom.wrapper, () => {
- return Math.min( Math.max( ( Date.now() - autoSlideStartTime ) / autoSlide, 0 ), 1 );
- } );
-
- autoSlidePlayer.on( 'click', onAutoSlidePlayerClick );
- autoSlidePaused = false;
- }
-
- // Add the navigation mode to the DOM so we can adjust styling
- if( config.navigationMode !== 'default' ) {
- dom.wrapper.setAttribute( 'data-navigation-mode', config.navigationMode );
- }
- else {
- dom.wrapper.removeAttribute( 'data-navigation-mode' );
- }
-
- notes.configure( config, oldConfig );
- focus.configure( config, oldConfig );
- pointer.configure( config, oldConfig );
- controls.configure( config, oldConfig );
- progress.configure( config, oldConfig );
- keyboard.configure( config, oldConfig );
- fragments.configure( config, oldConfig );
- slideNumber.configure( config, oldConfig );
-
- sync();
-
- }
-
- /**
- * Binds all event listeners.
- */
- function addEventListeners() {
-
- eventsAreBound = true;
-
- window.addEventListener( 'resize', onWindowResize, false );
-
- if( config.touch ) touch.bind();
- if( config.keyboard ) keyboard.bind();
- if( config.progress ) progress.bind();
- if( config.respondToHashChanges ) location.bind();
- controls.bind();
- focus.bind();
-
- dom.slides.addEventListener( 'click', onSlidesClicked, false );
- dom.slides.addEventListener( 'transitionend', onTransitionEnd, false );
- dom.pauseOverlay.addEventListener( 'click', resume, false );
-
- if( config.focusBodyOnPageVisibilityChange ) {
- document.addEventListener( 'visibilitychange', onPageVisibilityChange, false );
- }
-
- }
-
- /**
- * Unbinds all event listeners.
- */
- function removeEventListeners() {
-
- eventsAreBound = false;
-
- touch.unbind();
- focus.unbind();
- keyboard.unbind();
- controls.unbind();
- progress.unbind();
- location.unbind();
-
- window.removeEventListener( 'resize', onWindowResize, false );
-
- dom.slides.removeEventListener( 'click', onSlidesClicked, false );
- dom.slides.removeEventListener( 'transitionend', onTransitionEnd, false );
- dom.pauseOverlay.removeEventListener( 'click', resume, false );
-
- }
-
- /**
- * Uninitializes reveal.js by undoing changes made to the
- * DOM and removing all event listeners.
- */
- function destroy() {
-
- removeEventListeners();
- cancelAutoSlide();
- disablePreviewLinks();
-
- // Destroy controllers
- notes.destroy();
- focus.destroy();
- plugins.destroy();
- pointer.destroy();
- controls.destroy();
- progress.destroy();
- backgrounds.destroy();
- slideNumber.destroy();
- jumpToSlide.destroy();
-
- // Remove event listeners
- document.removeEventListener( 'fullscreenchange', onFullscreenChange );
- document.removeEventListener( 'webkitfullscreenchange', onFullscreenChange );
- document.removeEventListener( 'visibilitychange', onPageVisibilityChange, false );
- window.removeEventListener( 'message', onPostMessage, false );
- window.removeEventListener( 'load', layout, false );
-
- // Undo DOM changes
- if( dom.pauseOverlay ) dom.pauseOverlay.remove();
- if( dom.statusElement ) dom.statusElement.remove();
-
- document.documentElement.classList.remove( 'reveal-full-page' );
-
- dom.wrapper.classList.remove( 'ready', 'center', 'has-horizontal-slides', 'has-vertical-slides' );
- dom.wrapper.removeAttribute( 'data-transition-speed' );
- dom.wrapper.removeAttribute( 'data-background-transition' );
-
- dom.viewport.classList.remove( 'reveal-viewport' );
- dom.viewport.style.removeProperty( '--slide-width' );
- dom.viewport.style.removeProperty( '--slide-height' );
-
- dom.slides.style.removeProperty( 'width' );
- dom.slides.style.removeProperty( 'height' );
- dom.slides.style.removeProperty( 'zoom' );
- dom.slides.style.removeProperty( 'left' );
- dom.slides.style.removeProperty( 'top' );
- dom.slides.style.removeProperty( 'bottom' );
- dom.slides.style.removeProperty( 'right' );
- dom.slides.style.removeProperty( 'transform' );
-
- Array.from( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( slide => {
- slide.style.removeProperty( 'display' );
- slide.style.removeProperty( 'top' );
- slide.removeAttribute( 'hidden' );
- slide.removeAttribute( 'aria-hidden' );
- } );
-
- }
-
- /**
- * Adds a listener to one of our custom reveal.js events,
- * like slidechanged.
- */
- function on( type, listener, useCapture ) {
-
- revealElement.addEventListener( type, listener, useCapture );
-
- }
-
- /**
- * Unsubscribes from a reveal.js event.
- */
- function off( type, listener, useCapture ) {
-
- revealElement.removeEventListener( type, listener, useCapture );
-
- }
-
- /**
- * Applies CSS transforms to the slides container. The container
- * is transformed from two separate sources: layout and the overview
- * mode.
- *
- * @param {object} transforms
- */
- function transformSlides( transforms ) {
-
- // Pick up new transforms from arguments
- if( typeof transforms.layout === 'string' ) slidesTransform.layout = transforms.layout;
- if( typeof transforms.overview === 'string' ) slidesTransform.overview = transforms.overview;
-
- // Apply the transforms to the slides container
- if( slidesTransform.layout ) {
- Util.transformElement( dom.slides, slidesTransform.layout + ' ' + slidesTransform.overview );
- }
- else {
- Util.transformElement( dom.slides, slidesTransform.overview );
- }
-
- }
-
- /**
- * Dispatches an event of the specified type from the
- * reveal DOM element.
- */
- function dispatchEvent({ target=dom.wrapper, type, data, bubbles=true }) {
-
- let event = document.createEvent( 'HTMLEvents', 1, 2 );
- event.initEvent( type, bubbles, true );
- Util.extend( event, data );
- target.dispatchEvent( event );
-
- if( target === dom.wrapper ) {
- // If we're in an iframe, post each reveal.js event to the
- // parent window. Used by the notes plugin
- dispatchPostMessage( type );
- }
-
- return event;
-
- }
-
- /**
- * Dispatched a postMessage of the given type from our window.
- */
- function dispatchPostMessage( type, data ) {
-
- if( config.postMessageEvents && window.parent !== window.self ) {
- let message = {
- namespace: 'reveal',
- eventName: type,
- state: getState()
- };
-
- Util.extend( message, data );
-
- window.parent.postMessage( JSON.stringify( message ), '*' );
- }
-
- }
-
- /**
- * Bind preview frame links.
- *
- * @param {string} [selector=a] - selector for anchors
- */
- function enablePreviewLinks( selector = 'a' ) {
-
- Array.from( dom.wrapper.querySelectorAll( selector ) ).forEach( element => {
- if( /^(http|www)/gi.test( element.getAttribute( 'href' ) ) ) {
- element.addEventListener( 'click', onPreviewLinkClicked, false );
- }
- } );
-
- }
-
- /**
- * Unbind preview frame links.
- */
- function disablePreviewLinks( selector = 'a' ) {
-
- Array.from( dom.wrapper.querySelectorAll( selector ) ).forEach( element => {
- if( /^(http|www)/gi.test( element.getAttribute( 'href' ) ) ) {
- element.removeEventListener( 'click', onPreviewLinkClicked, false );
- }
- } );
-
- }
-
- /**
- * Opens a preview window for the target URL.
- *
- * @param {string} url - url for preview iframe src
- */
- function showPreview( url ) {
-
- closeOverlay();
-
- dom.overlay = document.createElement( 'div' );
- dom.overlay.classList.add( 'overlay' );
- dom.overlay.classList.add( 'overlay-preview' );
- dom.wrapper.appendChild( dom.overlay );
-
- dom.overlay.innerHTML =
- `<header>
- <a class="close" href="#"><span class="icon"></span></a>
- <a class="external" href="${url}" target="_blank"><span class="icon"></span></a>
- </header>
- <div class="spinner"></div>
- <div class="viewport">
- <iframe src="${url}"></iframe>
- <small class="viewport-inner">
- <span class="x-frame-error">Unable to load iframe. This is likely due to the site's policy (x-frame-options).</span>
- </small>
- </div>`;
-
- dom.overlay.querySelector( 'iframe' ).addEventListener( 'load', event => {
- dom.overlay.classList.add( 'loaded' );
- }, false );
-
- dom.overlay.querySelector( '.close' ).addEventListener( 'click', event => {
- closeOverlay();
- event.preventDefault();
- }, false );
-
- dom.overlay.querySelector( '.external' ).addEventListener( 'click', event => {
- closeOverlay();
- }, false );
-
- }
-
- /**
- * Open or close help overlay window.
- *
- * @param {Boolean} [override] Flag which overrides the
- * toggle logic and forcibly sets the desired state. True means
- * help is open, false means it's closed.
- */
- function toggleHelp( override ){
-
- if( typeof override === 'boolean' ) {
- override ? showHelp() : closeOverlay();
- }
- else {
- if( dom.overlay ) {
- closeOverlay();
- }
- else {
- showHelp();
- }
- }
- }
-
- /**
- * Opens an overlay window with help material.
- */
- function showHelp() {
-
- if( config.help ) {
-
- closeOverlay();
-
- dom.overlay = document.createElement( 'div' );
- dom.overlay.classList.add( 'overlay' );
- dom.overlay.classList.add( 'overlay-help' );
- dom.wrapper.appendChild( dom.overlay );
-
- let html = '<p class="title">Keyboard Shortcuts</p><br/>';
-
- let shortcuts = keyboard.getShortcuts(),
- bindings = keyboard.getBindings();
-
- html += '<table><th>KEY</th><th>ACTION</th>';
- for( let key in shortcuts ) {
- html += `<tr><td>${key}</td><td>${shortcuts[ key ]}</td></tr>`;
- }
-
- // Add custom key bindings that have associated descriptions
- for( let binding in bindings ) {
- if( bindings[binding].key && bindings[binding].description ) {
- html += `<tr><td>${bindings[binding].key}</td><td>${bindings[binding].description}</td></tr>`;
- }
- }
-
- html += '</table>';
-
- dom.overlay.innerHTML = `
- <header>
- <a class="close" href="#"><span class="icon"></span></a>
- </header>
- <div class="viewport">
- <div class="viewport-inner">${html}</div>
- </div>
- `;
-
- dom.overlay.querySelector( '.close' ).addEventListener( 'click', event => {
- closeOverlay();
- event.preventDefault();
- }, false );
-
- }
-
- }
-
- /**
- * Closes any currently open overlay.
- */
- function closeOverlay() {
-
- if( dom.overlay ) {
- dom.overlay.parentNode.removeChild( dom.overlay );
- dom.overlay = null;
- return true;
- }
-
- return false;
-
- }
-
- /**
- * Applies JavaScript-controlled layout rules to the
- * presentation.
- */
- function layout() {
-
- if( dom.wrapper && !print.isPrintingPDF() ) {
-
- if( !config.disableLayout ) {
-
- // On some mobile devices '100vh' is taller than the visible
- // viewport which leads to part of the presentation being
- // cut off. To work around this we define our own '--vh' custom
- // property where 100x adds up to the correct height.
- //
- // https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
- if( Device.isMobile && !config.embedded ) {
- document.documentElement.style.setProperty( '--vh', ( window.innerHeight * 0.01 ) + 'px' );
- }
-
- const size = getComputedSlideSize();
-
- const oldScale = scale;
-
- // Layout the contents of the slides
- layoutSlideContents( config.width, config.height );
-
- dom.slides.style.width = size.width + 'px';
- dom.slides.style.height = size.height + 'px';
-
- // Determine scale of content to fit within available space
- scale = Math.min( size.presentationWidth / size.width, size.presentationHeight / size.height );
-
- // Respect max/min scale settings
- scale = Math.max( scale, config.minScale );
- scale = Math.min( scale, config.maxScale );
-
- // Don't apply any scaling styles if scale is 1
- if( scale === 1 ) {
- dom.slides.style.zoom = '';
- dom.slides.style.left = '';
- dom.slides.style.top = '';
- dom.slides.style.bottom = '';
- dom.slides.style.right = '';
- transformSlides( { layout: '' } );
- }
- else {
- dom.slides.style.zoom = '';
- dom.slides.style.left = '50%';
- dom.slides.style.top = '50%';
- dom.slides.style.bottom = 'auto';
- dom.slides.style.right = 'auto';
- transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +')' } );
- }
-
- // Select all slides, vertical and horizontal
- const slides = Array.from( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) );
-
- for( let i = 0, len = slides.length; i < len; i++ ) {
- const slide = slides[ i ];
-
- // Don't bother updating invisible slides
- if( slide.style.display === 'none' ) {
- continue;
- }
-
- if( config.center || slide.classList.contains( 'center' ) ) {
- // Vertical stacks are not centred since their section
- // children will be
- if( slide.classList.contains( 'stack' ) ) {
- slide.style.top = 0;
- }
- else {
- slide.style.top = Math.max( ( size.height - slide.scrollHeight ) / 2, 0 ) + 'px';
- }
- }
- else {
- slide.style.top = '';
- }
-
- }
-
- if( oldScale !== scale ) {
- dispatchEvent({
- type: 'resize',
- data: {
- oldScale,
- scale,
- size
- }
- });
- }
- }
-
- dom.viewport.style.setProperty( '--slide-scale', scale );
-
- progress.update();
- backgrounds.updateParallax();
-
- if( overview.isActive() ) {
- overview.update();
- }
-
- }
-
- }
-
- /**
- * Applies layout logic to the contents of all slides in
- * the presentation.
- *
- * @param {string|number} width
- * @param {string|number} height
- */
- function layoutSlideContents( width, height ) {
-
- // Handle sizing of elements with the 'r-stretch' class
- Util.queryAll( dom.slides, 'section > .stretch, section > .r-stretch' ).forEach( element => {
-
- // Determine how much vertical space we can use
- let remainingHeight = Util.getRemainingHeight( element, height );
-
- // Consider the aspect ratio of media elements
- if( /(img|video)/gi.test( element.nodeName ) ) {
- const nw = element.naturalWidth || element.videoWidth,
- nh = element.naturalHeight || element.videoHeight;
-
- const es = Math.min( width / nw, remainingHeight / nh );
-
- element.style.width = ( nw * es ) + 'px';
- element.style.height = ( nh * es ) + 'px';
-
- }
- else {
- element.style.width = width + 'px';
- element.style.height = remainingHeight + 'px';
- }
-
- } );
-
- }
-
- /**
- * Calculates the computed pixel size of our slides. These
- * values are based on the width and height configuration
- * options.
- *
- * @param {number} [presentationWidth=dom.wrapper.offsetWidth]
- * @param {number} [presentationHeight=dom.wrapper.offsetHeight]
- */
- function getComputedSlideSize( presentationWidth, presentationHeight ) {
- let width = config.width;
- let height = config.height;
-
- if( config.disableLayout ) {
- width = dom.slides.offsetWidth;
- height = dom.slides.offsetHeight;
- }
-
- const size = {
- // Slide size
- width: width,
- height: height,
-
- // Presentation size
- presentationWidth: presentationWidth || dom.wrapper.offsetWidth,
- presentationHeight: presentationHeight || dom.wrapper.offsetHeight
- };
-
- // Reduce available space by margin
- size.presentationWidth -= ( size.presentationWidth * config.margin );
- size.presentationHeight -= ( size.presentationHeight * config.margin );
-
- // Slide width may be a percentage of available width
- if( typeof size.width === 'string' && /%$/.test( size.width ) ) {
- size.width = parseInt( size.width, 10 ) / 100 * size.presentationWidth;
- }
-
- // Slide height may be a percentage of available height
- if( typeof size.height === 'string' && /%$/.test( size.height ) ) {
- size.height = parseInt( size.height, 10 ) / 100 * size.presentationHeight;
- }
-
- return size;
-
- }
-
- /**
- * Stores the vertical index of a stack so that the same
- * vertical slide can be selected when navigating to and
- * from the stack.
- *
- * @param {HTMLElement} stack The vertical stack element
- * @param {string|number} [v=0] Index to memorize
- */
- function setPreviousVerticalIndex( stack, v ) {
-
- if( typeof stack === 'object' && typeof stack.setAttribute === 'function' ) {
- stack.setAttribute( 'data-previous-indexv', v || 0 );
- }
-
- }
-
- /**
- * Retrieves the vertical index which was stored using
- * #setPreviousVerticalIndex() or 0 if no previous index
- * exists.
- *
- * @param {HTMLElement} stack The vertical stack element
- */
- function getPreviousVerticalIndex( stack ) {
-
- if( typeof stack === 'object' && typeof stack.setAttribute === 'function' && stack.classList.contains( 'stack' ) ) {
- // Prefer manually defined start-indexv
- const attributeName = stack.hasAttribute( 'data-start-indexv' ) ? 'data-start-indexv' : 'data-previous-indexv';
-
- return parseInt( stack.getAttribute( attributeName ) || 0, 10 );
- }
-
- return 0;
-
- }
-
- /**
- * Checks if the current or specified slide is vertical
- * (nested within another slide).
- *
- * @param {HTMLElement} [slide=currentSlide] The slide to check
- * orientation of
- * @return {Boolean}
- */
- function isVerticalSlide( slide = currentSlide ) {
-
- return slide && slide.parentNode && !!slide.parentNode.nodeName.match( /section/i );
-
- }
-
- /**
- * Returns true if we're on the last slide in the current
- * vertical stack.
- */
- function isLastVerticalSlide() {
-
- if( currentSlide && isVerticalSlide( currentSlide ) ) {
- // Does this slide have a next sibling?
- if( currentSlide.nextElementSibling ) return false;
-
- return true;
- }
-
- return false;
-
- }
-
- /**
- * Returns true if we're currently on the first slide in
- * the presentation.
- */
- function isFirstSlide() {
-
- return indexh === 0 && indexv === 0;
-
- }
-
- /**
- * Returns true if we're currently on the last slide in
- * the presenation. If the last slide is a stack, we only
- * consider this the last slide if it's at the end of the
- * stack.
- */
- function isLastSlide() {
-
- if( currentSlide ) {
- // Does this slide have a next sibling?
- if( currentSlide.nextElementSibling ) return false;
-
- // If it's vertical, does its parent have a next sibling?
- if( isVerticalSlide( currentSlide ) && currentSlide.parentNode.nextElementSibling ) return false;
-
- return true;
- }
-
- return false;
-
- }
-
- /**
- * Enters the paused mode which fades everything on screen to
- * black.
- */
- function pause() {
-
- if( config.pause ) {
- const wasPaused = dom.wrapper.classList.contains( 'paused' );
-
- cancelAutoSlide();
- dom.wrapper.classList.add( 'paused' );
-
- if( wasPaused === false ) {
- dispatchEvent({ type: 'paused' });
- }
- }
-
- }
-
- /**
- * Exits from the paused mode.
- */
- function resume() {
-
- const wasPaused = dom.wrapper.classList.contains( 'paused' );
- dom.wrapper.classList.remove( 'paused' );
-
- cueAutoSlide();
-
- if( wasPaused ) {
- dispatchEvent({ type: 'resumed' });
- }
-
- }
-
- /**
- * Toggles the paused mode on and off.
- */
- function togglePause( override ) {
-
- if( typeof override === 'boolean' ) {
- override ? pause() : resume();
- }
- else {
- isPaused() ? resume() : pause();
- }
-
- }
-
- /**
- * Checks if we are currently in the paused mode.
- *
- * @return {Boolean}
- */
- function isPaused() {
-
- return dom.wrapper.classList.contains( 'paused' );
-
- }
-
- /**
- * Toggles visibility of the jump-to-slide UI.
- */
- function toggleJumpToSlide( override ) {
-
- if( typeof override === 'boolean' ) {
- override ? jumpToSlide.show() : jumpToSlide.hide();
- }
- else {
- jumpToSlide.isVisible() ? jumpToSlide.hide() : jumpToSlide.show();
- }
-
- }
-
- /**
- * Toggles the auto slide mode on and off.
- *
- * @param {Boolean} [override] Flag which sets the desired state.
- * True means autoplay starts, false means it stops.
- */
-
- function toggleAutoSlide( override ) {
-
- if( typeof override === 'boolean' ) {
- override ? resumeAutoSlide() : pauseAutoSlide();
- }
-
- else {
- autoSlidePaused ? resumeAutoSlide() : pauseAutoSlide();
- }
-
- }
-
- /**
- * Checks if the auto slide mode is currently on.
- *
- * @return {Boolean}
- */
- function isAutoSliding() {
-
- return !!( autoSlide && !autoSlidePaused );
-
- }
-
- /**
- * Steps from the current point in the presentation to the
- * slide which matches the specified horizontal and vertical
- * indices.
- *
- * @param {number} [h=indexh] Horizontal index of the target slide
- * @param {number} [v=indexv] Vertical index of the target slide
- * @param {number} [f] Index of a fragment within the
- * target slide to activate
- * @param {number} [origin] Origin for use in multimaster environments
- */
- function slide( h, v, f, origin ) {
-
- // Dispatch an event before the slide
- const slidechange = dispatchEvent({
- type: 'beforeslidechange',
- data: {
- indexh: h === undefined ? indexh : h,
- indexv: v === undefined ? indexv : v,
- origin
- }
- });
-
- // Abort if this slide change was prevented by an event listener
- if( slidechange.defaultPrevented ) return;
-
- // Remember where we were at before
- previousSlide = currentSlide;
-
- // Query all horizontal slides in the deck
- const horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
-
- // Abort if there are no slides
- if( horizontalSlides.length === 0 ) return;
-
- // If no vertical index is specified and the upcoming slide is a
- // stack, resume at its previous vertical index
- if( v === undefined && !overview.isActive() ) {
- v = getPreviousVerticalIndex( horizontalSlides[ h ] );
- }
-
- // If we were on a vertical stack, remember what vertical index
- // it was on so we can resume at the same position when returning
- if( previousSlide && previousSlide.parentNode && previousSlide.parentNode.classList.contains( 'stack' ) ) {
- setPreviousVerticalIndex( previousSlide.parentNode, indexv );
- }
-
- // Remember the state before this slide
- const stateBefore = state.concat();
-
- // Reset the state array
- state.length = 0;
-
- let indexhBefore = indexh || 0,
- indexvBefore = indexv || 0;
-
- // Activate and transition to the new slide
- indexh = updateSlides( HORIZONTAL_SLIDES_SELECTOR, h === undefined ? indexh : h );
- indexv = updateSlides( VERTICAL_SLIDES_SELECTOR, v === undefined ? indexv : v );
-
- // Dispatch an event if the slide changed
- let slideChanged = ( indexh !== indexhBefore || indexv !== indexvBefore );
-
- // Ensure that the previous slide is never the same as the current
- if( !slideChanged ) previousSlide = null;
-
- // Find the current horizontal slide and any possible vertical slides
- // within it
- let currentHorizontalSlide = horizontalSlides[ indexh ],
- currentVerticalSlides = currentHorizontalSlide.querySelectorAll( 'section' );
-
- // Store references to the previous and current slides
- currentSlide = currentVerticalSlides[ indexv ] || currentHorizontalSlide;
-
- let autoAnimateTransition = false;
-
- // Detect if we're moving between two auto-animated slides
- if( slideChanged && previousSlide && currentSlide && !overview.isActive() ) {
-
- // If this is an auto-animated transition, we disable the
- // regular slide transition
- //
- // Note 20-03-2020:
- // This needs to happen before we update slide visibility,
- // otherwise transitions will still run in Safari.
- if( previousSlide.hasAttribute( 'data-auto-animate' ) && currentSlide.hasAttribute( 'data-auto-animate' )
- && previousSlide.getAttribute( 'data-auto-animate-id' ) === currentSlide.getAttribute( 'data-auto-animate-id' )
- && !( ( indexh > indexhBefore || indexv > indexvBefore ) ? currentSlide : previousSlide ).hasAttribute( 'data-auto-animate-restart' ) ) {
-
- autoAnimateTransition = true;
- dom.slides.classList.add( 'disable-slide-transitions' );
- }
-
- transition = 'running';
-
- }
-
- // Update the visibility of slides now that the indices have changed
- updateSlidesVisibility();
-
- layout();
-
- // Update the overview if it's currently active
- if( overview.isActive() ) {
- overview.update();
- }
-
- // Show fragment, if specified
- if( typeof f !== 'undefined' ) {
- fragments.goto( f );
- }
-
- // Solves an edge case where the previous slide maintains the
- // 'present' class when navigating between adjacent vertical
- // stacks
- if( previousSlide && previousSlide !== currentSlide ) {
- previousSlide.classList.remove( 'present' );
- previousSlide.setAttribute( 'aria-hidden', 'true' );
-
- // Reset all slides upon navigate to home
- if( isFirstSlide() ) {
- // Launch async task
- setTimeout( () => {
- getVerticalStacks().forEach( slide => {
- setPreviousVerticalIndex( slide, 0 );
- } );
- }, 0 );
- }
- }
-
- // Apply the new state
- stateLoop: for( let i = 0, len = state.length; i < len; i++ ) {
- // Check if this state existed on the previous slide. If it
- // did, we will avoid adding it repeatedly
- for( let j = 0; j < stateBefore.length; j++ ) {
- if( stateBefore[j] === state[i] ) {
- stateBefore.splice( j, 1 );
- continue stateLoop;
- }
- }
-
- dom.viewport.classList.add( state[i] );
-
- // Dispatch custom event matching the state's name
- dispatchEvent({ type: state[i] });
- }
-
- // Clean up the remains of the previous state
- while( stateBefore.length ) {
- dom.viewport.classList.remove( stateBefore.pop() );
- }
-
- if( slideChanged ) {
- dispatchEvent({
- type: 'slidechanged',
- data: {
- indexh,
- indexv,
- previousSlide,
- currentSlide,
- origin
- }
- });
- }
-
- // Handle embedded content
- if( slideChanged || !previousSlide ) {
- slideContent.stopEmbeddedContent( previousSlide );
- slideContent.startEmbeddedContent( currentSlide );
- }
-
- // Announce the current slide contents to screen readers
- // Use animation frame to prevent getComputedStyle in getStatusText
- // from triggering layout mid-frame
- requestAnimationFrame( () => {
- announceStatus( getStatusText( currentSlide ) );
- });
-
- progress.update();
- controls.update();
- notes.update();
- backgrounds.update();
- backgrounds.updateParallax();
- slideNumber.update();
- fragments.update();
-
- // Update the URL hash
- location.writeURL();
-
- cueAutoSlide();
-
- // Auto-animation
- if( autoAnimateTransition ) {
-
- setTimeout( () => {
- dom.slides.classList.remove( 'disable-slide-transitions' );
- }, 0 );
-
- if( config.autoAnimate ) {
- // Run the auto-animation between our slides
- autoAnimate.run( previousSlide, currentSlide );
- }
-
- }
-
- }
-
- /**
- * Syncs the presentation with the current DOM. Useful
- * when new slides or control elements are added or when
- * the configuration has changed.
- */
- function sync() {
-
- // Subscribe to input
- removeEventListeners();
- addEventListeners();
-
- // Force a layout to make sure the current config is accounted for
- layout();
-
- // Reflect the current autoSlide value
- autoSlide = config.autoSlide;
-
- // Start auto-sliding if it's enabled
- cueAutoSlide();
-
- // Re-create all slide backgrounds
- backgrounds.create();
-
- // Write the current hash to the URL
- location.writeURL();
-
- if( config.sortFragmentsOnSync === true ) {
- fragments.sortAll();
- }
-
- controls.update();
- progress.update();
-
- updateSlidesVisibility();
-
- notes.update();
- notes.updateVisibility();
- backgrounds.update( true );
- slideNumber.update();
- slideContent.formatEmbeddedContent();
-
- // Start or stop embedded content depending on global config
- if( config.autoPlayMedia === false ) {
- slideContent.stopEmbeddedContent( currentSlide, { unloadIframes: false } );
- }
- else {
- slideContent.startEmbeddedContent( currentSlide );
- }
-
- if( overview.isActive() ) {
- overview.layout();
- }
-
- }
-
- /**
- * Updates reveal.js to keep in sync with new slide attributes. For
- * example, if you add a new `data-background-image` you can call
- * this to have reveal.js render the new background image.
- *
- * Similar to #sync() but more efficient when you only need to
- * refresh a specific slide.
- *
- * @param {HTMLElement} slide
- */
- function syncSlide( slide = currentSlide ) {
-
- backgrounds.sync( slide );
- fragments.sync( slide );
-
- slideContent.load( slide );
-
- backgrounds.update();
- notes.update();
-
- }
-
- /**
- * Resets all vertical slides so that only the first
- * is visible.
- */
- function resetVerticalSlides() {
-
- getHorizontalSlides().forEach( horizontalSlide => {
-
- Util.queryAll( horizontalSlide, 'section' ).forEach( ( verticalSlide, y ) => {
-
- if( y > 0 ) {
- verticalSlide.classList.remove( 'present' );
- verticalSlide.classList.remove( 'past' );
- verticalSlide.classList.add( 'future' );
- verticalSlide.setAttribute( 'aria-hidden', 'true' );
- }
-
- } );
-
- } );
-
- }
-
- /**
- * Randomly shuffles all slides in the deck.
- */
- function shuffle( slides = getHorizontalSlides() ) {
-
- slides.forEach( ( slide, i ) => {
-
- // Insert the slide next to a randomly picked sibling slide
- // slide. This may cause the slide to insert before itself,
- // but that's not an issue.
- let beforeSlide = slides[ Math.floor( Math.random() * slides.length ) ];
- if( beforeSlide.parentNode === slide.parentNode ) {
- slide.parentNode.insertBefore( slide, beforeSlide );
- }
-
- // Randomize the order of vertical slides (if there are any)
- let verticalSlides = slide.querySelectorAll( 'section' );
- if( verticalSlides.length ) {
- shuffle( verticalSlides );
- }
-
- } );
-
- }
-
- /**
- * Updates one dimension of slides by showing the slide
- * with the specified index.
- *
- * @param {string} selector A CSS selector that will fetch
- * the group of slides we are working with
- * @param {number} index The index of the slide that should be
- * shown
- *
- * @return {number} The index of the slide that is now shown,
- * might differ from the passed in index if it was out of
- * bounds.
- */
- function updateSlides( selector, index ) {
-
- // Select all slides and convert the NodeList result to
- // an array
- let slides = Util.queryAll( dom.wrapper, selector ),
- slidesLength = slides.length;
-
- let printMode = print.isPrintingPDF();
- let loopedForwards = false;
- let loopedBackwards = false;
-
- if( slidesLength ) {
-
- // Should the index loop?
- if( config.loop ) {
- if( index >= slidesLength ) loopedForwards = true;
-
- index %= slidesLength;
-
- if( index < 0 ) {
- index = slidesLength + index;
- loopedBackwards = true;
- }
- }
-
- // Enforce max and minimum index bounds
- index = Math.max( Math.min( index, slidesLength - 1 ), 0 );
-
- for( let i = 0; i < slidesLength; i++ ) {
- let element = slides[i];
-
- let reverse = config.rtl && !isVerticalSlide( element );
-
- // Avoid .remove() with multiple args for IE11 support
- element.classList.remove( 'past' );
- element.classList.remove( 'present' );
- element.classList.remove( 'future' );
-
- // http://www.w3.org/html/wg/drafts/html/master/editing.html#the-hidden-attribute
- element.setAttribute( 'hidden', '' );
- element.setAttribute( 'aria-hidden', 'true' );
-
- // If this element contains vertical slides
- if( element.querySelector( 'section' ) ) {
- element.classList.add( 'stack' );
- }
-
- // If we're printing static slides, all slides are "present"
- if( printMode ) {
- element.classList.add( 'present' );
- continue;
- }
-
- if( i < index ) {
- // Any element previous to index is given the 'past' class
- element.classList.add( reverse ? 'future' : 'past' );
-
- if( config.fragments ) {
- // Show all fragments in prior slides
- showFragmentsIn( element );
- }
- }
- else if( i > index ) {
- // Any element subsequent to index is given the 'future' class
- element.classList.add( reverse ? 'past' : 'future' );
-
- if( config.fragments ) {
- // Hide all fragments in future slides
- hideFragmentsIn( element );
- }
- }
- // Update the visibility of fragments when a presentation loops
- // in either direction
- else if( i === index && config.fragments ) {
- if( loopedForwards ) {
- hideFragmentsIn( element );
- }
- else if( loopedBackwards ) {
- showFragmentsIn( element );
- }
- }
- }
-
- let slide = slides[index];
- let wasPresent = slide.classList.contains( 'present' );
-
- // Mark the current slide as present
- slide.classList.add( 'present' );
- slide.removeAttribute( 'hidden' );
- slide.removeAttribute( 'aria-hidden' );
-
- if( !wasPresent ) {
- // Dispatch an event indicating the slide is now visible
- dispatchEvent({
- target: slide,
- type: 'visible',
- bubbles: false
- });
- }
-
- // If this slide has a state associated with it, add it
- // onto the current state of the deck
- let slideState = slide.getAttribute( 'data-state' );
- if( slideState ) {
- state = state.concat( slideState.split( ' ' ) );
- }
-
- }
- else {
- // Since there are no slides we can't be anywhere beyond the
- // zeroth index
- index = 0;
- }
-
- return index;
-
- }
-
- /**
- * Shows all fragment elements within the given contaienr.
- */
- function showFragmentsIn( container ) {
-
- Util.queryAll( container, '.fragment' ).forEach( fragment => {
- fragment.classList.add( 'visible' );
- fragment.classList.remove( 'current-fragment' );
- } );
-
- }
-
- /**
- * Hides all fragment elements within the given contaienr.
- */
- function hideFragmentsIn( container ) {
-
- Util.queryAll( container, '.fragment.visible' ).forEach( fragment => {
- fragment.classList.remove( 'visible', 'current-fragment' );
- } );
-
- }
-
- /**
- * Optimization method; hide all slides that are far away
- * from the present slide.
- */
- function updateSlidesVisibility() {
-
- // Select all slides and convert the NodeList result to
- // an array
- let horizontalSlides = getHorizontalSlides(),
- horizontalSlidesLength = horizontalSlides.length,
- distanceX,
- distanceY;
-
- if( horizontalSlidesLength && typeof indexh !== 'undefined' ) {
-
- // The number of steps away from the present slide that will
- // be visible
- let viewDistance = overview.isActive() ? 10 : config.viewDistance;
-
- // Shorten the view distance on devices that typically have
- // less resources
- if( Device.isMobile ) {
- viewDistance = overview.isActive() ? 6 : config.mobileViewDistance;
- }
-
- // All slides need to be visible when exporting to PDF
- if( print.isPrintingPDF() ) {
- viewDistance = Number.MAX_VALUE;
- }
-
- for( let x = 0; x < horizontalSlidesLength; x++ ) {
- let horizontalSlide = horizontalSlides[x];
-
- let verticalSlides = Util.queryAll( horizontalSlide, 'section' ),
- verticalSlidesLength = verticalSlides.length;
-
- // Determine how far away this slide is from the present
- distanceX = Math.abs( ( indexh || 0 ) - x ) || 0;
-
- // If the presentation is looped, distance should measure
- // 1 between the first and last slides
- if( config.loop ) {
- distanceX = Math.abs( ( ( indexh || 0 ) - x ) % ( horizontalSlidesLength - viewDistance ) ) || 0;
- }
-
- // Show the horizontal slide if it's within the view distance
- if( distanceX < viewDistance ) {
- slideContent.load( horizontalSlide );
- }
- else {
- slideContent.unload( horizontalSlide );
- }
-
- if( verticalSlidesLength ) {
-
- let oy = getPreviousVerticalIndex( horizontalSlide );
-
- for( let y = 0; y < verticalSlidesLength; y++ ) {
- let verticalSlide = verticalSlides[y];
-
- distanceY = x === ( indexh || 0 ) ? Math.abs( ( indexv || 0 ) - y ) : Math.abs( y - oy );
-
- if( distanceX + distanceY < viewDistance ) {
- slideContent.load( verticalSlide );
- }
- else {
- slideContent.unload( verticalSlide );
- }
- }
-
- }
- }
-
- // Flag if there are ANY vertical slides, anywhere in the deck
- if( hasVerticalSlides() ) {
- dom.wrapper.classList.add( 'has-vertical-slides' );
- }
- else {
- dom.wrapper.classList.remove( 'has-vertical-slides' );
- }
-
- // Flag if there are ANY horizontal slides, anywhere in the deck
- if( hasHorizontalSlides() ) {
- dom.wrapper.classList.add( 'has-horizontal-slides' );
- }
- else {
- dom.wrapper.classList.remove( 'has-horizontal-slides' );
- }
-
- }
-
- }
-
- /**
- * Determine what available routes there are for navigation.
- *
- * @return {{left: boolean, right: boolean, up: boolean, down: boolean}}
- */
- function availableRoutes({ includeFragments = false } = {}) {
-
- let horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ),
- verticalSlides = dom.wrapper.querySelectorAll( VERTICAL_SLIDES_SELECTOR );
-
- let routes = {
- left: indexh > 0,
- right: indexh < horizontalSlides.length - 1,
- up: indexv > 0,
- down: indexv < verticalSlides.length - 1
- };
-
- // Looped presentations can always be navigated as long as
- // there are slides available
- if( config.loop ) {
- if( horizontalSlides.length > 1 ) {
- routes.left = true;
- routes.right = true;
- }
-
- if( verticalSlides.length > 1 ) {
- routes.up = true;
- routes.down = true;
- }
- }
-
- if ( horizontalSlides.length > 1 && config.navigationMode === 'linear' ) {
- routes.right = routes.right || routes.down;
- routes.left = routes.left || routes.up;
- }
-
- // If includeFragments is set, a route will be considered
- // available if either a slid OR fragment is available in
- // the given direction
- if( includeFragments === true ) {
- let fragmentRoutes = fragments.availableRoutes();
- routes.left = routes.left || fragmentRoutes.prev;
- routes.up = routes.up || fragmentRoutes.prev;
- routes.down = routes.down || fragmentRoutes.next;
- routes.right = routes.right || fragmentRoutes.next;
- }
-
- // Reverse horizontal controls for rtl
- if( config.rtl ) {
- let left = routes.left;
- routes.left = routes.right;
- routes.right = left;
- }
-
- return routes;
-
- }
-
- /**
- * Returns the number of past slides. This can be used as a global
- * flattened index for slides.
- *
- * @param {HTMLElement} [slide=currentSlide] The slide we're counting before
- *
- * @return {number} Past slide count
- */
- function getSlidePastCount( slide = currentSlide ) {
-
- let horizontalSlides = getHorizontalSlides();
-
- // The number of past slides
- let pastCount = 0;
-
- // Step through all slides and count the past ones
- mainLoop: for( let i = 0; i < horizontalSlides.length; i++ ) {
-
- let horizontalSlide = horizontalSlides[i];
- let verticalSlides = horizontalSlide.querySelectorAll( 'section' );
-
- for( let j = 0; j < verticalSlides.length; j++ ) {
-
- // Stop as soon as we arrive at the present
- if( verticalSlides[j] === slide ) {
- break mainLoop;
- }
-
- // Don't count slides with the "uncounted" class
- if( verticalSlides[j].dataset.visibility !== 'uncounted' ) {
- pastCount++;
- }
-
- }
-
- // Stop as soon as we arrive at the present
- if( horizontalSlide === slide ) {
- break;
- }
-
- // Don't count the wrapping section for vertical slides and
- // slides marked as uncounted
- if( horizontalSlide.classList.contains( 'stack' ) === false && horizontalSlide.dataset.visibility !== 'uncounted' ) {
- pastCount++;
- }
-
- }
-
- return pastCount;
-
- }
-
- /**
- * Returns a value ranging from 0-1 that represents
- * how far into the presentation we have navigated.
- *
- * @return {number}
- */
- function getProgress() {
-
- // The number of past and total slides
- let totalCount = getTotalSlides();
- let pastCount = getSlidePastCount();
-
- if( currentSlide ) {
-
- let allFragments = currentSlide.querySelectorAll( '.fragment' );
-
- // If there are fragments in the current slide those should be
- // accounted for in the progress.
- if( allFragments.length > 0 ) {
- let visibleFragments = currentSlide.querySelectorAll( '.fragment.visible' );
-
- // This value represents how big a portion of the slide progress
- // that is made up by its fragments (0-1)
- let fragmentWeight = 0.9;
-
- // Add fragment progress to the past slide count
- pastCount += ( visibleFragments.length / allFragments.length ) * fragmentWeight;
- }
-
- }
-
- return Math.min( pastCount / ( totalCount - 1 ), 1 );
-
- }
-
- /**
- * Retrieves the h/v location and fragment of the current,
- * or specified, slide.
- *
- * @param {HTMLElement} [slide] If specified, the returned
- * index will be for this slide rather than the currently
- * active one
- *
- * @return {{h: number, v: number, f: number}}
- */
- function getIndices( slide ) {
-
- // By default, return the current indices
- let h = indexh,
- v = indexv,
- f;
-
- // If a slide is specified, return the indices of that slide
- if( slide ) {
- let isVertical = isVerticalSlide( slide );
- let slideh = isVertical ? slide.parentNode : slide;
-
- // Select all horizontal slides
- let horizontalSlides = getHorizontalSlides();
-
- // Now that we know which the horizontal slide is, get its index
- h = Math.max( horizontalSlides.indexOf( slideh ), 0 );
-
- // Assume we're not vertical
- v = undefined;
-
- // If this is a vertical slide, grab the vertical index
- if( isVertical ) {
- v = Math.max( Util.queryAll( slide.parentNode, 'section' ).indexOf( slide ), 0 );
- }
- }
-
- if( !slide && currentSlide ) {
- let hasFragments = currentSlide.querySelectorAll( '.fragment' ).length > 0;
- if( hasFragments ) {
- let currentFragment = currentSlide.querySelector( '.current-fragment' );
- if( currentFragment && currentFragment.hasAttribute( 'data-fragment-index' ) ) {
- f = parseInt( currentFragment.getAttribute( 'data-fragment-index' ), 10 );
- }
- else {
- f = currentSlide.querySelectorAll( '.fragment.visible' ).length - 1;
- }
- }
- }
-
- return { h, v, f };
-
- }
-
- /**
- * Retrieves all slides in this presentation.
- */
- function getSlides() {
-
- return Util.queryAll( dom.wrapper, SLIDES_SELECTOR + ':not(.stack):not([data-visibility="uncounted"])' );
-
- }
-
- /**
- * Returns a list of all horizontal slides in the deck. Each
- * vertical stack is included as one horizontal slide in the
- * resulting array.
- */
- function getHorizontalSlides() {
-
- return Util.queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR );
-
- }
-
- /**
- * Returns all vertical slides that exist within this deck.
- */
- function getVerticalSlides() {
-
- return Util.queryAll( dom.wrapper, '.slides>section>section' );
-
- }
-
- /**
- * Returns all vertical stacks (each stack can contain multiple slides).
- */
- function getVerticalStacks() {
-
- return Util.queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR + '.stack');
-
- }
-
- /**
- * Returns true if there are at least two horizontal slides.
- */
- function hasHorizontalSlides() {
-
- return getHorizontalSlides().length > 1;
- }
-
- /**
- * Returns true if there are at least two vertical slides.
- */
- function hasVerticalSlides() {
-
- return getVerticalSlides().length > 1;
-
- }
-
- /**
- * Returns an array of objects where each object represents the
- * attributes on its respective slide.
- */
- function getSlidesAttributes() {
-
- return getSlides().map( slide => {
-
- let attributes = {};
- for( let i = 0; i < slide.attributes.length; i++ ) {
- let attribute = slide.attributes[ i ];
- attributes[ attribute.name ] = attribute.value;
- }
- return attributes;
-
- } );
-
- }
-
- /**
- * Retrieves the total number of slides in this presentation.
- *
- * @return {number}
- */
- function getTotalSlides() {
-
- return getSlides().length;
-
- }
-
- /**
- * Returns the slide element matching the specified index.
- *
- * @return {HTMLElement}
- */
- function getSlide( x, y ) {
-
- let horizontalSlide = getHorizontalSlides()[ x ];
- let verticalSlides = horizontalSlide && horizontalSlide.querySelectorAll( 'section' );
-
- if( verticalSlides && verticalSlides.length && typeof y === 'number' ) {
- return verticalSlides ? verticalSlides[ y ] : undefined;
- }
-
- return horizontalSlide;
-
- }
-
- /**
- * Returns the background element for the given slide.
- * All slides, even the ones with no background properties
- * defined, have a background element so as long as the
- * index is valid an element will be returned.
- *
- * @param {mixed} x Horizontal background index OR a slide
- * HTML element
- * @param {number} y Vertical background index
- * @return {(HTMLElement[]|*)}
- */
- function getSlideBackground( x, y ) {
-
- let slide = typeof x === 'number' ? getSlide( x, y ) : x;
- if( slide ) {
- return slide.slideBackgroundElement;
- }
-
- return undefined;
-
- }
-
- /**
- * Retrieves the current state of the presentation as
- * an object. This state can then be restored at any
- * time.
- *
- * @return {{indexh: number, indexv: number, indexf: number, paused: boolean, overview: boolean}}
- */
- function getState() {
-
- let indices = getIndices();
-
- return {
- indexh: indices.h,
- indexv: indices.v,
- indexf: indices.f,
- paused: isPaused(),
- overview: overview.isActive()
- };
-
- }
-
- /**
- * Restores the presentation to the given state.
- *
- * @param {object} state As generated by getState()
- * @see {@link getState} generates the parameter `state`
- */
- function setState( state ) {
-
- if( typeof state === 'object' ) {
- slide( Util.deserialize( state.indexh ), Util.deserialize( state.indexv ), Util.deserialize( state.indexf ) );
-
- let pausedFlag = Util.deserialize( state.paused ),
- overviewFlag = Util.deserialize( state.overview );
-
- if( typeof pausedFlag === 'boolean' && pausedFlag !== isPaused() ) {
- togglePause( pausedFlag );
- }
-
- if( typeof overviewFlag === 'boolean' && overviewFlag !== overview.isActive() ) {
- overview.toggle( overviewFlag );
- }
- }
-
- }
-
- /**
- * Cues a new automated slide if enabled in the config.
- */
- function cueAutoSlide() {
-
- cancelAutoSlide();
-
- if( currentSlide && config.autoSlide !== false ) {
-
- let fragment = currentSlide.querySelector( '.current-fragment' );
-
- let fragmentAutoSlide = fragment ? fragment.getAttribute( 'data-autoslide' ) : null;
- let parentAutoSlide = currentSlide.parentNode ? currentSlide.parentNode.getAttribute( 'data-autoslide' ) : null;
- let slideAutoSlide = currentSlide.getAttribute( 'data-autoslide' );
-
- // Pick value in the following priority order:
- // 1. Current fragment's data-autoslide
- // 2. Current slide's data-autoslide
- // 3. Parent slide's data-autoslide
- // 4. Global autoSlide setting
- if( fragmentAutoSlide ) {
- autoSlide = parseInt( fragmentAutoSlide, 10 );
- }
- else if( slideAutoSlide ) {
- autoSlide = parseInt( slideAutoSlide, 10 );
- }
- else if( parentAutoSlide ) {
- autoSlide = parseInt( parentAutoSlide, 10 );
- }
- else {
- autoSlide = config.autoSlide;
-
- // If there are media elements with data-autoplay,
- // automatically set the autoSlide duration to the
- // length of that media. Not applicable if the slide
- // is divided up into fragments.
- // playbackRate is accounted for in the duration.
- if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) {
- Util.queryAll( currentSlide, 'video, audio' ).forEach( el => {
- if( el.hasAttribute( 'data-autoplay' ) ) {
- if( autoSlide && (el.duration * 1000 / el.playbackRate ) > autoSlide ) {
- autoSlide = ( el.duration * 1000 / el.playbackRate ) + 1000;
- }
- }
- } );
- }
- }
-
- // Cue the next auto-slide if:
- // - There is an autoSlide value
- // - Auto-sliding isn't paused by the user
- // - The presentation isn't paused
- // - The overview isn't active
- // - The presentation isn't over
- if( autoSlide && !autoSlidePaused && !isPaused() && !overview.isActive() && ( !isLastSlide() || fragments.availableRoutes().next || config.loop === true ) ) {
- autoSlideTimeout = setTimeout( () => {
- if( typeof config.autoSlideMethod === 'function' ) {
- config.autoSlideMethod()
- }
- else {
- navigateNext();
- }
- cueAutoSlide();
- }, autoSlide );
- autoSlideStartTime = Date.now();
- }
-
- if( autoSlidePlayer ) {
- autoSlidePlayer.setPlaying( autoSlideTimeout !== -1 );
- }
-
- }
-
- }
-
- /**
- * Cancels any ongoing request to auto-slide.
- */
- function cancelAutoSlide() {
-
- clearTimeout( autoSlideTimeout );
- autoSlideTimeout = -1;
-
- }
-
- function pauseAutoSlide() {
-
- if( autoSlide && !autoSlidePaused ) {
- autoSlidePaused = true;
- dispatchEvent({ type: 'autoslidepaused' });
- clearTimeout( autoSlideTimeout );
-
- if( autoSlidePlayer ) {
- autoSlidePlayer.setPlaying( false );
- }
- }
-
- }
-
- function resumeAutoSlide() {
-
- if( autoSlide && autoSlidePaused ) {
- autoSlidePaused = false;
- dispatchEvent({ type: 'autoslideresumed' });
- cueAutoSlide();
- }
-
- }
-
- function navigateLeft({skipFragments=false}={}) {
-
- navigationHistory.hasNavigatedHorizontally = true;
-
- // Reverse for RTL
- if( config.rtl ) {
- if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().left ) {
- slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
- }
- }
- // Normal navigation
- else if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().left ) {
- slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
- }
-
- }
-
- function navigateRight({skipFragments=false}={}) {
-
- navigationHistory.hasNavigatedHorizontally = true;
-
- // Reverse for RTL
- if( config.rtl ) {
- if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().right ) {
- slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
- }
- }
- // Normal navigation
- else if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().right ) {
- slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
- }
-
- }
-
- function navigateUp({skipFragments=false}={}) {
-
- // Prioritize hiding fragments
- if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().up ) {
- slide( indexh, indexv - 1 );
- }
-
- }
-
- function navigateDown({skipFragments=false}={}) {
-
- navigationHistory.hasNavigatedVertically = true;
-
- // Prioritize revealing fragments
- if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().down ) {
- slide( indexh, indexv + 1 );
- }
-
- }
-
- /**
- * Navigates backwards, prioritized in the following order:
- * 1) Previous fragment
- * 2) Previous vertical slide
- * 3) Previous horizontal slide
- */
- function navigatePrev({skipFragments=false}={}) {
-
- // Prioritize revealing fragments
- if( skipFragments || fragments.prev() === false ) {
- if( availableRoutes().up ) {
- navigateUp({skipFragments});
- }
- else {
- // Fetch the previous horizontal slide, if there is one
- let previousSlide;
-
- if( config.rtl ) {
- previousSlide = Util.queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR + '.future' ).pop();
- }
- else {
- previousSlide = Util.queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR + '.past' ).pop();
- }
-
- // When going backwards and arriving on a stack we start
- // at the bottom of the stack
- if( previousSlide && previousSlide.classList.contains( 'stack' ) ) {
- let v = ( previousSlide.querySelectorAll( 'section' ).length - 1 ) || undefined;
- let h = indexh - 1;
- slide( h, v );
- }
- else {
- navigateLeft({skipFragments});
- }
- }
- }
-
- }
-
- /**
- * The reverse of #navigatePrev().
- */
- function navigateNext({skipFragments=false}={}) {
-
- navigationHistory.hasNavigatedHorizontally = true;
- navigationHistory.hasNavigatedVertically = true;
-
- // Prioritize revealing fragments
- if( skipFragments || fragments.next() === false ) {
-
- let routes = availableRoutes();
-
- // When looping is enabled `routes.down` is always available
- // so we need a separate check for when we've reached the
- // end of a stack and should move horizontally
- if( routes.down && routes.right && config.loop && isLastVerticalSlide() ) {
- routes.down = false;
- }
-
- if( routes.down ) {
- navigateDown({skipFragments});
- }
- else if( config.rtl ) {
- navigateLeft({skipFragments});
- }
- else {
- navigateRight({skipFragments});
- }
- }
-
- }
-
-
- // --------------------------------------------------------------------//
- // ----------------------------- EVENTS -------------------------------//
- // --------------------------------------------------------------------//
-
- /**
- * Called by all event handlers that are based on user
- * input.
- *
- * @param {object} [event]
- */
- function onUserInput( event ) {
-
- if( config.autoSlideStoppable ) {
- pauseAutoSlide();
- }
-
- }
-
- /**
- * Listener for post message events posted to this window.
- */
- function onPostMessage( event ) {
-
- let data = event.data;
-
- // Make sure we're dealing with JSON
- if( typeof data === 'string' && data.charAt( 0 ) === '{' && data.charAt( data.length - 1 ) === '}' ) {
- data = JSON.parse( data );
-
- // Check if the requested method can be found
- if( data.method && typeof Reveal[data.method] === 'function' ) {
-
- if( POST_MESSAGE_METHOD_BLACKLIST.test( data.method ) === false ) {
-
- const result = Reveal[data.method].apply( Reveal, data.args );
-
- // Dispatch a postMessage event with the returned value from
- // our method invocation for getter functions
- dispatchPostMessage( 'callback', { method: data.method, result: result } );
-
- }
- else {
- console.warn( 'reveal.js: "'+ data.method +'" is is blacklisted from the postMessage API' );
- }
-
- }
- }
-
- }
-
- /**
- * Event listener for transition end on the current slide.
- *
- * @param {object} [event]
- */
- function onTransitionEnd( event ) {
-
- if( transition === 'running' && /section/gi.test( event.target.nodeName ) ) {
- transition = 'idle';
- dispatchEvent({
- type: 'slidetransitionend',
- data: { indexh, indexv, previousSlide, currentSlide }
- });
- }
-
- }
-
- /**
- * A global listener for all click events inside of the
- * .slides container.
- *
- * @param {object} [event]
- */
- function onSlidesClicked( event ) {
-
- const anchor = Util.closest( event.target, 'a[href^="#"]' );
-
- // If a hash link is clicked, we find the target slide
- // and navigate to it. We previously relied on 'hashchange'
- // for links like these but that prevented media with
- // audio tracks from playing in mobile browsers since it
- // wasn't considered a direct interaction with the document.
- if( anchor ) {
- const hash = anchor.getAttribute( 'href' );
- const indices = location.getIndicesFromHash( hash );
-
- if( indices ) {
- Reveal.slide( indices.h, indices.v, indices.f );
- event.preventDefault();
- }
- }
-
- }
-
- /**
- * Handler for the window level 'resize' event.
- *
- * @param {object} [event]
- */
- function onWindowResize( event ) {
-
- layout();
-
- }
-
- /**
- * Handle for the window level 'visibilitychange' event.
- *
- * @param {object} [event]
- */
- function onPageVisibilityChange( event ) {
-
- // If, after clicking a link or similar and we're coming back,
- // focus the document.body to ensure we can use keyboard shortcuts
- if( document.hidden === false && document.activeElement !== document.body ) {
- // Not all elements support .blur() - SVGs among them.
- if( typeof document.activeElement.blur === 'function' ) {
- document.activeElement.blur();
- }
- document.body.focus();
- }
-
- }
-
- /**
- * Handler for the document level 'fullscreenchange' event.
- *
- * @param {object} [event]
- */
- function onFullscreenChange( event ) {
-
- let element = document.fullscreenElement || document.webkitFullscreenElement;
- if( element === dom.wrapper ) {
- event.stopImmediatePropagation();
-
- // Timeout to avoid layout shift in Safari
- setTimeout( () => {
- Reveal.layout();
- Reveal.focus.focus(); // focus.focus :'(
- }, 1 );
- }
-
- }
-
- /**
- * Handles clicks on links that are set to preview in the
- * iframe overlay.
- *
- * @param {object} event
- */
- function onPreviewLinkClicked( event ) {
-
- if( event.currentTarget && event.currentTarget.hasAttribute( 'href' ) ) {
- let url = event.currentTarget.getAttribute( 'href' );
- if( url ) {
- showPreview( url );
- event.preventDefault();
- }
- }
-
- }
-
- /**
- * Handles click on the auto-sliding controls element.
- *
- * @param {object} [event]
- */
- function onAutoSlidePlayerClick( event ) {
-
- // Replay
- if( isLastSlide() && config.loop === false ) {
- slide( 0, 0 );
- resumeAutoSlide();
- }
- // Resume
- else if( autoSlidePaused ) {
- resumeAutoSlide();
- }
- // Pause
- else {
- pauseAutoSlide();
- }
-
- }
-
-
- // --------------------------------------------------------------------//
- // ------------------------------- API --------------------------------//
- // --------------------------------------------------------------------//
-
- // The public reveal.js API
- const API = {
- VERSION,
-
- initialize,
- configure,
- destroy,
-
- sync,
- syncSlide,
- syncFragments: fragments.sync.bind( fragments ),
-
- // Navigation methods
- slide,
- left: navigateLeft,
- right: navigateRight,
- up: navigateUp,
- down: navigateDown,
- prev: navigatePrev,
- next: navigateNext,
-
- // Navigation aliases
- navigateLeft, navigateRight, navigateUp, navigateDown, navigatePrev, navigateNext,
-
- // Fragment methods
- navigateFragment: fragments.goto.bind( fragments ),
- prevFragment: fragments.prev.bind( fragments ),
- nextFragment: fragments.next.bind( fragments ),
-
- // Event binding
- on,
- off,
-
- // Legacy event binding methods left in for backwards compatibility
- addEventListener: on,
- removeEventListener: off,
-
- // Forces an update in slide layout
- layout,
-
- // Randomizes the order of slides
- shuffle,
-
- // Returns an object with the available routes as booleans (left/right/top/bottom)
- availableRoutes,
-
- // Returns an object with the available fragments as booleans (prev/next)
- availableFragments: fragments.availableRoutes.bind( fragments ),
-
- // Toggles a help overlay with keyboard shortcuts
- toggleHelp,
-
- // Toggles the overview mode on/off
- toggleOverview: overview.toggle.bind( overview ),
-
- // Toggles the "black screen" mode on/off
- togglePause,
-
- // Toggles the auto slide mode on/off
- toggleAutoSlide,
-
- // Toggles visibility of the jump-to-slide UI
- toggleJumpToSlide,
-
- // Slide navigation checks
- isFirstSlide,
- isLastSlide,
- isLastVerticalSlide,
- isVerticalSlide,
-
- // State checks
- isPaused,
- 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
- isReady: () => ready,
-
- // Slide preloading
- loadSlide: slideContent.load.bind( slideContent ),
- unloadSlide: slideContent.unload.bind( slideContent ),
-
- // Preview management
- showPreview,
- hidePreview: closeOverlay,
-
- // Adds or removes all internal event listeners
- addEventListeners,
- removeEventListeners,
- dispatchEvent,
-
- // Facility for persisting and restoring the presentation state
- getState,
- setState,
-
- // Presentation progress on range of 0-1
- getProgress,
-
- // Returns the indices of the current, or specified, slide
- getIndices,
-
- // Returns an Array of key:value maps of the attributes of each
- // slide in the deck
- getSlidesAttributes,
-
- // Returns the number of slides that we have passed
- getSlidePastCount,
-
- // Returns the total number of slides
- getTotalSlides,
-
- // Returns the slide element at the specified index
- getSlide,
-
- // Returns the previous slide element, may be null
- getPreviousSlide: () => previousSlide,
-
- // Returns the current slide element
- getCurrentSlide: () => currentSlide,
-
- // Returns the slide background element at the specified index
- getSlideBackground,
-
- // Returns the speaker notes string for a slide, or null
- getSlideNotes: notes.getSlideNotes.bind( notes ),
-
- // Returns an Array of all slides
- getSlides,
-
- // Returns an array with all horizontal/vertical slides in the deck
- getHorizontalSlides,
- getVerticalSlides,
-
- // Checks if the presentation contains two or more horizontal
- // and vertical slides
- hasHorizontalSlides,
- hasVerticalSlides,
-
- // Checks if the deck has navigated on either axis at least once
- hasNavigatedHorizontally: () => navigationHistory.hasNavigatedHorizontally,
- hasNavigatedVertically: () => navigationHistory.hasNavigatedVertically,
-
- // Adds/removes a custom key binding
- addKeyBinding: keyboard.addKeyBinding.bind( keyboard ),
- removeKeyBinding: keyboard.removeKeyBinding.bind( keyboard ),
-
- // Programmatically triggers a keyboard event
- triggerKey: keyboard.triggerKey.bind( keyboard ),
-
- // Registers a new shortcut to include in the help overlay
- registerKeyboardShortcut: keyboard.registerKeyboardShortcut.bind( keyboard ),
-
- getComputedSlideSize,
-
- // Returns the current scale of the presentation content
- getScale: () => scale,
-
- // Returns the current configuration object
- getConfig: () => config,
-
- // Helper method, retrieves query string as a key:value map
- getQueryHash: Util.getQueryHash,
-
- // Returns the path to the current slide as represented in the URL
- getSlidePath: location.getHash.bind( location ),
-
- // Returns reveal.js DOM elements
- getRevealElement: () => revealElement,
- getSlidesElement: () => dom.slides,
- getViewportElement: () => dom.viewport,
- getBackgroundsElement: () => backgrounds.element,
-
- // API for registering and retrieving plugins
- registerPlugin: plugins.registerPlugin.bind( plugins ),
- hasPlugin: plugins.hasPlugin.bind( plugins ),
- getPlugin: plugins.getPlugin.bind( plugins ),
- getPlugins: plugins.getRegisteredPlugins.bind( plugins )
-
- };
-
- // Our internal API which controllers have access to
- Util.extend( Reveal, {
- ...API,
-
- // Methods for announcing content to screen readers
- announceStatus,
- getStatusText,
-
- // Controllers
- print,
- focus,
- progress,
- controls,
- location,
- overview,
- fragments,
- slideContent,
- slideNumber,
-
- onUserInput,
- closeOverlay,
- updateSlidesVisibility,
- layoutSlideContents,
- transformSlides,
- cueAutoSlide,
- cancelAutoSlide
- } );
-
- return API;
-
-};
diff --git a/geschichte/js/utils/color.js b/geschichte/js/utils/color.js
deleted file mode 100644
index edf67c4..0000000
--- a/geschichte/js/utils/color.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Converts various color input formats to an {r:0,g:0,b:0} object.
- *
- * @param {string} color The string representation of a color
- * @example
- * colorToRgb('#000');
- * @example
- * colorToRgb('#000000');
- * @example
- * colorToRgb('rgb(0,0,0)');
- * @example
- * colorToRgb('rgba(0,0,0)');
- *
- * @return {{r: number, g: number, b: number, [a]: number}|null}
- */
-export const colorToRgb = ( color ) => {
-
- let hex3 = color.match( /^#([0-9a-f]{3})$/i );
- if( hex3 && hex3[1] ) {
- hex3 = hex3[1];
- return {
- r: parseInt( hex3.charAt( 0 ), 16 ) * 0x11,
- g: parseInt( hex3.charAt( 1 ), 16 ) * 0x11,
- b: parseInt( hex3.charAt( 2 ), 16 ) * 0x11
- };
- }
-
- let hex6 = color.match( /^#([0-9a-f]{6})$/i );
- if( hex6 && hex6[1] ) {
- hex6 = hex6[1];
- return {
- r: parseInt( hex6.slice( 0, 2 ), 16 ),
- g: parseInt( hex6.slice( 2, 4 ), 16 ),
- b: parseInt( hex6.slice( 4, 6 ), 16 )
- };
- }
-
- let rgb = color.match( /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i );
- if( rgb ) {
- return {
- r: parseInt( rgb[1], 10 ),
- g: parseInt( rgb[2], 10 ),
- b: parseInt( rgb[3], 10 )
- };
- }
-
- let rgba = color.match( /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\,\s*([\d]+|[\d]*.[\d]+)\s*\)$/i );
- if( rgba ) {
- return {
- r: parseInt( rgba[1], 10 ),
- g: parseInt( rgba[2], 10 ),
- b: parseInt( rgba[3], 10 ),
- a: parseFloat( rgba[4] )
- };
- }
-
- return null;
-
-}
-
-/**
- * Calculates brightness on a scale of 0-255.
- *
- * @param {string} color See colorToRgb for supported formats.
- * @see {@link colorToRgb}
- */
-export const colorBrightness = ( color ) => {
-
- if( typeof color === 'string' ) color = colorToRgb( color );
-
- if( color ) {
- return ( color.r * 299 + color.g * 587 + color.b * 114 ) / 1000;
- }
-
- return null;
-
-} \ No newline at end of file
diff --git a/geschichte/js/utils/constants.js b/geschichte/js/utils/constants.js
deleted file mode 100644
index 43fcb84..0000000
--- a/geschichte/js/utils/constants.js
+++ /dev/null
@@ -1,10 +0,0 @@
-
-export const SLIDES_SELECTOR = '.slides section';
-export const HORIZONTAL_SLIDES_SELECTOR = '.slides>section';
-export const VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section';
-
-// Methods that may not be invoked via the postMessage API
-export const POST_MESSAGE_METHOD_BLACKLIST = /registerPlugin|registerKeyboardShortcut|addKeyBinding|addEventListener|showPreview/;
-
-// Regex for retrieving the fragment style from a class attribute
-export const FRAGMENT_STYLE_REGEX = /fade-(down|up|right|left|out|in-then-out|in-then-semi-out)|semi-fade-out|current-visible|shrink|grow/; \ No newline at end of file
diff --git a/geschichte/js/utils/device.js b/geschichte/js/utils/device.js
deleted file mode 100644
index f2bce20..0000000
--- a/geschichte/js/utils/device.js
+++ /dev/null
@@ -1,8 +0,0 @@
-const UA = navigator.userAgent;
-
-export const isMobile = /(iphone|ipod|ipad|android)/gi.test( UA ) ||
- ( navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 ); // iPadOS
-
-export const isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA );
-
-export const isAndroid = /android/gi.test( UA ); \ No newline at end of file
diff --git a/geschichte/js/utils/loader.js b/geschichte/js/utils/loader.js
deleted file mode 100644
index 58d39ac..0000000
--- a/geschichte/js/utils/loader.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Loads a JavaScript file from the given URL and executes it.
- *
- * @param {string} url Address of the .js file to load
- * @param {function} callback Method to invoke when the script
- * has loaded and executed
- */
-export const loadScript = ( url, callback ) => {
-
- const script = document.createElement( 'script' );
- script.type = 'text/javascript';
- script.async = false;
- script.defer = false;
- script.src = url;
-
- if( typeof callback === 'function' ) {
-
- // Success callback
- script.onload = script.onreadystatechange = event => {
- if( event.type === 'load' || /loaded|complete/.test( script.readyState ) ) {
-
- // Kill event listeners
- script.onload = script.onreadystatechange = script.onerror = null;
-
- callback();
-
- }
- };
-
- // Error callback
- script.onerror = err => {
-
- // Kill event listeners
- script.onload = script.onreadystatechange = script.onerror = null;
-
- callback( new Error( 'Failed loading script: ' + script.src + '\n' + err ) );
-
- };
-
- }
-
- // Append the script at the end of <head>
- const head = document.querySelector( 'head' );
- head.insertBefore( script, head.lastChild );
-
-} \ No newline at end of file
diff --git a/geschichte/js/utils/util.js b/geschichte/js/utils/util.js
deleted file mode 100644
index a5515e8..0000000
--- a/geschichte/js/utils/util.js
+++ /dev/null
@@ -1,313 +0,0 @@
-/**
- * Extend object a with the properties of object b.
- * If there's a conflict, object b takes precedence.
- *
- * @param {object} a
- * @param {object} b
- */
-export const extend = ( a, b ) => {
-
- for( let i in b ) {
- a[ i ] = b[ i ];
- }
-
- return a;
-
-}
-
-/**
- * querySelectorAll but returns an Array.
- */
-export const queryAll = ( el, selector ) => {
-
- return Array.from( el.querySelectorAll( selector ) );
-
-}
-
-/**
- * classList.toggle() with cross browser support
- */
-export const toggleClass = ( el, className, value ) => {
- if( value ) {
- el.classList.add( className );
- }
- else {
- el.classList.remove( className );
- }
-}
-
-/**
- * Utility for deserializing a value.
- *
- * @param {*} value
- * @return {*}
- */
-export const deserialize = ( value ) => {
-
- if( typeof value === 'string' ) {
- if( value === 'null' ) return null;
- else if( value === 'true' ) return true;
- else if( value === 'false' ) return false;
- else if( value.match( /^-?[\d\.]+$/ ) ) return parseFloat( value );
- }
-
- return value;
-
-}
-
-/**
- * Measures the distance in pixels between point a
- * and point b.
- *
- * @param {object} a point with x/y properties
- * @param {object} b point with x/y properties
- *
- * @return {number}
- */
-export const distanceBetween = ( a, b ) => {
-
- let dx = a.x - b.x,
- dy = a.y - b.y;
-
- return Math.sqrt( dx*dx + dy*dy );
-
-}
-
-/**
- * Applies a CSS transform to the target element.
- *
- * @param {HTMLElement} element
- * @param {string} transform
- */
-export const transformElement = ( element, transform ) => {
-
- element.style.transform = transform;
-
-}
-
-/**
- * Element.matches with IE support.
- *
- * @param {HTMLElement} target The element to match
- * @param {String} selector The CSS selector to match
- * the element against
- *
- * @return {Boolean}
- */
-export const matches = ( target, selector ) => {
-
- let matchesMethod = target.matches || target.matchesSelector || target.msMatchesSelector;
-
- return !!( matchesMethod && matchesMethod.call( target, selector ) );
-
-}
-
-/**
- * Find the closest parent that matches the given
- * selector.
- *
- * @param {HTMLElement} target The child element
- * @param {String} selector The CSS selector to match
- * the parents against
- *
- * @return {HTMLElement} The matched parent or null
- * if no matching parent was found
- */
-export const closest = ( target, selector ) => {
-
- // Native Element.closest
- if( typeof target.closest === 'function' ) {
- return target.closest( selector );
- }
-
- // Polyfill
- while( target ) {
- if( matches( target, selector ) ) {
- return target;
- }
-
- // Keep searching
- target = target.parentNode;
- }
-
- return null;
-
-}
-
-/**
- * Handling the fullscreen functionality via the fullscreen API
- *
- * @see http://fullscreen.spec.whatwg.org/
- * @see https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode
- */
-export const enterFullscreen = element => {
-
- element = element || document.documentElement;
-
- // Check which implementation is available
- let requestMethod = element.requestFullscreen ||
- element.webkitRequestFullscreen ||
- element.webkitRequestFullScreen ||
- element.mozRequestFullScreen ||
- element.msRequestFullscreen;
-
- if( requestMethod ) {
- requestMethod.apply( element );
- }
-
-}
-
-/**
- * Creates an HTML element and returns a reference to it.
- * If the element already exists the existing instance will
- * be returned.
- *
- * @param {HTMLElement} container
- * @param {string} tagname
- * @param {string} classname
- * @param {string} innerHTML
- *
- * @return {HTMLElement}
- */
-export const createSingletonNode = ( container, tagname, classname, innerHTML='' ) => {
-
- // Find all nodes matching the description
- let nodes = container.querySelectorAll( '.' + classname );
-
- // Check all matches to find one which is a direct child of
- // the specified container
- for( let i = 0; i < nodes.length; i++ ) {
- let testNode = nodes[i];
- if( testNode.parentNode === container ) {
- return testNode;
- }
- }
-
- // If no node was found, create it now
- let node = document.createElement( tagname );
- node.className = classname;
- node.innerHTML = innerHTML;
- container.appendChild( node );
-
- return node;
-
-}
-
-/**
- * Injects the given CSS styles into the DOM.
- *
- * @param {string} value
- */
-export const createStyleSheet = ( value ) => {
-
- let tag = document.createElement( 'style' );
- tag.type = 'text/css';
-
- if( value && value.length > 0 ) {
- if( tag.styleSheet ) {
- tag.styleSheet.cssText = value;
- }
- else {
- tag.appendChild( document.createTextNode( value ) );
- }
- }
-
- document.head.appendChild( tag );
-
- return tag;
-
-}
-
-/**
- * Returns a key:value hash of all query params.
- */
-export const getQueryHash = () => {
-
- let query = {};
-
- location.search.replace( /[A-Z0-9]+?=([\w\.%-]*)/gi, a => {
- query[ a.split( '=' ).shift() ] = a.split( '=' ).pop();
- } );
-
- // Basic deserialization
- for( let i in query ) {
- let value = query[ i ];
-
- query[ i ] = deserialize( unescape( value ) );
- }
-
- // Do not accept new dependencies via query config to avoid
- // the potential of malicious script injection
- if( typeof query['dependencies'] !== 'undefined' ) delete query['dependencies'];
-
- return query;
-
-}
-
-/**
- * Returns the remaining height within the parent of the
- * target element.
- *
- * remaining height = [ configured parent height ] - [ current parent height ]
- *
- * @param {HTMLElement} element
- * @param {number} [height]
- */
-export const getRemainingHeight = ( element, height = 0 ) => {
-
- if( element ) {
- let newHeight, oldHeight = element.style.height;
-
- // Change the .stretch element height to 0 in order find the height of all
- // the other elements
- element.style.height = '0px';
-
- // In Overview mode, the parent (.slide) height is set of 700px.
- // Restore it temporarily to its natural height.
- element.parentNode.style.height = 'auto';
-
- newHeight = height - element.parentNode.offsetHeight;
-
- // Restore the old height, just in case
- element.style.height = oldHeight + 'px';
-
- // Clear the parent (.slide) height. .removeProperty works in IE9+
- element.parentNode.style.removeProperty('height');
-
- return newHeight;
- }
-
- return height;
-
-}
-
-const fileExtensionToMimeMap = {
- 'mp4': 'video/mp4',
- 'm4a': 'video/mp4',
- 'ogv': 'video/ogg',
- 'mpeg': 'video/mpeg',
- 'webm': 'video/webm'
-}
-
-/**
- * Guess the MIME type for common file formats.
- */
-export const getMimeTypeFromFile = ( filename='' ) => {
- return fileExtensionToMimeMap[filename.split('.').pop()]
-}
-
-/**
- * Encodes a string for RFC3986-compliant URL format.
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encoding_for_rfc3986
- *
- * @param {string} url
- */
-export const encodeRFC3986URI = ( url='' ) => {
- return encodeURI(url)
- .replace(/%5B/g, "[")
- .replace(/%5D/g, "]")
- .replace(
- /[!'()*]/g,
- (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
- );
-} \ No newline at end of file