From 8a1b730343f259b9a6f5d07416af69a9c2ffa703 Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Wed, 7 Sep 2016 10:22:04 -0700 Subject: [PATCH 1/6] 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, }), ], }, From 218b3b4cfec206ede15a7dadaadb87fb30829778 Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Wed, 7 Sep 2016 10:22:26 -0700 Subject: [PATCH 2/6] Update and improve content for work with latest exerslide --- slides/00-Introduction/00-instructions.md | 16 ++++--- slides/00-Introduction/01-faqs.md | 13 +++--- slides/02-Developers/01-headings.html.md | 11 +++-- slides/02-Developers/02-images.html.md | 13 +++--- slides/02-Developers/03-keyboard.html.md | 23 +++++----- slides/02-Developers/04-labels.html.md | 22 ++++----- slides/02-Developers/05-list.html.md | 12 ++--- slides/02-Developers/06-dialog.html.md | 18 +++----- slides/02-Developers/07-tables.html.md | 12 ++--- slides/02-Developers/08-menu.html.md | 45 +++++++++++++++++-- slides/02-Developers/09-aria.html.md | 43 +++++++++--------- slides/02-Developers/10-checklist.md | 7 +-- slides/03-Designers/01-color-contrast.html.md | 20 ++++----- slides/03-Designers/02-color-meaning.md | 31 +++++++++---- slides/03-Designers/03-text.html.md | 21 ++++----- slides/03-Designers/04-site-copy.md | 22 ++++++--- slides/03-Designers/05-photos.md | 16 ++++--- slides/03-Designers/06-checklist.md | 6 +-- 18 files changed, 209 insertions(+), 142 deletions(-) diff --git a/slides/00-Introduction/00-instructions.md b/slides/00-Introduction/00-instructions.md index 09faf35..c27b7c2 100755 --- a/slides/00-Introduction/00-instructions.md +++ b/slides/00-Introduction/00-instructions.md @@ -10,13 +10,17 @@ Welcome to the Teach Access Tutorial! This resource is part of the Teach Access use the verify button to check whether your solution is correct. 3. You can also verify the code sample output using VoiceOver - Apple's built-in screen reader (other screen readers work too). Here are some instructions for navigating with VoiceOver: - * cmd + F5 turns VoiceOver on/off - * tab navigates to an interactive element - * ctrl + opt + right arrow (repeatedly) navigates to the next element - * ctrl + opt + cmd + h (repeatedly) navigates by headings -

    + * cmd + F5 turns VoiceOver on/off + * tab navigates to an interactive element + * ctrl + opt + right arrow (repeatedly) + navigates to the next element + * ctrl + opt + cmd + h + (repeatedly) navigates by headings +

    + 4. When verifying with VoiceOver, use Chrome on a Mac for the best experience. However, the "Verify" button provided after each exercise will work with any browser/OS combination. -5. ARIA stands for Accessible Rich Internet Applications, a W3C standard for building accessible user interfaces on the web. +5. ARIA stands for Accessible Rich Internet Applications, a W3C standard for + building accessible user interfaces on the web. Happy learning! Smiley Icon diff --git a/slides/00-Introduction/01-faqs.md b/slides/00-Introduction/01-faqs.md index e7ab9ba..e920bf6 100755 --- a/slides/00-Introduction/01-faqs.md +++ b/slides/00-Introduction/01-faqs.md @@ -19,15 +19,16 @@ The tutorial should work with most assistive technologies, but Apple's VoiceOver **Where can I find more information on accessibility?** Here are a few resources to get you started: -- Web Content Accessibility Guidelines: https://www.w3.org/WAI/intro/wcag -- WebAIM: http://webaim.org/ +- Web Content Accessibility Guidelines: +- WebAIM: **What are some good, free, developer tools for accessibility?** -- WAVE by WebAIM for general website accessibility: http://wave.webaim.org/ -- Juicy Studio's Readability Test: http://juicystudio.com/services/readability.php -- Vischeck's Color Blindness Checker: http://www.vischeck.com/ +- WAVE by WebAIM for general website accessibility: +- Juicy Studio's Readability Test: + +- Vischeck's Color Blindness Checker: **Are there jobs in the field of accessibility?** -Definitely, and the industry is growing. Take a look here: https://twitter.com/a11yjobs +Definitely, and the industry is growing. Take a look here: diff --git a/slides/02-Developers/01-headings.html.md b/slides/02-Developers/01-headings.html.md index 5f2fe21..1d15448 100755 --- a/slides/02-Developers/01-headings.html.md +++ b/slides/02-Developers/01-headings.html.md @@ -9,15 +9,11 @@ style: | margin: 0; } - #slide h3 { + .exerslide-slide h3 { margin: 5px; } -layoutData: - description: | - Headings provide structure to a page. A person using a screen reader can - navigate a page quickly using headings on the page if the headings used are - semantic. Semantic headings include real heading tags such as `h1`, `h2`. +layout_data: examples: - title: Semantic Heading description: | @@ -43,3 +39,6 @@ layoutData: ); --- +Headings provide structure to a page. A person using a screen reader can +navigate a page quickly using headings on the page if the headings used are +semantic. Semantic headings include real heading tags such as `h1`, `h2`. diff --git a/slides/02-Developers/02-images.html.md b/slides/02-Developers/02-images.html.md index 072672a..e316936 100755 --- a/slides/02-Developers/02-images.html.md +++ b/slides/02-Developers/02-images.html.md @@ -2,12 +2,8 @@ title: Images chapter: Writing Code -layoutData: +layout_data: description: | - Screen readers interact with text on the screen. So, to convey the meaning of an image to screen reader users, - we put an accessible text label in the HTML. If an image is decorative, we can hide it from screen - reader users by giving it an empty label (`alt=""`). After the completing the exercise below, you can learn a lot more about writing good alt text for images by checking out WebAIM's resource on the topic. - examples: - title: An Accessible Inline Image description: | @@ -38,3 +34,10 @@ layoutData: "It doesn't look like you added an alt to your image." ); --- +Screen readers interact with text on the screen. So, to convey the meaning of +an image to screen reader users, +we put an accessible text label in the HTML. If an image is decorative, we can hide it from screen +reader users by giving it an empty label (`alt=""`). After the completing the +exercise below, you can learn a lot more about writing good alt text for images +by checking out [WebAIM's resource on the +topic](http://webaim.org/techniques/alttext/). diff --git a/slides/02-Developers/03-keyboard.html.md b/slides/02-Developers/03-keyboard.html.md index 3c2f3c0..24afabb 100755 --- a/slides/02-Developers/03-keyboard.html.md +++ b/slides/02-Developers/03-keyboard.html.md @@ -13,13 +13,7 @@ style: | text-align: center; } -layoutData: - description: | - Make all interactive elements work with a keyboard. For example, make sure a button that you activate - with a click is also in the keyboard tab sequence and that pressing enter or space - activates it. Set the tabindex attribute to 0 to include an element in the browser's keyboard tab sequence. If you want an element out of sequence, set its tabindex to -1 and use Javascript to control its focus and tab sequence, and related keyboard events. We do not recommend using tabindex values - greater than 0 even though browsers support them. Note that HTML links and input elements have an implied tabindex of 0. - +layout_data: examples: - title: Semantic Button description: | @@ -37,9 +31,9 @@ layoutData: description: | The button below is constructed using an unsemantic div. The easiest way to make this semantic is to use a real button or input tag. Here is another way. In the - example below, - 1. Add `role` = 'button'. - 2. `tabindex` = '0'. + example below, add + 1. `role='button'` + 2. `tabindex='0'` Verify with VoiceOver that you can tab to the button and hear the button name and the fact that it is a button element. Note that you would need to add an onkeypress or onkeydown handler to the button so you @@ -63,3 +57,12 @@ layoutData: ); --- +Make all interactive elements work with a keyboard. For example, make sure a +button that you activate +with a click is also in the keyboard tab sequence and that pressing enter or space +activates it. Set the `tabindex` attribute to `0` to include an element in the +browser's keyboard tab sequence. If you want an element out of sequence, set +its `tabindex` to `-1` and use JavaScript to control its focus and tab +sequence, and related keyboard events. We do not recommend using `tabindex` +values greater than `0` even though browsers support them. Note that HTML links +and input elements have an implied `tabindex` of `0`. diff --git a/slides/02-Developers/04-labels.html.md b/slides/02-Developers/04-labels.html.md index e6a56ac..70192c3 100755 --- a/slides/02-Developers/04-labels.html.md +++ b/slides/02-Developers/04-labels.html.md @@ -12,7 +12,6 @@ style: | #composer { border: 1px solid #1466F2; - width: 200px; } #description { @@ -23,16 +22,7 @@ style: | font-size: 13px; } -layoutData: - description: | - Accessible labels are necessary to make several other types of elements understandable, - such as inputs, widgets, and ARIA landmark regions. - Accessible labels that create a delightful experience are: - 1. Concise -- 1 to 3 simple words. Only occasionally as many as 5 words. - 2. Meaningful -- accurately convey the purpose of the element. - - There are many ways to label an interactive element such as a button or an input field, which you will see below. You can check the results of adding the various label types by testing in your screen reader too! - +layout_data: examples: - title: Self-labeled description: | @@ -150,3 +140,13 @@ layoutData: "It doesn't look like you added an aria-describedby to the input field" ); --- +Accessible labels are necessary to make several other types of elements +understandable, +such as inputs, widgets, and ARIA landmark regions. +Accessible labels that create a delightful experience are: + +1. Concise -- 1 to 3 simple words. Only occasionally as many as 5 words. +2. Meaningful -- accurately convey the purpose of the element. + +There are many ways to label an interactive element such as a button or an input field, which you will see below. You can check the results of adding the various label types by testing in your screen reader too! + diff --git a/slides/02-Developers/05-list.html.md b/slides/02-Developers/05-list.html.md index adb7aa7..5b42897 100755 --- a/slides/02-Developers/05-list.html.md +++ b/slides/02-Developers/05-list.html.md @@ -8,16 +8,12 @@ style: | height: 100px; } -layoutData: - description: | - Semantic lists help screen readers understand the type of the element and the number of items in the element, and provide - easier navigation via list commands specific to screen readers. - +layout_data: examples: - title: Semantic Lists Using HTML description: | HTML provides tags that express lists. Most likely you are already familiar with the - ```ul``` (unordered list) and ```ol``` (ordered list) tags. + `ul` (unordered list) and `ol` (ordered list) tags. In the example below, the list is correctly announced by screen readers as a list with three items. @@ -78,3 +74,7 @@ layoutData: "Wrap the items in an 'li' element or in a 'span' OR 'div' with the role 'listitem'." ); --- +Semantic lists help screen readers understand the type of the element and the +number of items in the element, and provide +easier navigation via list commands specific to screen readers. + diff --git a/slides/02-Developers/06-dialog.html.md b/slides/02-Developers/06-dialog.html.md index 0f76a06..96458dc 100755 --- a/slides/02-Developers/06-dialog.html.md +++ b/slides/02-Developers/06-dialog.html.md @@ -15,6 +15,8 @@ style: | text-align:center; z-index: 1000; background-color: rgba(0, 0, 0, .4); + align-items: center; + justify-content: center; } #container, #container2 { @@ -22,15 +24,6 @@ style: | background-color: #fff; border:1px solid #000; padding:15px; - text-align:center; - } - - #container { - margin: 400px auto; - } - - #container2 { - margin: 400px auto; } label { @@ -63,10 +56,7 @@ style: | margin: 10px 0; } -layoutData: - description: | - Dialogs are a little bit trickier to make accessible, but with a few key principles, they can be made keyboard navigable and usable with screen readers. - +layout_data: examples: - title: Semantic Dialog description: | @@ -183,3 +173,5 @@ layoutData: ); --- +Dialogs are a little bit trickier to make accessible, but with a few key +principles, they can be made keyboard navigable and usable with screen readers. diff --git a/slides/02-Developers/07-tables.html.md b/slides/02-Developers/07-tables.html.md index 3c033d4..33cfcb8 100755 --- a/slides/02-Developers/07-tables.html.md +++ b/slides/02-Developers/07-tables.html.md @@ -7,6 +7,7 @@ style: | .editorWithPreview > .editor, .editorWithPreview > .preview { width: 50%; + max-width: 50%; } table, th, td { @@ -48,12 +49,7 @@ style: | display: table-row-group; } -layoutData: - description: | - Tables help screen readers process information presented in a tabular format. - When information is presented using table markup, screen reader users can - read down columns and across rows, and even hear column and row headings as they do so. - +layout_data: examples: - title: Semantic Table description: | @@ -132,3 +128,7 @@ layoutData: "Are you using semantic td tags?" ); --- +Tables help screen readers process information presented in a tabular format. +When information is presented using table markup, screen reader users can +read down columns and across rows, and even hear column and row headings as they do so. + diff --git a/slides/02-Developers/08-menu.html.md b/slides/02-Developers/08-menu.html.md index 81f5bc4..41cd5a8 100755 --- a/slides/02-Developers/08-menu.html.md +++ b/slides/02-Developers/08-menu.html.md @@ -7,10 +7,46 @@ style: | height: 100px; } -layoutData: - description: | - Menus, like dialogs, rely on a few key principles to render them usable with the keyboard or screen reader. + .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; + list-style: none; + margin: 0; + } + + .popupMenuWidget [role="menu"] a { + display: block; + padding: 0px 5px; + } + .popupMenuWidget [role="menuitem"]:focus { + background-color: #428bca; + color: white; + } + +layout_data: examples: - title: Accessible Menu description: | @@ -175,3 +211,6 @@ layoutData: ); --- +Menus, like dialogs, rely on a few key principles to render them usable with +the keyboard or screen reader. + diff --git a/slides/02-Developers/09-aria.html.md b/slides/02-Developers/09-aria.html.md index 1746172..660e31e 100755 --- a/slides/02-Developers/09-aria.html.md +++ b/slides/02-Developers/09-aria.html.md @@ -14,12 +14,8 @@ style: | display: none; } -layoutData: +layout_data: description: | - ARIA or Accessible Rich Internet - Applications provides a framework of roles, properties, and guidelines to help - develop accessible user interactions. - examples: - title: ARIA description: @@ -55,28 +51,33 @@ layoutData: There are several types of landmark roles. Some of them are: - `
    =
    ` - Equivalent to “directing the gaze” of the screen - reader user. Should contain only the primary content of the page. + - `
    `,`
    ` -- Equivalent to “directing the gaze” of + the screen reader user. Should contain only the primary content of the + page. - `