├── .gitignore ├── .prettierrc ├── .vscode ├── launch.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── nav.spec.js ├── old-tests │ ├── index.js │ ├── login-page.js │ └── utils.js ├── plugins │ └── index.js └── support │ └── index.js ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package-lock.json ├── package.json ├── src ├── components │ ├── __tests__ │ │ ├── card-flip-test.js │ │ └── login-form-test.js │ ├── card-flip │ │ ├── card-flip.css │ │ └── index.js │ ├── carousel │ │ ├── carousel.css │ │ └── carousel.js │ ├── header.js │ ├── image.js │ ├── layout.css │ ├── layout.js │ ├── login-form.js │ ├── menu │ │ ├── baseStyles.js │ │ ├── closeIcon.js │ │ ├── menu.css │ │ ├── menu.js │ │ └── menuIcon.js │ ├── reset.css │ ├── seo.js │ ├── signup-form.js │ └── trip-planner │ │ ├── trip-planner.css │ │ ├── trip-planner.js │ │ └── trip-plans.js ├── data │ ├── friend-data.js │ └── image-gallery.js ├── fonts │ └── font-awesome-4.2.0 │ │ ├── css │ │ └── font-awesome.min.css │ │ └── fonts │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff ├── gallery │ ├── 1.jpg │ ├── 10.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg ├── images │ ├── IMG_0663.JPG │ ├── bagley.jpg │ ├── gatsby-astronaut.png │ ├── gatsby-icon.png │ ├── kitten-mittens.jpg │ ├── kuhtai.jpg │ ├── lb.jpg │ ├── mini-horse.jpg │ ├── mtbachelor.jpg │ ├── rainier-headshot.jpg │ ├── rainier-large.jpg │ ├── rainier-lowres.jpg │ └── white-blocks.jpg ├── pages │ ├── 404.js │ ├── friends.js │ ├── gallery.js │ ├── gearlist.js │ ├── index.js │ └── login-form.js └── registerServiceWorker.js └── static ├── favicon.ico ├── favicon.png └── scripts └── inert.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Cypress coverage 24 | cypress/integration/examples 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # Typescript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # gatsby files 61 | .cache/ 62 | public 63 | public/* 64 | 65 | # Mac files 66 | .DS_Store 67 | 68 | # Yarn 69 | yarn-error.log 70 | .pnp/ 71 | .pnp.js 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/index.js", 12 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/react-scripts", 13 | "args": [ 14 | "test", 15 | "--runInBand", 16 | "--no-cache", 17 | "--env=jsdom" 18 | ], 19 | "cwd": "${workspaceRoot}", 20 | "protocol": "inspector", 21 | "console": "integratedTerminal", 22 | "internalConsoleOptions": "neverOpen" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorTheme": "Default Dark+" 3 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This project was partially bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app). 4 | 5 | Below you will find some information on how to perform common tasks. 6 | 7 | ## Table of Contents 8 | 9 | - [Folder Structure](#folder-structure) 10 | - [Available Scripts](#available-scripts) 11 | - [npm start](#npm-start) 12 | - [npm test](#npm-test) 13 | - [npm run integration](#npm-run-integration) 14 | - [npm run build](#npm-run-build) 15 | - [npm run eject](#npm-run-eject) 16 | - [Required Polyfills](#required-polyfills) 17 | - [Importing a Component](#importing-a-component) 18 | - [Running Tests](#running-tests) 19 | - [Filename Conventions](#filename-conventions) 20 | - [Command Line Interface](#command-line-interface) 21 | - [Version Control Integration](#version-control-integration) 22 | - [Writing Tests](#writing-tests) 23 | - [Testing Components](#testing-components) 24 | - [Developing Components in Isolation](#developing-components-in-isolation) 25 | - [Getting Started with Storybook](#getting-started-with-storybook) 26 | - [Getting Started with Styleguidist](#getting-started-with-styleguidist) 27 | - [Deployment](#deployment) 28 | - [GitHub Pages](#github-pages) 29 | 30 | ## Folder Structure 31 | 32 | After creation, your project should look like this: 33 | 34 | ``` 35 | my-app/ 36 | README.md 37 | node_modules/ 38 | package.json 39 | public/ 40 | index.html 41 | favicon.ico 42 | src/ 43 | App.css 44 | App.js 45 | App.test.js 46 | index.css 47 | index.js 48 | logo.svg 49 | ``` 50 | 51 | For the project to build, **these files must exist with exact filenames**: 52 | 53 | * `public/index.html` is the page template; 54 | * `src/index.js` is the JavaScript entry point. 55 | 56 | You can delete or rename the other files. 57 | 58 | You may create subdirectories inside `src`. For faster rebuilds, only files inside `src` are processed by Webpack.
59 | You need to **put any JS and CSS files inside `src`**, otherwise Webpack won’t see them. 60 | 61 | Only files inside `public` can be used from `public/index.html`.
62 | Read instructions below for using assets from JavaScript and HTML. 63 | 64 | You can, however, create more top-level directories.
65 | They will not be included in the production build so you can use them for things like documentation. 66 | 67 | ## Available Scripts 68 | 69 | In the project directory, you can run: 70 | 71 | ### `npm start` 72 | 73 | Runs the app in the development mode.
74 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 75 | 76 | The page will reload if you make edits.
77 | You will also see any lint errors in the console. 78 | 79 | ### `npm test` 80 | 81 | Launches the test runner in the interactive watch mode.
82 | See the section about [running tests](#running-tests) for more information. 83 | 84 | ### `npm run integration` 85 | 86 | Runs the integration tests with Selenium Webdriver. Requires running `npm start` in another tab. 87 | 88 | ### `npm run build` 89 | 90 | Builds the app for production to the `build` folder.
91 | It correctly bundles React in production mode and optimizes the build for the best performance. 92 | 93 | The build is minified and the filenames include the hashes.
94 | Your app is ready to be deployed! 95 | 96 | See the section about [deployment](#deployment) for more information. 97 | 98 | ### `npm run eject` 99 | 100 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 101 | 102 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 103 | 104 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 105 | 106 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 107 | 108 | 109 | ## Required polyfills 110 | 111 | 112 | ## Running Tests 113 | 114 | >Note: this feature is available with `react-scripts@0.3.0` and higher.
115 | >[Read the migration guide to learn how to enable it in older projects!](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md#migrating-from-023-to-030) 116 | 117 | Create React App uses [Jest](https://facebook.github.io/jest/) as its test runner. To prepare for this integration, we did a [major revamp](https://facebook.github.io/jest/blog/2016/09/01/jest-15.html) of Jest so if you heard bad things about it years ago, give it another try. 118 | 119 | Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness. 120 | 121 | While Jest provides browser globals such as `window` thanks to [jsdom](https://github.com/tmpvar/jsdom), they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks. 122 | 123 | We recommend that you use a separate tool for browser end-to-end tests if you need them. They are beyond the scope of Create React App. 124 | 125 | ### Filename Conventions 126 | 127 | Jest will look for test files with any of the following popular naming conventions: 128 | 129 | * Files with `.js` suffix in `__tests__` folders. 130 | * Files with `.test.js` suffix. 131 | * Files with `.spec.js` suffix. 132 | 133 | The `.test.js` / `.spec.js` files (or the `__tests__` folders) can be located at any depth under the `src` top level folder. 134 | 135 | We recommend to put the test files (or `__tests__` folders) next to the code they are testing so that relative imports appear shorter. For example, if `App.test.js` and `App.js` are in the same folder, the test just needs to `import App from './App'` instead of a long relative path. Colocation also helps find tests more quickly in larger projects. 136 | 137 | ### Command Line Interface 138 | 139 | When you run `npm test`, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, just like `npm start` recompiles the code. 140 | 141 | The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run: 142 | 143 | ![Jest watch mode](http://facebook.github.io/jest/img/blog/15-watch.gif) 144 | 145 | ### Version Control Integration 146 | 147 | By default, when you run `npm test`, Jest will only run the tests related to files changed since the last commit. This is an optimization designed to make your tests run fast regardless of how many tests you have. However it assumes that you don’t often commit the code that doesn’t pass the tests. 148 | 149 | Jest will always explicitly mention that it only ran tests related to the files changed since the last commit. You can also press `a` in the watch mode to force Jest to run all tests. 150 | 151 | Jest will always run all tests on a [continuous integration](#continuous-integration) server or if the project is not inside a Git or Mercurial repository. 152 | 153 | ### Writing Tests 154 | 155 | To create tests, add `it()` (or `test()`) blocks with the name of the test and its code. You may optionally wrap them in `describe()` blocks for logical grouping but this is neither required nor recommended. 156 | 157 | Jest provides a built-in `expect()` global function for making assertions. A basic test could look like this: 158 | 159 | ```js 160 | import sum from './sum'; 161 | 162 | it('sums numbers', () => { 163 | expect(sum(1, 2)).toEqual(3); 164 | expect(sum(2, 2)).toEqual(4); 165 | }); 166 | ``` 167 | 168 | All `expect()` matchers supported by Jest are [extensively documented here](https://facebook.github.io/jest/docs/en/expect.html#content).
169 | You can also use [`jest.fn()` and `expect(fn).toBeCalled()`](https://facebook.github.io/jest/docs/en/expect.html#tohavebeencalled) to create “spies” or mock functions. 170 | 171 | ### Testing Components 172 | 173 | There is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes. 174 | 175 | Different projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating simple smoke tests for your components: 176 | 177 | ```js 178 | import React from 'react'; 179 | import ReactDOM from 'react-dom'; 180 | import App from './App'; 181 | 182 | it('renders without crashing', () => { 183 | const div = document.createElement('div'); 184 | ReactDOM.render(, div); 185 | }); 186 | ``` 187 | 188 | This test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot of value with very little effort so they are great as a starting point, and this is the test you will find in `src/App.test.js`. 189 | 190 | When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior. 191 | 192 | If you’d like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](http://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](http://airbnb.io/enzyme/). To install it, run: 193 | 194 | ```sh 195 | npm install --save enzyme enzyme-adapter-react-16 react-test-renderer 196 | ``` 197 | 198 | Alternatively you may use `yarn`: 199 | 200 | ```sh 201 | yarn add enzyme enzyme-adapter-react-16 react-test-renderer 202 | ``` 203 | 204 | As of Enzyme 3, you will need to install Enzyme along with an Adapter corresponding to the version of React you are using. (The examples above use the adapter for React 16.) 205 | 206 | The adapter will also need to be configured in your [global setup file](#initializing-test-environment): 207 | 208 | #### `src/setupTests.js` 209 | ```js 210 | import { configure } from 'enzyme'; 211 | import Adapter from 'enzyme-adapter-react-16'; 212 | 213 | configure({ adapter: new Adapter() }); 214 | ``` 215 | 216 | >Note: Keep in mind that if you decide to "eject" before creating `src/setupTests.js`, the resulting `package.json` file won't contain any reference to it. [Read here](#initializing-test-environment) to learn how to add this after ejecting. 217 | 218 | Now you can write a smoke test with it: 219 | 220 | ```js 221 | import React from 'react'; 222 | import { shallow } from 'enzyme'; 223 | import App from './App'; 224 | 225 | it('renders without crashing', () => { 226 | shallow(); 227 | }); 228 | ``` 229 | 230 | Unlike the previous smoke test using `ReactDOM.render()`, this test only renders `` and doesn’t go deeper. For example, even if `` itself renders a ` 19 | 20 | ) 21 | export default SignupForm 22 | -------------------------------------------------------------------------------- /src/components/trip-planner/trip-planner.css: -------------------------------------------------------------------------------- 1 | #tripPlanner { 2 | background-color: #f2f2f2; 3 | box-shadow: 1px 1px 2px rgba(0,0,0,0.3); 4 | border: 1px solid black; 5 | color: #999; 6 | margin: 0 auto 1em; 7 | max-width: 800px; 8 | } 9 | #tripPlanner form > div { 10 | align-items: center; 11 | display: flex; 12 | padding: 1em; 13 | } 14 | #tripPlanner button { 15 | background-color: #f5f5f5; 16 | -webkit-appearance: none; 17 | height: 32px; 18 | width: 32px; 19 | } 20 | #tripPlanner .button-wrap.left { 21 | margin-right: 1em; 22 | } 23 | #tripPlanner .button-wrap.right { 24 | margin-left: 1em; 25 | margin-bottom: 1em; 26 | } 27 | #tripPlanner div.label.fit { 28 | flex-grow: 2; 29 | margin: 0; 30 | padding: 1em; 31 | width: 40%; 32 | } 33 | #tripPlanner div.label.fit input, 34 | #tripPlanner .button-wrap button { 35 | border: 1px solid #666; 36 | } 37 | #tripPlanner button.expand { 38 | background-color: #878c96; 39 | box-shadow: 1px 1px 2px rgba(0,0,0,0.3); 40 | border: none; 41 | color: #fff; 42 | } 43 | #tripPlanner div.label input { 44 | border: 0; 45 | height: 32px; 46 | padding: 0.25em; 47 | width: 100%; 48 | } 49 | #tripPlanner .inputGroup { 50 | border: 1px solid #666; 51 | display: flex; 52 | margin-bottom: 1em; 53 | margin-left: 4em; 54 | padding: 0; 55 | width: 39%; 56 | } 57 | #tripPlanner .select { 58 | border: 1px solid #666; 59 | background-color: white; 60 | height: 32px; 61 | margin-bottom: 1em; 62 | margin-left: 1em; 63 | width: 32%; 64 | } 65 | #tripPlanner .select select { 66 | border: none; 67 | height: 100%; 68 | width: 100%; 69 | } 70 | #tripPlanner .inputGroup div.label { 71 | flex-grow: 2; 72 | } 73 | #tripPlanner .inputGroup input { 74 | border: 0; 75 | height: 100%; 76 | text-align: center; 77 | } 78 | #tripPlanner .inputGroup button { 79 | border: 0; 80 | padding: 0.25em 0.5em; 81 | } 82 | #tripPlanner .button-wrap .submit { 83 | background-color: #b30000; 84 | box-shadow: 1px 1px 2px rgba(0,0,0,0.3); 85 | border: none; 86 | color: white; 87 | margin-left: 1.5em; 88 | width: 50px; 89 | } -------------------------------------------------------------------------------- /src/components/trip-planner/trip-planner.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | 3 | import './trip-planner.css' 4 | import { TripPlans } from './trip-plans' 5 | 6 | function TripPlanner() { 7 | const [state, setState] = useState({}) 8 | 9 | const submitFn = ((event) => { 10 | event.preventDefault() 11 | let target = event.target 12 | setState({data: { 13 | tripName: target.tripName.value, 14 | areaName: target.areaName.value, 15 | date: target.date.value, 16 | type: target.type.value 17 | }}) 18 | }) 19 | return ( 20 | <> 21 |

Fill out the trip planner form to get started.

22 |
23 |
24 |
25 |
26 | 29 |
30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 40 |
41 |
42 |
43 |
44 | 47 |
48 | 49 |
50 | 53 |
54 |
55 | 58 |
59 |
60 |
61 | 69 |
70 |
71 |
72 | 75 |
76 |
77 |
78 |
79 | 80 | 81 | ) 82 | } 83 | export default TripPlanner; 84 | -------------------------------------------------------------------------------- /src/components/trip-planner/trip-plans.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const TripPlans = ((props) => { 4 | let data = props.data 5 | return ( 6 | <> 7 | {data !== undefined ?
8 |
    9 |
  • Event name: {data.tripName}
  • 10 |
  • Location: {data.areaName}
  • 11 |
  • Date: {data.date}
  • 12 |
  • Type: {data.type}
  • 13 |
14 |
: null} 15 | 16 | ) 17 | }) 18 | -------------------------------------------------------------------------------- /src/data/friend-data.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | name: 'Rainier McCheddarton', 3 | headshot: require('../images/rainier-headshot.jpg'), 4 | subtitle: 'Labradoodle, squeaker, cheese fan', 5 | bio: 'Doggo ipsum very hand that feed shibe heckin good boys and girls fat boi much ruin diet you are doing me the shock wrinkler length boy, I am bekom fat lotsa pats dat tungg tho shooberino.', 6 | twitterLink: 'http://twitter.com' 7 | }, 8 | { 9 | name: 'Bagley Fluffpants', 10 | headshot: require('../images/bagley.jpg'), 11 | subtitle: 'Cheshire cat, supreme loaf', 12 | bio: "The door is opening! how exciting oh, it's you, meh drink water out of the faucet. Spend six hours per day washing, but still have a crusty butthole, so lies down or sit on human they not getting up ever, but lick human with sandpaper tongue.", 13 | twitterLink: 'http://twitter.com' 14 | }, 15 | { 16 | name: 'Butterscotch', 17 | headshot: require('../images/mini-horse.jpg'), 18 | subtitle: 'My future mini horse', 19 | bio: "Kickin' cow his him boobtube damn moonshine skedaddled. Gal ain't havin' dirty tractor crazy tin. Hogjowls hold cain't hardware horse gospel tractor kinfolk, down.", 20 | twitterLink: 'http://twitter.com' 21 | }] 22 | -------------------------------------------------------------------------------- /src/data/image-gallery.js: -------------------------------------------------------------------------------- 1 | export default ImageData = [{ 2 | name: '', 3 | alt: '' 4 | },{ 5 | name: '', 6 | alt: '' 7 | },{ 8 | name: '', 9 | alt: '' 10 | },{ 11 | name: '', 12 | alt: '' 13 | },{ 14 | name: '', 15 | alt: '' 16 | },{ 17 | name: '', 18 | alt: '' 19 | },{ 20 | name: '', 21 | alt: '' 22 | },{ 23 | name: '', 24 | alt: '' 25 | },{ 26 | name: '', 27 | alt: '' 28 | }] 29 | -------------------------------------------------------------------------------- /src/fonts/font-awesome-4.2.0/css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"} -------------------------------------------------------------------------------- /src/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/gallery/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/1.jpg -------------------------------------------------------------------------------- /src/gallery/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/10.jpg -------------------------------------------------------------------------------- /src/gallery/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/2.jpg -------------------------------------------------------------------------------- /src/gallery/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/3.jpg -------------------------------------------------------------------------------- /src/gallery/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/4.jpg -------------------------------------------------------------------------------- /src/gallery/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/5.jpg -------------------------------------------------------------------------------- /src/gallery/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/6.jpg -------------------------------------------------------------------------------- /src/gallery/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/7.jpg -------------------------------------------------------------------------------- /src/gallery/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/8.jpg -------------------------------------------------------------------------------- /src/gallery/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/gallery/9.jpg -------------------------------------------------------------------------------- /src/images/IMG_0663.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/IMG_0663.JPG -------------------------------------------------------------------------------- /src/images/bagley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/bagley.jpg -------------------------------------------------------------------------------- /src/images/gatsby-astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/gatsby-astronaut.png -------------------------------------------------------------------------------- /src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /src/images/kitten-mittens.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/kitten-mittens.jpg -------------------------------------------------------------------------------- /src/images/kuhtai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/kuhtai.jpg -------------------------------------------------------------------------------- /src/images/lb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/lb.jpg -------------------------------------------------------------------------------- /src/images/mini-horse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/mini-horse.jpg -------------------------------------------------------------------------------- /src/images/mtbachelor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/mtbachelor.jpg -------------------------------------------------------------------------------- /src/images/rainier-headshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/rainier-headshot.jpg -------------------------------------------------------------------------------- /src/images/rainier-large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/rainier-large.jpg -------------------------------------------------------------------------------- /src/images/rainier-lowres.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/rainier-lowres.jpg -------------------------------------------------------------------------------- /src/images/white-blocks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/src/images/white-blocks.jpg -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ) 13 | 14 | export default NotFoundPage 15 | -------------------------------------------------------------------------------- /src/pages/friends.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CardFlip from '../components/card-flip/' 3 | 4 | import Layout from "../components/layout" 5 | import SEO from "../components/seo" 6 | import friends from "../data/friend-data" 7 | 8 | const FriendsPage = () => ( 9 | 10 | 11 |
12 |

Which friends shall we bring?

13 | 21 | 28 | 35 |
36 |
37 | ) 38 | 39 | export default FriendsPage 40 | -------------------------------------------------------------------------------- /src/pages/gallery.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react" 2 | import { graphql } from "gatsby" 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | import Carousel from "../components/carousel/carousel" 6 | 7 | const imageData = [ 8 | 'Backpacking with Rainier the labradoodle', 9 | 'Camping with the dog at a wilderness lake', 10 | 'Carrying puppy Rainier on a mountain hike', 11 | 'Mt. Baker Wilderness at Chain Lakes', 12 | 'Skyline Lake reflection', 13 | 'Bagley the cat wants to go van camping', 14 | 'Sunny trail magic in the North Cascades', 15 | 'Snowy Iceberg the Adventure Van', 16 | 'Rainier in his snow suit in the Baker backcountry', 17 | 'My splitboard in the snow', 18 | ] 19 | 20 | class GalleryPage extends Component { 21 | render() { 22 | const data = this.props.data 23 | 24 | return ( 25 | 26 | 27 |

Inspiration

28 | 29 |
30 | ) 31 | } 32 | } 33 | 34 | export const imageQuery = graphql` 35 | query { 36 | gallery: allFile(filter: { sourceInstanceName: { eq: "gallery" } }) { 37 | edges { 38 | node { 39 | name 40 | childImageSharp { 41 | fluid(maxWidth: 400, maxHeight: 400) { 42 | ...GatsbyImageSharpFluid 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | ` 50 | 51 | export default GalleryPage 52 | -------------------------------------------------------------------------------- /src/pages/gearlist.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Layout from "../components/layout" 3 | 4 | class GearList extends Component { 5 | render() { 6 | return ( 7 | 8 |

Gear Packing List

9 |

It’s a bummer to forget a critical item when you’re headed to a cold snowy place. 10 | Here’s a handy checklist of things you might need.

11 |
12 |
13 |

All winter days

14 |
    15 |
  • Snow jacket
  • 16 |
  • Snow pants
  • 17 |
  • Base layers top & bottom
  • 18 |
  • Waterproof gloves
  • 19 |
  • Beanie
  • 20 |
  • Ski socks
  • 21 |
  • Ski boots
  • 22 |
  • Skis
  • 23 |
  • Poles
  • 24 |
  • Helmet
  • 25 |
  • Goggles
  • 26 |
  • Lunch
  • 27 |
  • Sunscreen
  • 28 |
29 |
30 |
31 |

Backcountry days

32 |
    33 |
  • Avalanche beacon
  • 34 |
  • Probe
  • 35 |
  • Shovel
  • 36 |
  • Touring hat
  • 37 |
  • Glove liners
  • 38 |
  • Map
  • 39 |
  • Touring skis
  • 40 |
  • Touring boots
  • 41 |
  • Skins
  • 42 |
  • Backpack
  • 43 |
  • Water
  • 44 |
  • Sunglasses
  • 45 |
46 |
47 |
48 |
49 | ) 50 | } 51 | } 52 | export default GearList 53 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useStaticQuery, graphql } from "gatsby" 3 | import Img from "gatsby-image" 4 | 5 | import TripPlanner from '../components/trip-planner/trip-planner'; 6 | import Layout from "../components/layout" 7 | import SEO from "../components/seo" 8 | 9 | const IndexPage = (() => { 10 | const data = useStaticQuery(graphql` 11 | query { 12 | landingImage: file(relativePath: { eq: "kuhtai.jpg" }) { 13 | childImageSharp { 14 | fluid { 15 | ...GatsbyImageSharpFluid 16 | } 17 | } 18 | } 19 | } 20 | `) 21 | return ( 22 | 23 | 24 | 25 |
30 | 31 |
32 |
33 | ) 34 | }) 35 | 36 | export default IndexPage 37 | -------------------------------------------------------------------------------- /src/pages/login-form.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import LoginForm from '../components/login-form' 4 | import Layout from "../components/layout" 5 | import SEO from "../components/seo" 6 | 7 | let fields = [ 8 | 'First name', 9 | 'Last name', 10 | 'Email' 11 | ] 12 | const LoginPage = () => ( 13 | 14 | 15 | 19 | 20 | ) 21 | 22 | export default LoginPage 23 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | 39 | // Add some additional logging to localhost, pointing developers to the 40 | // service worker/PWA documentation. 41 | navigator.serviceWorker.ready.then(() => { 42 | console.log( 43 | 'This web app is being served cache-first by a service ' + 44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ' 45 | ); 46 | }); 47 | } else { 48 | // Is not local host. Just register service worker 49 | registerValidSW(swUrl); 50 | } 51 | }); 52 | } 53 | } 54 | 55 | function registerValidSW(swUrl) { 56 | navigator.serviceWorker 57 | .register(swUrl) 58 | .then(registration => { 59 | registration.onupdatefound = () => { 60 | const installingWorker = registration.installing; 61 | installingWorker.onstatechange = () => { 62 | if (installingWorker.state === 'installed') { 63 | if (navigator.serviceWorker.controller) { 64 | // At this point, the old content will have been purged and 65 | // the fresh content will have been added to the cache. 66 | // It's the perfect time to display a "New content is 67 | // available; please refresh." message in your web app. 68 | console.log('New content is available; please refresh.'); 69 | } else { 70 | // At this point, everything has been precached. 71 | // It's the perfect time to display a 72 | // "Content is cached for offline use." message. 73 | console.log('Content is cached for offline use.'); 74 | } 75 | } 76 | }; 77 | }; 78 | }) 79 | .catch(error => { 80 | console.error('Error during service worker registration:', error); 81 | }); 82 | } 83 | 84 | function checkValidServiceWorker(swUrl) { 85 | // Check if the service worker can be found. If it can't reload the page. 86 | fetch(swUrl) 87 | .then(response => { 88 | // Ensure service worker exists, and that we really are getting a JS file. 89 | if ( 90 | response.status === 404 || 91 | response.headers.get('content-type').indexOf('javascript') === -1 92 | ) { 93 | // No service worker found. Probably a different app. Reload the page. 94 | navigator.serviceWorker.ready.then(registration => { 95 | registration.unregister().then(() => { 96 | window.location.reload(); 97 | }); 98 | }); 99 | } else { 100 | // Service worker found. Proceed as normal. 101 | registerValidSW(swUrl); 102 | } 103 | }) 104 | .catch(() => { 105 | console.log( 106 | 'No internet connection found. App is running in offline mode.' 107 | ); 108 | }); 109 | } 110 | 111 | export function unregister() { 112 | if ('serviceWorker' in navigator) { 113 | navigator.serviceWorker.ready.then(registration => { 114 | registration.unregister(); 115 | }); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/static/favicon.ico -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcysutton/empathy-driven-development/b418b7b9028db42cb0db012f433a1a8e14face84/static/favicon.png -------------------------------------------------------------------------------- /static/scripts/inert.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory() : 3 | typeof define === 'function' && define.amd ? define(factory) : 4 | (factory()); 5 | }(this, (function () { 'use strict'; 6 | 7 | /** 8 | * Determine if a DOM element matches a CSS selector 9 | * 10 | * @param {Element} elem 11 | * @param {String} selector 12 | * @return {Boolean} 13 | * @api public 14 | */ 15 | 16 | function matches(elem, selector) { 17 | // Vendor-specific implementations of `Element.prototype.matches()`. 18 | var proto = window.Element.prototype; 19 | var nativeMatches = proto.matches || 20 | proto.mozMatchesSelector || 21 | proto.msMatchesSelector || 22 | proto.oMatchesSelector || 23 | proto.webkitMatchesSelector; 24 | 25 | if (!elem || elem.nodeType !== 1) { 26 | return false; 27 | } 28 | 29 | var parentElem = elem.parentNode; 30 | 31 | // use native 'matches' 32 | if (nativeMatches) { 33 | return nativeMatches.call(elem, selector); 34 | } 35 | 36 | // native support for `matches` is missing and a fallback is required 37 | var nodes = parentElem.querySelectorAll(selector); 38 | var len = nodes.length; 39 | 40 | for (var i = 0; i < len; i++) { 41 | if (nodes[i] === elem) { 42 | return true; 43 | } 44 | } 45 | 46 | return false; 47 | } 48 | 49 | /** 50 | * Expose `matches` 51 | */ 52 | 53 | var index = matches; 54 | 55 | var classCallCheck = function (instance, Constructor) { 56 | if (!(instance instanceof Constructor)) { 57 | throw new TypeError("Cannot call a class as a function"); 58 | } 59 | }; 60 | 61 | var createClass = function () { 62 | function defineProperties(target, props) { 63 | for (var i = 0; i < props.length; i++) { 64 | var descriptor = props[i]; 65 | descriptor.enumerable = descriptor.enumerable || false; 66 | descriptor.configurable = true; 67 | if ("value" in descriptor) descriptor.writable = true; 68 | Object.defineProperty(target, descriptor.key, descriptor); 69 | } 70 | } 71 | 72 | return function (Constructor, protoProps, staticProps) { 73 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 74 | if (staticProps) defineProperties(Constructor, staticProps); 75 | return Constructor; 76 | }; 77 | }(); 78 | 79 | /** 80 | * This work is licensed under the W3C Software and Document License 81 | * (http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 82 | */ 83 | 84 | (function (document) { 85 | // Convenience function for converting NodeLists. 86 | /** @type {function(number,number):Array} */ 87 | var slice = Array.prototype.slice; 88 | 89 | /** @type {string} */ 90 | var _focusableElementsString = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'iframe', 'object', 'embed', '[contenteditable]'].join(','); 91 | 92 | /** 93 | * `InertRoot` manages a single inert subtree, i.e. a DOM subtree whose root element has an `inert` 94 | * attribute. 95 | * 96 | * Its main functions are: 97 | * 98 | * - to create and maintain a set of managed `InertNode`s, including when mutations occur in the 99 | * subtree. The `makeSubtreeUnfocusable()` method handles collecting `InertNode`s via registering 100 | * each focusable node in the subtree with the singleton `InertManager` which manages all known 101 | * focusable nodes within inert subtrees. `InertManager` ensures that a single `InertNode` 102 | * instance exists for each focusable node which has at least one inert root as an ancestor. 103 | * 104 | * - to notify all managed `InertNode`s when this subtree stops being inert (i.e. when the `inert` 105 | * attribute is removed from the root node). This is handled in the destructor, which calls the 106 | * `deregister` method on `InertManager` for each managed inert node. 107 | */ 108 | 109 | var InertRoot = function () { 110 | /** 111 | * @param {Element} rootElement The Element at the root of the inert subtree. 112 | * @param {InertManager} inertManager The global singleton InertManager object. 113 | */ 114 | function InertRoot(rootElement, inertManager) { 115 | classCallCheck(this, InertRoot); 116 | 117 | /** @type {InertManager} */ 118 | this._inertManager = inertManager; 119 | 120 | /** @type {Element} */ 121 | this._rootElement = rootElement; 122 | 123 | /** 124 | * @type {Set} 125 | * All managed focusable nodes in this InertRoot's subtree. 126 | */ 127 | this._managedNodes = new Set([]); 128 | 129 | // Make the subtree hidden from assistive technology 130 | if (this._rootElement.hasAttribute('aria-hidden')) { 131 | this._savedAriaHidden = this._rootElement.getAttribute('aria-hidden'); 132 | } 133 | this._rootElement.setAttribute('aria-hidden', 'true'); 134 | 135 | // Make all focusable elements in the subtree unfocusable and add them to _managedNodes 136 | this._makeSubtreeUnfocusable(this._rootElement); 137 | 138 | // Watch for: 139 | // - any additions in the subtree: make them unfocusable too 140 | // - any removals from the subtree: remove them from this inert root's managed nodes 141 | // - attribute changes: if `tabindex` is added, or removed from an intrinsically focusable 142 | // element, make that node a managed node. 143 | this._observer = new MutationObserver(this._onMutation.bind(this)); 144 | this._observer.observe(this._rootElement, { attributes: true, childList: true, subtree: true }); 145 | } 146 | 147 | /** 148 | * Call this whenever this object is about to become obsolete. This unwinds all of the state 149 | * stored in this object and updates the state of all of the managed nodes. 150 | */ 151 | 152 | 153 | createClass(InertRoot, [{ 154 | key: 'destructor', 155 | value: function destructor() { 156 | this._observer.disconnect(); 157 | this._observer = null; 158 | 159 | if (this._rootElement) { 160 | if (this.hasSavedAriaHidden) { 161 | this._rootElement.setAttribute('aria-hidden', this.savedAriaHidden); 162 | } else { 163 | this._rootElement.removeAttribute('aria-hidden'); 164 | } 165 | } 166 | this._rootElement = null; 167 | 168 | var _iteratorNormalCompletion = true; 169 | var _didIteratorError = false; 170 | var _iteratorError = undefined; 171 | 172 | try { 173 | for (var _iterator = this._managedNodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 174 | var inertNode = _step.value; 175 | 176 | this._unmanageNode(inertNode.node); 177 | } 178 | } catch (err) { 179 | _didIteratorError = true; 180 | _iteratorError = err; 181 | } finally { 182 | try { 183 | if (!_iteratorNormalCompletion && _iterator.return) { 184 | _iterator.return(); 185 | } 186 | } finally { 187 | if (_didIteratorError) { 188 | throw _iteratorError; 189 | } 190 | } 191 | } 192 | 193 | this._managedNodes = null; 194 | 195 | this._inertManager = null; 196 | } 197 | 198 | /** 199 | * @return {Set} A copy of this InertRoot's managed nodes set. 200 | */ 201 | 202 | }, { 203 | key: '_makeSubtreeUnfocusable', 204 | 205 | 206 | /** 207 | * @param {Node} startNode 208 | */ 209 | value: function _makeSubtreeUnfocusable(startNode) { 210 | var _this = this; 211 | 212 | composedTreeWalk(startNode, function (node) { 213 | return _this._visitNode(node); 214 | }); 215 | 216 | var activeElement = document.activeElement; 217 | if (!contains(document.body, startNode)) { 218 | // startNode may be in shadow DOM, so find its nearest shadowRoot to get the activeElement. 219 | var node = startNode; 220 | var root = undefined; 221 | while (node) { 222 | if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { 223 | root = node; 224 | break; 225 | } 226 | node = node.parentNode; 227 | } 228 | if (root) { 229 | activeElement = root.activeElement; 230 | } 231 | } 232 | if (contains(startNode, activeElement)) { 233 | activeElement.blur(); 234 | } 235 | } 236 | 237 | /** 238 | * @param {Node} node 239 | */ 240 | 241 | }, { 242 | key: '_visitNode', 243 | value: function _visitNode(node) { 244 | if (node.nodeType !== Node.ELEMENT_NODE) { 245 | return; 246 | } 247 | 248 | // If a descendant inert root becomes un-inert, its descendants will still be inert because of 249 | // this inert root, so all of its managed nodes need to be adopted by this InertRoot. 250 | if (node !== this._rootElement && node.hasAttribute('inert')) { 251 | this._adoptInertRoot(node); 252 | } 253 | 254 | if (index(node, _focusableElementsString) || node.hasAttribute('tabindex')) { 255 | this._manageNode(node); 256 | } 257 | } 258 | 259 | /** 260 | * Register the given node with this InertRoot and with InertManager. 261 | * @param {Node} node 262 | */ 263 | 264 | }, { 265 | key: '_manageNode', 266 | value: function _manageNode(node) { 267 | var inertNode = this._inertManager.register(node, this); 268 | this._managedNodes.add(inertNode); 269 | } 270 | 271 | /** 272 | * Unregister the given node with this InertRoot and with InertManager. 273 | * @param {Node} node 274 | */ 275 | 276 | }, { 277 | key: '_unmanageNode', 278 | value: function _unmanageNode(node) { 279 | var inertNode = this._inertManager.deregister(node, this); 280 | if (inertNode) { 281 | this._managedNodes.delete(inertNode); 282 | } 283 | } 284 | 285 | /** 286 | * Unregister the entire subtree starting at `startNode`. 287 | * @param {Node} startNode 288 | */ 289 | 290 | }, { 291 | key: '_unmanageSubtree', 292 | value: function _unmanageSubtree(startNode) { 293 | var _this2 = this; 294 | 295 | composedTreeWalk(startNode, function (node) { 296 | return _this2._unmanageNode(node); 297 | }); 298 | } 299 | 300 | /** 301 | * If a descendant node is found with an `inert` attribute, adopt its managed nodes. 302 | * @param {Node} node 303 | */ 304 | 305 | }, { 306 | key: '_adoptInertRoot', 307 | value: function _adoptInertRoot(node) { 308 | var inertSubroot = this._inertManager.getInertRoot(node); 309 | 310 | // During initialisation this inert root may not have been registered yet, 311 | // so register it now if need be. 312 | if (!inertSubroot) { 313 | this._inertManager.setInert(node, true); 314 | inertSubroot = this._inertManager.getInertRoot(node); 315 | } 316 | 317 | var _iteratorNormalCompletion2 = true; 318 | var _didIteratorError2 = false; 319 | var _iteratorError2 = undefined; 320 | 321 | try { 322 | for (var _iterator2 = inertSubroot.managedNodes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { 323 | var savedInertNode = _step2.value; 324 | 325 | this._manageNode(savedInertNode.node); 326 | } 327 | } catch (err) { 328 | _didIteratorError2 = true; 329 | _iteratorError2 = err; 330 | } finally { 331 | try { 332 | if (!_iteratorNormalCompletion2 && _iterator2.return) { 333 | _iterator2.return(); 334 | } 335 | } finally { 336 | if (_didIteratorError2) { 337 | throw _iteratorError2; 338 | } 339 | } 340 | } 341 | } 342 | 343 | /** 344 | * Callback used when mutation observer detects subtree additions, removals, or attribute changes. 345 | * @param {MutationRecord} records 346 | * @param {MutationObserver} self 347 | */ 348 | 349 | }, { 350 | key: '_onMutation', 351 | value: function _onMutation(records, self) { 352 | var _iteratorNormalCompletion3 = true; 353 | var _didIteratorError3 = false; 354 | var _iteratorError3 = undefined; 355 | 356 | try { 357 | for (var _iterator3 = records[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { 358 | var record = _step3.value; 359 | 360 | var target = record.target; 361 | if (record.type === 'childList') { 362 | // Manage added nodes 363 | var _iteratorNormalCompletion4 = true; 364 | var _didIteratorError4 = false; 365 | var _iteratorError4 = undefined; 366 | 367 | try { 368 | for (var _iterator4 = slice.call(record.addedNodes)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { 369 | var node = _step4.value; 370 | 371 | this._makeSubtreeUnfocusable(node); 372 | } 373 | 374 | // Un-manage removed nodes 375 | } catch (err) { 376 | _didIteratorError4 = true; 377 | _iteratorError4 = err; 378 | } finally { 379 | try { 380 | if (!_iteratorNormalCompletion4 && _iterator4.return) { 381 | _iterator4.return(); 382 | } 383 | } finally { 384 | if (_didIteratorError4) { 385 | throw _iteratorError4; 386 | } 387 | } 388 | } 389 | 390 | var _iteratorNormalCompletion5 = true; 391 | var _didIteratorError5 = false; 392 | var _iteratorError5 = undefined; 393 | 394 | try { 395 | for (var _iterator5 = slice.call(record.removedNodes)[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { 396 | var _node = _step5.value; 397 | 398 | this._unmanageSubtree(_node); 399 | } 400 | } catch (err) { 401 | _didIteratorError5 = true; 402 | _iteratorError5 = err; 403 | } finally { 404 | try { 405 | if (!_iteratorNormalCompletion5 && _iterator5.return) { 406 | _iterator5.return(); 407 | } 408 | } finally { 409 | if (_didIteratorError5) { 410 | throw _iteratorError5; 411 | } 412 | } 413 | } 414 | } else if (record.type === 'attributes') { 415 | if (record.attributeName === 'tabindex') { 416 | // Re-initialise inert node if tabindex changes 417 | this._manageNode(target); 418 | } else if (target !== this._rootElement && record.attributeName === 'inert' && target.hasAttribute('inert')) { 419 | // If a new inert root is added, adopt its managed nodes and make sure it knows about the 420 | // already managed nodes from this inert subroot. 421 | this._adoptInertRoot(target); 422 | var inertSubroot = this._inertManager.getInertRoot(target); 423 | var _iteratorNormalCompletion6 = true; 424 | var _didIteratorError6 = false; 425 | var _iteratorError6 = undefined; 426 | 427 | try { 428 | for (var _iterator6 = this._managedNodes[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { 429 | var managedNode = _step6.value; 430 | 431 | if (contains(target, managedNode.node)) { 432 | inertSubroot._manageNode(managedNode.node); 433 | } 434 | } 435 | } catch (err) { 436 | _didIteratorError6 = true; 437 | _iteratorError6 = err; 438 | } finally { 439 | try { 440 | if (!_iteratorNormalCompletion6 && _iterator6.return) { 441 | _iterator6.return(); 442 | } 443 | } finally { 444 | if (_didIteratorError6) { 445 | throw _iteratorError6; 446 | } 447 | } 448 | } 449 | } 450 | } 451 | } 452 | } catch (err) { 453 | _didIteratorError3 = true; 454 | _iteratorError3 = err; 455 | } finally { 456 | try { 457 | if (!_iteratorNormalCompletion3 && _iterator3.return) { 458 | _iterator3.return(); 459 | } 460 | } finally { 461 | if (_didIteratorError3) { 462 | throw _iteratorError3; 463 | } 464 | } 465 | } 466 | } 467 | }, { 468 | key: 'managedNodes', 469 | get: function get$$1() { 470 | return new Set(this._managedNodes); 471 | } 472 | 473 | /** @return {boolean} */ 474 | 475 | }, { 476 | key: 'hasSavedAriaHidden', 477 | get: function get$$1() { 478 | return '_savedAriaHidden' in this; 479 | } 480 | 481 | /** @param {string} ariaHidden */ 482 | 483 | }, { 484 | key: 'savedAriaHidden', 485 | set: function set$$1(ariaHidden) { 486 | this._savedAriaHidden = ariaHidden; 487 | } 488 | 489 | /** @return {string} */ 490 | , 491 | get: function get$$1() { 492 | return this._savedAriaHidden; 493 | } 494 | }]); 495 | return InertRoot; 496 | }(); 497 | 498 | /** 499 | * `InertNode` initialises and manages a single inert node. 500 | * A node is inert if it is a descendant of one or more inert root elements. 501 | * 502 | * On construction, `InertNode` saves the existing `tabindex` value for the node, if any, and 503 | * either removes the `tabindex` attribute or sets it to `-1`, depending on whether the element 504 | * is intrinsically focusable or not. 505 | * 506 | * `InertNode` maintains a set of `InertRoot`s which are descendants of this `InertNode`. When an 507 | * `InertRoot` is destroyed, and calls `InertManager.deregister()`, the `InertManager` notifies the 508 | * `InertNode` via `removeInertRoot()`, which in turn destroys the `InertNode` if no `InertRoot`s 509 | * remain in the set. On destruction, `InertNode` reinstates the stored `tabindex` if one exists, 510 | * or removes the `tabindex` attribute if the element is intrinsically focusable. 511 | */ 512 | 513 | 514 | var InertNode = function () { 515 | /** 516 | * @param {Node} node A focusable element to be made inert. 517 | * @param {InertRoot} inertRoot The inert root element associated with this inert node. 518 | */ 519 | function InertNode(node, inertRoot) { 520 | classCallCheck(this, InertNode); 521 | 522 | /** @type {Node} */ 523 | this._node = node; 524 | 525 | /** @type {boolean} */ 526 | this._overrodeFocusMethod = false; 527 | 528 | /** 529 | * @type {Set} The set of descendant inert roots. 530 | * If and only if this set becomes empty, this node is no longer inert. 531 | */ 532 | this._inertRoots = new Set([inertRoot]); 533 | 534 | /** @type {boolean} */ 535 | this._destroyed = false; 536 | 537 | // Save any prior tabindex info and make this node untabbable 538 | this.ensureUntabbable(); 539 | } 540 | 541 | /** 542 | * Call this whenever this object is about to become obsolete. 543 | * This makes the managed node focusable again and deletes all of the previously stored state. 544 | */ 545 | 546 | 547 | createClass(InertNode, [{ 548 | key: 'destructor', 549 | value: function destructor() { 550 | this._throwIfDestroyed(); 551 | 552 | if (this._node) { 553 | if (this.hasSavedTabIndex) { 554 | this._node.setAttribute('tabindex', this.savedTabIndex); 555 | } else { 556 | this._node.removeAttribute('tabindex'); 557 | } 558 | 559 | // Use `delete` to restore native focus method. 560 | if (this._overrodeFocusMethod) { 561 | delete this._node.focus; 562 | } 563 | } 564 | this._node = null; 565 | this._inertRoots = null; 566 | 567 | this._destroyed = true; 568 | } 569 | 570 | /** 571 | * @type {boolean} Whether this object is obsolete because the managed node is no longer inert. 572 | * If the object has been destroyed, any attempt to access it will cause an exception. 573 | */ 574 | 575 | }, { 576 | key: '_throwIfDestroyed', 577 | 578 | 579 | /** 580 | * Throw if user tries to access destroyed InertNode. 581 | */ 582 | value: function _throwIfDestroyed() { 583 | if (this.destroyed) { 584 | throw new Error('Trying to access destroyed InertNode'); 585 | } 586 | } 587 | 588 | /** @return {boolean} */ 589 | 590 | }, { 591 | key: 'ensureUntabbable', 592 | 593 | 594 | /** Save the existing tabindex value and make the node untabbable and unfocusable */ 595 | value: function ensureUntabbable() { 596 | var node = this.node; 597 | if (index(node, _focusableElementsString)) { 598 | if (node.tabIndex === -1 && this.hasSavedTabIndex) { 599 | return; 600 | } 601 | 602 | if (node.hasAttribute('tabindex')) { 603 | this._savedTabIndex = node.tabIndex; 604 | } 605 | node.setAttribute('tabindex', '-1'); 606 | if (node.nodeType === Node.ELEMENT_NODE) { 607 | node.focus = function () {}; 608 | this._overrodeFocusMethod = true; 609 | } 610 | } else if (node.hasAttribute('tabindex')) { 611 | this._savedTabIndex = node.tabIndex; 612 | node.removeAttribute('tabindex'); 613 | } 614 | } 615 | 616 | /** 617 | * Add another inert root to this inert node's set of managing inert roots. 618 | * @param {InertRoot} inertRoot 619 | */ 620 | 621 | }, { 622 | key: 'addInertRoot', 623 | value: function addInertRoot(inertRoot) { 624 | this._throwIfDestroyed(); 625 | this._inertRoots.add(inertRoot); 626 | } 627 | 628 | /** 629 | * Remove the given inert root from this inert node's set of managing inert roots. 630 | * If the set of managing inert roots becomes empty, this node is no longer inert, 631 | * so the object should be destroyed. 632 | * @param {InertRoot} inertRoot 633 | */ 634 | 635 | }, { 636 | key: 'removeInertRoot', 637 | value: function removeInertRoot(inertRoot) { 638 | this._throwIfDestroyed(); 639 | this._inertRoots.delete(inertRoot); 640 | if (this._inertRoots.size === 0) { 641 | this.destructor(); 642 | } 643 | } 644 | }, { 645 | key: 'destroyed', 646 | get: function get$$1() { 647 | return this._destroyed; 648 | } 649 | }, { 650 | key: 'hasSavedTabIndex', 651 | get: function get$$1() { 652 | return '_savedTabIndex' in this; 653 | } 654 | 655 | /** @return {Node} */ 656 | 657 | }, { 658 | key: 'node', 659 | get: function get$$1() { 660 | this._throwIfDestroyed(); 661 | return this._node; 662 | } 663 | 664 | /** @param {number} tabIndex */ 665 | 666 | }, { 667 | key: 'savedTabIndex', 668 | set: function set$$1(tabIndex) { 669 | this._throwIfDestroyed(); 670 | this._savedTabIndex = tabIndex; 671 | } 672 | 673 | /** @return {number} */ 674 | , 675 | get: function get$$1() { 676 | this._throwIfDestroyed(); 677 | return this._savedTabIndex; 678 | } 679 | }]); 680 | return InertNode; 681 | }(); 682 | 683 | /** 684 | * InertManager is a per-document singleton object which manages all inert roots and nodes. 685 | * 686 | * When an element becomes an inert root by having an `inert` attribute set and/or its `inert` 687 | * property set to `true`, the `setInert` method creates an `InertRoot` object for the element. 688 | * The `InertRoot` in turn registers itself as managing all of the element's focusable descendant 689 | * nodes via the `register()` method. The `InertManager` ensures that a single `InertNode` instance 690 | * is created for each such node, via the `_managedNodes` map. 691 | */ 692 | 693 | 694 | var InertManager = function () { 695 | /** 696 | * @param {Document} document 697 | */ 698 | function InertManager(document) { 699 | classCallCheck(this, InertManager); 700 | 701 | if (!document) { 702 | throw new Error('Missing required argument; InertManager needs to wrap a document.'); 703 | } 704 | 705 | /** @type {Document} */ 706 | this._document = document; 707 | 708 | /** 709 | * All managed nodes known to this InertManager. In a map to allow looking up by Node. 710 | * @type {Map} 711 | */ 712 | this._managedNodes = new Map(); 713 | 714 | /** 715 | * All inert roots known to this InertManager. In a map to allow looking up by Node. 716 | * @type {Map} 717 | */ 718 | this._inertRoots = new Map(); 719 | 720 | /** 721 | * Observer for mutations on `document.body`. 722 | * @type {MutationObserver} 723 | */ 724 | this._observer = new MutationObserver(this._watchForInert.bind(this)); 725 | 726 | // Add inert style. 727 | addInertStyle(document.head || document.body || document.documentElement); 728 | 729 | // Wait for document to be loaded. 730 | if (document.readyState === 'loading') { 731 | document.addEventListener('DOMContentLoaded', this._onDocumentLoaded.bind(this)); 732 | } else { 733 | this._onDocumentLoaded(); 734 | } 735 | } 736 | 737 | /** 738 | * Set whether the given element should be an inert root or not. 739 | * @param {Element} root 740 | * @param {boolean} inert 741 | */ 742 | 743 | 744 | createClass(InertManager, [{ 745 | key: 'setInert', 746 | value: function setInert(root, inert) { 747 | if (inert) { 748 | if (this._inertRoots.has(root)) { 749 | // element is already inert 750 | return; 751 | } 752 | 753 | var inertRoot = new InertRoot(root, this); 754 | root.setAttribute('inert', ''); 755 | this._inertRoots.set(root, inertRoot); 756 | // If not contained in the document, it must be in a shadowRoot. 757 | // Ensure inert styles are added there. 758 | if (!contains(this._document.body, root)) { 759 | var parent = root.parentNode; 760 | while (parent) { 761 | if (parent.nodeType === 11) { 762 | addInertStyle(parent); 763 | } 764 | parent = parent.parentNode; 765 | } 766 | } 767 | } else { 768 | if (!this._inertRoots.has(root)) { 769 | // element is already non-inert 770 | return; 771 | } 772 | 773 | var _inertRoot = this._inertRoots.get(root); 774 | _inertRoot.destructor(); 775 | this._inertRoots.delete(root); 776 | root.removeAttribute('inert'); 777 | } 778 | } 779 | 780 | /** 781 | * Get the InertRoot object corresponding to the given inert root element, if any. 782 | * @param {Element} element 783 | * @return {InertRoot?} 784 | */ 785 | 786 | }, { 787 | key: 'getInertRoot', 788 | value: function getInertRoot(element) { 789 | return this._inertRoots.get(element); 790 | } 791 | 792 | /** 793 | * Register the given InertRoot as managing the given node. 794 | * In the case where the node has a previously existing inert root, this inert root will 795 | * be added to its set of inert roots. 796 | * @param {Node} node 797 | * @param {InertRoot} inertRoot 798 | * @return {InertNode} inertNode 799 | */ 800 | 801 | }, { 802 | key: 'register', 803 | value: function register(node, inertRoot) { 804 | var inertNode = this._managedNodes.get(node); 805 | if (inertNode !== undefined) { 806 | // node was already in an inert subtree 807 | inertNode.addInertRoot(inertRoot); 808 | // Update saved tabindex value if necessary 809 | inertNode.ensureUntabbable(); 810 | } else { 811 | inertNode = new InertNode(node, inertRoot); 812 | } 813 | 814 | this._managedNodes.set(node, inertNode); 815 | 816 | return inertNode; 817 | } 818 | 819 | /** 820 | * De-register the given InertRoot as managing the given inert node. 821 | * Removes the inert root from the InertNode's set of managing inert roots, and remove the inert 822 | * node from the InertManager's set of managed nodes if it is destroyed. 823 | * If the node is not currently managed, this is essentially a no-op. 824 | * @param {Node} node 825 | * @param {InertRoot} inertRoot 826 | * @return {InertNode?} The potentially destroyed InertNode associated with this node, if any. 827 | */ 828 | 829 | }, { 830 | key: 'deregister', 831 | value: function deregister(node, inertRoot) { 832 | var inertNode = this._managedNodes.get(node); 833 | if (!inertNode) { 834 | return null; 835 | } 836 | 837 | inertNode.removeInertRoot(inertRoot); 838 | if (inertNode.destroyed) { 839 | this._managedNodes.delete(node); 840 | } 841 | 842 | return inertNode; 843 | } 844 | 845 | /** 846 | * Callback used when document has finished loading. 847 | */ 848 | 849 | }, { 850 | key: '_onDocumentLoaded', 851 | value: function _onDocumentLoaded() { 852 | // Find all inert roots in document and make them actually inert. 853 | var inertElements = slice.call(this._document.querySelectorAll('[inert]')); 854 | var _iteratorNormalCompletion7 = true; 855 | var _didIteratorError7 = false; 856 | var _iteratorError7 = undefined; 857 | 858 | try { 859 | for (var _iterator7 = inertElements[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { 860 | var inertElement = _step7.value; 861 | 862 | this.setInert(inertElement, true); 863 | } 864 | 865 | // Comment this out to use programmatic API only. 866 | } catch (err) { 867 | _didIteratorError7 = true; 868 | _iteratorError7 = err; 869 | } finally { 870 | try { 871 | if (!_iteratorNormalCompletion7 && _iterator7.return) { 872 | _iterator7.return(); 873 | } 874 | } finally { 875 | if (_didIteratorError7) { 876 | throw _iteratorError7; 877 | } 878 | } 879 | } 880 | 881 | this._observer.observe(this._document.body, { attributes: true, subtree: true, childList: true }); 882 | } 883 | 884 | /** 885 | * Callback used when mutation observer detects attribute changes. 886 | * @param {MutationRecord} records 887 | * @param {MutationObserver} self 888 | */ 889 | 890 | }, { 891 | key: '_watchForInert', 892 | value: function _watchForInert(records, self) { 893 | var _iteratorNormalCompletion8 = true; 894 | var _didIteratorError8 = false; 895 | var _iteratorError8 = undefined; 896 | 897 | try { 898 | for (var _iterator8 = records[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) { 899 | var record = _step8.value; 900 | 901 | switch (record.type) { 902 | case 'childList': 903 | var _iteratorNormalCompletion9 = true; 904 | var _didIteratorError9 = false; 905 | var _iteratorError9 = undefined; 906 | 907 | try { 908 | for (var _iterator9 = slice.call(record.addedNodes)[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) { 909 | var node = _step9.value; 910 | 911 | if (node.nodeType !== Node.ELEMENT_NODE) { 912 | continue; 913 | } 914 | var inertElements = slice.call(node.querySelectorAll('[inert]')); 915 | if (index(node, '[inert]')) { 916 | inertElements.unshift(node); 917 | } 918 | var _iteratorNormalCompletion10 = true; 919 | var _didIteratorError10 = false; 920 | var _iteratorError10 = undefined; 921 | 922 | try { 923 | for (var _iterator10 = inertElements[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) { 924 | var inertElement = _step10.value; 925 | 926 | this.setInert(inertElement, true); 927 | } 928 | } catch (err) { 929 | _didIteratorError10 = true; 930 | _iteratorError10 = err; 931 | } finally { 932 | try { 933 | if (!_iteratorNormalCompletion10 && _iterator10.return) { 934 | _iterator10.return(); 935 | } 936 | } finally { 937 | if (_didIteratorError10) { 938 | throw _iteratorError10; 939 | } 940 | } 941 | } 942 | } 943 | } catch (err) { 944 | _didIteratorError9 = true; 945 | _iteratorError9 = err; 946 | } finally { 947 | try { 948 | if (!_iteratorNormalCompletion9 && _iterator9.return) { 949 | _iterator9.return(); 950 | } 951 | } finally { 952 | if (_didIteratorError9) { 953 | throw _iteratorError9; 954 | } 955 | } 956 | } 957 | 958 | break; 959 | case 'attributes': 960 | if (record.attributeName !== 'inert') { 961 | continue; 962 | } 963 | var target = record.target; 964 | var inert = target.hasAttribute('inert'); 965 | this.setInert(target, inert); 966 | break; 967 | } 968 | } 969 | } catch (err) { 970 | _didIteratorError8 = true; 971 | _iteratorError8 = err; 972 | } finally { 973 | try { 974 | if (!_iteratorNormalCompletion8 && _iterator8.return) { 975 | _iterator8.return(); 976 | } 977 | } finally { 978 | if (_didIteratorError8) { 979 | throw _iteratorError8; 980 | } 981 | } 982 | } 983 | } 984 | }]); 985 | return InertManager; 986 | }(); 987 | 988 | /** 989 | * Recursively walk the composed tree from |node|. 990 | * @param {Node} node 991 | * @param {(function (Element))=} callback Callback to be called for each element traversed, 992 | * before descending into child nodes. 993 | * @param {ShadowRoot=} shadowRootAncestor The nearest ShadowRoot ancestor, if any. 994 | */ 995 | 996 | 997 | function composedTreeWalk(node, callback, shadowRootAncestor) { 998 | if (node.nodeType == Node.ELEMENT_NODE) { 999 | var element = /** @type {Element} */node; 1000 | if (callback) { 1001 | callback(element); 1002 | } 1003 | 1004 | // Descend into node: 1005 | // If it has a ShadowRoot, ignore all child elements - these will be picked 1006 | // up by the or elements. Descend straight into the 1007 | // ShadowRoot. 1008 | var shadowRoot = element.shadowRoot || element.webkitShadowRoot; 1009 | if (shadowRoot) { 1010 | composedTreeWalk(shadowRoot, callback, shadowRoot); 1011 | return; 1012 | } 1013 | 1014 | // If it is a element, descend into distributed elements - these 1015 | // are elements from outside the shadow root which are rendered inside the 1016 | // shadow DOM. 1017 | if (element.localName == 'content') { 1018 | var content = /** @type {HTMLContentElement} */element; 1019 | // Verifies if ShadowDom v0 is supported. 1020 | var distributedNodes = content.getDistributedNodes ? content.getDistributedNodes() : []; 1021 | for (var i = 0; i < distributedNodes.length; i++) { 1022 | composedTreeWalk(distributedNodes[i], callback, shadowRootAncestor); 1023 | } 1024 | return; 1025 | } 1026 | 1027 | // If it is a element, descend into assigned nodes - these 1028 | // are elements from outside the shadow root which are rendered inside the 1029 | // shadow DOM. 1030 | if (element.localName == 'slot') { 1031 | var slot = /** @type {HTMLSlotElement} */element; 1032 | // Verify if ShadowDom v1 is supported. 1033 | var _distributedNodes = slot.assignedNodes ? slot.assignedNodes({ flatten: true }) : []; 1034 | for (var _i = 0; _i < _distributedNodes.length; _i++) { 1035 | composedTreeWalk(_distributedNodes[_i], callback, shadowRootAncestor); 1036 | } 1037 | return; 1038 | } 1039 | } 1040 | 1041 | // If it is neither the parent of a ShadowRoot, a element, a 1042 | // element, nor a element recurse normally. 1043 | var child = node.firstChild; 1044 | while (child != null) { 1045 | composedTreeWalk(child, callback, shadowRootAncestor); 1046 | child = child.nextSibling; 1047 | } 1048 | } 1049 | 1050 | /** 1051 | * Adds a style element to the node containing the inert specific styles 1052 | * @param {Node} node 1053 | */ 1054 | function addInertStyle(node) { 1055 | if (node.querySelector('style#inert-style')) { 1056 | return; 1057 | } 1058 | var style = document.createElement('style'); 1059 | style.setAttribute('id', 'inert-style'); 1060 | style.textContent = '\n' + '[inert] {\n' + ' pointer-events: none;\n' + ' cursor: default;\n' + '}\n' + '\n' + '[inert], [inert] * {\n' + ' user-select: none;\n' + ' -webkit-user-select: none;\n' + ' -moz-user-select: none;\n' + ' -ms-user-select: none;\n' + '}\n'; 1061 | node.appendChild(style); 1062 | } 1063 | 1064 | /** 1065 | * `Node#contains()` polyfill. 1066 | * 1067 | * See: http://compatibility.shwups-cms.ch/en/polyfills/?&id=1 1068 | * 1069 | * @param {Node} node 1070 | * @param {Node} other 1071 | * @return {Boolean} 1072 | * @public 1073 | */ 1074 | function contains(node, other) { 1075 | return other && (node === other || !!(node.compareDocumentPosition(other) & 16)); 1076 | } 1077 | 1078 | var inertManager = new InertManager(document); 1079 | 1080 | Object.defineProperty(Element.prototype, 'inert', { 1081 | enumerable: true, 1082 | get: function get$$1() { 1083 | return this.hasAttribute('inert'); 1084 | }, 1085 | set: function set$$1(inert) { 1086 | inertManager.setInert(this, inert); 1087 | } 1088 | }); 1089 | })(document); 1090 | 1091 | }))); 1092 | --------------------------------------------------------------------------------