summaryrefslogtreecommitdiffstats
path: root/geschichte/js/controllers
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-07-13 14:29:19 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-07-13 14:29:19 +0200
commitf2d7195922bd72167f2a01ea10419296bc2e915a (patch)
tree4a29035f0353a9561660b5358b0374b6f84ed0a4 /geschichte/js/controllers
parentchore(src/data/hello.sh): Remove (diff)
downloadb-peetz.de-f2d7195922bd72167f2a01ea10419296bc2e915a.zip
chore(geschichte): Remove
This is also irrelevant, as it is no longer used.
Diffstat (limited to '')
-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
17 files changed, 0 insertions, 4585 deletions
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