From 8a1b730343f259b9a6f5d07416af69a9c2ffa703 Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Wed, 7 Sep 2016 10:22:04 -0700 Subject: [PATCH] Update to latest exerslide version --- css/a11y.css | 53 ++------------ css/navigationButtons.css | 17 ----- css/style.css | 134 ++++++++++++++++++++++------------ css/taop.css | 22 ++++-- css/toc.css | 51 ------------- exerslide.config.js | 2 +- js/MasterLayout.js | 47 ++++-------- js/SlideLayout.js | 31 ++++++++ js/analytics.js | 8 ++ js/app.js | 4 - js/components/TOC.js | 118 ++++++++++++++++-------------- js/components/Toolbar.js | 74 ++++++++++--------- js/components/css/toc.css | 84 +++++++++++---------- js/components/css/toolbar.css | 26 ++++--- js/keyMap.js | 28 ------- js/presentation.js | 86 +++++++++++++++++----- js/scriptHelper.js | 26 ++++--- layouts/HTMLExercise.js | 21 +++--- layouts/css/Center.css | 8 -- layouts/css/TwoColumn.css | 19 ----- package.json | 16 ++-- references.yml | 7 ++ statics/index.html | 2 +- webpack.config.js | 14 +++- 24 files changed, 451 insertions(+), 447 deletions(-) delete mode 100755 css/navigationButtons.css delete mode 100755 css/toc.css create mode 100644 js/SlideLayout.js create mode 100644 js/analytics.js delete mode 100755 js/app.js delete mode 100755 js/keyMap.js delete mode 100755 layouts/css/Center.css delete mode 100755 layouts/css/TwoColumn.css create mode 100644 references.yml diff --git a/css/a11y.css b/css/a11y.css index f7f6654..4749499 100755 --- a/css/a11y.css +++ b/css/a11y.css @@ -4,11 +4,7 @@ .htmlExercise > .example > .editorWithPreview { border: 1px solid #DDD; -} - -.htmlExercise > .example > .editorWithPreview > * { - display: inline-block; - vertical-align: top; + display: flex; } .editorWithPreview > .preview, @@ -22,17 +18,19 @@ } .editorWithPreview > .editor { - width: 70%; font-size: 0.8em; + max-width: 70%; } .editorWithPreview > .preview { - width: 30%; - padding-left: 20px; - padding-top: 10px; + padding: 10px; overflow: auto; } +.CodeMirror { + overflow: hidden; +} + .htmlExercise > .example > .verify { margin-top: 10px; } @@ -51,40 +49,3 @@ kbd { line-height: 1.4; white-space: nowrap; } - -.popupMenuWidget { - padding: 1em; - position: relative; -} - -.popupMenuWidget [role="button"] { - border: 1px solid black; - border-radius: 3px; - display: inline-block; - padding: 1px 3px; - position: relative; - z-index: 2; -} - -.popupMenuWidget [role="button"]:hover, -.popupMenuWidget [role="button"]:focus { - text-decoration: none; -} - -.popupMenuWidget [role="menu"] { - border: 1px solid black; - display: none; - position: relative; - top: -1px; - z-index: 1; -} - -.popupMenuWidget [role="menu"] > a { - display: block; - padding: 0px 3px; -} - -.popupMenuWidget [role="menuitem"]:focus { - background-color: #428bca; - color: white; -} diff --git a/css/navigationButtons.css b/css/navigationButtons.css deleted file mode 100755 index 4c71e35..0000000 --- a/css/navigationButtons.css +++ /dev/null @@ -1,17 +0,0 @@ -#navigation-buttons { - text-align: right; - padding-right: 10px; - padding-bottom: 10px; - width: 100%; - max-width: 940px; -} - -#navigation-buttons button { - background-color: transparent; - border: none; - font-size: 1.5em; -} - -#navigation-buttons button[disabled] { - visibility: hidden; -} diff --git a/css/style.css b/css/style.css index a94247b..746ca14 100644 --- a/css/style.css +++ b/css/style.css @@ -17,13 +17,24 @@ * so that it is easy to overwrite them. */ +html, body { + /** + * Disables inertia effects + */ + height: 100%; + overflow: hidden; + font-family: Helvetica Neue,Helvetica,Roboto,Arial,sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + body { color: #333; margin: 0; padding: 0; } -#loader { +#exerslide-loader { align-items: center; display: flex; font-size: 4em; @@ -31,10 +42,11 @@ body { justify-content: center; } -#page { +#exerslide-page { bottom: 0; display: flex; left: 0; + line-height: 1; position: absolute; right: 0; top: 0; @@ -59,100 +71,126 @@ body { /* CODE */ -pre > code { +#exerslide-slide code, +#exerslide-slide p > code { background: #f9f9f9; - display: block; - font-size: 0.9em; - overflow-x: auto; - padding: 1rem; } -pre { - margin-bottom: 1.5rem; +#exerslide-slide pre + :not(hr) { + margin-top: 1rem; +} + +#exerslide-slide pre > code { + display: block; + font-size: 0.9rem; + overflow-x: auto; + padding: 0.5rem; } /* MAIN CONTENT */ -#slide { +#exerslide-slide { align-items: center; + box-sizing: border-box; display: flex; flex-direction: column; flex: 2; overflow-y: auto; - padding: 1.5em; + padding: 1rem; position: relative; width: 100%; } -#slide-content { - width: 100%; +#exerslide-slide > * { + display: flex; + flex: 1; + flex-direction: column; + line-height: 1.6; /** * This is the default max width of the slide content. However, since * exerslide allows the content width to be configured via slides, this is * not going to have any effect, unless auto-scaling is disabled completely * (via scale: false in the meta data section of the first slide) + * + * We cannot just use `width: 45em` because we want the slide to be responsive + * when the viewport shrinks. */ max-width: 45em; - flex: 1; - flex-direction: column; - display: flex; + /** + * This ensures that slides with little content (i.e. without a full line of + * content) are still positioned correclty. + */ + width: 100%; +} + + +#exerslide-slide h1, +#exerslide-slide h2, +#exerslide-slide h3, +#exerslide-slide h4 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; } -#slide h1, -#slide-title { +#exerslide-slide h1, +#exerslide-slide-title { + margin-top: 0; flex-shrink: 0; - margin-bottom: 1rem; text-align: center; } -#slide-title:focus { +#exerslide-slide h1:focus, +#exerslide-slide-title:focus { outline: none; } -/* This ensures that embedded images are scaled down to the width of the main - * column. - */ -#slide img { - max-width: 100%; +#exerslide-slide h1 { + font-size: 1.8rem; } -/* DEBUG information */ +#exerslide-slide h2 { + font-size: 1.4rem; +} -.__exerslide__file_path { - background-color: #EEE; - line-height: 1em; - padding: 0.5em; - text-align: center; - width: 100%; +#exerslide-slide h3 { + font-size: 1.2rem; +} + +#exerslide-slide h4 { + font-size: 1.1rem; +} + +#exerslide-slide h2 + p, +#exerslide-slide h3 + p, +#exerslide-slide h4 + p { + margin-top: 0.3rem; +} + +/** + * Responsive images. + */ +#exerslide-slide img { + max-width: 100%; } /* MOBILE */ @media(max-width: 768px) { + html, body { + overflow: auto; + } + /* * Makes navigation bar move to the end of the content instead of sticking to * the bottom of the screen */ - #page { + #exerslide-page { bottom: initial; + min-height: 100vh; } /* Makes the page look better when the menu is TOC is expanded */ - #main { + #exerslide-main { overflow-x: hidden; } } - -@media screen and (min-width: 40em) { - #slide h1 { - font-size: 2.2em; - } - - #slide h2 { - font-size: 1.8em; - } - - #slide h3 { - font-size: 1.4em; - } -} diff --git a/css/taop.css b/css/taop.css index 0e31c35..30603b2 100644 --- a/css/taop.css +++ b/css/taop.css @@ -7,7 +7,8 @@ width: 1px; } -#toolbar { +.exerslide-toolbar-text, +.exerslide-toolbar-button { color: #888; } @@ -16,7 +17,8 @@ html .editorWithPreview input[type=number], html .editorWithPreview textarea { display: inline-block;; box-sizing: border-box; - width: auto;; + width: initial; + max-width: 100%; height: auto; padding: 1px; border: 1px inset; @@ -39,22 +41,30 @@ html .editorWithPreview button { line-height: inherit; } -#slide h2 { +#exerslide-slide { + position: initial; +} + +#exerslide-slide { + padding-top: 0; +} + +#exerslide-slide h2 { font-size: 1.3em; margin: 1.1em 0 0.8em 0; font-weight: bold; } -#slide .previewHeading { +#exerslide-slide .previewHeading { margin: 0 0 1.1em; color: grey; } -#slide h3 { +#exerslide-slide h3 { font-size: 1.1em; } @media screen and (min-width: 40em) { - #slide h1 { + #exerslide-slide h1 { font-size: 1.8em; font-weight: bold; } diff --git a/css/toc.css b/css/toc.css deleted file mode 100755 index ffbf78d..0000000 --- a/css/toc.css +++ /dev/null @@ -1,51 +0,0 @@ -#toc { - background-color: #EEE; - border-right: 1px solid #AAA; - font-size: 110%; - font-weight: 100; - max-width: 300px; - min-width: 300px; - overflow-y: auto; -} - -#toc > ul { - padding-left: 10px; - padding-top: 10px; -} - -#toc > h2 { - display: none; -} - -#toc li { - list-style: none; -} - -#toc .chapter { - margin-top: 15px; -} - -#toc .chapter > .title { - font-size: 1.08em; -} -#toc .chapter.active > .title { - font-weight: bold; -} - -#toc .slide { - padding-bottom: 5px; -} - -#toc .slides { - padding-left: 15px; -} - -#toc .slide.active { - font-weight: bold; -} - -#toc .slide > a:active, -#toc .slide > a:focus { - color: #428bca; - text-decoration: none; -} diff --git a/exerslide.config.js b/exerslide.config.js index 0bb0b89..1c9c369 100644 --- a/exerslide.config.js +++ b/exerslide.config.js @@ -49,11 +49,11 @@ module.exports = { * A list of module names (exerslide-plugin-* can be omitted) or paths. */ plugins: [ + 'bulletlist-layout', 'center-layout', 'column-layout', 'html-converter', 'markdown-converter', - 'shared-urls', ], /** Advanced configuration options **/ diff --git a/js/MasterLayout.js b/js/MasterLayout.js index 11996d9..b5bd49a 100644 --- a/js/MasterLayout.js +++ b/js/MasterLayout.js @@ -6,6 +6,7 @@ * the root directory of this source tree. */ +import ExtensionPoint from 'exerslide/components/ExtensionPoint'; import React from 'react'; import TOC from './components/TOC'; import Toolbar from './components/Toolbar'; @@ -32,48 +33,30 @@ import Toolbar from './components/Toolbar'; * +----------------------------------------+ * */ -export default function MasterLayout(props) { - const slide = props.slides[props.slideIndex]; - const {className, children, ...restProps} = props; +export default function MasterLayout({className, children}) { return ( -
- -
- {slide.__path__ ? // for debugging -
- File path: {slide.__path__} -
: - null - } - Teach Access Bridge - {children} - -
+
+ + +
+ Teach Access Bridge + {children} + +
+
); } MasterLayout.propTypes = { /** - * The index of the current slide - */ - slideIndex: React.PropTypes.number, - - /** - * All slides + * CSS class names to add to the page. */ - slides: React.PropTypes.array, + className: React.PropTypes.string, /** - * CSS class names to add to the page. + * The rendered slide is passed as child to the master layout. */ - className: React.PropTypes.string, + children: React.PropTypes.node, }; diff --git a/js/SlideLayout.js b/js/SlideLayout.js new file mode 100644 index 0000000..7632f7e --- /dev/null +++ b/js/SlideLayout.js @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ + +import ExtensionPoint from 'exerslide/components/ExtensionPoint'; +import React from 'react'; + +/** + * The base layout for every slide. This allows you do add additional + * content to all slides before or after the content. + */ +export default function SlideLayout({children}) { + return ( + +
+ {children} +
+
+ ); +} + +SlideLayout.propTypes = { + /** + * The current slide content and header are passed in as children by exerslide + */ + children: React.PropTypes.node, +}; diff --git a/js/analytics.js b/js/analytics.js new file mode 100644 index 0000000..78cdfe0 --- /dev/null +++ b/js/analytics.js @@ -0,0 +1,8 @@ +export default function(exerslide) { + /* global ga */ + exerslide.subscribe('SLIDE.DID_MOUNT', ({slide}) => { + ga('send', 'pageview', { + 'page': location.pathname + slide.url, + }); + }); +}; diff --git a/js/app.js b/js/app.js deleted file mode 100755 index e76258b..0000000 --- a/js/app.js +++ /dev/null @@ -1,4 +0,0 @@ -import * as config from './config'; -import presentation from 'exerslide/js/presentation'; - -presentation.init(config); diff --git a/js/components/TOC.js b/js/components/TOC.js index 17199dd..d990259 100644 --- a/js/components/TOC.js +++ b/js/components/TOC.js @@ -7,10 +7,8 @@ */ import React from 'react'; -import {groupByChapter} from 'exerslide/js/chapterHelper'; -import {IS_MOBILE} from 'exerslide/js/deviceHelper'; -import {getOptions} from 'exerslide/js/optionHelper'; -import {getSlideURL} from 'exerslide/js/url'; +import * as exerslide from 'exerslide/browser'; +const {groupByChapter, IS_MOBILE} = exerslide; import './css/toc.css'; @@ -32,27 +30,28 @@ class Entry extends React.Component { render() { const {slideIndex, slides, active} = this.props; const slide = slides[slideIndex]; - const slideOptions = getOptions(slides, slideIndex); - const classes = 'slide' + (active ? ' active' : ''); - const Layout = slide.layout; - const layoutClasses = - Layout && Layout.getClassNames && Layout.getClassNames(slideIndex); + const slideOptions = slide.options; + let classes = ['exerslide-toc-entry']; + const layout = slide.layout; + if (layout && layout.getClassNames) { + classes = classes.concat(layout.getClassNames(slideIndex, exerslide)); + } const title = slideOptions.toc || slideOptions.title || `Slide ${slideIndex + 1}`; const props = {}; if (active) { + classes.push('active'); props['aria-current'] = 'page'; } return ( -
  • +
  • + href={slide.url}> {title}
  • @@ -71,34 +70,34 @@ Entry.propTypes = { */ export default class TOC extends React.Component { - constructor(props) { - super(props); - const slideOptions = getOptions(props.slides, props.slideIndex); + constructor(props, context) { + super(props, context); + const slideOptions = context.slide.options; let collapsed = false; if (props.togglable) { // On mobile devices we collapse the TOC by default if (IS_MOBILE) { collapsed = true; - } else if (slideOptions.hasOwnProperty('hidetoc')) { - collapsed = slideOptions.hidetoc; + } else if (slideOptions.hasOwnProperty('hideTOC')) { + collapsed = slideOptions.hideTOC; } } this.state = { - groupedSlides: groupByChapter(props.slides), + groupedSlides: groupByChapter(context.slides), collapsed, explicitlyToggled: false, }; this._onToggle = this._onToggle.bind(this); } - componentWillReceiveProps(nextProps) { - if (nextProps.slides !== this.props.slides) { - this.setState({groupedSlides: groupByChapter(nextProps.slides)}); + componentWillReceiveProps(nextProps, nextContext) { + if (nextContext.slides !== this.context.slides) { + this.setState({groupedSlides: groupByChapter(nextContext.slides)}); } - if (nextProps.slideIndex !== this.props.slideIndex) { - const slideOptions = getOptions(nextProps.slides, nextProps.slideIndex); + if (nextContext.slide !== this.context.slide) { + const slideOptions = nextContext.slide.options; if (!this.state.explicitlyToggled) { - let collapsed = IS_MOBILE ? true : Boolean(slideOptions.hidetoc); + let collapsed = IS_MOBILE ? true : Boolean(slideOptions.hideTOC); this.setState( { collapsed, @@ -121,29 +120,30 @@ export default class TOC extends React.Component { render() { let slideIndex = 0; - const {slides, togglable} = this.props; + const {togglable} = this.props; + const {slides} = this.context; const {collapsed} = this.state; const chapters = this.state.groupedSlides.map(chapter => { let entry; if (Array.isArray(chapter)) { - const isActive = this.props.slideIndex >= slideIndex && - this.props.slideIndex < slideIndex + chapter.length; + const isActive = this.context.slideIndex >= slideIndex && + this.context.slideIndex < slideIndex + chapter.length; entry = chapter.map((slide, index) => ); entry =
  • -

    + className={'exerslide-toc-chapter' + (isActive ? ' active' : '')}> +

    {chapter[0].options.chapter}

    -
      {entry}
    +
      {entry}
  • ; slideIndex += chapter.length; } else { @@ -152,39 +152,42 @@ export default class TOC extends React.Component { key={slideIndex} slideIndex={slideIndex} slides={slides} - active={this.props.slideIndex === slideIndex} + active={this.context.slideIndex === slideIndex} />; slideIndex += 1; } return entry; }); + const icon = + ; + return ( @@ -194,24 +197,31 @@ export default class TOC extends React.Component { TOC.propTypes = { /** - * Index of the currently shown slide. + * Whether to show a toggle button or not. */ - slideIndex: React.PropTypes.number, + togglable: React.PropTypes.bool, /** - * All slides. + * Callback called when TOC is shown or hidden. */ - slides: React.PropTypes.array, + onToggle: React.PropTypes.func, +}; +TOC.contextTypes = { /** - * Whether to show a toggle button or not. + * Current slide. */ - togglable: React.PropTypes.bool, + slide: React.PropTypes.object, /** - * Callback called when TOC is shown or hidden. + * Index of the currently shown slide. */ - onToggle: React.PropTypes.func, + slideIndex: React.PropTypes.number, + + /** + * All slides. + */ + slides: React.PropTypes.array, }; TOC.defaultProps = { diff --git a/js/components/Toolbar.js b/js/components/Toolbar.js index 15cd3dc..69fb9e6 100644 --- a/js/components/Toolbar.js +++ b/js/components/Toolbar.js @@ -7,8 +7,8 @@ */ import React from 'react'; -import {nextSlide, previousSlide} from 'exerslide/js/navigation'; -import {getContentWidthStyle} from 'exerslide/js/layoutHelper'; +import ExtensionPoint from 'exerslide/components/ExtensionPoint'; +import {forward, back} from 'exerslide/browser'; import './css/toolbar.css'; @@ -16,47 +16,55 @@ import './css/toolbar.css'; * This components generates a previous and next buttons (rendered as arrows, * using Font Awesome) to navigate the presentation. */ -export default function Toolbar(props) { - const {slideIndex} = props; +export default function Toolbar({className}, {slideIndex, slides}) { + const numberOfSlides = slides.length; + return ( - + +
    + + + {' ' + (slideIndex + 1) + '/' + numberOfSlides + ' '} + + +
    +
    ); } Toolbar.propTypes = { + className: React.PropTypes.string, +}; + +Toolbar.contextTypes = { /** * This index of the current slide. */ slideIndex: React.PropTypes.number.isRequired, + /** * Number of slides. */ - numberOfSlides: React.PropTypes.number.isRequired, + slides: React.PropTypes.arrayOf(React.PropTypes.object).isRequired, }; - diff --git a/js/components/css/toc.css b/js/components/css/toc.css index 65837b7..29bf1b1 100644 --- a/js/components/css/toc.css +++ b/js/components/css/toc.css @@ -6,7 +6,7 @@ * the root directory of this source tree. */ -#toc { +.exerslide-toc-container { background-color: #F4F4F4; border-right: 1px solid #CCC; display: flex; @@ -15,7 +15,7 @@ min-width: 20em; } -#toc.collapsed { +.exerslide-toc-container.collapsed { background-color: inherit; border-right: none; min-width: 0; @@ -23,83 +23,93 @@ z-index: 100; } -#toc ol { +ol.exerslide-toc-entries, +ol#exerslide-toc-list { + list-style: none; + counter-reset: item; + overflow-y: auto; margin: 0; } -#toc > h2, -#toc.collapsed > #toc-list { + +ol#exerslide-toc-list { + padding-left: 1em; + padding-right: 1em; +} + +ol.exerslide-toc-entries { + padding-left: 0; +} + +ol#exerslide-toc-list > * { + margin-bottom: 1em; +} + +#exerslide-toc-title, +.exerslide-toc-container.collapsed > #exerslide-toc-list { display: none; } -#toc > .toggleButton { +.exerslide-toc-toggleButton { align-self: flex-end; background-color: transparent; border: none; color: #AAA; + cursor: pointer; flex-shrink: 0; + font-size: 1em; outline-width: thin; - padding: 0.5rem; + padding: 0.5em; } -#toc > .toggleButton:hover { +.exerslide-toc-toggleButton:hover { color: inherit; } -#toc #toc-list, -#toc #toc-list .slides { - counter-reset: item; - overflow-y: auto; - margin-left: 0.6em; -} - -#toc > #toc-list > * { - margin-bottom: 1em; -} - -#toc > #toc-list > :first-child { +#toc-list > :first-child { margin-top: 0; } -#toc .slide, -#toc .chapter { +.exerslide-toc-entry, +.exerslide-toc-chapter { display: block; } -#toc .chapter::before, -#toc .slide::before { +.exerslide-toc-entry::before, +.exerslide-toc-chapter::before { content: counters(item, '.') ". "; counter-increment: item; } -#toc .chapter > .title { +.exerslide-toc-title { display: inline-block; margin: 0; + margin-bottom: 0.5em; } -#toc #toc-list > .slide::before, -#toc #toc-list > .slide, -#toc .chapter::before, -#toc .chapter > .title { +#exerslide-toc-list > .exerslide-toc-entry::before, +#exerslide-toc-list > .exerslide-toc-entry, +.exerslide-toc-chapter::before, +.exerslide-toc-title { font-weight: bold; font-size: 1em; } -#toc .slide { +.exerslide-toc-entry { + padding: 0.1em 0; } -#toc .slide > a { +.exerslide-toc-entry > a { color: inherit; } - -#toc .slide, -#toc .slide > a { +.exerslide-toc-entry, +.exerslide-toc-entry > a { text-decoration: none; outline-width: thin; } -#toc .slide.active, -#toc .slide.active > a, -#toc .slide:hover { +.exerslide-toc-entry.active, +.exerslide-toc-entry.active > a, +.exerslide-toc-entry:hover { color: #428bca; } diff --git a/js/components/css/toolbar.css b/js/components/css/toolbar.css index 813567c..e4f83a4 100644 --- a/js/components/css/toolbar.css +++ b/js/components/css/toolbar.css @@ -6,7 +6,7 @@ * the root directory of this source tree. */ -#toolbar { +.exerslide-toolbar { box-sizing: border-box; color: #BBB; padding: 0 1.5em; @@ -14,33 +14,35 @@ width: 100%; } -#toolbar > * { - font-size: 1.05em; - max-width: 45em; +.exerslide-toolbar-button, +.exerslide-toolbar-text { + font-size: 1.05rem; } - -#toolbar button { +.exerslide-toolbar-button { background-color: transparent; + cursor: pointer; + color: #BBB; border: none; padding: 10px; } -#toolbar button:focus, -#toolbar button:hover { +.exerslide-toolbar-button:focus, +.exerslide-toolbar-button:hover { color: #555; } -#toolbar button[disabled] { +.exerslide-toolbar-button[disabled] { visibility: hidden; } @media(max-width: 768px) { - #toolbar { + .exerslide-toolbar { text-align: center; margin-bottom: 1em; } - #toolbar > * { - font-size: 1.5em; + .exerslide-toolbar-button, + .exerslide-toolbar-text { + font-size: 1.5rem; } } diff --git a/js/keyMap.js b/js/keyMap.js deleted file mode 100755 index d2720cb..0000000 --- a/js/keyMap.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This sets up the default keybindings for a presentation. The module should - * return an object with `keys -> function` mapping. exerslide will bind event - * handlers for those keys (key combinations) and call the corresponding function - * providing an API to control the presentation. Currently provided is - * - * - nextSlide(): Advance to the next slide - * - previousSlide(): Go back to the previous slide - * - gotToSlide(index): Go to slide - * - * We use http://dmauro.github.io/Keypress/ to bind the event handlers. Have - * a look at the documentation to find out how to specify key combinations. - */ - -function next({nextSlide}) { - nextSlide(); -} - -function prev({previousSlide}) { - previousSlide(); -} - -export default { - left: prev, - right: next, - 'alt pageup': prev, - 'alt pagedown': next, -}; diff --git a/js/presentation.js b/js/presentation.js index 0565cf1..efcc192 100644 --- a/js/presentation.js +++ b/js/presentation.js @@ -14,7 +14,7 @@ * kind of custom initialization step. */ -import presentation from 'exerslide/js/presentation'; +import {present, use} from 'exerslide/browser'; /** * The master layout for this presentation. To customize is, either edit it @@ -23,32 +23,76 @@ import presentation from 'exerslide/js/presentation'; import MasterLayout from './MasterLayout'; /** - * This sets up the default keybindings for a presentation. This should be an - * object with `keys -> function` mapping. exerslide will bind event - * handlers for those keys (key combinations) and call the corresponding function - * providing an API to control the presentation. Currently provided is + * The base slide layout. To customize is, either edit it directly or copy it + * and point to the copy here. + */ +import SlideLayout from './SlideLayout'; + +/** + * Many features of exerslide are actually made available via runtime plugins. + * + * The following plugin enables keyboard navigation. This sets up the default + * keybindings for a presentation. This should be an object with + * `keys -> function` mapping. exerslide will bind event handlers for those keys + * (key combinations) and call the corresponding function providing an API to + * control the presentation. Currently provided is * * - nextSlide(): Advance to the next slide * - previousSlide(): Go back to the previous slide - * - gotToSlide(index): Go to slide * * We use https://craig.is/killing/mice to bind the event handlers. Have * a look at the documentation to find out how to specify key combinations. */ -function next({nextSlide}) { - nextSlide(); +import keyboardNavigation from 'exerslide/browser-plugins/keyboardNavigation'; +function forward({forward}) { + forward(); } -function prev({previousSlide}) { - previousSlide(); +function back({back}) { + back(); } +use( + keyboardNavigation, + { + left: back, + right: forward, + 'alt+pageup': back, + 'alt+pagedown': forward, + } +); + +/** + * This plugin automatically scales the font size according to the provided + * settings. The default settings try to maintain a line length that is + * considered to be readable. To disable this plugin, just comment or remove the + * following two lines. + */ +import scaledContent from 'exerslide/browser-plugins/scaledContent'; +use(scaledContent); + +/** + * This plugin, when applied to content, injects alerts for screenreaders that + * let the author know if the content isn't fully visible. That allows authors + * with visual impairment to adjust the content or to scroll to make the content + * visible. + */ +import contentVisibility from 'exerslide/browser-plugins/contentVisibility'; +use(contentVisibility); + +/** + * This plugin is only enabled during development and shows the file path of the + * current slide and allows to view the source of the slide. + */ +import debugInformation from 'exerslide/browser-plugins/debugInformation'; +//use(debugInformation); -const keyMap = { - left: prev, - right: next, - 'alt+pageup': prev, - 'alt+pagedown': next, -}; +/** + * It is likely that you will be linking to the same external sources from + * multiple slides. By default exerslide provides the references.yml file as a + * central place to keep those references. The default markdown parser takes + * them into account. + */ +import references from '!!json!yaml!../references.yml'; /** * __exerslide_slides__ is "magic" global variable that holds an array of slide @@ -57,8 +101,12 @@ const keyMap = { */ /* global __exerslide_slides__*/ -presentation({ - MasterLayout, - keyMap, +import analytics from './analytics'; +use(analytics); + +present({ + masterLayout: MasterLayout, + slideLayout: SlideLayout, + references, slides: __exerslide_slides__, }); diff --git a/js/scriptHelper.js b/js/scriptHelper.js index 734f7b4..9d0f2a0 100755 --- a/js/scriptHelper.js +++ b/js/scriptHelper.js @@ -38,12 +38,12 @@ global.showHideDialog = function(ev) { document.getElementById('inputfield').focus(); } } - if (el.style.display == "block") { + if (el.style.display == "flex") { el.style.display = "none"; document.getElementById('sourceLink').focus(); document.body.style.overflow = 'initial'; } else { - el.style.display = "block"; + el.style.display = "flex"; document.getElementById('inputfield').focus(); document.body.style.overflow = 'hidden'; } @@ -58,12 +58,12 @@ global.showHideDialog2 = function(ev) { document.getElementById('inputfield2').focus(); } } - if (el.style.display == "block") { + if (el.style.display == "flex") { el.style.display = "none"; document.getElementById('sourceLink2').focus(); document.body.style.overflow = 'initial'; } else { - el.style.display = "block"; + el.style.display = "flex"; document.getElementById('inputfield2').focus(); document.body.style.overflow = 'hidden'; } @@ -89,9 +89,9 @@ global.closeDialog2 = function(ev) { // Menu example code. global.menuExample = { onClick: function (event) { - var isOpen = this.toggleMenu(event.currentTarget.parentNode); + var isOpen = this.toggleMenu(event.currentTarget); if (isOpen) { - this.setMenuItemFocus(event.currentTarget.parentNode); + this.setMenuItemFocus(event.currentTarget); } }, // Keep all clicks from escaping the widget. @@ -231,14 +231,16 @@ global.menuExample = { this.findButtonElement(menuWidgetElement).focus(); }, - getActiveMenuItem: function (menuWidgetElement) { - var menuElement = this.findMenuElement(menuWidgetElement); - var activeMenuItemElement = menuElement.querySelector('[data-active="true"]'); - }, findMenuElement: function (menuWidgetElement) { - return menuWidgetElement.querySelector('[role="menu"]'); + while (menuWidgetElement.className.indexOf('popupMenuWidget') === -1) { + menuWidgetElement = menuWidgetElement.parentNode; + } + return menuWidgetElement.querySelector('[role="menu"],ul'); }, findButtonElement: function (menuWidgetElement) { - return menuWidgetElement.querySelector('[role="button"]'); + while (menuWidgetElement.className.indexOf('popupMenuWidget') === -1) { + menuWidgetElement = menuWidgetElement.parentNode; + } + return menuWidgetElement.querySelector('[role="button"],a'); } }; diff --git a/layouts/HTMLExercise.js b/layouts/HTMLExercise.js index 3512e18..c4ec57a 100755 --- a/layouts/HTMLExercise.js +++ b/layouts/HTMLExercise.js @@ -1,5 +1,6 @@ import React from 'react'; import Editor from 'exerslide/components/Editor'; +import ContentRenderer from 'exerslide/components/ContentRenderer'; import '../js/scriptHelper'; import 'codemirror/mode/htmlmixed/htmlmixed'; @@ -77,11 +78,11 @@ class Example extends React.Component {
    : null } -  {title} + {' '}{title} : null } - {description ? this.props.contentConverter(description) : null} + {description ? : null} {this.props.code ?
    @@ -129,7 +130,7 @@ class Example extends React.Component { } {this.props.note ?
    - {this.props.contentConverter(description)} +
    : null } @@ -140,20 +141,22 @@ class Example extends React.Component { export default class HTMLExercise extends React.Component { componentDidMount() { - let {layoutData: {description, examples}, slideIndex} = this.props; + /* if (slideIndex == 14) { exerslide.platFormFn(document, 'script', 'facebook-jssdk'); } + */ } render(element: ReactElement, container: DOMElement) { - let {layoutData: {description, examples}, slideIndex} = this.props; + let {title, layoutData: {examples}, content} = this.props; return (
    - {description ? this.props.contentConverter(description) : null} + {title} + {content ? : null} {examples && examples.map( - (example, i) => + (example, i) => )}
    ); diff --git a/layouts/css/Center.css b/layouts/css/Center.css deleted file mode 100755 index 010b305..0000000 --- a/layouts/css/Center.css +++ /dev/null @@ -1,8 +0,0 @@ -#slide > .Center-wrapper { - align-items: center; - display: flex; - flex-direction: column; - flex: 1; - justify-content: center; - text-align: center; -} diff --git a/layouts/css/TwoColumn.css b/layouts/css/TwoColumn.css deleted file mode 100755 index 229fe44..0000000 --- a/layouts/css/TwoColumn.css +++ /dev/null @@ -1,19 +0,0 @@ -.TwoColumn-wrapper { - display: flex; -} - -.TwoColumn-column { - flex: 1; - padding: 10px; -} - -.TwoColumn-column.TwoColumn-image { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.TwoColumn-column.TwoColumn-image > img { - flex-shrink: 0; -} diff --git a/package.json b/package.json index e56a794..87cf2b6 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,12 @@ "private": true, "dependencies": { "codemirror": "^5.7.0", - "exerslide": "~1.0.0", - "exerslide-plugin-center-layout": "~1.0.0", - "exerslide-plugin-column-layout": "~1.0.0", - "exerslide-plugin-html-converter": "~1.0.0", - "exerslide-plugin-markdown-converter": "~1.0.0", - "exerslide-plugin-shared-urls": "~1.0.0", + "exerslide": "~1.0.2", + "exerslide-plugin-bulletlist-layout": "^1.0.0", + "exerslide-plugin-center-layout": "^1.0.0", + "exerslide-plugin-column-layout": "^1.0.0", + "exerslide-plugin-html-converter": "^1.0.0", + "exerslide-plugin-markdown-converter": "^1.0.1", "font-awesome": "^4.4.0", "foundation-sites": "^6.1.2", "react": "^15.0.0", @@ -29,7 +29,9 @@ "extract-text-webpack-plugin": "^0.9.1", "file-loader": "^0.8.5", "is-text-path": "^1.0.1", + "json-loader": "^0.5.4", "style-loader": "^0.13.0", - "webpack": "^1.12.9" + "webpack": "^1.12.9", + "yaml-loader": "^0.4.0" } } diff --git a/references.yml b/references.yml new file mode 100644 index 0000000..85819e2 --- /dev/null +++ b/references.yml @@ -0,0 +1,7 @@ +# You can keep links to external sources here. This lets you avoid repeating the +# same URL on different slides. The default markdown parser takes these into +# account.The format is: "name: URL" +# +# Example: +# +# example: http://example.org diff --git a/statics/index.html b/statics/index.html index 9470621..7d9d754 100644 --- a/statics/index.html +++ b/statics/index.html @@ -33,7 +33,7 @@ -
    +
    diff --git a/webpack.config.js b/webpack.config.js index 1cf935b..ee499c9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -18,6 +18,7 @@ const PROD = process.env.NODE_ENV === 'production'; const plugins = [ new webpack.DefinePlugin({ + '__DEV__': !PROD, 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), }), @@ -27,6 +28,9 @@ const plugins = [ if (PROD) { plugins.push(new webpack.optimize.UglifyJsPlugin({ sourceMap: false, + compress: { + warnings: false, + }, })); } @@ -51,7 +55,7 @@ module.exports = { { test: /\.jsx?$/, loader: 'babel', - exclude: /node_modules\/(?!exerslide\/)/, + exclude: /node_modules\/(?!exerslide\b)/, query: { presets: [ require.resolve('babel-preset-es2015'), @@ -63,6 +67,10 @@ module.exports = { ], }, }, + { + test: /\.json$/, + loader: 'json-loader', + }, { test: /\.css$/, loader: ExtractTextPlugin.extract( @@ -93,8 +101,8 @@ module.exports = { * slides. If you don't want to auto-copy them at all, remove this * transform. */ - exerslide.transforms.extractAssetPaths({ - pattern: /(?:\.{1,2}\/)+[-_\/a-z\d.]+\.(?:png|jpe?g|gif|svg)\b/ig, + exerslide.transforms.requireAssets({ + // pattern: /(?:\.{1,2}\/)+[-_\/a-z\d.]+\.(?:png|jpe?g|gif|svg)\b/ig, }), ], },