From 914ccc45503be3af440918937f5811bd32e6d7fa Mon Sep 17 00:00:00 2001 From: squidfunk Date: Thu, 6 Oct 2016 12:14:33 +0200 Subject: [PATCH] Rewrite of Gulp asset pipeline in ES6 and separation of tasks --- .babelrc | 6 + .eslintrc | 41 +- .gitignore | 16 +- .nvmrc | 1 + .sass-lint.yml | 1 + .travis.yml | 4 +- CHANGELOG | 1 + Gulpfile.babel.js | 328 +++++++++++++ Gulpfile.js | 434 ------------------ MANIFEST.in | 4 +- ...9b6c4d53e.js => application-2ff8f6a9f1.js} | 10 +- .../javascripts/modernizr-29976e9007.js | 1 - .../javascripts/modernizr-dede1352ed.js | 1 + .../stylesheets/application-2ebf05d4b7.css | 1 + .../stylesheets/application-bcbe056a5b.css | 1 - material/base.html | 22 +- package.json | 10 +- src/assets/javascripts/application.js | 43 +- src/assets/javascripts/components/Material.js | 73 +++ .../components/Material/Sidebar.js | 33 ++ .../components/Material/Sidebar/Abstract.js | 94 ++++ .../components/Material/Sidebar/Marker.js | 103 +++++ .../components/Material/Sidebar/Position.js | 103 +++++ .../javascripts/components/scrollspy.js | 42 +- src/assets/javascripts/components/search.js | 2 - src/assets/stylesheets/_config.scss | 8 +- src/assets/stylesheets/_shame.scss | 2 +- src/assets/stylesheets/application.scss | 4 +- src/assets/stylesheets/base/_icons.scss | 2 +- src/assets/stylesheets/base/_reset.scss | 2 +- src/assets/stylesheets/base/_typeset.scss | 4 +- .../stylesheets/extensions/_admonition.scss | 4 +- .../stylesheets/extensions/_codehilite.scss | 4 +- .../stylesheets/extensions/_footnotes.scss | 4 +- .../stylesheets/extensions/_permalinks.scss | 4 +- src/assets/stylesheets/helpers/_break.scss | 4 +- src/assets/stylesheets/helpers/_px2em.scss | 2 +- src/assets/stylesheets/layout/_base.scss | 6 +- src/assets/stylesheets/layout/_content.scss | 2 +- src/assets/stylesheets/layout/_footer.scss | 2 +- src/assets/stylesheets/layout/_header.scss | 2 +- src/assets/stylesheets/layout/_nav.scss | 6 +- src/assets/stylesheets/layout/_search.scss | 4 +- src/assets/stylesheets/layout/_sidebar.scss | 8 +- src/assets/stylesheets/layout/_source.scss | 4 +- src/base.html | 26 +- tasks/assets/images/build/ico.js | 35 ++ tasks/assets/images/build/svg.js | 49 ++ tasks/assets/images/clean.js | 35 ++ tasks/assets/javascripts/build/application.js | 90 ++++ tasks/assets/javascripts/build/modernizr.js | 63 +++ tasks/assets/javascripts/clean.js | 35 ++ tasks/assets/javascripts/lint.js | 107 +++++ tasks/assets/stylesheets/build.js | 75 +++ tasks/assets/stylesheets/clean.js | 35 ++ tasks/assets/stylesheets/lint.js | 96 ++++ tasks/mkdocs/build.js | 33 ++ tasks/mkdocs/clean.js | 35 ++ tasks/mkdocs/serve.js | 58 +++ tasks/views/build.js | 55 +++ tasks/views/clean.js | 35 ++ 61 files changed, 1747 insertions(+), 568 deletions(-) create mode 100644 .babelrc create mode 100644 .nvmrc create mode 100755 Gulpfile.babel.js delete mode 100755 Gulpfile.js rename material/assets/javascripts/{application-29b6c4d53e.js => application-2ff8f6a9f1.js} (61%) delete mode 100644 material/assets/javascripts/modernizr-29976e9007.js create mode 100644 material/assets/javascripts/modernizr-dede1352ed.js create mode 100644 material/assets/stylesheets/application-2ebf05d4b7.css delete mode 100644 material/assets/stylesheets/application-bcbe056a5b.css create mode 100644 src/assets/javascripts/components/Material.js create mode 100644 src/assets/javascripts/components/Material/Sidebar.js create mode 100644 src/assets/javascripts/components/Material/Sidebar/Abstract.js create mode 100644 src/assets/javascripts/components/Material/Sidebar/Marker.js create mode 100644 src/assets/javascripts/components/Material/Sidebar/Position.js create mode 100644 tasks/assets/images/build/ico.js create mode 100644 tasks/assets/images/build/svg.js create mode 100644 tasks/assets/images/clean.js create mode 100644 tasks/assets/javascripts/build/application.js create mode 100644 tasks/assets/javascripts/build/modernizr.js create mode 100644 tasks/assets/javascripts/clean.js create mode 100644 tasks/assets/javascripts/lint.js create mode 100644 tasks/assets/stylesheets/build.js create mode 100644 tasks/assets/stylesheets/clean.js create mode 100644 tasks/assets/stylesheets/lint.js create mode 100644 tasks/mkdocs/build.js create mode 100644 tasks/mkdocs/clean.js create mode 100644 tasks/mkdocs/serve.js create mode 100644 tasks/views/build.js create mode 100644 tasks/views/clean.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..e51860877 --- /dev/null +++ b/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": ["es2015"], + "plugins": [ + "add-module-exports" + ] +} \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 0c866a34d..5f3f52927 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,8 +1,27 @@ { "extends": "eslint:recommended", "ecmaFeatures": { + "arrowFunctions": true, + "binaryLiterals": true, + "blockBindings": true, + "classes": true, + "defaultParams": true, + "destructuring": true, + "forOf": true, + "generators": true, "globalReturn": true, - "modules": true + "modules": true, + "objectLiteralComputedProperties": true, + "objectLiteralDuplicateProperties": true, + "objectLiteralShorthandMethods": true, + "objectLiteralShorthandProperties": true, + "octalLiterals": true, + "regexUFlag": true, + "regexYFlag": true, + "spread": true, + "superInFunctions": false, + "templateStrings": true, + "unicodeCodePointEscapes": true }, "env": { "browser": true, @@ -10,10 +29,10 @@ "node": true }, "globals": { - "describe": true, "before": true, - "it": true, + "describe": true, "expect": true, + "it": true, "Modernizr": true, "navigator": true }, @@ -34,7 +53,7 @@ "block-spacing": 2, "brace-style": 2, "camelcase": [2, { - "properties": "always", + "properties": "always" }], "comma-dangle": [2, "never"], "comma-style": [2, "last"], @@ -71,13 +90,12 @@ "lines-around-comment": 2, "lines-around-directive": 2, "max-depth": 2, - "max-len": [2, { + "max-len": [1, { "ignorePattern": "\/\/ TODO" }], "max-nested-callbacks": 2, "max-params": 2, "max-statements-per-line": 2, - "multiline-ternary": 2, "new-cap": 2, "newline-per-chained-call": 2, "no-array-constructor": 2, @@ -86,6 +104,7 @@ "no-confusing-arrow": [2, { "allowParens": false }], + "no-console": 1, "no-duplicate-imports": 2, "no-eq-null": 2, "no-eval": 2, @@ -97,7 +116,7 @@ "no-labels": 2, "no-lone-blocks": 2, "no-loop-func": 2, - "no-multiple-empty-lines": [2, { + "no-multiple-empty-lines": [1, { "max": 1 }], "no-nested-ternary": 2, @@ -118,6 +137,7 @@ "no-unneeded-ternary": 2, "no-unsafe-negation": 2, "no-unused-expressions": 2, + "no-unused-vars": 1, "no-use-before-define": 2, "no-useless-call": 2, "no-useless-computed-key": 2, @@ -126,8 +146,7 @@ "no-var": 2, "no-whitespace-before-property": 2, "no-with": 2, - "object-curly-newline": 2, - "object-curly-spacing": 2, + "object-curly-spacing": [2, "always"], "object-property-newline": 2, "object-shorthand": 2, "one-var-declaration-per-line": 2, @@ -139,7 +158,7 @@ "prefer-template": 2, "quotes": [2, "double"], "radix": 2, - "require-jsdoc": [2, { + "require-jsdoc": [1, { "require": { "FunctionDeclaration": true, "MethodDefinition": true, @@ -167,7 +186,7 @@ "strict": 2, "template-curly-spacing": 2, "unicode-bom": 2, - "valid-jsdoc": [2, { + "valid-jsdoc": [1, { "prefer": { "arg": "param", "argument": "param", diff --git a/.gitignore b/.gitignore index 0dacbf28e..e8de676b4 100644 --- a/.gitignore +++ b/.gitignore @@ -21,15 +21,15 @@ # Mac OS X internals .DS_Store -# NPM libraries -node_modules +# Dependencies +/node_modules # Build files -build -manifest.json -MANIFEST -site +/build +/manifest.json +/MANIFEST +/site # Distribution files -dist -mkdocs_material.egg-info \ No newline at end of file +/dist +/mkdocs_material.egg-info \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..07a7b03c9 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +6.7.0 \ No newline at end of file diff --git a/.sass-lint.yml b/.sass-lint.yml index 246e0e080..e324f7de4 100644 --- a/.sass-lint.yml +++ b/.sass-lint.yml @@ -21,6 +21,7 @@ files: ignore: - src/assets/stylesheets/_shame.scss + - src/assets/stylesheets/extensions/_codehilite.scss # Temporary disabled options: merge-default-rules: true diff --git a/.travis.yml b/.travis.yml index 2070547ca..28e813bd0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,8 @@ language: node_js # Node.js versions node_js: - - '4.1' - - '0.11' + - 4.5.0 + - 6.7.0 # Install dependencies before_script: diff --git a/CHANGELOG b/CHANGELOG index 9a180dae0..05f56b32d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,7 @@ mkdocs-material-1.0.0-rc.1 (2016-XX-XX) * Rewrite of JavaScript using ES6 and Babel as a transpiler * Rewrite of Admonition, Permalinks and Codehilite integration * Rewrite of the complete typographical system + * Rewrite of Gulp asset pipeline in ES6 and separate tasks * Removed Bower as a dependency in favor of npm * Removed custom icon build in favor of the Material Design iconset * Removed _blank targets on links due to vulnerability: http://bit.ly/1Mk2Rtw diff --git a/Gulpfile.babel.js b/Gulpfile.babel.js new file mode 100755 index 000000000..993778c7d --- /dev/null +++ b/Gulpfile.babel.js @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import gulp from "gulp" +import notifier from "node-notifier" +import plumber from "gulp-plumber" +import util from "gulp-util" +import yargs from "yargs" + +/* ---------------------------------------------------------------------------- + * Configuration and arguments + * ------------------------------------------------------------------------- */ + +const config = { + assets: { + src: "src/assets", /* Source directory for assets */ + build: "material/assets" /* Target directory for assets */ + }, + views: { + src: "src", /* Source directory for views */ + build: "material" /* Target directory for views */ + } +} + +const args = yargs + .default("clean", false) /* Clean before build */ + .default("lint", true) /* Lint sources */ + .default("mkdocs", false) /* MkDocs watchdog */ + .default("optimize", true) /* Optimize sources */ + .default("revision", true) /* Revision assets */ + .default("sourcemaps", false) /* Create sourcemaps */ + .argv + +/* ---------------------------------------------------------------------------- + * Overrides and helpers + * ------------------------------------------------------------------------- */ + +/* + * Override gulp.src() for nicer error handling. + */ +const src = gulp.src +gulp.src = (...glob) => { + return src.apply(gulp, glob) + .pipe( + plumber(function(error) { + util.log(util.colors.red( + `Error (${error.plugin}): ${error.message}` + )) + + /* Extract file where error happened, if existent */ + const file = error.relativePath + ? error.relativePath.split("/").pop() + : "" + + /* Dispatch system-level notification */ + notifier.notify({ + title: `Error (${error.plugin}): ${file}`, + message: error.messageOriginal + }) + + // eslint-disable-next-line no-invalid-this + this.emit("end") + + /* Throw error and abort, if not in watch mode */ + if (args._[0] !== "watch") + throw error + })) +} + +/* + * Helper function to load a task + */ +const load = task => { + return require(`./tasks/${task}.js`)(gulp, config, args) +} + +/* ---------------------------------------------------------------------------- + * Images + * ------------------------------------------------------------------------- */ + +/* + * Copy favicon + */ +gulp.task("assets:images:build:ico", + load("assets/images/build/ico")) + +/* + * Copy and minify vector graphics + */ +gulp.task("assets:images:build:svg", + load("assets/images/build/svg")) + +/* + * Copy images + */ +gulp.task("assets:images:build", args.clean ? [ + "assets:images:clean" +] : [], () => { + return gulp.start([ + "assets:images:build:ico", + "assets:images:build:svg" + ]) +}) + +/* + * Clean images generated by build + */ +gulp.task("assets:images:clean", + load("assets/images/clean")) + +/* ---------------------------------------------------------------------------- + * Javascripts + * ------------------------------------------------------------------------- */ + +/* + * Build application logic + */ +gulp.task("assets:javascripts:build:application", + load("assets/javascripts/build/application")) + +/* + * Build custom modernizr + */ +gulp.task("assets:javascripts:build:modernizr", [ + "assets:stylesheets:build" +], load("assets/javascripts/build/modernizr")) + +/* + * Build application logic and modernizr + */ +gulp.task("assets:javascripts:build", (args.clean ? [ + "assets:javascripts:clean" +] : []).concat(args.lint ? [ + "assets:javascripts:lint" +] : []), () => { + gulp.start([ + "assets:javascripts:build:application", + "assets:javascripts:build:modernizr" + ]) +}) + +/* + * Clean javascripts generated by build + */ +gulp.task("assets:javascripts:clean", + load("assets/javascripts/clean")) + +/* + * Lint javascripts + */ +gulp.task("assets:javascripts:lint", + load("assets/javascripts/lint")) + +/* ---------------------------------------------------------------------------- + * Stylesheets + * ------------------------------------------------------------------------- */ + +/* + * Build stylesheets from SASS source + */ +gulp.task("assets:stylesheets:build", (args.clean ? [ + "assets:stylesheets:clean" +] : []).concat(args.lint ? [ + "assets:stylesheets:lint" +] : []), + load("assets/stylesheets/build")) + +/* + * Clean stylesheets generated by build + */ +gulp.task("assets:stylesheets:clean", + load("assets/stylesheets/clean")) + +/* + * Lint SASS sources + */ +gulp.task("assets:stylesheets:lint", + load("assets/stylesheets/lint")) + +/* ---------------------------------------------------------------------------- + * Assets + * ------------------------------------------------------------------------- */ + +/* + * Build assets + */ +gulp.task("assets:build", [ + "assets:images:build", + "assets:javascripts:build", + "assets:stylesheets:build" +]) + +/* + * Clean files generated by build + */ +gulp.task("assets:clean", [ + "assets:images:clean", + "assets:javascripts:clean", + "assets:stylesheets:clean" +]) + +/* ---------------------------------------------------------------------------- + * Views + * ------------------------------------------------------------------------- */ + +/* + * Minify views + */ +gulp.task("views:build", (args.revision ? [ + "assets:images:build", + "assets:stylesheets:build", + "assets:javascripts:build" +] : []).concat(args.clean ? [ + "views:clean" +] : []), load("views/build")) + +/* + * Clean views + */ +gulp.task("views:clean", + load("views/clean")) + +/* ---------------------------------------------------------------------------- + * MkDocs + * ------------------------------------------------------------------------- */ + +/* + * Build documentation + */ +gulp.task("mkdocs:build", [ + "assets:build", + "views:build", + "mkdocs:clean" +], load("mkdocs/build")) + +/* + * Clean documentation build + */ +gulp.task("mkdocs:clean", + load("mkdocs/clean")) + +/* + * Restart MkDocs server + */ +gulp.task("mkdocs:serve", + load("mkdocs/serve")) + +/* ---------------------------------------------------------------------------- + * Interface + * ------------------------------------------------------------------------- */ + +/* + * Build assets and documentation + */ +gulp.task("build", [ + "clean" +], () => { + return gulp.start([ + "assets:build", + "views:build" + ].concat(args.mkdocs + ? "mkdocs:build" + : [])) +}) + +/* + * Clean assets and documentation + */ +gulp.task("clean", [ + "assets:clean", + "views:clean", + "mkdocs:clean" +]) + +/* + * Watch for changes and rebuild assets on the fly + */ +gulp.task("watch", [ + "assets:build", + "views:build" +], () => { + if (args.mkdocs) + gulp.start("mkdocs:serve") + + /* Rebuild stylesheets */ + gulp.watch([ + `${config.assets.src}/stylesheets/**/*.scss` + ], ["assets:stylesheets:build"]) + + /* Rebuild javascripts */ + gulp.watch([ + `${config.assets.src}/javascripts/**/*.js` + ], ["assets:javascripts:build:application"]) + + /* Copy images */ + gulp.watch([ + `${config.assets.src}/images/**/*` + ], ["assets:images:build"]) + + /* Minify views */ + gulp.watch([ + `${config.views.src}/**/*.html` + ], ["views:build"]) +}) + +/* + * Build assets by default + */ +gulp.task("default", ["build"]) diff --git a/Gulpfile.js b/Gulpfile.js deleted file mode 100755 index 586646ddb..000000000 --- a/Gulpfile.js +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (c) 2016 Martin Donath - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -"use strict" - -/* ---------------------------------------------------------------------------- - * Imports - * ------------------------------------------------------------------------- */ - -var gulp = require("gulp") -var args = require("yargs").argv -var autoprefix = require("autoprefixer") -var changed = require("gulp-changed") -var child = require("child_process") -var clean = require("del") -var compact = require("gulp-remove-empty-lines") -var concat = require("gulp-concat") -var gulpif = require("gulp-if") -var mincss = require("gulp-cssnano") -var minhtml = require("gulp-htmlmin") -var minsvg = require("gulp-svgmin") -var modernizr = require("gulp-modernizr") -var mqpacker = require("css-mqpacker") -var notifier = require("node-notifier") -var path = require("path") -var plumber = require("gulp-plumber") -var postcss = require("gulp-postcss") -var replace = require("gulp-replace") -var rev = require("gulp-rev") -var sass = require("gulp-sass") -var sasslint = require("gulp-sass-lint") -var sourcemaps = require("gulp-sourcemaps") -var stream = require("webpack-stream") -var uglify = require("gulp-uglify") -var util = require("gulp-util") -var vinyl = require("vinyl-paths") -var version = require("gulp-rev-replace") -var webpack = require("webpack") - -/* ---------------------------------------------------------------------------- - * Locals - * ------------------------------------------------------------------------- */ - -/* MkDocs server */ -var server = null - -/* Watching context */ -var watch = false - -/* ---------------------------------------------------------------------------- - * Overrides - * ------------------------------------------------------------------------- */ - -/* - * Override gulp.src() for nicer error handling. - */ -var src = gulp.src // TODO: do this via extension somehow... -gulp.src = function() { - return src.apply(gulp, arguments) - .pipe( - plumber(function(error) { - util.log(util.colors.red( - "Error (" + error.plugin + "): " + error.message - )) - - /* Extract file where error happened, if existent */ - var file = error.relativePath - ? error.relativePath.split("/").pop() - : "" - - /* Dispatch system-level notification */ - notifier.notify({ - title: "Error (" + error.plugin + "): " + file, - message: error.messageOriginal - }) - this.emit("end") - })) -} - -/* ---------------------------------------------------------------------------- - * Asset pipeline - * ------------------------------------------------------------------------- */ - -/* - * Clean stylesheets generated by build. - */ -gulp.task("assets:clean:stylesheets", () => { - return gulp.src("material/assets/stylesheets/*") - .pipe(vinyl(clean)) -}) - -/* - * Clean javascripts generated by build. - */ -gulp.task("assets:clean:javascripts", () => { - return gulp.src("material/assets/javascripts/*") - .pipe(vinyl(clean)) -}) - -/* - * Clean images generated by build. - */ -gulp.task("assets:clean:images", () => { - return gulp.src("material/assets/images/*") - .pipe(vinyl(clean)) -}) - -/* - * Clean files generated by build. - */ -gulp.task("assets:clean", [ - "assets:clean:stylesheets", - "assets:clean:javascripts", - "assets:clean:images" -]) - -/* - * Build stylesheets from SASS source. - */ -gulp.task("assets:build:stylesheets", args.production ? [ - "assets:clean:stylesheets", - "assets:build:images" -] : [], () => { - return gulp.src("src/assets/stylesheets/*.scss") - .pipe(gulpif(args.sourcemaps, sourcemaps.init())) - .pipe( - sass({ - includePaths: [ - "node_modules/modularscale-sass/stylesheets", - "node_modules/material-design-color", - "node_modules/material-shadows" - ] - })) - .pipe( - postcss([ - autoprefix(), - mqpacker - ])) - .pipe(gulpif(args.sourcemaps, sourcemaps.write())) - .pipe(gulpif(args.production, mincss())) - .pipe(gulpif(args.production, rev())) - .pipe(gulpif(args.production, - version({ manifest: gulp.src("manifest.json") }))) - .pipe(gulp.dest("material/assets/stylesheets")) - .pipe(gulpif(args.production, - rev.manifest("manifest.json", { - base: "material/assets", - merge: true - }))) - .pipe(gulpif(args.production, gulp.dest("material/assets"))) -}) - -/* - * Build javascripts by transpiling ES6 with babel. - */ -gulp.task("assets:build:javascripts", args.production ? [ - "assets:clean:javascripts" -] : [], () => { - return gulp.src("src/assets/javascripts/**/*.js") - .pipe( - stream({ - entry: "application.js", - output: { - filename: "application.js" - }, - module: { - loaders: [{ - loader: "babel-loader", - test: path.join(__dirname, "src/assets/javascripts"), - query: { - presets: "es2015" - } - }, { - test: /\.js$/, - loader: "eslint-loader", - exclude: /node_modules/ - }] - }, - plugins: [ - new webpack.NoErrorsPlugin() - ].concat( - args.production ? [ - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - } - }) - ] : []), - stats: { - colors: true - }, - resolve: { - modulesDirectories: [ - "src/assets/javascripts", - "node_modules" - ], - extensions: [ - "", ".js" - ] - }, - devtool: args.sourcemaps ? "source-map" : "" - })) - .pipe(gulpif(args.production, rev())) - .pipe(gulp.dest("material/assets/javascripts")) - .pipe(gulpif(args.production, - rev.manifest("manifest.json", { - base: "material/assets", - merge: true - }))) - .pipe(gulpif(args.production, gulp.dest("material/assets"))) -}) - -/* - * Create a customized modernizr build. - */ -gulp.task("assets:build:modernizr", [ - "assets:build:stylesheets", - "assets:build:javascripts" -], () => { - return gulp.src([ - "material/assets/stylesheets/*.css", - "material/assets/javascripts/*.js" - ]).pipe( - modernizr({ - options: [ - "addTest", /* Add custom tests */ - "fnBind", /* Use function.bind */ - "html5printshiv", /* HTML5 support for IE */ - "setClasses", /* Add CSS classes to root tag */ - "testProp" /* Test for properties */ - ] - })) - .pipe(concat("modernizr.js")) - .pipe(gulpif(args.production, uglify())) - .pipe(gulpif(args.production, rev())) - .pipe(gulp.dest("material/assets/javascripts")) - .pipe(gulpif(args.production, - rev.manifest("manifest.json", { - base: "material/assets", - merge: true - }))) - .pipe(gulpif(args.production, gulp.dest("material/assets"))) -}) - -/* - * Copy and minify vector graphics. - */ -gulp.task("assets:build:images:svg", () => { - return gulp.src("src/assets/images/**/*.svg") - .pipe(gulpif(watch, changed("material/assets/images"))) - .pipe(gulpif(args.production, minsvg())) - .pipe(gulpif(args.production, rev())) - .pipe(gulp.dest("material/assets/images")) - .pipe(gulpif(args.production, - rev.manifest("manifest.json", { - base: "material/assets", - merge: true - }))) - .pipe(gulpif(args.production, gulp.dest("material/assets"))) -}) - -/* - * Copy favicon. - */ -gulp.task("assets:build:images:ico", () => { - return gulp.src("src/assets/images/**/*.ico") - .pipe(gulp.dest("material/assets/images")) -}) - -/* - * Copy images. - */ -gulp.task("assets:build:images", [ - "assets:clean:images" -], () => { - return gulp.start([ - "assets:build:images:svg", - "assets:build:images:ico" - ]) -}) - -/* - * Minify views. - */ -gulp.task("assets:build:views", args.production ? [ - "assets:build:stylesheets", - "assets:build:modernizr", - "assets:build:images" -] : [], () => { - var metadata = require("./package.json") - return gulp.src("src/**/*.html") - .pipe(gulpif(watch, changed("material"))) - .pipe( - minhtml({ - collapseBooleanAttributes: true, - removeComments: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true, - customAttrCollapse: /(content)/ - })) - .pipe(replace("$theme-name$", metadata.name)) - .pipe(replace("$theme-version$", metadata.version)) - .pipe(compact()) - .pipe(gulpif(args.production, - version({ manifest: gulp.src("manifest.json") }))) - .pipe(gulp.dest("material")) -}) - -/* - * Build assets. - */ -gulp.task("assets:build", [ - "assets:build:stylesheets", - "assets:build:javascripts", - "assets:build:modernizr", - "assets:build:images", - "assets:build:views" -]) - -/* - * Watch assets for changes and rebuild on the fly. - */ -gulp.task("assets:watch", () => { - watch = true - - /* Rebuild stylesheets */ - gulp.watch([ - "src/assets/stylesheets/**/*.scss" - ], ["assets:build:stylesheets"]) - - /* Rebuild javascripts */ - gulp.watch([ - "src/assets/javascripts/**/*.js" - ], ["assets:build:javascripts"]) - - /* Copy images */ - gulp.watch([ - "src/assets/images/**/*" - ], ["assets:build:images"]) - - /* Minify views */ - gulp.watch([ - "src/**/*.html" - ], ["assets:build:views"]) -}) - -/* ---------------------------------------------------------------------------- - * Application server - * ------------------------------------------------------------------------- */ - -/* - * Build documentation. - */ -gulp.task("mkdocs:build", [ - "assets:build" -], () => { - return child.spawnSync("mkdocs", ["build"]) -}) - -/* - * Restart MkDocs server. - */ -gulp.task("mkdocs:serve", () => { - if (server) - server.kill() - - /* Spawn MkDocs server */ - server = child.spawn("mkdocs", ["serve", "-a", "0.0.0.0:8000"]) - - /* Pretty print server log output */ - server.stdout.on("data", data => { - var lines = data.toString().split("\n") - for (var l in lines) - if (lines[l].length) - util.log(lines[l]) - }) - - /* Print errors to stdout */ - server.stderr.on("data", data => { - process.stdout.write(data.toString()) - }) -}) - -/* ---------------------------------------------------------------------------- - * Interface - * ------------------------------------------------------------------------- */ - -/* - * Build assets and documentation. - */ -gulp.task("build", [ - "assets:clean", - "assets:build" -].concat(args.mkdocs - ? "mkdocs:build" - : [])) - -/* - * Start asset and MkDocs watchdogs. - */ -gulp.task("watch", [ - "assets:clean", - "assets:build" -], () => { - return gulp.start([ - "assets:watch" - ].concat(args.mkdocs - ? "mkdocs:serve" - : [])) -}) - -/* - * Build assets by default. - */ -gulp.task("default", ["build"]) \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index 515bad148..3bd56b9c9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,4 @@ recursive-include material *.ico *.js *.css *.html *.svg -recursive-exclude site * \ No newline at end of file +recursive-exclude site * +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] \ No newline at end of file diff --git a/material/assets/javascripts/application-29b6c4d53e.js b/material/assets/javascripts/application-2ff8f6a9f1.js similarity index 61% rename from material/assets/javascripts/application-29b6c4d53e.js rename to material/assets/javascripts/application-2ff8f6a9f1.js index 332855dd1..4171775bd 100644 --- a/material/assets/javascripts/application-29b6c4d53e.js +++ b/material/assets/javascripts/application-2ff8f6a9f1.js @@ -1,11 +1,11 @@ -!function(e){function t(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return e[i].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}var o=n(1),r=i(o),s=n(2),a=i(s),c=n(3),l=i(c),u=n(4),h=i(u);document.addEventListener("DOMContentLoaded",function(){Modernizr.addTest("ios",function(){return!!navigator.userAgent.match(/(iPad|iPhone|iPod)/g)}),Modernizr.addTest("standalone",function(){return!!navigator.standalone}),r["default"].attach(document.body);var e=window.matchMedia("(min-width: 1200px)"),t=new l["default"](".md-sidebar--primary"),n=function(){e.matches?t.listen():t.unlisten()};n();var i=new l["default"](".md-sidebar--secondary");i.listen();var o=new h["default"](".md-sidebar--secondary .md-nav--secondary .md-nav__link");o.listen(),window.addEventListener("resize",n);var s=document.getElementById("query");s.addEventListener("focus",function(){document.querySelector(".md-search").classList.add("md-js__search--locked")});var c=0,u=document.getElementById("search");u.addEventListener("click",function(e){var t=document.body.classList,n=!matchMedia("only screen and (min-width: 960px)").matches;t.contains("md-js__body--locked")?(t.remove("md-js__body--locked"),n&&setTimeout(function(){window.scrollTo(0,c)},100)):(c=window.scrollY,n&&setTimeout(function(){window.scrollTo(0,0)},400),setTimeout(function(){e.target.checked&&(n&&t.add("md-js__body--locked"),setTimeout(function(){document.getElementById("md-search").focus()},200))},450))});var d=document.querySelectorAll(".md-nav__item--nested > .md-nav__link");[].forEach.call(d,function(e){var t=e.nextElementSibling;t.style.maxHeight=t.getBoundingClientRect().height+"px",e.addEventListener("click",function(){var e=t.getBoundingClientRect().height;e?(t.style.maxHeight=e+"px",requestAnimationFrame(function(){t.classList.add("md-nav--transitioning"),t.style.maxHeight="0px"})):!function(){t.style.maxHeight="",t.classList.add("md-nav--toggled");var e=t.getBoundingClientRect().height;t.classList.remove("md-nav--toggled"),t.style.maxHeight="0px",requestAnimationFrame(function(){t.classList.add("md-nav--transitioning"),t.style.maxHeight=e+"px"})}()}),t.addEventListener("transitionend",function(e){e.target.classList.remove("md-nav--transitioning"),e.target.getBoundingClientRect().height>0&&(e.target.style.maxHeight="100%")})}),fetch("https://api.github.com/repos/squidfunk/mkdocs-material").then(function(e){return e.json()}).then(function(e){var t=e.stargazers_count,n=e.forks_count,i=document.querySelectorAll(".md-source__facts");[].forEach.call(i,function(e){var i=document.createElement("li");i.className="md-source__fact md-source__fact--hidden",i.innerText=t+" Stars",e.appendChild(i),setTimeout(function(e){e.classList.remove("md-source__fact--hidden")},100,i),i=document.createElement("li"),i.className="md-source__fact md-source__fact--hidden",i.innerText=n+" Forks",e.appendChild(i),setTimeout(function(e){e.classList.remove("md-source__fact--hidden")},500,i)})})["catch"](function(){}),fetch("/mkdocs/search_index.json").then(function(e){return e.json()}).then(function(e){var t=(0,a["default"])(function(){(void 0).field("title",{boost:10}),(void 0).field("text"),(void 0).ref("location")}),n={};e.docs.forEach(function(e){e.text=e.text.replace(/\s(\.,\:)\s/gi,function(e,t){return t+" "}),e.location=window.baseUrl+e.location,n[e.location]=e,t.add(e)});var i=document.getElementById("query");i.addEventListener("keyup",function(){for(var e=document.querySelector(".md-search-result__list");e.firstChild;)e.removeChild(e.firstChild);var i=t.search(s.value);i.forEach(function(t){var i=n[t.ref],o=document.createElement("a");o.classList.add("md-search-result__link"),o.href=i.location;var r=document.createElement("li");r.classList.add("md-search-result__item"),r.appendChild(o);var s=document.createElement("div");s.classList.add("md-search-result__title"),s.innerHTML=i.title,o.appendChild(s);var a=document.createElement("p");a.classList.add("md-search-result__description"),a.innerHTML=i.text,o.appendChild(a),e.appendChild(r)});var o=document.querySelector(".md-search-result__meta");o.innerHTML=i.length+" search result"+(1!==i.length?"s":"")})})["catch"](function(){})})},function(e,t,n){var i;!function(){"use strict";/** +var Application=function(e){function t(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return e[i].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n .md-nav__link");[].forEach.call(i,function(e){var t=e.nextElementSibling;t.style.maxHeight=t.getBoundingClientRect().height+"px",e.addEventListener("click",function(){var e=t.getBoundingClientRect().height;e?(t.style.maxHeight=e+"px",requestAnimationFrame(function(){t.classList.add("md-nav--transitioning"),t.style.maxHeight="0px"})):!function(){t.style.maxHeight="",t.classList.add("md-nav--toggled");var e=t.getBoundingClientRect().height;t.classList.remove("md-nav--toggled"),t.style.maxHeight="0px",requestAnimationFrame(function(){t.classList.add("md-nav--transitioning"),t.style.maxHeight=e+"px"})}()}),t.addEventListener("transitionend",function(e){e.target.classList.remove("md-nav--transitioning"),e.target.getBoundingClientRect().height>0&&(e.target.style.maxHeight="100%")})}),fetch("https://api.github.com/repos/squidfunk/mkdocs-material").then(function(e){return e.json()}).then(function(e){var t=e.stargazers_count,n=e.forks_count,i=document.querySelectorAll(".md-source__facts");[].forEach.call(i,function(e){var i=document.createElement("li");i.className="md-source__fact md-source__fact--hidden",i.innerText=t+" Stars",e.appendChild(i),setTimeout(function(e){e.classList.remove("md-source__fact--hidden")},100,i),i=document.createElement("li"),i.className="md-source__fact md-source__fact--hidden",i.innerText=n+" Forks",e.appendChild(i),setTimeout(function(e){e.classList.remove("md-source__fact--hidden")},500,i)})})["catch"](function(){}),fetch("/mkdocs/search_index.json").then(function(e){return e.json()}).then(function(t){var n=(0,u["default"])(function(){(void 0).field("title",{boost:10}),(void 0).field("text"),(void 0).ref("location")}),i={};t.docs.forEach(function(e){e.text=e.text.replace(/\s(\.,\:)\s/gi,function(e,t){return t+" "}),e.location=window.baseUrl+e.location,i[e.location]=e,n.add(e)});var o=document.getElementById("query");o.addEventListener("keyup",function(){for(var t=document.querySelector(".md-search-result__list");t.firstChild;)t.removeChild(t.firstChild);var o=n.search(e.value);o.forEach(function(e){var n=i[e.ref],o=document.createElement("a");o.classList.add("md-search-result__link"),o.href=n.location;var r=document.createElement("li");r.classList.add("md-search-result__item"),r.appendChild(o);var s=document.createElement("div");s.classList.add("md-search-result__title"),s.innerHTML=n.title,o.appendChild(s);var a=document.createElement("p");a.classList.add("md-search-result__description"),a.innerHTML=n.text,o.appendChild(a),t.appendChild(r)});var r=document.querySelector(".md-search-result__meta");r.innerHTML=o.length+" search result"+(1!==o.length?"s":"")})})["catch"](function(){})}),e.exports=t["default"]},function(e,t,n){var i;!function(){"use strict";/** * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs. * * @codingstandard ftlabs-jsv2 * @copyright The Financial Times Limited [All Rights Reserved] * @license MIT License (see LICENSE.txt) */ -function o(e,t){function n(e,t){return function(){return e.apply(t,arguments)}}var i;if(t=t||{},this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=t.touchBoundary||10,this.layer=e,this.tapDelay=t.tapDelay||200,this.tapTimeout=t.tapTimeout||700,!o.notNeeded(e)){for(var r=["onMouse","onClick","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel"],a=this,c=0,l=r.length;c=0,s=navigator.userAgent.indexOf("Android")>0&&!r,a=/iP(ad|hone|od)/.test(navigator.userAgent)&&!r,c=a&&/OS 4_\d(_\d)?/.test(navigator.userAgent),l=a&&/OS [6-7]_\d/.test(navigator.userAgent),u=navigator.userAgent.indexOf("BB10")>0;o.prototype.needsClick=function(e){switch(e.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(e.disabled)return!0;break;case"input":if(a&&"file"===e.type||e.disabled)return!0;break;case"label":case"iframe":case"video":return!0}return/\bneedsclick\b/.test(e.className)},o.prototype.needsFocus=function(e){switch(e.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!s;case"input":switch(e.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!e.disabled&&!e.readOnly;default:return/\bneedsfocus\b/.test(e.className)}},o.prototype.sendClick=function(e,t){var n,i;document.activeElement&&document.activeElement!==e&&document.activeElement.blur(),i=t.changedTouches[0],n=document.createEvent("MouseEvents"),n.initMouseEvent(this.determineEventType(e),!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),n.forwardedTouchEvent=!0,e.dispatchEvent(n)},o.prototype.determineEventType=function(e){return s&&"select"===e.tagName.toLowerCase()?"mousedown":"click"},o.prototype.focus=function(e){var t;a&&e.setSelectionRange&&0!==e.type.indexOf("date")&&"time"!==e.type&&"month"!==e.type?(t=e.value.length,e.setSelectionRange(t,t)):e.focus()},o.prototype.updateScrollParent=function(e){var t,n;if(t=e.fastClickScrollParent,!t||!t.contains(e)){n=e;do{if(n.scrollHeight>n.offsetHeight){t=n,e.fastClickScrollParent=n;break}n=n.parentElement}while(n)}t&&(t.fastClickLastScrollTop=t.scrollTop)},o.prototype.getTargetElementFromEventTarget=function(e){return e.nodeType===Node.TEXT_NODE?e.parentNode:e},o.prototype.onTouchStart=function(e){var t,n,i;if(e.targetTouches.length>1)return!0;if(t=this.getTargetElementFromEventTarget(e.target),n=e.targetTouches[0],a){if(i=window.getSelection(),i.rangeCount&&!i.isCollapsed)return!0;if(!c){if(n.identifier&&n.identifier===this.lastTouchIdentifier)return e.preventDefault(),!1;this.lastTouchIdentifier=n.identifier,this.updateScrollParent(t)}}return this.trackingClick=!0,this.trackingClickStart=e.timeStamp,this.targetElement=t,this.touchStartX=n.pageX,this.touchStartY=n.pageY,e.timeStamp-this.lastClickTimen||Math.abs(t.pageY-this.touchStartY)>n},o.prototype.onTouchMove=function(e){return!this.trackingClick||((this.targetElement!==this.getTargetElementFromEventTarget(e.target)||this.touchHasMoved(e))&&(this.trackingClick=!1,this.targetElement=null),!0)},o.prototype.findControl=function(e){return void 0!==e.control?e.control:e.htmlFor?document.getElementById(e.htmlFor):e.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")},o.prototype.onTouchEnd=function(e){var t,n,i,o,r,u=this.targetElement;if(!this.trackingClick)return!0;if(e.timeStamp-this.lastClickTimethis.tapTimeout)return!0;if(this.cancelNextClick=!1,this.lastClickTime=e.timeStamp,n=this.trackingClickStart,this.trackingClick=!1,this.trackingClickStart=0,l&&(r=e.changedTouches[0],u=document.elementFromPoint(r.pageX-window.pageXOffset,r.pageY-window.pageYOffset)||u,u.fastClickScrollParent=this.targetElement.fastClickScrollParent),i=u.tagName.toLowerCase(),"label"===i){if(t=this.findControl(u)){if(this.focus(u),s)return!1;u=t}}else if(this.needsFocus(u))return e.timeStamp-n>100||a&&window.top!==window&&"input"===i?(this.targetElement=null,!1):(this.focus(u),this.sendClick(u,e),a&&"select"===i||(this.targetElement=null,e.preventDefault()),!1);return!(!a||c||(o=u.fastClickScrollParent,!o||o.fastClickLastScrollTop===o.scrollTop))||(this.needsClick(u)||(e.preventDefault(),this.sendClick(u,e)),!1)},o.prototype.onTouchCancel=function(){this.trackingClick=!1,this.targetElement=null},o.prototype.onMouse=function(e){return!this.targetElement||(!!e.forwardedTouchEvent||(!e.cancelable||(!(!this.needsClick(this.targetElement)||this.cancelNextClick)||(e.stopImmediatePropagation?e.stopImmediatePropagation():e.propagationStopped=!0,e.stopPropagation(),e.preventDefault(),!1))))},o.prototype.onClick=function(e){var t;return this.trackingClick?(this.targetElement=null,this.trackingClick=!1,!0):"submit"===e.target.type&&0===e.detail||(t=this.onMouse(e),t||(this.targetElement=null),t)},o.prototype.destroy=function(){var e=this.layer;s&&(e.removeEventListener("mouseover",this.onMouse,!0),e.removeEventListener("mousedown",this.onMouse,!0),e.removeEventListener("mouseup",this.onMouse,!0)),e.removeEventListener("click",this.onClick,!0),e.removeEventListener("touchstart",this.onTouchStart,!1),e.removeEventListener("touchmove",this.onTouchMove,!1),e.removeEventListener("touchend",this.onTouchEnd,!1),e.removeEventListener("touchcancel",this.onTouchCancel,!1)},o.notNeeded=function(e){var t,n,i,o;if("undefined"==typeof window.ontouchstart)return!0;if(n=+(/Chrome\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]){if(!s)return!0;if(t=document.querySelector("meta[name=viewport]")){if(t.content.indexOf("user-scalable=no")!==-1)return!0;if(n>31&&document.documentElement.scrollWidth<=window.outerWidth)return!0}}if(u&&(i=navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/),i[1]>=10&&i[2]>=3&&(t=document.querySelector("meta[name=viewport]")))){if(t.content.indexOf("user-scalable=no")!==-1)return!0;if(document.documentElement.scrollWidth<=window.outerWidth)return!0}return"none"===e.style.msTouchAction||"manipulation"===e.style.touchAction||(o=+(/Firefox\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1],!!(o>=27&&(t=document.querySelector("meta[name=viewport]"),t&&(t.content.indexOf("user-scalable=no")!==-1||document.documentElement.scrollWidth<=window.outerWidth)))||("none"===e.style.touchAction||"manipulation"===e.style.touchAction))},o.attach=function(e,t){return new o(e,t)},i=function(){return o}.call(t,n,t,e),!(void 0!==i&&(e.exports=i))}()},function(e,t,n){var i,o;!function(){var r=function(e){var t=new r.Index;return t.pipeline.add(r.trimmer,r.stopWordFilter,r.stemmer),e&&e.call(t,t),t};r.version="0.7.1",/*! +function o(e,t){function n(e,t){return function(){return e.apply(t,arguments)}}var i;if(t=t||{},this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=t.touchBoundary||10,this.layer=e,this.tapDelay=t.tapDelay||200,this.tapTimeout=t.tapTimeout||700,!o.notNeeded(e)){for(var r=["onMouse","onClick","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel"],a=this,c=0,u=r.length;c=0,s=navigator.userAgent.indexOf("Android")>0&&!r,a=/iP(ad|hone|od)/.test(navigator.userAgent)&&!r,c=a&&/OS 4_\d(_\d)?/.test(navigator.userAgent),u=a&&/OS [6-7]_\d/.test(navigator.userAgent),l=navigator.userAgent.indexOf("BB10")>0;o.prototype.needsClick=function(e){switch(e.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(e.disabled)return!0;break;case"input":if(a&&"file"===e.type||e.disabled)return!0;break;case"label":case"iframe":case"video":return!0}return/\bneedsclick\b/.test(e.className)},o.prototype.needsFocus=function(e){switch(e.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!s;case"input":switch(e.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!e.disabled&&!e.readOnly;default:return/\bneedsfocus\b/.test(e.className)}},o.prototype.sendClick=function(e,t){var n,i;document.activeElement&&document.activeElement!==e&&document.activeElement.blur(),i=t.changedTouches[0],n=document.createEvent("MouseEvents"),n.initMouseEvent(this.determineEventType(e),!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),n.forwardedTouchEvent=!0,e.dispatchEvent(n)},o.prototype.determineEventType=function(e){return s&&"select"===e.tagName.toLowerCase()?"mousedown":"click"},o.prototype.focus=function(e){var t;a&&e.setSelectionRange&&0!==e.type.indexOf("date")&&"time"!==e.type&&"month"!==e.type?(t=e.value.length,e.setSelectionRange(t,t)):e.focus()},o.prototype.updateScrollParent=function(e){var t,n;if(t=e.fastClickScrollParent,!t||!t.contains(e)){n=e;do{if(n.scrollHeight>n.offsetHeight){t=n,e.fastClickScrollParent=n;break}n=n.parentElement}while(n)}t&&(t.fastClickLastScrollTop=t.scrollTop)},o.prototype.getTargetElementFromEventTarget=function(e){return e.nodeType===Node.TEXT_NODE?e.parentNode:e},o.prototype.onTouchStart=function(e){var t,n,i;if(e.targetTouches.length>1)return!0;if(t=this.getTargetElementFromEventTarget(e.target),n=e.targetTouches[0],a){if(i=window.getSelection(),i.rangeCount&&!i.isCollapsed)return!0;if(!c){if(n.identifier&&n.identifier===this.lastTouchIdentifier)return e.preventDefault(),!1;this.lastTouchIdentifier=n.identifier,this.updateScrollParent(t)}}return this.trackingClick=!0,this.trackingClickStart=e.timeStamp,this.targetElement=t,this.touchStartX=n.pageX,this.touchStartY=n.pageY,e.timeStamp-this.lastClickTimen||Math.abs(t.pageY-this.touchStartY)>n},o.prototype.onTouchMove=function(e){return!this.trackingClick||((this.targetElement!==this.getTargetElementFromEventTarget(e.target)||this.touchHasMoved(e))&&(this.trackingClick=!1,this.targetElement=null),!0)},o.prototype.findControl=function(e){return void 0!==e.control?e.control:e.htmlFor?document.getElementById(e.htmlFor):e.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")},o.prototype.onTouchEnd=function(e){var t,n,i,o,r,l=this.targetElement;if(!this.trackingClick)return!0;if(e.timeStamp-this.lastClickTimethis.tapTimeout)return!0;if(this.cancelNextClick=!1,this.lastClickTime=e.timeStamp,n=this.trackingClickStart,this.trackingClick=!1,this.trackingClickStart=0,u&&(r=e.changedTouches[0],l=document.elementFromPoint(r.pageX-window.pageXOffset,r.pageY-window.pageYOffset)||l,l.fastClickScrollParent=this.targetElement.fastClickScrollParent),i=l.tagName.toLowerCase(),"label"===i){if(t=this.findControl(l)){if(this.focus(l),s)return!1;l=t}}else if(this.needsFocus(l))return e.timeStamp-n>100||a&&window.top!==window&&"input"===i?(this.targetElement=null,!1):(this.focus(l),this.sendClick(l,e),a&&"select"===i||(this.targetElement=null,e.preventDefault()),!1);return!(!a||c||(o=l.fastClickScrollParent,!o||o.fastClickLastScrollTop===o.scrollTop))||(this.needsClick(l)||(e.preventDefault(),this.sendClick(l,e)),!1)},o.prototype.onTouchCancel=function(){this.trackingClick=!1,this.targetElement=null},o.prototype.onMouse=function(e){return!this.targetElement||(!!e.forwardedTouchEvent||(!e.cancelable||(!(!this.needsClick(this.targetElement)||this.cancelNextClick)||(e.stopImmediatePropagation?e.stopImmediatePropagation():e.propagationStopped=!0,e.stopPropagation(),e.preventDefault(),!1))))},o.prototype.onClick=function(e){var t;return this.trackingClick?(this.targetElement=null,this.trackingClick=!1,!0):"submit"===e.target.type&&0===e.detail||(t=this.onMouse(e),t||(this.targetElement=null),t)},o.prototype.destroy=function(){var e=this.layer;s&&(e.removeEventListener("mouseover",this.onMouse,!0),e.removeEventListener("mousedown",this.onMouse,!0),e.removeEventListener("mouseup",this.onMouse,!0)),e.removeEventListener("click",this.onClick,!0),e.removeEventListener("touchstart",this.onTouchStart,!1),e.removeEventListener("touchmove",this.onTouchMove,!1),e.removeEventListener("touchend",this.onTouchEnd,!1),e.removeEventListener("touchcancel",this.onTouchCancel,!1)},o.notNeeded=function(e){var t,n,i,o;if("undefined"==typeof window.ontouchstart)return!0;if(n=+(/Chrome\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]){if(!s)return!0;if(t=document.querySelector("meta[name=viewport]")){if(t.content.indexOf("user-scalable=no")!==-1)return!0;if(n>31&&document.documentElement.scrollWidth<=window.outerWidth)return!0}}if(l&&(i=navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/),i[1]>=10&&i[2]>=3&&(t=document.querySelector("meta[name=viewport]")))){if(t.content.indexOf("user-scalable=no")!==-1)return!0;if(document.documentElement.scrollWidth<=window.outerWidth)return!0}return"none"===e.style.msTouchAction||"manipulation"===e.style.touchAction||(o=+(/Firefox\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1],!!(o>=27&&(t=document.querySelector("meta[name=viewport]"),t&&(t.content.indexOf("user-scalable=no")!==-1||document.documentElement.scrollWidth<=window.outerWidth)))||("none"===e.style.touchAction||"manipulation"===e.style.touchAction))},o.attach=function(e,t){return new o(e,t)},i=function(){return o}.call(t,n,t,e),!(void 0!==i&&(e.exports=i))}()},function(e,t,n){var i,o;!function(){var r=function(e){var t=new r.Index;return t.pipeline.add(r.trimmer,r.stopWordFilter,r.stemmer),e&&e.call(t,t),t};r.version="0.7.1",/*! * lunr.utils * Copyright (C) 2016 Oliver Nightingale */ @@ -33,7 +33,7 @@ r.SortedSet=function(){this.length=0,this.elements=[]},r.SortedSet.load=function * lunr.Index * Copyright (C) 2016 Oliver Nightingale */ -r.Index=function(){this._fields=[],this._ref="id",this.pipeline=new r.Pipeline,this.documentStore=new r.Store,this.tokenStore=new r.TokenStore,this.corpusTokens=new r.SortedSet,this.eventEmitter=new r.EventEmitter,this.tokenizerFn=r.tokenizer,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},r.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},r.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},r.Index.load=function(e){e.version!==r.version&&r.utils.warn("version mismatch: current "+r.version+" importing "+e.version);var t=new this;return t._fields=e.fields,t._ref=e.ref,t.tokenizer=r.tokenizer.load(e.tokenizer),t.documentStore=r.Store.load(e.documentStore),t.tokenStore=r.TokenStore.load(e.tokenStore),t.corpusTokens=r.SortedSet.load(e.corpusTokens),t.pipeline=r.Pipeline.load(e.pipeline),t},r.Index.prototype.field=function(e,t){var t=t||{},n={name:e,boost:t.boost||1};return this._fields.push(n),this},r.Index.prototype.ref=function(e){return this._ref=e,this},r.Index.prototype.tokenizer=function(e){var t=e.label&&e.label in r.tokenizer.registeredFunctions;return t||r.utils.warn("Function is not a registered tokenizer. This may cause problems when serialising the index"),this.tokenizerFn=e,this},r.Index.prototype.add=function(e,t){var n={},i=new r.SortedSet,o=e[this._ref],t=void 0===t||t;this._fields.forEach(function(t){var o=this.pipeline.run(this.tokenizerFn(e[t.name]));n[t.name]=o;for(var r=0;r0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[t]=i},r.Index.prototype.search=function(e){var t=this.pipeline.run(this.tokenizerFn(e)),n=new r.Vector,i=[],o=this._fields.reduce(function(e,t){return e+t.boost},0),s=t.some(function(e){return this.tokenStore.has(e)},this);if(!s)return[];t.forEach(function(e,t,s){var a=1/s.length*this._fields.length*o,c=this,l=this.tokenStore.expand(e).reduce(function(t,i){var o=c.corpusTokens.indexOf(i),s=c.idf(i),l=1,u=new r.SortedSet;if(i!==e){var h=Math.max(3,i.length-e.length);l=1/Math.log(h)}o>-1&&n.insert(o,a*s*l);for(var d=c.tokenStore.get(i),f=Object.keys(d),p=f.length,m=0;m0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[t]=i},r.Index.prototype.search=function(e){var t=this.pipeline.run(this.tokenizerFn(e)),n=new r.Vector,i=[],o=this._fields.reduce(function(e,t){return e+t.boost},0),s=t.some(function(e){return this.tokenStore.has(e)},this);if(!s)return[];t.forEach(function(e,t,s){var a=1/s.length*this._fields.length*o,c=this,u=this.tokenStore.expand(e).reduce(function(t,i){var o=c.corpusTokens.indexOf(i),s=c.idf(i),u=1,l=new r.SortedSet;if(i!==e){var d=Math.max(3,i.length-e.length);u=1/Math.log(d)}o>-1&&n.insert(o,a*s*u);for(var h=c.tokenStore.get(i),f=Object.keys(h),p=f.length,m=0;m0&&this.el_[e-1].classList.add("md-nav__link--marked"),this.index_=e}else for(var n=this.index_;n>=0;n--){var i=document.querySelector(this.el_[n].hash);if(!(i.offsetTop>window.pageYOffset)){this.index_=n;break}n>0&&this.el_[n-1].classList.remove("md-nav__link--marked")}this.offset_=window.pageYOffset}},{key:"reset",value:function(){[].forEach.call(this.el_,function(e){e.classList.remove("md-nav__link--marked")})}},{key:"listen",value:function(){var e=this;["scroll","resize","orientationchange"].forEach(function(t){window.addEventListener(t,e.handler_,!1)}),this.update()}},{key:"unlisten",value:function(){var e=this;["scroll","resize","orientationchange"].forEach(function(t){window.removeEventListener(t,e.handler_,!1)}),this.reset()}}]),e}();t["default"]=o}]); \ No newline at end of file +r.TokenStore=function(){this.root={docs:{}},this.length=0},r.TokenStore.load=function(e){var t=new this;return t.root=e.root,t.length=e.length,t},r.TokenStore.prototype.add=function(e,t,n){var n=n||this.root,i=e.charAt(0),o=e.slice(1);return i in n||(n[i]={docs:{}}),0===o.length?(n[i].docs[t.ref]=t,void(this.length+=1)):this.add(o,t,n[i])},r.TokenStore.prototype.has=function(e){if(!e)return!1;for(var t=this.root,n=0;n0&&(this.els_[e-1].dataset.mdMarked=!0),this.index_=e;else for(var t=this.index_;t>=0;t--){if(!(this.anchors_[t].offsetTop>window.pageYOffset)){this.index_=t;break}t>0&&delete this.els_[t-1].dataset.mdMarked}this.offset_=window.pageYOffset}},{key:"reset",value:function(){[].forEach.call(this.els_,function(e){delete e.dataset.mdMarked})}}]),t}(u["default"]);t["default"]=l,e.exports=t["default"]},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n",r.insertBefore(n.lastChild,r.firstChild)}function r(){var e=C.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=C.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),C.elements=n+" "+e,l(t)}function i(e){var t=x[e[E]];return t||(t={},w++,e[E]=w,x[w]=t),t}function a(e,n,r){if(n||(n=t),v)return n.createElement(e);r||(r=i(n));var o;return o=r.cache[e]?r.cache[e].cloneNode():b.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!o.canHaveChildren||S.test(e)||o.tagUrn?o:r.frag.appendChild(o)}function s(e,n){if(e||(e=t),v)return e.createDocumentFragment();n=n||i(e);for(var o=n.frag.cloneNode(),a=0,s=r(),c=s.length;a+~])("+r().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+_+"\\:$2";o--;)t=n[o]=n[o].split("}"),t[t.length-1]=t[t.length-1].replace(i,a),n[o]=t.join("}");return n.join("{")}function p(e){for(var t=e.length;t--;)e[t].removeNode()}function m(e){function t(){clearTimeout(a._removeSheetTimer),r&&r.removeNode(!0),r=null}var r,o,a=i(e),s=e.namespaces,c=e.parentWindow;return!N||e.printShived?e:("undefined"==typeof s[_]&&s.add(_),c.attachEvent("onbeforeprint",function(){t();for(var i,a,s,c=e.styleSheets,l=[],f=c.length,p=Array(f);f--;)p[f]=c[f];for(;s=p.pop();)if(!s.disabled&&T.test(s.media)){try{i=s.imports,a=i.length}catch(m){a=0}for(f=0;f",h="hidden"in e,v=1==e.childNodes.length||function(){t.createElement("a");var e=t.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(n){h=!0,v=!0}}();var C={elements:y.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:g,shivCSS:y.shivCSS!==!1,supportsUnknownElements:v,shivMethods:y.shivMethods!==!1,type:"default",shivDocument:l,createElement:a,createDocumentFragment:s,addElements:o};e.html5=C,l(t);var T=/^$|\b(?:all|print)\b/,_="html5shiv",N=!v&&function(){var n=t.documentElement;return!("undefined"==typeof t.namespaces||"undefined"==typeof t.parentWindow||"undefined"==typeof n.applyElement||"undefined"==typeof n.removeNode||"undefined"==typeof e.attachEvent)}();C.type+=" print",C.shivPrint=m,m(t),"object"==typeof module&&module.exports&&(module.exports=C)}("undefined"!=typeof e?e:this,t);var _={elem:l("modernizr")};E._q.push(function(){delete _.elem});var N={style:_.elem.style};E._q.unshift(function(){delete N.style});b.testProp=function(e,t,r){return h([e],n,t,r)};E.addTest("svg",!!t.createElementNS&&!!t.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect);var j=b.testStyles=f,k=function(){var e=navigator.userAgent,t=e.match(/applewebkit\/([0-9]+)/gi)&&parseFloat(RegExp.$1),n=e.match(/w(eb)?osbrowser/gi),r=e.match(/windows phone/gi)&&e.match(/iemobile\/([0-9])+/gi)&&parseFloat(RegExp.$1)>=9,o=t<533&&e.match(/android/gi);return n||o||r}();k?E.addTest("fontface",!1):j('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),o=r.sheet||r.styleSheet,i=o?o.cssRules&&o.cssRules[0]?o.cssRules[0].cssText:o.cssText||"":"",a=/src/i.test(i)&&0===i.indexOf(n.split(" ")[0]);E.addTest("fontface",a)});var z="Moz O ms Webkit",A=b._config.usePrefixes?z.split(" "):[];b._cssomPrefixes=A;var P=b._config.usePrefixes?z.toLowerCase().split(" "):[];b._domPrefixes=P,b.testAllProps=g,b.testAllProps=y;var F="CSS"in e&&"supports"in e.CSS,$="supportsCSS"in e;E.addTest("supports",F||$),E.addTest("csstransforms3d",function(){var e=!!y("perspective","1px",!0),t=E._config.usePrefixes;if(e&&(!t||"webkitPerspective"in C.style)){var n,r="#modernizr{width:0;height:0}";E.supports?n="@supports (perspective: 1px)":(n="@media (transform-3d)",t&&(n+=",(-webkit-transform-3d)")),n+="{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}",j(r+n,function(t){e=7===t.offsetWidth&&18===t.offsetHeight})}return e});var R=function(){function e(e,t){var o;return!!e&&(t&&"string"!=typeof t||(t=l(t||"div")),e="on"+e,o=e in t,!o&&r&&(t.setAttribute||(t=l("div")),t.setAttribute(e,""),o="function"==typeof t[e],t[e]!==n&&(t[e]=n),t.removeAttribute(e)),o)}var r=!("onblur"in t.documentElement);return e}();b.hasEvent=R,E.addTest("inputsearchevent",R("search")),E.addTest("json","JSON"in e&&"parse"in JSON&&"stringify"in JSON),E.addTest("checked",function(){return j("#modernizr {position:absolute} #modernizr input {margin-left:10px} #modernizr :checked {margin-left:20px;display:block}",function(e){var t=l("input");return t.setAttribute("type","checkbox"),t.setAttribute("checked","checked"),e.appendChild(t),20===t.offsetLeft})}),E.addTest("target",function(){var t=e.document;if(!("querySelectorAll"in t))return!1;try{return t.querySelectorAll(":target"),!0}catch(n){return!1}}),E.addTest("contains",r(String.prototype.contains,"function")),o(),i(x),delete b.addTest,delete b.addAsyncTest;for(var q=0;q=9,s=t<533&&e.match(/android/gi);return n||s||r}();P?S.addTest("fontface",!1):E('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),s=r.sheet||r.styleSheet,o=s?s.cssRules&&s.cssRules[0]?s.cssRules[0].cssText:s.cssText||"":"",i=/src/i.test(o)&&0===o.indexOf(n.split(" ")[0]);S.addTest("fontface",i)});var z="Moz O ms Webkit",N=C._config.usePrefixes?z.split(" "):[];C._cssomPrefixes=N;var j={elem:a("modernizr")};S._q.push(function(){delete j.elem});var k={style:j.elem.style};S._q.unshift(function(){delete k.style});var R=C._config.usePrefixes?z.toLowerCase().split(" "):[];C._domPrefixes=R,C.testAllProps=v,C.testAllProps=y;var A="CSS"in e&&"supports"in e.CSS,q="supportsCSS"in e;S.addTest("supports",A||q),S.addTest("csstransforms3d",function(){var e=!!y("perspective","1px",!0),t=S._config.usePrefixes;if(e&&(!t||"webkitPerspective"in b.style)){var n,r="#modernizr{width:0;height:0}";S.supports?n="@supports (perspective: 1px)":(n="@media (transform-3d)",t&&(n+=",(-webkit-transform-3d)")),n+="{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}",E(r+n,function(t){e=7===t.offsetWidth&&18===t.offsetHeight})}return e}),s(),o(x),delete C.addTest,delete C.addAsyncTest;for(var L=0;Lcode{font-size:inherit}.md-typeset>div>pre::-webkit-scrollbar,.md-typeset>pre>code::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset>div>pre::-webkit-scrollbar-thumb,.md-typeset>pre>code::-webkit-scrollbar-thumb{background:rgba(0,0,0,.26)}.md-typeset kbd{display:inline-block;padding:.4rem .5rem .5rem;border:.1rem solid #c9c9c9;border-radius:.3rem;border-bottom-color:#bcbcbc;background-color:#fcfcfc;color:#555;font-size:85%;line-height:1rem;box-shadow:inset 0 -.1rem 0 #b0b0b0;vertical-align:.1rem;word-break:break-word}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.1rem}.md-typeset blockquote{padding-left:1.2rem;border-left:.4rem solid rgba(0,0,0,.26);color:rgba(0,0,0,.54)}.md-typeset ul{list-style-type:disc}.md-typeset ol ol{list-style-type:lower-alpha}.md-typeset ol ol ol{list-style-type:lower-roman}.md-typeset ol,.md-typeset ul{margin-left:1rem;padding:0}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:2rem}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:1rem;margin-left:1rem;padding-top:1rem}html{height:100%;font-size:62.5%}body{position:relative;min-height:100%}body.md-js__body--locked{height:100%;overflow:hidden}hr{display:block;height:.1rem;padding:0;border:0}.md-grid{max-width:120rem;margin-right:auto;margin-left:auto}.md-container,.md-main{overflow:auto}.md-main{margin-top:5.6rem}.md-main__inner{margin-top:3rem;margin-bottom:9.2rem;overflow:auto}.md-toggle{display:none}.md-overlay{position:fixed;top:0;width:0;height:0;-webkit-transition:width 0s .25s,height 0s .25s,opacity .25s;transition:width 0s .25s,height 0s .25s,opacity .25s;background:rgba(0,0,0,.54);opacity:0;z-index:2}.md-flex{display:table}.md-flex__cell{display:table-cell;position:relative;vertical-align:top}.md-flex__cell--shrink{width:0}.md-flex__cell--stretch{display:table;width:100%;table-layout:fixed}.md-flex__ellipsis{display:table-cell;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md-content__inner{margin:2.4rem 1.6rem}.md-content__copyright{display:block}.md-header{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);position:fixed;top:0;right:0;left:0;height:5.6rem;background:#3f51b5;color:#fff;z-index:1}.md-header-nav{padding:.4rem}.md-header-nav__icon{position:relative;-webkit-transition:opacity .25s;transition:opacity .25s;z-index:1}.md-header-nav__icon:hover{opacity:.7}.md-header-nav__title{padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-header-nav__source{display:none}.md-footer{position:absolute;bottom:0;width:100%}.md-footer-pagination{background:rgba(0,0,0,.87);color:#fff}.md-footer-nav{padding:.4rem;overflow:auto}.md-footer-nav__link{padding-top:2.8rem;padding-bottom:.8rem;-webkit-transition:opacity .25s;transition:opacity .25s}.md-footer-nav__link:hover{opacity:.7}.md-footer-nav__link--prev{width:25%;float:left}.md-footer-nav__link--next{width:75%;float:right;text-align:right}.md-footer-nav__icon{-webkit-transition:background .25s;transition:background .25s}.md-footer-nav__title{position:relative;padding:0 .4rem;font-size:1.8rem;line-height:4.8rem}.md-footer-nav__direction{position:absolute;right:0;left:0;margin-top:-2rem;padding:0 .4rem;color:hsla(0,0%,100%,.7);font-size:1.5rem}.md-nav{font-size:1.28rem;line-height:1.3}.md-nav--secondary{border-left:.4rem solid #3f51b5}.md-nav__title{display:block;padding:1.2rem 1.2rem 0;font-weight:700;text-overflow:ellipsis;overflow:hidden}.md-nav__title:before{display:none;content:"arrow_back"}.md-nav__list{margin:0;padding:0;list-style:none}.md-nav__item{padding:.625em 1.2rem 0}.md-nav__item:last-child{padding-bottom:1.2rem}.md-nav__item .md-nav__item{padding-right:0}.md-nav__item .md-nav__item:last-child{padding-bottom:0}.md-nav__link{display:block;-webkit-transition:color .125s;transition:color .125s;text-overflow:ellipsis;cursor:pointer;overflow:hidden}.md-nav__item--nested>.md-nav__link:after{content:"expand_more"}html .md-nav__link[for=toc],html .md-nav__link[for=toc]+.md-nav__link:after,html .md-nav__link[for=toc]~.md-nav{display:none}.md-nav__link[data-md-marked]{color:rgba(0,0,0,.54)}.md-nav__link--active,.md-nav__link:active,.md-nav__link:hover{color:#536dfe}.md-nav__source{display:none}.md-search{padding:.8rem .8rem 0}.no-js .md-search{display:none}.md-search__form{position:relative;border-radius:.2rem;text-align:right}.md-search__icon{position:absolute;top:.8rem;left:1.2rem;-webkit-transition:color .25s;transition:color .25s;font-size:2.4rem;cursor:pointer}.md-search__input{padding:0 1.6rem 0 6.4rem;border-radius:.2rem;text-overflow:ellipsis}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-sidebar{position:relative;width:24.2rem;float:left;overflow:visible}.md-sidebar[data-md-locked]{position:fixed;top:5.6rem}.md-sidebar--secondary{display:none}.md-sidebar__scrollwrap{margin:2.4rem .4rem;overflow-y:scroll}.js .md-sidebar__scrollwrap{position:absolute;top:0;right:0;bottom:0;left:0}.md-sidebar__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-source{display:block;-webkit-transition:opacity .25s;transition:opacity .25s;font-size:1.3rem;line-height:1.2;white-space:nowrap}.md-source:hover{opacity:.7}.md-source:before{display:inline-block;height:4.8rem;content:"";vertical-align:middle}.md-source--bitbucket:before,.md-source--github:before,.md-source--gitlab:before{width:4.8rem;background-repeat:no-repeat;background-position:50%;background-size:2.4rem 2.4rem}.md-source--bitbucket .md-source__repository,.md-source--github .md-source__repository,.md-source--gitlab .md-source__repository{margin-left:-4.4rem;padding-left:4rem}.md-source--bitbucket:before{background-image:url(../images/icons/bitbucket-white-42306ad0de.svg)}.md-source--github:before{background-image:url(../images/icons/github-white-1cfc8ff99e.svg)}.md-source--gitlab:before{background-image:url(../images/icons/gitlab-white-d65054b8fe.svg)}.md-source__repository{display:inline-block;max-width:100%;margin-left:.8rem;font-weight:700;text-overflow:ellipsis;overflow:hidden;vertical-align:middle}.md-source__facts{margin:0;padding:0;font-size:1.1rem;font-weight:700;opacity:.75;list-style-type:none}.md-source__fact{float:left;-webkit-transform:translateY(0);transform:translateY(0);-webkit-transition:opacity .25s,-webkit-transform .25s cubic-bezier(.1,.7,.1,1);transition:opacity .25s,-webkit-transform .25s cubic-bezier(.1,.7,.1,1);transition:opacity .25s,transform .25s cubic-bezier(.1,.7,.1,1);transition:opacity .25s,transform .25s cubic-bezier(.1,.7,.1,1),-webkit-transform .25s cubic-bezier(.1,.7,.1,1);opacity:1}.md-source__fact--hidden{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}.md-source__fact:before{margin:0 .2rem;content:"\00B7"}.md-source__fact:first-child:before{display:none}.admonition{position:relative;margin:2rem 0;padding:.8rem 1.6rem;border-left:3.2rem solid #448aff;border-radius:.2rem;background:rgba(68,138,255,.05)}.admonition:before{display:block;position:absolute;top:.2rem;left:-2.6rem;float:left;color:#fff;font-family:Material Icons;font-size:2rem;font-weight:400;content:"edit";vertical-align:-.1em}.admonition-title{color:#2979ff;font-size:1.28rem;font-weight:700;line-height:2;text-transform:uppercase}html .admonition-title{margin-bottom:1.6rem}html .admonition-title+*{margin-top:1.6rem}.admonition :first-child{margin-top:0}.admonition :last-child{margin-bottom:0}.admonition.summary,.admonition.tldr{border-color:#00b0ff;background:rgba(0,176,255,.05)}.admonition.summary:before,.admonition.tldr:before{content:"subject"}.admonition.summary .admonition-title,.admonition.tldr .admonition-title{color:#00b0ff}.admonition.idea,.admonition.tip{border-color:#00bfa5;background:rgba(0,191,165,.05)}.admonition.idea:before,.admonition.tip:before{content:"whatshot"}.admonition.idea .admonition-title,.admonition.tip .admonition-title{color:#00bfa5}.admonition.check,.admonition.done,.admonition.success{border-color:#00e676;background:rgba(0,230,118,.05)}.admonition.check:before,.admonition.done:before,.admonition.success:before{content:"done"}.admonition.check .admonition-title,.admonition.done .admonition-title,.admonition.success .admonition-title{color:#00e676}.admonition.warn,.admonition.warning{border-color:#ff9100;background:rgba(255,145,0,.05)}.admonition.warn:before,.admonition.warning:before{content:"warning"}.admonition.warn .admonition-title,.admonition.warning .admonition-title{color:#ff9100}.admonition.fail,.admonition.failure,.admonition.missing{border-color:#ff5252;background:rgba(255,82,82,.05)}.admonition.fail:before,.admonition.failure:before,.admonition.missing:before{content:"clear"}.admonition.fail .admonition-title,.admonition.failure .admonition-title,.admonition.missing .admonition-title{color:#ff5252}.admonition.danger,.admonition.fatal{border-color:#ff1744;background:rgba(255,23,68,.05)}.admonition.danger:before,.admonition.fatal:before{content:"flash_on"}.admonition.danger .admonition-title,.admonition.fatal .admonition-title{color:#ff1744}.admonition.bug,.admonition.error{border-color:#f50057;background:rgba(245,0,87,.05)}.admonition.bug:before,.admonition.error:before{content:"bug_report"}.admonition.bug .admonition-title,.admonition.error .admonition-title{color:#f50057}.code .err,.codehilite .err{color:#a61717}.code .o,.codehilite .o{color:inherit}.code .ge,.codehilite .ge{color:#000}.code .gr,.codehilite .gr{color:#a00}.code .gh,.codehilite .gh{color:#999}.code .go,.codehilite .go{color:#888}.code .gp,.codehilite .gp{color:#555}.code .gs,.codehilite .gs{color:inherit}.code .gu,.codehilite .gu{color:#aaa}.code .gt,.codehilite .gt{color:#a00}.code .k,.code .kc,.code .kd,.code .kn,.code .kp,.codehilite .k,.codehilite .kc,.codehilite .kd,.codehilite .kn,.codehilite .kp{color:#a71d5d}.code .kr,.code .kt,.codehilite .kr,.codehilite .kt{color:#0086b3}.code .c,.code .cm,.codehilite .c,.codehilite .cm{color:#969896}.code .cp,.codehilite .cp{color:#666}.code .c1,.code .cs,.codehilite .c1,.codehilite .cs{color:#969896}.code .bp,.code .na,.code .nb,.code .nc,.code .nd,.code .ne,.code .nf,.code .ni,.code .nl,.code .nn,.code .no,.code .nt,.code .nv,.code .vc,.code .vg,.code .vi,.codehilite .bp,.codehilite .na,.codehilite .nb,.codehilite .nc,.codehilite .nd,.codehilite .ne,.codehilite .nf,.codehilite .ni,.codehilite .nl,.codehilite .nn,.codehilite .no,.codehilite .nt,.codehilite .nv,.codehilite .vc,.codehilite .vg,.codehilite .vi{color:#795da3}.code .ow,.codehilite .ow{color:inherit}.code .il,.code .m,.code .mf,.code .mh,.code .mi,.code .mo,.codehilite .il,.codehilite .m,.codehilite .mf,.codehilite .mh,.codehilite .mi,.codehilite .mo{color:#0086b3}.code .s,.code .s2,.code .sb,.code .sc,.code .sd,.code .se,.code .sh,.code .si,.code .sx,.codehilite .s,.codehilite .s2,.codehilite .sb,.codehilite .sc,.codehilite .sd,.codehilite .se,.codehilite .sh,.codehilite .si,.codehilite .sx{color:#183691}.code .sr,.codehilite .sr{color:#009926}.code .s1,.codehilite .s1{color:#d01040}.code .ss,.codehilite .ss{color:#990073}.code .gd,.codehilite .gd{background-color:#fdd}.code .gi,.codehilite .gi{background-color:#dfd}.code .w,.codehilite .w{color:transparent}.footnote{color:rgba(0,0,0,.54);font-size:80%}.footnote ol{margin-left:0}.footnote li:hover .footnote-backref,.footnote li:target .footnote-backref{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}.footnote li:hover .footnote-backref:hover,.footnote li:target .footnote-backref{color:#536dfe}.footnote-ref:before{position:absolute;margin-top:-8rem;padding-top:8rem;content:"";pointer-events:none}.footnote-backref{position:absolute;-webkit-transform:translate3d(.5rem,0,0);transform:translate3d(.5rem,0,0);-webkit-transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s,-webkit-transform .25s .125s;color:rgba(0,0,0,.26);font-size:2rem;opacity:0;vertical-align:middle}.footnote-backref:first-letter{font-size:0}.footnote-backref:after{content:"keyboard_return"}.md-typeset .headerlink{display:inline-block;margin-left:1rem;-webkit-transform:translateY(.5rem);transform:translateY(.5rem);-webkit-transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s,-webkit-transform .25s .25s;color:rgba(0,0,0,.26);opacity:0}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink,.md-typeset [id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink:hover,.md-typeset [id]:target .headerlink{color:#536dfe}.md-typeset h1[id]:before{display:block;margin-top:-11rem;padding-top:11rem;content:""}.md-typeset h2[id]:before{display:block;margin-top:-8.2rem;padding-top:8.2rem;content:""}.md-typeset h3[id]:before{display:block;margin-top:-8.4rem;padding-top:8.4rem;content:""}.md-typeset h4[id]:before{display:block;margin-top:-8.6rem;padding-top:8.6rem;content:""}.md-typeset h5[id]:before,.md-typeset h6[id]:before{display:block;margin-top:-9rem;padding-top:9rem;content:""}.md-search__input:focus{border-radius:.3rem .3rem 0 0}.md-search-term{position:relative;padding:0 .8rem 0 4.8rem;line-height:4rem;font-size:1.6rem;-webkit-transition:background .25s;transition:background .25s;cursor:pointer}.md-search-term:before{position:absolute;content:"access_time";font-size:2.4rem;line-height:4rem;left:1.2rem;color:rgba(0,0,0,.26)}.md-search-term:hover{background:#eceef8}.checklist li{position:relative;list-style-type:none}.checklist li:before{position:absolute;-webkit-appearance:none;-moz-appearance:none;appearance:none;color:blue;content:"check_box";font-size:2.4rem}.checklist input[type=checkbox]:checked{width:20px}del.critic,ins.critic,mark{margin:0 .4rem;padding:.1rem 0;word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone;border-radius:.2rem}ins.critic{background:#dfd;box-shadow:.4rem 0 0 #dfd,-.4rem 0 0 #dfd;text-decoration:none}del.critic{background:#fdd;box-shadow:.4rem 0 0 #fdd,-.4rem 0 0 #fdd}mark{background:#ff0;box-shadow:.4rem 0 0 #ff0,-.4rem 0 0 #ff0;overflow:auto}.critic.comment{margin:0 .4rem;padding:.1rem 0;border-radius:.2rem;background:#f0f0f0;color:#37474f;box-shadow:.4rem 0 0 #f0f0f0,-.4rem 0 0 #f0f0f0;-webkit-box-decoration-break:clone;box-decoration-break:clone}.critic.comment:before{color:rgba(0,0,0,.26);content:"chat";font-size:1.6rem;padding-right:.2rem;vertical-align:-.2rem}.md-button{float:right;margin-top:9px;font-size:13px;padding-left:2.6rem;font-weight:700;text-transform:uppercase}.task-list-item{list-style-type:none}.task-list-item input{margin:0 4px .25em -20px;vertical-align:middle}.task-list-item{position:relative}.task-list-item input[type=checkbox]{opacity:0}.task-list-item input[type=checkbox]+label{display:block;position:absolute;top:50%;left:-24px;width:16px;margin-top:-8px;height:16px;border-radius:2px;background:#ccc}.task-list-item input[type=checkbox]:checked+label:before{display:block;margin-top:-4px;margin-left:2px;font-size:1.2em;line-height:1;border-radius:2px;content:"✔";color:#1ebb52}.codehilite .hll{background:#ff0;display:block;margin:0 -16px;padding:0 16px}.md-search__output{overflow-y:auto}@media only screen and (max-width:44.9375em){.md-typeset>div>pre,.md-typeset>pre>code{margin:1em -1.6rem;padding:1rem 1.6rem;border-radius:0}.md-search__form{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2)}.md-search__icon{top:1.2rem}.md-search__icon:before{content:"arrow_back"}.md-search__input{width:100%;height:4.8rem;font-size:1.8rem}.md-search__inner{position:fixed;top:0;left:100%;width:100%;height:56px;opacity:0;z-index:2;-webkit-transform:translate3d(5%,0,0);transform:translate3d(5%,0,0);-webkit-transition:opacity .15s .15s,-webkit-transform .3s cubic-bezier(.1,.7,.1,1) .15s;transition:opacity .15s .15s,-webkit-transform .3s cubic-bezier(.1,.7,.1,1) .15s;transition:transform .3s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;transition:transform .3s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s,-webkit-transform .3s cubic-bezier(.1,.7,.1,1) .15s}.md-toggle--search:checked~.md-header .md-search__inner{-webkit-transform:translateZ(0);transform:translateZ(0);left:0;opacity:1}.md-search__suggest{position:relative;z-index:2}}@media only screen and (min-width:100em){html{font-size:68.75%}}@media only screen and (min-width:125em){html{font-size:75%}}@media only screen and (max-width:74.9375em){.md-toggle--drawer:checked~.md-overlay{width:100%;height:100%;-webkit-transition:width 0s,height 0s,opacity .25s;transition:width 0s,height 0s,opacity .25s;opacity:1}.md-header-nav__icon--home{display:none}.md-nav--primary,.md-nav--primary .md-nav{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;top:0;right:0;left:0;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:100%;z-index:1}.md-nav--primary{background:#fff}.md-nav--primary .md-nav__toggle~.md-nav{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.4);left:.4rem;background:#fff}html .md-nav--primary .md-nav__title{position:relative;padding:.4rem 1.6rem .4rem 5.6rem;background:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-size:1.8rem;font-weight:400;line-height:4.8rem;white-space:nowrap;cursor:pointer}html .md-nav--primary .md-nav__title:before{display:block;position:absolute;left:.4rem;width:4rem;height:4rem;color:rgba(0,0,0,.54)}html .md-nav--primary .md-nav__title~.md-nav__list>.md-nav__item:first-child{border-top:0}.md-nav--primary .md-nav__list{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow-y:scroll}.md-nav--primary .md-nav__item{padding:0;border-top:.1rem solid rgba(0,0,0,.07)}.md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:4.8rem}.md-nav--primary .md-nav__link{position:relative;padding:1.6rem}.md-nav--primary .md-nav__link:after{position:absolute;top:50%;right:1.2rem;-webkit-transform:translateY(-50%) rotate(-90deg);transform:translateY(-50%) rotate(-90deg);-webkit-transition:inherit;transition:inherit;color:rgba(0,0,0,.54);font-size:2.4rem}.md-nav--primary .md-nav__link:hover:after{color:#536dfe}.md-nav--primary .md-nav--secondary .md-nav{position:static}.md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:2.8rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:4rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:5.2rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:6.4rem}.md-nav__toggle~.md-nav{display:none}.csstransforms3d .md-nav__toggle~.md-nav{display:block;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);-webkit-transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s;transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);opacity:0}.md-nav__toggle:checked~.md-nav{display:block}.csstransforms3d .md-nav__toggle:checked~.md-nav{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1}.md-nav .md-nav__item,.md-nav .md-nav__title{font-size:1.6rem;line-height:1.4}.md-sidebar--primary{position:fixed;top:0;left:-24.2rem;width:24.2rem;height:100%;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);background:#fff;z-index:2}.no-csstransforms3d .md-sidebar--primary{display:none}.md-toggle--drawer:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);-webkit-transform:translate3d(24.2rem,0,0);transform:translate3d(24.2rem,0,0)}.no-csstransforms3d .md-toggle--drawer:checked~.md-container .md-sidebar--primary{display:block}.md-sidebar--primary .md-sidebar__scrollwrap{overflow:hidden;margin:0}}@media only screen and (min-width:60em){.md-content{margin-right:24.2rem}.md-header-nav__source{display:block;width:23rem;max-width:23rem;padding-right:1.2rem}.md-sidebar--secondary{display:block;float:right}.md-sidebar--secondary[data-md-locked]{margin-left:100%;-webkit-transform:translate(-100%);transform:translate(-100%)}}@media only screen and (min-width:75em){.md-content{margin-left:24.2rem}.md-content__inner{margin:2.4rem}.md-header-nav__icon--menu{display:none}.md-nav.md-nav--transitioning{-webkit-transition:max-height .25s cubic-bezier(.86,0,.07,1);transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav__toggle~.md-nav{max-height:0;overflow:hidden}.md-nav.md-nav--toggled,.md-nav__toggle:checked~.md-nav{max-height:100%}.md-nav__title+.md-nav__list .md-nav__title{display:none}.md-nav__item--nested>.md-nav__link:after{display:inline-block;-webkit-transform-origin:.45em .45em;transform-origin:.45em .45em;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;vertical-align:-.125em}.js .md-nav__item--nested>.md-nav__link:after{-webkit-transition:-webkit-transform .4s;transition:-webkit-transform .4s;transition:transform .4s;transition:transform .4s,-webkit-transform .4s}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link:after{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.md-sidebar__inner{border-right:.1rem solid rgba(0,0,0,.07)}.md-search__output{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);width:100%;max-height:0;opacity:0;-webkit-transition:opacity .4s,max-height .4s;transition:opacity .4s,max-height .4s;position:absolute;background:#fff;border-top:.1rem solid rgba(0,0,0,.07);text-align:left;border-radius:0 0 .3rem .3rem;z-index:-1}.md-js__search--locked .md-search__output{max-height:75vh;opacity:1}.md-search__output::-webkit-scrollbar{width:.4rem;height:.4rem}.md-search__output::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-search__output::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-search__output{background:-webkit-linear-gradient(#fff 10%,hsla(0,0%,100%,0)),-webkit-linear-gradient(top,rgba(0,0,0,.5),rgba(0,0,0,.2) 20%,transparent 60%);background:linear-gradient(#fff 10%,hsla(0,0%,100%,0)),linear-gradient(180deg,rgba(0,0,0,.5),rgba(0,0,0,.2) 20%,transparent 60%);background-repeat:no-repeat;background-color:#fff;background-size:100% 20px,100% 5px;background-attachment:local,scroll}.md-search-result__meta{color:rgba(0,0,0,.54);padding-left:4.8rem;padding-right:1.6rem;line-height:4rem;font-size:1.28rem}.md-search-result__list{margin:0;padding:0;list-style-type:none;border-top:.1rem solid rgba(0,0,0,.07)}.md-search-result__link{overflow:auto;display:block;padding-left:4.8rem;padding-right:1.6rem}.md-search-result__link:hover{background:#ff0}.md-search-result__title{color:rgba(0,0,0,.87);font-size:1.6rem;line-height:1.4;margin-top:.5em}.md-search-result__description{color:rgba(0,0,0,.54);font-size:1.28rem;line-height:1.4;margin:.5em 0}}@media only screen and (min-width:45em){.md-header-nav__icon--search{display:none}.md-search{padding:.4rem;padding-right:3.2rem}.md-search__form{width:23rem;-webkit-transition:width .25s cubic-bezier(.1,.7,.1,1);transition:width .25s cubic-bezier(.1,.7,.1,1)}.md-js__search--locked .md-search__form{width:66.8rem}.md-search__input{width:100%;height:4rem;padding-left:4.8rem;-webkit-transition:background-color .25s,color .25s;transition:background-color .25s,color .25s;background:rgba(0,0,0,.26);color:#fff;font-size:1.6rem}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input:hover{background:hsla(0,0%,100%,.12)}.md-js__search--locked .md-search__input{border-radius:.3rem .3rem 0 0;background:#fff;color:rgba(0,0,0,.87);text-overflow:none}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input::placeholder{color:rgba(0,0,0,.54)}}@media only screen and (min-width:30em){.md-footer-nav__link{width:50%}}@media only screen and (max-width:29.9375em){.md-footer-nav__link--prev .md-footer-nav__title{display:none}}@media only screen and (max-width:59.9375em){.md-nav--secondary{border-left:0}html .md-nav__link[for=toc]{display:block}html .md-nav__link[for=toc]:after{-webkit-transform:translateY(-50%);transform:translateY(-50%);color:#536dfe;content:"toc"}html .md-nav__link[for=toc]+.md-nav__link{display:none}html .md-nav__link[for=toc]~.md-nav{display:-webkit-box;display:-ms-flexbox;display:flex}.md-nav__source{display:block;padding:.4rem;background:rgba(0,0,0,.87);color:#fff}}@media only screen and (min-width:60em) and (min-width:75em){.md-sidebar--secondary[data-md-locked]{margin-left:120rem}} \ No newline at end of file diff --git a/material/assets/stylesheets/application-bcbe056a5b.css b/material/assets/stylesheets/application-bcbe056a5b.css deleted file mode 100644 index 1f72f18cd..000000000 --- a/material/assets/stylesheets/application-bcbe056a5b.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";.checklist li:before,.critic.comment:before,.footnote-backref,.md-icon,.md-nav__link:after,.md-nav__title:before,.md-search-term:before{font-family:Material Icons;font-style:normal;font-variant:normal;font-weight:400;line-height:1;text-transform:none;white-space:nowrap;speak:none;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.md-footer-nav__icon,.md-header-nav__icon,.md-nav__title:before{display:inline-block;margin:.4rem;padding:.8rem;font-size:2.4rem;cursor:pointer}.md-icon--back:before{content:"arrow_back"}.md-icon--forward:before{content:"arrow_forward"}.md-icon--close:before{content:"close"}html{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}*,:after,:before{box-sizing:inherit;-moz-box-sizing:inherit;-webkit-box-sizing:inherit}html{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none}body{margin:0}article,aside,figcaption,figure,footer,header,main,nav,section{display:block}hr{overflow:visible;box-sizing:content-box}a{color:inherit;text-decoration:none}a:active,a:hover{outline-width:0}a{-webkit-text-decoration-skip:objects}a,button,input,label{-webkit-tap-highlight-color:transparent}small,sub,sup{font-size:80%}sub,sup{position:relative;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}table{border-collapse:collapse;border-spacing:0}td,th{font-weight:400;text-align:left;vertical-align:top}button{padding:0;background:transparent;font-size:inherit}button,input{border:0;outline:0}body{color:rgba(0,0,0,.87);font-family:Roboto,Helvetica,Arial,sans-serif;font-weight:400;-webkit-font-feature-settings:"kern","onum","liga";font-feature-settings:"kern","onum","liga";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.no-fontface body{font-family:Helvetica Neue,Helvetica,Arial,sans-serif}code,kbd,pre{color:rgba(0,0,0,.87);font-family:Roboto Mono,Courier New,Courier,monospace;font-weight:400;-webkit-font-feature-settings:"kern","onum","liga";font-feature-settings:"kern","onum","liga"}.no-fontface code,.no-fontface kbd,.no-fontface pre{font-family:Courier New,Courier,monospace}.md-typeset{font-size:1.6rem;line-height:1.6}.md-typeset blockquote,.md-typeset ol,.md-typeset p,.md-typeset ul{margin:1em 0}.md-typeset h1{margin:0 0 4rem;color:rgba(0,0,0,.54);font-size:3.125rem;line-height:1.3}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{margin:4rem 0 1.6rem;font-size:2.5rem;line-height:1.4}.md-typeset h3{margin:3.2rem 0 1.6rem;font-size:2rem;font-weight:400;letter-spacing:-.01em;line-height:1.5}.md-typeset h2+h3{margin-top:1.6rem}.md-typeset h4{font-size:1.6rem}.md-typeset h4,.md-typeset h5,.md-typeset h6{margin:1.6rem 0;font-weight:700;letter-spacing:-.01em}.md-typeset h5,.md-typeset h6{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset h5{text-transform:uppercase}.md-typeset hr{margin:2.4rem 0;border-bottom:.1rem dotted rgba(0,0,0,.26)}.md-typeset a{color:#3f51b5}.md-typeset a,.md-typeset a:before{-webkit-transition:color .125s;transition:color .125s}.md-typeset a:active,.md-typeset a:hover{color:#536dfe}.md-typeset code{margin:0 .4rem;padding:.1rem 0;border-radius:.2rem;background:#f7f7f7;color:#37474f;font-size:85%;box-shadow:.4rem 0 0 #f7f7f7,-.4rem 0 0 #f7f7f7;word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset h1 code,.md-typeset h2 code,.md-typeset h3 code,.md-typeset h4 code,.md-typeset h5 code,.md-typeset h6 code{margin:0;background:transparent;box-shadow:none}.md-typeset pre{margin:1em 0;padding:1rem 1.2rem;border-radius:.2rem;background:#f7f7f7;color:#37474f;font-size:85%;line-height:1.4;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset pre>code{font-size:inherit}.md-typeset>div>pre::-webkit-scrollbar,.md-typeset>pre>code::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset>div>pre::-webkit-scrollbar-thumb,.md-typeset>pre>code::-webkit-scrollbar-thumb{background:rgba(0,0,0,.26)}.md-typeset kbd{display:inline-block;padding:.4rem .5rem .5rem;border:.1rem solid #c9c9c9;border-radius:.3rem;border-bottom-color:#bcbcbc;background-color:#fcfcfc;color:#555;font-size:85%;line-height:1rem;box-shadow:inset 0 -.1rem 0 #b0b0b0;vertical-align:.1rem;word-break:break-word}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.1rem}.md-typeset blockquote{padding-left:1.2rem;border-left:.4rem solid rgba(0,0,0,.26);color:rgba(0,0,0,.54)}.md-typeset ul{list-style-type:disc}.md-typeset ol ol{list-style-type:lower-alpha}.md-typeset ol ol ol{list-style-type:lower-roman}.md-typeset ol,.md-typeset ul{margin-left:1rem;padding:0}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:2rem}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:1rem;margin-left:1rem;padding-top:1rem}html{height:100%;font-size:62.5%}body{position:relative;min-height:100%}body.md-js__body--locked{height:100%;overflow:hidden}hr{display:block;height:.1rem;padding:0;border:0}.md-grid{max-width:120rem;margin-right:auto;margin-left:auto}.md-container,.md-main{overflow:auto}.md-main{margin-top:5.6rem}.md-main__inner{margin-top:3rem;margin-bottom:9.2rem;overflow:auto}.md-toggle{display:none}.md-overlay{position:fixed;top:0;width:0;height:0;-webkit-transition:width 0s .25s,height 0s .25s,opacity .25s;transition:width 0s .25s,height 0s .25s,opacity .25s;background:rgba(0,0,0,.54);opacity:0;z-index:2}.md-flex{display:table}.md-flex__cell{display:table-cell;position:relative;vertical-align:top}.md-flex__cell--shrink{width:0}.md-flex__cell--stretch{display:table;width:100%;table-layout:fixed}.md-flex__ellipsis{display:table-cell;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md-content__inner{margin:2.4rem 1.6rem}.md-content__copyright{display:block}.md-header{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);position:fixed;top:0;right:0;left:0;height:5.6rem;background:#3f51b5;color:#fff;z-index:1}.md-header-nav{padding:.4rem}.md-header-nav__icon{position:relative;-webkit-transition:opacity .25s;transition:opacity .25s;z-index:1}.md-header-nav__icon:hover{opacity:.7}.md-header-nav__title{padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-header-nav__source{display:none}.md-footer{position:absolute;bottom:0;width:100%}.md-footer-pagination{background:rgba(0,0,0,.87);color:#fff}.md-footer-nav{padding:.4rem;overflow:auto}.md-footer-nav__link{padding-top:2.8rem;padding-bottom:.8rem;-webkit-transition:opacity .25s;transition:opacity .25s}.md-footer-nav__link:hover{opacity:.7}.md-footer-nav__link--prev{width:25%;float:left}.md-footer-nav__link--next{width:75%;float:right;text-align:right}.md-footer-nav__icon{-webkit-transition:background .25s;transition:background .25s}.md-footer-nav__title{position:relative;padding:0 .4rem;font-size:1.8rem;line-height:4.8rem}.md-footer-nav__direction{position:absolute;right:0;left:0;margin-top:-2rem;padding:0 .4rem;color:hsla(0,0%,100%,.7);font-size:1.5rem}.md-nav{font-size:1.28rem;line-height:1.3}.md-nav--secondary{border-left:.4rem solid #3f51b5}.md-nav__title{display:block;padding:1.2rem 1.2rem 0;font-weight:700;text-overflow:ellipsis;overflow:hidden}.md-nav__title:before{display:none;content:"arrow_back"}.md-nav__list{margin:0;padding:0;list-style:none}.md-nav__item{padding:.625em 1.2rem 0}.md-nav__item:last-child{padding-bottom:1.2rem}.md-nav__item .md-nav__item{padding-right:0}.md-nav__item .md-nav__item:last-child{padding-bottom:0}.md-nav__link{display:block;-webkit-transition:color .125s;transition:color .125s;text-overflow:ellipsis;cursor:pointer;overflow:hidden}.md-nav__item--nested>.md-nav__link:after{content:"expand_more"}html .md-nav__link[for=toc],html .md-nav__link[for=toc]+.md-nav__link:after,html .md-nav__link[for=toc]~.md-nav{display:none}.md-nav__link--marked{color:rgba(0,0,0,.54)}.md-nav__link--active,.md-nav__link:active,.md-nav__link:hover{color:#536dfe}.md-nav__source{display:none}.md-search{padding:.8rem .8rem 0}.no-js .md-search{display:none}.md-search__form{position:relative;border-radius:.2rem;text-align:right}.md-search__icon{position:absolute;top:.8rem;left:1.2rem;-webkit-transition:color .25s;transition:color .25s;font-size:2.4rem;cursor:pointer}.md-search__input{padding:0 1.6rem 0 6.4rem;border-radius:.2rem;text-overflow:ellipsis}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.md-search__input+.md-search__icon,.md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-sidebar{position:relative;width:24.2rem;float:left;overflow:visible}.md-sidebar.md-js__sidebar--locked{position:fixed;top:5.6rem}.md-sidebar--secondary{display:none}.md-sidebar__scrollwrap{margin:2.4rem .4rem;overflow-y:scroll}.js .md-sidebar__scrollwrap{position:absolute;top:0;right:0;bottom:0;left:0}.md-sidebar__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-source{display:block;-webkit-transition:opacity .25s;transition:opacity .25s;font-size:1.3rem;line-height:1.2;white-space:nowrap}.md-source:hover{opacity:.7}.md-source:before{display:inline-block;height:4.8rem;content:"";vertical-align:middle}.md-source--bitbucket:before,.md-source--github:before,.md-source--gitlab:before{width:4.8rem;background-repeat:no-repeat;background-position:50%;background-size:2.4rem 2.4rem}.md-source--bitbucket .md-source__repository,.md-source--github .md-source__repository,.md-source--gitlab .md-source__repository{margin-left:-4.4rem;padding-left:4rem}.md-source--bitbucket:before{background-image:url(../images/icons/bitbucket-white-42306ad0de.svg)}.md-source--github:before{background-image:url(../images/icons/github-white-1cfc8ff99e.svg)}.md-source--gitlab:before{background-image:url(../images/icons/gitlab-white-d65054b8fe.svg)}.md-source__repository{display:inline-block;max-width:100%;margin-left:.8rem;font-weight:700;text-overflow:ellipsis;overflow:hidden;vertical-align:middle}.md-source__facts{margin:0;padding:0;font-size:1.1rem;font-weight:700;opacity:.75;list-style-type:none}.md-source__fact{float:left;-webkit-transform:translateY(0);transform:translateY(0);-webkit-transition:opacity .25s,-webkit-transform .25s cubic-bezier(.1,.7,.1,1);transition:opacity .25s,-webkit-transform .25s cubic-bezier(.1,.7,.1,1);transition:opacity .25s,transform .25s cubic-bezier(.1,.7,.1,1);transition:opacity .25s,transform .25s cubic-bezier(.1,.7,.1,1),-webkit-transform .25s cubic-bezier(.1,.7,.1,1);opacity:1}.md-source__fact--hidden{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}.md-source__fact:before{margin:0 .2rem;content:"\00B7"}.md-source__fact:first-child:before{display:none}.admonition{position:relative;margin:2rem 0;padding:.8rem 1.6rem;border-left:3.2rem solid #448aff;border-radius:.2rem;background:rgba(68,138,255,.05)}.admonition:before{display:block;position:absolute;top:.2rem;left:-2.6rem;float:left;color:#fff;font-family:Material Icons;font-size:2rem;font-weight:400;content:"edit";vertical-align:-.1em}.admonition-title{color:#2979ff;font-size:1.28rem;font-weight:700;line-height:2;text-transform:uppercase}html .admonition-title{margin-bottom:1.6rem}html .admonition-title+*{margin-top:1.6rem}.admonition :first-child{margin-top:0}.admonition :last-child{margin-bottom:0}.admonition.summary,.admonition.tldr{border-color:#00b0ff;background:rgba(0,176,255,.05)}.admonition.summary:before,.admonition.tldr:before{content:"subject"}.admonition.summary .admonition-title,.admonition.tldr .admonition-title{color:#00b0ff}.admonition.idea,.admonition.tip{border-color:#00bfa5;background:rgba(0,191,165,.05)}.admonition.idea:before,.admonition.tip:before{content:"whatshot"}.admonition.idea .admonition-title,.admonition.tip .admonition-title{color:#00bfa5}.admonition.check,.admonition.done,.admonition.success{border-color:#00e676;background:rgba(0,230,118,.05)}.admonition.check:before,.admonition.done:before,.admonition.success:before{content:"done"}.admonition.check .admonition-title,.admonition.done .admonition-title,.admonition.success .admonition-title{color:#00e676}.admonition.warn,.admonition.warning{border-color:#ff9100;background:rgba(255,145,0,.05)}.admonition.warn:before,.admonition.warning:before{content:"warning"}.admonition.warn .admonition-title,.admonition.warning .admonition-title{color:#ff9100}.admonition.fail,.admonition.failure,.admonition.missing{border-color:#ff5252;background:rgba(255,82,82,.05)}.admonition.fail:before,.admonition.failure:before,.admonition.missing:before{content:"clear"}.admonition.fail .admonition-title,.admonition.failure .admonition-title,.admonition.missing .admonition-title{color:#ff5252}.admonition.danger,.admonition.fatal{border-color:#ff1744;background:rgba(255,23,68,.05)}.admonition.danger:before,.admonition.fatal:before{content:"flash_on"}.admonition.danger .admonition-title,.admonition.fatal .admonition-title{color:#ff1744}.admonition.bug,.admonition.error{border-color:#f50057;background:rgba(245,0,87,.05)}.admonition.bug:before,.admonition.error:before{content:"bug_report"}.admonition.bug .admonition-title,.admonition.error .admonition-title{color:#f50057}.code .err,.codehilite .err{color:#a61717}.code .o,.codehilite .o{color:inherit}.code .ge,.codehilite .ge{color:#000}.code .gr,.codehilite .gr{color:#a00}.code .gh,.codehilite .gh{color:#999}.code .go,.codehilite .go{color:#888}.code .gp,.codehilite .gp{color:#555}.code .gs,.codehilite .gs{color:inherit}.code .gu,.codehilite .gu{color:#aaa}.code .gt,.codehilite .gt{color:#a00}.code .k,.code .kc,.code .kd,.code .kn,.code .kp,.codehilite .k,.codehilite .kc,.codehilite .kd,.codehilite .kn,.codehilite .kp{color:#a71d5d}.code .kr,.code .kt,.codehilite .kr,.codehilite .kt{color:#0086b3}.code .c,.code .cm,.codehilite .c,.codehilite .cm{color:#969896}.code .cp,.codehilite .cp{color:#666}.code .c1,.code .cs,.codehilite .c1,.codehilite .cs{color:#969896}.code .bp,.code .na,.code .nb,.code .nc,.code .nd,.code .ne,.code .nf,.code .ni,.code .nl,.code .nn,.code .no,.code .nt,.code .nv,.code .vc,.code .vg,.code .vi,.codehilite .bp,.codehilite .na,.codehilite .nb,.codehilite .nc,.codehilite .nd,.codehilite .ne,.codehilite .nf,.codehilite .ni,.codehilite .nl,.codehilite .nn,.codehilite .no,.codehilite .nt,.codehilite .nv,.codehilite .vc,.codehilite .vg,.codehilite .vi{color:#795da3}.code .ow,.codehilite .ow{color:inherit}.code .il,.code .m,.code .mf,.code .mh,.code .mi,.code .mo,.codehilite .il,.codehilite .m,.codehilite .mf,.codehilite .mh,.codehilite .mi,.codehilite .mo{color:#0086b3}.code .s,.code .s2,.code .sb,.code .sc,.code .sd,.code .se,.code .sh,.code .si,.code .sx,.codehilite .s,.codehilite .s2,.codehilite .sb,.codehilite .sc,.codehilite .sd,.codehilite .se,.codehilite .sh,.codehilite .si,.codehilite .sx{color:#183691}.code .sr,.codehilite .sr{color:#009926}.code .s1,.codehilite .s1{color:#d01040}.code .ss,.codehilite .ss{color:#990073}.code .gd,.codehilite .gd{background-color:#fdd}.code .gi,.codehilite .gi{background-color:#dfd}.code .w,.codehilite .w{color:transparent}.footnote{color:rgba(0,0,0,.54);font-size:80%}.footnote ol{margin-left:0}.footnote li:hover .footnote-backref,.footnote li:target .footnote-backref{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}.footnote li:hover .footnote-backref:hover,.footnote li:target .footnote-backref{color:#536dfe}.footnote-ref:before{position:absolute;margin-top:-8rem;padding-top:8rem;content:"";pointer-events:none}.footnote-backref{position:absolute;-webkit-transform:translate3d(.5rem,0,0);transform:translate3d(.5rem,0,0);-webkit-transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s,-webkit-transform .25s .125s;color:rgba(0,0,0,.26);font-size:2rem;opacity:0;vertical-align:middle}.footnote-backref:first-letter{font-size:0}.footnote-backref:after{content:"keyboard_return"}.md-typeset .headerlink{display:inline-block;margin-left:1rem;-webkit-transform:translateY(.5rem);transform:translateY(.5rem);-webkit-transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s,-webkit-transform .25s .25s;color:rgba(0,0,0,.26);opacity:0}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink,.md-typeset [id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset [id] .headerlink:focus,.md-typeset [id]:hover .headerlink:hover,.md-typeset [id]:target .headerlink{color:#536dfe}.md-typeset h1[id]:before{display:block;margin-top:-11rem;padding-top:11rem;content:""}.md-typeset h2[id]:before{display:block;margin-top:-8.2rem;padding-top:8.2rem;content:""}.md-typeset h3[id]:before{display:block;margin-top:-8.4rem;padding-top:8.4rem;content:""}.md-typeset h4[id]:before{display:block;margin-top:-8.6rem;padding-top:8.6rem;content:""}.md-typeset h5[id]:before,.md-typeset h6[id]:before{display:block;margin-top:-9rem;padding-top:9rem;content:""}.md-search__input:focus{border-radius:.3rem .3rem 0 0}.md-search-term{position:relative;padding:0 .8rem 0 4.8rem;line-height:4rem;font-size:1.6rem;-webkit-transition:background .25s;transition:background .25s;cursor:pointer}.md-search-term:before{position:absolute;content:"access_time";font-size:2.4rem;line-height:4rem;left:1.2rem;color:rgba(0,0,0,.26)}.md-search-term:hover{background:#eceef8}.checklist li{position:relative;list-style-type:none}.checklist li:before{position:absolute;-webkit-appearance:none;-moz-appearance:none;appearance:none;color:blue;content:"check_box";font-size:2.4rem}.checklist input[type=checkbox]:checked{width:20px}del.critic,ins.critic,mark{margin:0 .4rem;padding:.1rem 0;word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone;border-radius:.2rem}ins.critic{background:#dfd;box-shadow:.4rem 0 0 #dfd,-.4rem 0 0 #dfd;text-decoration:none}del.critic{background:#fdd;box-shadow:.4rem 0 0 #fdd,-.4rem 0 0 #fdd}mark{background:#ff0;box-shadow:.4rem 0 0 #ff0,-.4rem 0 0 #ff0;overflow:auto}.critic.comment{margin:0 .4rem;padding:.1rem 0;border-radius:.2rem;background:#f0f0f0;color:#37474f;box-shadow:.4rem 0 0 #f0f0f0,-.4rem 0 0 #f0f0f0;-webkit-box-decoration-break:clone;box-decoration-break:clone}.critic.comment:before{color:rgba(0,0,0,.26);content:"chat";font-size:1.6rem;padding-right:.2rem;vertical-align:-.2rem}.md-button{float:right;margin-top:9px;font-size:13px;padding-left:2.6rem;font-weight:700;text-transform:uppercase}.task-list-item{list-style-type:none}.task-list-item input{margin:0 4px .25em -20px;vertical-align:middle}.task-list-item{position:relative}.task-list-item input[type=checkbox]{opacity:0}.task-list-item input[type=checkbox]+label{display:block;position:absolute;top:50%;left:-24px;width:16px;margin-top:-8px;height:16px;border-radius:2px;background:#ccc}.task-list-item input[type=checkbox]:checked+label:before{display:block;margin-top:-4px;margin-left:2px;font-size:1.2em;line-height:1;border-radius:2px;content:"✔";color:#1ebb52}.codehilite .hll{background:#ff0;display:block;margin:0 -16px;padding:0 16px}.md-search__output{overflow-y:auto}@media only screen and (max-width:44.9375em){.md-typeset>div>pre,.md-typeset>pre>code{margin:1em -1.6rem;padding:1rem 1.6rem;border-radius:0}.md-search__form{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2)}.md-search__icon{top:1.2rem}.md-search__icon:before{content:"arrow_back"}.md-search__input{width:100%;height:4.8rem;font-size:1.8rem}.md-search__inner{position:fixed;top:0;left:100%;width:100%;height:56px;opacity:0;z-index:2;-webkit-transform:translate3d(5%,0,0);transform:translate3d(5%,0,0);-webkit-transition:opacity .15s .15s,-webkit-transform .3s cubic-bezier(.1,.7,.1,1) .15s;transition:opacity .15s .15s,-webkit-transform .3s cubic-bezier(.1,.7,.1,1) .15s;transition:transform .3s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;transition:transform .3s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s,-webkit-transform .3s cubic-bezier(.1,.7,.1,1) .15s}.md-toggle--search:checked~.md-header .md-search__inner{-webkit-transform:translateZ(0);transform:translateZ(0);left:0;opacity:1}.md-search__suggest{position:relative;z-index:2}}@media only screen and (min-width:100em){html{font-size:68.75%}}@media only screen and (min-width:125em){html{font-size:75%}}@media only screen and (max-width:74.9375em){.md-toggle--drawer:checked~.md-overlay{width:100%;height:100%;-webkit-transition:width 0s,height 0s,opacity .25s;transition:width 0s,height 0s,opacity .25s;opacity:1}.md-header-nav__icon--home{display:none}.md-nav--primary,.md-nav--primary .md-nav{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;top:0;right:0;left:0;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:100%;z-index:1}.md-nav--primary{background:#fff}.md-nav--primary .md-nav__toggle~.md-nav{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.4);left:.4rem;background:#fff}html .md-nav--primary .md-nav__title{position:relative;padding:.4rem 1.6rem .4rem 5.6rem;background:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-size:1.8rem;font-weight:400;line-height:4.8rem;white-space:nowrap;cursor:pointer}html .md-nav--primary .md-nav__title:before{display:block;position:absolute;left:.4rem;width:4rem;height:4rem;color:rgba(0,0,0,.54)}html .md-nav--primary .md-nav__title~.md-nav__list>.md-nav__item:first-child{border-top:0}.md-nav--primary .md-nav__list{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow-y:scroll}.md-nav--primary .md-nav__item{padding:0;border-top:.1rem solid rgba(0,0,0,.07)}.md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:4.8rem}.md-nav--primary .md-nav__link{position:relative;padding:1.6rem}.md-nav--primary .md-nav__link:after{position:absolute;top:50%;right:1.2rem;-webkit-transform:translateY(-50%) rotate(-90deg);transform:translateY(-50%) rotate(-90deg);-webkit-transition:inherit;transition:inherit;color:rgba(0,0,0,.54);font-size:2.4rem}.md-nav--primary .md-nav__link:hover:after{color:#536dfe}.md-nav--primary .md-nav--secondary .md-nav{position:static}.md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:2.8rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:4rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:5.2rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:6.4rem}.md-nav__toggle~.md-nav{display:none}.csstransforms3d .md-nav__toggle~.md-nav{display:block;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);-webkit-transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s;transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);opacity:0}.md-nav__toggle:checked~.md-nav{display:block}.csstransforms3d .md-nav__toggle:checked~.md-nav{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1}.md-nav .md-nav__item,.md-nav .md-nav__title{font-size:1.6rem;line-height:1.4}.md-sidebar--primary{position:fixed;top:0;left:-24.2rem;width:24.2rem;height:100%;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);background:#fff;z-index:2}.no-csstransforms3d .md-sidebar--primary{display:none}.md-toggle--drawer:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);-webkit-transform:translate3d(24.2rem,0,0);transform:translate3d(24.2rem,0,0)}.no-csstransforms3d .md-toggle--drawer:checked~.md-container .md-sidebar--primary{display:block}.md-sidebar--primary .md-sidebar__scrollwrap{overflow:hidden;margin:0}}@media only screen and (min-width:60em){.md-content{margin-right:24.2rem}.md-header-nav__source{display:block;width:23rem;max-width:23rem;padding-right:1.2rem}.md-sidebar--secondary{display:block;float:right}.md-sidebar--secondary.md-js__sidebar--locked{margin-left:100%;-webkit-transform:translate(-100%);transform:translate(-100%)}}@media only screen and (min-width:75em){.md-content{margin-left:24.2rem}.md-content__inner{margin:2.4rem}.md-header-nav__icon--menu{display:none}.md-nav.md-nav--transitioning{-webkit-transition:max-height .25s cubic-bezier(.86,0,.07,1);transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav__toggle~.md-nav{max-height:0;overflow:hidden}.md-nav.md-nav--toggled,.md-nav__toggle:checked~.md-nav{max-height:100%}.md-nav__title+.md-nav__list .md-nav__title{display:none}.md-nav__item--nested>.md-nav__link:after{display:inline-block;-webkit-transform-origin:.45em .45em;transform-origin:.45em .45em;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;vertical-align:-.125em}.js .md-nav__item--nested>.md-nav__link:after{-webkit-transition:-webkit-transform .4s;transition:-webkit-transform .4s;transition:transform .4s;transition:transform .4s,-webkit-transform .4s}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link:after{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.md-sidebar__inner{border-right:.1rem solid rgba(0,0,0,.07)}.md-search__output{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);width:100%;max-height:0;opacity:0;-webkit-transition:opacity .4s,max-height .4s;transition:opacity .4s,max-height .4s;position:absolute;background:#fff;border-top:.1rem solid rgba(0,0,0,.07);text-align:left;border-radius:0 0 .3rem .3rem;z-index:-1}.md-js__search--locked .md-search__output{max-height:75vh;opacity:1}.md-search__output::-webkit-scrollbar{width:.4rem;height:.4rem}.md-search__output::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-search__output::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-search__output{background:-webkit-linear-gradient(#fff 10%,hsla(0,0%,100%,0)),-webkit-linear-gradient(top,rgba(0,0,0,.5),rgba(0,0,0,.2) 20%,transparent 60%);background:linear-gradient(#fff 10%,hsla(0,0%,100%,0)),linear-gradient(180deg,rgba(0,0,0,.5),rgba(0,0,0,.2) 20%,transparent 60%);background-repeat:no-repeat;background-color:#fff;background-size:100% 20px,100% 5px;background-attachment:local,scroll}.md-search-result__meta{color:rgba(0,0,0,.54);padding-left:4.8rem;padding-right:1.6rem;line-height:4rem;font-size:1.28rem}.md-search-result__list{margin:0;padding:0;list-style-type:none;border-top:.1rem solid rgba(0,0,0,.07)}.md-search-result__link{overflow:auto;display:block;padding-left:4.8rem;padding-right:1.6rem}.md-search-result__link:hover{background:#ff0}.md-search-result__title{color:rgba(0,0,0,.87);font-size:1.6rem;line-height:1.4;margin-top:.5em}.md-search-result__description{color:rgba(0,0,0,.54);font-size:1.28rem;line-height:1.4;margin:.5em 0}}@media only screen and (min-width:45em){.md-header-nav__icon--search{display:none}.md-search{padding:.4rem;padding-right:3.2rem}.md-search__form{width:23rem;-webkit-transition:width .25s cubic-bezier(.1,.7,.1,1);transition:width .25s cubic-bezier(.1,.7,.1,1)}.md-js__search--locked .md-search__form{width:66.8rem}.md-search__input{width:100%;height:4rem;padding-left:4.8rem;-webkit-transition:background-color .25s,color .25s;transition:background-color .25s,color .25s;background:rgba(0,0,0,.26);color:#fff;font-size:1.6rem}.md-search__input+.md-search__icon,.md-search__input::-webkit-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::-moz-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input:-ms-input-placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input+.md-search__icon,.md-search__input::placeholder{-webkit-transition:color .25s;transition:color .25s;color:#fff}.md-search__input:hover{background:hsla(0,0%,100%,.12)}.md-js__search--locked .md-search__input{border-radius:.3rem .3rem 0 0;background:#fff;color:rgba(0,0,0,.87);text-overflow:none}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input::-moz-placeholder{color:rgba(0,0,0,.54)}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input:-ms-input-placeholder{color:rgba(0,0,0,.54)}.md-js__search--locked .md-search__input+.md-search__icon,.md-js__search--locked .md-search__input::placeholder{color:rgba(0,0,0,.54)}}@media only screen and (min-width:30em){.md-footer-nav__link{width:50%}}@media only screen and (max-width:29.9375em){.md-footer-nav__link--prev .md-footer-nav__title{display:none}}@media only screen and (max-width:59.9375em){.md-nav--secondary{border-left:0}html .md-nav__link[for=toc]{display:block}html .md-nav__link[for=toc]:after{-webkit-transform:translateY(-50%);transform:translateY(-50%);color:#536dfe;content:"toc"}html .md-nav__link[for=toc]+.md-nav__link{display:none}html .md-nav__link[for=toc]~.md-nav{display:-webkit-box;display:-ms-flexbox;display:flex}.md-nav__source{display:block;padding:.4rem;background:rgba(0,0,0,.87);color:#fff}}@media only screen and (min-width:60em) and (min-width:75em){.md-sidebar--secondary.md-js__sidebar--locked{margin-left:120rem}} \ No newline at end of file diff --git a/material/base.html b/material/base.html index 109fe6428..230d7e5eb 100644 --- a/material/base.html +++ b/material/base.html @@ -20,11 +20,11 @@ {% endif %} - + - + {% for path in extra_css %} {% endfor %} @@ -39,7 +39,7 @@
{% set h1 = "\x3ch1 id=" in content %} {% if nav %} -
+
{% include "partials/nav.html" %} @@ -48,7 +48,7 @@
{% endif %} {% if toc %} -
+
{% include "partials/toc.html" %} @@ -87,11 +87,19 @@ {% include "partials/footer.html" %}
+ - {% for path in extra_javascript %} {% endfor %} diff --git a/package.json b/package.json index 61ef6921b..7a67b6864 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,9 @@ "license": "MIT", "main": "Gulpfile.js", "scripts": { - "start": "./node_modules/.bin/gulp watch --mkdocs", - "build": "./node_modules/.bin/gulp build --production" + "start": "./node_modules/.bin/gulp watch --mkdocs --no-lint --no-revision", + "build": "./node_modules/.bin/gulp build --clean", + "clean": "./node_modules/.bin/gulp clean" }, "repository": { "type": "git", @@ -29,11 +30,11 @@ "autoprefixer": "^6.3.2", "babel-eslint": "^6.1.2", "babel-loader": "^6.2.4", + "babel-plugin-add-module-exports": "^0.2.1", "babel-preset-es2015": "^6.13.2", "css-mqpacker": "^4.0.0", "del": "^2.2.0", "eslint": "^3.6.1", - "eslint-loader": "^1.5.0", "gulp": "^3.9.1", "gulp-changed": "^1.3.2", "gulp-concat": "^2.6.0", @@ -49,12 +50,13 @@ "gulp-rev": "^7.0.0", "gulp-rev-replace": "^0.4.3", "gulp-sass": "^2.2.0", - "gulp-sass-lint": "^1.2.0", "gulp-sourcemaps": "^1.6.0", "gulp-svgmin": "^1.2.2", "gulp-uglify": "^1.5.2", "gulp-util": "^3.0.7", "node-notifier": "^4.5.0", + "sass-lint": "^1.9.1", + "through2": "^2.0.1", "vinyl-paths": "^2.1.0", "webpack": "^1.13.1", "webpack-stream": "^3.2.0", diff --git a/src/assets/javascripts/application.js b/src/assets/javascripts/application.js index cd2b8f197..bf9a942fc 100644 --- a/src/assets/javascripts/application.js +++ b/src/assets/javascripts/application.js @@ -28,8 +28,8 @@ import FastClick from "fastclick" import lunr from "lunr" // import Expander from "./components/expander" -import Sidebar from "./components/sidebar" -import ScrollSpy from "./components/scrollspy" + +import Material from "./components/Material" // import Search from './components/search'; @@ -37,6 +37,22 @@ import ScrollSpy from "./components/scrollspy" * Application * ------------------------------------------------------------------------- */ +class Application { + + /** + * @return {void} + */ + initialize() { + const material = new Material() + material.initialize() + } +} + +export default Application + +// TODO: wrap in function call +// application module export + /* Initialize application upon DOM ready */ document.addEventListener("DOMContentLoaded", () => { @@ -53,27 +69,6 @@ document.addEventListener("DOMContentLoaded", () => { /* Attack FastClick to mitigate 300ms delay on touch devices */ FastClick.attach(document.body) - const width = window.matchMedia("(min-width: 1200px)") - - const sidebar = new Sidebar(".md-sidebar--primary") - const handler = function() { - if (width.matches) { - sidebar.listen() - } else { - sidebar.unlisten() - } - } - handler() // check listen! - - const toc = new Sidebar(".md-sidebar--secondary") - toc.listen() - - const spy = - new ScrollSpy(".md-sidebar--secondary .md-nav--secondary .md-nav__link") - spy.listen() - - window.addEventListener("resize", handler) - const query = document.getElementById("query") query.addEventListener("focus", () => { document.querySelector(".md-search").classList.add("md-js__search--locked") @@ -230,7 +225,7 @@ document.addEventListener("DOMContentLoaded", () => { /* Create index */ const index = lunr(() => { /* eslint-disable no-invalid-this, lines-around-comment */ - this.field("title", {boost: 10}) + this.field("title", { boost: 10 }) this.field("text") this.ref("location") /* eslint-enable no-invalid-this, lines-around-comment */ diff --git a/src/assets/javascripts/components/Material.js b/src/assets/javascripts/components/Material.js new file mode 100644 index 000000000..780aaee46 --- /dev/null +++ b/src/assets/javascripts/components/Material.js @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import Sidebar from "./Material/Sidebar" + +/* ---------------------------------------------------------------------------- + * Material application + * ------------------------------------------------------------------------- */ + +export default +class Material { + + /** + * Constructor + * + * @constructor + */ + // constructor() { + // + // } + + /** + * @return {void} + */ + initialize() { + + // class AnchorMarker extends PageYOffsetListener + // class SidebarConstrainer extends PageYOffsetListener + + // MatchMedia!? + + const width = window.matchMedia("(min-width: 1200px)") + + // separate function in application.js --> initSidebar() + const sidebar = new Sidebar.Position("[data-md-sidebar=primary]") + const handler = function() { + if (width.matches) { + sidebar.listen() + } else { + sidebar.unlisten() + } + } + handler() // check listen! + + const toc = new Sidebar.Position("[data-md-sidebar=secondary]") + toc.listen() + + window.addEventListener("resize", handler) // TODO: orientation change etc... + + const marker = + new Sidebar.Marker("[data-md-sidebar=secondary] .md-nav__link") + marker.listen() + } +} diff --git a/src/assets/javascripts/components/Material/Sidebar.js b/src/assets/javascripts/components/Material/Sidebar.js new file mode 100644 index 000000000..28aa892be --- /dev/null +++ b/src/assets/javascripts/components/Material/Sidebar.js @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import Marker from "./Sidebar/Marker" +import Position from "./Sidebar/Position" + +/* ---------------------------------------------------------------------------- + * Definition + * ------------------------------------------------------------------------- */ + +export default { + Marker, + Position +} diff --git a/src/assets/javascripts/components/Material/Sidebar/Abstract.js b/src/assets/javascripts/components/Material/Sidebar/Abstract.js new file mode 100644 index 000000000..d1d172cad --- /dev/null +++ b/src/assets/javascripts/components/Material/Sidebar/Abstract.js @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* ---------------------------------------------------------------------------- + * Definition + * ------------------------------------------------------------------------- */ + +export default +class Abstract { + + /** + * Dispatch update on next repaint + * + * @constructor + */ + constructor() { + // if (new.target === this.constructor) + // throw new TypeError("Cannot construct abstract instance") + + /* Dispatch update on next repaint */ + this.handler_ = ev => { + window.requestAnimationFrame(() => { + this.update(ev) + }) + } + } + + /** + * Update state + * + * @abstract + * @return {void} + */ + update() { + throw new Error("update(): not implemented") + } + + /** + * Reset state + * + * @abstract + * @return {void} + */ + reset() { + throw new Error("reset(): not implemented") + } + + /** + * Register listener for all relevant events + * + * @return {void} + */ + listen() { + ["scroll", "resize", "orientationchange"].forEach(name => { + window.addEventListener(name, this.handler_, false) + }) + + /* Initial update */ + this.update() + } + + /** + * Unregister listener for all relevant events + * + * @return {void} + */ + unlisten() { + ["scroll", "resize", "orientationchange"].forEach(name => { + window.removeEventListener(name, this.handler_, false) + }) + + /* Final reset */ + this.reset() + } +} diff --git a/src/assets/javascripts/components/Material/Sidebar/Marker.js b/src/assets/javascripts/components/Material/Sidebar/Marker.js new file mode 100644 index 000000000..b6962d498 --- /dev/null +++ b/src/assets/javascripts/components/Material/Sidebar/Marker.js @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import Abstract from "./Abstract" + +/* ---------------------------------------------------------------------------- + * Definition + * ------------------------------------------------------------------------- */ + +export default +class Marker extends Abstract { + + /** + * Mark anchors within the table of contents above current page y-offset + * + * @constructor + * @param {(string|HTMLCollection)} els - Selector or HTML elements + */ + constructor(els) { + super() + + /* Resolve elements */ + this.els_ = (typeof els === "string") + ? document.querySelectorAll(els) + : els + + /* Initialize index and page y-offset */ + this.index_ = 0 + this.offset_ = window.pageYOffset + + /* Index anchor nodes for fast lookup */ + this.anchors_ = [].map.call(this.els_, el => { + return document.querySelector(el.hash) + }) + } + + /** + * Update anchor states + * + * @param {Event} ev - Event (omitted) + * @return {void} + */ + update() { + + /* Scroll direction is down */ + if (this.offset_ <= window.pageYOffset) { + for (let i = this.index_ + 1; i < this.els_.length; i++) { + if (this.anchors_[i].offsetTop <= window.pageYOffset) { + if (i > 0) + this.els_[i - 1].dataset.mdMarked = true + this.index_ = i + } else { + break + } + } + + /* Scroll direction is up */ + } else { + for (let i = this.index_; i >= 0; i--) { + if (this.anchors_[i].offsetTop > window.pageYOffset) { + if (i > 0) + delete this.els_[i - 1].dataset.mdMarked + } else { + this.index_ = i + break + } + } + } + + /* Remember current offset for next iteration */ + this.offset_ = window.pageYOffset + } + + /** + * Reset anchor states + * + * @return {void} + */ + reset() { + [].forEach.call(this.els_, el => { + delete el.dataset.mdMarked + }) + } +} diff --git a/src/assets/javascripts/components/Material/Sidebar/Position.js b/src/assets/javascripts/components/Material/Sidebar/Position.js new file mode 100644 index 000000000..fca2fc16e --- /dev/null +++ b/src/assets/javascripts/components/Material/Sidebar/Position.js @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import Abstract from "./Abstract" + +/* ---------------------------------------------------------------------------- + * Definition + * ------------------------------------------------------------------------- */ + +export default +class Position extends Abstract { + + /** + * Set sidebars to locked state and limit height to parent node + * + * @constructor + * @param {(string|HTMLElement)} el - Selector or HTML element + */ + constructor(el) { + super() + + /* Resolve elements */ + this.el_ = (typeof el === "string") + ? document.querySelector(el) + : el + + /* Index inner and outer container */ + this.inner_ = this.el_.parentNode + this.outer_ = this.el_.parentNode.parentNode + + /* Initialize current height */ + this.height_ = 0 + } + + /** + * Update locked state and height + * + * @param {Event} ev - Event (omitted) + * @return {void} + */ + update() { + const bounds = this.inner_.getBoundingClientRect() // TODO: thresholds can be calculated as a function + const parent = this.outer_.offsetTop + + /* Determine top and bottom offsets */ + const top = bounds.top + window.pageYOffset, + bottom = bounds.bottom + window.pageYOffset + + /* Determine current y-offset at top and bottom of window */ + const upper = window.pageYOffset, + lower = window.pageYOffset + window.innerHeight + + /* Calculate new bounds */ + const offset = top - upper + const height = window.innerHeight + - Math.max(lower - bottom, 0) + - Math.max(offset, parent) + + /* If height changed, update element */ + if (height !== this.height_) + this.el_.style.height = `${this.height_ = height}px` + + /* Sidebar should be locked, as we're below parent offset */ + if (offset < parent) { + if (!this.el_.dataset.mdLocked) + this.el_.dataset.mdLocked = true + + /* Sidebar should be unlocked, if locked */ + } else if (this.el_.dataset.mdLocked) { + delete this.el_.dataset.mdLocked + } + } + + /** + * Reset locked state and height + * + * @return {void} + */ + reset() { + delete this.el_.dataset.mdLocked + this.el_.style.height = "" + this.height_ = 0 + } +} diff --git a/src/assets/javascripts/components/scrollspy.js b/src/assets/javascripts/components/scrollspy.js index bd43d22f5..a88021dc4 100644 --- a/src/assets/javascripts/components/scrollspy.js +++ b/src/assets/javascripts/components/scrollspy.js @@ -24,23 +24,29 @@ * Sidebar scroll-spy * ------------------------------------------------------------------------- */ +export default class ScrollSpy { /** * Constructor * * @constructor - * @param {(string|HTMLCollection)} el - Selector or HTML elements + * @param {(string|HTMLCollection)} els - Selector or HTML elements */ - constructor(el) { - this.el_ = (typeof el === "string") - ? document.querySelectorAll(el) - : el + constructor(els) { + this.els_ = (typeof els === "string") + ? document.querySelectorAll(els) + : els /* Initialize index for currently active element */ - this.index_ = 0 + this.index_ = 0 this.offset_ = window.pageYOffset + /* Index anchor nodes for fast lookup */ + this.anchors_ = [].map.call(this.els_, el => { + return document.querySelector(el.hash) + }) + /* Event listener */ this.handler_ = ev => { this.update(ev) @@ -48,7 +54,7 @@ class ScrollSpy { } /** - * Update state of sidebar and hash + * Update state of sidebar * * @param {Event} ev - Event (omitted) * @return {void} @@ -57,11 +63,10 @@ class ScrollSpy { /* Scroll direction is down */ if (this.offset_ <= window.pageYOffset) { - for (let i = this.index_ + 1; i < this.el_.length; i++) { - const anchor = document.querySelector(this.el_[i].hash) // TODO: improve performance by caching - if (anchor.offsetTop <= window.pageYOffset) { + for (let i = this.index_ + 1; i < this.els_.length; i++) { + if (this.anchors_[i].offsetTop <= window.pageYOffset) { if (i > 0) - this.el_[i - 1].classList.add("md-nav__link--marked") + this.els_[i - 1].dataset.mdMarked = true this.index_ = i } else { break @@ -71,10 +76,9 @@ class ScrollSpy { /* Scroll direction is up */ } else { for (let i = this.index_; i >= 0; i--) { - const anchor = document.querySelector(this.el_[i].hash) - if (anchor.offsetTop > window.pageYOffset) { + if (this.anchors_[i].offsetTop > window.pageYOffset) { if (i > 0) - this.el_[i - 1].classList.remove("md-nav__link--marked") + delete this.els_[i - 1].dataset.mdMarked } else { this.index_ = i break @@ -92,8 +96,8 @@ class ScrollSpy { * @return {void} */ reset() { - [].forEach.call(this.el_, el => { - el.classList.remove("md-nav__link--marked") + [].forEach.call(this.els_, el => { + delete el.dataset.mdMarked }) } @@ -125,9 +129,3 @@ class ScrollSpy { this.reset() } } - -/* ---------------------------------------------------------------------------- - * Exports - * ------------------------------------------------------------------------- */ - -export default ScrollSpy diff --git a/src/assets/javascripts/components/search.js b/src/assets/javascripts/components/search.js index 40fb7c92c..9a24b30cf 100644 --- a/src/assets/javascripts/components/search.js +++ b/src/assets/javascripts/components/search.js @@ -20,8 +20,6 @@ * IN THE SOFTWARE. */ -"use strict" - /* ---------------------------------------------------------------------------- * Search * ------------------------------------------------------------------------- */ diff --git a/src/assets/stylesheets/_config.scss b/src/assets/stylesheets/_config.scss index 21160a4ce..bb777f41e 100644 --- a/src/assets/stylesheets/_config.scss +++ b/src/assets/stylesheets/_config.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Typography +// Variables: typography // ---------------------------------------------------------------------------- // Modular typographic scale @@ -29,7 +29,7 @@ $ms-base: 1.6rem; $ms-ratio: $major-third; // ---------------------------------------------------------------------------- -// Breakpoints +// Variables: breakpoints // ---------------------------------------------------------------------------- // Device-specific breakpoints @@ -50,7 +50,7 @@ $break-devices: ( ); // ---------------------------------------------------------------------------- -// Colors +// Variables: base colors // ---------------------------------------------------------------------------- // Primary and accent colors @@ -70,7 +70,7 @@ $md-color-white--lighter: hsla(0, 0%, 100%, 0.30); $md-color-white--lightest: hsla(0, 0%, 100%, 0.12); // ---------------------------------------------------------------------------- -// Sizing and spacing +// Variables: sizing and spacing // ---------------------------------------------------------------------------- // Icons diff --git a/src/assets/stylesheets/_shame.scss b/src/assets/stylesheets/_shame.scss index 87575c9f8..149df7d3e 100644 --- a/src/assets/stylesheets/_shame.scss +++ b/src/assets/stylesheets/_shame.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Nothing to see here, move along +// Rules // ---------------------------------------------------------------------------- @include break-from-device(screen) { diff --git a/src/assets/stylesheets/application.scss b/src/assets/stylesheets/application.scss index a17696487..e7519e3f7 100644 --- a/src/assets/stylesheets/application.scss +++ b/src/assets/stylesheets/application.scss @@ -29,7 +29,7 @@ @import "material-shadows"; // ---------------------------------------------------------------------------- -// Application +// Local imports // ---------------------------------------------------------------------------- @import "helpers/break"; @@ -37,8 +37,8 @@ @import "config"; -@import "base/icons"; @import "base/reset"; +@import "base/icons"; @import "base/typeset"; @import "layout/base"; diff --git a/src/assets/stylesheets/base/_icons.scss b/src/assets/stylesheets/base/_icons.scss index 69236a55a..65c06c4d7 100644 --- a/src/assets/stylesheets/base/_icons.scss +++ b/src/assets/stylesheets/base/_icons.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Icon set +// Rules // ---------------------------------------------------------------------------- // Icon placeholders diff --git a/src/assets/stylesheets/base/_reset.scss b/src/assets/stylesheets/base/_reset.scss index 8af839b34..f2240d59c 100644 --- a/src/assets/stylesheets/base/_reset.scss +++ b/src/assets/stylesheets/base/_reset.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Resets +// Rules // ---------------------------------------------------------------------------- // Enfore correct box model - the prefixed versions are necessary for older diff --git a/src/assets/stylesheets/base/_typeset.scss b/src/assets/stylesheets/base/_typeset.scss index 824c2e1e2..d747c9340 100644 --- a/src/assets/stylesheets/base/_typeset.scss +++ b/src/assets/stylesheets/base/_typeset.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Font definitions +// Rules: font definitions // ---------------------------------------------------------------------------- // Default fonts @@ -57,7 +57,7 @@ kbd { } // ---------------------------------------------------------------------------- -// Typeset +// Rules: typesetted content // ---------------------------------------------------------------------------- // Content that is typeset diff --git a/src/assets/stylesheets/extensions/_admonition.scss b/src/assets/stylesheets/extensions/_admonition.scss index b3dbf8aaf..6440f2cc8 100644 --- a/src/assets/stylesheets/extensions/_admonition.scss +++ b/src/assets/stylesheets/extensions/_admonition.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Admonition extension +// Rules // ---------------------------------------------------------------------------- -// Admonition +// Admonition extension .admonition { position: relative; margin: 2.0rem 0; diff --git a/src/assets/stylesheets/extensions/_codehilite.scss b/src/assets/stylesheets/extensions/_codehilite.scss index 5e984af54..dfa800f91 100644 --- a/src/assets/stylesheets/extensions/_codehilite.scss +++ b/src/assets/stylesheets/extensions/_codehilite.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Codehilite extension +// Rules // ---------------------------------------------------------------------------- -// Github-style syntax highlighting +// Codehilite extension .codehilite, .code { diff --git a/src/assets/stylesheets/extensions/_footnotes.scss b/src/assets/stylesheets/extensions/_footnotes.scss index a13e028ba..4c0208573 100644 --- a/src/assets/stylesheets/extensions/_footnotes.scss +++ b/src/assets/stylesheets/extensions/_footnotes.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Footnotes extension +// Rules // ---------------------------------------------------------------------------- -// Footnote +// Footnotes extension .footnote { color: $md-color-black--light; font-size: 80%; diff --git a/src/assets/stylesheets/extensions/_permalinks.scss b/src/assets/stylesheets/extensions/_permalinks.scss index 4b6b5bafe..d2aec1921 100644 --- a/src/assets/stylesheets/extensions/_permalinks.scss +++ b/src/assets/stylesheets/extensions/_permalinks.scss @@ -21,13 +21,13 @@ //// // ---------------------------------------------------------------------------- -// Permalinks extension +// Rules // ---------------------------------------------------------------------------- // Scoped in typesetted content for greater specificity .md-typeset { - // Permalink + // Permalinks extension .headerlink { display: inline-block; margin-left: 1.0rem; diff --git a/src/assets/stylesheets/helpers/_break.scss b/src/assets/stylesheets/helpers/_break.scss index 6c03daea7..34d024f5b 100644 --- a/src/assets/stylesheets/helpers/_break.scss +++ b/src/assets/stylesheets/helpers/_break.scss @@ -51,7 +51,7 @@ $break-devices: () !default; // ---------------------------------------------------------------------------- -// Breakpoint helpers +// Helpers // ---------------------------------------------------------------------------- /// @@ -115,7 +115,7 @@ $break-devices: () !default; } // ---------------------------------------------------------------------------- -// Breakpoint mixins +// Mixins // ---------------------------------------------------------------------------- /// diff --git a/src/assets/stylesheets/helpers/_px2em.scss b/src/assets/stylesheets/helpers/_px2em.scss index 0756797c4..46a49f963 100644 --- a/src/assets/stylesheets/helpers/_px2em.scss +++ b/src/assets/stylesheets/helpers/_px2em.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Pixel conversion helpers +// Helpers // ---------------------------------------------------------------------------- /// diff --git a/src/assets/stylesheets/layout/_base.scss b/src/assets/stylesheets/layout/_base.scss index 6882c31c9..e97c6c80b 100644 --- a/src/assets/stylesheets/layout/_base.scss +++ b/src/assets/stylesheets/layout/_base.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Grid +// Rules: base grid and containers // ---------------------------------------------------------------------------- // Stretch container to viewport and set base font-size to 10px for simple @@ -87,7 +87,7 @@ hr { } // ---------------------------------------------------------------------------- -// Navigational elements +// Rules: navigational elements // ---------------------------------------------------------------------------- // Toggle checkbox @@ -124,7 +124,7 @@ hr { } // ---------------------------------------------------------------------------- -// Flexible elements, implemented with table layout +// Rules: flexible elements, implemented with table layout // ---------------------------------------------------------------------------- // Flexible layout container diff --git a/src/assets/stylesheets/layout/_content.scss b/src/assets/stylesheets/layout/_content.scss index aa6b40ed0..15e6b62d1 100644 --- a/src/assets/stylesheets/layout/_content.scss +++ b/src/assets/stylesheets/layout/_content.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Main content +// Rules // ---------------------------------------------------------------------------- // Content container diff --git a/src/assets/stylesheets/layout/_footer.scss b/src/assets/stylesheets/layout/_footer.scss index dc852d715..b89ce2a43 100644 --- a/src/assets/stylesheets/layout/_footer.scss +++ b/src/assets/stylesheets/layout/_footer.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Footer +// Rules // ---------------------------------------------------------------------------- // Application footer diff --git a/src/assets/stylesheets/layout/_header.scss b/src/assets/stylesheets/layout/_header.scss index 1b8a4c836..912119be1 100644 --- a/src/assets/stylesheets/layout/_header.scss +++ b/src/assets/stylesheets/layout/_header.scss @@ -21,7 +21,7 @@ //// // ---------------------------------------------------------------------------- -// Header +// Rules // ---------------------------------------------------------------------------- // Application header (stays always on top) diff --git a/src/assets/stylesheets/layout/_nav.scss b/src/assets/stylesheets/layout/_nav.scss index 82b7b13c2..959b146fb 100644 --- a/src/assets/stylesheets/layout/_nav.scss +++ b/src/assets/stylesheets/layout/_nav.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Navigation +// Rules // ---------------------------------------------------------------------------- -// Nested navigation +// Navigation container .md-nav { font-size: ms(-1); line-height: 1.3; @@ -113,7 +113,7 @@ } // Marked item - &--marked { + &[data-md-marked] { color: $md-color-black--light; } diff --git a/src/assets/stylesheets/layout/_search.scss b/src/assets/stylesheets/layout/_search.scss index b818ff868..28b32429a 100644 --- a/src/assets/stylesheets/layout/_search.scss +++ b/src/assets/stylesheets/layout/_search.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Search +// Rules // ---------------------------------------------------------------------------- -// Application search +// Search container .md-search { padding: 0.8rem 0.8rem 0; diff --git a/src/assets/stylesheets/layout/_sidebar.scss b/src/assets/stylesheets/layout/_sidebar.scss index ceff9d385..dfece0192 100644 --- a/src/assets/stylesheets/layout/_sidebar.scss +++ b/src/assets/stylesheets/layout/_sidebar.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Sidebar +// Rules // ---------------------------------------------------------------------------- -// Sidebar content +// Sidebar container .md-sidebar { position: relative; width: 24.2rem; @@ -32,7 +32,7 @@ overflow: visible; // Lock sidebar to container height (account for fixed header) - &.md-js__sidebar--locked { + &[data-md-locked] { position: fixed; top: 5.6rem; } @@ -87,7 +87,7 @@ float: right; // Hack: align right in case of locked sidebar - &.md-js__sidebar--locked { + &[data-md-locked] { margin-left: 100%; transform: translate(-100%, 0); diff --git a/src/assets/stylesheets/layout/_source.scss b/src/assets/stylesheets/layout/_source.scss index d0d485e64..80c0e5799 100644 --- a/src/assets/stylesheets/layout/_source.scss +++ b/src/assets/stylesheets/layout/_source.scss @@ -21,10 +21,10 @@ //// // ---------------------------------------------------------------------------- -// Source +// Rules // ---------------------------------------------------------------------------- -// Repository containing source +// Source container .md-source { display: block; transition: opacity 0.25s; diff --git a/src/base.html b/src/base.html index 9d8d23672..617cc9c84 100644 --- a/src/base.html +++ b/src/base.html @@ -65,7 +65,7 @@ + href="https://fonts.googleapis.com/icon?family=Material+Icons" /> {% if nav %} -
+
{% include "partials/nav.html" %} @@ -116,7 +117,8 @@ {% if toc %} -
+
{% include "partials/toc.html" %} @@ -169,11 +171,21 @@
- + {% for path in extra_javascript %} {% endfor %} diff --git a/tasks/assets/images/build/ico.js b/tasks/assets/images/build/ico.js new file mode 100644 index 000000000..250d427b6 --- /dev/null +++ b/tasks/assets/images/build/ico.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import changed from "gulp-changed" + +/* ---------------------------------------------------------------------------- + * Task: clean images generated by build + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src(`${config.assets.src}/images/**/*.ico`) + .pipe(changed(`${config.assets.build}/images`)) + .pipe(gulp.dest(`${config.assets.build}/images`)) + } +} diff --git a/tasks/assets/images/build/svg.js b/tasks/assets/images/build/svg.js new file mode 100644 index 000000000..5b3688a75 --- /dev/null +++ b/tasks/assets/images/build/svg.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import changed from "gulp-changed" +import gulpif from "gulp-if" +import minsvg from "gulp-svgmin" +import rev from "gulp-rev" +import version from "gulp-rev-replace" + +/* ---------------------------------------------------------------------------- + * Task: clean images generated by build + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + return () => { + return gulp.src(`${config.assets.src}/images/**/*.svg`) + .pipe(changed(`${config.assets.build}/images`)) + .pipe(gulpif(args.optimize, minsvg())) + .pipe(gulpif(args.revision, rev())) + .pipe(gulpif(args.revision, + version({ manifest: gulp.src("manifest.json") }))) + .pipe(gulp.dest(`${config.assets.build}/images`)) + .pipe(gulpif(args.revision, + rev.manifest("manifest.json", { + base: config.assets.build, + merge: true + }))) + .pipe(gulpif(args.revision, gulp.dest(config.assets.build))) + } +} diff --git a/tasks/assets/images/clean.js b/tasks/assets/images/clean.js new file mode 100644 index 000000000..969f6302c --- /dev/null +++ b/tasks/assets/images/clean.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import clean from "del" +import vinyl from "vinyl-paths" + +/* ---------------------------------------------------------------------------- + * Task: clean images generated by build + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src(`${config.assets.build}/images/*`) + .pipe(vinyl(clean)) + } +} diff --git a/tasks/assets/javascripts/build/application.js b/tasks/assets/javascripts/build/application.js new file mode 100644 index 000000000..0307b1366 --- /dev/null +++ b/tasks/assets/javascripts/build/application.js @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import gulpif from "gulp-if" +import path from "path" +import rev from "gulp-rev" +import stream from "webpack-stream" +import version from "gulp-rev-replace" +import webpack from "webpack" + +/* ---------------------------------------------------------------------------- + * Task: build application logic + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + return () => { + return gulp.src(`${config.assets.src}/javascripts/**/*.js`) + + /* Transpile with webpack */ + .pipe( + stream({ + entry: "application.js", + output: { + filename: "application.js", + library: "Application" + }, + module: { + loaders: [ + { + loader: "babel-loader", + test: path.join(process.cwd(), + `${config.assets.src}/javascripts`) + } + ] + }, + plugins: [ + new webpack.NoErrorsPlugin() + ].concat( + args.optimize ? [ + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false + } + }) + ] : []), + stats: { + colors: true + }, + resolve: { + modulesDirectories: [ + "src/assets/javascripts", + "node_modules" + ], + extensions: [ + "", ".js" + ] + }, + devtool: args.sourcemaps ? "source-map" : "" + })) + .pipe(gulpif(args.revision, rev())) + .pipe(gulpif(args.revision, + version({ manifest: gulp.src("manifest.json") }))) + .pipe(gulp.dest(`${config.assets.build}/javascripts`)) + .pipe(gulpif(args.revision, + rev.manifest("manifest.json", { + base: config.assets.build, + merge: true + }))) + .pipe(gulpif(args.revision, gulp.dest(config.assets.build))) + } +} diff --git a/tasks/assets/javascripts/build/modernizr.js b/tasks/assets/javascripts/build/modernizr.js new file mode 100644 index 000000000..26a69a4f5 --- /dev/null +++ b/tasks/assets/javascripts/build/modernizr.js @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import concat from "gulp-concat" +import gulpif from "gulp-if" +import modernizr from "gulp-modernizr" +import uglify from "gulp-uglify" +import rev from "gulp-rev" +import version from "gulp-rev-replace" + +/* ---------------------------------------------------------------------------- + * Task: build custom modernizr + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + return () => { + return gulp.src(`${config.assets.build}/stylesheets/*.css`) + + /* Build custom modernizr */ + .pipe( + modernizr({ + options: [ + "addTest", /* Add custom tests */ + "setClasses" /* Add CSS classes to root tag */ + ] + })) + .pipe(concat("modernizr.js")) + + /* Minify sources */ + .pipe(gulpif(args.optimize, uglify())) + + /* Revisioning */ + .pipe(gulpif(args.revision, rev())) + .pipe(gulpif(args.revision, + version({ manifest: gulp.src("manifest.json") }))) + .pipe(gulp.dest(`${config.assets.build}/javascripts`)) + .pipe(gulpif(args.revision, + rev.manifest("manifest.json", { + base: config.assets.build, + merge: true + }))) + .pipe(gulpif(args.revision, gulp.dest(config.assets.build))) + } +} diff --git a/tasks/assets/javascripts/clean.js b/tasks/assets/javascripts/clean.js new file mode 100644 index 000000000..664c06f2a --- /dev/null +++ b/tasks/assets/javascripts/clean.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import clean from "del" +import vinyl from "vinyl-paths" + +/* ---------------------------------------------------------------------------- + * Task: clean javascripts generated by build + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src(`${config.assets.build}/javascripts/*`) + .pipe(vinyl(clean)) + } +} diff --git a/tasks/assets/javascripts/lint.js b/tasks/assets/javascripts/lint.js new file mode 100644 index 000000000..c8264b5a1 --- /dev/null +++ b/tasks/assets/javascripts/lint.js @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import path from "path" +import through from "through2" +import util from "gulp-util" +import { CLIEngine } from "eslint" + +/* ---------------------------------------------------------------------------- + * Locals + * ------------------------------------------------------------------------- */ + +const eslint = new CLIEngine +const format = eslint.getFormatter() + +/* ---------------------------------------------------------------------------- + * Task: lint SASS sources + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src(`${config.assets.src}/javascripts/**/*.js`) + + /* Linting */ + .pipe( + through.obj(function(file, enc, cb) { + if (file.isNull() || file.isStream()) + return cb() + + /* Lint file using .eslintrc */ + file.eslint = eslint.executeOnText( + file.contents.toString()) + + /* Correct file path */ + file.eslint.results[0].filePath = + path.relative(process.cwd(), file.path) + + // eslint-disable-next-line no-invalid-this + this.push(file) + cb() + })) + + /* Print errors */ + .pipe( + through.obj(function(file, enc, cb) { + if (file.eslint.errorCount || file.eslint.warningCount) { + // eslint-disable-next-line no-console + console.log(format(file.eslint.results)) + } + + // eslint-disable-next-line no-invalid-this + this.push(file) + cb() + })) + + /* Terminate on error */ + .pipe( + (() => { + const errors = [] + + /* Gather errors */ + return through.obj(function(file, enc, cb) { + const results = file.eslint + + /* Consider warnings as errors */ + if (results.errorCount || results.warningCount) + errors.push(file) + + // eslint-disable-next-line no-invalid-this + this.push(file) + cb() + + /* Format errors and terminate */ + }, function(cb) { + if (errors.length > 0) { + const message = errors.map(file => { + return file.relative + }).join(", ") + + // eslint-disable-next-line no-invalid-this + this.emit("error", new util.PluginError("eslint", + `Terminated with errors in files: ${message}`)) + } + cb() + }) + })()) + } +} diff --git a/tasks/assets/stylesheets/build.js b/tasks/assets/stylesheets/build.js new file mode 100644 index 000000000..92dedfa97 --- /dev/null +++ b/tasks/assets/stylesheets/build.js @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import autoprefixer from "autoprefixer" +import gulpif from "gulp-if" +import mincss from "gulp-cssnano" +import mqpacker from "css-mqpacker" +import postcss from "gulp-postcss" +import rev from "gulp-rev" +import sass from "gulp-sass" +import sourcemaps from "gulp-sourcemaps" +import version from "gulp-rev-replace" + +/* ---------------------------------------------------------------------------- + * Task: build stylesheets from SASS source + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + return () => { + return gulp.src(`${config.assets.src}/stylesheets/*.scss`) + .pipe(gulpif(args.sourcemaps, sourcemaps.init())) + + /* Compile SASS sources */ + .pipe( + sass({ + includePaths: [ + "node_modules/modularscale-sass/stylesheets", + "node_modules/material-design-color", + "node_modules/material-shadows" + ] + })) + + /* Apply PostCSS plugins */ + .pipe( + postcss([ + autoprefixer(), + mqpacker + ])) + + /* Minify sources */ + .pipe(gulpif(args.optimize, mincss())) + + /* Revisioning */ + .pipe(gulpif(args.revision, rev())) + .pipe(gulpif(args.revision, + version({ manifest: gulp.src("manifest.json") }))) + .pipe(gulpif(args.sourcemaps, sourcemaps.write("."))) + .pipe(gulp.dest(`${config.assets.build}/stylesheets`)) + .pipe(gulpif(args.revision, + rev.manifest("manifest.json", { + base: config.assets.build, + merge: true + }))) + .pipe(gulpif(args.revision, gulp.dest(config.assets.build))) + } +} diff --git a/tasks/assets/stylesheets/clean.js b/tasks/assets/stylesheets/clean.js new file mode 100644 index 000000000..51506be0d --- /dev/null +++ b/tasks/assets/stylesheets/clean.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import clean from "del" +import vinyl from "vinyl-paths" + +/* ---------------------------------------------------------------------------- + * Task: clean stylesheets generated by build + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src(`${config.assets.build}/stylesheets/*`) + .pipe(vinyl(clean)) + } +} diff --git a/tasks/assets/stylesheets/lint.js b/tasks/assets/stylesheets/lint.js new file mode 100644 index 000000000..1ce179e7f --- /dev/null +++ b/tasks/assets/stylesheets/lint.js @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import path from "path" +import sasslint from "sass-lint" +import through from "through2" +import util from "gulp-util" + +/* ---------------------------------------------------------------------------- + * Task: lint SASS sources + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + return () => { + return gulp.src(`${config.assets.src}/stylesheets/**/*.scss`) + + /* Linting */ + .pipe( + through.obj(function(file, enc, cb) { + if (file.isNull() || file.isStream()) + return cb() + + /* Lint file using .sass-lint.yml */ + file.sasslint = sasslint.lintFileText({ + text: file.contents, + format: path.extname(file.path).replace(".", ""), + filename: path.relative(process.cwd(), file.path) + }) + + // eslint-disable-next-line no-invalid-this + this.push(file) + cb() + })) + + /* Print errors */ + .pipe( + through.obj(function(file, enc, cb) { + sasslint.outputResults([file.sasslint]) + + // eslint-disable-next-line no-invalid-this + this.push(file) + cb() + })) + + /* Terminate on error */ + .pipe( + (() => { + const errors = [] + + /* Gather errors */ + return through.obj(function(file, enc, cb) { + const results = file.sasslint + + /* Consider warnings as errors during clean compilation */ + if (results.errorCount || results.warningCount) + errors.push(file) + + // eslint-disable-next-line no-invalid-this + this.push(file) + cb() + + /* Format errors and terminate */ + }, function(cb) { + if (errors.length > 0) { + const message = errors.map(file => { + return file.relative + }).join(", ") + + // eslint-disable-next-line no-invalid-this + this.emit("error", new util.PluginError("eslint", + `Terminated with errors in files: ${message}`)) + } + cb() + }) + })()) + } +} diff --git a/tasks/mkdocs/build.js b/tasks/mkdocs/build.js new file mode 100644 index 000000000..2e26f9d1c --- /dev/null +++ b/tasks/mkdocs/build.js @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import child from "child_process" + +/* ---------------------------------------------------------------------------- + * Task: build documentation + * ------------------------------------------------------------------------- */ + +export default () => { + return () => { + return child.spawnSync("mkdocs", ["build"]) + } +} diff --git a/tasks/mkdocs/clean.js b/tasks/mkdocs/clean.js new file mode 100644 index 000000000..c364b4881 --- /dev/null +++ b/tasks/mkdocs/clean.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import clean from "del" +import vinyl from "vinyl-paths" + +/* ---------------------------------------------------------------------------- + * Task: clean documentation build + * ------------------------------------------------------------------------- */ + +export default gulp => { + return () => { + return gulp.src("site") + .pipe(vinyl(clean)) + } +} diff --git a/tasks/mkdocs/serve.js b/tasks/mkdocs/serve.js new file mode 100644 index 000000000..66efc39c4 --- /dev/null +++ b/tasks/mkdocs/serve.js @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import child from "child_process" +import util from "gulp-util" + +/* ---------------------------------------------------------------------------- + * Locals + * ------------------------------------------------------------------------- */ + +/* MkDocs server */ +let server = null + +/* ---------------------------------------------------------------------------- + * Task: serve documentation + * ------------------------------------------------------------------------- */ + +export default () => { + return () => { + if (server) + server.kill() + + /* Spawn MkDocs server */ + server = child.spawn("mkdocs", ["serve", "-a", "0.0.0.0:8000"]) + + /* Pretty print server log output */ + server.stdout.on("data", data => { + const lines = data.toString().split("\n") + for (const l in lines) + if (lines[l].length) + util.log(lines[l]) + }) + + /* Print errors to stdout */ + server.stderr.on("data", data => { + process.stdout.write(data.toString()) + }) + } +} diff --git a/tasks/views/build.js b/tasks/views/build.js new file mode 100644 index 000000000..797242fd7 --- /dev/null +++ b/tasks/views/build.js @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import changed from "gulp-changed" +import compact from "gulp-remove-empty-lines" +import gulpif from "gulp-if" +import minhtml from "gulp-htmlmin" +import path from "path" +import replace from "gulp-replace" +import version from "gulp-rev-replace" + +/* ---------------------------------------------------------------------------- + * Task: minify views + * ------------------------------------------------------------------------- */ + +export default (gulp, config, args) => { + return () => { + const metadata = require(path.join(process.cwd(), "./package.json")) + return gulp.src(`${config.views.src}/**/*.html`) + .pipe(changed(config.views.build)) + .pipe( + minhtml({ + collapseBooleanAttributes: true, + removeComments: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + customAttrCollapse: /(content)/ + })) + .pipe(replace("$theme-name$", metadata.name)) + .pipe(replace("$theme-version$", metadata.version)) + .pipe(compact()) + .pipe(gulpif(args.revision, + version({ manifest: gulp.src("manifest.json") }))) + .pipe(gulp.dest(config.views.build)) + } +} diff --git a/tasks/views/clean.js b/tasks/views/clean.js new file mode 100644 index 000000000..592fa52d2 --- /dev/null +++ b/tasks/views/clean.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import clean from "del" +import vinyl from "vinyl-paths" + +/* ---------------------------------------------------------------------------- + * Task: clean views + * ------------------------------------------------------------------------- */ + +export default (gulp, config) => { + return () => { + return gulp.src(`${config.views.build}/**/*.html`) + .pipe(vinyl(clean)) + } +}