Skip to content
Snippets Groups Projects
Unverified Commit 94ebead4 authored by orestis.malaspin's avatar orestis.malaspin
Browse files

added reveal

parent 1f57a0b9
No related branches found
No related tags found
No related merge requests found
Showing
with 5034 additions and 0 deletions
// Base settings for all themes that can optionally be
// overridden by the super-theme
// Background of the presentation
$backgroundColor: #2b2b2b;
// Primary/body text
$mainFont: 'Lato', sans-serif;
$mainFontSize: 20px;
$mainColor: #eee;
// Vertical spacing between blocks of text
$blockMargin: 20px;
// Headings
$headingMargin: 0 0 $blockMargin 0;
$headingFont: 'League Gothic', Impact, sans-serif;
$headingColor: #eee;
$headingLineHeight: 1.2;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingTextShadow: none;
$headingFontWeight: normal;
$heading1TextShadow: $headingTextShadow;
$heading1Size: 3.77em;
$heading2Size: 2.11em;
$heading3Size: 1.55em;
$heading4Size: 1.00em;
$codeFont: monospace;
// Links and actions
$linkColor: #13DAEC;
$linkColorHover: lighten( $linkColor, 20% );
// Text selection
$selectionBackgroundColor: #FF5E99;
$selectionColor: #fff;
// Generates the presentation background, can be overridden
// to return a background image or gradient
@mixin bodyBackground() {
background: $backgroundColor;
}
// Base theme template for reveal.js
/*********************************************
* GLOBAL STYLES
*********************************************/
@import "./exposer";
.reveal-viewport {
@include bodyBackground();
background-color: $backgroundColor;
}
.reveal {
font-family: $mainFont;
font-size: $mainFontSize;
font-weight: normal;
color: $mainColor;
}
.reveal ::selection {
color: $selectionColor;
background: $selectionBackgroundColor;
text-shadow: none;
}
.reveal ::-moz-selection {
color: $selectionColor;
background: $selectionBackgroundColor;
text-shadow: none;
}
.reveal .slides section,
.reveal .slides section>section {
line-height: 1.3;
font-weight: inherit;
}
/*********************************************
* HEADERS
*********************************************/
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
margin: $headingMargin;
color: $headingColor;
font-family: $headingFont;
font-weight: $headingFontWeight;
line-height: $headingLineHeight;
letter-spacing: $headingLetterSpacing;
text-transform: $headingTextTransform;
text-shadow: $headingTextShadow;
word-wrap: break-word;
}
.reveal h1 {font-size: $heading1Size; }
.reveal h2 {font-size: $heading2Size; }
.reveal h3 {font-size: $heading3Size; }
.reveal h4 {font-size: $heading4Size; }
.reveal h1 {
text-shadow: $heading1TextShadow;
}
/*********************************************
* OTHER
*********************************************/
.reveal p {
margin: $blockMargin 0;
line-height: 1.3;
}
/* Remove trailing margins after titles */
.reveal h1:last-child,
.reveal h2:last-child,
.reveal h3:last-child,
.reveal h4:last-child,
.reveal h5:last-child,
.reveal h6:last-child {
margin-bottom: 0;
}
/* Ensure certain elements are never larger than the slide itself */
.reveal img,
.reveal video,
.reveal iframe {
max-width: 95%;
max-height: 95%;
}
.reveal strong,
.reveal b {
font-weight: bold;
}
.reveal em {
font-style: italic;
}
.reveal ol,
.reveal dl,
.reveal ul {
display: inline-block;
text-align: left;
margin: 0 0 0 1em;
}
.reveal ol {
list-style-type: decimal;
}
.reveal ul {
list-style-type: disc;
}
.reveal ul ul {
list-style-type: square;
}
.reveal ul ul ul {
list-style-type: circle;
}
.reveal ul ul,
.reveal ul ol,
.reveal ol ol,
.reveal ol ul {
display: block;
margin-left: 40px;
}
.reveal dt {
font-weight: bold;
}
.reveal dd {
margin-left: 40px;
}
.reveal blockquote {
display: block;
position: relative;
width: 70%;
margin: $blockMargin auto;
padding: 5px;
font-style: italic;
background: rgba(255, 255, 255, 0.05);
box-shadow: 0px 0px 2px rgba(0,0,0,0.2);
}
.reveal blockquote p:first-child,
.reveal blockquote p:last-child {
display: inline-block;
}
.reveal q {
font-style: italic;
}
.reveal pre {
display: block;
position: relative;
width: 90%;
margin: $blockMargin auto;
text-align: left;
font-size: 0.55em;
font-family: $codeFont;
line-height: 1.2em;
word-wrap: break-word;
box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15);
}
.reveal code {
font-family: $codeFont;
text-transform: none;
}
.reveal pre code {
display: block;
padding: 5px;
overflow: auto;
max-height: 400px;
word-wrap: normal;
}
.reveal table {
margin: auto;
border-collapse: collapse;
border-spacing: 0;
}
.reveal table th {
font-weight: bold;
}
.reveal table th,
.reveal table td {
text-align: left;
padding: 0.2em 0.5em 0.2em 0.5em;
border-bottom: 1px solid;
}
.reveal table th[align="center"],
.reveal table td[align="center"] {
text-align: center;
}
.reveal table th[align="right"],
.reveal table td[align="right"] {
text-align: right;
}
.reveal table tbody tr:last-child th,
.reveal table tbody tr:last-child td {
border-bottom: none;
}
.reveal sup {
vertical-align: super;
font-size: smaller;
}
.reveal sub {
vertical-align: sub;
font-size: smaller;
}
.reveal small {
display: inline-block;
font-size: 0.6em;
line-height: 1.2em;
vertical-align: top;
}
.reveal small * {
vertical-align: top;
}
.reveal img {
margin: $blockMargin 0;
}
/*********************************************
* LINKS
*********************************************/
.reveal a {
color: $linkColor;
text-decoration: none;
transition: color .15s ease;
}
.reveal a:hover {
color: $linkColorHover;
text-shadow: none;
border: none;
}
.reveal .roll span:after {
color: #fff;
background: darken( $linkColor, 15% );
}
/*********************************************
* Frame helper
*********************************************/
.reveal .r-frame {
border: 4px solid $mainColor;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
}
.reveal a .r-frame {
transition: all .15s linear;
}
.reveal a:hover .r-frame {
border-color: $linkColor;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55);
}
/*********************************************
* NAVIGATION CONTROLS
*********************************************/
.reveal .controls {
color: $linkColor;
}
/*********************************************
* PROGRESS BAR
*********************************************/
.reveal .progress {
background: rgba(0,0,0,0.2);
color: $linkColor;
}
/*********************************************
* PRINT BACKGROUND
*********************************************/
@media print {
.backgrounds {
background-color: $backgroundColor;
}
}
/**
* UI component that lets the use control auto-slide
* playback via play/pause.
*/
export default class Playback {
/**
* @param {HTMLElement} container The component will append
* itself to this
* @param {function} progressCheck A method which will be
* called frequently to get the current playback progress on
* a range of 0-1
*/
constructor( container, progressCheck ) {
// Cosmetics
this.diameter = 100;
this.diameter2 = this.diameter/2;
this.thickness = 6;
// Flags if we are currently playing
this.playing = false;
// Current progress on a 0-1 range
this.progress = 0;
// Used to loop the animation smoothly
this.progressOffset = 1;
this.container = container;
this.progressCheck = progressCheck;
this.canvas = document.createElement( 'canvas' );
this.canvas.className = 'playback';
this.canvas.width = this.diameter;
this.canvas.height = this.diameter;
this.canvas.style.width = this.diameter2 + 'px';
this.canvas.style.height = this.diameter2 + 'px';
this.context = this.canvas.getContext( '2d' );
this.container.appendChild( this.canvas );
this.render();
}
setPlaying( value ) {
const wasPlaying = this.playing;
this.playing = value;
// Start repainting if we weren't already
if( !wasPlaying && this.playing ) {
this.animate();
}
else {
this.render();
}
}
animate() {
const progressBefore = this.progress;
this.progress = this.progressCheck();
// When we loop, offset the progress so that it eases
// smoothly rather than immediately resetting
if( progressBefore > 0.8 && this.progress < 0.2 ) {
this.progressOffset = this.progress;
}
this.render();
if( this.playing ) {
requestAnimationFrame( this.animate.bind( this ) );
}
}
/**
* Renders the current progress and playback state.
*/
render() {
let progress = this.playing ? this.progress : 0,
radius = ( this.diameter2 ) - this.thickness,
x = this.diameter2,
y = this.diameter2,
iconSize = 28;
// Ease towards 1
this.progressOffset += ( 1 - this.progressOffset ) * 0.1;
const endAngle = ( - Math.PI / 2 ) + ( progress * ( Math.PI * 2 ) );
const startAngle = ( - Math.PI / 2 ) + ( this.progressOffset * ( Math.PI * 2 ) );
this.context.save();
this.context.clearRect( 0, 0, this.diameter, this.diameter );
// Solid background color
this.context.beginPath();
this.context.arc( x, y, radius + 4, 0, Math.PI * 2, false );
this.context.fillStyle = 'rgba( 0, 0, 0, 0.4 )';
this.context.fill();
// Draw progress track
this.context.beginPath();
this.context.arc( x, y, radius, 0, Math.PI * 2, false );
this.context.lineWidth = this.thickness;
this.context.strokeStyle = 'rgba( 255, 255, 255, 0.2 )';
this.context.stroke();
if( this.playing ) {
// Draw progress on top of track
this.context.beginPath();
this.context.arc( x, y, radius, startAngle, endAngle, false );
this.context.lineWidth = this.thickness;
this.context.strokeStyle = '#fff';
this.context.stroke();
}
this.context.translate( x - ( iconSize / 2 ), y - ( iconSize / 2 ) );
// Draw play/pause icons
if( this.playing ) {
this.context.fillStyle = '#fff';
this.context.fillRect( 0, 0, iconSize / 2 - 4, iconSize );
this.context.fillRect( iconSize / 2 + 4, 0, iconSize / 2 - 4, iconSize );
}
else {
this.context.beginPath();
this.context.translate( 4, 0 );
this.context.moveTo( 0, 0 );
this.context.lineTo( iconSize - 4, iconSize / 2 );
this.context.lineTo( 0, iconSize );
this.context.fillStyle = '#fff';
this.context.fill();
}
this.context.restore();
}
on( type, listener ) {
this.canvas.addEventListener( type, listener, false );
}
off( type, listener ) {
this.canvas.removeEventListener( type, listener, false );
}
destroy() {
this.playing = false;
if( this.canvas.parentNode ) {
this.container.removeChild( this.canvas );
}
}
}
\ No newline at end of file
/**
* The default reveal.js config object.
*/
export default {
// The "normal" size of the presentation, aspect ratio will be preserved
// when the presentation is scaled to fit different resolutions
width: 960,
height: 700,
// Factor of the display size that should remain empty around the content
margin: 0.04,
// Bounds for smallest/largest possible scale to apply to content
minScale: 0.2,
maxScale: 2.0,
// Display presentation control arrows
controls: true,
// Help the user learn the controls by providing hints, for example by
// bouncing the down arrow when they first encounter a vertical slide
controlsTutorial: true,
// Determines where controls appear, "edges" or "bottom-right"
controlsLayout: 'bottom-right',
// Visibility rule for backwards navigation arrows; "faded", "hidden"
// or "visible"
controlsBackArrows: 'faded',
// Display a presentation progress bar
progress: true,
// Display the page number of the current slide
// - true: Show slide number
// - false: Hide slide number
//
// Can optionally be set as a string that specifies the number formatting:
// - "h.v": Horizontal . vertical slide number (default)
// - "h/v": Horizontal / vertical slide number
// - "c": Flattened slide number
// - "c/t": Flattened slide number / total slides
//
// Alternatively, you can provide a function that returns the slide
// number for the current slide. The function should take in a slide
// object and return an array with one string [slideNumber] or
// three strings [n1,delimiter,n2]. See #formatSlideNumber().
slideNumber: false,
// Can be used to limit the contexts in which the slide number appears
// - "all": Always show the slide number
// - "print": Only when printing to PDF
// - "speaker": Only in the speaker view
showSlideNumber: 'all',
// Use 1 based indexing for # links to match slide number (default is zero
// based)
hashOneBasedIndex: false,
// Add the current slide number to the URL hash so that reloading the
// page/copying the URL will return you to the same slide
hash: false,
// Flags if we should monitor the hash and change slides accordingly
respondToHashChanges: true,
// Push each slide change to the browser history. Implies `hash: true`
history: false,
// Enable keyboard shortcuts for navigation
keyboard: true,
// Optional function that blocks keyboard events when retuning false
//
// If you set this to 'foucsed', we will only capture keyboard events
// for embdedded decks when they are in focus
keyboardCondition: null,
// Disables the default reveal.js slide layout (scaling and centering)
// so that you can use custom CSS layout
disableLayout: false,
// Enable the slide overview mode
overview: true,
// Vertical centering of slides
center: true,
// Enables touch navigation on devices with touch input
touch: true,
// Loop the presentation
loop: false,
// Change the presentation direction to be RTL
rtl: false,
// Changes the behavior of our navigation directions.
//
// "default"
// Left/right arrow keys step between horizontal slides, up/down
// arrow keys step between vertical slides. Space key steps through
// all slides (both horizontal and vertical).
//
// "linear"
// Removes the up/down arrows. Left/right arrows step through all
// slides (both horizontal and vertical).
//
// "grid"
// When this is enabled, stepping left/right from a vertical stack
// to an adjacent vertical stack will land you at the same vertical
// index.
//
// Consider a deck with six slides ordered in two vertical stacks:
// 1.1 2.1
// 1.2 2.2
// 1.3 2.3
//
// If you're on slide 1.3 and navigate right, you will normally move
// from 1.3 -> 2.1. If "grid" is used, the same navigation takes you
// from 1.3 -> 2.3.
navigationMode: 'default',
// Randomizes the order of slides each time the presentation loads
shuffle: false,
// Turns fragments on and off globally
fragments: true,
// Flags whether to include the current fragment in the URL,
// so that reloading brings you to the same fragment position
fragmentInURL: true,
// Flags if the presentation is running in an embedded mode,
// i.e. contained within a limited portion of the screen
embedded: false,
// Flags if we should show a help overlay when the question-mark
// key is pressed
help: true,
// Flags if it should be possible to pause the presentation (blackout)
pause: true,
// Flags if speaker notes should be visible to all viewers
showNotes: false,
// Flags if slides with data-visibility="hidden" should be kep visible
showHiddenSlides: false,
// Global override for autolaying embedded media (video/audio/iframe)
// - null: Media will only autoplay if data-autoplay is present
// - true: All media will autoplay, regardless of individual setting
// - false: No media will autoplay, regardless of individual setting
autoPlayMedia: null,
// Global override for preloading lazy-loaded iframes
// - null: Iframes with data-src AND data-preload will be loaded when within
// the viewDistance, iframes with only data-src will be loaded when visible
// - true: All iframes with data-src will be loaded when within the viewDistance
// - false: All iframes with data-src will be loaded only when visible
preloadIframes: null,
// Can be used to globally disable auto-animation
autoAnimate: true,
// Optionally provide a custom element matcher that will be
// used to dictate which elements we can animate between.
autoAnimateMatcher: null,
// Default settings for our auto-animate transitions, can be
// overridden per-slide or per-element via data arguments
autoAnimateEasing: 'ease',
autoAnimateDuration: 1.0,
autoAnimateUnmatched: true,
// CSS properties that can be auto-animated. Position & scale
// is matched separately so there's no need to include styles
// like top/right/bottom/left, width/height or margin.
autoAnimateStyles: [
'opacity',
'color',
'background-color',
'padding',
'font-size',
'line-height',
'letter-spacing',
'border-width',
'border-color',
'border-radius',
'outline',
'outline-offset'
],
// Controls automatic progression to the next slide
// - 0: Auto-sliding only happens if the data-autoslide HTML attribute
// is present on the current slide or fragment
// - 1+: All slides will progress automatically at the given interval
// - false: No auto-sliding, even if data-autoslide is present
autoSlide: 0,
// Stop auto-sliding after user input
autoSlideStoppable: true,
// Use this method for navigation when auto-sliding (defaults to navigateNext)
autoSlideMethod: null,
// Specify the average time in seconds that you think you will spend
// presenting each slide. This is used to show a pacing timer in the
// speaker view
defaultTiming: null,
// Enable slide navigation via mouse wheel
mouseWheel: false,
// Opens links in an iframe preview overlay
// Add `data-preview-link` and `data-preview-link="false"` to customise each link
// individually
previewLinks: false,
// Exposes the reveal.js API through window.postMessage
postMessage: true,
// Dispatches all reveal.js events to the parent window through postMessage
postMessageEvents: false,
// Focuses body when page changes visibility to ensure keyboard shortcuts work
focusBodyOnPageVisibilityChange: true,
// Transition style
transition: 'slide', // none/fade/slide/convex/concave/zoom
// Transition speed
transitionSpeed: 'default', // default/fast/slow
// Transition style for full page slide backgrounds
backgroundTransition: 'fade', // none/fade/slide/convex/concave/zoom
// Parallax background image
parallaxBackgroundImage: '', // CSS syntax, e.g. "a.jpg"
// Parallax background size
parallaxBackgroundSize: '', // CSS syntax, e.g. "3000px 2000px"
// Parallax background repeat
parallaxBackgroundRepeat: '', // repeat/repeat-x/repeat-y/no-repeat/initial/inherit
// Parallax background position
parallaxBackgroundPosition: '', // CSS syntax, e.g. "top left"
// Amount of pixels to move the parallax background per slide step
parallaxBackgroundHorizontal: null,
parallaxBackgroundVertical: null,
// The maximum number of pages a single slide can expand onto when printing
// to PDF, unlimited by default
pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY,
// Prints each fragment on a separate slide
pdfSeparateFragments: true,
// Offset used to reduce the height of content within exported PDF pages.
// This exists to account for environment differences based on how you
// print to PDF. CLI printing options, like phantomjs and wkpdf, can end
// on precisely the total height of the document whereas in-browser
// printing has to end one pixel before.
pdfPageHeightOffset: -1,
// Number of slides away from the current that are visible
viewDistance: 3,
// Number of slides away from the current that are visible on mobile
// devices. It is advisable to set this to a lower number than
// viewDistance in order to save resources.
mobileViewDistance: 2,
// The display mode that will be used to show slides
display: 'block',
// Hide cursor if inactive
hideInactiveCursor: true,
// Time before the cursor is hidden (in ms)
hideCursorTime: 5000,
// Script dependencies to load
dependencies: [],
// Plugin objects to register and use for this presentation
plugins: []
}
\ No newline at end of file
This diff is collapsed.
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() {
let printMode = this.Reveal.isPrintingPDF();
// 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 ) {
let element = slide.slideBackgroundElement,
contentElement = slide.slideBackgroundContentElement;
// 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 = '';
let 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' ),
backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
backgroundPosition: slide.getAttribute( 'data-background-position' ),
backgroundTransition: slide.getAttribute( 'data-background-transition' ),
backgroundOpacity: slide.getAttribute( 'data-background-opacity' )
};
if( data.background ) {
// Auto-wrap image urls in url(...)
if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)([?#\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.backgroundImage || data.backgroundVideo || data.backgroundIframe ) {
element.setAttribute( 'data-background-hash', data.background +
data.backgroundSize +
data.backgroundImage +
data.backgroundVideo +
data.backgroundIframe +
data.backgroundColor +
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.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
if( slide.hasAttribute( 'data-preload' ) ) 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, check the computed background
if( !contrastColor ) {
let computedBackgroundStyle = window.getComputedStyle( element );
if( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) {
contrastColor = computedBackgroundStyle.backgroundColor;
}
}
if( contrastColor ) {
let 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';
}
}
}
\ No newline at end of file
This diff is collapsed.
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;
}
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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* Handles the showing and
*/
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. As an <aside class="notes"> inside of the slide
*
* @param {HTMLElement} [slide=currentSlide]
* @return {(string|null)}
*/
getSlideNotes( slide = this.Reveal.getCurrentSlide() ) {
// Notes can be specified via the data-notes attribute...
if( slide.hasAttribute( 'data-notes' ) ) {
return slide.getAttribute( 'data-notes' );
}
// ... or using an <aside class="notes"> element
let notesElement = slide.querySelector( 'aside.notes' );
if( notesElement ) {
return notesElement.innerHTML;
}
return null;
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment