diff --git a/css/theme/template/settings.scss b/css/theme/template/settings.scss index 1f43e2bb..1e57b154 100644 --- a/css/theme/template/settings.scss +++ b/css/theme/template/settings.scss @@ -48,7 +48,7 @@ $selection-color: #fff !default; $overlay-element-bg-color: 240, 240, 240 !default; $overlay-element-fg-color: 0, 0, 0 !default; -// Expose all variables to the DOM +// Expose all SCSS variables as CSS custom properties :root { // Background of the presentation --r-background: #{$background}; diff --git a/js/config.ts b/js/config.ts index 1e478b47..127c1ec6 100644 --- a/js/config.ts +++ b/js/config.ts @@ -1,743 +1,743 @@ interface Config { - /** - * The "normal" size of the presentation, aspect ratio will be preserved - * when the presentation is scaled to fit different resolutions - * - * @defaultValue 960 - */ - width?: number | string; + /** + * The "normal" size of the presentation, aspect ratio will be preserved + * when the presentation is scaled to fit different resolutions + * + * @defaultValue 960 + */ + width?: number | string; - /** - * The "normal" size of the presentation, aspect ratio will be preserved - * when the presentation is scaled to fit different resolutions - * - * @defaultValue 700 - */ - height?: number | string; + /** + * The "normal" size of the presentation, aspect ratio will be preserved + * when the presentation is scaled to fit different resolutions + * + * @defaultValue 700 + */ + height?: number | string; - /** - * Factor of the display size that should remain empty around the content - * - * @defaultValue 0.04 - */ - margin?: number; + /** + * Factor of the display size that should remain empty around the content + * + * @defaultValue 0.04 + */ + margin?: number; - /** - * Bounds for smallest/largest possible scale to apply to content - * - * @defaultValue 0.2 - */ - minScale?: number; + /** + * Bounds for smallest/largest possible scale to apply to content + * + * @defaultValue 0.2 + */ + minScale?: number; - /** - * - * @defaultValue 2.0 - */ - maxScale?: number; + /** + * + * @defaultValue 2.0 + */ + maxScale?: number; - /** - * Display presentation control arrows + /** + * Display presentation control arrows * - true: Display controls in all views * - false: Hide controls in all views * - 'speaker-only': Display controls only in the speaker view - * - * @defaultValue true - */ - controls?: boolean | 'speaker-only'; - - /** - * Help the user learn the controls by providing hints, for example by - * bouncing the down arrow when they first encounter a vertical slide - * - * @defaultValue true - */ - controlsTutorial?: boolean; - - /** - * Determines where controls appear, "edges" or "bottom-right" - * - * @defaultValue 'bottom-right' - */ - controlsLayout?: 'edges' | 'bottom-right'; - - /** - * Visibility rule for backwards navigation arrows; "faded", "hidden" - * or "visible" - * - * @defaultValue 'faded' - */ - controlsBackArrows?: 'faded' | 'hidden' | 'visible'; - - /** - * Display a presentation progress bar - * - * @defaultValue true - */ - progress?: boolean; - - /** - * Display the page number of the current slide - * - true: Show slide number - * - false: Hide slide number - * - * Can optionally be set as a string that specifies the number formatting: - * - "h.v": Horizontal . vertical slide number (default) - * - "h/v": Horizontal / vertical slide number - * - "c": Flattened slide number - * - "c/t": Flattened slide number / total slides - * - * Alternatively, you can provide a function that returns the slide - * number for the current slide. The function should take in a slide - * object and return an array with one string [slideNumber] or - * three strings [n1,delimiter,n2]. See #formatSlideNumber(). - * - * @defaultValue false - */ - slideNumber?: - | boolean - | 'h.v' - | 'h/v' - | 'c' - | 'c/t' - | ((slide: any) => string | [string, string, string]); - - /** - * Can be used to limit the contexts in which the slide number appears - * - "all": Always show the slide number - * - "print": Only when printing to PDF - * - "speaker": Only in the speaker view - * - * @defaultValue 'all' - */ - showSlideNumber?: 'all' | 'print' | 'speaker'; - - /** - * Use 1 based indexing for # links to match slide number (default is zero - * based) - * - * @defaultValue false - */ - hashOneBasedIndex?: boolean; - - /** - * Add the current slide number to the URL hash so that reloading the - * page/copying the URL will return you to the same slide - * - * @defaultValue false - */ - hash?: boolean; - - /** - * Flags if we should monitor the hash and change slides accordingly - * - * @defaultValue true - */ - respondToHashChanges?: boolean; - - /** - * Enable support for jump-to-slide navigation shortcuts - * - * @defaultValue true - */ - jumpToSlide?: boolean; - - /** - * Push each slide change to the browser history. Implies `hash: true` - * - * @defaultValue false - */ - history?: boolean; - - /** - * Enable keyboard shortcuts for navigation - * - * @defaultValue true - */ - keyboard?: boolean; - - /** - * Optional function that blocks keyboard events when returning false - * - * If you set this to 'focused', we will only capture keyboard events - * for embedded decks when they are in focus - * - * @defaultValue null - */ - keyboardCondition?: null | 'focused' | ((event: KeyboardEvent) => boolean); - - /** - * Disables the default reveal.js slide layout (scaling and centering) - * so that you can use custom CSS layout - * - * @defaultValue false - */ - disableLayout?: boolean; - - /** - * Enable the slide overview mode - * - * @defaultValue true - */ - overview?: boolean; - - /** - * Vertical centering of slides - * - * @defaultValue true - */ - center?: boolean; - - /** - * Enables touch navigation on devices with touch input - * - * @defaultValue true - */ - touch?: boolean; - - /** - * Loop the presentation - * - * @defaultValue false - */ - loop?: boolean; - - /** - * Change the presentation direction to be RTL - * - * @defaultValue false - */ - rtl?: boolean; - - /** - * Changes the behavior of our navigation directions. - * - * "default" - * Left/right arrow keys step between horizontal slides, up/down - * arrow keys step between vertical slides. Space key steps through - * all slides (both horizontal and vertical). - * - * "linear" - * Removes the up/down arrows. Left/right arrows step through all - * slides (both horizontal and vertical). - * - * "grid" - * When this is enabled, stepping left/right from a vertical stack - * to an adjacent vertical stack will land you at the same vertical - * index. - * - * Consider a deck with six slides ordered in two vertical stacks: - * 1.1 2.1 - * 1.2 2.2 - * 1.3 2.3 - * - * If you're on slide 1.3 and navigate right, you will normally move - * from 1.3 -> 2.1. If "grid" is used, the same navigation takes you - * from 1.3 -> 2.3. - * - * @defaultValue 'default' - */ - navigationMode?: 'default' | 'linear' | 'grid'; - - /** - * Randomizes the order of slides each time the presentation loads - * - * @defaultValue false - */ - shuffle?: boolean; - - /** - * Turns fragments on and off globally - * - * @defaultValue true - */ - fragments?: boolean; - - /** - * Flags whether to include the current fragment in the URL, - * so that reloading brings you to the same fragment position - * - * @defaultValue true - */ - fragmentInURL?: boolean; - - /** - * Flags if the presentation is running in an embedded mode, - * i.e. contained within a limited portion of the screen - * - * @defaultValue false - */ - embedded?: boolean; - - /** - * Flags if we should show a help overlay when the question-mark - * key is pressed - * - * @defaultValue true - */ - help?: boolean; - - /** - * Flags if it should be possible to pause the presentation (blackout) - * - * @defaultValue true - */ - pause?: boolean; - - /** - * Flags if speaker notes should be visible to all viewers - * - * @defaultValue false - */ - showNotes?: boolean; - - /** - * Flags if slides with data-visibility="hidden" should be kept visible - * - * @defaultValue false - */ - showHiddenSlides?: boolean; - - /** - * Global override for autoplaying embedded media (video/audio/iframe) - * - null: Media will only autoplay if data-autoplay is present - * - true: All media will autoplay, regardless of individual setting - * - false: No media will autoplay, regardless of individual setting - * - * @defaultValue null - */ - autoPlayMedia?: null | boolean; - - /** - * Global override for preloading lazy-loaded iframes - * - null: Iframes with data-src AND data-preload will be loaded when within - * the viewDistance, iframes with only data-src will be loaded when visible - * - true: All iframes with data-src will be loaded when within the viewDistance - * - false: All iframes with data-src will be loaded only when visible - * - * @defaultValue null - */ - preloadIframes?: null | boolean; - - /** - * Can be used to globally disable auto-animation - * - * @defaultValue true - */ - autoAnimate?: boolean; - - /** - * Optionally provide a custom element matcher that will be - * used to dictate which elements we can animate between. - * - * @defaultValue null - */ - autoAnimateMatcher?: null | Function; - - /** - * Default settings for our auto-animate transitions, can be - * overridden per-slide or per-element via data arguments - * - * @defaultValue 'ease' - */ - autoAnimateEasing?: 'ease' | string; - - /** - * Number of seconds to animate each element. - * - * @defaultValue 1.0 - */ - autoAnimateDuration?: number; - - /** - * Should unmatched elements be faded in? - * - * @defaultValue true - */ - autoAnimateUnmatched?: boolean; - - /** - * CSS properties that can be auto-animated. Position & scale - * is matched separately so there's no need to include styles - * like top/right/bottom/left, width/height or margin. - * - * @defaultValue ['opacity', 'color', 'background-color', 'padding', 'font-size', 'line-height', 'letter-spacing', 'border-width', 'border-color', 'border-radius', 'outline', 'outline-offset'] - */ - autoAnimateStyles?: string[]; - - /** - * Controls automatic progression to the next slide - * - 0: Auto-sliding only happens if the data-autoslide HTML attribute - * is present on the current slide or fragment - * - 1+: All slides will progress automatically at the given interval - * - false: No auto-sliding, even if data-autoslide is present - * - * @defaultValue 0 - */ - autoSlide?: number | false; - - /** - * Stop auto-sliding after user input - * - * @defaultValue true - */ - autoSlideStoppable?: boolean; - - /** - * Use this method for navigation when auto-sliding (defaults to navigateNext) - * - * @defaultValue null - */ - autoSlideMethod?: null | Function; - - /** - * Specify the average time in seconds that you think you will spend - * presenting each slide. This is used to show a pacing timer in the - * speaker view - * - * @defaultValue null - */ - defaultTiming?: null; - - /** - * Enable slide navigation via mouse wheel - * - * @defaultValue false - */ - mouseWheel?: boolean; - - /** - * Opens links in an iframe preview overlay - * Add `data-preview-link` and `data-preview-link="false"` to customize each link - * individually - * - * @defaultValue false - */ - previewLinks?: boolean; - - /** - * Exposes the reveal.js API through window.postMessage - * - * @defaultValue true - */ - postMessage?: boolean; - - /** - * Dispatches all reveal.js events to the parent window through postMessage - * - * @defaultValue false - */ - postMessageEvents?: boolean; - - /** - * Focuses body when page changes visibility to ensure keyboard shortcuts work - * - * @defaultValue true - */ - focusBodyOnPageVisibilityChange?: boolean; - - /** - * Transition style - * - * @defaultValue 'slide' - */ - transition?: 'none' | 'fade' | 'slide' | 'convex' | 'concave' | 'zoom'; - - /** - * Transition speed - * - * @defaultValue 'default' - */ - transitionSpeed?: 'default' | 'fast' | 'slow'; - - /** - * Transition style for full page slide backgrounds - * - * @defaultValue 'fade' - */ - backgroundTransition?: 'fade' | 'none' | 'slide' | 'convex' | 'concave' | 'zoom'; - - /** - * Parallax background image - * - * @defaultValue '' - */ - parallaxBackgroundImage?: null | string; // CSS syntax, e.g. "a.jpg" - - /** - * Parallax background size - * - * @defaultValue '' - */ - parallaxBackgroundSize?: null | string; // CSS syntax, e.g. "3000px 2000px" - - /** - * Parallax background repeat - * - * @defaultValue '' - */ - parallaxBackgroundRepeat?: null | string; // repeat/repeat-x/repeat-y/no-repeat/initial/inherit - - /** - * Parallax background position - * - * @defaultValue '' - */ - parallaxBackgroundPosition?: null | string; // CSS syntax, e.g. "top left" - - /** - * Amount of pixels to move the parallax background per slide step - * - * @defaultValue null - */ - parallaxBackgroundHorizontal?: null | number; - /** - * - * @defaultValue null - */ - parallaxBackgroundVertical?: null | number; - - /** - * Can be used to initialize reveal.js in one of the following views: - * - print: Render the presentation so that it can be printed to PDF - * - scroll: Show the presentation as a tall scrollable page with scroll - * triggered animations - * - * @defaultValue null - */ - view?: null | 'print' | 'scroll'; - - /** - * Adjusts the height of each slide in the scroll view. - * - full: Each slide is as tall as the viewport - * - compact: Slides are as small as possible, allowing multiple slides - * to be visible in parallel on tall devices - * - * @defaultValue 'full' - */ - scrollLayout?: 'full' | 'compact'; - - /** - * Control how scroll snapping works in the scroll view. - * - false: No snapping, scrolling is continuous - * - proximity: Snap when close to a slide - * - mandatory: Always snap to the closest slide - * - * Only applies to presentations in scroll view. - * - * @defaultValue 'mandatory' - */ - scrollSnap?: false | 'proximity' | 'mandatory'; - - /** - * Enables and configures the scroll view progress bar. - * - 'auto': Show the scrollbar while scrolling, hide while idle - * - true: Always show the scrollbar - * - false: Never show the scrollbar - * - * @defaultValue 'auto' - */ - scrollProgress?: 'auto' | boolean; - - /** - * Automatically activate the scroll view when we the viewport falls - * below the given width. - * - * @defaultValue 435 - */ - scrollActivationWidth?: number; - - /** - * The maximum number of pages a single slide can expand onto when printing - * to PDF, unlimited by default - * - * @defaultValue Number.POSITIVE_INFINITY - */ - pdfMaxPagesPerSlide?: number; - - /** - * Prints each fragment on a separate slide - * - * @defaultValue true - */ - pdfSeparateFragments?: boolean; - - /** - * Offset used to reduce the height of content within exported PDF pages. - * This exists to account for environment differences based on how you - * print to PDF. CLI printing options, like phantomjs and wkpdf, can end - * on precisely the total height of the document whereas in-browser - * printing has to end one pixel before. - * - * @defaultValue -1 - */ - pdfPageHeightOffset?: number; - - /** - * Number of slides away from the current that are visible - * - * @defaultValue 3 - */ - viewDistance?: number; - - /** - * Number of slides away from the current that are visible on mobile - * devices. It is advisable to set this to a lower number than - * viewDistance in order to save resources. - * - * @defaultValue 2 - */ - mobileViewDistance?: number; - - /** - * The display mode that will be used to show slides - * - * @defaultValue 'block' - */ - display?: string; - - /** - * Hide cursor if inactive - * - * @defaultValue true - */ - hideInactiveCursor?: boolean; - - /** - * Time before the cursor is hidden (in ms) - * - * @defaultValue 5000 - */ - hideCursorTime?: number; - - /** - * Should we automatically sort and set indices for fragments - * at each sync? (See Reveal.sync) - * - * @defaultValue true - */ - sortFragmentsOnSync?: boolean; - - /** - * Script dependencies to load - * - * @defaultValue [] - */ - dependencies?: any[]; - - /** - * Plugin objects to register and use for this presentation - * - * @defaultValue [] - */ - plugins?: any[]; + * + * @defaultValue true + */ + controls?: boolean | 'speaker-only'; + + /** + * Help the user learn the controls by providing hints, for example by + * bouncing the down arrow when they first encounter a vertical slide + * + * @defaultValue true + */ + controlsTutorial?: boolean; + + /** + * Determines where controls appear, "edges" or "bottom-right" + * + * @defaultValue 'bottom-right' + */ + controlsLayout?: 'edges' | 'bottom-right'; + + /** + * Visibility rule for backwards navigation arrows; "faded", "hidden" + * or "visible" + * + * @defaultValue 'faded' + */ + controlsBackArrows?: 'faded' | 'hidden' | 'visible'; + + /** + * Display a presentation progress bar + * + * @defaultValue true + */ + progress?: boolean; + + /** + * Display the page number of the current slide + * - true: Show slide number + * - false: Hide slide number + * + * Can optionally be set as a string that specifies the number formatting: + * - "h.v": Horizontal . vertical slide number (default) + * - "h/v": Horizontal / vertical slide number + * - "c": Flattened slide number + * - "c/t": Flattened slide number / total slides + * + * Alternatively, you can provide a function that returns the slide + * number for the current slide. The function should take in a slide + * object and return an array with one string [slideNumber] or + * three strings [n1,delimiter,n2]. See #formatSlideNumber(). + * + * @defaultValue false + */ + slideNumber?: + | boolean + | 'h.v' + | 'h/v' + | 'c' + | 'c/t' + | ((slide: any) => string | [string, string, string]); + + /** + * Can be used to limit the contexts in which the slide number appears + * - "all": Always show the slide number + * - "print": Only when printing to PDF + * - "speaker": Only in the speaker view + * + * @defaultValue 'all' + */ + showSlideNumber?: 'all' | 'print' | 'speaker'; + + /** + * Use 1 based indexing for # links to match slide number (default is zero + * based) + * + * @defaultValue false + */ + hashOneBasedIndex?: boolean; + + /** + * Add the current slide number to the URL hash so that reloading the + * page/copying the URL will return you to the same slide + * + * @defaultValue false + */ + hash?: boolean; + + /** + * Flags if we should monitor the hash and change slides accordingly + * + * @defaultValue true + */ + respondToHashChanges?: boolean; + + /** + * Enable support for jump-to-slide navigation shortcuts + * + * @defaultValue true + */ + jumpToSlide?: boolean; + + /** + * Push each slide change to the browser history. Implies `hash: true` + * + * @defaultValue false + */ + history?: boolean; + + /** + * Enable keyboard shortcuts for navigation + * + * @defaultValue true + */ + keyboard?: boolean; + + /** + * Optional function that blocks keyboard events when returning false + * + * If you set this to 'focused', we will only capture keyboard events + * for embedded decks when they are in focus + * + * @defaultValue null + */ + keyboardCondition?: null | 'focused' | ((event: KeyboardEvent) => boolean); + + /** + * Disables the default reveal.js slide layout (scaling and centering) + * so that you can use custom CSS layout + * + * @defaultValue false + */ + disableLayout?: boolean; + + /** + * Enable the slide overview mode + * + * @defaultValue true + */ + overview?: boolean; + + /** + * Vertical centering of slides + * + * @defaultValue true + */ + center?: boolean; + + /** + * Enables touch navigation on devices with touch input + * + * @defaultValue true + */ + touch?: boolean; + + /** + * Loop the presentation + * + * @defaultValue false + */ + loop?: boolean; + + /** + * Change the presentation direction to be RTL + * + * @defaultValue false + */ + rtl?: boolean; + + /** + * Changes the behavior of our navigation directions. + * + * "default" + * Left/right arrow keys step between horizontal slides, up/down + * arrow keys step between vertical slides. Space key steps through + * all slides (both horizontal and vertical). + * + * "linear" + * Removes the up/down arrows. Left/right arrows step through all + * slides (both horizontal and vertical). + * + * "grid" + * When this is enabled, stepping left/right from a vertical stack + * to an adjacent vertical stack will land you at the same vertical + * index. + * + * Consider a deck with six slides ordered in two vertical stacks: + * 1.1 2.1 + * 1.2 2.2 + * 1.3 2.3 + * + * If you're on slide 1.3 and navigate right, you will normally move + * from 1.3 -> 2.1. If "grid" is used, the same navigation takes you + * from 1.3 -> 2.3. + * + * @defaultValue 'default' + */ + navigationMode?: 'default' | 'linear' | 'grid'; + + /** + * Randomizes the order of slides each time the presentation loads + * + * @defaultValue false + */ + shuffle?: boolean; + + /** + * Turns fragments on and off globally + * + * @defaultValue true + */ + fragments?: boolean; + + /** + * Flags whether to include the current fragment in the URL, + * so that reloading brings you to the same fragment position + * + * @defaultValue true + */ + fragmentInURL?: boolean; + + /** + * Flags if the presentation is running in an embedded mode, + * i.e. contained within a limited portion of the screen + * + * @defaultValue false + */ + embedded?: boolean; + + /** + * Flags if we should show a help overlay when the question-mark + * key is pressed + * + * @defaultValue true + */ + help?: boolean; + + /** + * Flags if it should be possible to pause the presentation (blackout) + * + * @defaultValue true + */ + pause?: boolean; + + /** + * Flags if speaker notes should be visible to all viewers + * + * @defaultValue false + */ + showNotes?: boolean; + + /** + * Flags if slides with data-visibility="hidden" should be kept visible + * + * @defaultValue false + */ + showHiddenSlides?: boolean; + + /** + * Global override for autoplaying embedded media (video/audio/iframe) + * - null: Media will only autoplay if data-autoplay is present + * - true: All media will autoplay, regardless of individual setting + * - false: No media will autoplay, regardless of individual setting + * + * @defaultValue null + */ + autoPlayMedia?: null | boolean; + + /** + * Global override for preloading lazy-loaded iframes + * - null: Iframes with data-src AND data-preload will be loaded when within + * the viewDistance, iframes with only data-src will be loaded when visible + * - true: All iframes with data-src will be loaded when within the viewDistance + * - false: All iframes with data-src will be loaded only when visible + * + * @defaultValue null + */ + preloadIframes?: null | boolean; + + /** + * Can be used to globally disable auto-animation + * + * @defaultValue true + */ + autoAnimate?: boolean; + + /** + * Optionally provide a custom element matcher that will be + * used to dictate which elements we can animate between. + * + * @defaultValue null + */ + autoAnimateMatcher?: null | Function; + + /** + * Default settings for our auto-animate transitions, can be + * overridden per-slide or per-element via data arguments + * + * @defaultValue 'ease' + */ + autoAnimateEasing?: 'ease' | string; + + /** + * Number of seconds to animate each element. + * + * @defaultValue 1.0 + */ + autoAnimateDuration?: number; + + /** + * Should unmatched elements be faded in? + * + * @defaultValue true + */ + autoAnimateUnmatched?: boolean; + + /** + * CSS properties that can be auto-animated. Position & scale + * is matched separately so there's no need to include styles + * like top/right/bottom/left, width/height or margin. + * + * @defaultValue ['opacity', 'color', 'background-color', 'padding', 'font-size', 'line-height', 'letter-spacing', 'border-width', 'border-color', 'border-radius', 'outline', 'outline-offset'] + */ + autoAnimateStyles?: string[]; + + /** + * Controls automatic progression to the next slide + * - 0: Auto-sliding only happens if the data-autoslide HTML attribute + * is present on the current slide or fragment + * - 1+: All slides will progress automatically at the given interval + * - false: No auto-sliding, even if data-autoslide is present + * + * @defaultValue 0 + */ + autoSlide?: number | false; + + /** + * Stop auto-sliding after user input + * + * @defaultValue true + */ + autoSlideStoppable?: boolean; + + /** + * Use this method for navigation when auto-sliding (defaults to navigateNext) + * + * @defaultValue null + */ + autoSlideMethod?: null | Function; + + /** + * Specify the average time in seconds that you think you will spend + * presenting each slide. This is used to show a pacing timer in the + * speaker view + * + * @defaultValue null + */ + defaultTiming?: null; + + /** + * Enable slide navigation via mouse wheel + * + * @defaultValue false + */ + mouseWheel?: boolean; + + /** + * Opens links in an iframe preview overlay + * Add `data-preview-link` and `data-preview-link="false"` to customize each link + * individually + * + * @defaultValue false + */ + previewLinks?: boolean; + + /** + * Exposes the reveal.js API through window.postMessage + * + * @defaultValue true + */ + postMessage?: boolean; + + /** + * Dispatches all reveal.js events to the parent window through postMessage + * + * @defaultValue false + */ + postMessageEvents?: boolean; + + /** + * Focuses body when page changes visibility to ensure keyboard shortcuts work + * + * @defaultValue true + */ + focusBodyOnPageVisibilityChange?: boolean; + + /** + * Transition style + * + * @defaultValue 'slide' + */ + transition?: 'none' | 'fade' | 'slide' | 'convex' | 'concave' | 'zoom'; + + /** + * Transition speed + * + * @defaultValue 'default' + */ + transitionSpeed?: 'default' | 'fast' | 'slow'; + + /** + * Transition style for full page slide backgrounds + * + * @defaultValue 'fade' + */ + backgroundTransition?: 'fade' | 'none' | 'slide' | 'convex' | 'concave' | 'zoom'; + + /** + * Parallax background image + * + * @defaultValue '' + */ + parallaxBackgroundImage?: null | string; // CSS syntax, e.g. "a.jpg" + + /** + * Parallax background size + * + * @defaultValue '' + */ + parallaxBackgroundSize?: null | string; // CSS syntax, e.g. "3000px 2000px" + + /** + * Parallax background repeat + * + * @defaultValue '' + */ + parallaxBackgroundRepeat?: null | string; // repeat/repeat-x/repeat-y/no-repeat/initial/inherit + + /** + * Parallax background position + * + * @defaultValue '' + */ + parallaxBackgroundPosition?: null | string; // CSS syntax, e.g. "top left" + + /** + * Amount of pixels to move the parallax background per slide step + * + * @defaultValue null + */ + parallaxBackgroundHorizontal?: null | number; + /** + * + * @defaultValue null + */ + parallaxBackgroundVertical?: null | number; + + /** + * Can be used to initialize reveal.js in one of the following views: + * - print: Render the presentation so that it can be printed to PDF + * - scroll: Show the presentation as a tall scrollable page with scroll + * triggered animations + * + * @defaultValue null + */ + view?: null | 'print' | 'scroll'; + + /** + * Adjusts the height of each slide in the scroll view. + * - full: Each slide is as tall as the viewport + * - compact: Slides are as small as possible, allowing multiple slides + * to be visible in parallel on tall devices + * + * @defaultValue 'full' + */ + scrollLayout?: 'full' | 'compact'; + + /** + * Control how scroll snapping works in the scroll view. + * - false: No snapping, scrolling is continuous + * - proximity: Snap when close to a slide + * - mandatory: Always snap to the closest slide + * + * Only applies to presentations in scroll view. + * + * @defaultValue 'mandatory' + */ + scrollSnap?: false | 'proximity' | 'mandatory'; + + /** + * Enables and configures the scroll view progress bar. + * - 'auto': Show the scrollbar while scrolling, hide while idle + * - true: Always show the scrollbar + * - false: Never show the scrollbar + * + * @defaultValue 'auto' + */ + scrollProgress?: 'auto' | boolean; + + /** + * Automatically activate the scroll view when we the viewport falls + * below the given width. + * + * @defaultValue 435 + */ + scrollActivationWidth?: number; + + /** + * The maximum number of pages a single slide can expand onto when printing + * to PDF, unlimited by default + * + * @defaultValue Number.POSITIVE_INFINITY + */ + pdfMaxPagesPerSlide?: number; + + /** + * Prints each fragment on a separate slide + * + * @defaultValue true + */ + pdfSeparateFragments?: boolean; + + /** + * Offset used to reduce the height of content within exported PDF pages. + * This exists to account for environment differences based on how you + * print to PDF. CLI printing options, like phantomjs and wkpdf, can end + * on precisely the total height of the document whereas in-browser + * printing has to end one pixel before. + * + * @defaultValue -1 + */ + pdfPageHeightOffset?: number; + + /** + * Number of slides away from the current that are visible + * + * @defaultValue 3 + */ + viewDistance?: number; + + /** + * Number of slides away from the current that are visible on mobile + * devices. It is advisable to set this to a lower number than + * viewDistance in order to save resources. + * + * @defaultValue 2 + */ + mobileViewDistance?: number; + + /** + * The display mode that will be used to show slides + * + * @defaultValue 'block' + */ + display?: string; + + /** + * Hide cursor if inactive + * + * @defaultValue true + */ + hideInactiveCursor?: boolean; + + /** + * Time before the cursor is hidden (in ms) + * + * @defaultValue 5000 + */ + hideCursorTime?: number; + + /** + * Should we automatically sort and set indices for fragments + * at each sync? (See Reveal.sync) + * + * @defaultValue true + */ + sortFragmentsOnSync?: boolean; + + /** + * Script dependencies to load + * + * @defaultValue [] + */ + dependencies?: any[]; + + /** + * Plugin objects to register and use for this presentation + * + * @defaultValue [] + */ + plugins?: any[]; } /** * The default reveal.js config object. */ const defaultConfig: Config = { - width: 960, - height: 700, - margin: 0.04, - minScale: 0.2, - maxScale: 2.0, + width: 960, + height: 700, + margin: 0.04, + minScale: 0.2, + maxScale: 2.0, - controls: true, - controlsTutorial: true, - controlsLayout: 'bottom-right', - controlsBackArrows: 'faded', - progress: true, + controls: true, + controlsTutorial: true, + controlsLayout: 'bottom-right', + controlsBackArrows: 'faded', + progress: true, - slideNumber: false, - showSlideNumber: 'all', - hashOneBasedIndex: false, - hash: false, - respondToHashChanges: true, - jumpToSlide: true, - history: false, - keyboard: true, - keyboardCondition: null, - disableLayout: false, - overview: true, - center: true, - touch: true, - loop: false, - rtl: false, - navigationMode: 'default', - shuffle: false, - fragments: true, - fragmentInURL: true, - embedded: false, - help: true, - pause: true, - showNotes: false, - showHiddenSlides: false, - autoPlayMedia: null, - preloadIframes: null, - mouseWheel: false, - previewLinks: false, - viewDistance: 3, - mobileViewDistance: 2, - display: 'block', - hideInactiveCursor: true, - hideCursorTime: 5000, - sortFragmentsOnSync: true, + slideNumber: false, + showSlideNumber: 'all', + hashOneBasedIndex: false, + hash: false, + respondToHashChanges: true, + jumpToSlide: true, + history: false, + keyboard: true, + keyboardCondition: null, + disableLayout: false, + overview: true, + center: true, + touch: true, + loop: false, + rtl: false, + navigationMode: 'default', + shuffle: false, + fragments: true, + fragmentInURL: true, + embedded: false, + help: true, + pause: true, + showNotes: false, + showHiddenSlides: false, + autoPlayMedia: null, + preloadIframes: null, + mouseWheel: false, + previewLinks: false, + viewDistance: 3, + mobileViewDistance: 2, + display: 'block', + hideInactiveCursor: true, + hideCursorTime: 5000, + sortFragmentsOnSync: true, - autoAnimate: true, - autoAnimateMatcher: null, - autoAnimateEasing: 'ease', - autoAnimateDuration: 1.0, - autoAnimateUnmatched: true, + autoAnimate: true, + autoAnimateMatcher: null, + autoAnimateEasing: 'ease', + autoAnimateDuration: 1.0, + autoAnimateUnmatched: true, - autoAnimateStyles: [ - 'opacity', - 'color', - 'background-color', - 'padding', - 'font-size', - 'line-height', - 'letter-spacing', - 'border-width', - 'border-color', - 'border-radius', - 'outline', - 'outline-offset', - ], + autoAnimateStyles: [ + 'opacity', + 'color', + 'background-color', + 'padding', + 'font-size', + 'line-height', + 'letter-spacing', + 'border-width', + 'border-color', + 'border-radius', + 'outline', + 'outline-offset', + ], - autoSlide: 0, - autoSlideStoppable: true, - autoSlideMethod: null, - defaultTiming: null, + autoSlide: 0, + autoSlideStoppable: true, + autoSlideMethod: null, + defaultTiming: null, - postMessage: true, - postMessageEvents: false, + postMessage: true, + postMessageEvents: false, - focusBodyOnPageVisibilityChange: true, + focusBodyOnPageVisibilityChange: true, - transition: 'slide', - transitionSpeed: 'default', - backgroundTransition: 'fade', + transition: 'slide', + transitionSpeed: 'default', + backgroundTransition: 'fade', - parallaxBackgroundImage: '', - parallaxBackgroundSize: '', - parallaxBackgroundRepeat: '', - parallaxBackgroundPosition: '', - parallaxBackgroundHorizontal: null, - parallaxBackgroundVertical: null, + parallaxBackgroundImage: '', + parallaxBackgroundSize: '', + parallaxBackgroundRepeat: '', + parallaxBackgroundPosition: '', + parallaxBackgroundHorizontal: null, + parallaxBackgroundVertical: null, - view: null, + view: null, - scrollLayout: 'full', - scrollSnap: 'mandatory', - scrollProgress: 'auto', - scrollActivationWidth: 435, + scrollLayout: 'full', + scrollSnap: 'mandatory', + scrollProgress: 'auto', + scrollActivationWidth: 435, - pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY, - pdfSeparateFragments: true, - pdfPageHeightOffset: -1, + pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY, + pdfSeparateFragments: true, + pdfPageHeightOffset: -1, - dependencies: [], - plugins: [], + dependencies: [], + plugins: [], }; export type { Config }; diff --git a/js/controllers/autoanimate.js b/js/controllers/autoanimate.js index 6a706e3c..b59b25ab 100644 --- a/js/controllers/autoanimate.js +++ b/js/controllers/autoanimate.js @@ -1,5 +1,4 @@ -import { queryAll, extend, createStyleSheet, matches, closest } from '../utils/util.js' -import { FRAGMENT_STYLE_REGEX } from '../utils/constants.js' +import { queryAll, extend, createStyleSheet, matches, closest } from '../utils/util' // Counter used to generate unique IDs for auto-animated elements let autoAnimateCounter = 0; diff --git a/js/controllers/backgrounds.js b/js/controllers/backgrounds.js index 93143a78..7f99b5b9 100644 --- a/js/controllers/backgrounds.js +++ b/js/controllers/backgrounds.js @@ -1,5 +1,5 @@ -import { queryAll } from '../utils/util.js' -import { colorToRgb, colorBrightness } from '../utils/color.js' +import { queryAll } from '../utils/util' +import { colorToRgb, colorBrightness } from '../utils/color' /** * Creates and updates slide backgrounds. diff --git a/js/controllers/controls.js b/js/controllers/controls.js index 7c52a0fc..f2d553a9 100644 --- a/js/controllers/controls.js +++ b/js/controllers/controls.js @@ -1,5 +1,5 @@ -import { queryAll, enterFullscreen } from '../utils/util.js' -import { isAndroid } from '../utils/device.js' +import { queryAll, enterFullscreen } from '../utils/util' +import { isAndroid } from '../utils/device' /** * Manages our presentation controls. This includes both diff --git a/js/controllers/focus.js b/js/controllers/focus.js index 3e68c3f6..be00a937 100644 --- a/js/controllers/focus.js +++ b/js/controllers/focus.js @@ -1,4 +1,4 @@ -import { closest } from '../utils/util.js' +import { closest } from '../utils/util' /** * Manages focus when a presentation is embedded. This diff --git a/js/controllers/fragments.js b/js/controllers/fragments.js index 0a84530a..ec45e447 100644 --- a/js/controllers/fragments.js +++ b/js/controllers/fragments.js @@ -1,4 +1,4 @@ -import { extend, queryAll } from '../utils/util.js' +import { extend, queryAll } from '../utils/util' /** * Handles sorting and navigation of slide fragments. diff --git a/js/controllers/keyboard.js b/js/controllers/keyboard.js index 58706442..587a72ea 100644 --- a/js/controllers/keyboard.js +++ b/js/controllers/keyboard.js @@ -1,4 +1,4 @@ -import { enterFullscreen } from '../utils/util.js' +import { enterFullscreen } from '../utils/util' /** * Handles all reveal.js keyboard interactions. diff --git a/js/controllers/overview.js b/js/controllers/overview.js index 4e146b6c..e438ff0c 100644 --- a/js/controllers/overview.js +++ b/js/controllers/overview.js @@ -1,5 +1,5 @@ -import { SLIDES_SELECTOR } from '../utils/constants.js' -import { extend, queryAll, transformElement } from '../utils/util.js' +import { SLIDES_SELECTOR } from '../utils/constants' +import { extend, queryAll, transformElement } from '../utils/util' /** * Handles all logic related to the overview mode diff --git a/js/controllers/plugins.js b/js/controllers/plugins.js index 88f57bfb..7baf733d 100644 --- a/js/controllers/plugins.js +++ b/js/controllers/plugins.js @@ -1,4 +1,4 @@ -import { loadScript } from '../utils/loader.js' +import { loadScript } from '../utils/loader' /** * Manages loading and registering of reveal.js plugins. diff --git a/js/controllers/printview.js b/js/controllers/printview.js index b3354623..fcdceb20 100644 --- a/js/controllers/printview.js +++ b/js/controllers/printview.js @@ -1,5 +1,5 @@ -import { SLIDES_SELECTOR } from '../utils/constants.js' -import { queryAll, createStyleSheet } from '../utils/util.js' +import { SLIDES_SELECTOR } from '../utils/constants' +import { queryAll, createStyleSheet } from '../utils/util' /** * Setups up our presentation for printing/exporting to PDF. diff --git a/js/controllers/scrollview.js b/js/controllers/scrollview.js index 1181bb53..a50f758f 100644 --- a/js/controllers/scrollview.js +++ b/js/controllers/scrollview.js @@ -1,5 +1,5 @@ -import { HORIZONTAL_SLIDES_SELECTOR, HORIZONTAL_BACKGROUNDS_SELECTOR } from '../utils/constants.js' -import { queryAll } from '../utils/util.js' +import { HORIZONTAL_SLIDES_SELECTOR, HORIZONTAL_BACKGROUNDS_SELECTOR } from '../utils/constants' +import { queryAll } from '../utils/util' const HIDE_SCROLLBAR_TIMEOUT = 500; const MAX_PROGRESS_SPACING = 4; diff --git a/js/controllers/slidecontent.js b/js/controllers/slidecontent.js index ae2ffe8d..c0260d22 100644 --- a/js/controllers/slidecontent.js +++ b/js/controllers/slidecontent.js @@ -1,5 +1,5 @@ -import { extend, queryAll, closest, getMimeTypeFromFile, encodeRFC3986URI } from '../utils/util.js' -import { isMobile } from '../utils/device.js' +import { extend, queryAll, closest, getMimeTypeFromFile, encodeRFC3986URI } from '../utils/util' +import { isMobile } from '../utils/device' import fitty from 'fitty'; diff --git a/js/controllers/touch.js b/js/controllers/touch.js index 7078cf25..cec01324 100644 --- a/js/controllers/touch.js +++ b/js/controllers/touch.js @@ -1,5 +1,5 @@ -import { isAndroid } from '../utils/device.js' -import { matches } from '../utils/util.js' +import { isAndroid } from '../utils/device' +import { matches } from '../utils/util' const SWIPE_THRESHOLD = 40; diff --git a/js/index.ts b/js/index.ts index 6568cc85..b5906c7b 100644 --- a/js/index.ts +++ b/js/index.ts @@ -1,6 +1,6 @@ import { Config } from './config.ts'; -//@ts-ignore +// @ts-ignore import Deck, { VERSION } from './reveal.js'; /** @@ -14,8 +14,8 @@ import Deck, { VERSION } from './reveal.js'; * }); */ const Reveal: { - initialize: (options?: Config) => Promise; - [key: string]: any; + initialize: (options?: Config) => Promise; + [key: string]: any; } = Deck; /** @@ -35,13 +35,13 @@ type RevealApiFunction = (...args: any[]) => any; const enqueuedAPICalls: RevealApiFunction[] = []; Reveal.initialize = (options?: Config) => { - // Create our singleton reveal.js instance - Object.assign(Reveal, new Deck(document.querySelector('.reveal'), options)); + // Create our singleton reveal.js instance + Object.assign(Reveal, new Deck(document.querySelector('.reveal'), options)); - // Invoke any enqueued API calls - enqueuedAPICalls.map((method) => method(Reveal)); + // Invoke any enqueued API calls + enqueuedAPICalls.map((method) => method(Reveal)); - return Reveal.initialize(); + return Reveal.initialize(); }; /** @@ -51,11 +51,11 @@ Reveal.initialize = (options?: Config) => { * of them when Reveal.initialize is called. */ ['configure', 'on', 'off', 'addEventListener', 'removeEventListener', 'registerPlugin'].forEach( - (method) => { - Reveal[method] = (...args: any) => { - enqueuedAPICalls.push((deck) => deck[method].call(null, ...args)); - }; - } + (method) => { + Reveal[method] = (...args: any) => { + enqueuedAPICalls.push((deck) => deck[method].call(null, ...args)); + }; + } ); Reveal.isReady = () => false; diff --git a/js/reveal.js b/js/reveal.js index ca89a8d3..978b2932 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -1,32 +1,32 @@ -import SlideContent from './controllers/slidecontent.js' -import SlideNumber from './controllers/slidenumber.js' -import JumpToSlide from './controllers/jumptoslide.js' -import Backgrounds from './controllers/backgrounds.js' -import AutoAnimate from './controllers/autoanimate.js' -import ScrollView from './controllers/scrollview.js' -import PrintView from './controllers/printview.js' -import Fragments from './controllers/fragments.js' -import Overview from './controllers/overview.js' -import Keyboard from './controllers/keyboard.js' -import Location from './controllers/location.js' -import Controls from './controllers/controls.js' -import Progress from './controllers/progress.js' -import Pointer from './controllers/pointer.js' -import Plugins from './controllers/plugins.js' -import Overlay from './controllers/overlay.js' -import Touch from './controllers/touch.js' -import Focus from './controllers/focus.js' -import Notes from './controllers/notes.js' -import Playback from './components/playback.js' +import SlideContent from './controllers/slidecontent' +import SlideNumber from './controllers/slidenumber' +import JumpToSlide from './controllers/jumptoslide' +import Backgrounds from './controllers/backgrounds' +import AutoAnimate from './controllers/autoanimate' +import ScrollView from './controllers/scrollview' +import PrintView from './controllers/printview' +import Fragments from './controllers/fragments' +import Overview from './controllers/overview' +import Keyboard from './controllers/keyboard' +import Location from './controllers/location' +import Controls from './controllers/controls' +import Progress from './controllers/progress' +import Pointer from './controllers/pointer' +import Plugins from './controllers/plugins' +import Overlay from './controllers/overlay' +import Touch from './controllers/touch' +import Focus from './controllers/focus' +import Notes from './controllers/notes' +import Playback from './components/playback' import { defaultConfig } from './config.ts' -import * as Util from './utils/util.js' -import * as Device from './utils/device.js' +import * as Util from './utils/util' +import * as Device from './utils/device' import { SLIDES_SELECTOR, HORIZONTAL_SLIDES_SELECTOR, VERTICAL_SLIDES_SELECTOR, POST_MESSAGE_METHOD_BLACKLIST -} from './utils/constants.js' +} from './utils/constants' // The reveal.js version export const VERSION = '6.0.0-rc.2'; diff --git a/js/utils/color.js b/js/utils/color.js deleted file mode 100644 index e28a2b13..00000000 --- a/js/utils/color.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Converts various color input formats to an {r:0,g:0,b:0} object. - * - * @param {string} color The string representation of a color - * @example - * colorToRgb('#000'); - * @example - * colorToRgb('#000000'); - * @example - * colorToRgb('rgb(0,0,0)'); - * @example - * colorToRgb('rgba(0,0,0)'); - * - * @return {{r: number, g: number, b: number, [a]: number}|null} - */ -export const colorToRgb = ( color ) => { - - let hex3 = color.match( /^#([0-9a-f]{3})$/i ); - if( hex3 && hex3[1] ) { - hex3 = hex3[1]; - return { - r: parseInt( hex3.charAt( 0 ), 16 ) * 0x11, - g: parseInt( hex3.charAt( 1 ), 16 ) * 0x11, - b: parseInt( hex3.charAt( 2 ), 16 ) * 0x11 - }; - } - - let hex6 = color.match( /^#([0-9a-f]{6})$/i ); - if( hex6 && hex6[1] ) { - hex6 = hex6[1]; - return { - r: parseInt( hex6.slice( 0, 2 ), 16 ), - g: parseInt( hex6.slice( 2, 4 ), 16 ), - b: parseInt( hex6.slice( 4, 6 ), 16 ) - }; - } - - let rgb = color.match( /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i ); - if( rgb ) { - return { - r: parseInt( rgb[1], 10 ), - g: parseInt( rgb[2], 10 ), - b: parseInt( rgb[3], 10 ) - }; - } - - let rgba = color.match( /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d]+|[\d]*.[\d]+)\s*\)$/i ); - if( rgba ) { - return { - r: parseInt( rgba[1], 10 ), - g: parseInt( rgba[2], 10 ), - b: parseInt( rgba[3], 10 ), - a: parseFloat( rgba[4] ) - }; - } - - return null; - -} - -/** - * Calculates brightness on a scale of 0-255. - * - * @param {string} color See colorToRgb for supported formats. - * @see {@link colorToRgb} - */ -export const colorBrightness = ( color ) => { - - if( typeof color === 'string' ) color = colorToRgb( color ); - - if( color ) { - return ( color.r * 299 + color.g * 587 + color.b * 114 ) / 1000; - } - - return null; - -} \ No newline at end of file diff --git a/js/utils/color.ts b/js/utils/color.ts new file mode 100644 index 00000000..b9097f7a --- /dev/null +++ b/js/utils/color.ts @@ -0,0 +1,75 @@ +/** + * Converts various color input formats to an {r:0,g:0,b:0} object. + * + * @param {string} color The string representation of a color + * @example + * colorToRgb('#000'); + * @example + * colorToRgb('#000000'); + * @example + * colorToRgb('rgb(0,0,0)'); + * @example + * colorToRgb('rgba(0,0,0)'); + * + * @return {{r: number, g: number, b: number, [a]: number}|null} + */ +export const colorToRgb = (color: string) => { + let hex3 = color.match(/^#([0-9a-f]{3})$/i); + if (hex3 && hex3[1]) { + const hex3Value = hex3[1]; + return { + r: parseInt(hex3Value.charAt(0), 16) * 0x11, + g: parseInt(hex3Value.charAt(1), 16) * 0x11, + b: parseInt(hex3Value.charAt(2), 16) * 0x11, + }; + } + + let hex6 = color.match(/^#([0-9a-f]{6})$/i); + if (hex6 && hex6[1]) { + const hex6Value = hex6[1]; + return { + r: parseInt(hex6Value.slice(0, 2), 16), + g: parseInt(hex6Value.slice(2, 4), 16), + b: parseInt(hex6Value.slice(4, 6), 16), + }; + } + + let rgb = color.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i); + if (rgb) { + return { + r: parseInt(rgb[1], 10), + g: parseInt(rgb[2], 10), + b: parseInt(rgb[3], 10), + }; + } + + let rgba = color.match( + /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d]+|[\d]*.[\d]+)\s*\)$/i + ); + if (rgba) { + return { + r: parseInt(rgba[1], 10), + g: parseInt(rgba[2], 10), + b: parseInt(rgba[3], 10), + a: parseFloat(rgba[4]), + }; + } + + return null; +}; + +/** + * Calculates brightness on a scale of 0-255. + * + * @param {string} color See colorToRgb for supported formats. + * @see {@link colorToRgb} + */ +export const colorBrightness = (color: string | { r: number; g: number; b: number } | null) => { + if (typeof color === 'string') color = colorToRgb(color); + + if (color) { + return (color.r * 299 + color.g * 587 + color.b * 114) / 1000; + } + + return null; +}; diff --git a/js/utils/constants.js b/js/utils/constants.ts similarity index 64% rename from js/utils/constants.js rename to js/utils/constants.ts index 91a9f224..9c336e17 100644 --- a/js/utils/constants.js +++ b/js/utils/constants.ts @@ -1,17 +1,18 @@ - export const SLIDES_SELECTOR = '.slides section'; export const HORIZONTAL_SLIDES_SELECTOR = '.slides>section'; export const VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section'; export const HORIZONTAL_BACKGROUNDS_SELECTOR = '.backgrounds>.slide-background'; // Methods that may not be invoked via the postMessage API -export const POST_MESSAGE_METHOD_BLACKLIST = /registerPlugin|registerKeyboardShortcut|addKeyBinding|addEventListener|showPreview/; +export const POST_MESSAGE_METHOD_BLACKLIST = + /registerPlugin|registerKeyboardShortcut|addKeyBinding|addEventListener|showPreview/; // Regex for retrieving the fragment style from a class attribute -export const FRAGMENT_STYLE_REGEX = /fade-(down|up|right|left|out|in-then-out|in-then-semi-out)|semi-fade-out|current-visible|shrink|grow/; +export const FRAGMENT_STYLE_REGEX = + /fade-(down|up|right|left|out|in-then-out|in-then-semi-out)|semi-fade-out|current-visible|shrink|grow/; // Slide number formats export const SLIDE_NUMBER_FORMAT_HORIZONTAL_DOT_VERTICAL = 'h.v'; export const SLIDE_NUMBER_FORMAT_HORIZONTAL_SLASH_VERTICAL = 'h/v'; export const SLIDE_NUMBER_FORMAT_CURRENT = 'c'; -export const SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL = 'c/t'; \ No newline at end of file +export const SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL = 'c/t'; diff --git a/js/utils/device.js b/js/utils/device.js deleted file mode 100644 index f2bce203..00000000 --- a/js/utils/device.js +++ /dev/null @@ -1,8 +0,0 @@ -const UA = navigator.userAgent; - -export const isMobile = /(iphone|ipod|ipad|android)/gi.test( UA ) || - ( navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 ); // iPadOS - -export const isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA ); - -export const isAndroid = /android/gi.test( UA ); \ No newline at end of file diff --git a/js/utils/device.ts b/js/utils/device.ts new file mode 100644 index 00000000..a04b30c3 --- /dev/null +++ b/js/utils/device.ts @@ -0,0 +1,9 @@ +const UA = navigator.userAgent; + +export const isMobile = + /(iphone|ipod|ipad|android)/gi.test(UA) || + (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); // iPadOS + +export const isChrome = /chrome/i.test(UA) && !/edge/i.test(UA); + +export const isAndroid = /android/gi.test(UA); diff --git a/js/utils/loader.js b/js/utils/loader.js deleted file mode 100644 index 58d39acb..00000000 --- a/js/utils/loader.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Loads a JavaScript file from the given URL and executes it. - * - * @param {string} url Address of the .js file to load - * @param {function} callback Method to invoke when the script - * has loaded and executed - */ -export const loadScript = ( url, callback ) => { - - const script = document.createElement( 'script' ); - script.type = 'text/javascript'; - script.async = false; - script.defer = false; - script.src = url; - - if( typeof callback === 'function' ) { - - // Success callback - script.onload = script.onreadystatechange = event => { - if( event.type === 'load' || /loaded|complete/.test( script.readyState ) ) { - - // Kill event listeners - script.onload = script.onreadystatechange = script.onerror = null; - - callback(); - - } - }; - - // Error callback - script.onerror = err => { - - // Kill event listeners - script.onload = script.onreadystatechange = script.onerror = null; - - callback( new Error( 'Failed loading script: ' + script.src + '\n' + err ) ); - - }; - - } - - // Append the script at the end of - const head = document.querySelector( 'head' ); - head.insertBefore( script, head.lastChild ); - -} \ No newline at end of file diff --git a/js/utils/loader.ts b/js/utils/loader.ts new file mode 100644 index 00000000..40fcec15 --- /dev/null +++ b/js/utils/loader.ts @@ -0,0 +1,40 @@ +/** + * Loads a JavaScript file from the given URL and executes it. + * + * @param {string} url Address of the .js file to load + * @param {function} callback Method to invoke when the script + * has loaded and executed + */ +export const loadScript = (url: string, callback?: (error?: Error) => void) => { + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.async = false; + script.defer = false; + script.src = url; + + if (typeof callback === 'function') { + // Success callback + script.onload = (event: Event) => { + if (event.type === 'load') { + // Kill event listeners + script.onload = script.onerror = null; + + callback(); + } + }; + + // Error callback + script.onerror = (err: Event | string) => { + // Kill event listeners + script.onload = script.onerror = null; + + callback(new Error('Failed loading script: ' + script.src + '\n' + err)); + }; + } + + // Append the script at the end of + const head = document.querySelector('head'); + if (head) { + head.insertBefore(script, head.lastChild); + } +}; diff --git a/js/utils/util.js b/js/utils/util.js deleted file mode 100644 index a5515e80..00000000 --- a/js/utils/util.js +++ /dev/null @@ -1,313 +0,0 @@ -/** - * Extend object a with the properties of object b. - * If there's a conflict, object b takes precedence. - * - * @param {object} a - * @param {object} b - */ -export const extend = ( a, b ) => { - - for( let i in b ) { - a[ i ] = b[ i ]; - } - - return a; - -} - -/** - * querySelectorAll but returns an Array. - */ -export const queryAll = ( el, selector ) => { - - return Array.from( el.querySelectorAll( selector ) ); - -} - -/** - * classList.toggle() with cross browser support - */ -export const toggleClass = ( el, className, value ) => { - if( value ) { - el.classList.add( className ); - } - else { - el.classList.remove( className ); - } -} - -/** - * Utility for deserializing a value. - * - * @param {*} value - * @return {*} - */ -export const deserialize = ( value ) => { - - if( typeof value === 'string' ) { - if( value === 'null' ) return null; - else if( value === 'true' ) return true; - else if( value === 'false' ) return false; - else if( value.match( /^-?[\d\.]+$/ ) ) return parseFloat( value ); - } - - return value; - -} - -/** - * Measures the distance in pixels between point a - * and point b. - * - * @param {object} a point with x/y properties - * @param {object} b point with x/y properties - * - * @return {number} - */ -export const distanceBetween = ( a, b ) => { - - let dx = a.x - b.x, - dy = a.y - b.y; - - return Math.sqrt( dx*dx + dy*dy ); - -} - -/** - * Applies a CSS transform to the target element. - * - * @param {HTMLElement} element - * @param {string} transform - */ -export const transformElement = ( element, transform ) => { - - element.style.transform = transform; - -} - -/** - * Element.matches with IE support. - * - * @param {HTMLElement} target The element to match - * @param {String} selector The CSS selector to match - * the element against - * - * @return {Boolean} - */ -export const matches = ( target, selector ) => { - - let matchesMethod = target.matches || target.matchesSelector || target.msMatchesSelector; - - return !!( matchesMethod && matchesMethod.call( target, selector ) ); - -} - -/** - * Find the closest parent that matches the given - * selector. - * - * @param {HTMLElement} target The child element - * @param {String} selector The CSS selector to match - * the parents against - * - * @return {HTMLElement} The matched parent or null - * if no matching parent was found - */ -export const closest = ( target, selector ) => { - - // Native Element.closest - if( typeof target.closest === 'function' ) { - return target.closest( selector ); - } - - // Polyfill - while( target ) { - if( matches( target, selector ) ) { - return target; - } - - // Keep searching - target = target.parentNode; - } - - return null; - -} - -/** - * Handling the fullscreen functionality via the fullscreen API - * - * @see http://fullscreen.spec.whatwg.org/ - * @see https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode - */ -export const enterFullscreen = element => { - - element = element || document.documentElement; - - // Check which implementation is available - let requestMethod = element.requestFullscreen || - element.webkitRequestFullscreen || - element.webkitRequestFullScreen || - element.mozRequestFullScreen || - element.msRequestFullscreen; - - if( requestMethod ) { - requestMethod.apply( element ); - } - -} - -/** - * Creates an HTML element and returns a reference to it. - * If the element already exists the existing instance will - * be returned. - * - * @param {HTMLElement} container - * @param {string} tagname - * @param {string} classname - * @param {string} innerHTML - * - * @return {HTMLElement} - */ -export const createSingletonNode = ( container, tagname, classname, innerHTML='' ) => { - - // Find all nodes matching the description - let nodes = container.querySelectorAll( '.' + classname ); - - // Check all matches to find one which is a direct child of - // the specified container - for( let i = 0; i < nodes.length; i++ ) { - let testNode = nodes[i]; - if( testNode.parentNode === container ) { - return testNode; - } - } - - // If no node was found, create it now - let node = document.createElement( tagname ); - node.className = classname; - node.innerHTML = innerHTML; - container.appendChild( node ); - - return node; - -} - -/** - * Injects the given CSS styles into the DOM. - * - * @param {string} value - */ -export const createStyleSheet = ( value ) => { - - let tag = document.createElement( 'style' ); - tag.type = 'text/css'; - - if( value && value.length > 0 ) { - if( tag.styleSheet ) { - tag.styleSheet.cssText = value; - } - else { - tag.appendChild( document.createTextNode( value ) ); - } - } - - document.head.appendChild( tag ); - - return tag; - -} - -/** - * Returns a key:value hash of all query params. - */ -export const getQueryHash = () => { - - let query = {}; - - location.search.replace( /[A-Z0-9]+?=([\w\.%-]*)/gi, a => { - query[ a.split( '=' ).shift() ] = a.split( '=' ).pop(); - } ); - - // Basic deserialization - for( let i in query ) { - let value = query[ i ]; - - query[ i ] = deserialize( unescape( value ) ); - } - - // Do not accept new dependencies via query config to avoid - // the potential of malicious script injection - if( typeof query['dependencies'] !== 'undefined' ) delete query['dependencies']; - - return query; - -} - -/** - * Returns the remaining height within the parent of the - * target element. - * - * remaining height = [ configured parent height ] - [ current parent height ] - * - * @param {HTMLElement} element - * @param {number} [height] - */ -export const getRemainingHeight = ( element, height = 0 ) => { - - if( element ) { - let newHeight, oldHeight = element.style.height; - - // Change the .stretch element height to 0 in order find the height of all - // the other elements - element.style.height = '0px'; - - // In Overview mode, the parent (.slide) height is set of 700px. - // Restore it temporarily to its natural height. - element.parentNode.style.height = 'auto'; - - newHeight = height - element.parentNode.offsetHeight; - - // Restore the old height, just in case - element.style.height = oldHeight + 'px'; - - // Clear the parent (.slide) height. .removeProperty works in IE9+ - element.parentNode.style.removeProperty('height'); - - return newHeight; - } - - return height; - -} - -const fileExtensionToMimeMap = { - 'mp4': 'video/mp4', - 'm4a': 'video/mp4', - 'ogv': 'video/ogg', - 'mpeg': 'video/mpeg', - 'webm': 'video/webm' -} - -/** - * Guess the MIME type for common file formats. - */ -export const getMimeTypeFromFile = ( filename='' ) => { - return fileExtensionToMimeMap[filename.split('.').pop()] -} - -/** - * Encodes a string for RFC3986-compliant URL format. - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encoding_for_rfc3986 - * - * @param {string} url - */ -export const encodeRFC3986URI = ( url='' ) => { - return encodeURI(url) - .replace(/%5B/g, "[") - .replace(/%5D/g, "]") - .replace( - /[!'()*]/g, - (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}` - ); -} \ No newline at end of file diff --git a/js/utils/util.ts b/js/utils/util.ts new file mode 100644 index 00000000..e36951ca --- /dev/null +++ b/js/utils/util.ts @@ -0,0 +1,301 @@ +/** + * Extend object a with the properties of object b. + * If there's a conflict, object b takes precedence. + * + * @param {object} a + * @param {object} b + */ +export const extend = (a: Record, b: Record) => { + for (let i in b) { + a[i] = b[i]; + } + + return a; +}; + +/** + * querySelectorAll but returns an Array. + */ +export const queryAll = (el: Element | Document, selector: string): Element[] => { + return Array.from(el.querySelectorAll(selector)); +}; + +/** + * classList.toggle() with cross browser support + */ +export const toggleClass = (el: Element, className: string, value: boolean) => { + if (value) { + el.classList.add(className); + } else { + el.classList.remove(className); + } +}; + +type DeserializedValue = string | number | boolean | null; + +/** + * Utility for deserializing a value. + * + * @param {*} value + * @return {*} + */ +export const deserialize = (value: string): DeserializedValue => { + if (typeof value === 'string') { + if (value === 'null') return null; + else if (value === 'true') return true; + else if (value === 'false') return false; + else if (value.match(/^-?[\d\.]+$/)) return parseFloat(value); + } + + return value; +}; + +/** + * Measures the distance in pixels between point a + * and point b. + * + * @param {object} a point with x/y properties + * @param {object} b point with x/y properties + * + * @return {number} + */ +export const distanceBetween = ( + a: { x: number; y: number }, + b: { x: number; y: number } +): number => { + let dx = a.x - b.x, + dy = a.y - b.y; + + return Math.sqrt(dx * dx + dy * dy); +}; + +/** + * Applies a CSS transform to the target element. + * + * @param {HTMLElement} element + * @param {string} transform + */ +export const transformElement = (element: HTMLElement, transform: string) => { + element.style.transform = transform; +}; + +/** + * Element.matches with IE support. + * + * @param {HTMLElement} target The element to match + * @param {String} selector The CSS selector to match + * the element against + * + * @return {Boolean} + */ +export const matches = (target: any, selector: string): boolean => { + let matchesMethod = target.matches || target.matchesSelector || target.msMatchesSelector; + + return !!(matchesMethod && matchesMethod.call(target, selector)); +}; + +/** + * Find the closest parent that matches the given + * selector. + * + * @param {HTMLElement} target The child element + * @param {String} selector The CSS selector to match + * the parents against + * + * @return {HTMLElement} The matched parent or null + * if no matching parent was found + */ +export const closest = (target: Element | null, selector: string): Element | null => { + // Native Element.closest + if (target && typeof target.closest === 'function') { + return target.closest(selector); + } + + // Polyfill + while (target) { + if (matches(target, selector)) { + return target; + } + + // Keep searching + target = target.parentElement; + } + + return null; +}; + +/** + * Handling the fullscreen functionality via the fullscreen API + * + * @see http://fullscreen.spec.whatwg.org/ + * @see https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode + */ +export const enterFullscreen = (element?: Element) => { + element = element || document.documentElement; + + // Check which implementation is available + let requestMethod = + (element as any).requestFullscreen || + (element as any).webkitRequestFullscreen || + (element as any).webkitRequestFullScreen || + (element as any).mozRequestFullScreen || + (element as any).msRequestFullscreen; + + if (requestMethod) { + requestMethod.apply(element); + } +}; + +/** + * Creates an HTML element and returns a reference to it. + * If the element already exists the existing instance will + * be returned. + * + * @param {HTMLElement} container + * @param {string} tagname + * @param {string} classname + * @param {string} innerHTML + * + * @return {HTMLElement} + */ +export const createSingletonNode = ( + container: Element, + tagname: string, + classname: string, + innerHTML: string = '' +): Element => { + // Find all nodes matching the description + let nodes = container.querySelectorAll('.' + classname); + + // Check all matches to find one which is a direct child of + // the specified container + for (let i = 0; i < nodes.length; i++) { + let testNode = nodes[i]; + if (testNode.parentNode === container) { + return testNode; + } + } + + // If no node was found, create it now + let node = document.createElement(tagname); + node.className = classname; + node.innerHTML = innerHTML; + container.appendChild(node); + + return node; +}; + +/** + * Injects the given CSS styles into the DOM. + * + * @param {string} value + */ +export const createStyleSheet = (value: string): HTMLStyleElement => { + let tag = document.createElement('style'); + + if (value && value.length > 0) { + tag.appendChild(document.createTextNode(value)); + } + + document.head.appendChild(tag); + + return tag; +}; + +/** + * Returns a key:value hash of all query params. + */ +export const getQueryHash = (): Record => { + let query: Record = {}; + + location.search.replace(/[A-Z0-9]+?=([\w\.%-]*)/gi, (a: string) => { + const key = a.split('=').shift(); + const value = a.split('=').pop(); + if (key && value !== undefined) { + query[key] = value; + } + return a; + }); + + // Basic deserialization + for (let i in query) { + let value = query[i]; + + query[i] = deserialize(unescape(value as string)); + } + + // Do not accept new dependencies via query config to avoid + // the potential of malicious script injection + if (typeof query['dependencies'] !== 'undefined') delete query['dependencies']; + + return query; +}; + +/** + * Returns the remaining height within the parent of the + * target element. + * + * remaining height = [ configured parent height ] - [ current parent height ] + * + * @param {HTMLElement} element + * @param {number} [height] + */ +export const getRemainingHeight = (element: HTMLElement | null, height: number = 0): number => { + if (element) { + let newHeight: number, + oldHeight = element.style.height; + + // Change the .stretch element height to 0 in order find the height of all + // the other elements + element.style.height = '0px'; + + // In Overview mode, the parent (.slide) height is set of 700px. + // Restore it temporarily to its natural height. + if (element.parentElement) { + element.parentElement.style.height = 'auto'; + } + + newHeight = height - (element.parentElement?.offsetHeight || 0); + + // Restore the old height, just in case + element.style.height = oldHeight + 'px'; + + // Clear the parent (.slide) height. .removeProperty works in IE9+ + if (element.parentElement) { + element.parentElement.style.removeProperty('height'); + } + + return newHeight; + } + + return height; +}; + +const fileExtensionToMimeMap: Record = { + mp4: 'video/mp4', + m4a: 'video/mp4', + ogv: 'video/ogg', + mpeg: 'video/mpeg', + webm: 'video/webm', +}; + +/** + * Guess the MIME type for common file formats. + */ +export const getMimeTypeFromFile = (filename: string = ''): string | undefined => { + const extension = filename.split('.').pop(); + return extension ? fileExtensionToMimeMap[extension] : undefined; +}; + +/** + * Encodes a string for RFC3986-compliant URL format. + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encoding_for_rfc3986 + * + * @param {string} url + */ +export const encodeRFC3986URI = (url: string = ''): string => { + return encodeURI(url) + .replace(/%5B/g, '[') + .replace(/%5D/g, ']') + .replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`); +};