Add variable fonts demo (#401)
What it says on the tin! :D Co-authored-by: Greg Whitworth <gwhit@microsoft.com> Co-authored-by: François Remy <francois.remy.dev@outlook.com>
39
.csslintrc
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"adjoining-classes": false,
|
||||
"box-model": false,
|
||||
"box-sizing": false,
|
||||
"bulletproof-font-face": false,
|
||||
"compatible-vendor-prefixes": true,
|
||||
"display-property-grouping": true,
|
||||
"duplicate-background-images": true,
|
||||
"duplicate-properties": true,
|
||||
"empty-rules": true,
|
||||
"errors": true,
|
||||
"fallback-colors": false,
|
||||
"floats": true,
|
||||
"font-faces": true,
|
||||
"font-sizes": true,
|
||||
"gradients": true,
|
||||
"ids": false,
|
||||
"import": true,
|
||||
"important": true,
|
||||
"known-properties": true,
|
||||
"order-alphabetical": false,
|
||||
"outline-none": true,
|
||||
"overqualified-elements": true,
|
||||
"qualified-headings": false,
|
||||
"regex-selectors": false,
|
||||
"rules-count": false,
|
||||
"selector-max": false,
|
||||
"selector-max-approaching": false,
|
||||
"selector-newline": true,
|
||||
"shorthand": true,
|
||||
"star-property-hack": true,
|
||||
"text-indent": true,
|
||||
"underscore-property-hack": true,
|
||||
"unique-headings": false,
|
||||
"universal-selector": false,
|
||||
"unqualified-attributes": false,
|
||||
"vendor-prefix": true,
|
||||
"zero-units": true
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
# Contributing to these demos
|
||||
|
||||
There are many ways you can contribute to these demos:
|
||||
|
||||
## Filing issues, fixing issues and improving the content
|
||||
Some of these demos have been migrated from the old TestDrive website and might contain some bugs with some browsers or the code doesn't follow the latest standards. We've tried to do our best to prevent this but we all know things can happen. If you find a bug, open an issue. If you know how to fix it or improve a demo, do a Pull Request!
|
||||
|
||||
## Adding new demos
|
||||
If you are interested in contributing with an interoperable, open source demo, open an issue and we will see how we can do that!
|
||||
|
||||
Thank you for contributing!
|
||||
|
||||
## Timelines
|
||||
|
||||
If your PR contains a new demo, it must be submitted **at least one week** in advance of the intended publication.
|
||||
|
||||
## Worfklow and requirements
|
||||
|
||||
### Setting up the project
|
||||
|
||||
1. Fork this project and [set up a remote](https://help.github.com/articles/configuring-a-remote-for-a-fork/) to file pull requests
|
||||
against later.
|
||||
2. [Install Node](https://nodejs.org/en/), then do an `npm install` from the root of the Demos repo to install linting dependencies.
|
||||
3. Create a feature branch off of the master branch. Each new demo, or solution to an issue, gets its own branch / PR.
|
||||
4. Review the [accessibility requirements](.github/ACCESSIBILITY_REQS.md) that your demo must meet. If you'd like help with design work, please chat with @melanierichards.
|
||||
|
||||
### Starting a new demo
|
||||
|
||||
Duplicate the `demo-template/` directory and start from there. Follow the instructions in the `index.html` file.
|
||||
|
||||
### Fixing issues
|
||||
|
||||
In your commit message, please include "fixes #issueNumber" or "ref #issueNumber", and a short, present-tense description of what you did.
|
||||
|
||||
### Submitting a pull request
|
||||
|
||||
1. Lint your work using `npm run lint:css -- demoDirectoryName/**/*.css` and `npm run lint:js -- demoDirectoryName/**/*.js`. You can add a `--fix` flag to the end of the CSS linting command, and [the linter](https://stylelint.io/user-guide/cli/) will fix as much as it can.
|
||||
2. Update your feature branch with any new commits from MicrosoftEdge/Demos/master.
|
||||
3. Check your PR one last time for [accessibility issues](.github/ACCESSIBILITY_REQS.md).
|
||||
4. Create a pull request against MicrosoftEdge/Demos/master with the changes from your branch. Title with the name of your demo or fixes. Mention [`@molant`](https://github.com/molant) and optionally [`@melanierichards`](https://github.com/melanierichards) (for front-end/design review) in the comments so we're aware of your PR.
|
||||
5. Push any changes based on feedback to your feature branch. This will update the PR with the most recent changes.
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
## Requirements
|
||||
|
||||
I've read and followed:
|
||||
|
||||
* [ ] All applicable accessibility requirements (See [`.github/ACCESSIBILITY_REQS.md`](https://github.com/MicrosoftEdge/Demos/blob/master/.github/ACCESSIBILITY_REQS.md)).
|
||||
* [ ] CSS code style guidelines (See [`.github/CSS_STYLE_REQS.md`](https://github.com/MicrosoftEdge/Demos/blob/master/.github/CSS_STYLE_REQS.md)).
|
||||
* [ ] My PR follows all applicable accessibility requirements (See [`.github/ACCESSIBILITY_REQS.md`](https://github.com/MicrosoftEdge/Demos/blob/master/.github/ACCESSIBILITY_REQS.md)).
|
||||
* [ ] My PR follows the CSS code style guidelines (See [`.github/CSS_STYLE_REQS.md`](https://github.com/MicrosoftEdge/Demos/blob/master/.github/CSS_STYLE_REQS.md)).
|
||||
* [ ] I have linted my code using `npm run lint:css -- demoDirectoryName/**/*.css` and `npm run lint:js -- demoDirectoryName/**/*.js`, and have fixed the errors.
|
|
@ -5,3 +5,7 @@
|
|||
webauthn/.vscode/
|
||||
webauthn/web.config
|
||||
webauthn/.idea/
|
||||
variable-fonts/fonts/Bahnschrift.ttf
|
||||
variable-fonts/fonts/Sitka.ttf
|
||||
variable-fonts/fonts/SitkaFV.ttf
|
||||
variable-fonts/styles/font-declarations.css
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"rules": {
|
||||
"at-rule-empty-line-before": [ "always", {
|
||||
except: [ "blockless-after-blockless", "first-nested" ],
|
||||
ignore: ["after-comment"],
|
||||
} ],
|
||||
"at-rule-semicolon-newline-after": "always",
|
||||
"block-closing-brace-newline-after": "always",
|
||||
"block-closing-brace-newline-before": "always-multi-line",
|
||||
"block-closing-brace-space-before": "always-single-line",
|
||||
"block-no-empty": true,
|
||||
"block-opening-brace-newline-after": "always-multi-line",
|
||||
"block-opening-brace-space-after": "always-single-line",
|
||||
"block-opening-brace-space-before": "always",
|
||||
"color-hex-case": "lower",
|
||||
"color-hex-length": "short",
|
||||
"color-named": "never",
|
||||
"color-no-invalid-hex": true,
|
||||
"comment-empty-line-before": [ "always", {
|
||||
except: ["first-nested"],
|
||||
ignore: ["stylelint-commands"],
|
||||
} ],
|
||||
"comment-whitespace-inside": "always",
|
||||
"declaration-bang-space-after": "never",
|
||||
"declaration-bang-space-before": "always",
|
||||
"declaration-block-no-shorthand-property-overrides": true,
|
||||
"declaration-block-semicolon-newline-after": "always-multi-line",
|
||||
"declaration-block-semicolon-space-after": "always-single-line",
|
||||
"declaration-block-semicolon-space-before": "never",
|
||||
"declaration-block-single-line-max-declarations": 1,
|
||||
"declaration-block-trailing-semicolon": "always",
|
||||
"declaration-colon-newline-after": "always-multi-line",
|
||||
"declaration-colon-space-after": "always-single-line",
|
||||
"declaration-colon-space-before": "never",
|
||||
"function-calc-no-unspaced-operator": true,
|
||||
"function-comma-newline-after": "always-multi-line",
|
||||
"function-comma-space-after": "always-single-line",
|
||||
"function-comma-space-before": "never",
|
||||
"function-linear-gradient-no-nonstandard-direction": null,
|
||||
"function-max-empty-lines": 0,
|
||||
"function-parentheses-newline-inside": "always-multi-line",
|
||||
"function-parentheses-space-inside": "never-single-line",
|
||||
"function-url-quotes": "always",
|
||||
"function-whitespace-after": "always",
|
||||
"indentation": "tab",
|
||||
"length-zero-no-unit": true,
|
||||
"max-empty-lines": 2,
|
||||
"media-feature-colon-space-after": "always",
|
||||
"media-feature-colon-space-before": "never",
|
||||
"media-feature-range-operator-space-after": "always",
|
||||
"media-feature-range-operator-space-before": "always",
|
||||
"media-query-list-comma-newline-after": "always-multi-line",
|
||||
"media-query-list-comma-space-after": "always-single-line",
|
||||
"media-query-list-comma-space-before": "never",
|
||||
"media-feature-parentheses-space-inside": "never",
|
||||
"no-eol-whitespace": true,
|
||||
"no-invalid-double-slash-comments": true,
|
||||
"no-missing-end-of-source-newline": null,
|
||||
"number-leading-zero": "never",
|
||||
"number-max-precision": 3,
|
||||
"number-no-trailing-zeros": true,
|
||||
"rule-empty-line-before": [ "always-multi-line", {
|
||||
ignore: ["after-comment", "inside-block"],
|
||||
} ],
|
||||
"selector-combinator-space-after": "always",
|
||||
"selector-combinator-space-before": "always",
|
||||
"selector-list-comma-space-before": "never",
|
||||
"selector-pseudo-element-colon-notation": "double",
|
||||
"selector-type-case": "lower",
|
||||
"string-quotes": "double",
|
||||
"time-min-milliseconds": 100,
|
||||
"unit-no-unknown": true,
|
||||
"value-list-comma-newline-after": "always-multi-line",
|
||||
"value-list-comma-space-after": "always-single-line",
|
||||
"value-list-comma-space-before": "never",
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
# Contributing
|
||||
|
||||
Thanks for your interest in contributing! There are many ways to contribute: filing issues, fixing bugs, improving content, and adding new demos. All these ways are very much appreciated.
|
||||
|
||||
In order to have the smoothest pull request experience, we suggest reading the following guidelines so you know what to expect:
|
||||
|
||||
* [Timelines](#timelines)
|
||||
* [Workflow](#workflow)
|
||||
* [Code style requirements](#code-style-requirements)
|
||||
* [Demo template](#demo-template)
|
||||
|
||||
## Timelines
|
||||
|
||||
If your PR contains a new demo, it must be submitted **at least one week** in advance of the intended publication.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Fork this project and [set up a remote](https://help.github.com/articles/configuring-a-remote-for-a-fork/) to file pull requests against later.
|
||||
2. Create a feature branch for your new demo or code fix off of the master branch.
|
||||
3. Before starting any work, and preferrably before designing the experience of your demo, review the [code style requirements](#code-style-requirements) that your demo must meet. If you'd like help with design work, please chat with @melanierichards.
|
||||
4. Before creating a PR, make sure your feature branch is up to date with the latest changes to `MicrosoftEdge/Demos/master`.
|
||||
5. Create a PR against MicrosoftEdge/Demos/master with the changes from your branch. Title with the name of your demo or fixes, and give a good description of the changes. If submitting a fix, your PR message should say something like `fixes #1234` so that the issue gets automagically linked to the PR. Mention [`@molant`](https://github.com/molant) and optionally [`@melanierichards`](https://github.com/melanierichards) (for front-end/design review) in the comments so we're aware of your PR.
|
||||
6. Push any changes based on feedback to your feature branch. This will update the PR with the most recent changes.
|
||||
|
||||
## Code style requirements
|
||||
|
||||
We will be checking pull requests against the following guidelines and requirements:
|
||||
|
||||
* [Accessibility requirements](.github/ACCESSIBILITY_REQS.md)
|
||||
* [CSS code style](.github/CSS_STYLE_REQS.md)
|
||||
|
||||
## Demo template
|
||||
|
||||
Duplicate the `demo-template/` directory and start from there. **Be sure to add your demo's details in the meta data.**
|
||||
|
||||
### If you're creating an immersive experience
|
||||
|
||||
The demo template is quite permissive; it pretty much just adds a universal header to the top of the page. While we suggest chatting with @melanierichards about design needs, the demos are a nice place to explore different approaches. As long as your demo reflects a cheerful optimism and technical competency, it should be appropriate for this context.
|
||||
|
||||
### If you'd like your demo to be a more simple walkthrough (like @supports or css3filters)
|
||||
|
||||
We'd prefer that your demo follow Microsoft design styles more strictly and not reinvent the wheel for simple things. Here's how to do that:
|
||||
|
||||
1. Internal folks: chat with [`@melanierichards`](https://github.com/melanierichards)
|
||||
2. Un-comment the [CSS file reference](demo-template/index.html#L11) in the head of the demo-template HTML file
|
||||
3. Remove the [demo-header.js reference](demo-template/index.html#L20) in that same HTML file
|
||||
4. Remove [config.json](demo-template/config.json) from the root directory of your demo. This config file tells dev.microsoftedge.com to display the demo in its own window instead of inline on the site, which would not be needed in this case.
|
|
@ -9,8 +9,8 @@ too sentimental). Some others are new. In any case, we are working on adding mor
|
|||
|
||||
## Contributing
|
||||
|
||||
Please see our [contribution guidelines](CONTRIBUTING.md) before submitting a PR.
|
||||
Thanks for contributing! Please see the [Contributing](.github/CONTRIBUTING.md) file for process details and requirements.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
// How many tags should we have if the user doesn't specify in a query string?
|
||||
var DEFAULT_NUM_TAGS = 75;
|
||||
const DEFAULT_NUM_TAGS = 75;
|
||||
// Which div id should we put the tags in?
|
||||
var TAGS_DIV = 'sidebar';
|
||||
const TAGS_DIV = 'sidebar';
|
||||
// How fast do we want the page to load?
|
||||
var LOADING_GOAL_TIME_MS = 500;
|
||||
const LOADING_GOAL_TIME_MS = 500;
|
||||
|
||||
var startMeasurePerf = function() {
|
||||
const startMeasurePerf = function() {
|
||||
'use strict';
|
||||
|
||||
// Start the clock for loading time
|
||||
performance.mark('script begin');
|
||||
if (window.msWriteProfilerMark) {
|
||||
|
@ -15,9 +16,10 @@ var startMeasurePerf = function() {
|
|||
};
|
||||
|
||||
// Sets all the given divs to default width and height
|
||||
var resetDivs = function (divs) {
|
||||
const resetDivs = function (divs) {
|
||||
'use strict';
|
||||
for (var i = 0; i < divs.length; i++) {
|
||||
|
||||
for (let i = 0; i < divs.length; i++) {
|
||||
divs[i].style.width = '';
|
||||
divs[i].style.height = '';
|
||||
}
|
||||
|
@ -25,23 +27,24 @@ var resetDivs = function (divs) {
|
|||
|
||||
// This function essentially re-implements css flexbox logic using inefficient javascript code. It takes all divs in the given
|
||||
// element, assumes they're inline, and modifies their widths so they fill whichever row they're on.
|
||||
var setWidthOfCells = function (divId) {
|
||||
const setWidthOfCells = function (divId) {
|
||||
'use strict';
|
||||
var mainContent = document.getElementById(divId);
|
||||
var cells = mainContent.getElementsByTagName('div');
|
||||
|
||||
const mainContent = document.getElementById(divId);
|
||||
const cells = mainContent.getElementsByTagName('div');
|
||||
|
||||
// First, reset all the divs to their default width and height
|
||||
resetDivs(cells);
|
||||
|
||||
// For every row
|
||||
for (var i = 0; i < cells.length; i++) {
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
// This is giving us 'for every row', because we'll only enter this 'if' for the tags on the far left side
|
||||
if (cells[i].offsetLeft === 0) {
|
||||
var cellsInRow = [];
|
||||
var totalWidth = 0;
|
||||
const cellsInRow = [];
|
||||
let totalWidth = 0;
|
||||
|
||||
// Get the list of divs that are in this row, and simultaneously count up their total width
|
||||
for (var j = 0; j < cells.length; j++) {
|
||||
for (let j = 0; j < cells.length; j++) {
|
||||
// If this cell is in the same row as the one on the left side...
|
||||
if (cells[j].offsetTop === cells[i].offsetTop) {
|
||||
// ...add it to our list of cells in this row, and add its width to the total width of cells in the row
|
||||
|
@ -57,20 +60,21 @@ var setWidthOfCells = function (divId) {
|
|||
|
||||
// Now expand all the tags in this row so that they fill the horizontal space.
|
||||
// Get the new widths by solving for x: currentWidthOfTag / currentTotalWidthOfTagsOnRow = x / containingDivWidth
|
||||
for (var k = 0; k < cellsInRow.length; k++) {
|
||||
cellsInRow[k].style.width = (((cellsInRow[k].offsetWidth * document.getElementById(divId).offsetWidth) / totalWidth) - 1 + 'px');
|
||||
for (let k = 0; k < cellsInRow.length; k++) {
|
||||
cellsInRow[k].style.width = (`${((cellsInRow[k].offsetWidth * document.getElementById(divId).offsetWidth) / totalWidth) - 1}px`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a string with a random cheesy hashtag. Not really important to the demo
|
||||
var randomText = function () {
|
||||
const randomText = function () {
|
||||
'use strict';
|
||||
var text = '#';
|
||||
var possible = ['Spectacular', 'Epic', 'Fortitude', 'Impressive', 'Demonstration', 'Edge', 'Microsoft', 'Awesome', 'Synergy', 'Nifty', 'Wonderful', 'Wow', 'MindBlowing', 'Love', 'Great'];
|
||||
|
||||
for (var i = 0; i < Math.random() * 2; i++) {
|
||||
let text = '#';
|
||||
const possible = ['Spectacular', 'Epic', 'Fortitude', 'Impressive', 'Demonstration', 'Edge', 'Microsoft', 'Awesome', 'Synergy', 'Nifty', 'Wonderful', 'Wow', 'MindBlowing', 'Love', 'Great'];
|
||||
|
||||
for (let i = 0; i < Math.random() * 2; i++) {
|
||||
text += possible[Math.floor(Math.random() * possible.length)];
|
||||
}
|
||||
|
||||
|
@ -79,11 +83,12 @@ var randomText = function () {
|
|||
|
||||
// Returns how many tags we should create on the left. The user can use a query string in the URL to specify the number of hastags with '?tags=120' (or any number)
|
||||
// If they don't, we just return the default, specified at the top of this script block. The code in this function isn't very important to the demo
|
||||
var getNumTags = function () {
|
||||
const getNumTags = function () {
|
||||
'use strict';
|
||||
var url = window.location.href.toLowerCase();
|
||||
var regex = new RegExp('[?&]tags(=([^&#]*)|&|#|$)');
|
||||
var results = regex.exec(url);
|
||||
|
||||
const url = window.location.href.toLowerCase();
|
||||
const regex = new RegExp('[?&]tags(=([^&#]*)|&|#|$)');
|
||||
const results = regex.exec(url);
|
||||
|
||||
if (results === null || !results[2]) {
|
||||
return DEFAULT_NUM_TAGS;
|
||||
|
@ -93,20 +98,20 @@ var getNumTags = function () {
|
|||
};
|
||||
|
||||
// Create the hash tags for the blog articles and format them to fill the sidebar
|
||||
var initializeHashtags = function () {
|
||||
const initializeHashtags = function () {
|
||||
'use strict';
|
||||
|
||||
// Add all of the hash tags to the document
|
||||
for (var i = 0; i < getNumTags(); i++) {
|
||||
for (let i = 0; i < getNumTags(); i++) {
|
||||
// create a div for each tag
|
||||
var tag = document.createElement('div');
|
||||
const tag = document.createElement('div');
|
||||
|
||||
// Give the tag an id and class
|
||||
tag.id = 'tag-' + i;
|
||||
tag.id = `tag-${i}`;
|
||||
tag.classList.add('tag');
|
||||
|
||||
// Give it some random hashtag text
|
||||
tag.innerHTML = '<p>' + randomText() + '</p>';
|
||||
tag.innerHTML = `<p>${randomText()}</p>`;
|
||||
|
||||
// Add the tag to the sidebar
|
||||
document.getElementById(TAGS_DIV).appendChild(tag);
|
||||
|
@ -116,16 +121,18 @@ var initializeHashtags = function () {
|
|||
}
|
||||
};
|
||||
|
||||
var attachResize = function () {
|
||||
const attachResize = function () {
|
||||
'use strict';
|
||||
|
||||
// Also, we need to redo that work when the browser is resized
|
||||
window.onresize = function resize() {
|
||||
setWidthOfCells(TAGS_DIV);
|
||||
};
|
||||
};
|
||||
|
||||
var stopMeasurePerf = function () {
|
||||
const stopMeasurePerf = function () {
|
||||
'use strict';
|
||||
|
||||
if (window.msWriteProfilerMark) {
|
||||
window.msWriteProfilerMark('script end');
|
||||
}
|
||||
|
@ -133,15 +140,16 @@ var stopMeasurePerf = function () {
|
|||
performance.measure('script', 'script begin', 'script end');
|
||||
};
|
||||
|
||||
var outputPerfResults = function () {
|
||||
const outputPerfResults = function () {
|
||||
'use strict';
|
||||
var measurePerf = function () {
|
||||
var afterOnLoad = function () {
|
||||
// Measure how long it took to execute this script on load
|
||||
var duration = performance.getEntriesByName('script')[0].duration;
|
||||
|
||||
var scriptCostElement = document.getElementById('scriptTime');
|
||||
var navCostElement = document.getElementById('navTime');
|
||||
const measurePerf = function () {
|
||||
const afterOnLoad = function () {
|
||||
// Measure how long it took to execute this script on load
|
||||
const duration = performance.getEntriesByName('script')[0].duration;
|
||||
|
||||
const scriptCostElement = document.getElementById('scriptTime');
|
||||
const navCostElement = document.getElementById('navTime');
|
||||
|
||||
// Now display the time it took to load on the page itself
|
||||
scriptCostElement.innerText = duration.toFixed(2);
|
||||
|
@ -161,8 +169,9 @@ var outputPerfResults = function () {
|
|||
window.addEventListener('load', measurePerf);
|
||||
};
|
||||
|
||||
var runOnParse = function () {
|
||||
const runOnParse = function () {
|
||||
'use strict';
|
||||
|
||||
startMeasurePerf();
|
||||
|
||||
// Make a bunch of hashtags on the left sidebar ...with expensive inline blocking script
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
var express = require('express');
|
||||
var path = require('path');
|
||||
var logger = require('morgan');
|
||||
var bodyParser = require('body-parser');
|
||||
var routes = require('./routes/index');
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const logger = require('morgan');
|
||||
const bodyParser = require('body-parser');
|
||||
const routes = require('./routes/index');
|
||||
|
||||
var app = express();
|
||||
const app = express();
|
||||
|
||||
// view engine setup
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
|
@ -18,7 +18,8 @@ app.use('/', routes);
|
|||
// catch 404 and forward to error handler
|
||||
app.use(function(req, res, next) {
|
||||
'use strict';
|
||||
var err = new Error('Not Found');
|
||||
|
||||
const err = new Error('Not Found');
|
||||
err.status = 404;
|
||||
next(err);
|
||||
});
|
||||
|
@ -30,6 +31,7 @@ app.use(function(req, res, next) {
|
|||
if (app.get('env') === 'development') {
|
||||
app.use(function(err, req, res) {
|
||||
'use strict';
|
||||
|
||||
res.status(err.status || 500);
|
||||
res.render('error', {
|
||||
message: err.message,
|
||||
|
@ -42,6 +44,7 @@ if (app.get('env') === 'development') {
|
|||
// no stacktraces leaked to user
|
||||
app.use(function(err, req, res) {
|
||||
'use strict';
|
||||
|
||||
res.status(err.status || 500);
|
||||
res.render('error', {
|
||||
message: err.message,
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
// Flag to determine if beacon has been used
|
||||
var usedBeacon = false;
|
||||
let usedBeacon = false;
|
||||
|
||||
|
||||
// Sends a beacon with the current time and returns true
|
||||
var sendBeacon = function() {
|
||||
const sendBeacon = function() {
|
||||
'use strict';
|
||||
|
||||
console.log('Sending beacon');
|
||||
navigator.sendBeacon('/data', Date.now().toString());
|
||||
return true;
|
||||
};
|
||||
|
||||
// Sends an XMLHttpRequest with the current time
|
||||
var sendXhr = function() {
|
||||
const sendXhr = function() {
|
||||
'use strict';
|
||||
|
||||
console.log('Falling back to async xhr');
|
||||
var xhr = new XMLHttpRequest();
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/data', true); // async
|
||||
xhr.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
|
||||
xhr.send(Date.now().toString());
|
||||
|
@ -28,18 +30,19 @@ if (!navigator.sendBeacon) {
|
|||
// Upon visibilitychange, send request to the server
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
'use strict';
|
||||
// Use sendBeacon if supported
|
||||
|
||||
// Use sendBeacon if supported
|
||||
|
||||
if (navigator.sendBeacon) {
|
||||
usedBeacon = sendBeacon();
|
||||
}
|
||||
|
||||
// Fallback to async XMLHttpRequest if beacon is not supported
|
||||
// Fallback to async XMLHttpRequest if beacon is not supported
|
||||
if (!usedBeacon) {
|
||||
sendXhr();
|
||||
}
|
||||
|
||||
// Re-render the page with the latest available roundtrip data (there’s no guarantee this last one has returned yet)
|
||||
// Re-render the page with the latest available roundtrip data (there’s no guarantee this last one has returned yet)
|
||||
location.reload();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,29 +1,31 @@
|
|||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
|
||||
var roundtrips = [];
|
||||
const roundtrips = [];
|
||||
|
||||
/* GET home page. */
|
||||
|
||||
router.get('/', function(req, res) {
|
||||
'use strict';
|
||||
|
||||
res.render('index', { title: 'Beacon API demo', data: JSON.stringify(roundtrips) });
|
||||
});
|
||||
|
||||
/* Beacon timestamp reporting */
|
||||
router.post('/data', function(req, res) {
|
||||
'use strict';
|
||||
var receivedTime = Date.now().toString();
|
||||
var requestTime = req.body;
|
||||
|
||||
const receivedTime = Date.now().toString();
|
||||
const requestTime = req.body;
|
||||
|
||||
console.log('Incoming beacon data');
|
||||
|
||||
var trip = {
|
||||
const trip = {
|
||||
beaconSent: requestTime,
|
||||
beaconReceived: receivedTime
|
||||
};
|
||||
roundtrips.push(trip);
|
||||
console.log('Current roundtrips data: ' + JSON.stringify(roundtrips));
|
||||
console.log(`Current roundtrips data: ${JSON.stringify(roundtrips)}`);
|
||||
res.end();
|
||||
});
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
'use strict';
|
||||
|
||||
// total number of values that are stored in the chart cache
|
||||
var defaults = {
|
||||
const defaults = {
|
||||
|
||||
// the width of an individual bar in pixels
|
||||
barWidth: 2,
|
||||
|
@ -67,18 +67,18 @@
|
|||
// a separate layer in the chart
|
||||
Chart.prototype.pushValues = function() {
|
||||
while (this.valueSets.length < arguments.length) {
|
||||
var values = this.valuesCount === 0 ? [] :
|
||||
const values = this.valuesCount === 0 ? [] :
|
||||
Array.apply(null, Array(this.options.valuesCount)).map(Number.prototype.valueOf, 0);
|
||||
this.valueSets.push(values);
|
||||
}
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var val = arguments[i] ? arguments[i] : 0;
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
const val = arguments[i] ? arguments[i] : 0;
|
||||
this.valueSets[i].push(val);
|
||||
|
||||
if (val > this.maxValue) {
|
||||
if (this.options.maxValueIncrement > 0) {
|
||||
var max = this.maxValue;
|
||||
let max = this.maxValue;
|
||||
while (max < val) {
|
||||
max += this.options.maxValueIncrement;
|
||||
}
|
||||
|
@ -105,19 +105,19 @@
|
|||
return [];
|
||||
}
|
||||
|
||||
var groupedVals = [];
|
||||
const groupedVals = [];
|
||||
|
||||
var groupSize = this.valuesCount <= (groupCount * this.options.minGroupSize) ?
|
||||
let groupSize = this.valuesCount <= (groupCount * this.options.minGroupSize) ?
|
||||
this.options.minGroupSize :
|
||||
this.valuesCount / groupCount,
|
||||
groupSum = 0,
|
||||
groupBreak = Math.round(groupSize) - 1,
|
||||
lastBreakIndex = -1;
|
||||
|
||||
for (var i = 0; i < this.valuesCount; i++) {
|
||||
for (let i = 0; i < this.valuesCount; i++) {
|
||||
groupSum += vals[i];
|
||||
if (i >= groupBreak || i === this.valuesCount - 1) {
|
||||
var sinceLastBreak = i - lastBreakIndex,
|
||||
let sinceLastBreak = i - lastBreakIndex,
|
||||
groupAverage = groupSum / sinceLastBreak;
|
||||
|
||||
groupedVals.push(groupAverage);
|
||||
|
@ -134,15 +134,15 @@
|
|||
this.resize();
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
var groupCount = Math.floor((this.canvas.width - this.options.barGap) / (this.options.barWidth + this.options.barGap)) + 1;
|
||||
const groupCount = Math.floor((this.canvas.width - this.options.barGap) / (this.options.barWidth + this.options.barGap)) + 1;
|
||||
|
||||
for (var v = 0; v < this.valueSets.length; v++) {
|
||||
var x = 0,
|
||||
for (let v = 0; v < this.valueSets.length; v++) {
|
||||
let x = 0,
|
||||
groupedVals = this.groupValues(this.valueSets[v], groupCount),
|
||||
color = this.options.colors[v % this.valueSets.length];
|
||||
|
||||
for (var i = 0; i < groupedVals.length; i++) {
|
||||
var val = groupedVals[i],
|
||||
for (let i = 0; i < groupedVals.length; i++) {
|
||||
let val = groupedVals[i],
|
||||
height = (val / this.maxValue) * this.canvas.height;
|
||||
|
||||
this.drawBar(color, x, 0, height);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
};
|
||||
/*eslint-enable*/
|
||||
|
||||
var match;
|
||||
let match;
|
||||
|
||||
$(document).ready(function() {
|
||||
/*eslint-disable no-unused-vars*/
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
(function(app, $) {
|
||||
'use strict';
|
||||
|
||||
var roundToDecimals = function(val, n) {
|
||||
var exponent = n || 2;
|
||||
const roundToDecimals = function(val, n) {
|
||||
const exponent = n || 2;
|
||||
return Math.round(val * Math.pow(10, exponent)) / Math.pow(10, exponent);
|
||||
};
|
||||
|
||||
var addCommasToNumber = function(n) {
|
||||
const addCommasToNumber = function(n) {
|
||||
if (n) {
|
||||
var s = n.toString();
|
||||
const s = n.toString();
|
||||
return s.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
return null;
|
||||
|
@ -195,8 +195,8 @@
|
|||
$stats.empty();
|
||||
|
||||
// figure out the incremental changes since last update
|
||||
var dNodes = info.nodes - stats.currentTurn.nodes;
|
||||
var dTime = info.time - stats.currentTurn.time;
|
||||
const dNodes = info.nodes - stats.currentTurn.nodes;
|
||||
const dTime = info.time - stats.currentTurn.time;
|
||||
|
||||
stats.totalNodes += dNodes;
|
||||
stats.totalTime += dTime;
|
||||
|
@ -218,7 +218,7 @@
|
|||
$('<h5/>').text('Nodes Visited')
|
||||
.appendTo($stats);
|
||||
|
||||
$('<div/>').text(addCommasToNumber(stats.totalTime) + ' ms')
|
||||
$('<div/>').text(`${addCommasToNumber(stats.totalTime)} ms`)
|
||||
.appendTo($stats);
|
||||
$('<h5/>').text('Total Time')
|
||||
.appendTo($stats);
|
||||
|
@ -231,8 +231,8 @@
|
|||
this.$scoreP1Score.text(addCommasToNumber(this.p1Stats.score));
|
||||
this.$scoreP2Score.text(addCommasToNumber(this.p2Stats.score));
|
||||
|
||||
this.$scoreP1Advantage.text(roundToDecimals(this.p1Stats.pWin * 100, 1) + '%');
|
||||
this.$scoreP2Advantage.text(roundToDecimals(this.p2Stats.pWin * 100, 1) + '%');
|
||||
this.$scoreP1Advantage.text(`${roundToDecimals(this.p1Stats.pWin * 100, 1)}%`);
|
||||
this.$scoreP2Advantage.text(`${roundToDecimals(this.p2Stats.pWin * 100, 1)}%`);
|
||||
};
|
||||
|
||||
Match.prototype.resize = function() {
|
||||
|
@ -242,7 +242,7 @@
|
|||
};
|
||||
|
||||
Match.prototype.onPlayerMove = function(move) {
|
||||
var result = this.game.move(move);
|
||||
const result = this.game.move(move);
|
||||
|
||||
if (result && result.captured) {
|
||||
this.onCapturedPiece(result);
|
||||
|
@ -258,10 +258,10 @@
|
|||
};
|
||||
|
||||
Match.prototype.onGameOver = function() {
|
||||
var message = '';
|
||||
let message = '';
|
||||
|
||||
if (this.game.in_checkmate()) {
|
||||
var history = this.game.history({ verbose: true }),
|
||||
let history = this.game.history({ verbose: true }),
|
||||
lastMove = history[history.length - 1];
|
||||
|
||||
if (lastMove) {
|
||||
|
@ -284,14 +284,14 @@
|
|||
};
|
||||
|
||||
Match.prototype.onCapturedPiece = function(result) {
|
||||
var piece;
|
||||
let piece;
|
||||
if (this.game.turn() === this.player1.color) {
|
||||
piece = 'w';
|
||||
} else {
|
||||
piece = 'b';
|
||||
}
|
||||
|
||||
$('#chess__none-captured-' + piece).hide();
|
||||
$(`#chess__none-captured-${piece}`).hide();
|
||||
|
||||
switch (result.captured) {
|
||||
case this.game.PAWN:
|
||||
|
@ -317,25 +317,25 @@
|
|||
break;
|
||||
}
|
||||
|
||||
$('.chess__holding-piece-' + piece).not('.chess__holding-captured')
|
||||
$(`.chess__holding-piece-${piece}`).not('.chess__holding-captured')
|
||||
.first()
|
||||
.addClass('chess__holding-captured');
|
||||
};
|
||||
|
||||
Match.prototype.startNextTurn = function() {
|
||||
// get the moves for the entire game
|
||||
var moves = '';
|
||||
var history = this.game.history({ verbose: true });
|
||||
for (var i = 0; i < history.length; ++i) {
|
||||
var move = history[i];
|
||||
moves += ' ' + move.from + move.to + (move.promotion ? move.promotion : '');
|
||||
let moves = '';
|
||||
const history = this.game.history({ verbose: true });
|
||||
for (let i = 0; i < history.length; ++i) {
|
||||
const move = history[i];
|
||||
moves += ` ${move.from}${move.to}${move.promotion ? move.promotion : ''}`;
|
||||
}
|
||||
var mv = history[history.length - 1];
|
||||
const mv = history[history.length - 1];
|
||||
|
||||
if (mv) {
|
||||
$('<span/>')
|
||||
.addClass('chess__color' + mv.color)
|
||||
.html(history.length + '. ' + mv.piece.toUpperCase() + '' + mv.from + ' ' + mv.to)
|
||||
.addClass(`chess__color${mv.color}`)
|
||||
.html(`${history.length}. ${mv.piece.toUpperCase()}${mv.from} ${mv.to}`)
|
||||
.appendTo(this.$gameHistory);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
};
|
||||
|
||||
Player.prototype.onEngineMessage = function(event) {
|
||||
var line;
|
||||
let line;
|
||||
|
||||
if (event && typeof event === 'object') {
|
||||
line = event.data;
|
||||
|
@ -47,7 +47,7 @@
|
|||
this.onReady();
|
||||
}
|
||||
} else {
|
||||
var match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([qrbk])?/);
|
||||
let match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([qrbk])?/);
|
||||
if (match) {
|
||||
// the AI made a move
|
||||
if (this.onMove) {
|
||||
|
@ -74,24 +74,24 @@
|
|||
};
|
||||
|
||||
Player.prototype.startTurn = function(gameMoves, moveTime) {
|
||||
this.uciCmd('position startpos moves' + (gameMoves || ''));
|
||||
this.uciCmd('go movetime ' + (moveTime || 500));
|
||||
this.uciCmd(`position startpos moves${gameMoves || ''}`);
|
||||
this.uciCmd(`go movetime ${moveTime || 500}`);
|
||||
};
|
||||
|
||||
Player.prototype.setSkillLevel = function(skill) {
|
||||
var clampedSkill = Math.max(0, Math.min(skill, 20));
|
||||
this.uciCmd('setoption name Skill Level value ' + clampedSkill);
|
||||
const clampedSkill = Math.max(0, Math.min(skill, 20));
|
||||
this.uciCmd(`setoption name Skill Level value ${clampedSkill}`);
|
||||
|
||||
// NOTE: Stockfish level 20 does not make errors (intentially),
|
||||
// so these numbers have no effect on level 20.
|
||||
// Level 0 starts at 1
|
||||
var errorProbability = Math.round((clampedSkill * 6.35) + 1);
|
||||
const errorProbability = Math.round((clampedSkill * 6.35) + 1);
|
||||
|
||||
// Level 0 starts at 10
|
||||
var maxError = Math.round((clampedSkill * -0.5) + 10);
|
||||
const maxError = Math.round((clampedSkill * -0.5) + 10);
|
||||
|
||||
this.uciCmd('setoption name Skill Level Maximum Error value ' + maxError);
|
||||
this.uciCmd('setoption name Skill Level Probability value ' + errorProbability);
|
||||
this.uciCmd(`setoption name Skill Level Maximum Error value ${maxError}`);
|
||||
this.uciCmd(`setoption name Skill Level Probability value ${errorProbability}`);
|
||||
};
|
||||
|
||||
Player.prototype.reset = function() {
|
||||
|
@ -101,11 +101,11 @@
|
|||
};
|
||||
|
||||
Player.prototype.setContempt = function(contempt) {
|
||||
this.uciCmd('setoption name Contempt value ' + contempt);
|
||||
this.uciCmd(`setoption name Contempt value ${contempt}`);
|
||||
};
|
||||
|
||||
Player.prototype.setAggressiveness = function(value) {
|
||||
this.uciCmd('setoption name Aggressiveness value ' + value);
|
||||
this.uciCmd(`setoption name Aggressiveness value ${value}`);
|
||||
};
|
||||
|
||||
app.Player = Player;
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
/* globals hljs */
|
||||
/* globals hljs */
|
||||
|
||||
const nButton = document.getElementById('night');
|
||||
const dButton = document.getElementById('day');
|
||||
const codez = document.getElementById('code');
|
||||
const toggleAnimationButton = document.getElementById('toggleAnimations');
|
||||
const buttons = [nButton, dButton, toggleAnimationButton];
|
||||
const bodyEl = document.getElementsByTagName('body')[0];
|
||||
const rootStyle = document.documentElement.style;
|
||||
let vars = [];
|
||||
const nButton = document.getElementById('night');
|
||||
const dButton = document.getElementById('day');
|
||||
const codez = document.getElementById('code');
|
||||
const toggleAnimationButton = document.getElementById('toggleAnimations');
|
||||
const buttons = [nButton, dButton, toggleAnimationButton];
|
||||
const bodyEl = document.getElementsByTagName('body')[0];
|
||||
const rootStyle = document.documentElement.style;
|
||||
let vars = [];
|
||||
|
||||
|
||||
// Set Vars
|
||||
// This will loop over the variables and set them
|
||||
const setVars = function(variables) {
|
||||
'use strict';
|
||||
// Set Vars
|
||||
// This will loop over the variables and set them
|
||||
const setVars = function(variables) {
|
||||
'use strict';
|
||||
|
||||
variables.forEach(function(prop) {
|
||||
rootStyle.setProperty(prop.name, prop.value);
|
||||
});
|
||||
};
|
||||
variables.forEach(function(prop) {
|
||||
rootStyle.setProperty(prop.name, prop.value);
|
||||
});
|
||||
};
|
||||
|
||||
// Get Vars
|
||||
// This will fetch the variables on the root and then
|
||||
// put them in the UI to show their current values
|
||||
const getVars = function(variables) {
|
||||
'use strict';
|
||||
const getVars = function(variables) {
|
||||
'use strict';
|
||||
|
||||
let text = '';
|
||||
variables.forEach(function(prop) {
|
||||
text += `${prop.name}: ${rootStyle.getPropertyValue(prop.name)}`;
|
||||
text += '\n';
|
||||
});
|
||||
let text = '';
|
||||
variables.forEach(function(prop) {
|
||||
text += `${prop.name}: ${rootStyle.getPropertyValue(prop.name)}`;
|
||||
text += '\n';
|
||||
});
|
||||
|
||||
codez.textContent = text;
|
||||
};
|
||||
codez.textContent = text;
|
||||
};
|
||||
|
||||
// Toggle Animations
|
||||
// For a11y reasons we need to provide a way for users
|
||||
// to pause/start all animations.
|
||||
const toggleAnimationz = function(elem) {
|
||||
'use strict';
|
||||
const toggleAnimationz = function(elem) {
|
||||
'use strict';
|
||||
|
||||
if (bodyEl.classList.contains('noAnimations')) {
|
||||
bodyEl.classList.remove('noAnimations');
|
||||
elem.textContent = 'Pause Animations';
|
||||
} else {
|
||||
bodyEl.classList.add('noAnimations');
|
||||
elem.textContent = 'Start Animations';
|
||||
}
|
||||
};
|
||||
if (bodyEl.classList.contains('noAnimations')) {
|
||||
bodyEl.classList.remove('noAnimations');
|
||||
elem.textContent = 'Pause Animations';
|
||||
} else {
|
||||
bodyEl.classList.add('noAnimations');
|
||||
elem.textContent = 'Start Animations';
|
||||
}
|
||||
};
|
||||
|
||||
// Feature Detect Float in noCalc
|
||||
// This will determine if you support floats inside of calc
|
||||
const featureDetectFloatCalc = function() {
|
||||
'use strict';
|
||||
const featureDetectFloatCalc = function() {
|
||||
'use strict';
|
||||
|
||||
const fd = document.getElementById('feature-detection');
|
||||
const noCalc = document.getElementsByClassName('no-rgb-calc')[0];
|
||||
const bc = window.getComputedStyle(fd).getPropertyValue('background-color');
|
||||
const fd = document.getElementById('feature-detection');
|
||||
const noCalc = document.getElementsByClassName('no-rgb-calc')[0];
|
||||
const bc = window.getComputedStyle(fd).getPropertyValue('background-color');
|
||||
|
||||
if (bc === 'rgba(0, 0, 0, 0)' || bc === 'transparent') {
|
||||
noCalc.style.display = 'block';
|
||||
}
|
||||
};
|
||||
if (bc === 'rgba(0, 0, 0, 0)' || bc === 'transparent') {
|
||||
noCalc.style.display = 'block';
|
||||
}
|
||||
};
|
||||
|
||||
// Change custom props to night
|
||||
const changeToNight = function() {
|
||||
'use strict';
|
||||
// Change custom props to night
|
||||
const changeToNight = function() {
|
||||
'use strict';
|
||||
|
||||
nButton.setAttribute('aria-selected', 'true');
|
||||
dButton.setAttribute('aria-selected', 'false');
|
||||
vars = [
|
||||
nButton.setAttribute('aria-selected', 'true');
|
||||
dButton.setAttribute('aria-selected', 'false');
|
||||
vars = [
|
||||
{name: '--sky-start', value: 'rgb(100, 75, 128)'},
|
||||
{name: '--sky-end', value: 'rgb(45, 45, 81)'},
|
||||
{name: '--light-r-mod', value: '-17.5'},
|
||||
|
@ -84,19 +84,19 @@
|
|||
{name: '--park-g-mod', value: '-.20'},
|
||||
{name: '--park-b-mod', value: '-.08'},
|
||||
{name: '--light-source', value: 'url(#moon)'}
|
||||
];
|
||||
setVars(vars);
|
||||
getVars(vars);
|
||||
return;
|
||||
};
|
||||
];
|
||||
setVars(vars);
|
||||
getVars(vars);
|
||||
return;
|
||||
};
|
||||
|
||||
// Change custom props to day
|
||||
const changeToDay = function() {
|
||||
'use strict';
|
||||
const changeToDay = function() {
|
||||
'use strict';
|
||||
|
||||
nButton.setAttribute('aria-selected', 'false');
|
||||
dButton.setAttribute('aria-selected', 'true');
|
||||
vars = [
|
||||
nButton.setAttribute('aria-selected', 'false');
|
||||
dButton.setAttribute('aria-selected', 'true');
|
||||
vars = [
|
||||
{name: '--dog-coat-r-mod', value: 0},
|
||||
{name: '--dog-coat-g-mod', value: 0},
|
||||
{name: '--dog-coat-b-mod', value: 0},
|
||||
|
@ -113,30 +113,30 @@
|
|||
{name: '--light-b-mod', value: 0},
|
||||
{name: '--show-stars', value: 'none'},
|
||||
{name: '--light-source', value: 'rgb(245, 169, 95)'}
|
||||
];
|
||||
setVars(vars);
|
||||
getVars(vars);
|
||||
return;
|
||||
};
|
||||
];
|
||||
setVars(vars);
|
||||
getVars(vars);
|
||||
return;
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
'use strict';
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
'use strict';
|
||||
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
buttons[i].addEventListener('click', function() {
|
||||
if (buttons[i].id === 'night') {
|
||||
changeToNight();
|
||||
} else if (buttons[i].id === 'day') {
|
||||
changeToDay();
|
||||
} else if (buttons[i].id === 'toggleAnimations') {
|
||||
toggleAnimationz(buttons[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
buttons[i].addEventListener('click', function() {
|
||||
if (buttons[i].id === 'night') {
|
||||
changeToNight();
|
||||
} else if (buttons[i].id === 'day') {
|
||||
changeToDay();
|
||||
} else if (buttons[i].id === 'toggleAnimations') {
|
||||
toggleAnimationz(buttons[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Do feature detection for custom props and float support in calc()
|
||||
featureDetectFloatCalc();
|
||||
});
|
||||
featureDetectFloatCalc();
|
||||
});
|
||||
|
||||
// Init Highlight
|
||||
hljs.initHighlightingOnLoad();
|
||||
// Init Highlight
|
||||
hljs.initHighlightingOnLoad();
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15"><path d="M8.2 7.5l5.1 5.1-.7.7-5.1-5.1-5.1 5.1-.7-.7 5.1-5.1-5-5.1.7-.7 5.1 5.1 5.1-5.1.7.7-5.2 5.1z"/></svg>
|
После Ширина: | Высота: | Размер: 172 B |
|
@ -3,20 +3,148 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>[Add a descriptive title here]</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="og:title" content="[Keep short; used as title in any teasers of this demo on dev.microsoftedge.com]">
|
||||
<meta name="description" content="[Used as description in any teasers of this demo on dev.microsoftedge.com]">
|
||||
<meta name="keywords" content="[First value is category for dev.microsoftedge.com/demos, following comma-separated values are tags]">
|
||||
<meta name="author" content="[your Github handle]">
|
||||
|
||||
<!-- Use/uncomment for more straightforward/simple demos, like @supports or css3filters: <link rel="stylesheet" href="https://edgeportal.blob.core.windows.net/media/demotemplate.css"> -->
|
||||
|
||||
<link rel="stylesheet" href="styles/demo.css">
|
||||
<link rel="stylesheet" href="https://az813057.vo.msecnd.net/styles/fonts-full-20180102.css">
|
||||
<link rel="stylesheet" href="styles/demo-template.css">
|
||||
<link rel="stylesheet" href="styles/your-demo-name.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="c-nav-bar">
|
||||
<div class="l-contain c-nav-bar__contain" data-menu>
|
||||
<nav class="c-nav-bar__breadcrumb" aria-label="breadcrumbs">
|
||||
<ul class="u-simple-list">
|
||||
<li class="c-nav-bar__index"><a href="https://developer.microsoft.com/en-us/microsoft-edge/testdrive/" class="c-nav-bar__more">Microsoft Edge Demos</a></li>
|
||||
<li class="c-nav-bar__title"><span class="u-sr-only">Current demo:</span>[Your Title]</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="c-toc">
|
||||
<button class="c-toc__btn" id="js-nav-btn" aria-haspopup="true" aria-expanded="false" aria-controls="js-nav-items" aria-label="Demo contents">
|
||||
Contents <svg class="c-toc__arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12"><path fill="none" stroke="#FFF" stroke-miterlimit="10" d="M12 3L6 9 0 3"/></svg>
|
||||
</button>
|
||||
<ul class="c-toc__items" id="js-nav-items" role="group" aria-hidden="true"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<main role="main">
|
||||
<section class="c-intro">
|
||||
<div class="l-contain">
|
||||
<h1 class="c-intro__heading">[Your title]</h1>
|
||||
<button id="toggle-anim" class="c-toggle-anim" aria-hidden="true" data-pressed-text="Play" data-unpressed-text="Pause"><span class="c-toggle-anim__state">Pause</span> animations</button>
|
||||
</div>
|
||||
</section>
|
||||
<div class="l-contain">
|
||||
<section id="code-style" data-nav-label="Code Style" class="l-section">
|
||||
<h2>Code Style</h2>
|
||||
<p>PRs will be reviewed with respects to the <a href="https://github.com/MicrosoftEdge/Demos/blob/master/CONTRIBUTING.md#code-style-requirements">code guidelines</a> outlined in our contribution demo.</p>
|
||||
</section>
|
||||
|
||||
<p>Whatever you want goes here.</p>
|
||||
<section id="instructions" data-nav-label="Instructions" class="l-section">
|
||||
<h2>Instructions</h2>
|
||||
<ol>
|
||||
<li>Copy this entire <code>demo-template</code> directory and rename it for your demo.</li>
|
||||
<li>Open the <code>config.json</code> in your new directory and delete the line that says <code>"skip": true</code>. This is the line that prevented the demo processor from running on the demo template itself.</li>
|
||||
<li>Rename <code>styles/your-demo-name.css</code> and <code>scripts/your-demo-name.js</code> and update the references in this index file.</li>
|
||||
<li>Fill out the title and metadata within the <code><head></code> of this index file.</li>
|
||||
<li>See notes below on using the required components and (very light) included styles. Have fun!</li>
|
||||
</ol>
|
||||
<section class="l-subsection">
|
||||
<h3>A note on separation of concerns</h3>
|
||||
<p>Scripts and styles in <code>demo-template.*</code> are unlikely to change, with the exception of the feature alert conditions you should add in <code>demo-template.js</code>; code in <code>your-demo-name.*</code> is meant to be customized. If you find yourself wanting to change something in the demo-template files, there should be a good reason for that (bug fixes or meaningful UX improvements instead of preferential changes), and probably a PR so that future demos can get that update, too.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Adds a universal header to the top of the page -->
|
||||
<script src="https://msedgecdn.azurewebsites.net/scripts/demo-header.js"></script>
|
||||
<section id="components" data-nav-label="Required Components" class="l-section">
|
||||
<h2>Required Components</h2>
|
||||
<section class="l-subsection">
|
||||
<h3>Nav Bar</h3>
|
||||
<p>This component appears at the very top of the page. It sets the context for the demo, and provides navigation back to other demos.</p>
|
||||
<p><strong>Overrideable styles</strong> can be found in the <code>COMPONENT: NAV BAR</code> section of <code>demo.css</code>. Do not override anything other than these styles, as it is very important this bar feels consistent from demo to demo. If you think you have a good idea for a universal change to this bar, <a href="https://github.com/MicrosoftEdge/Demos/issues">please file an issue</a>. The mechanism to explore more demos is likely to change.</p>
|
||||
</section>
|
||||
<section class="l-subsection">
|
||||
<h3>Feature-detection alert</h3>
|
||||
<p>As we are providing an experience of new technologies, demos should be querying for feature support and exposing a standardized alert in the case that the feature is missing.</p>
|
||||
<p>Inside the <code>insertAlert()</code> function in the <code>scripts/your-demo-name.js</code> file (whatever you named it to), update the placeholder content with the name(s) of your feature(s), and update the link with the relevant Status URL. If you need to change the verbage slightly to support querying for more than one feature, feel free to do so (links should still have meaningful text, not "learn more" or similar). Then write your support query conditions such that the alert only appears when those conditions are false.</p>
|
||||
</section>
|
||||
<section class="l-subsection">
|
||||
<h3>Demo Contents</h3>
|
||||
<p>This is the dropdown that lives in the nav bar. It is automagically populated with JavaScript based on the sections in your demo. For this to work, your section tags should be formed like this:</p>
|
||||
<pre><code>
|
||||
<section id="your-hash" data-nav-label="Title for Nav" class="l-section"></section>
|
||||
</code></pre>
|
||||
<p>The ID is used for the window hash location (jump link). The <code>data-nav-label</code> is used for the title of this section in the demo navigation. This doesn't have to perfectly match the title of the section, it can be a shorter version if that makes sense for the nav.</p>
|
||||
</section>
|
||||
<section class="l-subsection">
|
||||
<h3>Intro</h3>
|
||||
<p>The large area at the top of the demo. You might consider making this expand to fill the viewport height, but we have left that option open for you.</p>
|
||||
<p><strong>Overrideable styles</strong> can be found in the <code>COMPONENT: INTRO</code> section of <code>demo.css</code>. It's pretty lightweight, so lots of flexibility here!</p>
|
||||
</section>
|
||||
<section class="l-subsection">
|
||||
<h3>Toggle animations button</h3>
|
||||
<p>At the end of the intro is a pause animations button that is affixed to the bottom right corner, which toggles a class of <code>.has-anim</code> on the body. You may remove the button/script in <code>your-demo-name.js</code> if you don't have any animations on your page. If you do have animations, you should add <code>body.has-anim</code> to the beginnings of CSS selectors which add CSS-only animations, or you may add to this function to control JS animations on the page.</p>
|
||||
<section class="l-subsection">
|
||||
<h3>Outro</h3>
|
||||
<p>This is the bar at the bottom of the demo which provides credits for the demo, a link to Github, and will eventually be expanded to include related demos. Fill out the names and URLs (Github preferred) for the contributors, as well as the Github URL.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="included-styles" data-nav-label="Included Styles" class="l-section">
|
||||
<h2>Included Styles</h2>
|
||||
<p>The demo template comes with very minimal styles, as we would like you to feel free to be creative. Here's what's included.</p>
|
||||
|
||||
<section class="l-subsection">
|
||||
<h3>Layout</h3>
|
||||
<p>There are a couple layout classes, denoted by the namespace prefix <code>l-</code>:</p>
|
||||
<ul>
|
||||
<li><code>.l-contain</code> creates a container with a max width and horizontal paddings; it can be used inside or outside of sections (see below). Please do not override these paddings.</li>
|
||||
<li><code>.l-section</code> and <code>.l-subsection</code> add top margins, thereby creating page sections and subsections. If you would like to override the margins on these, you need to have a good reason for doing so.</li>
|
||||
<li><code>.l-section--banner</code> and <code>.l-subsection--banner</code> can be added onto those sectioning classes respectively. These add top and bottom paddings to match their top margins, as well as a light grey background for clarity (it is expected you'll probably override that background color).</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="l-subsection">
|
||||
<h3>Body Copy</h3>
|
||||
<p>Body copy has default styles, top margins, and maximum widths. If a body copy element matches the <code>:first-child</code> selector, the top margin is <code>0</code>. If you change the body copy styles defined here, there should be a good reason to do so.</p>
|
||||
<p>This is a paragraph</p>
|
||||
<ul>
|
||||
<li>This is an unordered list</li>
|
||||
<li>Another list item</li>
|
||||
<li>Yet another list item</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>This is an unordered list</li>
|
||||
<li>Another list item</li>
|
||||
<li>Yet another list item</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="l-subsection">
|
||||
<h3>Utilities</h3>
|
||||
<p>Utilities are denoted by the <code>u-</code> namespace prefix.
|
||||
<ul>
|
||||
<li><code>.u-clear</code>: place this class on a parent and it will clear its children's floats.</li>
|
||||
<li><code>.u-sr-only</code>: visibly hides content, without hiding the content from screen readers.</li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="l-section l-section--banner c-outro" role="contentinfo" aria-label="Demo credits">
|
||||
<div class="l-contain">
|
||||
<div class="c-outro__byline">
|
||||
<p><a href="https://developer.microsoft.com/en-us/microsoft-edge/testdrive/" class="c-nav-bar__more">A demo</a> by Microsoft Edge</p>
|
||||
<p>Contributors: <a href="">[Firstname Lastname]</a>, <a href="">Another Person</a></p>
|
||||
</div>
|
||||
<a href="[Github URL]" class="c-outro__github" aria-label="Explore code on Github">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path fill-rule="evenodd" clip-rule="evenodd" fill="#FFF" d="M10 .2C4.5.2 0 4.7 0 10.2c0 4.4 2.9 8.2 6.8 9.5.5.1.7-.2.7-.5v-1.7c-2.8.6-3.4-1.3-3.4-1.3-.4-1.1-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.6 2.4 1.2 2.9.9.1-.6.3-1.1.6-1.3-2.1-.3-4.5-1.1-4.5-5 0-1.1.4-2 1-2.7-.1-.2-.4-1.2.1-2.6 0 0 .8-.3 2.7 1 .9-.2 1.8-.3 2.6-.3s1.7.1 2.5.3c1.9-1.3 2.7-1 2.7-1 .5 1.4.2 2.4.1 2.6.6.7 1 1.6 1 2.7 0 3.8-2.3 4.7-4.6 4.9.4.3.7.9.7 1.9v2.7c0 .3.2.6.7.5 4-1.3 6.8-5.1 6.8-9.5.1-5.5-4.4-10-9.9-10z"/></svg><span>Explore code</span>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
<script src="scripts/demo-template.js"></script>
|
||||
<script src="scripts/your-demo-name.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
/* eslint-env browser */
|
||||
/* eslint-disable no-var, prefer-template, strict, prefer-arrow-callback, object-shorthand, no-continue */
|
||||
/*globals event*/
|
||||
|
||||
/*
|
||||
* DEMO TEMPLATE SCRIPTS
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* GENERIC JS-ENABLED CLASS ON BODY
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
document.body.classList.add('has-js');
|
||||
}());
|
||||
|
||||
/*
|
||||
* FEATURE SUPPORT ALERT
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* These scripts are written old-school so that they work on older browsers */
|
||||
var closeAlert = function(e) {
|
||||
if (e.target.id === 'dismissFeatureAlert') {
|
||||
var featureAlert = document.getElementById('featureAlert');
|
||||
document.body.removeChild(featureAlert);
|
||||
document.body.classList.remove('has-alert');
|
||||
document.querySelector('.c-nav-bar').focus();
|
||||
}
|
||||
};
|
||||
|
||||
var insertAlert = function() {
|
||||
var featureAlertMsg = '<strong>Notice:</strong> This page demonstrates [feature], which is not supported in your browser version. For the full experience, please view in Microsoft Edge [build #/version info] or <a href="https://status.microsoftedge.com">any browser that supports [feature]</a>.',
|
||||
featureAlert = document.createElement('div');
|
||||
|
||||
featureAlert.className = 'c-alert c-alert--error';
|
||||
featureAlert.setAttribute('role', 'alert');
|
||||
featureAlert.setAttribute('aria-live', 'polite');
|
||||
featureAlert.setAttribute('id', 'featureAlert');
|
||||
|
||||
document.body.insertBefore(featureAlert, document.body.querySelector(':first-child'));
|
||||
document.body.classList.add('has-alert');
|
||||
|
||||
/* Set trivial timeout to trigger aria-live readout cross-browser */
|
||||
setTimeout(function(){
|
||||
featureAlert.innerHTML = '<div class="l-contain c-alert__contain"><p class="c-alert__message">' + featureAlertMsg + '</p><button class="c-alert__dismiss" aria-label="Close alert" aria-controls="featureAlert" id="dismissFeatureAlert"></button></div>';
|
||||
}, 10);
|
||||
|
||||
/* Makes heading focusable by JS, for when alert is cleared */
|
||||
document.querySelector('.c-nav-bar').setAttribute('tabindex', '-1');
|
||||
window.addEventListener('click', closeAlert, false);
|
||||
};
|
||||
|
||||
/* Add your own feature query conditions here, run insertAlert() only if false */
|
||||
insertAlert();
|
||||
}());
|
||||
|
||||
/*
|
||||
* COMPONENT: DEMO NAV
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
/* Generates nav items for each section on the page */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const demoNavItems = document.getElementById('js-nav-items');
|
||||
const pageSections = document.querySelectorAll('[data-nav-label]');
|
||||
|
||||
for (let i = 0; i < pageSections.length; i++) {
|
||||
const section = pageSections[i];
|
||||
const newLink = document.createElement('li');
|
||||
newLink.className = 'c-toc__item';
|
||||
newLink.innerHTML = '<a href="#' + section.getAttribute('id') + '">' + section.getAttribute('data-nav-label') + '</a>';
|
||||
demoNavItems.appendChild(newLink);
|
||||
|
||||
// Smooth scroll TOC links
|
||||
newLink.addEventListener('click', function(e) {
|
||||
const thisHash = e.target.hash,
|
||||
thisID = thisHash.replace('#', '');
|
||||
if (thisID) {
|
||||
e.preventDefault();
|
||||
document.getElementById(thisID).scrollIntoView({block: 'start', behavior: 'smooth'});
|
||||
history.replaceState({}, '', window.location.pathname + thisHash);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
//nav menu
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const menu = document.querySelector('.c-toc__btn');
|
||||
const items = menu.parentElement.querySelector('.c-toc__items');
|
||||
|
||||
const collapse = function () {
|
||||
items.setAttribute('aria-hidden', 'true');
|
||||
menu.setAttribute('aria-expanded', 'false');
|
||||
};
|
||||
|
||||
|
||||
const toggleSection = function (evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
const expanded = evt.currentTarget.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
if (expanded) {
|
||||
collapse();
|
||||
} else {
|
||||
items.removeAttribute('aria-hidden');
|
||||
menu.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
};
|
||||
|
||||
const toggleKeydownSection = function (evt) {
|
||||
const key = evt.which || evt.keyCode;
|
||||
|
||||
if (key !== 32 && key !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleSection(evt);
|
||||
};
|
||||
|
||||
|
||||
menu.addEventListener('click', toggleSection, false);
|
||||
menu.addEventListener('keydown', toggleKeydownSection, false);
|
||||
|
||||
document.addEventListener('click', function () {
|
||||
collapse();
|
||||
});
|
||||
|
||||
const insideContainer = function (item, container) {
|
||||
let result = false;
|
||||
|
||||
while (item) {
|
||||
if (item === container) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
item = item.parentElement; //eslint-disable-line no-param-reassign
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
document.addEventListener('focus', function (evt) {
|
||||
const target = evt.target;
|
||||
const expandedMenus = document.querySelectorAll('.navbar__submenu:not([aria-hidden="true"])');
|
||||
|
||||
if (expandedMenus.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let j = 0, lj = expandedMenus.length; j < lj; j++) {
|
||||
const expandedMenu = expandedMenus[j];
|
||||
|
||||
if (!insideContainer(target, expandedMenu)) {
|
||||
expandedMenu.setAttribute('aria-hidden', 'true');
|
||||
expandedMenu.parentElement.querySelector('[aria-expanded="true"]').removeAttribute('aria-expanded');
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
}());
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var menus = document.querySelectorAll('[data-menu]');
|
||||
|
||||
if (menus.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var findIndex = function (element, elements) {
|
||||
var index, l;
|
||||
|
||||
for (index = 0, l = elements.length; index < l; index++) {
|
||||
if (elements[index] === element) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
var next = function (elements) {
|
||||
return function (index) {
|
||||
if (typeof index === 'number') {
|
||||
var i = index + 1;
|
||||
var element = elements[i];
|
||||
var current = document.activeElement;
|
||||
|
||||
while (element) {
|
||||
element.focus();
|
||||
if (current !== document.activeElement) {
|
||||
break;
|
||||
} else {
|
||||
i++;
|
||||
element = elements[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var previous = function (elements) {
|
||||
return function (index) {
|
||||
if (typeof index === 'number') {
|
||||
var i = index - 1;
|
||||
var element = elements[i];
|
||||
var current = document.activeElement;
|
||||
|
||||
while (element) {
|
||||
element.focus();
|
||||
if (current !== document.activeElement) {
|
||||
break;
|
||||
} else {
|
||||
i--;
|
||||
element = elements[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var findSiblings = function (source, type, topParent) {
|
||||
if (source === topParent) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var parent = source.parentElement;
|
||||
|
||||
var elements = topParent.querySelectorAll(type);
|
||||
|
||||
if (elements.length === 1) {
|
||||
return findSiblings(parent, type, topParent);
|
||||
}
|
||||
|
||||
return elements;
|
||||
};
|
||||
|
||||
var arrowAction = function (action, container) {
|
||||
var activeElement = document.activeElement;
|
||||
var elements = findSiblings(activeElement, activeElement.tagName.toLowerCase(), container);
|
||||
var nextElementTo = action(elements);
|
||||
|
||||
nextElementTo(findIndex(activeElement, elements));
|
||||
};
|
||||
|
||||
var keydown = function (container) {
|
||||
return function () {
|
||||
var key = event.keyCode;
|
||||
var handled = true;
|
||||
|
||||
//right or down
|
||||
if (key === 39 || key === 40) {
|
||||
arrowAction(next, container);
|
||||
//up or left
|
||||
} else if (key === 38 || key === 37) {
|
||||
arrowAction(previous, container);
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
for (var i = 0, l = menus.length; i < l; i++) {
|
||||
var menu = menus[i];
|
||||
|
||||
menu.addEventListener('keydown', keydown(menu), false);
|
||||
}
|
||||
}());
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* NAME OF YOUR DEMO
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* COMPONENT: PAUSE ANIMATIONS BUTTON
|
||||
* Toggles "has-anim" class; CSS selectors and JS
|
||||
* should be written so that animations only run
|
||||
* when this class is present
|
||||
* ----------------------------------------------
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const animButton = document.getElementById('toggle-anim');
|
||||
|
||||
if (animButton) {
|
||||
const toggleAnim = function() {
|
||||
const stateName = animButton.querySelector('.c-toggle-anim__state');
|
||||
if (animButton.getAttribute('aria-pressed') === 'true') {
|
||||
console.log('animations were off');
|
||||
animButton.setAttribute('aria-pressed', 'false');
|
||||
stateName.innerText = animButton.getAttribute('data-unpressed-text');
|
||||
document.body.classList.add('has-anim');
|
||||
} else {
|
||||
console.log('animations were on');
|
||||
animButton.setAttribute('aria-pressed', 'true');
|
||||
stateName.innerText = animButton.getAttribute('data-pressed-text');
|
||||
document.body.classList.remove('has-anim');
|
||||
}
|
||||
};
|
||||
|
||||
const showAnimButton = function() {
|
||||
document.body.classList.add('has-anim');
|
||||
animButton.removeAttribute('aria-hidden');
|
||||
animButton.setAttribute('aria-pressed', 'false');
|
||||
animButton.addEventListener('click', toggleAnim, false);
|
||||
};
|
||||
|
||||
showAnimButton();
|
||||
}
|
||||
}());
|
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
* DEMO TEMPLATE STYLES
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font: 400 100%/1.4 base, "Segoe UI", Segoe, "Segoe WP", "Lucida Grande", "Lucida Sans", Verdana, sans-serif;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
text-underline-offset: 1px;
|
||||
text-decoration-skip: ink;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (min-width: 80em) {
|
||||
html {
|
||||
font-size: 112.5%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 120em) {
|
||||
html {
|
||||
font-size: 118.75%;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LAYOUT
|
||||
* ---------------------------------------------
|
||||
* @NOTE: The layout margins and paddings are in
|
||||
* rem (mostly) so that changing the font size
|
||||
* of a layout element doesn't change those
|
||||
* measurements. Vertical measurements in the
|
||||
* mobile-first experience are in em.
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.l-contain {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding-right: 1.25rem;
|
||||
padding-left: 1.25rem;
|
||||
max-width: 960px;
|
||||
max-width: 100rem;
|
||||
}
|
||||
|
||||
.l-section {
|
||||
margin-top: 3.5em;
|
||||
}
|
||||
|
||||
.l-section--banner,
|
||||
.c-intro {
|
||||
padding-top: 3.5em;
|
||||
padding-bottom: 3.5em;
|
||||
}
|
||||
|
||||
.l-subsection {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.l-subsection--banner {
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.l-section--banner + .l-section--banner,
|
||||
.l-subsection--banner + .l-subsection--banner {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 36em) {
|
||||
.l-contain {
|
||||
padding-right: 3rem;
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.l-section {
|
||||
margin-top: 6rem;
|
||||
}
|
||||
|
||||
.l-subsection--banner,
|
||||
.c-intro {
|
||||
padding-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
}
|
||||
|
||||
.l-subsection {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.l-subsection--banner {
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.l-section--banner + .l-section--banner,
|
||||
.l-subsection--banner + .l-subsection--banner {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 60em) {
|
||||
.l-contain {
|
||||
padding-right: 6rem;
|
||||
padding-left: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BODY TYPE
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
p, ul, ol {
|
||||
margin-top: 1em;
|
||||
max-width: 44rem;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
padding-left: 1.25em;
|
||||
}
|
||||
|
||||
p:first-child, ul:first-child, ol:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
li + li {
|
||||
margin-top: .625em;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/*
|
||||
* UTILITIES
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
/* Clear floated elements */
|
||||
.u-clear::before,
|
||||
.u-clear::after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
|
||||
.u-clear::after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Hide element visually (not from screen reader) */
|
||||
.u-sr-only {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Simple list */
|
||||
.u-simple-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: NAV BAR
|
||||
* @NOTE: These styles are not intended to be
|
||||
* changed by demo authors. For those styles,
|
||||
* see demo.css
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-nav-bar {
|
||||
position: fixed;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
font-size: .813em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb {
|
||||
position: relative;
|
||||
z-index: 9000; /* Higher than demo TOC */
|
||||
margin-right: 9em;
|
||||
max-width: none;
|
||||
padding: .75em 1.25rem;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb li {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb li + li {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.c-nav-bar__title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.c-toc {
|
||||
position: absolute;
|
||||
z-index: 8890; /* Unnecessarily high just in case… */
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* If alert present above nav, change layout */
|
||||
.has-alert .c-toc {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.c-toc__btn {
|
||||
float: right;
|
||||
padding: 1.5em 1.25rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Focus styles are in your-demo-name.css */
|
||||
.c-toc__btn:hover,
|
||||
.c-toc__btn:focus,
|
||||
.c-toc__item a:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.c-toc__btn:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.c-toc__arrow {
|
||||
margin-left: .5em;
|
||||
transform: translateY(.1em);
|
||||
}
|
||||
|
||||
.c-toc__items {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 4.5em);
|
||||
overflow: auto;
|
||||
clear: both;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.c-toc__items[aria-hidden="true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.c-toc__item {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.c-toc__item a {
|
||||
display: block;
|
||||
padding: 1em 1.25rem;
|
||||
text-decoration: none;
|
||||
transition: background-color ease-out 400ms;
|
||||
}
|
||||
|
||||
.c-toc__item a:hover,
|
||||
.c-toc__item a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 36em) {
|
||||
.c-nav-bar__contain {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 36em) {
|
||||
.c-nav-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb {
|
||||
margin-right: 13em;
|
||||
padding: .75rem 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.c-nav-bar__index::after {
|
||||
padding: .5em;
|
||||
content: "\005C"; /* Backslash */
|
||||
}
|
||||
|
||||
.c-toc {
|
||||
position: fixed;
|
||||
right: 3rem;
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
.c-toc__btn,
|
||||
.c-toc__items {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.c-toc__btn,
|
||||
.c-toc__item a {
|
||||
padding: .75rem;
|
||||
}
|
||||
|
||||
.c-toc__btn {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.c-toc__items {
|
||||
max-height: calc(100vh - 3em);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.c-nav-bar {
|
||||
font-size: .938em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 60em) {
|
||||
.c-toc {
|
||||
right: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 112em) {
|
||||
/* Align toc to edge of contents whenever .l-contain maxes out */
|
||||
.c-toc {
|
||||
right: calc(50vw - 44rem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: ALERT
|
||||
* Only used for the feature-detection area for
|
||||
* now, but built as a component in case we want
|
||||
* to allow for reuse elsewhere
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-alert {
|
||||
position: relative;
|
||||
z-index: 9000;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.c-alert__contain {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
max-width: 100rem;
|
||||
}
|
||||
|
||||
/* Add side padding if not already on the element from .l-contain */
|
||||
.c-alert__contain:not(.l-contain) {
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.c-alert a:link,
|
||||
.c-alert a:visited {
|
||||
display: inline-block;
|
||||
color: #0067b8;
|
||||
}
|
||||
|
||||
.c-alert__message {
|
||||
margin: 0;
|
||||
max-width: 44rem;
|
||||
padding: 1em 0;
|
||||
padding: 1rem 0;
|
||||
font-size: .813em;
|
||||
}
|
||||
|
||||
.c-alert--error a:link,
|
||||
.c-alert--error a:visited {
|
||||
color: #005da6;
|
||||
}
|
||||
|
||||
.c-alert__dismiss {
|
||||
margin-left: 1em;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
background: url("../images/x.svg") no-repeat center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.c-alert__dismiss:hover,
|
||||
.c-alert__dismiss:focus {
|
||||
outline: 2px solid hsla(0, 0%, 0%, .4);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.c-alert__dismiss:active {
|
||||
background-color: hsla(0, 0%, 0%, .2);
|
||||
}
|
||||
|
||||
@media (min-width: 36em) {
|
||||
.c-alert__dismiss {
|
||||
margin-right: -1em;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: TOGGLE ANIMATIONS BUTTON
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-toggle-anim {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 8880;
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
font-size: .875em;
|
||||
}
|
||||
|
||||
.c-toggle-anim__state {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
body.has-js .c-toggle-anim {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: OUTRO
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-outro {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.c-outro__byline p {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
max-width: 24em;
|
||||
font-size: .875em;
|
||||
}
|
||||
|
||||
.c-outro__byline p + p {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.c-outro__github {
|
||||
display: inline-block;
|
||||
margin-top: 2em;
|
||||
padding: .5em .75em;
|
||||
border: 1px solid transparent;
|
||||
line-height: 1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.c-outro__github:hover,
|
||||
.c-outro__github:focus {
|
||||
border-color: hsla(0, 0%, 0%, .4);
|
||||
}
|
||||
|
||||
.c-outro__github svg,
|
||||
.c-outro__github span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.c-outro__github svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.c-outro__github span {
|
||||
margin-left: .5em;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* NAME OF YOUR DEMO
|
||||
* =============================================
|
||||
* @Dependencies:
|
||||
* @Note:
|
||||
* @TODO:
|
||||
*/
|
||||
|
||||
/*
|
||||
* A SECTION OF YOUR STYLES
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
/* Short Comment */
|
||||
|
||||
/*
|
||||
Long form Comment
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
*/
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* NAME OF YOUR DEMO
|
||||
* =============================================
|
||||
* @Dependencies:
|
||||
* @Note:
|
||||
* @TODO:
|
||||
*/
|
||||
|
||||
/* DO NOT remove focus altogether, just style to your colors */
|
||||
:focus {
|
||||
outline: 1px dotted #000;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: #0078d7;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #0078d7;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: #0078d7;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/*
|
||||
* FORM ELEMENTS
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
button {
|
||||
padding: .5em .75em;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
font: inherit;
|
||||
-webkit-appearance: none;
|
||||
background-color: #ccc;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus {
|
||||
outline: 2px solid hsla(0, 0%, 0%, .4);
|
||||
outline-offset: 0;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
/*
|
||||
* UNIVERSAL DEMO-SPECIFIC STYLES
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* A SECTION OF YOUR STYLES
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
/* Short Comment */
|
||||
|
||||
/*
|
||||
Long form Comment
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DEMO SECTION STYLES
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/* Short Comment */
|
||||
|
||||
/*
|
||||
Long form Comment
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
*/
|
||||
|
||||
/*
|
||||
* UNIVERSAL COMPONENTS
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* COMPONENT: NAV BAR
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-nav-bar {
|
||||
background: #000;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.c-nav-bar a {
|
||||
color: #fff;
|
||||
border-bottom-color: rgba(255, 255, 255, .66);
|
||||
}
|
||||
|
||||
/* DO NOT remove focus altogether, just style to your colors */
|
||||
.c-nav-bar__breadcrumb a:focus {
|
||||
outline: 1px dotted #fff;
|
||||
}
|
||||
|
||||
/* Only used in mobile-first design */
|
||||
.c-nav-bar__breadcrumb {
|
||||
border-bottom-color: #444;
|
||||
}
|
||||
|
||||
.c-nav-bar__title {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* TABLE OF CONTENTS DROPDOWN */
|
||||
|
||||
.c-toc__btn {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.c-toc__btn:hover,
|
||||
.c-toc__btn:focus {
|
||||
background: #222;
|
||||
}
|
||||
|
||||
.c-toc__btn:active {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.c-toc__arrow path {
|
||||
stroke: #fff;
|
||||
}
|
||||
|
||||
.c-toc__items {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.c-toc__item a:hover,
|
||||
.c-toc__item a:focus {
|
||||
background: #222;
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: INTRO
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-intro {
|
||||
background: #f9f9f9;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* LAYOUT: "BANNER" SECTIONS
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.l-section--banner,
|
||||
.l-subsection--banner {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.l-section--bannert a:link,
|
||||
.l-section--banner a:visited,
|
||||
.l-subsection--banner a:link,
|
||||
.l-subsection--banner a:visited {
|
||||
color: #0067b8;
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: OUTRO
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-outro a {
|
||||
color: #006fc6;
|
||||
}
|
||||
|
||||
.c-outro a:hover {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
a.c-outro__github {
|
||||
background: #0078d7;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a.c-outro__github:hover {
|
||||
background: #006cc2;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a.c-outro__github:active {
|
||||
background: #005497;
|
||||
}
|
|
@ -311,7 +311,12 @@
|
|||
this.sendMediaSegment();
|
||||
return;
|
||||
}
|
||||
if (this.vid.currentTime + this.MAX_BUFFER <= end) {
|
||||
var maxBuffer = this.MAX_BUFFER;
|
||||
if (this.vid.playbackRate > 1) {
|
||||
maxBuffer *= this.vid.playbackRate;
|
||||
}
|
||||
|
||||
if (this.vid.currentTime + maxBuffer <= end) {
|
||||
return;
|
||||
}
|
||||
this.appending = true;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<!-- DEMO CONTENT -->
|
||||
<div id="alert-banner" class="section section--alert">
|
||||
<div class="container">
|
||||
<p class="title">Demo requires features supported by Microsoft Edge & access to microphone.</p>
|
||||
<p class="title">Demo requires features supported by Microsoft Edge & access to microphone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<section id="demo-banner" class="section section--demo-mic" style="display:none">
|
||||
|
|
12
package.json
|
@ -1,12 +1,14 @@
|
|||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-eslint": "^19.0.0",
|
||||
"load-grunt-tasks": "^3.5.0",
|
||||
"time-grunt": "^1.3.0"
|
||||
"eslint": "^4.14.0",
|
||||
"stylelint": "^8.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
"lint:css": "stylelint",
|
||||
"lint:css:all": "stylelint -- \"**/*.css\"",
|
||||
"lint:js": "eslint --config .eslintrc.json --ignore-path .eslintignore",
|
||||
"lint:js:all": "npm run lint:js -- \"**/*.js\"",
|
||||
"test": "npm run lint:js:all"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,22 +3,22 @@ addEventListener('load', function() {
|
|||
'use strict';
|
||||
|
||||
//Helper functions
|
||||
var $ = function(selector) {
|
||||
const $ = function(selector) {
|
||||
return Array.prototype.slice.call(document.querySelectorAll(selector));
|
||||
};
|
||||
|
||||
var getBody = function(source) {
|
||||
return (source + '')
|
||||
const getBody = function(source) {
|
||||
return (`${source}`)
|
||||
.replace(/^.*?\{.*\n*/, '')
|
||||
.replace(/\s*\}\s*$/, '');
|
||||
};
|
||||
|
||||
var normalize = function(source, indention) {
|
||||
var string = (source + '');
|
||||
var body = getBody(string);
|
||||
var oldIndent = (/^[\t ]+/).exec(body)[0];
|
||||
var newIndent = Array((indention || 0) + 1).join(' ');
|
||||
var newBody = body.replace(RegExp('^' + oldIndent, 'gm'), newIndent);
|
||||
const normalize = function(source, indention) {
|
||||
const string = (`${source}`);
|
||||
const body = getBody(string);
|
||||
const oldIndent = (/^[\t ]+/).exec(body)[0];
|
||||
const newIndent = Array((indention || 0) + 1).join(' ');
|
||||
const newBody = body.replace(RegExp(`^${oldIndent}`, 'gm'), newIndent);
|
||||
return string
|
||||
.replace(body, newBody)
|
||||
.replace(/\bfunction\s+\(/g, 'function(')
|
||||
|
@ -27,12 +27,12 @@ addEventListener('load', function() {
|
|||
.replace(/\t/g, '\xa0\xa0');
|
||||
};
|
||||
|
||||
var getSource = function(func) {
|
||||
const getSource = function(func) {
|
||||
return getBody(normalize(func, 0))
|
||||
.replace(/\bGlobal\./g, '');
|
||||
};
|
||||
|
||||
var warning = document.getElementById('not-supported');
|
||||
const warning = document.getElementById('not-supported');
|
||||
|
||||
//Show message if the browser supports the Payment Request API
|
||||
if (!('PaymentRequest' in window)) {
|
||||
|
@ -40,9 +40,9 @@ addEventListener('load', function() {
|
|||
warning.innerHTML = '<p>This browser does not support web payments. You should try <a href="https://microsoft.com/windows/microsoft-edge">Microsoft Edge</a>, or <a href="http://caniuse.com/#search=Payment%20Request%20API">other browsers</a> that support them.</p>';
|
||||
}
|
||||
|
||||
var shippingOptionChangeHandlerString = '\n\nvar onShippingOptionChange = ' + normalize(Global.onShippingOptionChange, 2) + ';',
|
||||
shippingAddressHandlerString = '\n\nvar onShippingAddressChange = ' + normalize(Global.onShippingAddressChange, 2) + ';',
|
||||
getShippingOptionsString = '\n\nvar onShippingOptionChange = ' + normalize(Global.getShippingOptions, 2) + ';';
|
||||
let shippingOptionChangeHandlerString = `\n\nvar onShippingOptionChange = ${normalize(Global.onShippingOptionChange, 2)};`,
|
||||
shippingAddressHandlerString = `\n\nvar onShippingAddressChange = ${normalize(Global.onShippingAddressChange, 2)};`,
|
||||
getShippingOptionsString = `\n\nvar onShippingOptionChange = ${normalize(Global.getShippingOptions, 2)};`;
|
||||
|
||||
//Loading the same code into the HTML
|
||||
document.getElementById('static-shipping-sample').textContent = (
|
||||
|
@ -71,7 +71,7 @@ addEventListener('load', function() {
|
|||
//Expand/minimize code sample height
|
||||
$('.code-expander').forEach(function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
var currButton = event.target,
|
||||
let currButton = event.target,
|
||||
codeSample = document.getElementById(currButton.dataset.sample).parentNode;
|
||||
|
||||
currButton.textContent = currButton.classList.contains('activated') ? 'Expand code sample' : 'Minimize code sample';
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
/*eslint-env es6 */
|
||||
(function () {
|
||||
'use strict';
|
||||
// Testing for browser support
|
||||
var speechSynthesisSupported = 'speechSynthesis' in window;
|
||||
|
||||
var isPaused = false;
|
||||
var isPlaying = false;
|
||||
// Testing for browser support
|
||||
const speechSynthesisSupported = 'speechSynthesis' in window;
|
||||
|
||||
let isPaused = false;
|
||||
let isPlaying = false;
|
||||
|
||||
// Getting html elements
|
||||
var supportMessageEle = document.getElementById('support-message');
|
||||
var speakBtn = document.getElementById('speak-btn');
|
||||
var pauseresumeBtn = document.getElementById('pauseresume-btn');
|
||||
var cancelBtn = document.getElementById('cancel-btn');
|
||||
var textToSpeechEle = document.getElementById('text-to-speech');
|
||||
var voiceSelect = document.getElementById('voice');
|
||||
var langSelect = document.getElementById('language');
|
||||
var volumeRange = document.getElementById('volume');
|
||||
var rateRange = document.getElementById('rate');
|
||||
const supportMessageEle = document.getElementById('support-message');
|
||||
const speakBtn = document.getElementById('speak-btn');
|
||||
const pauseresumeBtn = document.getElementById('pauseresume-btn');
|
||||
const cancelBtn = document.getElementById('cancel-btn');
|
||||
const textToSpeechEle = document.getElementById('text-to-speech');
|
||||
const voiceSelect = document.getElementById('voice');
|
||||
const langSelect = document.getElementById('language');
|
||||
const volumeRange = document.getElementById('volume');
|
||||
const rateRange = document.getElementById('rate');
|
||||
// var pitchRange = document.getElementById('pitch');
|
||||
var speechStatus = document.getElementById('speech-status');
|
||||
const speechStatus = document.getElementById('speech-status');
|
||||
|
||||
var log = function (message) {
|
||||
const log = function (message) {
|
||||
console.log(`${message}<br/>`);
|
||||
};
|
||||
|
||||
|
@ -33,19 +34,19 @@
|
|||
|
||||
// Loading available voices for this browser/platform
|
||||
// And displaying them into the combobox
|
||||
var loadVoices = function () {
|
||||
var voices = speechSynthesis.getVoices();
|
||||
const loadVoices = function () {
|
||||
const voices = speechSynthesis.getVoices();
|
||||
|
||||
voices.forEach((voice) => {
|
||||
var option = document.createElement('option');
|
||||
const option = document.createElement('option');
|
||||
option.value = voice.name;
|
||||
option.innerHTML = voice.name;
|
||||
voiceSelect.appendChild(option);
|
||||
});
|
||||
};
|
||||
|
||||
var speak = function (textToSpeech) {
|
||||
var synUtterance = new SpeechSynthesisUtterance();
|
||||
const speak = function (textToSpeech) {
|
||||
const synUtterance = new SpeechSynthesisUtterance();
|
||||
synUtterance.text = textToSpeech;
|
||||
if (voiceSelect.value) {
|
||||
synUtterance.voice = speechSynthesis
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
Variable Font Guide
|
||||
-------------------------------
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
Intersection Observor Polyfill
|
||||
-------------------------------
|
||||
[Intersection Observor Polyfill](https://github.com/w3c/IntersectionObserver) used under the [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document)
|
||||
|
||||
Decovar Font
|
||||
-------------------------------
|
||||
Copyright TypeNetwork by David Berlow
|
После Ширина: | Высота: | Размер: 27 KiB |
После Ширина: | Высота: | Размер: 62 KiB |
После Ширина: | Высота: | Размер: 163 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="18.1" height="33.4"><path fill="none" stroke="#424F5E" stroke-width="2" stroke-miterlimit="10" d="M.7.7l16 16-16 16"/></svg>
|
После Ширина: | Высота: | Размер: 171 B |
После Ширина: | Высота: | Размер: 255 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="18.1" height="33.4"><path fill="none" stroke="#424F5E" stroke-width="2" stroke-miterlimit="10" d="M17.6.7l-16 16 16 16"/></svg>
|
После Ширина: | Высота: | Размер: 174 B |
После Ширина: | Высота: | Размер: 9.5 KiB |
После Ширина: | Высота: | Размер: 162 B |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 112 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15"><path d="M8.2 7.5l5.1 5.1-.7.7-5.1-5.1-5.1 5.1-.7-.7 5.1-5.1-5-5.1.7-.7 5.1 5.1 5.1-5.1.7.7-5.2 5.1z"/></svg>
|
После Ширина: | Высота: | Размер: 172 B |
|
@ -0,0 +1,687 @@
|
|||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Variable Fonts Demo | Microsoft Edge Demos</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="og:title" content="Variable Fonts">
|
||||
<meta name="description" content="OpenType Font Variations make it possible to access multiple typefaces within a family from a single resource. Take an expedition into the typographical variety available via variable fonts">
|
||||
<meta name="keywords" content="CSS, web typography">
|
||||
<meta name="author" content="melanierichards, gregwhitworth, FremyCompany">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:site" content="@msedgedev">
|
||||
<meta name="twitter:title" content="Variable Fonts Demo">
|
||||
<meta name="twitter:description" content="OpenType Font Variations make it possible to access multiple typefaces within a family from a single resource. Take an expedition into the typographical variety available via variable fonts">
|
||||
<meta name="twitter:image" content="images/social-image.jpg">
|
||||
|
||||
<meta property="og:title" content="Variable Fonts Demo">
|
||||
<meta property="og:description" content="OpenType Font Variations make it possible to access multiple typefaces within a family from a single resource. Take an expedition into the typographical variety available via variable fonts">
|
||||
<meta property="og:site_name" content="Microsoft Edge Demos">
|
||||
<meta property="og:locale" content="en_US">
|
||||
<meta property="og:image" content="images/social-image.jpg">
|
||||
|
||||
<link rel="stylesheet" href="https://use.typekit.net/gcs2hsx.css">
|
||||
<link rel="stylesheet" href="https://az813057.vo.msecnd.net/testdrive/var-fonts/font-declarations.css">
|
||||
<link rel="stylesheet" href="styles/demo-template.css">
|
||||
<link rel="stylesheet" href="styles/var-fonts.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="c-nav-bar">
|
||||
<div class="l-contain c-nav-bar__contain" data-menu>
|
||||
<nav class="c-nav-bar__breadcrumb" aria-label="breadcrumbs">
|
||||
<ul class="u-simple-list">
|
||||
<li class="c-nav-bar__index"><a href="https://developer.microsoft.com/en-us/microsoft-edge/testdrive/" class="c-nav-bar__more">Microsoft Edge Demos</a></li>
|
||||
<li class="c-nav-bar__title"><span class="u-sr-only">Current demo: </span>Variable Fonts</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="c-toc">
|
||||
<button class="c-toc__btn" id="js-nav-btn" aria-haspopup="true" aria-expanded="false" aria-controls="js-nav-items" aria-label="Demo contents">
|
||||
Contents <svg class="c-toc__arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12"><path fill="none" stroke="#FFF" stroke-miterlimit="10" d="M12 3L6 9 0 3"/></svg>
|
||||
</button>
|
||||
<ul class="c-toc__items" id="js-nav-items" role="group" aria-hidden="true"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<main role="main">
|
||||
<div class="intro">
|
||||
<div class="l-contain">
|
||||
<section class="intro__section">
|
||||
<div class="intro__masthead">
|
||||
<h1 class="intro__heading">
|
||||
<span aria-label="Variable Fonts">
|
||||
<span aria-hidden="true" class="intro__var-1">Var</span><span aria-hidden="true" class="intro__var-2">iab</span><span aria-hidden="true" class="intro__var-3">le</span>
|
||||
<span aria-hidden="true">Fonts</span>
|
||||
</span>
|
||||
</h1>
|
||||
<p class="h4 intro__subheading">An exploration of expressive, performant typography</p>
|
||||
</div>
|
||||
<div class="intro__actions">
|
||||
<a class="poem-start" href="#poem">
|
||||
Begin expedition
|
||||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><circle fill="none" stroke="#424F5E" stroke-width="2" stroke-miterlimit="10" cx="12" cy="12" r="11"/><path fill="none" stroke="#424F5E" stroke-width="2" stroke-miterlimit="10" d="M18.5 9.8L12 16.3 5.5 9.8"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<button id="toggle-anim" class="c-toggle-anim" aria-hidden="true" data-pressed-text="Play" data-unpressed-text="Pause"><span class="c-toggle-anim__state">Pause</span> animations</button>
|
||||
<!-- POEM: SPAN SOUP! :D -->
|
||||
<section id="poem" data-nav-label="Poem demo" class="intro__section">
|
||||
<div class="poem-viewer">
|
||||
<div class="poem">
|
||||
<div class="poem__slide">
|
||||
<h2 class="poem__masthead">
|
||||
<span class="poem__masthead-prefix">An excerpt from</span>
|
||||
<span class="poem__masthead-title">The Rime of the Ancient Mariner</span>
|
||||
</h2>
|
||||
<p class="poem__byline">By Samuel Coleridge</p>
|
||||
<svg aria-hidden="true" class="poem__anchor" xmlns="http://www.w3.org/2000/svg" width="15" height="20"><g fill="none" stroke="#424F5E"><g stroke-miterlimit="10"><path d="M7.5 19.5v-16M2.5 7.5h10"/></g><path stroke-miterlimit="2" d="M11.4 14.1l2.8-1.1c0 4.4-2.9 6.6-6.5 6.6h-.4C3.7 19.6.8 17.5.8 13l2.8 1.1"/><circle stroke-miterlimit="2" cx="7.5" cy="2" r="1.5"/></g></svg>
|
||||
<p class="poem__description">Variable fonts open a wider range of typographic flexibility on the web. We can even animate typographic changes: for example, key words from this classic Arctic misadventure…</p>
|
||||
</div>
|
||||
<div class="poem__slide">
|
||||
<p class="poem__stanza" aria-label="And now the STORM-BLAST came, and he was tyrannous and strong: he struck with his o’ertaking wings, and chased us south along.">
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>now</span> <span>the</span>
|
||||
<span class="boldish">STORM-BLAST</span>
|
||||
<span>came,</span> <span>and</span> <span>he</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>Was</span>
|
||||
<span class="bolden">tyrannous</span>
|
||||
<span>and</span>
|
||||
<span class="bolden">strong:</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>He</span> <span>struck</span> <span>with</span> <span>his</span> <span>o’ertaking</span> <span>wings,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>chased</span> <span>us</span> <span>south</span> <span>along.</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="poem__slide">
|
||||
<p class="poem__stanza" aria-label="With sloping masts and dipping prow, as who pursued with yell and blow, still treads the shadow of his foe, and forward bends his head, the ship drove fast, loud roared the blast, and southward aye we fled.">
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>With</span> <span>sloping</span> <span>masts</span> <span>and</span> <span>dipping</span> <span>prow,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>As</span> <span>who</span> <span>pursued</span> <span>with</span>
|
||||
<span class="bolden">yell</span>
|
||||
<span>and</span> <span>blow</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>Still</span> <span>treads</span> <span>the</span> <span>shadow</span> <span>of</span> <span>his</span> <span>foe,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>forward</span> <span>bends</span> <span>his</span> <span>head,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>The</span> <span>ship</span> <span>drove</span> <span>fast,</span> <span>loud</span>
|
||||
<span class="bolden">roared</span>
|
||||
<span>the</span> <span>blast,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>southward</span> <span>aye</span> <span>we</span>
|
||||
<span>fled.</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="poem__slide">
|
||||
<p class="poem__stanza" aria-label="And now there came both mist and snow, and it grew wondrous cold: and ice, mast-high, came floating by, as green as emerald.">
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>now</span> <span>there</span> <span>came</span> <span>both</span>
|
||||
<span>mist</span> <span>and</span> <span>snow,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>it</span> <span>grew</span>
|
||||
<span class="boldish">wondrous</span> <span>cold:</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>ice,</span> <span>mast-high,</span> <span>came</span> <span>floating</span> <span>by,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>As</span> <span>green</span> <span>as</span> <span>emerald.</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="poem__slide">
|
||||
<p class="poem__stanza" aria-label="The land of ice, and of fearful sounds where no living thing was to be seen.">
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>The</span> <span>land</span> <span>of</span> <span>ice,</span> <span>and</span> <span>of</span> <span>fearful</span> <span>sounds</span> <span>where</span> <span>no</span> <span>living</span> <span>thing</span> <span>was</span> <span>to</span> <span>be</span> <span>seen.</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="poem__stanza" aria-label="And through the drifts the snowy clifts did send a dismal sheen: nor shapes of men nor beasts we ken—the ice was all between. The ice was here, the ice was there, the ice was all around: it cracked and growled, and roared and howled, like noises in a swound!">
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>And</span> <span>through</span> <span>the</span> <span>drifts</span> <span>the</span> <span>snowy</span> <span>clifts</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>Did</span> <span>send</span> <span>a</span> <span>dismal</span> <span>sheen:</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>Nor</span> <span>shapes</span> <span>of</span> <span>men</span> <span>nor</span> <span>beasts</span> <span>we</span> <span>ken—</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>The</span> <span>ice</span> <span>was</span> <span>all</span> <span>between.</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="poem__slide">
|
||||
<p class="poem__stanza" aria-label="The ice was here, the ice was there, the ice was all around: it cracked and growled, and roared and howled, like noises in a swound!">
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>The</span> <span>ice</span> <span>was</span> <span>here,</span> <span>the</span> <span>ice</span> <span>was</span> <span>there,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>The</span> <span>ice</span> <span>was</span> <span>all</span> <span>around:</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>It</span>
|
||||
<span class="space-out">cracked</span>
|
||||
<span>and</span>
|
||||
<span class="bolden">growled,</span>
|
||||
<span>and</span>
|
||||
<span class="bolden">roared</span>
|
||||
<span>and</span>
|
||||
<span class="space-out">howled,</span>
|
||||
</span>
|
||||
<span class="poem__line" aria-hidden="true">
|
||||
<span>Like</span> <span>noises</span> <span>in</span> <span>a</span> <span>swound!</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<svg aria-hidden="true" class="ice-floes" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 1366 700" width="1366" height="700" preserveAspectRatio="xMidYMid meet">
|
||||
<rect fill="transparent" stroke="transparent" x="0" y="0" width="1366" height="700" class="svg-center" />
|
||||
<path fill="#F2F3F4" stroke="#F2F3F4" d="M1069.8 646.3l83.2-6.4 74.7-155.7-.2-2.4-174.5-76.6-163.2 100-31.5 157.9 74.7 13.7z"/>
|
||||
<path fill="#E5EBF0" stroke="#E5EBF0" d="M1215.1 342.1l6.3-63.2 6.3-88.4-102.1-112.7-84.2-4.2 25.3 131.6-13.7 200 174.5 76.6z"/>
|
||||
<path fill="#D5E3EE" stroke="#D5E3EE" d="M1062.5 266.3l4.2-61.1-25.3-131.6-129.5-56.8-29.4 12.6L838.3-.1l-94.8 266.4z"/>
|
||||
<path fill="#E5EBF0" stroke="#E5EBF0" d="M890.9 504.6h-.6l.2.2zM890.3 504.6l-20.5-20.4-138.9 2.1-11.6-4.2-33.7-9.5-27.3-13.7-46.4 7.4 10.6 61 38.8 136.8 162.2 7.4 34.8-8.4 31.5-157.9.7-.4z"/>
|
||||
<path fill="#E8E8E8" stroke="#E8E8E8" d="M890.9 504.6l162.1-99.4 9.5-138.9h-319l2.1 75.8-14.7 28.4v115.8l138.9-2.1 20.5 20.4"/>
|
||||
<path fill="#F2F3F4" stroke="#F2F3F4" d="M685.6 472.6l33.7 9.5 11.6 4.2V370.5l14.7-28.4-2.1-75.8 29.6-83.1-192.7 8.3-23.2 183.2 54.7 91.6 46.4-7.4z"/>
|
||||
<path fill="#C7D4DE" stroke="#C7D4DE" d="M500.4 432.6l-79 6.3 12.1 260.9.6.1 161-38.9 66.2 3.1-38.8-136.8-10.6-61-27.7-46.4-47 19z"/>
|
||||
<path fill="#D5E3EE" stroke="#D5E3EE" d="M297.2 482.1l-92.2 9.7 25.9 38.7 60 123.1 142.6 46.2-9-194.6h-69.4z"/>
|
||||
<path fill="#E5EBF0" stroke="#E5EBF0" d="M379.3 334.7l-88.4-56.9-43.2 11.6-76.2-8 .4.7 2.2 73.6-1.1 88.5 32 47.6 92.2-9.7 57.9 23.1h69.4l-3.1-66.3h.2l-19.1-93.7z"/>
|
||||
<path fill="#F4F5F6" stroke="#F4F5F6" d="M463.5 233.6l-23.1-22.1-126.3-15.8-20.3 84 85.5 55 23.2 10.5 19.1 93.7 78.8-6.3 36.8 6.3 47-19-27-45.2 9.2-72.5-88.1-66.5z"/>
|
||||
<path fill="#E8E8E8" stroke="#E8E8E8" d="M309.8 102.1L287.4 5.3l-.7-.1-141.1 68.4-7.3 21.1v131.6l33.2 55.1 76.2 8 43.2-11.6 2.9 1.9 20.2-83.9-9.4-49.5z"/>
|
||||
<path fill="#D5E3EE" stroke="#D5E3EE" d="M465.6 139.9l3.2-29.4L453 49.4l-63.2-30.5L287.4 5.3l22.4 96.8-5.2 44.2 9.4 49.5.1-.1 126.1 15.8 2.3-52.6z"/>
|
||||
<path fill="#E5EBF0" stroke="#E5EBF0" d="M611.9 99.9l8.5-49.4L616.8.1 453 49.4l15.8 61.1-3.2 29.4-23.1 19-2.3 52.6h.2l23.1 22.1 14.8 2.1 88.1 66.5 14-110.7 10.5-44.2z"/>
|
||||
<path fill="#C7D4DE" stroke="#C7D4DE" d="M838.3-.1H617.2l-.4.2 3.6 50.4-8.5 49.4-21 47.4-10.5 44.2 192.7-8.3z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="guide-content">
|
||||
|
||||
<!-- WEB TYPOGRAPHY ====================================== -->
|
||||
<section id="web-type" data-nav-label="Web typography" class="l-section l-section--timeline l-section--web-type">
|
||||
<header class="l-contain l-section__header">
|
||||
<h2>Web typography</h2>
|
||||
<p class="h4">A brief history</p>
|
||||
</header>
|
||||
<div class="l-grid l-section__body">
|
||||
<p class="l-col-left c-feature-para">Rich typography has for years been the envy of many web designers, who long for the typographic variety, texture, and precision available in print media.</p>
|
||||
<div class="l-col-right">
|
||||
<p>The first huge stride in typographic detail on the web was the introduction of web fonts, which allowed designers and developers to use many other fonts besides the handful generally available on user’s operating systems.</p>
|
||||
<p>Why were web fonts so exciting for designers? Jason Pamental put it <a href="http://rwt.io/presentations/talk/variable-fonts-future-web-design" target="_blank">eloquently</a>, “typography is communication” but currently the web is “all system, no soul.” Web fonts teased the opportunity of bringing that “soul” to the web. Unfortunately for web fonts, to provide this soul, it comes at an especially important cost.</p>
|
||||
</div>
|
||||
|
||||
<!-- Pull quote demo -->
|
||||
<div class="l-col-left">
|
||||
<figure class="soul-wrap" role="img" aria-label="Currently, the web is all system, no soul. (Jason Pamental)">
|
||||
<quote-grid class="soul" aria-hidden="true">
|
||||
<span class="soul__ldquo">“</span>
|
||||
<span class="soul__currentl">Currentl</span>
|
||||
<span class="soul__y">y</span>
|
||||
<span class="soul__web">the web</span>
|
||||
<span class="soul__is">
|
||||
<span>is</span>
|
||||
</span>
|
||||
<span class="soul__all">
|
||||
<span>A<span zw> </span>L<span zw> </span>L</span>
|
||||
</span>
|
||||
<span class="soul__system">
|
||||
<span>S<span zw> </span>Y<span zw> </span>S<span zw> </span>T<span zw> </span>E<span zw> </span>M</span>
|
||||
</span>
|
||||
<span class="soul__no-soul"><span>no</span> <span>soul</span></span>
|
||||
<span class="soul__rdquo">„</span>
|
||||
<span class="soul__jason">- Jason Pamental</span>
|
||||
</quote-grid>
|
||||
</figure>
|
||||
<p class="caption soul-caption">
|
||||
Multi-type quotes like this used to only be performant in images or SVG; until variable fonts. View this <br /><a href="https://codepen.io/MSEdgeDev/pen/34ee6c6e3732e35cf48c67753b80f0d3" target="_blank">pull quote code on Codepen</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="l-col-right">
|
||||
<p>Delivering this “soul” using web fonts with regular OpenType fonts required web developers to include every different font file for the various font variants the designer chose. Take the following simple example:</p>
|
||||
|
||||
<!-- DEMO -->
|
||||
<p class="tk-korolev-compressed">
|
||||
<span style="font-weight: 500" class="tk-korolev">1. This</span>
|
||||
<span style="font-weight: 300">sentence</span>
|
||||
is
|
||||
<span style="font-weight: 350;" class="tk-korolev-condensed">composed</span>
|
||||
<span style="font-weight: 600" class="tk-korolev-condensed">from</span>
|
||||
<span style="font-weight: 900;" class="tk-korolev-condensed">three</span>
|
||||
<span style="font-weight: 700;" class="tk-korolev">different</span>
|
||||
<span style="font-weight: 900;" class="tk-korolev">non-variable</span>
|
||||
<span style="font-weight: 700;">font</span>
|
||||
<span style="font-weight: 900;">files</span>.
|
||||
</p>
|
||||
<p>To achieve the look in the previous sentence we had to download three different font files. As a result of needing to download every type face, web developers quickly found that for every beautiful font that a designer added to a site, it had a noticeable impact on the performance and overall experience to the end user. To help surface potential perf impacts, font services such as Adobe’s TypeKit have added in heuristics to warn web developers about the size and number of requests in their font selections.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ENTER VARIABLE FONTS ====================================== -->
|
||||
<section id="enter" data-nav-label="Variable fonts" class="l-section l-section--timeline">
|
||||
<header class="l-contain l-section__header">
|
||||
<h2>Enter variable fonts</h2>
|
||||
</header>
|
||||
<div class="l-grid l-section__body">
|
||||
<img class="l-col-left" src="images/bahnschrift-letter-e-800.jpg" alt="Showing the letter E in font Bahnshrift in a font design tool." />
|
||||
<div class="l-col-right">
|
||||
<p>Similarly, many web developers have advocated a return to system font stacks, prioritizing performance over brand cohesion or design differentiation. Performance has the potential for major impact on user experience and a business’s bottom line, and so the web community needed to figure out how to balance this priority against the desire for beautiful typography.</p>
|
||||
<p>To help solve this problem, one of the most impactful changes was made to the OpenType font format in collaboration by Adobe, Apple, Google, Microsoft and others. The solution was to enable font designers to provide various axes that could be adjusted dynamically by the software rendering the font, such as a web browser.</p>
|
||||
<p>To show the beauty of this simple, but powerful capability; let’s achieve a similar designed sentence as our previous example, but this time using a single variable font.</p>
|
||||
|
||||
<!-- DEMO -->
|
||||
<p class="tk-korolev-compressed">
|
||||
<span style="font-weight: 500" class="tk-korolev">1. This</span>
|
||||
<span style="font-weight: 300">sentence</span>
|
||||
is
|
||||
<span style="font-weight: 350;" class="tk-korolev-condensed">composed</span>
|
||||
<span style="font-weight: 600" class="tk-korolev-condensed">from</span>
|
||||
<span style="font-weight: 900;" class="tk-korolev-condensed">three</span>
|
||||
<span style="font-weight: 700;" class="tk-korolev">different</span>
|
||||
<span style="font-weight: 900;" class="tk-korolev">non-variable</span>
|
||||
<span style="font-weight: 700;">font</span>
|
||||
<span style="font-weight: 900;">files</span>.
|
||||
</p>
|
||||
<!-- TODO// Need to add in correct weights for Bahnschrift but I need the new font viewer to match up with Korelev -->
|
||||
<p class="variable-font">
|
||||
<span style="font-weight: 300; font-variation-settings: 'wdth' 100">2. This</span><!-- Light -->
|
||||
<span style="font-weight: 300; font-variation-settings: 'wdth' 75">sentence</span><!-- light condensed -->
|
||||
<span style="font-weight: 350; font-variation-settings: 'wdth' 100">is</span> <!-- SemiLight -->
|
||||
<span style="font-weight: 350; font-variation-settings: 'wdth' 75">composed</span><!-- SemiLight Condensed -->
|
||||
<span style="font-weight: 400; font-variation-settings: 'wdth' 100">from</span><!-- Regular -->
|
||||
<span style="font-weight: 600; font-variation-settings: 'wdth' 100">one</span><!-- SemiBold -->
|
||||
<span style="font-weight: 700; font-variation-settings: 'wdth' 100">variable</span><!-- Bold -->
|
||||
<span style="font-weight: 700; font-variation-settings: 'wdth' 75">font</span><!-- Bold Condensed -->
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FONT-VARIATION-SETTINGS ====================================== -->
|
||||
<section id="font-variation-settings" data-nav-label="font-variation-settings" class="l-section l-section--timeline">
|
||||
<header class="l-contain l-section__header">
|
||||
<p class="h4">Using variable fonts</p>
|
||||
<h2 class="c-property-heading" style="font-feature-settings: 'liga' 1;">font-variation-settings</h2>
|
||||
</header>
|
||||
<div class="l-section__body">
|
||||
<div class="l-grid">
|
||||
<p class="l-col-left c-feature-para">So how exactly did we achieve the seemingly different typefaces in the, previous example, with a single font?</p>
|
||||
<div class="l-col-right">
|
||||
<p> We utilized the variable font, “Bahnschrift” by Microsoft, and pivoted the various axes to match that of sentence number one. To adjust an axis in CSS, you can utilize font-variation-settings, like so:</p>
|
||||
<p><code>font-variation-settings: normal | [<string> <number>]#</code></p>
|
||||
<p>For example, all of the following are valid values for font-variation-settings.</p>
|
||||
<pre><code>font-variation-settings: "wght" 400;
|
||||
font-variation-settings: "wght" 400, "wdth" 80;
|
||||
font-variation-settings: normal;</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-subsection l-subsection--banner l-subsection--banner-angled">
|
||||
<div class="l-grid l-grid--stack-med">
|
||||
<div class="l-col-right ticket-wrap" aria-label="A fake boat ticket demonstrating mixing font weights and widths">
|
||||
<div class="ticket" aria-hidden="true">
|
||||
<div class="ticket__header">
|
||||
<div class="ticket__co">
|
||||
<svg class="ticket__co-icon" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><circle fill="#506072" cx="32" cy="32" r="32"/><path fill="#F4F5F6" d="M17.8 23.7c.5.2 1.1.1 1.4.2.6.1 1.3.1 1.8-.1.2-.1.5-.3.8-.5.3-.3.6-.6 1.1-1 .4-.4.9-.8 1.5-1.2.6-.4 1.3-.7 2.1-.8.4-.1.7-.1 1.1-.1h1c.7.1 1.4.3 2 .6 1.3.7 2.2 1.7 2.8 2.4.6.7 1.1 1.2 1.7 1.4.7.2 1.5.3 2.2.1.7-.2 1.4-.7 2.3-1.5.5-.4 1-.8 1.6-1.1.6-.3 1.2-.5 1.9-.6 1.2-.1 2.5.1 3.6.8 1 .7 1.7 1.6 2.5 2.3.8.7 1.8 1.2 2.9 1.2-.6 0-1.2-.1-1.8-.4-.5-.3-1-.6-1.5-1-1-.7-2-1.7-3.2-1.9-.6-.1-1.2-.1-1.7 0-.6.1-1.1.3-1.5.6-.8.5-1.3 1.6-2.4 2.8-.6.6-1.3 1.1-2.2 1.4-.9.3-1.7.3-2.6.1-1.1-.2-2-.7-2.7-1.3-.7-.6-1.1-1.1-1.5-1.5-.8-.8-1.3-1.1-1.8-1.2-.5-.1-.8-.1-.9 0-.1 0 0 .1.3.1-.2 0-.4 0-.6.1-.2.1-.3.1-.5.3-.3.2-.4.5-.6.6-.3.2-.6.5-.8.7-.4.3-.7.6-1.2 1-1 .7-2.4 1.3-3.6 1.4-.2.1-.5.1-.9.2h-.9c-.8-.2-1.6-.6-2.2-1.1-.6-.5-1-1.1-1.4-1.6-.7-1.1-1.4-2.1-2.8-2.4.3 0 .5-.1.5-.1l-.6-.3c-.5-.3-.7-.3-1-.4.2-.1.4-.1.7-.1h.8c.5 0 1.1.2 1.7.4 1 .4 1.9 1.2 2.6 1.5z"/><g opacity=".85" fill="#F4F5F6"><path d="M48.9 40.3l-.3-.3c0 .1.1.1.1.2s.1.1.2.1zM48.3 39.7l-.1-.1h-.1zM47.6 39.1l.3.3c0-.1-.1-.2-.3-.3zM48 39.6s.1-.1 0 0l.1-.1-.2-.1c.1.1.1.2.1.2zM48 39.6v.2c.1 0 .1-.1 0-.2zM47.1 40.3c-.1 0 .1-.2 0-.3-.3-.2-.6-.3-.9-.4-.1 0-.1-.4-.3-.4-.4-.1-1.2.1-.8.2.6.2 1 .4 1.6.8.5.3 1 .6 1.6 1 .1.1.3.2.4.4-.2-.2-.3-.4-.5-.6-.1-.4-.7-.4-1.1-.7zM51.6 41.8c-.1 0-.2.1-.2.1-.3-.3-.7-.2-1-.3l.1.2c.2.1.3 0 .1-.1.3.3.8.4 1.2.4-.1-.2-.1-.3-.2-.3zM52 42h-.2.2z"/><path d="M46 38.4c-1-.5-2.1-.5-3.1-.4-.1.1-.1.2-.2.1h-.3l-.4.1-.1.1c-.1.1 0 .1 0 .1h0-.2c-.1.1-.2.2-.4.2.1-.1.2-.2.4-.2l.2-.2.1-.1c-.3.1-.6.3-.9.5-.1 0-.1.1-.2.1-.2.2-.3.4-.5.4l-.1.1h-.1l-.6.5c-.1.2-.1.3-.2.5h-.2c0 .1 0 .2-.1.3.2 0 .3 0 .4-.1.2 0 0-.5.4-.4-.3-.1-.2.4-.4.4-.1 0-.3 0-.4.1-.1.3-.4.5-.6.5.2-.3.4-.3.7-.3.1-.1.1-.2.1-.3h.2c.1-.1.2-.3.2-.5-.4.3-.7.6-1.1.9-.6.4-1.3.6-2 .7-.7.1-1.4 0-2-.3-.6-.2-1.2-.7-1.7-1.2s-1.1-1.2-1.8-1.8c-.8-.6-1.9-1-2.9-1.1-1-.1-2.1.1-3.1.5-.9.5-1.6 1.2-2.2 1.7-.6.5-1.1.9-1.6 1.1-.5.2-1.2.2-1.7.1-.6-.2-1-.5-1.3-1-.3-.4-.8-1-1.7-1.8-.5-.4-1-.8-1.5-1-.6-.3-1.1-.4-1.6-.5-.6 0-1 .2-1.2.4-.3.2-.3.4-.3.6 0 .4.3.8.3.8.5.6.8.8 1.2 1 .4.3.9.6 1.4 1.6-.4-.6-.1-.6.4-.2.5.4 1.1 1.2 1.6 2 .4.6 1.1 1.1 1.9 1.3.8.2 1.6.2 2.5 0 .9-.2 1.7-.6 2.4-1.1.7-.5 1.2-1 1.7-1.4.5-.4.8-.8 1.2-1 .5-.2 1-.2 1.6-.2.6.1 1 .2 1.5.5.5.4 1.1 1 2.1 1.8.4.4 1 .7 1.7 1 .6.3 1.3.4 2 .5 1.4.1 2.7-.5 3.6-1.2.7-.5 1.4-.9 1.8-1.3.6-.6 1-1.1 1.3-1.5-.5.4-.7.8-1.3 1.4-.4.4 0-.6.2-.9.1-.2.5-.1.5-.2.2-.2.3-.5.6-.7.1-.1.2.2.3.1l.4-.4c.1-.2.3-.3.4-.2.2 0 .4 0 .6.1h.4l.2-.1c-.1-.1-.1-.2-.1-.3.1 0 .3.1.4.1-.1 0-.3-.1-.4-.1 0 .1 0 .2.1.3.6-.2 1.3-.1 2 .1-.4-.2-.7-.3-1-.6.2.1.1.2-.1.2l-.4-.4c.4 0 .8 0 1 .4h.3c.1.1 0 .2 0 .3.1 0 .1.1.2.1-.1-.2-.5-.6-.5-.6z"/><path d="M41.7 38.5c.1 0 .1-.1.2-.1-.3.1-.5.2-.7.4.2 0 .3-.2.5-.3z"/></g><path fill="#F4F5F6" d="M12 28.7c.4.2 1 .3 1.8.6.7.3 1.5.9 2 1.5.6.6 1 1.2 1.5 1.7s.9.8 1.3 1c.6.3 1.2.3 1.6.4.4 0-.5.1-1.6-.4-.5-.2-1-.5-1.5-1 .5.8 1.2 1.4 1.9 1.7.5.1 1 .1 1.5.1 1.2 0 2.3-.6 3.1-1.4.8-.7 1.6-1.6 2.5-1.9.3-.1.9-.3 1.5-.3s1.1.1 1.4.2c-.7-.2-1.4-.2-2.1-.1-.7.1-1.3.5-1.9 1-.6.5-1.1 1.1-1.8 1.7-.7.5-1.6.9-2.5 1h.3c.9-.1 1.9-.6 2.6-1.2.7-.6 1.3-1.2 1.9-1.6.2-.1.4-.3.7-.4-.2.1-.4.2-.7.4-.5.4-1 1-1.6 1.6-.4.4-1 .7-1.5 1-.4.2-.9.2-1.4.3-.3.1-.6.1-.8.1h-.3c.2.1.8.3 1.6.2.9-.1 1.9-.6 2.7-1.3.8-.6 1.4-1.1 1.9-1.4.5-.2.8-.3 1-.3.5-.2 1.2-.6 1.9-.4.2.1.4.2.6.2h.3c.5.2.7.8 1.2 1 .1.1.2.5.3.9.1.4.2.7.3.7.7-.3.1-.1 1 .6.1.1.6 0 .8.2.7.5 1.1.4 2 .4.3 0 .6 0 .9-.1h.6c.2 0 .4-.1.6-.1.2-.1.4-.2.7-.5.1-.1.5-.3.8-.7.3-.3.6-.7.6-.7 1-.8 1.2-1.7 2.2-1.7.3-.4.8-.6 1.4-.7.6 0 1.1.1 1.6.2 1 .2 1.1.7 1.5 1.5.2.2.3.3.4.5 0 .2.5.3.7.6l-.2.1c.1.1.2.3.3.3.1.1 0 .1-.1.1-.1.1-.3.1-.2.3.3.4.8.9 1.3 1.2.6.2 1.3.3 1.9.3.1-.1.1-.2.2-.2.2 0 .3 0 .5-.1.1-.2.1-.4.2-.5.1-.5.6-1 .5-1.5 0-.2-.7-.2-.9-.5 0-.1.1-.2.2-.4-.3-.1-.3-.3-.1-.4-.1 0-.1-.1-.1-.1 0-.1.1-.2.1-.2-.5-.4-.6-1-1.5-1.6-.2-.1-.5-.3-.8-.4-.1-.1-.3-.4-.4-.5-.3 0-.4.2-.6.3-.1-.2-.4-.4-.7-.6-.3-.2-.6-.4-1-.6-.7-.3-1.2-.2-1.3.1-.8-.1-.9.2-1.7.3-.5.1-1.1.2-1.7.5-.6.3-1.1.7-1.5 1.1L38.7 32l-.4.4c-.7.6-1.3.9-2.1.9s-1.5-.1-2-.5c-.6-.3-1.1-.9-1.8-1.6-.7-.7-1.7-1.4-2.9-1.7-1.2-.2-2.4-.1-3.5.4s-1.9 1.3-2.6 2c-.7.7-1.4 1.3-2.2 1.4-.8.2-1.7.1-2.3-.1-1.3-.5-2-1.9-3-2.9-.5-.5-1.1-1-1.7-1.2-.3-.1-.5-.2-.8-.3-.2-.1-.4-.1-.6-.1H12z" opacity=".8"/></svg>
|
||||
<span class="ticket__co-name">Variable Tides</span>
|
||||
<span class="u-upper ticket__co-subname">Boating Adventures</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ticket__body">
|
||||
<p class="ticket__route">Winter Wonderland</p>
|
||||
<p class="ticket__description">A four-hour tour of the Strait of Garamond</p>
|
||||
<div class="ticket__timing">
|
||||
<p>
|
||||
<span class="u-upper ticket__small-label">Date</span>
|
||||
<span class="ticket__detail">Feb 27</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="u-upper ticket__small-label">Launch</span>
|
||||
<span class="ticket__detail">10:30 am</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="u-upper ticket__small-label">Boarding</span>
|
||||
<span class="ticket__detail">10:00 am</span>
|
||||
</p>
|
||||
</div>
|
||||
<p class="ticket__fine-print">This ticket cannot be transferred to another voyage</p>
|
||||
<p class="u-upper ticket__admit">Admit one adult</p>
|
||||
<img class="ticket__barcode" src="images/barcode.png" alt="Fake barcode" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-col-left ticket-info">
|
||||
<h3>Adjusting multiple axes</h3>
|
||||
<p>If you want to adjust multiple axes on an element, you can do that by listing out axes separated by a comma. For example, the “Variable Tides” company name on this ticket has both a weight and a width adjustment:</p>
|
||||
<pre><code>.ticket__co-name {
|
||||
font-variation-settings: "wght" 500, "wdth" 75;
|
||||
}
|
||||
</code></pre>
|
||||
<p>
|
||||
<a href="https://codepen.io/MSEdgeDev/pen/d5a08cf4f631275fceaa73056b78bc14">View ticket example on Codepen</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="l-subsection l-grid">
|
||||
<h3 class="l-col-left">Reserved axis tags</h3>
|
||||
<div class="l-col-right">
|
||||
<p>While font designers can create as many axes as they desire using whatever
|
||||
four-character tags (eg: <code>'wdth'</code>) they want; there are currently five reserved axis tags.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<th>Reserved axis</th>
|
||||
<th>Used for</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>ital</code></td>
|
||||
<td>Italic</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>opsz</code></td>
|
||||
<td>Optical Size</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>slnt</code></td>
|
||||
<td>Slant</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>wdth</code></td>
|
||||
<td>Width</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>wght</code></td>
|
||||
<td>Weight</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Wait, what? Now we have to manipulate a font’s weight using the ‘wght’ axis rather than using the font-weight property? Using the font-variation-settings property is just one method of controlling variable axes. These reserved axis tags can also be manipulated by familiar CSS properties:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<th>Reserved axis</th>
|
||||
<th>Font property equivalent</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>ital</code></td>
|
||||
<td>font-style: italic</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>opsz</code></td>
|
||||
<td>font-optical-sizing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>slnt</code></td>
|
||||
<td>font-style: oblique + angle</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>wdth</code></td>
|
||||
<td>font-stretch</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>wght</code></td>
|
||||
<td>font-weight</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Because of this, the following two CSS declarations will produce identical results:</p>
|
||||
<pre><code>.someClass {
|
||||
font-variations-settings: "wght" 300, "ital" 1, "slnt" 45, "wdth" 50%, "opsz" 25;
|
||||
}
|
||||
|
||||
.someClass {
|
||||
font-style: italic;
|
||||
font-optical-sizing: auto;
|
||||
font-size: 25;
|
||||
font-style: oblique 45deg;
|
||||
font-stretch: 50%;
|
||||
font-weight: 300;
|
||||
}</code></pre>
|
||||
</div>
|
||||
<h3 class="l-col-left">Animating axes</h3>
|
||||
<figure class="l-col-left">
|
||||
<video autoplay loop>
|
||||
<source src="video/animating-headers-intersection-observer.mp4" type="video/mp4">
|
||||
</video>
|
||||
<figcaption>A practical example of animating the font-weight on headers as they scroll into view using IntersectionObserver. View the “<a href="https://codepen.io/MSEdgeDev/pen/e1d7a7a20330af0e99d133ec46b95619" target="_blank">Codepen</a>”</figcaption>
|
||||
</figure>
|
||||
<div class="l-col-right">
|
||||
<p>Now that we’ve covered what variable fonts are and how they can be used, it’s important to note that they can also be animated and interpolated. You may have noticed as you scroll down this page that the section headings animate in scale and font weight as they scroll into view; this is a very practical and compelling use case for variable fonts. If you're curious how we did this - take a peek at the <a href="https://codepen.io/MSEdgeDev/pen/e1d7a7a20330af0e99d133ec46b95619">Codepen</a>.</p>
|
||||
<p>One thing to keep in mind when animating axes, according to the spec you can interpolate between two declarations that are “like”. So what does this mean? The following animation will <em>not</em> work:</p>
|
||||
<pre><code>from {
|
||||
font-variation-settings: "wght" 300;
|
||||
}
|
||||
|
||||
to {
|
||||
font-variation-settings: "wdth" 80;
|
||||
}</code></pre>
|
||||
<p>The reason this doesn’t work is because the engine doesn’t know what to interpolate to: does it keep “wght” at 300 or interpolate it to 0? We need to have all the relevant axes represented so the engine can interpolate them, or in the words of the spec—make the declarations become “like”:</p>
|
||||
<pre><code>from {
|
||||
font-variation-settings: "wght" 300;
|
||||
}
|
||||
|
||||
to {
|
||||
font-variation-settings: "wght" 0, "wdth" 80;
|
||||
}</code></pre>
|
||||
<p>We took this ability to animate variable fonts and had a little fun with some of Decovar’s astounding 15 different axes to create this animation:</p>
|
||||
</div>
|
||||
|
||||
<div class="l-col-full vf-decovar">
|
||||
<span class="vf-decovar__text" aria-label="A single font">
|
||||
<span aria-hidden="true">A single</span>
|
||||
<span aria-hidden="true">font</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FONT-OPTICAL-SIZING ====================================== -->
|
||||
<section id="font-optical-sizing" data-nav-label="font-optical-sizing" class="l-section l-section--timeline">
|
||||
<header class="l-contain l-section__header">
|
||||
<p class="h4">Using variable fonts</p>
|
||||
<h2 class="c-property-heading">font-optical-sizing</h2>
|
||||
</header>
|
||||
<div class="l-grid l-grid--stack-med l-section__body">
|
||||
<p class="l-col-left">In a font of standard construction, the same weight across varying sizes can look inconsistent. A light weight might feel too wispy at a caption size; a bold weight commands a little too much attention at heading sizes, or it looks clunky at a particular size. To help ensure that these weights carry a consistent mood and bar of quality across sizes, some variable fonts support an axis called optical size. This can be controlled via the font-optical-sizing property. It has two values, auto and none. This is similar to what has been done in the printing industry for years.</p>
|
||||
<figure class="l-col-right">
|
||||
<img src="images/Century_Expanded-a-normalized.jpg" />
|
||||
<figcaption>An example of optical size adjustment in print on the letter “a” created by Nick Sherman for his article titled “<a href="http://alistapart.com/column/font-hinting-and-the-future-of-responsive-typography" target="_blank">Font Hinting and the Future of Responsive Typography</a>”</figcaption>
|
||||
</figure>
|
||||
|
||||
<p class="l-col-left">In fonts with automatic optical sizing, this optimization comes for free, as auto is the initial value. Sitka, a variable font created by Microsoft, automatically adjusts text between sizes 6pt and 36pt, such that across this entire range, small optimizations are done to make sure the type always looks its best. This behavior can be toggled using font-optical-sizing and setting the value to none.</p>
|
||||
<figure class="l-col-right vf-optical-sizing">
|
||||
<table>
|
||||
<thead>
|
||||
<th>Automatic optical sizing</th>
|
||||
<th>font-optical-sizing: none;</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="vf-optical-sizing__72pt">Abcdef</td>
|
||||
<td class="vf-optical-sizing__72pt vf-optical-sizing__off">Abcdef</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="vf-optical-sizing__36pt">Abcdef</td>
|
||||
<td class="vf-optical-sizing__36pt vf-optical-sizing__off">Abcdef</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="vf-optical-sizing__12pt">Abcdef</td>
|
||||
<td class="vf-optical-sizing__12pt vf-optical-sizing__off">Abcdef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<figcaption>This table shows variable font Sitka, produced by Microsoft, at 72pt, 36pt and 12pt with and without font-optical-sizing. As the font gets smaller the stroke widths are increased and the x-height gets taller to improve legibility.</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- How to design with variable fonts ====================================== -->
|
||||
<section id="design" data-nav-label="Design tools" class="l-section l-section--timeline">
|
||||
<header class="l-contain l-section__header">
|
||||
<h2>Design tools</h2>
|
||||
</header>
|
||||
<div class="l-section__body">
|
||||
<div class="l-contain">
|
||||
<p class="c-feature-para">You may be asking yourself, “Ok, so if I’m using a font that has axes that aren’t reserved—how do I know what they’re named in the font to control them via font-variation-settings.” That’s a great question. Luckily, common design tools and operating systems are stepping up to fill this gap. Here are just a few ways you can inspect variable fonts for use in your websites.</p>
|
||||
</div>
|
||||
<section class="l-subsection l-subsection--banner l-subsection--banner-angled c-tool">
|
||||
<div class="l-grid l-grid--stack-med">
|
||||
<div class="l-col-left">
|
||||
<h4>The new font explorer in Windows 10</h4>
|
||||
<p>2018’s Spring Windows 10 Update includes a new and improved font explorer. The new font explorer not only provides a visual representation of the font, but also provides you with the various axes that the variable font contains.</p>
|
||||
<p>To use the font explorer:</p>
|
||||
<ol>
|
||||
<li>Press the Windows Key, then type “Fonts” and select “Font Preview and related settings”</li>
|
||||
<li>Search and select the variable font you want to inspect. In our video we search for Microsoft’s Bahnschrift.</li>
|
||||
<li>On the next screen you’ll see “instance view”, which shows you the various instances the font has defined. For example Bahnschrift has 15, including Light, Light Condensed, SemiLight, Bold, and many others.</li>
|
||||
<li>If you scroll down you’ll see a Metadata section with a label “Variable Font”. Clicking on “Variable Font Properties” will take you to the page that details the various axes and allows you to change them in real time.</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="l-col-right l-col-right--bleed">
|
||||
<video controls>
|
||||
<source src="video/new-font-explorer.mp4" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="l-subsection c-tool">
|
||||
<div class="l-grid l-grid--stack-med">
|
||||
<div class="l-col-left">
|
||||
<h4>Adobe Photoshop and Illustrator in Creative Cloud 2018</h4>
|
||||
<p>For those who design in Adobe products, an update in CC 2018 allows you to modify the variable fonts right where you normally build out your compositions. To do this:</p>
|
||||
<ol>
|
||||
<li>Select a text block that is using a variable font, in the typeface selection menu, variable fonts are labelled with the <img class="inline-media" src="images/photoshop-variable-font-icon.png" alt="Adobe variable font"/> icon.</li>
|
||||
<li>In the Type panel (which you can get to using Window > Type > Characters), you’ll see that it now lists out the various axes of the variable font (in Illustrator you need to click the <img class="inline-media" src="images/variable-axis-slider.png" alt="Adobe variable font slider"/> icon to open up the window that contains the axes sliders).</li>
|
||||
<li>Adjust the various axes sliders to update styles in the selected text block.</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="l-col-right l-col-right--bleed">
|
||||
<video controls>
|
||||
<source src="video/photoshop-variable-font-support.mp4" type="video/mp4">
|
||||
</video>
|
||||
<p class="caption">An example of using built-in variable fonts controls on the quote by Jason Pamental in Photoshop</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="l-subsection l-subsection--banner l-subsection--banner-angled c-tool">
|
||||
<div class="l-grid l-grid--stack-med">
|
||||
<div class="l-col-left">
|
||||
<h4>Axis-Praxis Variable Font Playground and CSS generation</h4>
|
||||
<p>Since variable fonts began to be standardized, Laurence Penney set up <a href="http://axis-praxis.org">Axis-Praxis</a> as a playground to test out various variable fonts and a way to view them live in the browser. We used this site for the animation of Decovar by adjusting the Decovar axes and then clicking the “CSS” button, which shows you CSS you can use to reproduce the same result on your own page. Axis-Praxis is also a great place to see some of the variable fonts that are available. Since variable fonts are new there aren’t many here – but many foundries are ramping up their implementation of variable fonts, including Microsoft.</p>
|
||||
</div>
|
||||
<div class="l-col-right l-col-right--bleed">
|
||||
<video controls>
|
||||
<source src="video/axis-praxis.mp4" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="l-subsection">
|
||||
<div class="l-grid l-grid--stack-med">
|
||||
<div class="l-col-left">
|
||||
<h4>Good ’ol wireframes</h4>
|
||||
<p>No matter how many tools come out, sometimes it just helps to sketch out ideas while you’re in a room brainstorming. That is exactly what Melanie and Greg did while coming up with the various ways to show practical and exciting ways in which Variable Fonts can improve a site.</p>
|
||||
<p>We then took these wireframes and moved into Adobe Illustrator and built them out, and then while coding it up we kept the spirit of the design in place while still making subtle tweaks. Our sketch shows the initial introduction of the poem that sets the theme for the entire expedition.</p>
|
||||
</div>
|
||||
<img class="l-col-right l-col-right--bleed" src="images/wireframe.jpg" alt="Wireframes of text animating showing how the text gets thicker from frame to frame" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Browser Support ====================================== -->
|
||||
<section id="shipping" data-nav-label="Shipping today" class="l-section l-section--timeline">
|
||||
<header class="l-contain l-section__header">
|
||||
<h2>Shipping today</h2>
|
||||
</header>
|
||||
<div class="l-grid l-section__body">
|
||||
<h3 class="l-col-left">Browser support</h3>
|
||||
<div class="l-col-right">
|
||||
<p>When EdgeHTML 17 ships, all modern desktop-based browsers will support <code>font-variation-settings</code>, except for Firefox, where it is behind a flag. On mobile, currently, Chrome and Safari 11.2 will support variable fonts, but UC Browser and Samsung Internet do not.</p>
|
||||
<p>At time of writing, only EdgeHTML 17, Safari 11 on MacOS, and Safari 11.2 on iOS support <code>font-optical-sizing</code>.</p>
|
||||
</div>
|
||||
<h3 class="l-col-left">Progressive enhancement</h3>
|
||||
<div class="l-col-right">
|
||||
<p>As you can see, support for variable fonts is beginning to make its way into browsers as well as into fonts, so it’s wise to use variable fonts in a progressive enhancements manner.
|
||||
To see if a browser supports variable fonts, utilize the CSS @supports conditional check, like so:</p>
|
||||
<pre><code>@supports (font-variation-settings: "wght" 500) {
|
||||
/* variable font code here */
|
||||
}</code></pre>
|
||||
<p>While this will check if the CSS parser understands font-variation-settings, it doesn’t necessarily ensure that the correct font is being selected. Take the following example:</p>
|
||||
<pre><code>font-family: "Bahnschrift", sans-serif;
|
||||
font-variation-settings: "wght" 600;</code></pre>
|
||||
<p>This will result in users utilizing a Windows 10 device with the desired result, but unless you are providing a fallback copy of Bahnschrift from the server, anyone accessing your site using a different OS will render without any axis change. Because of this you should provide fallbacks and only utilize font-variation-settings for non-reserved axes so that no matter the font they’ll be styled similarly. For example a better approach would be:</p>
|
||||
<pre><code>font-family: "Bahnschrift", -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-weight: 600;</code></pre>
|
||||
<p>This will ensure that if the user is on Windows, Mac, iOS, Android result in grabbing their respective variable font. When using this approach however, you need to ensure that your design doesn’t depend on certain font metrics. If your design does depend on certain font metrics or a non-reserved axis then you should serve the font using @font-face, like so:</p>
|
||||
<pre><code>@font-face {
|
||||
font-family: "Decovar";
|
||||
src: url("fonts/DecovarAlpha-VF.ttf");
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Decovar";
|
||||
font-variation-settings: "TRMD" 400;
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Demos & further reading ====================================== -->
|
||||
<section id="resources" data-nav-label="Resources" class="l-section l-section--timeline">
|
||||
<div class="l-contain">
|
||||
<header class="l-section__header">
|
||||
<h2>More resources</h2>
|
||||
</header>
|
||||
<div class="l-section__body">
|
||||
<ul>
|
||||
<li><a href="https://codepen.io/collection/938731d2762f40387ee8668de6c664f2/#" target="_blank">All Codepen demos used in this guide</a></li>
|
||||
<li><a href="https://www.axis-praxis.org/specimens/__DEFAULT__" target="_blank">Test-drive variable font specimens on Axis-Praxis</a></li>
|
||||
<li><a href="http://rwt.io/presentations/talk/variable-fonts-future-web-design" target="_blank">Jason Pamental’s Variable Font Presentation</a></li>
|
||||
<li><a href="https://docs.microsoft.com/en-us/typography/opentype/spec/">Open Type Specification</a></li>
|
||||
<li><a href="https://twitter.com/variablefonts">Variable fonts news</a></li>
|
||||
<li><a href="https://codepen.io/mandymichael/pen/dJZQaz" target="_blank">Variable font "Hello" demo by Mandy Michael</a></li>
|
||||
</ul>
|
||||
<p>We'd love to see what you come up with using variable fonts; please do share your experiments and production implementations with us at <a href="https://twitter.com/MSEdgeDev">@MSEdgeDev</a>. Happy coding! <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="15" height="15"><g fill="none" stroke="#424F5E" stroke-miterlimit="10"><path d="M2.2 7.5h10.5M.5 5.7l1.8 1.8L.5 9.3M14.5 5.7l-1.8 1.8 1.8 1.8"/><path d="M4.9 12.1L10.1 3M2.4 12.7l2.5-.7.7 2.5M9.4.5l.7 2.5 2.5-.7"/><path d="M10.1 12.1L4.9 3M12.6 12.7l-2.5-.7-.7 2.5M5.6.5L4.9 3l-2.5-.7"/></g></svg></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="l-section l-section--banner c-outro" role="contentinfo" aria-label="Demo credits">
|
||||
<div class="l-contain">
|
||||
<div class="c-outro__byline">
|
||||
<p><a href="https://developer.microsoft.com/en-us/microsoft-edge/testdrive/" class="c-nav-bar__more">A demo</a> by Microsoft Edge</p>
|
||||
<p>Contributors: <a href="https://github.com/gregwhitworth">Greg Whitworth</a>, <a href="https://github.com/melanierichards">Melanie Richards</a>, <a href="https://github.com/FremyCompany">Francois Remy</a></p>
|
||||
<p>Bahnschrift and Sitka fonts by Microsoft</p>
|
||||
<p>Decovar font by David Berlow at TypeNetwork</p>
|
||||
</div>
|
||||
<a href="https://github.com/MicrosoftEdge/Demos" class="c-outro__github" aria-label="Explore code on Github">
|
||||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path fill-rule="evenodd" clip-rule="evenodd" fill="#FFF" d="M10 .2C4.5.2 0 4.7 0 10.2c0 4.4 2.9 8.2 6.8 9.5.5.1.7-.2.7-.5v-1.7c-2.8.6-3.4-1.3-3.4-1.3-.4-1.1-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.6 2.4 1.2 2.9.9.1-.6.3-1.1.6-1.3-2.1-.3-4.5-1.1-4.5-5 0-1.1.4-2 1-2.7-.1-.2-.4-1.2.1-2.6 0 0 .8-.3 2.7 1 .9-.2 1.8-.3 2.6-.3s1.7.1 2.5.3c1.9-1.3 2.7-1 2.7-1 .5 1.4.2 2.4.1 2.6.6.7 1 1.6 1 2.7 0 3.8-2.3 4.7-4.6 4.9.4.3.7.9.7 1.9v2.7c0 .3.2.6.7.5 4-1.3 6.8-5.1 6.8-9.5.1-5.5-4.4-10-9.9-10z"/></svg><span>Explore code</span>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="scripts/demo-template.js"></script>
|
||||
<script src="scripts/var-fonts.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,289 @@
|
|||
/* eslint-env browser */
|
||||
/* eslint-disable no-var, prefer-template, strict, prefer-arrow-callback, object-shorthand, no-continue */
|
||||
/*globals event*/
|
||||
|
||||
/*
|
||||
* DEMO TEMPLATE SCRIPTS
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* GENERIC JS-ENABLED CLASS ON BODY
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
document.body.classList.add('has-js');
|
||||
}());
|
||||
|
||||
/*
|
||||
* FEATURE SUPPORT ALERT
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* These scripts are written old-school so that they work on older browsers */
|
||||
var closeAlert = function(e) {
|
||||
if (e.target.id === 'dismissFeatureAlert') {
|
||||
var featureAlert = document.getElementById('featureAlert');
|
||||
document.body.removeChild(featureAlert);
|
||||
document.body.classList.remove('has-alert');
|
||||
document.querySelector('.c-nav-bar').focus();
|
||||
}
|
||||
};
|
||||
|
||||
var insertAlert = function() {
|
||||
var featureAlertMsg = '<strong>Notice:</strong> This page demonstrates variable fonts, which is not supported in your browser version. For the full experience, please view in Microsoft Edge build 17074+ or <a href="https://developer.microsoft.com/en-us/microsoft-edge/platform/status/fontvariationpropertieswithopentypevariablefontsupport/">any browser that supports variable fonts</a>.',
|
||||
featureAlert = document.createElement('div');
|
||||
|
||||
featureAlert.className = 'c-alert c-alert--error';
|
||||
featureAlert.setAttribute('role', 'alert');
|
||||
featureAlert.setAttribute('aria-live', 'polite');
|
||||
featureAlert.setAttribute('id', 'featureAlert');
|
||||
|
||||
document.body.insertBefore(featureAlert, document.body.querySelector(':first-child'));
|
||||
document.body.className += 'has-alert';
|
||||
|
||||
/* Set trivial timeout to trigger aria-live readout cross-browser */
|
||||
setTimeout(function(){
|
||||
featureAlert.innerHTML = '<div class="l-contain c-alert__contain"><p class="c-alert__message">' + featureAlertMsg + '</p><button class="c-alert__dismiss" aria-label="Close alert" aria-controls="featureAlert" id="dismissFeatureAlert"></button></div>';
|
||||
}, 10);
|
||||
|
||||
/* Makes heading focusable by JS, for when alert is cleared */
|
||||
document.querySelector('.c-nav-bar').setAttribute('tabindex', '-1');
|
||||
window.addEventListener('click', closeAlert, false);
|
||||
};
|
||||
|
||||
/* Render alert if font-variation-settings isn't supported */
|
||||
if (typeof window.CSS === 'undefined' || !CSS.supports('font-variation-settings', '"wdth" 100')) {
|
||||
insertAlert();
|
||||
}
|
||||
}());
|
||||
|
||||
/*
|
||||
* COMPONENT: DEMO NAV
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
/* Generates nav items for each section on the page */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const demoNavItems = document.getElementById('js-nav-items');
|
||||
const pageSections = document.querySelectorAll('[data-nav-label]');
|
||||
|
||||
for (let i = 0; i < pageSections.length; i++) {
|
||||
const section = pageSections[i];
|
||||
const newLink = document.createElement('li');
|
||||
newLink.className = 'c-toc__item';
|
||||
newLink.innerHTML = '<a href="#' + section.getAttribute('id') + '">' + section.getAttribute('data-nav-label') + '</a>';
|
||||
demoNavItems.appendChild(newLink);
|
||||
|
||||
// Smooth scroll TOC links
|
||||
newLink.addEventListener('click', function(e) {
|
||||
const thisHash = e.target.hash,
|
||||
thisID = thisHash.replace('#', '');
|
||||
if (thisID) {
|
||||
e.preventDefault();
|
||||
document.getElementById(thisID).scrollIntoView({block: 'start', behavior: 'smooth'});
|
||||
history.replaceState({}, '', window.location.pathname + thisHash);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
//nav menu
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const menu = document.querySelector('.c-toc__btn');
|
||||
const items = menu.parentElement.querySelector('.c-toc__items');
|
||||
|
||||
const collapse = function () {
|
||||
items.setAttribute('aria-hidden', 'true');
|
||||
menu.setAttribute('aria-expanded', 'false');
|
||||
};
|
||||
|
||||
|
||||
const toggleSection = function (evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
const expanded = evt.currentTarget.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
if (expanded) {
|
||||
collapse();
|
||||
} else {
|
||||
items.removeAttribute('aria-hidden');
|
||||
menu.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
};
|
||||
|
||||
const toggleKeydownSection = function (evt) {
|
||||
const key = evt.which || evt.keyCode;
|
||||
|
||||
if (key !== 32 && key !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleSection(evt);
|
||||
};
|
||||
|
||||
|
||||
menu.addEventListener('click', toggleSection, false);
|
||||
menu.addEventListener('keydown', toggleKeydownSection, false);
|
||||
|
||||
document.addEventListener('click', function () {
|
||||
collapse();
|
||||
});
|
||||
|
||||
const insideContainer = function (item, container) {
|
||||
let result = false;
|
||||
|
||||
while (item) {
|
||||
if (item === container) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
item = item.parentElement; //eslint-disable-line no-param-reassign
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
document.addEventListener('focus', function (evt) {
|
||||
const target = evt.target;
|
||||
const expandedMenus = document.querySelectorAll('.navbar__submenu:not([aria-hidden="true"])');
|
||||
|
||||
if (expandedMenus.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let j = 0, lj = expandedMenus.length; j < lj; j++) {
|
||||
const expandedMenu = expandedMenus[j];
|
||||
|
||||
if (!insideContainer(target, expandedMenu)) {
|
||||
expandedMenu.setAttribute('aria-hidden', 'true');
|
||||
expandedMenu.parentElement.querySelector('[aria-expanded="true"]').removeAttribute('aria-expanded');
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
}());
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var menus = document.querySelectorAll('[data-menu]');
|
||||
|
||||
if (menus.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var findIndex = function (element, elements) {
|
||||
var index, l;
|
||||
|
||||
for (index = 0, l = elements.length; index < l; index++) {
|
||||
if (elements[index] === element) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
var next = function (elements) {
|
||||
return function (index) {
|
||||
if (typeof index === 'number') {
|
||||
var i = index + 1;
|
||||
var element = elements[i];
|
||||
var current = document.activeElement;
|
||||
|
||||
while (element) {
|
||||
element.focus();
|
||||
if (current !== document.activeElement) {
|
||||
break;
|
||||
} else {
|
||||
i++;
|
||||
element = elements[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var previous = function (elements) {
|
||||
return function (index) {
|
||||
if (typeof index === 'number') {
|
||||
var i = index - 1;
|
||||
var element = elements[i];
|
||||
var current = document.activeElement;
|
||||
|
||||
while (element) {
|
||||
element.focus();
|
||||
if (current !== document.activeElement) {
|
||||
break;
|
||||
} else {
|
||||
i--;
|
||||
element = elements[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var findSiblings = function (source, type, topParent) {
|
||||
if (source === topParent) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var parent = source.parentElement;
|
||||
|
||||
var elements = topParent.querySelectorAll(type);
|
||||
|
||||
if (elements.length === 1) {
|
||||
return findSiblings(parent, type, topParent);
|
||||
}
|
||||
|
||||
return elements;
|
||||
};
|
||||
|
||||
var arrowAction = function (action, container) {
|
||||
var activeElement = document.activeElement;
|
||||
var elements = findSiblings(activeElement, activeElement.tagName.toLowerCase(), container);
|
||||
var nextElementTo = action(elements);
|
||||
|
||||
nextElementTo(findIndex(activeElement, elements));
|
||||
};
|
||||
|
||||
var keydown = function (container) {
|
||||
return function () {
|
||||
var key = event.keyCode;
|
||||
var handled = true;
|
||||
|
||||
//right or down
|
||||
if (key === 39 || key === 40) {
|
||||
arrowAction(next, container);
|
||||
//up or left
|
||||
} else if (key === 38 || key === 37) {
|
||||
arrowAction(previous, container);
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
for (var i = 0, l = menus.length; i < l; i++) {
|
||||
var menu = menus[i];
|
||||
|
||||
menu.addEventListener('keydown', keydown(menu), false);
|
||||
}
|
||||
}());
|
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
* DEMO TEMPLATE STYLES
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font: 400 100%/1.4 base, "Segoe UI", Segoe, "Segoe WP", "Lucida Grande", "Lucida Sans", Verdana, sans-serif;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
text-underline-offset: 1px;
|
||||
text-decoration-skip: ink;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (min-width: 80em) {
|
||||
html {
|
||||
font-size: 112.5%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 120em) {
|
||||
html {
|
||||
font-size: 118.75%;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LAYOUT
|
||||
* ---------------------------------------------
|
||||
* @NOTE: The layout margins and paddings are in
|
||||
* rem (mostly) so that changing the font size
|
||||
* of a layout element doesn't change those
|
||||
* measurements. Vertical measurements in the
|
||||
* mobile-first experience are in em.
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.l-contain {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding-right: 1.25rem;
|
||||
padding-left: 1.25rem;
|
||||
max-width: 960px;
|
||||
max-width: 100rem;
|
||||
}
|
||||
|
||||
.l-section {
|
||||
margin-top: 3.5em;
|
||||
}
|
||||
|
||||
.l-section--banner,
|
||||
.c-intro {
|
||||
padding-top: 3.5em;
|
||||
padding-bottom: 3.5em;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
.l-subsection {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.l-subsection--banner {
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2em;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
.l-section--banner + .l-section--banner,
|
||||
.l-subsection--banner + .l-subsection--banner {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 36em) {
|
||||
.l-contain {
|
||||
padding-right: 3rem;
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.l-section {
|
||||
margin-top: 6rem;
|
||||
}
|
||||
|
||||
.l-subsection--banner,
|
||||
.c-intro {
|
||||
padding-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
}
|
||||
|
||||
.l-subsection {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.l-subsection--banner {
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.l-section--banner + .l-section--banner,
|
||||
.l-subsection--banner + .l-subsection--banner {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 60em) {
|
||||
.l-contain {
|
||||
padding-right: 6rem;
|
||||
padding-left: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BODY TYPE
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
p, ul, ol {
|
||||
margin-top: 1em;
|
||||
max-width: 44rem;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
padding-left: 1.25em;
|
||||
}
|
||||
|
||||
p:first-child, ul:first-child, ol:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
li + li {
|
||||
margin-top: .625em;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/*
|
||||
* FORM ELEMENTS
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
button {
|
||||
padding: .5em .75em;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
font: inherit;
|
||||
line-height: 1;
|
||||
-webkit-appearance: none;
|
||||
background-color: #ccc;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus {
|
||||
outline: 2px solid hsla(0, 0%, 0%, .4);
|
||||
outline-offset: 0;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: hsla(0, 0%, 0%, .4);
|
||||
}
|
||||
|
||||
/*
|
||||
* UTILITIES
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
/* Clear floated elements */
|
||||
.u-clear::before,
|
||||
.u-clear::after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
|
||||
.u-clear::after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Hide element visually (not from screen reader) */
|
||||
.u-sr-only {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Simple list */
|
||||
.u-simple-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: NAV BAR
|
||||
* @NOTE: These styles are not intended to be
|
||||
* changed by demo authors. For those styles,
|
||||
* see demo.css
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-nav-bar {
|
||||
position: fixed;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
font-size: .813em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb {
|
||||
position: relative;
|
||||
z-index: 9000; /* Higher than demo TOC */
|
||||
margin-right: 9em;
|
||||
max-width: none;
|
||||
padding: .75em 1.25rem;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb li {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb li + li {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.c-nav-bar__title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.c-toc {
|
||||
position: absolute;
|
||||
z-index: 8890; /* Unnecessarily high just in case… */
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* If alert present above nav, change layout */
|
||||
.has-alert .c-toc {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.c-toc__btn {
|
||||
float: right;
|
||||
padding: 1.5em 1.25rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Focus styles are in your-demo-name.css */
|
||||
.c-toc__btn:hover,
|
||||
.c-toc__btn:focus,
|
||||
.c-toc__item a:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.c-toc__btn:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.c-toc__arrow {
|
||||
margin-left: .5em;
|
||||
transform: translateY(.1em);
|
||||
}
|
||||
|
||||
.c-toc__items {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 4.5em);
|
||||
overflow: auto;
|
||||
clear: both;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.c-toc__items[aria-hidden="true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.c-toc__item {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.c-toc__item a {
|
||||
display: block;
|
||||
padding: 1em 1.25rem;
|
||||
text-decoration: none;
|
||||
transition: background-color ease-out 400ms;
|
||||
}
|
||||
|
||||
.c-toc__item a:hover,
|
||||
.c-toc__item a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 36em) {
|
||||
.c-nav-bar__contain {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 36em) {
|
||||
.c-nav-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb {
|
||||
margin-right: 13em;
|
||||
padding: .75rem 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.c-nav-bar__breadcrumb li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.c-nav-bar__index::after {
|
||||
padding: .5em;
|
||||
content: "\005C"; /* Backslash */
|
||||
}
|
||||
|
||||
.c-toc {
|
||||
position: fixed;
|
||||
right: 3rem;
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
.c-toc__btn,
|
||||
.c-toc__items {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.c-toc__btn,
|
||||
.c-toc__item a {
|
||||
padding: .75rem;
|
||||
}
|
||||
|
||||
.c-toc__btn {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.c-toc__items {
|
||||
max-height: calc(100vh - 3em);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.c-nav-bar {
|
||||
font-size: .938em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 60em) {
|
||||
.c-toc {
|
||||
right: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 112em) {
|
||||
/* Align toc to edge of contents whenever .l-contain maxes out */
|
||||
.c-toc {
|
||||
right: calc(50vw - 44rem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: ALERT
|
||||
* Only used for the feature-detection area for
|
||||
* now, but built as a component in case we want
|
||||
* to allow for reuse elsewhere
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-alert {
|
||||
position: relative;
|
||||
z-index: 9000;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.c-alert__contain {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
max-width: 100rem;
|
||||
}
|
||||
|
||||
/* Add side padding if not already on the element from .l-contain */
|
||||
.c-alert__contain:not(.l-contain) {
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.c-alert a:link,
|
||||
.c-alert a:visited {
|
||||
display: inline-block;
|
||||
color: #0067b8;
|
||||
}
|
||||
|
||||
.c-alert__message {
|
||||
margin: 0;
|
||||
max-width: 44rem;
|
||||
padding: 1em 0;
|
||||
padding: 1rem 0;
|
||||
font-size: .813em;
|
||||
}
|
||||
|
||||
.c-alert--error a:link,
|
||||
.c-alert--error a:visited {
|
||||
color: #005da6;
|
||||
}
|
||||
|
||||
.c-alert__dismiss {
|
||||
margin-left: 1em;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
background: url("../images/x.svg") no-repeat center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.c-alert__dismiss:hover,
|
||||
.c-alert__dismiss:focus {
|
||||
outline: 2px solid hsla(0, 0%, 0%, .4);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.c-alert__dismiss:active {
|
||||
background-color: hsla(0, 0%, 0%, .2);
|
||||
}
|
||||
|
||||
@media (min-width: 36em) {
|
||||
.c-alert__dismiss {
|
||||
margin-right: -1em;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: TOGGLE ANIMATIONS BUTTON
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-toggle-anim {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 8880;
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
font-size: .875em;
|
||||
}
|
||||
|
||||
.c-toggle-anim__state {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
body.has-js .c-toggle-anim {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* COMPONENT: OUTRO
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
|
||||
.c-outro {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.c-outro__byline p {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
font-size: .875em;
|
||||
}
|
||||
|
||||
.c-outro__byline p + p {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.c-outro__github {
|
||||
display: inline-block;
|
||||
margin-top: 2em;
|
||||
padding: .5em .75em;
|
||||
border: 1px solid transparent;
|
||||
line-height: 1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.c-outro__github:hover,
|
||||
.c-outro__github:focus {
|
||||
border-color: hsla(0, 0%, 0%, .4);
|
||||
}
|
||||
|
||||
.c-outro__github svg,
|
||||
.c-outro__github span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.c-outro__github svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.c-outro__github span {
|
||||
margin-left: .5em;
|
||||
}
|
|
@ -265,13 +265,13 @@
|
|||
.then(function (credInfo) {
|
||||
// Web developers can also store the credential id on their server.
|
||||
localStorage.setItem('credentialId', credInfo.credential.id);
|
||||
// The public key here is a JSON object.
|
||||
// The public key here is a JSON object.
|
||||
localStorage.setItem('publicKey', credInfo.publicKey);
|
||||
|
||||
gotoHome();
|
||||
})
|
||||
.catch(function(reason) {
|
||||
// Windows Hello isn't setup, show dialog explaining how to set it up
|
||||
// Windows Hello isn't setup, show dialog explaining how to set it up
|
||||
helpSetup(reason.message);
|
||||
});
|
||||
} catch (ex) {
|
||||
|
@ -293,7 +293,7 @@
|
|||
|
||||
type: 'ScopedCred',
|
||||
|
||||
/* Because the current website only supports one user to login,
|
||||
/* Because the current website only supports one user to login,
|
||||
there should only be one credential available to use. */
|
||||
id: localStorage.getItem('acctId')
|
||||
}];
|
||||
|
|
|
@ -181,10 +181,10 @@ navigator.authentication = navigator.authentication || (function () {
|
|||
|
||||
return cred;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`makeCredential failed: ${err}`);
|
||||
throw new Error('NotAllowedError');
|
||||
});
|
||||
.catch((err) => {
|
||||
console.log(`makeCredential failed: ${err}`);
|
||||
throw new Error('NotAllowedError');
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error('NotAllowedError');
|
||||
}
|
||||
|
@ -209,9 +209,9 @@ navigator.authentication = navigator.authentication || (function () {
|
|||
return { type: 'FIDO_2_0', id: descriptor.id};
|
||||
}));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Credential lists cannot be retrieved: ${err}`);
|
||||
});
|
||||
.catch((err) => {
|
||||
console.log(`Credential lists cannot be retrieved: ${err}`);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -233,24 +233,24 @@ navigator.authentication = navigator.authentication || (function () {
|
|||
|
||||
return msCredentials.getAssertion(challenge, filter, sigParams);
|
||||
})
|
||||
.then((sig) => {
|
||||
if (sig.type === 'FIDO_2_0') {
|
||||
return Promise.resolve(Object.freeze({
|
||||
.then((sig) => {
|
||||
if (sig.type === 'FIDO_2_0') {
|
||||
return Promise.resolve(Object.freeze({
|
||||
|
||||
credential: {type: 'ScopedCred', id: sig.id},
|
||||
clientData: sig.signature.clientData,
|
||||
authenticatorData: sig.signature.authnrData,
|
||||
signature: sig.signature.signature
|
||||
credential: {type: 'ScopedCred', id: sig.id},
|
||||
clientData: sig.signature.clientData,
|
||||
authenticatorData: sig.signature.authnrData,
|
||||
signature: sig.signature.signature
|
||||
|
||||
}));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return Promise.resolve(sig);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`getAssertion failed: ${err}`);
|
||||
throw new Error('NotAllowedError');
|
||||
});
|
||||
return Promise.resolve(sig);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`getAssertion failed: ${err}`);
|
||||
throw new Error('NotAllowedError');
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
|