diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 15c68e78..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "env": { - "es6": true, - "amd": true, - "browser": true, - "mocha": true, - "node": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "sourceType": "module" - }, - "globals": { - "describe": true, - "it": true, - "expect": true, - "sinon": true - }, - "rules": { - "no-cond-assign": 2, - "no-console": 1, - "no-const-assign": 2, - "no-class-assign": 2, - "no-this-before-super": 2, - "no-unused-vars": 1, - "no-var": 2, - "object-shorthand": [2, "always"] - } -} diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 4964429a..00000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.js eol=lf diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 30d294d8..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,16 +0,0 @@ - - -### Environment - -* Operating System: -* Browser Version: -* ScrollReveal Version: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 38bc6e19..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/.gitignore b/.gitignore index c3faa557..ac39bdd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ -.DS_Store -.ignore/ -.vscode/ -node_modules/ -yarn.lock -package-lock.json +## generic files to ignore +*~ +*.lock +*.DS_Store diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4d5e39f4..00000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: node_js -dist: trusty -node_js: - - '9' -addons: - chrome: stable - hosts: localsauce -sudo: required -before_script: - - 'sudo chown root /opt/google/chrome/chrome-sandbox' - - 'sudo chmod 4755 /opt/google/chrome/chrome-sandbox' -after_success: - - npm run coverage diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 90ac6307..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,566 +0,0 @@ -# Change Log - -## [4.0.9] - 2021-03-04 - -### Fixed - -- Styles applied using CSSOM don't drop `:` characters. - -## [4.0.8] - 2021-03-02 - -### Fixed - -- Avoid Content Security Policy (CSP) violations. [@lambdacasserole](https://github.com/lambdacasserole) [#431](https://github.com/jlmakes/scrollreveal/pull/431) - -## [4.0.7] - 2020-07-15 - -### Fixed - -- Ensure element geometry exists. [#437](https://github.com/jlmakes/scrollreveal/issues/437) - -## [4.0.6] - 2020-03-15 - -### Fixed - -- Default transition values of `none` are now correctly ignored. [#231](https://github.com/jlmakes/scrollreveal/issues/231) - -### Fixed - -## [4.0.5] - 2018-10-20 - -### Fixed - -- Calling `reveal()` on the same `target` breaking animation. [#468](https://github.com/jlmakes/scrollreveal/issues/468) - -## [4.0.4] - 2018-09-22 - -### Fixed - -- Malformed `package.json` - -## [4.0.3] - 2018-09-21 - -### Fixed - -– `options.cleanup` is now correctly set to `false` by default. [#457](https://github.com/jlmakes/scrollreveal/issues/457) - -## [4.0.2] - 2018-09-11 - -### Fixed - -- Null property assignment regression in mount function. [#456](https://github.com/jlmakes/scrollreveal/issues/456) - -## [4.0.1] - 2018-09-09 - -### Fixed - -- Noop instances were not correctly unmounting from the DOM. [#455](https://github.com/jlmakes/scrollreveal/issues/455) -- Readme links to pricing page no longer 404. - -## [4.0.0] - 2018-08-06 - -### Added - -- ScrollReveal can be enabled/disabled on desktops using `options.desktop`. -- The class `sr` is added to `` during instantiation when supported. [#294](https://github.com/jlmakes/scrollreveal/issues/294) -- `height: 100%` is added to `` during instantiation when supported. [#298](https://github.com/jlmakes/scrollreveal/issues/298) -- Unused containers are removed from the store, and their event listeners destroyed. -- ScrollReveal skips generating opacity styles when `options.opacity` is set to `null`. -- ScrollReveal retains element CSS transformations. [#251](https://github.comjlmakes/scrollreveal/issues/251) -- New `options.cleanup` toggles whether generated styles are removed upon reveal completion (when `options.reset` is `false`). [#292](https://github.comjlmakes/scrollreveal/issues/292) -- ScrollReveal tracks scroll direction as container store data. [#384](https://github.com/jlmakes/scrollreveal/issues/384) -- New `clean()` method removes specific generated styles and event listeners. [#227](https://github.com/jlmakes/scrollreveal/issues/227) -- New `destroy()` method removes all generated styles and event listeners. [#227](https://github.com/jlmakes/scrollreveal/issues/227) -- New `debug` static property toggles error messages in console. [#351](https://github.com/jlmakes/scrollreveal/issues/351) -- Instance methods now accept native arrays of HTML elements. - -### Changed - -- **Breaking:** The `reveal()` method no longer accepts an `interval` parameter. Instead, sequence intervals are now defined with `options.interval`. -- **Breaking:** The instance method `isSupported()` is now static. -- **Breaking:** `options.distance` supports only `em` `px` and `%` values. -- **Breaking:** ScrollReveal methods are no longer chainable. -- **Breaking:** ScrollReveal requires a commercial license, unless for [GPL-3.0](https://opensource.org/licenses/GPL-3.0) compatible open source projects. -- Elements in a reveal sequence are no longer grouped, and reveal progressively when visible. -- ScrollReveal uses a single `matrix3d()` property, with the correct prefix and only when necessary. [#292](https://github.com/jlmakes/scrollreveal/issues/292) -- ScrollReveal returns a non-operational instance when instantiated in unsupported browsers. -- ScrollReveal `version` is now a read-only instance property. -- ScrollReveal methods are now bound read-only instance properties. -- `options.viewFactor` clamps values outside of `0.0` to `1.0`. -- ScrollReveal constructor now returns a singleton. - -### Fixed - -- The `requestAnimationFrame` polyfill now reliably throttles callback invocations. - -## [3.3.6] - 2017-06-23 - -### Fixed - -- Element visibility now checks left and right boundaries correctly. [#352](https://github.com/jlmakes/scrollreveal/issues/352) -- Library version instance property is again accurate. - -## [3.3.5] - 2017-04-05 - -### Fixed - -- Patched to ensure version 3 is the default NPM package. - -## [3.3.4] - 2017-02-18 - -### Fixed - -- Update stale CDN link in README. - -### Changed - -- Add deprecation warnings to README. - -## [3.3.3] - 2017-02-18 - -### Fixed - -- Fix error when using Bower and Wordpress due to missing semi-colon. [#278](https://github.com/jlmakes/scrollreveal/issues/278) - -## [3.3.2] - 2016-10-02 - -### Changed - -- Updated Starting Defaults section in README. [#273](https://github.comjlmakes/scrollreveal/issues/273) - -### Fixed - -- Using a selector to define a default container during instantiation now works. [#289](https://github.com/jlmakes/scrollreveal/issues/289) - -## [3.3.1] - 2016-07-22 - -### Fixed - -- Instance variable `version` updated with correct library version. - -## [3.3.0] - 2016-07-22 - -### Added - -- New callback `beforeReveal(el)`. [#273](https://github.comjlmakes/scrollreveal/issues/273) -- New callback `beforeReset(el)`. [#273](https://github.com/jlmakes/scrollreveal/issues/273) - -## [3.2.0] - 2016-07-08 - -### Added - -- New `isNodeList()` method added to `Tools`. -- New `version` instance variable contains library version. -- HTML Collections are now supported as the first argument in `reveal()`. [#246](https://github.com/jlmakes/scrollreveal/issues/246) -- Added fallback for `requestAnimationFrame`. [#267](https://github.comjlmakes/scrollreveal/issues/267) - -### Changed - -- Updated Starting Defaults section in README. - -### Fixed - -- Calling `reveal()` multiple times on an element with `config.origin` as `top` or `left` no longer produces invalid CSS. [#270](https://github.com/jlmakes/scrollreveal/issues/270) -- Refactored AMD/CommonJS module wrapper to work with Codekit. [#253](https://github.com/jlmakes/scrollreveal/issues/253) - -## [3.1.5] - 2016-07-06 - -### Fixed - -- `sync()` method now properly supports sequences. - -## [3.1.4] - 2016-03-28 - -### Changed - -- Added `console.log` calls back to non-minified distribution. [#235](https://github.com/jlmakes/scrollreveal/issues/235) - -## [3.1.3] - 2016-03-28 - -### Removed - -- Removed `console.log` calls from distribution. [#235](https://github.comjlmakes/scrollreveal/issues/235) - -## [3.1.2] - 2016-03-23 - -### Fixed - -- Removed stray quotation mark in `reveal()` error message. - -## [3.1.1] - 2016-03-08 - -### Fixed - -- `config.reset` now works properly with sequences. [#241](https://github.comjlmakes/scrollreveal/issues/241) - -## [3.1.0] - 2016-03-07 - -### Added - -- New `isNode()` method added to `Tools`. -- HTML elements are now supported as the first argument in `reveal()`. -- Selector strings assigned to `config.container` are now supported. -- `reveal()` now accepts an `interval` as it's last argument to create sequences. [#86](https://github.com/jlmakes/scrollreveal/issues/86) [#180](https://github.com/jlmakes/scrollreveal/issues/180) [#187](https://github.comjlmakes/scrollreveal/issues/187) [#215](https://github.com/jlmakes/scrollreveal/issues/215) [#234](https://github.com/jlmakes/scrollreveal/issues/234) -- New section on sequenced animations added to README. - -### Changed - -- Messages logged to console are now prepended with `ScrollReveal:` for clarity. -- Revised and renamed `supported()` method to `isSupported()`. -- Updated Custom Containers section in README with an example using a selector. -- Updated Tips section in README. - -### Fixed - -- Added semi-colon before global IIFE to improve reliability. [#228](https://github.com/jlmakes/scrollreveal/issues/228) -- The existence of `console.log` is now confirmed for IE9. [#230](https://github.com/jlmakes/scrollreveal/issues/230) -- Typos, indentation and semicolons corrected in README. - -## [3.0.9] - 2016-01-14 - -### Changed - -- Updated example site links in the README. - -### Fixed - -- Fixed operator mismatch inside `supported()`. [#220](https://github.comjlmakes/scrollreveal/issues/220) - -## [3.0.8] - 2016-01-13 - -### Changed - -- Public methods now verify that ScrollReveal is supported. - -### Fixed - -- Updated Tips section in README. - -## [3.0.7] - 2016-01-13 - -### Added - -- Added brower support information to README. [#219](https://github.comjlmakes/scrollreveal/issues/219) - -### Changed - -- `console.log` is now used instead of `console.warn`. [#215](https://github.com/jlmakes/scrollreveal/issues/215) -- Moved `tools.isSupported` method to `ScrollReveal.prototype.supported`. -- Updated the configuration and tips documentation in the README. - -### Removed - -- The `init()` method was removed. - -### Fixed - -- Using `config.mobile` in `reveal()` now works. [#216](https://github.comjlmakes/scrollreveal/issues/216) - -## [3.0.6] - 2016-01-02 - -### Fixed - -- Custom default containers are now used. -- Critical issues affecting Chrome on iOS were (finally) solved. [#196](https://github.com/jlmakes/scrollreveal/issues/196) -- Revisited `3.0.4` changes to chaining `reveal()` calls. [#212](https://github.com/jlmakes/scrollreveal/issues/212) - -## [3.0.5] - 2015-12-30 - -### Fixed - -- Fixed compatibility issues with Webpack. [#209](https://github.comjlmakes/scrollreveal/issues/209) - -## [3.0.4] - 2015-12-30 - -### Fixed - -- Squashed Webkit browser bugs due to syntax errors. [#208](https://github.comjlmakes/scrollreveal/issues/208) -- Chaining `reveal()` calls no longer prematurely initialize animation. -- Cleaned up README typos, and stale reference to `config.wait`. - -## [3.0.3] - 2015-12-22 - -### Changed - -- `reveal()` and `sync()` now return the ScrollReveal instance even on failure. [#198](https://github.com/jlmakes/scrollreveal/issues/198) - -## [3.0.2] - 2015-12-22 - -### Added - -- Added `bower.json` to release package. [#199](https://github.comjlmakes/scrollreveal/issues/199) - -### Fixed - -- Preexisting CSS transition styles are no longer destroyed. [#197](https://github.com/jlmakes/scrollreveal/issues/197) - -## [3.0.1] - 2015-12-21 - -### Changed - -- Updated Getting Started section in the README. - -### Fixed - -- Hard learned NPM and Bower issues related to release management were endured. -- Issues related to element visibility and animation behavior were addressed. [#193](https://github.com/jlmakes/scrollreveal/issues/193) [#196](https://github.comjlmakes/scrollreveal/issues/196) - -## [3.0.0] - 2015-12-15 - -This version marks a significant change in how developers use ScrollReveal, introducing a JavaScript API to replace the inline attribute parser. It's a big shift, but prioritizes maintainability and flexibility over the novelty of natural language parsing. - -### Added - -- New method `reveal()`. [#1](https://github.com/jlmakes/scrollreveal/issues/1) [#122](https://github.com/jlmakes/scrollreveal/issues/122) -- New method `sync()`. -- New callback `config.afterReset`. -- Horizontal scrolling is now supported. [#184](https://github.comjlmakes/scrollreveal/issues/184) - -### Changed - -- **Breaking:** `config.enter` renamed `config.origin`. -- **Breaking:** `config.wait` renamed `config.delay`. -- **Breaking:** `config.delay` renamed `config.useDelay`. -- **Breaking:** `config.over` renamed `config.duration`. -- **Breaking:** `config.move` renamed `config.distance`. -- **Breaking:** `config.viewport` renamed `config.container`. -- **Breaking:** `config.vFactor` renamed `config.viewFactor`. -- **Breaking:** `config.complete` renamed `config.afterReveal`. -- **Breaking:** Time values are now expected in milliseconds (instead of `string`). -- **Breaking:** `config.scale` expects value type `number` (instead of `object`). -- **Breaking:** `config.rotation` axis values require `string` with unit type (instead of `number`). -- **Breaking:** ScrollReveal constructor is now capitalized. -- Reveals now resolve to element's computed opacity, instead of `1`. [#185](https://github.com/jlmakes/scrollreveal/issues/185) - -### Removed - -- ScrollReveal no longer recognizes `data-sr` attributes. - -### Fixed - -- Improved reliability of callback timers. - -## [2.3.2] - 2015-06-15 - -### Changed - -- Updated `bower.json` syntax. [#150](https://github.com/jlmakes/scrollreveal/issues/150) - -## [2.3.1] - 2015-06-04 - -### Added - -- Simple instantiation (without `new` keyword) is now supported. [#148](https://github.com/jlmakes/scrollreveal/issues/148) - -## [2.3.0] - 2015-04-25 - -### Added - -- New keyword `vFactor` and alias `vF` control when an element is considered visible. -- New keyword `opacity` controls starting opacity. - -### Removed - -- The easing keyword `hustle` was removed. - -## [2.2.0] - 2015-03-18 - -### Added - -- New keyword `spin` controls yaw. -- New keyword `roll` controls roll. -- New keyword `flip` controls pitch. - -### Changed - -- Improved Basic Usage examples in README. - -## [2.1.0] - 2014-11-25 - -### Added - -- Various tablets added to mobile device detection. [#32](https://github.comjlmakes/scrollreveal/issues/32) [#81](https://github.com/jlmakes/scrollreveal/issues/81) -- CSS Transition support is now confirmed during instantiation. [#109](https://github.com/jlmakes/scrollreveal/issues/109) - -## [2.0.5] - 2014-11-23 - -### Changed - -- Reverted `2.0.4` change to element animation logic. [#108](https://github.comjlmakes/scrollreveal/issues/108) - -## [2.0.4] - 2014-11-21 - -### Changed - -- Revised how element animations are handled. -- Reverted `2.0.3` change to element visibility logic. [#106](https://github.com/jlmakes/scrollreveal/issues/106) - -## [2.0.3] - 2014-11-14 - -### Added - -- `data-sr` attributes are now stripped from initialized elements. [#100](https://github.com/jlmakes/scrollreveal/issues/100) @orapouso. -- Live Reload added to development environment. - -### Changed - -- Revised how element visibility is determined. - -### Removed - -- Multiple instances sharing the same viewport element no longer throw an error. [#98](https://github.com/jlmakes/scrollreveal/issues/98) @orapouso. - -### Fixed - -- Incomplete support for `config.delay = "onload"` was addressed. -- Issues related to `setTimeout`, `config.complete` and incorrect animation timing were addressed. [#96](https://github.com/jlmakes/scrollreveal/issues/96) - -## [2.0.2] - 2014-10-23 - -### Added - -- An error is now thrown when multiple instances share the same viewport element. [#91](https://github.com/jlmakes/scrollreveal/issues/91) - -### Fixed - -- Updated NPM and Bower references with new distribution path. - -## [2.0.1] - 2014-10-18 - -### Fixed - -- Incomplete support for `config.viewport` was addressed. [#67](https://github.com/jlmakes/scrollreveal/issues/67) [#68](https://github.comjlmakes/scrollreveal/issues/68) - -## [2.0.0] - 2014-10-17 - -### Added - -- New keyword `scale` controls element starting size. -- New option `config.complete` defines a callback for when reveals finish. -- New option `config.viewport` defines custom viewports. -- New option `config.mobile` enables/disables ScrollReveal on mobile devices. -- New option `config.delay` controls when animations are delayed. - -### Changed - -- **BREAKING:** ScrollReveal now uses the `data-sr` instead of `data-scroll-reveal`. -- Repository now follows [Semantic Versioning](http://semver.org/). - -### Removed - -- The `after` keyword was removed. - -## 0.1.3 - 2014-05-26 [YANKED] - -### Added - -- Configuration now includes starting opacity. [#33](https://github.comjlmakes/scrollreveal/issues/33) @kierzniak -- New `data-scroll-reveal-id` attribute added to revealed DOM elements. - -### Changed - -- Scroll event handling now uses `requestAnimationFrame`. [#48](https://github.com/jlmakes/scrollreveal/issues/48) @pazguille -- Generated styles are now stored in an object corresponding to the `data-scroll-reveal-id` attribute on each element. [#38](https://github.com/jlmakes/scrollreveal/pull/38) @georgelee1 - -## 0.1.2 - 2014-03-13 [YANKED] - -### Added - -- Elements with `position: fixed` are now supported. [#35](https://github.comjlmakes/scrollreveal/issues/35) - -### Fixed - -- Generated styles are now more specific. [#37](https://github.comjlmakes/scrollreveal/issues/37) - -## 0.1.1 - 2014-03-06 [YANKED] - -### Fixed - -- Squashed bug with `enter top` and `enter left`. [#13](https://github.comjlmakes/scrollreveal/issues/13) [#31](https://github.com/jlmakes/scrollreveal/issues/31) @sherban @danycerone - -## 0.1.0 - 2014-03-05 [YANKED] - -### Added - -- Distribution now supports AMD/CommonJS. -- Repository now uses Gulp. -- Boilerplate Testline suite added to repository. - -### Changed - -- **BREAKING:** ScrollReveal now uses the `data-scroll-reveal` attribute to parse animation instructions, in place of `data-scrollReveal`. - -## 0.0.4 - 2014-02-28 [YANKED] - -### Fixed - -- ScrollReveal no longer destroys the existing style attribute on revealed elements, but instead, now appends the necessary animation styles to existing inline styles. - -## 0.0.3 - 2014-02-22 [YANKED] - -### Fixed - -- Removed unused CSS Transition/Transform prefixes for Mozilla and Opera. - -## 0.0.2 - 2014-02-13 [YANKED] - -### Added - -- Constructor now accepts a configuration object to customize defaults. -- New `reset` keyword allows elements to reveal each time they enter the viewport. -- The `move` keyword can now be replaced with with CSS easing keywords (e.g. `ease-in-out`). -- Library documentation and code examples added to README. - -### Changed - -- ScrollReveal is no longer automatically instantiated by the `DOMContentLoaded` event. - -## 0.0.1 - 2014-01-22 [YANKED] - -### Hello World - -[4.0.9]: https://github.com/jlmakes/scrollreveal/compare/v4.0.8...v4.0.9 -[4.0.8]: https://github.com/jlmakes/scrollreveal/compare/v4.0.7...v4.0.8 -[4.0.7]: https://github.com/jlmakes/scrollreveal/compare/v4.0.6...v4.0.7 -[4.0.6]: https://github.com/jlmakes/scrollreveal/compare/v4.0.5...v4.0.6 -[4.0.5]: https://github.com/jlmakes/scrollreveal/compare/v4.0.4...v4.0.5 -[4.0.4]: https://github.com/jlmakes/scrollreveal/compare/v4.0.3...v4.0.4 -[4.0.3]: https://github.com/jlmakes/scrollreveal/compare/v4.0.2...v4.0.3 -[4.0.2]: https://github.com/jlmakes/scrollreveal/compare/v4.0.1...v4.0.2 -[4.0.1]: https://github.com/jlmakes/scrollreveal/compare/v4.0.0...v4.0.1 -[4.0.0]: https://github.com/jlmakes/scrollreveal/compare/v3.3.6...v4.0.0 -[3.3.6]: https://github.com/jlmakes/scrollreveal/compare/v3.3.5...v3.3.6 -[3.3.5]: https://github.com/jlmakes/scrollreveal/compare/v3.3.4...v3.3.5 -[3.3.4]: https://github.com/jlmakes/scrollreveal/compare/v3.3.3...v3.3.4 -[3.3.3]: https://github.com/jlmakes/scrollreveal/compare/v3.2.2...v3.3.3 -[3.3.2]: https://github.com/jlmakes/scrollreveal/compare/v3.3.1...v3.3.2 -[3.3.1]: https://github.com/jlmakes/scrollreveal/compare/v3.3.0...v3.3.1 -[3.3.0]: https://github.com/jlmakes/scrollreveal/compare/v3.2.0...v3.3.0 -[3.2.0]: https://github.com/jlmakes/scrollreveal/compare/v3.1.5...v3.2.0 -[3.1.5]: https://github.com/jlmakes/scrollreveal/compare/v3.1.4...v3.1.5 -[3.1.4]: https://github.com/jlmakes/scrollreveal/compare/v3.1.3...v3.1.4 -[3.1.3]: https://github.com/jlmakes/scrollreveal/compare/v3.1.2...v3.1.3 -[3.1.2]: https://github.com/jlmakes/scrollreveal/compare/v3.1.1...v3.1.2 -[3.1.1]: https://github.com/jlmakes/scrollreveal/compare/v3.1.0...v3.1.1 -[3.1.0]: https://github.com/jlmakes/scrollreveal/compare/v3.0.9...v3.1.0 -[3.0.9]: https://github.com/jlmakes/scrollreveal/compare/v3.0.8...v3.0.9 -[3.0.8]: https://github.com/jlmakes/scrollreveal/compare/v3.0.7...v3.0.8 -[3.0.7]: https://github.com/jlmakes/scrollreveal/compare/v3.0.6...v3.0.7 -[3.0.6]: https://github.com/jlmakes/scrollreveal/compare/v3.0.5...v3.0.6 -[3.0.5]: https://github.com/jlmakes/scrollreveal/compare/v3.0.4...v3.0.5 -[3.0.4]: https://github.com/jlmakes/scrollreveal/compare/v3.0.3...v3.0.4 -[3.0.3]: https://github.com/jlmakes/scrollreveal/compare/v3.0.2...v3.0.3 -[3.0.2]: https://github.com/jlmakes/scrollreveal/compare/v3.0.1...v3.0.2 -[3.0.1]: https://github.com/jlmakes/scrollreveal/compare/v3.0.0...v3.0.1 -[3.0.0]: https://github.com/jlmakes/scrollreveal/compare/v2.3.2...v3.0.0 -[2.3.2]: https://github.com/jlmakes/scrollreveal/compare/v2.3.1...v2.3.2 -[2.3.1]: https://github.com/jlmakes/scrollreveal/compare/v2.3.0...v2.3.1 -[2.3.0]: https://github.com/jlmakes/scrollreveal/compare/v2.2.0...v2.3.0 -[2.2.0]: https://github.com/jlmakes/scrollreveal/compare/v2.1.0...v2.2.0 -[2.1.0]: https://github.com/jlmakes/scrollreveal/compare/v2.0.5...v2.1.0 -[2.0.5]: https://github.com/jlmakes/scrollreveal/compare/v2.0.4...v2.0.5 -[2.0.4]: https://github.com/jlmakes/scrollreveal/compare/v2.0.3...v2.0.4 -[2.0.3]: https://github.com/jlmakes/scrollreveal/compare/v2.0.2...v2.0.3 -[2.0.2]: https://github.com/jlmakes/scrollreveal/compare/v2.0.1...v2.0.2 -[2.0.1]: https://github.com/jlmakes/scrollreveal/compare/v2.0.0...v2.0.1 -[2.0.0]: https://github.com/jlmakes/scrollreveal/tree/v2.0.0 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..e38ee5d2 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2014 Julian Lloyd https://twitter.com/julianlloyd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index fe586674..0457fe02 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,110 @@ -

- - ScrollReveal - -

-
-

- - ScrollReveal - -

-

Animate elements as they scroll into view.

- -

- - Build status - - - Monthly downloads - - - Version - - 5.7 kB min+gzip - - GPLv3 License - -

- -
- -# Installation - -## Browser - -A simple and fast way to get started is to include this script on your page: +#scrollReveal.js +####Declarative on-scroll reveal animations. +A simple way to create and maintain how elements fade in, triggered when they enter the viewport. An open-source experiment by [@JulianLloyd](https://twitter.com/julianlloyd) +*** +##[See Demo](http://julianlloyd.me/scrollreveal) +> **Disclaimer:** Please bear in mind that this plug-in is an experimental stage, and that breaking changes are virtually guaranteed in future updates. + +##1. Installation +Clone or download `scrollReveal.js` into your JavaScript folder, and reference it just before the closing `` tag. It will automatically instantiate ready-to-go when the `DOMContentReady` event fires. + ```html - + // Everything else + // ... + + + ``` -This will create the global variable `ScrollReveal` +>**NOTE:** scrollReveal.js does not require jQuery, but *does* rely upon CSS3 transitions; as such, it has been developed exclusively for modern browser use only. -> Be careful using this method in production. Without specifying a fixed version number, Unpkg may delay your page load while it resolves the latest version. Learn more at [unpkg.com](https://unpkg.com) -## Module +##2. Usage +By adding a `data-scrollreveal` attribute to an element, it will automatically be revealed (using default values) as soon as the element is within the viewport.

**Fig 1**: -```bash -$ npm install scrollreveal +```html +

Hello world!

+``` +However, scrollReveal.js allows you to define custom reveals, using *descriptive language*.

**Fig 2**: +```html +

Foo

+

Bar

+

Baz

``` -#### CommonJS -```js -const ScrollReveal = require('scrollreveal') -``` -#### ES2015 +###2.1 Keywords, Values and Fillers +Whatever string is passed to the `data-scrollreveal` attribute is parsed for specific words: **keywords** that expect to be followed by a **value**, and semantic **fillers** that facilitate more natural language. -```js -import ScrollReveal from 'scrollreveal' -``` +####2.1.1 Keywords and Values +These words describe the reveal behavior, using **keyword** / **value** pairs. -
+--- -# Usage +- **Enter** — Controls the direction of your element transition. Whatever value is passed is considered the vector origin. For example, specifying `top` will reveal your element with a downward motion. -Installation provides us with the constructor function [`ScrollReveal()`](https://scrollrevealjs.org/api/constructor.html). Calling this function returns the ScrollReveal instance, the “brain” behind the magic. + * Accepted values: `top`, `right`, `bottom` or `left` + * Example: `enter top` -> ScrollReveal employs the singleton pattern; no matter how many times the constructor is called, it will always return the same instance. This means we can call it anywhere, worry-free. +--- -There’s a lot we can do with this instance, but most of the time we’ll be using the [`reveal()`](https://scrollrevealjs.org/api/reveal.html) method to create animation. Fundamentally, this is how to use ScrollReveal: +- **Move** — The distance your element will travel during transition. -```html -

- Widget Inc. -

-``` + * Accepted value: **[ integer ] px** + * Example: `move 33px` -```js -ScrollReveal().reveal('.headline') -``` +--- -**🔎 See this demo live on [JSBin](http://jsbin.com/jufohaxonu/edit?html,output)** +- **Over** — The duration of your element’s transition. -
+ * Accepted value: **[ decimal ] s** + * Example: `over 1.66s` --- -### The full documentation can be found at [https://scrollrevealjs.org](https://scrollrevealjs.org) +- **After/Wait** — The delay before your element begins its transition. -> If you’re using an older version of ScrollReveal, you can find legacy documentation in the [wiki](https://github.com/jlmakes/scrollreveal/wiki) + * Accepted value: **[ decimal ] s** + * Example: `after 0.33s` or `wait 0.33s` --- -
+#### 2.1.2 Fillers +While **keywords** must be followed by an appropriate accepted **value**, the use of conjoining **fillers** are permitted for more readable language. These are shown below: + +- `from` +- `the` +- `and` +- `then` +- `but` + +**Fig 3**: +```html + +

foo

+

foo

+ + +

bar

+

bar

+

bar

+``` + +### 3. Contributions +There are already some great ideas under development (see [open issues](https://github.com/julianlloyd/scrollReveal.js/issues?state=open)); if you’d like to contribute, please do! - - Commercial License Badge - +Many thanks to [@Codrops](https://twitter.com/codrops), [@Mary Lou](https://twitter.com/crnacura) and the [cbpScroller.js](http://tympanus.net/codrops/2013/07/18/on-scroll-effect-layout/), © 2014, [Codrops](http://tympanus.net/codrops/). -
+### 4. License -# License +Licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php) -**For commercial sites, themes, projects, and applications, keep your source code private/proprietary by purchasing a [Commercial License](https://scrollrevealjs.org/pricing/).** +Copyright 2014 [@JulianLloyd](https://twitter.com/julianlloyd) -Licensed under the GNU General Public License 3.0 for compatible open source projects and non-commercial use. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -Copyright 2023 Fisssion LLC +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..52a375df --- /dev/null +++ b/bower.json @@ -0,0 +1,25 @@ +{ + "name": "scrollReveal.js", + "version": "0.0.1", + "homepage": "https://github.com/julianlloyd/scrollReveal.js", + "authors": [ + "Julian Lloyd " + ], + "description": "A simple way to create and maintain how elements fade in, triggered when they enter the viewport.", + "main": ["js/scrollReveal.js"], + "keywords": [ + "animation", + "CSS", + "transition", + "JavaScript" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "app/bower_components", + "test", + "tests" + ] +} diff --git a/build/rollup.conf.banner.js b/build/rollup.conf.banner.js deleted file mode 100644 index 5f944627..00000000 --- a/build/rollup.conf.banner.js +++ /dev/null @@ -1,15 +0,0 @@ -const { version } = require('../package.json') - -const banner = `/*! @license ScrollReveal v${version} - - Copyright 2021 Fisssion LLC. - - Licensed under the GNU General Public License 3.0 for - compatible open source projects and non-commercial use. - - For commercial sites, themes, projects, and applications, - keep your source code private/proprietary by purchasing - a commercial license from https://scrollrevealjs.org/ -*/` - -export default banner diff --git a/build/rollup.conf.js b/build/rollup.conf.js deleted file mode 100644 index 31ea527b..00000000 --- a/build/rollup.conf.js +++ /dev/null @@ -1,26 +0,0 @@ -import buble from 'rollup-plugin-buble' -import json from 'rollup-plugin-json' -import pkg from '../package.json' -import nodeResolve from 'rollup-plugin-node-resolve' -import banner from './rollup.conf.banner' - -const base = { - input: './src/index.js', - plugins: [json(), nodeResolve(), buble()] -} - -const es = Object.assign({}, base, { - external: [...Object.keys(pkg.dependencies || {})], - output: { banner, format: 'es', file: './dist/scrollreveal.es.js' } -}) - -const umd = Object.assign({}, base, { - output: { - banner, - format: 'umd', - file: './dist/scrollreveal.js', - name: 'ScrollReveal' - } -}) - -export default [es, umd] diff --git a/build/rollup.conf.min.js b/build/rollup.conf.min.js deleted file mode 100644 index 6d4a7814..00000000 --- a/build/rollup.conf.min.js +++ /dev/null @@ -1,30 +0,0 @@ -import buble from 'rollup-plugin-buble' -import json from 'rollup-plugin-json' -import nodeResolve from 'rollup-plugin-node-resolve' -import strip from 'rollup-plugin-strip' -import { uglify } from 'rollup-plugin-uglify' -import banner from './rollup.conf.banner' - -export default { - input: 'src/index.js', - plugins: [ - json(), - nodeResolve(), - buble(), - strip({ - functions: ['logger'], - sourceMaps: false - }), - uglify({ - output: { - comments: /@license ScrollReveal/ - } - }) - ], - output: { - banner, - format: 'iife', - file: 'dist/scrollreveal.min.js', - name: 'ScrollReveal' - } -} diff --git a/css/style.css b/css/style.css new file mode 100644 index 00000000..9f99f459 --- /dev/null +++ b/css/style.css @@ -0,0 +1,322 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +a { + cursor: pointer; +} + +* { + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html { + overflow: -moz-scrollbars-vertical; + overflow-y: scroll; +} + +h1, .h1 { + font-family: "proxima-nova", sams-serif; + font-weight: 100; +} + +html, body { + font-family: "proxima-nova", sans-serif; + font-weight: 300; +} + +.clearfix:before, +.clearfix:after { + content: " "; + display: table; +} + +.clearfix:after { + clear: both; +} + +html, body { + color: white; + text-align: center; +} +@media screen and (min-width: 300px) { + html, body { + font-size: 14px; + } +} +@media screen and (min-width: 460px) { + html, body { + font-size: 20px; + } +} +@media screen and (min-width: 900px) { + html, body { + font-size: 24px; + } +} + +h1, .h1 { + line-height: 1.166; + margin: .66em 0; +} + +@media screen and (min-width: 300px) { + h1, .h1 { + font-size: 2.33em; + } +} +@media screen and (min-width: 460px) { + h1, .h1 { + font-size: 2.66em; + } +} +@media screen and (min-width: 720px) { + h1, .h1 { + font-size: 3.33em; + } +} + +p { + color: #616c84; + margin: 0.33em 0; +} + +a.inline:link, +a.inline:visited { + color: #35ff99; + text-decoration: none; + border-radius: 5px; + padding: 2px; +} + +a.inline:hover, +a.inline:active { + background: #35ff99; + color: #202a39; +} + +small { + font-size: .75em; +} + +em { + font-style: italic; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +html, body { + height: 100%; + background: #202a39; +} + +.column-container { + width: 80%; + max-width: 1000px; + margin: 0 auto; + overflow: hidden; + height: 250%; + text-align: center; +} +@media screen and (min-width: 300px) { + .column-container { + padding-top: 20%; + margin-bottom: -125px; + } +} +@media screen and (min-width: 720px) { + .column-container { + padding-top: 10%; + } +} + +.column { + width: 3%; + height: 100%; + margin: 0 2%; + display: inline-block; +} + +.block { + border-radius: 5px; + margin-bottom: 150%; +} + +.block-1x { + height: 10%; +} + +.block-2x { + height: 15%; +} + +.block-3x { + height: 20%; +} + +.block-blueberry { + background: #008597; +} + +.block-slate { + background: #2d3443; +} + +.block-grape { + background: #4d407c; +} + +.block-raspberry { + background: #ff005d; +} + +.block-mango { + background: #ffcc00; +} + +.block-orange { + background: #ff7c35; +} + +.block-kiwi { + background: #35ff99; +} + +.withLove { + overflow: hidden; + text-align: center; + padding-bottom: 2em; + cursor: default; + color: #616c84; +} +@media screen and (min-width: 900px) { + .withLove { + margin-top: 125px; + } +} +.withLove * { + display: inline-block; +} +.withLove .alpha, +.withLove .omega { + width: 40%; +} +.withLove .alpha { + text-align: right; +} +.withLove .omega { + text-align: left; +} +.withLove .heart { + margin: 0 -2px; + position: relative; + z-index: 3; + -webkit-animation: throb 1.33s ease-in-out infinite; + animation: throb 1.33s ease-in-out infinite; +} +.withLove .heart path { + fill: #ff005d; +} +@media screen and (min-width: 300px) { + .withLove .heart { + width: 30px; + height: 30px; + top: .66em; + } +} +@media screen and (min-width: 460px) { + .withLove .heart { + top: .8em; + width: 50px; + height: 50px; + } +} + +@-webkit-keyframes throb { + 0% { + -webkit-transform: scale(1); + } + + 50% { + -webkit-transform: scale(0.8); + } + + 100% { + -webkit-transform: scale(1); + } +} + +@keyframes throb { + 0% { + transform: scale(1); + } + + 50% { + transform: scale(0.8); + } + + 100% { + transform: scale(1); + } +} diff --git a/dist/scrollreveal.es.js b/dist/scrollreveal.es.js deleted file mode 100644 index fcd284c8..00000000 --- a/dist/scrollreveal.es.js +++ /dev/null @@ -1,1186 +0,0 @@ -/*! @license ScrollReveal v4.0.9 - - Copyright 2021 Fisssion LLC. - - Licensed under the GNU General Public License 3.0 for - compatible open source projects and non-commercial use. - - For commercial sites, themes, projects, and applications, - keep your source code private/proprietary by purchasing - a commercial license from https://scrollrevealjs.org/ -*/ -import $ from 'tealight'; -import { translateY, translateX, rotateX, rotateY, rotateZ, scale, parse, multiply } from 'rematrix'; -import raf from 'miniraf'; - -var defaults = { - delay: 0, - distance: '0', - duration: 600, - easing: 'cubic-bezier(0.5, 0, 0, 1)', - interval: 0, - opacity: 0, - origin: 'bottom', - rotate: { - x: 0, - y: 0, - z: 0 - }, - scale: 1, - cleanup: false, - container: document.documentElement, - desktop: true, - mobile: true, - reset: false, - useDelay: 'always', - viewFactor: 0.0, - viewOffset: { - top: 0, - right: 0, - bottom: 0, - left: 0 - }, - afterReset: function afterReset() {}, - afterReveal: function afterReveal() {}, - beforeReset: function beforeReset() {}, - beforeReveal: function beforeReveal() {} -}; - -function failure() { - document.documentElement.classList.remove('sr'); - - return { - clean: function clean() {}, - destroy: function destroy() {}, - reveal: function reveal() {}, - sync: function sync() {}, - get noop() { - return true - } - } -} - -function success() { - document.documentElement.classList.add('sr'); - - if (document.body) { - document.body.style.height = '100%'; - } else { - document.addEventListener('DOMContentLoaded', function () { - document.body.style.height = '100%'; - }); - } -} - -var mount = { success: success, failure: failure }; - -function isObject(x) { - return ( - x !== null && - x instanceof Object && - (x.constructor === Object || - Object.prototype.toString.call(x) === '[object Object]') - ) -} - -function each(collection, callback) { - if (isObject(collection)) { - var keys = Object.keys(collection); - return keys.forEach(function (key) { return callback(collection[key], key, collection); }) - } - if (collection instanceof Array) { - return collection.forEach(function (item, i) { return callback(item, i, collection); }) - } - throw new TypeError('Expected either an array or object literal.') -} - -function logger(message) { - var details = [], len = arguments.length - 1; - while ( len-- > 0 ) details[ len ] = arguments[ len + 1 ]; - - if (this.constructor.debug && console) { - var report = "%cScrollReveal: " + message; - details.forEach(function (detail) { return (report += "\n — " + detail); }); - console.log(report, 'color: #ea654b;'); // eslint-disable-line no-console - } -} - -function rinse() { - var this$1 = this; - - var struct = function () { return ({ - active: [], - stale: [] - }); }; - - var elementIds = struct(); - var sequenceIds = struct(); - var containerIds = struct(); - - /** - * Take stock of active element IDs. - */ - try { - each($('[data-sr-id]'), function (node) { - var id = parseInt(node.getAttribute('data-sr-id')); - elementIds.active.push(id); - }); - } catch (e) { - throw e - } - /** - * Destroy stale elements. - */ - each(this.store.elements, function (element) { - if (elementIds.active.indexOf(element.id) === -1) { - elementIds.stale.push(element.id); - } - }); - - each(elementIds.stale, function (staleId) { return delete this$1.store.elements[staleId]; }); - - /** - * Take stock of active container and sequence IDs. - */ - each(this.store.elements, function (element) { - if (containerIds.active.indexOf(element.containerId) === -1) { - containerIds.active.push(element.containerId); - } - if (element.hasOwnProperty('sequence')) { - if (sequenceIds.active.indexOf(element.sequence.id) === -1) { - sequenceIds.active.push(element.sequence.id); - } - } - }); - - /** - * Destroy stale containers. - */ - each(this.store.containers, function (container) { - if (containerIds.active.indexOf(container.id) === -1) { - containerIds.stale.push(container.id); - } - }); - - each(containerIds.stale, function (staleId) { - var stale = this$1.store.containers[staleId].node; - stale.removeEventListener('scroll', this$1.delegate); - stale.removeEventListener('resize', this$1.delegate); - delete this$1.store.containers[staleId]; - }); - - /** - * Destroy stale sequences. - */ - each(this.store.sequences, function (sequence) { - if (sequenceIds.active.indexOf(sequence.id) === -1) { - sequenceIds.stale.push(sequence.id); - } - }); - - each(sequenceIds.stale, function (staleId) { return delete this$1.store.sequences[staleId]; }); -} - -var getPrefixedCssProp = (function () { - var properties = {}; - var style = document.documentElement.style; - - function getPrefixedCssProperty(name, source) { - if ( source === void 0 ) source = style; - - if (name && typeof name === 'string') { - if (properties[name]) { - return properties[name] - } - if (typeof source[name] === 'string') { - return (properties[name] = name) - } - if (typeof source[("-webkit-" + name)] === 'string') { - return (properties[name] = "-webkit-" + name) - } - throw new RangeError(("Unable to find \"" + name + "\" style property.")) - } - throw new TypeError('Expected a string.') - } - - getPrefixedCssProperty.clearCache = function () { return (properties = {}); }; - - return getPrefixedCssProperty -})(); - -function style(element) { - var computed = window.getComputedStyle(element.node); - var position = computed.position; - var config = element.config; - - /** - * Generate inline styles - */ - var inline = {}; - var inlineStyle = element.node.getAttribute('style') || ''; - var inlineMatch = inlineStyle.match(/[\w-]+\s*:\s*[^;]+\s*/gi) || []; - - inline.computed = inlineMatch ? inlineMatch.map(function (m) { return m.trim(); }).join('; ') + ';' : ''; - - inline.generated = inlineMatch.some(function (m) { return m.match(/visibility\s?:\s?visible/i); }) - ? inline.computed - : inlineMatch.concat( ['visibility: visible']).map(function (m) { return m.trim(); }).join('; ') + ';'; - - /** - * Generate opacity styles - */ - var computedOpacity = parseFloat(computed.opacity); - var configOpacity = !isNaN(parseFloat(config.opacity)) - ? parseFloat(config.opacity) - : parseFloat(computed.opacity); - - var opacity = { - computed: computedOpacity !== configOpacity ? ("opacity: " + computedOpacity + ";") : '', - generated: computedOpacity !== configOpacity ? ("opacity: " + configOpacity + ";") : '' - }; - - /** - * Generate transformation styles - */ - var transformations = []; - - if (parseFloat(config.distance)) { - var axis = config.origin === 'top' || config.origin === 'bottom' ? 'Y' : 'X'; - - /** - * Let’s make sure our our pixel distances are negative for top and left. - * e.g. { origin: 'top', distance: '25px' } starts at `top: -25px` in CSS. - */ - var distance = config.distance; - if (config.origin === 'top' || config.origin === 'left') { - distance = /^-/.test(distance) ? distance.substr(1) : ("-" + distance); - } - - var ref = distance.match(/(^-?\d+\.?\d?)|(em$|px$|%$)/g); - var value = ref[0]; - var unit = ref[1]; - - switch (unit) { - case 'em': - distance = parseInt(computed.fontSize) * value; - break - case 'px': - distance = value; - break - case '%': - /** - * Here we use `getBoundingClientRect` instead of - * the existing data attached to `element.geometry` - * because only the former includes any transformations - * current applied to the element. - * - * If that behavior ends up being unintuitive, this - * logic could instead utilize `element.geometry.height` - * and `element.geoemetry.width` for the distance calculation - */ - distance = - axis === 'Y' - ? (element.node.getBoundingClientRect().height * value) / 100 - : (element.node.getBoundingClientRect().width * value) / 100; - break - default: - throw new RangeError('Unrecognized or missing distance unit.') - } - - if (axis === 'Y') { - transformations.push(translateY(distance)); - } else { - transformations.push(translateX(distance)); - } - } - - if (config.rotate.x) { transformations.push(rotateX(config.rotate.x)); } - if (config.rotate.y) { transformations.push(rotateY(config.rotate.y)); } - if (config.rotate.z) { transformations.push(rotateZ(config.rotate.z)); } - if (config.scale !== 1) { - if (config.scale === 0) { - /** - * The CSS Transforms matrix interpolation specification - * basically disallows transitions of non-invertible - * matrixes, which means browsers won't transition - * elements with zero scale. - * - * That’s inconvenient for the API and developer - * experience, so we simply nudge their value - * slightly above zero; this allows browsers - * to transition our element as expected. - * - * `0.0002` was the smallest number - * that performed across browsers. - */ - transformations.push(scale(0.0002)); - } else { - transformations.push(scale(config.scale)); - } - } - - var transform = {}; - if (transformations.length) { - transform.property = getPrefixedCssProp('transform'); - /** - * The default computed transform value should be one of: - * undefined || 'none' || 'matrix()' || 'matrix3d()' - */ - transform.computed = { - raw: computed[transform.property], - matrix: parse(computed[transform.property]) - }; - - transformations.unshift(transform.computed.matrix); - var product = transformations.reduce(multiply); - - transform.generated = { - initial: ((transform.property) + ": matrix3d(" + (product.join(', ')) + ");"), - final: ((transform.property) + ": matrix3d(" + (transform.computed.matrix.join(', ')) + ");") - }; - } else { - transform.generated = { - initial: '', - final: '' - }; - } - - /** - * Generate transition styles - */ - var transition = {}; - if (opacity.generated || transform.generated.initial) { - transition.property = getPrefixedCssProp('transition'); - transition.computed = computed[transition.property]; - transition.fragments = []; - - var delay = config.delay; - var duration = config.duration; - var easing = config.easing; - - if (opacity.generated) { - transition.fragments.push({ - delayed: ("opacity " + (duration / 1000) + "s " + easing + " " + (delay / 1000) + "s"), - instant: ("opacity " + (duration / 1000) + "s " + easing + " 0s") - }); - } - - if (transform.generated.initial) { - transition.fragments.push({ - delayed: ((transform.property) + " " + (duration / 1000) + "s " + easing + " " + (delay / 1000) + "s"), - instant: ((transform.property) + " " + (duration / 1000) + "s " + easing + " 0s") - }); - } - - /** - * The default computed transition property should be undefined, or one of: - * '' || 'none 0s ease 0s' || 'all 0s ease 0s' || 'all 0s 0s cubic-bezier()' - */ - var hasCustomTransition = - transition.computed && !transition.computed.match(/all 0s|none 0s/); - - if (hasCustomTransition) { - transition.fragments.unshift({ - delayed: transition.computed, - instant: transition.computed - }); - } - - var composed = transition.fragments.reduce( - function (composition, fragment, i) { - composition.delayed += i === 0 ? fragment.delayed : (", " + (fragment.delayed)); - composition.instant += i === 0 ? fragment.instant : (", " + (fragment.instant)); - return composition - }, - { - delayed: '', - instant: '' - } - ); - - transition.generated = { - delayed: ((transition.property) + ": " + (composed.delayed) + ";"), - instant: ((transition.property) + ": " + (composed.instant) + ";") - }; - } else { - transition.generated = { - delayed: '', - instant: '' - }; - } - - return { - inline: inline, - opacity: opacity, - position: position, - transform: transform, - transition: transition - } -} - -/** - * apply a CSS string to an element using the CSSOM (element.style) rather - * than setAttribute, which may violate the content security policy. - * - * @param {Node} [el] Element to receive styles. - * @param {string} [declaration] Styles to apply. - */ -function applyStyle (el, declaration) { - declaration.split(';').forEach(function (pair) { - var ref = pair.split(':'); - var property = ref[0]; - var value = ref.slice(1); - if (property && value) { - el.style[property.trim()] = value.join(':'); - } - }); -} - -function clean(target) { - var this$1 = this; - - var dirty; - try { - each($(target), function (node) { - var id = node.getAttribute('data-sr-id'); - if (id !== null) { - dirty = true; - var element = this$1.store.elements[id]; - if (element.callbackTimer) { - window.clearTimeout(element.callbackTimer.clock); - } - applyStyle(element.node, element.styles.inline.generated); - node.removeAttribute('data-sr-id'); - delete this$1.store.elements[id]; - } - }); - } catch (e) { - return logger.call(this, 'Clean failed.', e.message) - } - - if (dirty) { - try { - rinse.call(this); - } catch (e) { - return logger.call(this, 'Clean failed.', e.message) - } - } -} - -function destroy() { - var this$1 = this; - - /** - * Remove all generated styles and element ids - */ - each(this.store.elements, function (element) { - applyStyle(element.node, element.styles.inline.generated); - element.node.removeAttribute('data-sr-id'); - }); - - /** - * Remove all event listeners. - */ - each(this.store.containers, function (container) { - var target = - container.node === document.documentElement ? window : container.node; - target.removeEventListener('scroll', this$1.delegate); - target.removeEventListener('resize', this$1.delegate); - }); - - /** - * Clear all data from the store - */ - this.store = { - containers: {}, - elements: {}, - history: [], - sequences: {} - }; -} - -function deepAssign(target) { - var sources = [], len = arguments.length - 1; - while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ]; - - if (isObject(target)) { - each(sources, function (source) { - each(source, function (data, key) { - if (isObject(data)) { - if (!target[key] || !isObject(target[key])) { - target[key] = {}; - } - deepAssign(target[key], data); - } else { - target[key] = data; - } - }); - }); - return target - } else { - throw new TypeError('Target must be an object literal.') - } -} - -function isMobile(agent) { - if ( agent === void 0 ) agent = navigator.userAgent; - - return /Android|iPhone|iPad|iPod/i.test(agent) -} - -var nextUniqueId = (function () { - var uid = 0; - return function () { return uid++; } -})(); - -function initialize() { - var this$1 = this; - - rinse.call(this); - - each(this.store.elements, function (element) { - var styles = [element.styles.inline.generated]; - - if (element.visible) { - styles.push(element.styles.opacity.computed); - styles.push(element.styles.transform.generated.final); - element.revealed = true; - } else { - styles.push(element.styles.opacity.generated); - styles.push(element.styles.transform.generated.initial); - element.revealed = false; - } - - applyStyle(element.node, styles.filter(function (s) { return s !== ''; }).join(' ')); - }); - - each(this.store.containers, function (container) { - var target = - container.node === document.documentElement ? window : container.node; - target.addEventListener('scroll', this$1.delegate); - target.addEventListener('resize', this$1.delegate); - }); - - /** - * Manually invoke delegate once to capture - * element and container dimensions, container - * scroll position, and trigger any valid reveals - */ - this.delegate(); - - /** - * Wipe any existing `setTimeout` now - * that initialization has completed. - */ - this.initTimeout = null; -} - -function animate(element, force) { - if ( force === void 0 ) force = {}; - - var pristine = force.pristine || this.pristine; - var delayed = - element.config.useDelay === 'always' || - (element.config.useDelay === 'onload' && pristine) || - (element.config.useDelay === 'once' && !element.seen); - - var shouldReveal = element.visible && !element.revealed; - var shouldReset = !element.visible && element.revealed && element.config.reset; - - if (force.reveal || shouldReveal) { - return triggerReveal.call(this, element, delayed) - } - - if (force.reset || shouldReset) { - return triggerReset.call(this, element) - } -} - -function triggerReveal(element, delayed) { - var styles = [ - element.styles.inline.generated, - element.styles.opacity.computed, - element.styles.transform.generated.final - ]; - if (delayed) { - styles.push(element.styles.transition.generated.delayed); - } else { - styles.push(element.styles.transition.generated.instant); - } - element.revealed = element.seen = true; - applyStyle(element.node, styles.filter(function (s) { return s !== ''; }).join(' ')); - registerCallbacks.call(this, element, delayed); -} - -function triggerReset(element) { - var styles = [ - element.styles.inline.generated, - element.styles.opacity.generated, - element.styles.transform.generated.initial, - element.styles.transition.generated.instant - ]; - element.revealed = false; - applyStyle(element.node, styles.filter(function (s) { return s !== ''; }).join(' ')); - registerCallbacks.call(this, element); -} - -function registerCallbacks(element, isDelayed) { - var this$1 = this; - - var duration = isDelayed - ? element.config.duration + element.config.delay - : element.config.duration; - - var beforeCallback = element.revealed - ? element.config.beforeReveal - : element.config.beforeReset; - - var afterCallback = element.revealed - ? element.config.afterReveal - : element.config.afterReset; - - var elapsed = 0; - if (element.callbackTimer) { - elapsed = Date.now() - element.callbackTimer.start; - window.clearTimeout(element.callbackTimer.clock); - } - - beforeCallback(element.node); - - element.callbackTimer = { - start: Date.now(), - clock: window.setTimeout(function () { - afterCallback(element.node); - element.callbackTimer = null; - if (element.revealed && !element.config.reset && element.config.cleanup) { - clean.call(this$1, element.node); - } - }, duration - elapsed) - }; -} - -function sequence(element, pristine) { - if ( pristine === void 0 ) pristine = this.pristine; - - /** - * We first check if the element should reset. - */ - if (!element.visible && element.revealed && element.config.reset) { - return animate.call(this, element, { reset: true }) - } - - var seq = this.store.sequences[element.sequence.id]; - var i = element.sequence.index; - - if (seq) { - var visible = new SequenceModel(seq, 'visible', this.store); - var revealed = new SequenceModel(seq, 'revealed', this.store); - - seq.models = { visible: visible, revealed: revealed }; - - /** - * If the sequence has no revealed members, - * then we reveal the first visible element - * within that sequence. - * - * The sequence then cues a recursive call - * in both directions. - */ - if (!revealed.body.length) { - var nextId = seq.members[visible.body[0]]; - var nextElement = this.store.elements[nextId]; - - if (nextElement) { - cue.call(this, seq, visible.body[0], -1, pristine); - cue.call(this, seq, visible.body[0], +1, pristine); - return animate.call(this, nextElement, { reveal: true, pristine: pristine }) - } - } - - /** - * If our element isn’t resetting, we check the - * element sequence index against the head, and - * then the foot of the sequence. - */ - if ( - !seq.blocked.head && - i === [].concat( revealed.head ).pop() && - i >= [].concat( visible.body ).shift() - ) { - cue.call(this, seq, i, -1, pristine); - return animate.call(this, element, { reveal: true, pristine: pristine }) - } - - if ( - !seq.blocked.foot && - i === [].concat( revealed.foot ).shift() && - i <= [].concat( visible.body ).pop() - ) { - cue.call(this, seq, i, +1, pristine); - return animate.call(this, element, { reveal: true, pristine: pristine }) - } - } -} - -function Sequence(interval) { - var i = Math.abs(interval); - if (!isNaN(i)) { - this.id = nextUniqueId(); - this.interval = Math.max(i, 16); - this.members = []; - this.models = {}; - this.blocked = { - head: false, - foot: false - }; - } else { - throw new RangeError('Invalid sequence interval.') - } -} - -function SequenceModel(seq, prop, store) { - var this$1 = this; - - this.head = []; - this.body = []; - this.foot = []; - - each(seq.members, function (id, index) { - var element = store.elements[id]; - if (element && element[prop]) { - this$1.body.push(index); - } - }); - - if (this.body.length) { - each(seq.members, function (id, index) { - var element = store.elements[id]; - if (element && !element[prop]) { - if (index < this$1.body[0]) { - this$1.head.push(index); - } else { - this$1.foot.push(index); - } - } - }); - } -} - -function cue(seq, i, direction, pristine) { - var this$1 = this; - - var blocked = ['head', null, 'foot'][1 + direction]; - var nextId = seq.members[i + direction]; - var nextElement = this.store.elements[nextId]; - - seq.blocked[blocked] = true; - - setTimeout(function () { - seq.blocked[blocked] = false; - if (nextElement) { - sequence.call(this$1, nextElement, pristine); - } - }, seq.interval); -} - -function reveal(target, options, syncing) { - var this$1 = this; - if ( options === void 0 ) options = {}; - if ( syncing === void 0 ) syncing = false; - - var containerBuffer = []; - var sequence$$1; - var interval = options.interval || defaults.interval; - - try { - if (interval) { - sequence$$1 = new Sequence(interval); - } - - var nodes = $(target); - if (!nodes.length) { - throw new Error('Invalid reveal target.') - } - - var elements = nodes.reduce(function (elementBuffer, elementNode) { - var element = {}; - var existingId = elementNode.getAttribute('data-sr-id'); - - if (existingId) { - deepAssign(element, this$1.store.elements[existingId]); - - /** - * In order to prevent previously generated styles - * from throwing off the new styles, the style tag - * has to be reverted to its pre-reveal state. - */ - applyStyle(element.node, element.styles.inline.computed); - } else { - element.id = nextUniqueId(); - element.node = elementNode; - element.seen = false; - element.revealed = false; - element.visible = false; - } - - var config = deepAssign({}, element.config || this$1.defaults, options); - - if ((!config.mobile && isMobile()) || (!config.desktop && !isMobile())) { - if (existingId) { - clean.call(this$1, element); - } - return elementBuffer // skip elements that are disabled - } - - var containerNode = $(config.container)[0]; - if (!containerNode) { - throw new Error('Invalid container.') - } - if (!containerNode.contains(elementNode)) { - return elementBuffer // skip elements found outside the container - } - - var containerId; - { - containerId = getContainerId( - containerNode, - containerBuffer, - this$1.store.containers - ); - if (containerId === null) { - containerId = nextUniqueId(); - containerBuffer.push({ id: containerId, node: containerNode }); - } - } - - element.config = config; - element.containerId = containerId; - element.styles = style(element); - - if (sequence$$1) { - element.sequence = { - id: sequence$$1.id, - index: sequence$$1.members.length - }; - sequence$$1.members.push(element.id); - } - - elementBuffer.push(element); - return elementBuffer - }, []); - - /** - * Modifying the DOM via setAttribute needs to be handled - * separately from reading computed styles in the map above - * for the browser to batch DOM changes (limiting reflows) - */ - each(elements, function (element) { - this$1.store.elements[element.id] = element; - element.node.setAttribute('data-sr-id', element.id); - }); - } catch (e) { - return logger.call(this, 'Reveal failed.', e.message) - } - - /** - * Now that element set-up is complete... - * Let’s commit any container and sequence data we have to the store. - */ - each(containerBuffer, function (container) { - this$1.store.containers[container.id] = { - id: container.id, - node: container.node - }; - }); - if (sequence$$1) { - this.store.sequences[sequence$$1.id] = sequence$$1; - } - - /** - * If reveal wasn't invoked by sync, we want to - * make sure to add this call to the history. - */ - if (syncing !== true) { - this.store.history.push({ target: target, options: options }); - - /** - * Push initialization to the event queue, giving - * multiple reveal calls time to be interpreted. - */ - if (this.initTimeout) { - window.clearTimeout(this.initTimeout); - } - this.initTimeout = window.setTimeout(initialize.bind(this), 0); - } -} - -function getContainerId(node) { - var collections = [], len = arguments.length - 1; - while ( len-- > 0 ) collections[ len ] = arguments[ len + 1 ]; - - var id = null; - each(collections, function (collection) { - each(collection, function (container) { - if (id === null && container.node === node) { - id = container.id; - } - }); - }); - return id -} - -/** - * Re-runs the reveal method for each record stored in history, - * for capturing new content asynchronously loaded into the DOM. - */ -function sync() { - var this$1 = this; - - each(this.store.history, function (record) { - reveal.call(this$1, record.target, record.options, true); - }); - - initialize.call(this); -} - -var polyfill = function (x) { return (x > 0) - (x < 0) || +x; }; -var mathSign = Math.sign || polyfill; - -function getGeometry(target, isContainer) { - /** - * We want to ignore padding and scrollbars for container elements. - * More information here: https://goo.gl/vOZpbz - */ - var height = isContainer ? target.node.clientHeight : target.node.offsetHeight; - var width = isContainer ? target.node.clientWidth : target.node.offsetWidth; - - var offsetTop = 0; - var offsetLeft = 0; - var node = target.node; - - do { - if (!isNaN(node.offsetTop)) { - offsetTop += node.offsetTop; - } - if (!isNaN(node.offsetLeft)) { - offsetLeft += node.offsetLeft; - } - node = node.offsetParent; - } while (node) - - return { - bounds: { - top: offsetTop, - right: offsetLeft + width, - bottom: offsetTop + height, - left: offsetLeft - }, - height: height, - width: width - } -} - -function getScrolled(container) { - var top, left; - if (container.node === document.documentElement) { - top = window.pageYOffset; - left = window.pageXOffset; - } else { - top = container.node.scrollTop; - left = container.node.scrollLeft; - } - return { top: top, left: left } -} - -function isElementVisible(element) { - if ( element === void 0 ) element = {}; - - var container = this.store.containers[element.containerId]; - if (!container) { return } - - var viewFactor = Math.max(0, Math.min(1, element.config.viewFactor)); - var viewOffset = element.config.viewOffset; - - var elementBounds = { - top: element.geometry.bounds.top + element.geometry.height * viewFactor, - right: element.geometry.bounds.right - element.geometry.width * viewFactor, - bottom: element.geometry.bounds.bottom - element.geometry.height * viewFactor, - left: element.geometry.bounds.left + element.geometry.width * viewFactor - }; - - var containerBounds = { - top: container.geometry.bounds.top + container.scroll.top + viewOffset.top, - right: container.geometry.bounds.right + container.scroll.left - viewOffset.right, - bottom: - container.geometry.bounds.bottom + container.scroll.top - viewOffset.bottom, - left: container.geometry.bounds.left + container.scroll.left + viewOffset.left - }; - - return ( - (elementBounds.top < containerBounds.bottom && - elementBounds.right > containerBounds.left && - elementBounds.bottom > containerBounds.top && - elementBounds.left < containerBounds.right) || - element.styles.position === 'fixed' - ) -} - -function delegate( - event, - elements -) { - var this$1 = this; - if ( event === void 0 ) event = { type: 'init' }; - if ( elements === void 0 ) elements = this.store.elements; - - raf(function () { - var stale = event.type === 'init' || event.type === 'resize'; - - each(this$1.store.containers, function (container) { - if (stale) { - container.geometry = getGeometry.call(this$1, container, true); - } - var scroll = getScrolled.call(this$1, container); - if (container.scroll) { - container.direction = { - x: mathSign(scroll.left - container.scroll.left), - y: mathSign(scroll.top - container.scroll.top) - }; - } - container.scroll = scroll; - }); - - /** - * Due to how the sequencer is implemented, it’s - * important that we update the state of all - * elements, before any animation logic is - * evaluated (in the second loop below). - */ - each(elements, function (element) { - if (stale || element.geometry === undefined) { - element.geometry = getGeometry.call(this$1, element); - } - element.visible = isElementVisible.call(this$1, element); - }); - - each(elements, function (element) { - if (element.sequence) { - sequence.call(this$1, element); - } else { - animate.call(this$1, element); - } - }); - - this$1.pristine = false; - }); -} - -function isTransformSupported() { - var style = document.documentElement.style; - return 'transform' in style || 'WebkitTransform' in style -} - -function isTransitionSupported() { - var style = document.documentElement.style; - return 'transition' in style || 'WebkitTransition' in style -} - -var version = "4.0.9"; - -var boundDelegate; -var boundDestroy; -var boundReveal; -var boundClean; -var boundSync; -var config; -var debug; -var instance; - -function ScrollReveal(options) { - if ( options === void 0 ) options = {}; - - var invokedWithoutNew = - typeof this === 'undefined' || - Object.getPrototypeOf(this) !== ScrollReveal.prototype; - - if (invokedWithoutNew) { - return new ScrollReveal(options) - } - - if (!ScrollReveal.isSupported()) { - logger.call(this, 'Instantiation failed.', 'This browser is not supported.'); - return mount.failure() - } - - var buffer; - try { - buffer = config - ? deepAssign({}, config, options) - : deepAssign({}, defaults, options); - } catch (e) { - logger.call(this, 'Invalid configuration.', e.message); - return mount.failure() - } - - try { - var container = $(buffer.container)[0]; - if (!container) { - throw new Error('Invalid container.') - } - } catch (e) { - logger.call(this, e.message); - return mount.failure() - } - - config = buffer; - - if ((!config.mobile && isMobile()) || (!config.desktop && !isMobile())) { - logger.call( - this, - 'This device is disabled.', - ("desktop: " + (config.desktop)), - ("mobile: " + (config.mobile)) - ); - return mount.failure() - } - - mount.success(); - - this.store = { - containers: {}, - elements: {}, - history: [], - sequences: {} - }; - - this.pristine = true; - - boundDelegate = boundDelegate || delegate.bind(this); - boundDestroy = boundDestroy || destroy.bind(this); - boundReveal = boundReveal || reveal.bind(this); - boundClean = boundClean || clean.bind(this); - boundSync = boundSync || sync.bind(this); - - Object.defineProperty(this, 'delegate', { get: function () { return boundDelegate; } }); - Object.defineProperty(this, 'destroy', { get: function () { return boundDestroy; } }); - Object.defineProperty(this, 'reveal', { get: function () { return boundReveal; } }); - Object.defineProperty(this, 'clean', { get: function () { return boundClean; } }); - Object.defineProperty(this, 'sync', { get: function () { return boundSync; } }); - - Object.defineProperty(this, 'defaults', { get: function () { return config; } }); - Object.defineProperty(this, 'version', { get: function () { return version; } }); - Object.defineProperty(this, 'noop', { get: function () { return false; } }); - - return instance ? instance : (instance = this) -} - -ScrollReveal.isSupported = function () { return isTransformSupported() && isTransitionSupported(); }; - -Object.defineProperty(ScrollReveal, 'debug', { - get: function () { return debug || false; }, - set: function (value) { return (debug = typeof value === 'boolean' ? value : debug); } -}); - -ScrollReveal(); - -export default ScrollReveal; diff --git a/dist/scrollreveal.js b/dist/scrollreveal.js deleted file mode 100644 index 99b46d30..00000000 --- a/dist/scrollreveal.js +++ /dev/null @@ -1,1564 +0,0 @@ -/*! @license ScrollReveal v4.0.9 - - Copyright 2021 Fisssion LLC. - - Licensed under the GNU General Public License 3.0 for - compatible open source projects and non-commercial use. - - For commercial sites, themes, projects, and applications, - keep your source code private/proprietary by purchasing - a commercial license from https://scrollrevealjs.org/ -*/ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global.ScrollReveal = factory()); -}(this, function () { 'use strict'; - - var defaults = { - delay: 0, - distance: '0', - duration: 600, - easing: 'cubic-bezier(0.5, 0, 0, 1)', - interval: 0, - opacity: 0, - origin: 'bottom', - rotate: { - x: 0, - y: 0, - z: 0 - }, - scale: 1, - cleanup: false, - container: document.documentElement, - desktop: true, - mobile: true, - reset: false, - useDelay: 'always', - viewFactor: 0.0, - viewOffset: { - top: 0, - right: 0, - bottom: 0, - left: 0 - }, - afterReset: function afterReset() {}, - afterReveal: function afterReveal() {}, - beforeReset: function beforeReset() {}, - beforeReveal: function beforeReveal() {} - }; - - function failure() { - document.documentElement.classList.remove('sr'); - - return { - clean: function clean() {}, - destroy: function destroy() {}, - reveal: function reveal() {}, - sync: function sync() {}, - get noop() { - return true - } - } - } - - function success() { - document.documentElement.classList.add('sr'); - - if (document.body) { - document.body.style.height = '100%'; - } else { - document.addEventListener('DOMContentLoaded', function () { - document.body.style.height = '100%'; - }); - } - } - - var mount = { success: success, failure: failure }; - - /*! @license is-dom-node v1.0.4 - - Copyright 2018 Fisssion LLC. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - */ - function isDomNode(x) { - return typeof window.Node === 'object' - ? x instanceof window.Node - : x !== null && - typeof x === 'object' && - typeof x.nodeType === 'number' && - typeof x.nodeName === 'string' - } - - /*! @license is-dom-node-list v1.2.1 - - Copyright 2018 Fisssion LLC. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - */ - - function isDomNodeList(x) { - var prototypeToString = Object.prototype.toString.call(x); - var regex = /^\[object (HTMLCollection|NodeList|Object)\]$/; - - return typeof window.NodeList === 'object' - ? x instanceof window.NodeList - : x !== null && - typeof x === 'object' && - typeof x.length === 'number' && - regex.test(prototypeToString) && - (x.length === 0 || isDomNode(x[0])) - } - - /*! @license Tealight v0.3.6 - - Copyright 2018 Fisssion LLC. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - */ - - function tealight(target, context) { - if ( context === void 0 ) { context = document; } - - if (target instanceof Array) { return target.filter(isDomNode); } - if (isDomNode(target)) { return [target]; } - if (isDomNodeList(target)) { return Array.prototype.slice.call(target); } - if (typeof target === "string") { - try { - var query = context.querySelectorAll(target); - return Array.prototype.slice.call(query); - } catch (err) { - return []; - } - } - return []; - } - - function isObject(x) { - return ( - x !== null && - x instanceof Object && - (x.constructor === Object || - Object.prototype.toString.call(x) === '[object Object]') - ) - } - - function each(collection, callback) { - if (isObject(collection)) { - var keys = Object.keys(collection); - return keys.forEach(function (key) { return callback(collection[key], key, collection); }) - } - if (collection instanceof Array) { - return collection.forEach(function (item, i) { return callback(item, i, collection); }) - } - throw new TypeError('Expected either an array or object literal.') - } - - function logger(message) { - var details = [], len = arguments.length - 1; - while ( len-- > 0 ) details[ len ] = arguments[ len + 1 ]; - - if (this.constructor.debug && console) { - var report = "%cScrollReveal: " + message; - details.forEach(function (detail) { return (report += "\n — " + detail); }); - console.log(report, 'color: #ea654b;'); // eslint-disable-line no-console - } - } - - function rinse() { - var this$1 = this; - - var struct = function () { return ({ - active: [], - stale: [] - }); }; - - var elementIds = struct(); - var sequenceIds = struct(); - var containerIds = struct(); - - /** - * Take stock of active element IDs. - */ - try { - each(tealight('[data-sr-id]'), function (node) { - var id = parseInt(node.getAttribute('data-sr-id')); - elementIds.active.push(id); - }); - } catch (e) { - throw e - } - /** - * Destroy stale elements. - */ - each(this.store.elements, function (element) { - if (elementIds.active.indexOf(element.id) === -1) { - elementIds.stale.push(element.id); - } - }); - - each(elementIds.stale, function (staleId) { return delete this$1.store.elements[staleId]; }); - - /** - * Take stock of active container and sequence IDs. - */ - each(this.store.elements, function (element) { - if (containerIds.active.indexOf(element.containerId) === -1) { - containerIds.active.push(element.containerId); - } - if (element.hasOwnProperty('sequence')) { - if (sequenceIds.active.indexOf(element.sequence.id) === -1) { - sequenceIds.active.push(element.sequence.id); - } - } - }); - - /** - * Destroy stale containers. - */ - each(this.store.containers, function (container) { - if (containerIds.active.indexOf(container.id) === -1) { - containerIds.stale.push(container.id); - } - }); - - each(containerIds.stale, function (staleId) { - var stale = this$1.store.containers[staleId].node; - stale.removeEventListener('scroll', this$1.delegate); - stale.removeEventListener('resize', this$1.delegate); - delete this$1.store.containers[staleId]; - }); - - /** - * Destroy stale sequences. - */ - each(this.store.sequences, function (sequence) { - if (sequenceIds.active.indexOf(sequence.id) === -1) { - sequenceIds.stale.push(sequence.id); - } - }); - - each(sequenceIds.stale, function (staleId) { return delete this$1.store.sequences[staleId]; }); - } - - /*! @license Rematrix v0.3.0 - - Copyright 2018 Julian Lloyd. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - /** - * @module Rematrix - */ - - /** - * Transformation matrices in the browser come in two flavors: - * - * - `matrix` using 6 values (short) - * - `matrix3d` using 16 values (long) - * - * This utility follows this [conversion guide](https://goo.gl/EJlUQ1) - * to expand short form matrices to their equivalent long form. - * - * @param {array} source - Accepts both short and long form matrices. - * @return {array} - */ - function format(source) { - if (source.constructor !== Array) { - throw new TypeError('Expected array.') - } - if (source.length === 16) { - return source - } - if (source.length === 6) { - var matrix = identity(); - matrix[0] = source[0]; - matrix[1] = source[1]; - matrix[4] = source[2]; - matrix[5] = source[3]; - matrix[12] = source[4]; - matrix[13] = source[5]; - return matrix - } - throw new RangeError('Expected array with either 6 or 16 values.') - } - - /** - * Returns a matrix representing no transformation. The product of any matrix - * multiplied by the identity matrix will be the original matrix. - * - * > **Tip:** Similar to how `5 * 1 === 5`, where `1` is the identity. - * - * @return {array} - */ - function identity() { - var matrix = []; - for (var i = 0; i < 16; i++) { - i % 5 == 0 ? matrix.push(1) : matrix.push(0); - } - return matrix - } - - /** - * Returns a 4x4 matrix describing the combined transformations - * of both arguments. - * - * > **Note:** Order is very important. For example, rotating 45° - * along the Z-axis, followed by translating 500 pixels along the - * Y-axis... is not the same as translating 500 pixels along the - * Y-axis, followed by rotating 45° along on the Z-axis. - * - * @param {array} m - Accepts both short and long form matrices. - * @param {array} x - Accepts both short and long form matrices. - * @return {array} - */ - function multiply(m, x) { - var fm = format(m); - var fx = format(x); - var product = []; - - for (var i = 0; i < 4; i++) { - var row = [fm[i], fm[i + 4], fm[i + 8], fm[i + 12]]; - for (var j = 0; j < 4; j++) { - var k = j * 4; - var col = [fx[k], fx[k + 1], fx[k + 2], fx[k + 3]]; - var result = - row[0] * col[0] + row[1] * col[1] + row[2] * col[2] + row[3] * col[3]; - - product[i + k] = result; - } - } - - return product - } - - /** - * Attempts to return a 4x4 matrix describing the CSS transform - * matrix passed in, but will return the identity matrix as a - * fallback. - * - * > **Tip:** This method is used to convert a CSS matrix (retrieved as a - * `string` from computed styles) to its equivalent array format. - * - * @param {string} source - `matrix` or `matrix3d` CSS Transform value. - * @return {array} - */ - function parse(source) { - if (typeof source === 'string') { - var match = source.match(/matrix(3d)?\(([^)]+)\)/); - if (match) { - var raw = match[2].split(', ').map(parseFloat); - return format(raw) - } - } - return identity() - } - - /** - * Returns a 4x4 matrix describing X-axis rotation. - * - * @param {number} angle - Measured in degrees. - * @return {array} - */ - function rotateX(angle) { - var theta = Math.PI / 180 * angle; - var matrix = identity(); - - matrix[5] = matrix[10] = Math.cos(theta); - matrix[6] = matrix[9] = Math.sin(theta); - matrix[9] *= -1; - - return matrix - } - - /** - * Returns a 4x4 matrix describing Y-axis rotation. - * - * @param {number} angle - Measured in degrees. - * @return {array} - */ - function rotateY(angle) { - var theta = Math.PI / 180 * angle; - var matrix = identity(); - - matrix[0] = matrix[10] = Math.cos(theta); - matrix[2] = matrix[8] = Math.sin(theta); - matrix[2] *= -1; - - return matrix - } - - /** - * Returns a 4x4 matrix describing Z-axis rotation. - * - * @param {number} angle - Measured in degrees. - * @return {array} - */ - function rotateZ(angle) { - var theta = Math.PI / 180 * angle; - var matrix = identity(); - - matrix[0] = matrix[5] = Math.cos(theta); - matrix[1] = matrix[4] = Math.sin(theta); - matrix[4] *= -1; - - return matrix - } - - /** - * Returns a 4x4 matrix describing 2D scaling. The first argument - * is used for both X and Y-axis scaling, unless an optional - * second argument is provided to explicitly define Y-axis scaling. - * - * @param {number} scalar - Decimal multiplier. - * @param {number} [scalarY] - Decimal multiplier. - * @return {array} - */ - function scale(scalar, scalarY) { - var matrix = identity(); - - matrix[0] = scalar; - matrix[5] = typeof scalarY === 'number' ? scalarY : scalar; - - return matrix - } - - /** - * Returns a 4x4 matrix describing X-axis translation. - * - * @param {number} distance - Measured in pixels. - * @return {array} - */ - function translateX(distance) { - var matrix = identity(); - matrix[12] = distance; - return matrix - } - - /** - * Returns a 4x4 matrix describing Y-axis translation. - * - * @param {number} distance - Measured in pixels. - * @return {array} - */ - function translateY(distance) { - var matrix = identity(); - matrix[13] = distance; - return matrix - } - - var getPrefixedCssProp = (function () { - var properties = {}; - var style = document.documentElement.style; - - function getPrefixedCssProperty(name, source) { - if ( source === void 0 ) source = style; - - if (name && typeof name === 'string') { - if (properties[name]) { - return properties[name] - } - if (typeof source[name] === 'string') { - return (properties[name] = name) - } - if (typeof source[("-webkit-" + name)] === 'string') { - return (properties[name] = "-webkit-" + name) - } - throw new RangeError(("Unable to find \"" + name + "\" style property.")) - } - throw new TypeError('Expected a string.') - } - - getPrefixedCssProperty.clearCache = function () { return (properties = {}); }; - - return getPrefixedCssProperty - })(); - - function style(element) { - var computed = window.getComputedStyle(element.node); - var position = computed.position; - var config = element.config; - - /** - * Generate inline styles - */ - var inline = {}; - var inlineStyle = element.node.getAttribute('style') || ''; - var inlineMatch = inlineStyle.match(/[\w-]+\s*:\s*[^;]+\s*/gi) || []; - - inline.computed = inlineMatch ? inlineMatch.map(function (m) { return m.trim(); }).join('; ') + ';' : ''; - - inline.generated = inlineMatch.some(function (m) { return m.match(/visibility\s?:\s?visible/i); }) - ? inline.computed - : inlineMatch.concat( ['visibility: visible']).map(function (m) { return m.trim(); }).join('; ') + ';'; - - /** - * Generate opacity styles - */ - var computedOpacity = parseFloat(computed.opacity); - var configOpacity = !isNaN(parseFloat(config.opacity)) - ? parseFloat(config.opacity) - : parseFloat(computed.opacity); - - var opacity = { - computed: computedOpacity !== configOpacity ? ("opacity: " + computedOpacity + ";") : '', - generated: computedOpacity !== configOpacity ? ("opacity: " + configOpacity + ";") : '' - }; - - /** - * Generate transformation styles - */ - var transformations = []; - - if (parseFloat(config.distance)) { - var axis = config.origin === 'top' || config.origin === 'bottom' ? 'Y' : 'X'; - - /** - * Let’s make sure our our pixel distances are negative for top and left. - * e.g. { origin: 'top', distance: '25px' } starts at `top: -25px` in CSS. - */ - var distance = config.distance; - if (config.origin === 'top' || config.origin === 'left') { - distance = /^-/.test(distance) ? distance.substr(1) : ("-" + distance); - } - - var ref = distance.match(/(^-?\d+\.?\d?)|(em$|px$|%$)/g); - var value = ref[0]; - var unit = ref[1]; - - switch (unit) { - case 'em': - distance = parseInt(computed.fontSize) * value; - break - case 'px': - distance = value; - break - case '%': - /** - * Here we use `getBoundingClientRect` instead of - * the existing data attached to `element.geometry` - * because only the former includes any transformations - * current applied to the element. - * - * If that behavior ends up being unintuitive, this - * logic could instead utilize `element.geometry.height` - * and `element.geoemetry.width` for the distance calculation - */ - distance = - axis === 'Y' - ? (element.node.getBoundingClientRect().height * value) / 100 - : (element.node.getBoundingClientRect().width * value) / 100; - break - default: - throw new RangeError('Unrecognized or missing distance unit.') - } - - if (axis === 'Y') { - transformations.push(translateY(distance)); - } else { - transformations.push(translateX(distance)); - } - } - - if (config.rotate.x) { transformations.push(rotateX(config.rotate.x)); } - if (config.rotate.y) { transformations.push(rotateY(config.rotate.y)); } - if (config.rotate.z) { transformations.push(rotateZ(config.rotate.z)); } - if (config.scale !== 1) { - if (config.scale === 0) { - /** - * The CSS Transforms matrix interpolation specification - * basically disallows transitions of non-invertible - * matrixes, which means browsers won't transition - * elements with zero scale. - * - * That’s inconvenient for the API and developer - * experience, so we simply nudge their value - * slightly above zero; this allows browsers - * to transition our element as expected. - * - * `0.0002` was the smallest number - * that performed across browsers. - */ - transformations.push(scale(0.0002)); - } else { - transformations.push(scale(config.scale)); - } - } - - var transform = {}; - if (transformations.length) { - transform.property = getPrefixedCssProp('transform'); - /** - * The default computed transform value should be one of: - * undefined || 'none' || 'matrix()' || 'matrix3d()' - */ - transform.computed = { - raw: computed[transform.property], - matrix: parse(computed[transform.property]) - }; - - transformations.unshift(transform.computed.matrix); - var product = transformations.reduce(multiply); - - transform.generated = { - initial: ((transform.property) + ": matrix3d(" + (product.join(', ')) + ");"), - final: ((transform.property) + ": matrix3d(" + (transform.computed.matrix.join(', ')) + ");") - }; - } else { - transform.generated = { - initial: '', - final: '' - }; - } - - /** - * Generate transition styles - */ - var transition = {}; - if (opacity.generated || transform.generated.initial) { - transition.property = getPrefixedCssProp('transition'); - transition.computed = computed[transition.property]; - transition.fragments = []; - - var delay = config.delay; - var duration = config.duration; - var easing = config.easing; - - if (opacity.generated) { - transition.fragments.push({ - delayed: ("opacity " + (duration / 1000) + "s " + easing + " " + (delay / 1000) + "s"), - instant: ("opacity " + (duration / 1000) + "s " + easing + " 0s") - }); - } - - if (transform.generated.initial) { - transition.fragments.push({ - delayed: ((transform.property) + " " + (duration / 1000) + "s " + easing + " " + (delay / 1000) + "s"), - instant: ((transform.property) + " " + (duration / 1000) + "s " + easing + " 0s") - }); - } - - /** - * The default computed transition property should be undefined, or one of: - * '' || 'none 0s ease 0s' || 'all 0s ease 0s' || 'all 0s 0s cubic-bezier()' - */ - var hasCustomTransition = - transition.computed && !transition.computed.match(/all 0s|none 0s/); - - if (hasCustomTransition) { - transition.fragments.unshift({ - delayed: transition.computed, - instant: transition.computed - }); - } - - var composed = transition.fragments.reduce( - function (composition, fragment, i) { - composition.delayed += i === 0 ? fragment.delayed : (", " + (fragment.delayed)); - composition.instant += i === 0 ? fragment.instant : (", " + (fragment.instant)); - return composition - }, - { - delayed: '', - instant: '' - } - ); - - transition.generated = { - delayed: ((transition.property) + ": " + (composed.delayed) + ";"), - instant: ((transition.property) + ": " + (composed.instant) + ";") - }; - } else { - transition.generated = { - delayed: '', - instant: '' - }; - } - - return { - inline: inline, - opacity: opacity, - position: position, - transform: transform, - transition: transition - } - } - - /** - * apply a CSS string to an element using the CSSOM (element.style) rather - * than setAttribute, which may violate the content security policy. - * - * @param {Node} [el] Element to receive styles. - * @param {string} [declaration] Styles to apply. - */ - function applyStyle (el, declaration) { - declaration.split(';').forEach(function (pair) { - var ref = pair.split(':'); - var property = ref[0]; - var value = ref.slice(1); - if (property && value) { - el.style[property.trim()] = value.join(':'); - } - }); - } - - function clean(target) { - var this$1 = this; - - var dirty; - try { - each(tealight(target), function (node) { - var id = node.getAttribute('data-sr-id'); - if (id !== null) { - dirty = true; - var element = this$1.store.elements[id]; - if (element.callbackTimer) { - window.clearTimeout(element.callbackTimer.clock); - } - applyStyle(element.node, element.styles.inline.generated); - node.removeAttribute('data-sr-id'); - delete this$1.store.elements[id]; - } - }); - } catch (e) { - return logger.call(this, 'Clean failed.', e.message) - } - - if (dirty) { - try { - rinse.call(this); - } catch (e) { - return logger.call(this, 'Clean failed.', e.message) - } - } - } - - function destroy() { - var this$1 = this; - - /** - * Remove all generated styles and element ids - */ - each(this.store.elements, function (element) { - applyStyle(element.node, element.styles.inline.generated); - element.node.removeAttribute('data-sr-id'); - }); - - /** - * Remove all event listeners. - */ - each(this.store.containers, function (container) { - var target = - container.node === document.documentElement ? window : container.node; - target.removeEventListener('scroll', this$1.delegate); - target.removeEventListener('resize', this$1.delegate); - }); - - /** - * Clear all data from the store - */ - this.store = { - containers: {}, - elements: {}, - history: [], - sequences: {} - }; - } - - function deepAssign(target) { - var sources = [], len = arguments.length - 1; - while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ]; - - if (isObject(target)) { - each(sources, function (source) { - each(source, function (data, key) { - if (isObject(data)) { - if (!target[key] || !isObject(target[key])) { - target[key] = {}; - } - deepAssign(target[key], data); - } else { - target[key] = data; - } - }); - }); - return target - } else { - throw new TypeError('Target must be an object literal.') - } - } - - function isMobile(agent) { - if ( agent === void 0 ) agent = navigator.userAgent; - - return /Android|iPhone|iPad|iPod/i.test(agent) - } - - var nextUniqueId = (function () { - var uid = 0; - return function () { return uid++; } - })(); - - function initialize() { - var this$1 = this; - - rinse.call(this); - - each(this.store.elements, function (element) { - var styles = [element.styles.inline.generated]; - - if (element.visible) { - styles.push(element.styles.opacity.computed); - styles.push(element.styles.transform.generated.final); - element.revealed = true; - } else { - styles.push(element.styles.opacity.generated); - styles.push(element.styles.transform.generated.initial); - element.revealed = false; - } - - applyStyle(element.node, styles.filter(function (s) { return s !== ''; }).join(' ')); - }); - - each(this.store.containers, function (container) { - var target = - container.node === document.documentElement ? window : container.node; - target.addEventListener('scroll', this$1.delegate); - target.addEventListener('resize', this$1.delegate); - }); - - /** - * Manually invoke delegate once to capture - * element and container dimensions, container - * scroll position, and trigger any valid reveals - */ - this.delegate(); - - /** - * Wipe any existing `setTimeout` now - * that initialization has completed. - */ - this.initTimeout = null; - } - - function animate(element, force) { - if ( force === void 0 ) force = {}; - - var pristine = force.pristine || this.pristine; - var delayed = - element.config.useDelay === 'always' || - (element.config.useDelay === 'onload' && pristine) || - (element.config.useDelay === 'once' && !element.seen); - - var shouldReveal = element.visible && !element.revealed; - var shouldReset = !element.visible && element.revealed && element.config.reset; - - if (force.reveal || shouldReveal) { - return triggerReveal.call(this, element, delayed) - } - - if (force.reset || shouldReset) { - return triggerReset.call(this, element) - } - } - - function triggerReveal(element, delayed) { - var styles = [ - element.styles.inline.generated, - element.styles.opacity.computed, - element.styles.transform.generated.final - ]; - if (delayed) { - styles.push(element.styles.transition.generated.delayed); - } else { - styles.push(element.styles.transition.generated.instant); - } - element.revealed = element.seen = true; - applyStyle(element.node, styles.filter(function (s) { return s !== ''; }).join(' ')); - registerCallbacks.call(this, element, delayed); - } - - function triggerReset(element) { - var styles = [ - element.styles.inline.generated, - element.styles.opacity.generated, - element.styles.transform.generated.initial, - element.styles.transition.generated.instant - ]; - element.revealed = false; - applyStyle(element.node, styles.filter(function (s) { return s !== ''; }).join(' ')); - registerCallbacks.call(this, element); - } - - function registerCallbacks(element, isDelayed) { - var this$1 = this; - - var duration = isDelayed - ? element.config.duration + element.config.delay - : element.config.duration; - - var beforeCallback = element.revealed - ? element.config.beforeReveal - : element.config.beforeReset; - - var afterCallback = element.revealed - ? element.config.afterReveal - : element.config.afterReset; - - var elapsed = 0; - if (element.callbackTimer) { - elapsed = Date.now() - element.callbackTimer.start; - window.clearTimeout(element.callbackTimer.clock); - } - - beforeCallback(element.node); - - element.callbackTimer = { - start: Date.now(), - clock: window.setTimeout(function () { - afterCallback(element.node); - element.callbackTimer = null; - if (element.revealed && !element.config.reset && element.config.cleanup) { - clean.call(this$1, element.node); - } - }, duration - elapsed) - }; - } - - function sequence(element, pristine) { - if ( pristine === void 0 ) pristine = this.pristine; - - /** - * We first check if the element should reset. - */ - if (!element.visible && element.revealed && element.config.reset) { - return animate.call(this, element, { reset: true }) - } - - var seq = this.store.sequences[element.sequence.id]; - var i = element.sequence.index; - - if (seq) { - var visible = new SequenceModel(seq, 'visible', this.store); - var revealed = new SequenceModel(seq, 'revealed', this.store); - - seq.models = { visible: visible, revealed: revealed }; - - /** - * If the sequence has no revealed members, - * then we reveal the first visible element - * within that sequence. - * - * The sequence then cues a recursive call - * in both directions. - */ - if (!revealed.body.length) { - var nextId = seq.members[visible.body[0]]; - var nextElement = this.store.elements[nextId]; - - if (nextElement) { - cue.call(this, seq, visible.body[0], -1, pristine); - cue.call(this, seq, visible.body[0], +1, pristine); - return animate.call(this, nextElement, { reveal: true, pristine: pristine }) - } - } - - /** - * If our element isn’t resetting, we check the - * element sequence index against the head, and - * then the foot of the sequence. - */ - if ( - !seq.blocked.head && - i === [].concat( revealed.head ).pop() && - i >= [].concat( visible.body ).shift() - ) { - cue.call(this, seq, i, -1, pristine); - return animate.call(this, element, { reveal: true, pristine: pristine }) - } - - if ( - !seq.blocked.foot && - i === [].concat( revealed.foot ).shift() && - i <= [].concat( visible.body ).pop() - ) { - cue.call(this, seq, i, +1, pristine); - return animate.call(this, element, { reveal: true, pristine: pristine }) - } - } - } - - function Sequence(interval) { - var i = Math.abs(interval); - if (!isNaN(i)) { - this.id = nextUniqueId(); - this.interval = Math.max(i, 16); - this.members = []; - this.models = {}; - this.blocked = { - head: false, - foot: false - }; - } else { - throw new RangeError('Invalid sequence interval.') - } - } - - function SequenceModel(seq, prop, store) { - var this$1 = this; - - this.head = []; - this.body = []; - this.foot = []; - - each(seq.members, function (id, index) { - var element = store.elements[id]; - if (element && element[prop]) { - this$1.body.push(index); - } - }); - - if (this.body.length) { - each(seq.members, function (id, index) { - var element = store.elements[id]; - if (element && !element[prop]) { - if (index < this$1.body[0]) { - this$1.head.push(index); - } else { - this$1.foot.push(index); - } - } - }); - } - } - - function cue(seq, i, direction, pristine) { - var this$1 = this; - - var blocked = ['head', null, 'foot'][1 + direction]; - var nextId = seq.members[i + direction]; - var nextElement = this.store.elements[nextId]; - - seq.blocked[blocked] = true; - - setTimeout(function () { - seq.blocked[blocked] = false; - if (nextElement) { - sequence.call(this$1, nextElement, pristine); - } - }, seq.interval); - } - - function reveal(target, options, syncing) { - var this$1 = this; - if ( options === void 0 ) options = {}; - if ( syncing === void 0 ) syncing = false; - - var containerBuffer = []; - var sequence$$1; - var interval = options.interval || defaults.interval; - - try { - if (interval) { - sequence$$1 = new Sequence(interval); - } - - var nodes = tealight(target); - if (!nodes.length) { - throw new Error('Invalid reveal target.') - } - - var elements = nodes.reduce(function (elementBuffer, elementNode) { - var element = {}; - var existingId = elementNode.getAttribute('data-sr-id'); - - if (existingId) { - deepAssign(element, this$1.store.elements[existingId]); - - /** - * In order to prevent previously generated styles - * from throwing off the new styles, the style tag - * has to be reverted to its pre-reveal state. - */ - applyStyle(element.node, element.styles.inline.computed); - } else { - element.id = nextUniqueId(); - element.node = elementNode; - element.seen = false; - element.revealed = false; - element.visible = false; - } - - var config = deepAssign({}, element.config || this$1.defaults, options); - - if ((!config.mobile && isMobile()) || (!config.desktop && !isMobile())) { - if (existingId) { - clean.call(this$1, element); - } - return elementBuffer // skip elements that are disabled - } - - var containerNode = tealight(config.container)[0]; - if (!containerNode) { - throw new Error('Invalid container.') - } - if (!containerNode.contains(elementNode)) { - return elementBuffer // skip elements found outside the container - } - - var containerId; - { - containerId = getContainerId( - containerNode, - containerBuffer, - this$1.store.containers - ); - if (containerId === null) { - containerId = nextUniqueId(); - containerBuffer.push({ id: containerId, node: containerNode }); - } - } - - element.config = config; - element.containerId = containerId; - element.styles = style(element); - - if (sequence$$1) { - element.sequence = { - id: sequence$$1.id, - index: sequence$$1.members.length - }; - sequence$$1.members.push(element.id); - } - - elementBuffer.push(element); - return elementBuffer - }, []); - - /** - * Modifying the DOM via setAttribute needs to be handled - * separately from reading computed styles in the map above - * for the browser to batch DOM changes (limiting reflows) - */ - each(elements, function (element) { - this$1.store.elements[element.id] = element; - element.node.setAttribute('data-sr-id', element.id); - }); - } catch (e) { - return logger.call(this, 'Reveal failed.', e.message) - } - - /** - * Now that element set-up is complete... - * Let’s commit any container and sequence data we have to the store. - */ - each(containerBuffer, function (container) { - this$1.store.containers[container.id] = { - id: container.id, - node: container.node - }; - }); - if (sequence$$1) { - this.store.sequences[sequence$$1.id] = sequence$$1; - } - - /** - * If reveal wasn't invoked by sync, we want to - * make sure to add this call to the history. - */ - if (syncing !== true) { - this.store.history.push({ target: target, options: options }); - - /** - * Push initialization to the event queue, giving - * multiple reveal calls time to be interpreted. - */ - if (this.initTimeout) { - window.clearTimeout(this.initTimeout); - } - this.initTimeout = window.setTimeout(initialize.bind(this), 0); - } - } - - function getContainerId(node) { - var collections = [], len = arguments.length - 1; - while ( len-- > 0 ) collections[ len ] = arguments[ len + 1 ]; - - var id = null; - each(collections, function (collection) { - each(collection, function (container) { - if (id === null && container.node === node) { - id = container.id; - } - }); - }); - return id - } - - /** - * Re-runs the reveal method for each record stored in history, - * for capturing new content asynchronously loaded into the DOM. - */ - function sync() { - var this$1 = this; - - each(this.store.history, function (record) { - reveal.call(this$1, record.target, record.options, true); - }); - - initialize.call(this); - } - - var polyfill = function (x) { return (x > 0) - (x < 0) || +x; }; - var mathSign = Math.sign || polyfill; - - /*! @license miniraf v1.0.1 - - Copyright 2018 Fisssion LLC. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - */ - var polyfill$1 = (function () { - var clock = Date.now(); - - return function (callback) { - var currentTime = Date.now(); - if (currentTime - clock > 16) { - clock = currentTime; - callback(currentTime); - } else { - setTimeout(function () { return polyfill$1(callback); }, 0); - } - } - })(); - - var miniraf = window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - polyfill$1; - - function getGeometry(target, isContainer) { - /** - * We want to ignore padding and scrollbars for container elements. - * More information here: https://goo.gl/vOZpbz - */ - var height = isContainer ? target.node.clientHeight : target.node.offsetHeight; - var width = isContainer ? target.node.clientWidth : target.node.offsetWidth; - - var offsetTop = 0; - var offsetLeft = 0; - var node = target.node; - - do { - if (!isNaN(node.offsetTop)) { - offsetTop += node.offsetTop; - } - if (!isNaN(node.offsetLeft)) { - offsetLeft += node.offsetLeft; - } - node = node.offsetParent; - } while (node) - - return { - bounds: { - top: offsetTop, - right: offsetLeft + width, - bottom: offsetTop + height, - left: offsetLeft - }, - height: height, - width: width - } - } - - function getScrolled(container) { - var top, left; - if (container.node === document.documentElement) { - top = window.pageYOffset; - left = window.pageXOffset; - } else { - top = container.node.scrollTop; - left = container.node.scrollLeft; - } - return { top: top, left: left } - } - - function isElementVisible(element) { - if ( element === void 0 ) element = {}; - - var container = this.store.containers[element.containerId]; - if (!container) { return } - - var viewFactor = Math.max(0, Math.min(1, element.config.viewFactor)); - var viewOffset = element.config.viewOffset; - - var elementBounds = { - top: element.geometry.bounds.top + element.geometry.height * viewFactor, - right: element.geometry.bounds.right - element.geometry.width * viewFactor, - bottom: element.geometry.bounds.bottom - element.geometry.height * viewFactor, - left: element.geometry.bounds.left + element.geometry.width * viewFactor - }; - - var containerBounds = { - top: container.geometry.bounds.top + container.scroll.top + viewOffset.top, - right: container.geometry.bounds.right + container.scroll.left - viewOffset.right, - bottom: - container.geometry.bounds.bottom + container.scroll.top - viewOffset.bottom, - left: container.geometry.bounds.left + container.scroll.left + viewOffset.left - }; - - return ( - (elementBounds.top < containerBounds.bottom && - elementBounds.right > containerBounds.left && - elementBounds.bottom > containerBounds.top && - elementBounds.left < containerBounds.right) || - element.styles.position === 'fixed' - ) - } - - function delegate( - event, - elements - ) { - var this$1 = this; - if ( event === void 0 ) event = { type: 'init' }; - if ( elements === void 0 ) elements = this.store.elements; - - miniraf(function () { - var stale = event.type === 'init' || event.type === 'resize'; - - each(this$1.store.containers, function (container) { - if (stale) { - container.geometry = getGeometry.call(this$1, container, true); - } - var scroll = getScrolled.call(this$1, container); - if (container.scroll) { - container.direction = { - x: mathSign(scroll.left - container.scroll.left), - y: mathSign(scroll.top - container.scroll.top) - }; - } - container.scroll = scroll; - }); - - /** - * Due to how the sequencer is implemented, it’s - * important that we update the state of all - * elements, before any animation logic is - * evaluated (in the second loop below). - */ - each(elements, function (element) { - if (stale || element.geometry === undefined) { - element.geometry = getGeometry.call(this$1, element); - } - element.visible = isElementVisible.call(this$1, element); - }); - - each(elements, function (element) { - if (element.sequence) { - sequence.call(this$1, element); - } else { - animate.call(this$1, element); - } - }); - - this$1.pristine = false; - }); - } - - function isTransformSupported() { - var style = document.documentElement.style; - return 'transform' in style || 'WebkitTransform' in style - } - - function isTransitionSupported() { - var style = document.documentElement.style; - return 'transition' in style || 'WebkitTransition' in style - } - - var version = "4.0.9"; - - var boundDelegate; - var boundDestroy; - var boundReveal; - var boundClean; - var boundSync; - var config; - var debug; - var instance; - - function ScrollReveal(options) { - if ( options === void 0 ) options = {}; - - var invokedWithoutNew = - typeof this === 'undefined' || - Object.getPrototypeOf(this) !== ScrollReveal.prototype; - - if (invokedWithoutNew) { - return new ScrollReveal(options) - } - - if (!ScrollReveal.isSupported()) { - logger.call(this, 'Instantiation failed.', 'This browser is not supported.'); - return mount.failure() - } - - var buffer; - try { - buffer = config - ? deepAssign({}, config, options) - : deepAssign({}, defaults, options); - } catch (e) { - logger.call(this, 'Invalid configuration.', e.message); - return mount.failure() - } - - try { - var container = tealight(buffer.container)[0]; - if (!container) { - throw new Error('Invalid container.') - } - } catch (e) { - logger.call(this, e.message); - return mount.failure() - } - - config = buffer; - - if ((!config.mobile && isMobile()) || (!config.desktop && !isMobile())) { - logger.call( - this, - 'This device is disabled.', - ("desktop: " + (config.desktop)), - ("mobile: " + (config.mobile)) - ); - return mount.failure() - } - - mount.success(); - - this.store = { - containers: {}, - elements: {}, - history: [], - sequences: {} - }; - - this.pristine = true; - - boundDelegate = boundDelegate || delegate.bind(this); - boundDestroy = boundDestroy || destroy.bind(this); - boundReveal = boundReveal || reveal.bind(this); - boundClean = boundClean || clean.bind(this); - boundSync = boundSync || sync.bind(this); - - Object.defineProperty(this, 'delegate', { get: function () { return boundDelegate; } }); - Object.defineProperty(this, 'destroy', { get: function () { return boundDestroy; } }); - Object.defineProperty(this, 'reveal', { get: function () { return boundReveal; } }); - Object.defineProperty(this, 'clean', { get: function () { return boundClean; } }); - Object.defineProperty(this, 'sync', { get: function () { return boundSync; } }); - - Object.defineProperty(this, 'defaults', { get: function () { return config; } }); - Object.defineProperty(this, 'version', { get: function () { return version; } }); - Object.defineProperty(this, 'noop', { get: function () { return false; } }); - - return instance ? instance : (instance = this) - } - - ScrollReveal.isSupported = function () { return isTransformSupported() && isTransitionSupported(); }; - - Object.defineProperty(ScrollReveal, 'debug', { - get: function () { return debug || false; }, - set: function (value) { return (debug = typeof value === 'boolean' ? value : debug); } - }); - - ScrollReveal(); - - return ScrollReveal; - -})); diff --git a/dist/scrollreveal.min.js b/dist/scrollreveal.min.js deleted file mode 100644 index 5428bbd7..00000000 --- a/dist/scrollreveal.min.js +++ /dev/null @@ -1,12 +0,0 @@ -/*! @license ScrollReveal v4.0.9 - - Copyright 2021 Fisssion LLC. - - Licensed under the GNU General Public License 3.0 for - compatible open source projects and non-commercial use. - - For commercial sites, themes, projects, and applications, - keep your source code private/proprietary by purchasing - a commercial license from https://scrollrevealjs.org/ -*/ -var ScrollReveal=function(){"use strict";var r={delay:0,distance:"0",duration:600,easing:"cubic-bezier(0.5, 0, 0, 1)",interval:0,opacity:0,origin:"bottom",rotate:{x:0,y:0,z:0},scale:1,cleanup:!1,container:document.documentElement,desktop:!0,mobile:!0,reset:!1,useDelay:"always",viewFactor:0,viewOffset:{top:0,right:0,bottom:0,left:0},afterReset:function(){},afterReveal:function(){},beforeReset:function(){},beforeReveal:function(){}};var n={success:function(){document.documentElement.classList.add("sr"),document.body?document.body.style.height="100%":document.addEventListener("DOMContentLoaded",function(){document.body.style.height="100%"})},failure:function(){return document.documentElement.classList.remove("sr"),{clean:function(){},destroy:function(){},reveal:function(){},sync:function(){},get noop(){return!0}}}};function o(e){return"object"==typeof window.Node?e instanceof window.Node:null!==e&&"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName}function u(e,t){if(void 0===t&&(t=document),e instanceof Array)return e.filter(o);if(o(e))return[e];if(n=e,i=Object.prototype.toString.call(n),"object"==typeof window.NodeList?n instanceof window.NodeList:null!==n&&"object"==typeof n&&"number"==typeof n.length&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(i)&&(0===n.length||o(n[0])))return Array.prototype.slice.call(e);var n,i;if("string"==typeof e)try{var r=t.querySelectorAll(e);return Array.prototype.slice.call(r)}catch(e){return[]}return[]}function s(e){return null!==e&&e instanceof Object&&(e.constructor===Object||"[object Object]"===Object.prototype.toString.call(e))}function f(n,i){if(s(n))return Object.keys(n).forEach(function(e){return i(n[e],e,n)});if(n instanceof Array)return n.forEach(function(e,t){return i(e,t,n)});throw new TypeError("Expected either an array or object literal.")}function h(e){for(var t=[],n=arguments.length-1;0=[].concat(r.body).shift())return j.call(this,n,i,-1,t),c.call(this,e,{reveal:!0,pristine:t});if(!n.blocked.foot&&i===[].concat(o.foot).shift()&&i<=[].concat(r.body).pop())return j.call(this,n,i,1,t),c.call(this,e,{reveal:!0,pristine:t})}}function E(e){var t=Math.abs(e);if(isNaN(t))throw new RangeError("Invalid sequence interval.");this.id=b(),this.interval=Math.max(t,16),this.members=[],this.models={},this.blocked={head:!1,foot:!1}}function d(e,i,r){var o=this;this.head=[],this.body=[],this.foot=[],f(e.members,function(e,t){var n=r.elements[e];n&&n[i]&&o.body.push(t)}),this.body.length&&f(e.members,function(e,t){var n=r.elements[e];n&&!n[i]&&(t + + + scrollReveal.js + + + + + + + + + + + + + + + + + + Fork me on GitHub + + +

scrollReveal.js

+

Declarative on-scroll reveal animations.

+

An open-source project by @JulianLloyd

+ +
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ +
+ +
+ Made with + + + + + + + + in California +
+ + + + + + \ No newline at end of file diff --git a/js/scrollReveal.js b/js/scrollReveal.js new file mode 100644 index 00000000..10286531 --- /dev/null +++ b/js/scrollReveal.js @@ -0,0 +1,304 @@ +/* + _ _ _____ _ _ + | | | __ \ | | (_) + ___ ___ _ __ ___ | | | |__) |_____ _____ __ _| | _ ___ + / __|/ __| '__/ _ \| | | _ // _ \ \ / / _ \/ _` | | | / __| + \__ \ (__| | | (_) | | | | \ \ __/\ V / __/ (_| | |_| \__ \ + |___/\___|_| \___/|_|_|_| \_\___| \_/ \___|\__,_|_(_) |___/ + _/ | + |__/ + + "Declarative on-scroll reveal animations." + +/*============================================================================= + + scrollReveal.js is inspired by cbpScroller.js, © 2014, Codrops. + + Licensed under the MIT license. + http://www.opensource.org/licenses/mit-license.php + + scrollReveal.js, © 2014 https://twitter.com/julianlloyd + +=============================================================================*/ + +;(function (window) { + + 'use strict'; + + var docElem = window.document.documentElement; + + function getViewportH () { + var client = docElem['clientHeight'], + inner = window['innerHeight']; + + return (client < inner) ? inner : client; + } + + function getOffset (el) { + var offsetTop = 0, + offsetLeft = 0; + + do { + if (!isNaN(el.offsetTop)) { + offsetTop += el.offsetTop; + } + if (!isNaN(el.offsetLeft)) { + offsetLeft += el.offsetLeft; + } + } while (el = el.offsetParent) + + return { + top: offsetTop, + left: offsetLeft + } + } + + function isElementInViewport (el, h) { + var scrolled = window.pageYOffset, + viewed = scrolled + getViewportH(), + elH = el.offsetHeight, + elTop = getOffset(el).top, + elBottom = elTop + elH, + h = h || 0; + + return (elTop + elH * h) <= viewed && (elBottom) >= scrolled; + } + + function extend (a, b) { + for (var key in b) { + if (b.hasOwnProperty(key)) { + a[key] = b[key]; + } + } + return a; + } + + + function scrollReveal(options) { + this.options = extend(this.defaults, options); + this._init(); + } + + + + scrollReveal.prototype = { + defaults: { + axis: 'y', + distance: '25px', + duration: '0.66s', + delay: '0s', + + // if 0, the element is considered in the viewport as soon as it enters + // if 1, the element is considered in the viewport when it's fully visible + viewportFactor: 0.33 + }, + + /*=============================================================================*/ + + _init: function () { + + var self = this; + + this.elems = Array.prototype.slice.call(docElem.querySelectorAll('[data-scrollReveal]')); + this.scrolled = false; + + // Initialize all scrollreveals, triggering all + // reveals on visible elements. + this.elems.forEach(function (el, i) { + self.animate(el); + }); + + var scrollHandler = function () { + if (!self.scrolled) { + self.scrolled = true; + setTimeout(function () { + self._scrollPage(); + }, 60); + } + }; + + var resizeHandler = function () { + function delayed() { + self._scrollPage(); + self.resizeTimeout = null; + } + if (self.resizeTimeout) { + clearTimeout(self.resizeTimeout); + } + self.resizeTimeout = setTimeout(delayed, 200); + }; + + window.addEventListener('scroll', scrollHandler, false); + window.addEventListener('resize', resizeHandler, false); + }, + + /*=============================================================================*/ + + _scrollPage: function () { + var self = this; + + this.elems.forEach(function (el, i) { + if (isElementInViewport(el, self.options.viewportFactor)) { + self.animate(el); + } + }); + this.scrolled = false; + }, + + /*=============================================================================*/ + + parseLanguage: function (el) { + + // Splits on a sequence of one or more commas or spaces. + var words = el.getAttribute('data-scrollreveal').split(/[, ]+/), + enterFrom, + parsed = {}; + + function filter (words) { + var ret = [], + + blacklist = [ + "from", + "the", + "and", + "then", + "but" + ]; + + words.forEach(function (word, i) { + if (blacklist.indexOf(word) > -1) { + return; + } + ret.push(word); + }); + + return ret; + } + + words = filter(words); + + words.forEach(function (word, i) { + + switch (word) { + case "enter": + enterFrom = words[i + 1]; + + if (enterFrom == "top" || enterFrom == "bottom") { + parsed.axis = "y"; + } + + if (enterFrom == "left" || enterFrom == "right") { + parsed.axis = "x"; + } + + return; + + case "after": + parsed.delay = words[i + 1]; + return; + + case "wait": + parsed.delay = words[i + 1]; + return; + + case "move": + parsed.distance = words[i + 1]; + return; + + case "over": + parsed.duration = words[i + 1]; + return; + + case "trigger": + parsed.eventName = words[i + 1]; + return; + + default: + // Unrecognizable words; do nothing. + return; + } + }); + + // After all values are parsed, let’s make sure our our + // pixel distance is negative for top and left entrances. + // + // ie. "move 25px from top" starts at 'top: -25px' in CSS. + + if (enterFrom == "top" || enterFrom == "left") { + + if (!typeof parsed.distance == "undefined") { + parsed.distance = "-" + parsed.distance; + } + + else { + parsed.distance = "-" + this.options.distance; + } + + } + + return parsed; + }, + + /*=============================================================================*/ + + genCSS: function (el) { + var parsed = this.parseLanguage(el); + + var dist = parsed.distance || this.options.distance, + dur = parsed.duration || this.options.duration, + delay = parsed.delay || this.options.delay, + axis = parsed.axis || this.options.axis; + + var transition = "-webkit-transition: all " + dur + " ease " + delay + ";" + + "-moz-transition: all " + dur + " ease " + delay + ";" + + "-o-transition: all " + dur + " ease " + delay + ";" + + "transition: all " + dur + " ease " + delay + ";"; + + var initial = "-webkit-transform: translate" + axis + "(" + dist + ");" + + "-moz-transform: translate" + axis + "(" + dist + ");" + + "transform: translate" + axis + "(" + dist + ");" + + "opacity: 0;"; + + var target = "-webkit-transform: translate" + axis + "(0);" + + "-moz-transform: translate" + axis + "(0);" + + "transform: translate" + axis + "(0);" + + "opacity: 1;"; + return { + transition: transition, + initial: initial, + target: target, + totalDuration: ((parseFloat(dur) + parseFloat(delay)) * 1000) + }; + }, + + /*=============================================================================*/ + + animate: function (el) { + var css = this.genCSS(el); + + if (!el.getAttribute('data-sr-init')) { + el.setAttribute('style', css.initial); + el.setAttribute('data-sr-init', true); + } + + if (el.getAttribute('data-sr-complete')) { + return; + } + + if (isElementInViewport(el, this.options.viewportFactor)) { + el.setAttribute('style', css.target + css.transition); + + setTimeout(function () { + el.removeAttribute('style'); + el.setAttribute('data-sr-complete', true); + }, css.totalDuration); + } + + } + }; // end scrollReveal.prototype + + document.addEventListener("DOMContentLoaded", function (evt) { + window.scrollReveal = new scrollReveal(); + }); + +})(window); \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index 84d29ff9..00000000 --- a/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "scrollreveal", - "version": "4.0.9", - "description": "Animate elements as they scroll into view", - "homepage": "https://scrollrevealjs.org/", - "main": "dist/scrollreveal.js", - "module": "dist/scrollreveal.es.js", - "jsnext:main": "dist/scrollreveal.es.js", - "files": [ - "dist" - ], - "scripts": { - "prebuild": "rm -rf dist/*", - "build": "npm run bundle && npm run bundle:min", - "bundle": "./node_modules/rollup/bin/rollup -c ./build/rollup.conf.js", - "bundle:min": "./node_modules/rollup/bin/rollup -c ./build/rollup.conf.min.js", - "lint": "./node_modules/eslint/bin/eslint.js src test", - "pretest": "rm -rf .ignore/coverage/**/ && npm run lint", - "test": "./node_modules/karma/bin/karma start ./test/karma.conf.js", - "testing": "cross-env COVERAGE=true npm test -- --no-single-run", - "coverage": "cross-env COVERAGE=true npm test", - "sandbox:bundle": "./node_modules/rollup/bin/rollup -w -c ./.ignore/sandbox/rollup.conf.sandbox.js", - "sandbox:server": "node ./.ignore/sandbox/server.sandbox.js", - "coverage:server": "node ./.ignore/coverage/server.coverage.js", - "postinstall": "node -e \"console.log('\\u001b[35m\\u001b[1mLove ScrollReveal? 🔑 Buy a license!\\u001b[22m\\u001b[35m\\n >> \\u001b[33mhttps://scrollrevealjs.org/pricing/\\u001b[0m\\n')\"" - }, - "keywords": [ - "scroll", - "animation", - "reveal", - "css", - "transform", - "transition" - ], - "repository": { - "type": "git", - "url": "https://github.com/jlmakes/scrollreveal.git" - }, - "bugs": { - "url": "https://github.com/jlmakes/scrollreveal/issues" - }, - "dependencies": { - "miniraf": "1.0.0", - "rematrix": "0.3.0", - "tealight": "0.3.6" - }, - "devDependencies": { - "chai": "^4.1.2", - "cross-env": "^5.1.3", - "eslint": "^4.16.0", - "karma": "^2.0.0", - "karma-chrome-launcher": "^2.0.0", - "karma-coverage": "^1.1.1", - "karma-coveralls": "^1.1.2", - "karma-mocha": "^1.3.0", - "karma-mocha-reporter": "^2.2.5", - "karma-rollup-preprocessor": "^5.1.1", - "karma-sauce-launcher": "^1.1.0", - "karma-sinon-chai": "^1.3.3", - "live-server": "jlmakes/live-server", - "mocha": "^4.0.1", - "rollup": "^0.55.0", - "rollup-plugin-buble": "^0.x", - "rollup-plugin-istanbul": "^1.1.0", - "rollup-plugin-json": "^2.1.0", - "rollup-plugin-node-resolve": "^3.0.0", - "rollup-plugin-strip": "^1.1.1", - "rollup-plugin-uglify": "^2.0.1", - "rollup-watch": "^4.3.1", - "sinon": "^4.2.0", - "sinon-chai": "^2.8.0" - }, - "author": "Julian Lloyd", - "license": "GPL-3.0" -} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 04c1b080..00000000 --- a/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import Constructor from './instance/constructor' - -Constructor() - -export default Constructor diff --git a/src/instance/constructor.js b/src/instance/constructor.js deleted file mode 100644 index 95ed60c4..00000000 --- a/src/instance/constructor.js +++ /dev/null @@ -1,112 +0,0 @@ -import defaults from './defaults' -import mount from './mount' - -import clean from './methods/clean' -import destroy from './methods/destroy' -import reveal from './methods/reveal' -import sync from './methods/sync' - -import delegate from './functions/delegate' - -import isMobile from '../utils/is-mobile' -import isTransformSupported from '../utils/is-transform-supported' -import isTransitionSupported from '../utils/is-transition-supported' - -import deepAssign from '../utils/deep-assign' -import logger from '../utils/logger' -import $ from 'tealight' - -import { version } from '../../package.json' - -let boundDelegate -let boundDestroy -let boundReveal -let boundClean -let boundSync -let config -let debug -let instance - -export default function ScrollReveal(options = {}) { - const invokedWithoutNew = - typeof this === 'undefined' || - Object.getPrototypeOf(this) !== ScrollReveal.prototype - - if (invokedWithoutNew) { - return new ScrollReveal(options) - } - - if (!ScrollReveal.isSupported()) { - logger.call(this, 'Instantiation failed.', 'This browser is not supported.') - return mount.failure() - } - - let buffer - try { - buffer = config - ? deepAssign({}, config, options) - : deepAssign({}, defaults, options) - } catch (e) { - logger.call(this, 'Invalid configuration.', e.message) - return mount.failure() - } - - try { - const container = $(buffer.container)[0] - if (!container) { - throw new Error('Invalid container.') - } - } catch (e) { - logger.call(this, e.message) - return mount.failure() - } - - config = buffer - - if ((!config.mobile && isMobile()) || (!config.desktop && !isMobile())) { - logger.call( - this, - 'This device is disabled.', - `desktop: ${config.desktop}`, - `mobile: ${config.mobile}` - ) - return mount.failure() - } - - mount.success() - - this.store = { - containers: {}, - elements: {}, - history: [], - sequences: {} - } - - this.pristine = true - - boundDelegate = boundDelegate || delegate.bind(this) - boundDestroy = boundDestroy || destroy.bind(this) - boundReveal = boundReveal || reveal.bind(this) - boundClean = boundClean || clean.bind(this) - boundSync = boundSync || sync.bind(this) - - Object.defineProperty(this, 'delegate', { get: () => boundDelegate }) - Object.defineProperty(this, 'destroy', { get: () => boundDestroy }) - Object.defineProperty(this, 'reveal', { get: () => boundReveal }) - Object.defineProperty(this, 'clean', { get: () => boundClean }) - Object.defineProperty(this, 'sync', { get: () => boundSync }) - - Object.defineProperty(this, 'defaults', { get: () => config }) - Object.defineProperty(this, 'version', { get: () => version }) - Object.defineProperty(this, 'noop', { get: () => false }) - - return instance ? instance : (instance = this) -} - -ScrollReveal.isSupported = () => - isTransformSupported() && isTransitionSupported() - -Object.defineProperty(ScrollReveal, 'debug', { - get: () => debug || false, - set: value => (debug = typeof value === 'boolean' ? value : debug) -}) diff --git a/src/instance/defaults.js b/src/instance/defaults.js deleted file mode 100644 index f792196a..00000000 --- a/src/instance/defaults.js +++ /dev/null @@ -1,32 +0,0 @@ -export default { - delay: 0, - distance: '0', - duration: 600, - easing: 'cubic-bezier(0.5, 0, 0, 1)', - interval: 0, - opacity: 0, - origin: 'bottom', - rotate: { - x: 0, - y: 0, - z: 0 - }, - scale: 1, - cleanup: false, - container: document.documentElement, - desktop: true, - mobile: true, - reset: false, - useDelay: 'always', - viewFactor: 0.0, - viewOffset: { - top: 0, - right: 0, - bottom: 0, - left: 0 - }, - afterReset() {}, - afterReveal() {}, - beforeReset() {}, - beforeReveal() {} -} diff --git a/src/instance/functions/animate.js b/src/instance/functions/animate.js deleted file mode 100644 index 9e5c1304..00000000 --- a/src/instance/functions/animate.js +++ /dev/null @@ -1,82 +0,0 @@ -import { applyStyle } from '../functions/style' -import clean from '../methods/clean' - -export default function animate(element, force = {}) { - const pristine = force.pristine || this.pristine - const delayed = - element.config.useDelay === 'always' || - (element.config.useDelay === 'onload' && pristine) || - (element.config.useDelay === 'once' && !element.seen) - - const shouldReveal = element.visible && !element.revealed - const shouldReset = !element.visible && element.revealed && element.config.reset - - if (force.reveal || shouldReveal) { - return triggerReveal.call(this, element, delayed) - } - - if (force.reset || shouldReset) { - return triggerReset.call(this, element) - } -} - -function triggerReveal(element, delayed) { - const styles = [ - element.styles.inline.generated, - element.styles.opacity.computed, - element.styles.transform.generated.final - ] - if (delayed) { - styles.push(element.styles.transition.generated.delayed) - } else { - styles.push(element.styles.transition.generated.instant) - } - element.revealed = element.seen = true - applyStyle(element.node, styles.filter((s) => s !== '').join(' ')) - registerCallbacks.call(this, element, delayed) -} - -function triggerReset(element) { - const styles = [ - element.styles.inline.generated, - element.styles.opacity.generated, - element.styles.transform.generated.initial, - element.styles.transition.generated.instant - ] - element.revealed = false - applyStyle(element.node, styles.filter((s) => s !== '').join(' ')) - registerCallbacks.call(this, element) -} - -function registerCallbacks(element, isDelayed) { - const duration = isDelayed - ? element.config.duration + element.config.delay - : element.config.duration - - const beforeCallback = element.revealed - ? element.config.beforeReveal - : element.config.beforeReset - - const afterCallback = element.revealed - ? element.config.afterReveal - : element.config.afterReset - - let elapsed = 0 - if (element.callbackTimer) { - elapsed = Date.now() - element.callbackTimer.start - window.clearTimeout(element.callbackTimer.clock) - } - - beforeCallback(element.node) - - element.callbackTimer = { - start: Date.now(), - clock: window.setTimeout(() => { - afterCallback(element.node) - element.callbackTimer = null - if (element.revealed && !element.config.reset && element.config.cleanup) { - clean.call(this, element.node) - } - }, duration - elapsed) - } -} diff --git a/src/instance/functions/delegate.js b/src/instance/functions/delegate.js deleted file mode 100644 index ea14bfc3..00000000 --- a/src/instance/functions/delegate.js +++ /dev/null @@ -1,54 +0,0 @@ -import animate from './animate' -import sequence from './sequence' -import mathSign from '../../polyfills/math-sign' -import raf from 'miniraf' -import each from '../../utils/each' -import getGeometry from '../../utils/get-geometry' -import getScrolled from '../../utils/get-scrolled' -import isElementVisible from '../../utils/is-element-visible' - -export default function delegate( - event = { type: 'init' }, - elements = this.store.elements -) { - raf(() => { - const stale = event.type === 'init' || event.type === 'resize' - - each(this.store.containers, container => { - if (stale) { - container.geometry = getGeometry.call(this, container, true) - } - const scroll = getScrolled.call(this, container) - if (container.scroll) { - container.direction = { - x: mathSign(scroll.left - container.scroll.left), - y: mathSign(scroll.top - container.scroll.top) - } - } - container.scroll = scroll - }) - - /** - * Due to how the sequencer is implemented, it’s - * important that we update the state of all - * elements, before any animation logic is - * evaluated (in the second loop below). - */ - each(elements, element => { - if (stale || element.geometry === undefined) { - element.geometry = getGeometry.call(this, element) - } - element.visible = isElementVisible.call(this, element) - }) - - each(elements, element => { - if (element.sequence) { - sequence.call(this, element) - } else { - animate.call(this, element) - } - }) - - this.pristine = false - }) -} diff --git a/src/instance/functions/initialize.js b/src/instance/functions/initialize.js deleted file mode 100644 index fe4fc63c..00000000 --- a/src/instance/functions/initialize.js +++ /dev/null @@ -1,43 +0,0 @@ -import each from '../../utils/each' -import { applyStyle } from '../functions/style' -import rinse from './rinse' - -export default function initialize() { - rinse.call(this) - - each(this.store.elements, element => { - let styles = [element.styles.inline.generated] - - if (element.visible) { - styles.push(element.styles.opacity.computed) - styles.push(element.styles.transform.generated.final) - element.revealed = true - } else { - styles.push(element.styles.opacity.generated) - styles.push(element.styles.transform.generated.initial) - element.revealed = false - } - - applyStyle(element.node, styles.filter((s) => s !== '').join(' ')) - }) - - each(this.store.containers, container => { - const target = - container.node === document.documentElement ? window : container.node - target.addEventListener('scroll', this.delegate) - target.addEventListener('resize', this.delegate) - }) - - /** - * Manually invoke delegate once to capture - * element and container dimensions, container - * scroll position, and trigger any valid reveals - */ - this.delegate() - - /** - * Wipe any existing `setTimeout` now - * that initialization has completed. - */ - this.initTimeout = null -} diff --git a/src/instance/functions/rinse.js b/src/instance/functions/rinse.js deleted file mode 100644 index 3cc55358..00000000 --- a/src/instance/functions/rinse.js +++ /dev/null @@ -1,76 +0,0 @@ -import $ from 'tealight' -import each from '../../utils/each' - -export default function rinse() { - const struct = () => ({ - active: [], - stale: [] - }) - - const elementIds = struct() - const sequenceIds = struct() - const containerIds = struct() - - /** - * Take stock of active element IDs. - */ - try { - each($('[data-sr-id]'), node => { - const id = parseInt(node.getAttribute('data-sr-id')) - elementIds.active.push(id) - }) - } catch (e) { - throw e - } - /** - * Destroy stale elements. - */ - each(this.store.elements, element => { - if (elementIds.active.indexOf(element.id) === -1) { - elementIds.stale.push(element.id) - } - }) - - each(elementIds.stale, staleId => delete this.store.elements[staleId]) - - /** - * Take stock of active container and sequence IDs. - */ - each(this.store.elements, element => { - if (containerIds.active.indexOf(element.containerId) === -1) { - containerIds.active.push(element.containerId) - } - if (element.hasOwnProperty('sequence')) { - if (sequenceIds.active.indexOf(element.sequence.id) === -1) { - sequenceIds.active.push(element.sequence.id) - } - } - }) - - /** - * Destroy stale containers. - */ - each(this.store.containers, container => { - if (containerIds.active.indexOf(container.id) === -1) { - containerIds.stale.push(container.id) - } - }) - - each(containerIds.stale, staleId => { - const stale = this.store.containers[staleId].node - stale.removeEventListener('scroll', this.delegate) - stale.removeEventListener('resize', this.delegate) - delete this.store.containers[staleId] - }) - - /** - * Destroy stale sequences. - */ - each(this.store.sequences, sequence => { - if (sequenceIds.active.indexOf(sequence.id) === -1) { - sequenceIds.stale.push(sequence.id) - } - }) - - each(sequenceIds.stale, staleId => delete this.store.sequences[staleId]) -} diff --git a/src/instance/functions/sequence.js b/src/instance/functions/sequence.js deleted file mode 100644 index 9cd11c6e..00000000 --- a/src/instance/functions/sequence.js +++ /dev/null @@ -1,121 +0,0 @@ -import animate from './animate' -import each from '../../utils/each' -import nextUniqueId from '../../utils/next-unique-id' - -export default function sequence(element, pristine = this.pristine) { - /** - * We first check if the element should reset. - */ - if (!element.visible && element.revealed && element.config.reset) { - return animate.call(this, element, { reset: true }) - } - - const seq = this.store.sequences[element.sequence.id] - const i = element.sequence.index - - if (seq) { - const visible = new SequenceModel(seq, 'visible', this.store) - const revealed = new SequenceModel(seq, 'revealed', this.store) - - seq.models = { visible, revealed } - - /** - * If the sequence has no revealed members, - * then we reveal the first visible element - * within that sequence. - * - * The sequence then cues a recursive call - * in both directions. - */ - if (!revealed.body.length) { - const nextId = seq.members[visible.body[0]] - const nextElement = this.store.elements[nextId] - - if (nextElement) { - cue.call(this, seq, visible.body[0], -1, pristine) - cue.call(this, seq, visible.body[0], +1, pristine) - return animate.call(this, nextElement, { reveal: true, pristine }) - } - } - - /** - * If our element isn’t resetting, we check the - * element sequence index against the head, and - * then the foot of the sequence. - */ - if ( - !seq.blocked.head && - i === [...revealed.head].pop() && - i >= [...visible.body].shift() - ) { - cue.call(this, seq, i, -1, pristine) - return animate.call(this, element, { reveal: true, pristine }) - } - - if ( - !seq.blocked.foot && - i === [...revealed.foot].shift() && - i <= [...visible.body].pop() - ) { - cue.call(this, seq, i, +1, pristine) - return animate.call(this, element, { reveal: true, pristine }) - } - } -} - -export function Sequence(interval) { - const i = Math.abs(interval) - if (!isNaN(i)) { - this.id = nextUniqueId() - this.interval = Math.max(i, 16) - this.members = [] - this.models = {} - this.blocked = { - head: false, - foot: false - } - } else { - throw new RangeError('Invalid sequence interval.') - } -} - -function SequenceModel(seq, prop, store) { - this.head = [] - this.body = [] - this.foot = [] - - each(seq.members, (id, index) => { - const element = store.elements[id] - if (element && element[prop]) { - this.body.push(index) - } - }) - - if (this.body.length) { - each(seq.members, (id, index) => { - const element = store.elements[id] - if (element && !element[prop]) { - if (index < this.body[0]) { - this.head.push(index) - } else { - this.foot.push(index) - } - } - }) - } -} - -function cue(seq, i, direction, pristine) { - const blocked = ['head', null, 'foot'][1 + direction] - const nextId = seq.members[i + direction] - const nextElement = this.store.elements[nextId] - - seq.blocked[blocked] = true - - setTimeout(() => { - seq.blocked[blocked] = false - if (nextElement) { - sequence.call(this, nextElement, pristine) - } - }, seq.interval) -} diff --git a/src/instance/functions/style.js b/src/instance/functions/style.js deleted file mode 100644 index 0c48149a..00000000 --- a/src/instance/functions/style.js +++ /dev/null @@ -1,234 +0,0 @@ -import { - multiply, - parse, - rotateX, - rotateY, - rotateZ, - scale, - translateX, - translateY -} from 'rematrix' -import getPrefixedCssProp from '../../utils/get-prefixed-css-prop' - -export default function style(element) { - const computed = window.getComputedStyle(element.node) - const position = computed.position - const config = element.config - - /** - * Generate inline styles - */ - const inline = {} - const inlineStyle = element.node.getAttribute('style') || '' - const inlineMatch = inlineStyle.match(/[\w-]+\s*:\s*[^;]+\s*/gi) || [] - - inline.computed = inlineMatch ? inlineMatch.map(m => m.trim()).join('; ') + ';' : '' - - inline.generated = inlineMatch.some(m => m.match(/visibility\s?:\s?visible/i)) - ? inline.computed - : [...inlineMatch, 'visibility: visible'].map(m => m.trim()).join('; ') + ';' - - /** - * Generate opacity styles - */ - const computedOpacity = parseFloat(computed.opacity) - const configOpacity = !isNaN(parseFloat(config.opacity)) - ? parseFloat(config.opacity) - : parseFloat(computed.opacity) - - const opacity = { - computed: computedOpacity !== configOpacity ? `opacity: ${computedOpacity};` : '', - generated: computedOpacity !== configOpacity ? `opacity: ${configOpacity};` : '' - } - - /** - * Generate transformation styles - */ - const transformations = [] - - if (parseFloat(config.distance)) { - const axis = config.origin === 'top' || config.origin === 'bottom' ? 'Y' : 'X' - - /** - * Let’s make sure our our pixel distances are negative for top and left. - * e.g. { origin: 'top', distance: '25px' } starts at `top: -25px` in CSS. - */ - let distance = config.distance - if (config.origin === 'top' || config.origin === 'left') { - distance = /^-/.test(distance) ? distance.substr(1) : `-${distance}` - } - - const [value, unit] = distance.match(/(^-?\d+\.?\d?)|(em$|px$|%$)/g) - - switch (unit) { - case 'em': - distance = parseInt(computed.fontSize) * value - break - case 'px': - distance = value - break - case '%': - /** - * Here we use `getBoundingClientRect` instead of - * the existing data attached to `element.geometry` - * because only the former includes any transformations - * current applied to the element. - * - * If that behavior ends up being unintuitive, this - * logic could instead utilize `element.geometry.height` - * and `element.geoemetry.width` for the distance calculation - */ - distance = - axis === 'Y' - ? (element.node.getBoundingClientRect().height * value) / 100 - : (element.node.getBoundingClientRect().width * value) / 100 - break - default: - throw new RangeError('Unrecognized or missing distance unit.') - } - - if (axis === 'Y') { - transformations.push(translateY(distance)) - } else { - transformations.push(translateX(distance)) - } - } - - if (config.rotate.x) transformations.push(rotateX(config.rotate.x)) - if (config.rotate.y) transformations.push(rotateY(config.rotate.y)) - if (config.rotate.z) transformations.push(rotateZ(config.rotate.z)) - if (config.scale !== 1) { - if (config.scale === 0) { - /** - * The CSS Transforms matrix interpolation specification - * basically disallows transitions of non-invertible - * matrixes, which means browsers won't transition - * elements with zero scale. - * - * That’s inconvenient for the API and developer - * experience, so we simply nudge their value - * slightly above zero; this allows browsers - * to transition our element as expected. - * - * `0.0002` was the smallest number - * that performed across browsers. - */ - transformations.push(scale(0.0002)) - } else { - transformations.push(scale(config.scale)) - } - } - - const transform = {} - if (transformations.length) { - transform.property = getPrefixedCssProp('transform') - /** - * The default computed transform value should be one of: - * undefined || 'none' || 'matrix()' || 'matrix3d()' - */ - transform.computed = { - raw: computed[transform.property], - matrix: parse(computed[transform.property]) - } - - transformations.unshift(transform.computed.matrix) - const product = transformations.reduce(multiply) - - transform.generated = { - initial: `${transform.property}: matrix3d(${product.join(', ')});`, - final: `${transform.property}: matrix3d(${transform.computed.matrix.join(', ')});` - } - } else { - transform.generated = { - initial: '', - final: '' - } - } - - /** - * Generate transition styles - */ - let transition = {} - if (opacity.generated || transform.generated.initial) { - transition.property = getPrefixedCssProp('transition') - transition.computed = computed[transition.property] - transition.fragments = [] - - const { delay, duration, easing } = config - - if (opacity.generated) { - transition.fragments.push({ - delayed: `opacity ${duration / 1000}s ${easing} ${delay / 1000}s`, - instant: `opacity ${duration / 1000}s ${easing} 0s` - }) - } - - if (transform.generated.initial) { - transition.fragments.push({ - delayed: `${transform.property} ${duration / 1000}s ${easing} ${delay / 1000}s`, - instant: `${transform.property} ${duration / 1000}s ${easing} 0s` - }) - } - - /** - * The default computed transition property should be undefined, or one of: - * '' || 'none 0s ease 0s' || 'all 0s ease 0s' || 'all 0s 0s cubic-bezier()' - */ - let hasCustomTransition = - transition.computed && !transition.computed.match(/all 0s|none 0s/) - - if (hasCustomTransition) { - transition.fragments.unshift({ - delayed: transition.computed, - instant: transition.computed - }) - } - - const composed = transition.fragments.reduce( - (composition, fragment, i) => { - composition.delayed += i === 0 ? fragment.delayed : `, ${fragment.delayed}` - composition.instant += i === 0 ? fragment.instant : `, ${fragment.instant}` - return composition - }, - { - delayed: '', - instant: '' - } - ) - - transition.generated = { - delayed: `${transition.property}: ${composed.delayed};`, - instant: `${transition.property}: ${composed.instant};` - } - } else { - transition.generated = { - delayed: '', - instant: '' - } - } - - return { - inline, - opacity, - position, - transform, - transition - } -} - -/** - * apply a CSS string to an element using the CSSOM (element.style) rather - * than setAttribute, which may violate the content security policy. - * - * @param {Node} [el] Element to receive styles. - * @param {string} [declaration] Styles to apply. - */ -export function applyStyle (el, declaration) { - declaration.split(';').forEach(pair => { - const [property, ...value] = pair.split(':') - if (property && value) { - el.style[property.trim()] = value.join(':') - } - }) -} - diff --git a/src/instance/methods/clean.js b/src/instance/methods/clean.js deleted file mode 100644 index 0fe71322..00000000 --- a/src/instance/methods/clean.js +++ /dev/null @@ -1,34 +0,0 @@ -import $ from 'tealight' -import each from '../../utils/each' -import logger from '../../utils/logger' -import rinse from '../functions/rinse' -import { applyStyle } from '../functions/style' - -export default function clean(target) { - let dirty - try { - each($(target), node => { - const id = node.getAttribute('data-sr-id') - if (id !== null) { - dirty = true - const element = this.store.elements[id] - if (element.callbackTimer) { - window.clearTimeout(element.callbackTimer.clock) - } - applyStyle(element.node, element.styles.inline.generated) - node.removeAttribute('data-sr-id') - delete this.store.elements[id] - } - }) - } catch (e) { - return logger.call(this, 'Clean failed.', e.message) - } - - if (dirty) { - try { - rinse.call(this) - } catch (e) { - return logger.call(this, 'Clean failed.', e.message) - } - } -} diff --git a/src/instance/methods/destroy.js b/src/instance/methods/destroy.js deleted file mode 100644 index d2008fe4..00000000 --- a/src/instance/methods/destroy.js +++ /dev/null @@ -1,32 +0,0 @@ -import each from '../../utils/each' -import { applyStyle } from '../functions/style' - -export default function destroy() { - /** - * Remove all generated styles and element ids - */ - each(this.store.elements, element => { - applyStyle(element.node, element.styles.inline.generated) - element.node.removeAttribute('data-sr-id') - }) - - /** - * Remove all event listeners. - */ - each(this.store.containers, container => { - const target = - container.node === document.documentElement ? window : container.node - target.removeEventListener('scroll', this.delegate) - target.removeEventListener('resize', this.delegate) - }) - - /** - * Clear all data from the store - */ - this.store = { - containers: {}, - elements: {}, - history: [], - sequences: {} - } -} diff --git a/src/instance/methods/reveal.js b/src/instance/methods/reveal.js deleted file mode 100644 index 6cd0bf17..00000000 --- a/src/instance/methods/reveal.js +++ /dev/null @@ -1,150 +0,0 @@ -import tealight from 'tealight' -import deepAssign from '../../utils/deep-assign' -import each from '../../utils/each' -import isMobile from '../../utils/is-mobile' -import logger from '../../utils/logger' -import nextUniqueId from '../../utils/next-unique-id' -import defaults from '../defaults' -import initialize from '../functions/initialize' -import { Sequence } from '../functions/sequence' -import style, { applyStyle } from '../functions/style' -import clean from '../methods/clean' - -export default function reveal(target, options = {}, syncing = false) { - const containerBuffer = [] - let sequence - let interval = options.interval || defaults.interval - - try { - if (interval) { - sequence = new Sequence(interval) - } - - const nodes = tealight(target) - if (!nodes.length) { - throw new Error('Invalid reveal target.') - } - - const elements = nodes.reduce((elementBuffer, elementNode) => { - const element = {} - const existingId = elementNode.getAttribute('data-sr-id') - - if (existingId) { - deepAssign(element, this.store.elements[existingId]) - - /** - * In order to prevent previously generated styles - * from throwing off the new styles, the style tag - * has to be reverted to its pre-reveal state. - */ - applyStyle(element.node, element.styles.inline.computed) - } else { - element.id = nextUniqueId() - element.node = elementNode - element.seen = false - element.revealed = false - element.visible = false - } - - const config = deepAssign({}, element.config || this.defaults, options) - - if ((!config.mobile && isMobile()) || (!config.desktop && !isMobile())) { - if (existingId) { - clean.call(this, element) - } - return elementBuffer // skip elements that are disabled - } - - const containerNode = tealight(config.container)[0] - if (!containerNode) { - throw new Error('Invalid container.') - } - if (!containerNode.contains(elementNode)) { - return elementBuffer // skip elements found outside the container - } - - let containerId - { - containerId = getContainerId( - containerNode, - containerBuffer, - this.store.containers - ) - if (containerId === null) { - containerId = nextUniqueId() - containerBuffer.push({ id: containerId, node: containerNode }) - } - } - - element.config = config - element.containerId = containerId - element.styles = style(element) - - if (sequence) { - element.sequence = { - id: sequence.id, - index: sequence.members.length - } - sequence.members.push(element.id) - } - - elementBuffer.push(element) - return elementBuffer - }, []) - - /** - * Modifying the DOM via setAttribute needs to be handled - * separately from reading computed styles in the map above - * for the browser to batch DOM changes (limiting reflows) - */ - each(elements, element => { - this.store.elements[element.id] = element - element.node.setAttribute('data-sr-id', element.id) - }) - } catch (e) { - return logger.call(this, 'Reveal failed.', e.message) - } - - /** - * Now that element set-up is complete... - * Let’s commit any container and sequence data we have to the store. - */ - each(containerBuffer, container => { - this.store.containers[container.id] = { - id: container.id, - node: container.node - } - }) - if (sequence) { - this.store.sequences[sequence.id] = sequence - } - - /** - * If reveal wasn't invoked by sync, we want to - * make sure to add this call to the history. - */ - if (syncing !== true) { - this.store.history.push({ target, options }) - - /** - * Push initialization to the event queue, giving - * multiple reveal calls time to be interpreted. - */ - if (this.initTimeout) { - window.clearTimeout(this.initTimeout) - } - this.initTimeout = window.setTimeout(initialize.bind(this), 0) - } -} - -function getContainerId(node, ...collections) { - let id = null - each(collections, collection => { - each(collection, container => { - if (id === null && container.node === node) { - id = container.id - } - }) - }) - return id -} diff --git a/src/instance/methods/sync.js b/src/instance/methods/sync.js deleted file mode 100644 index 23d2f69f..00000000 --- a/src/instance/methods/sync.js +++ /dev/null @@ -1,15 +0,0 @@ -import initialize from '../functions/initialize' -import each from '../../utils/each' -import reveal from './reveal' - -/** - * Re-runs the reveal method for each record stored in history, - * for capturing new content asynchronously loaded into the DOM. - */ -export default function sync() { - each(this.store.history, record => { - reveal.call(this, record.target, record.options, true) - }) - - initialize.call(this) -} diff --git a/src/instance/mount.js b/src/instance/mount.js deleted file mode 100644 index 69c84fe5..00000000 --- a/src/instance/mount.js +++ /dev/null @@ -1,27 +0,0 @@ -function failure() { - document.documentElement.classList.remove('sr') - - return { - clean() {}, - destroy() {}, - reveal() {}, - sync() {}, - get noop() { - return true - } - } -} - -function success() { - document.documentElement.classList.add('sr') - - if (document.body) { - document.body.style.height = '100%' - } else { - document.addEventListener('DOMContentLoaded', () => { - document.body.style.height = '100%' - }) - } -} - -export default { success, failure } diff --git a/src/polyfills/math-sign.js b/src/polyfills/math-sign.js deleted file mode 100644 index 474d67e0..00000000 --- a/src/polyfills/math-sign.js +++ /dev/null @@ -1,2 +0,0 @@ -export const polyfill = x => (x > 0) - (x < 0) || +x -export default Math.sign || polyfill diff --git a/src/utils/deep-assign.js b/src/utils/deep-assign.js deleted file mode 100644 index 0e70fc2c..00000000 --- a/src/utils/deep-assign.js +++ /dev/null @@ -1,22 +0,0 @@ -import isObject from './is-object' -import each from './each' - -export default function deepAssign(target, ...sources) { - if (isObject(target)) { - each(sources, source => { - each(source, (data, key) => { - if (isObject(data)) { - if (!target[key] || !isObject(target[key])) { - target[key] = {} - } - deepAssign(target[key], data) - } else { - target[key] = data - } - }) - }) - return target - } else { - throw new TypeError('Target must be an object literal.') - } -} diff --git a/src/utils/each.js b/src/utils/each.js deleted file mode 100644 index 825abbd0..00000000 --- a/src/utils/each.js +++ /dev/null @@ -1,12 +0,0 @@ -import isObject from './is-object' - -export default function each(collection, callback) { - if (isObject(collection)) { - const keys = Object.keys(collection) - return keys.forEach(key => callback(collection[key], key, collection)) - } - if (collection instanceof Array) { - return collection.forEach((item, i) => callback(item, i, collection)) - } - throw new TypeError('Expected either an array or object literal.') -} diff --git a/src/utils/get-geometry.js b/src/utils/get-geometry.js deleted file mode 100644 index 79fc451b..00000000 --- a/src/utils/get-geometry.js +++ /dev/null @@ -1,33 +0,0 @@ -export default function getGeometry(target, isContainer) { - /** - * We want to ignore padding and scrollbars for container elements. - * More information here: https://goo.gl/vOZpbz - */ - const height = isContainer ? target.node.clientHeight : target.node.offsetHeight - const width = isContainer ? target.node.clientWidth : target.node.offsetWidth - - let offsetTop = 0 - let offsetLeft = 0 - let node = target.node - - do { - if (!isNaN(node.offsetTop)) { - offsetTop += node.offsetTop - } - if (!isNaN(node.offsetLeft)) { - offsetLeft += node.offsetLeft - } - node = node.offsetParent - } while (node) - - return { - bounds: { - top: offsetTop, - right: offsetLeft + width, - bottom: offsetTop + height, - left: offsetLeft - }, - height, - width - } -} diff --git a/src/utils/get-prefixed-css-prop.js b/src/utils/get-prefixed-css-prop.js deleted file mode 100644 index 3e425f5d..00000000 --- a/src/utils/get-prefixed-css-prop.js +++ /dev/null @@ -1,26 +0,0 @@ -const getPrefixedCssProp = (() => { - let properties = {} - const style = document.documentElement.style - - function getPrefixedCssProperty(name, source = style) { - if (name && typeof name === 'string') { - if (properties[name]) { - return properties[name] - } - if (typeof source[name] === 'string') { - return (properties[name] = name) - } - if (typeof source[`-webkit-${name}`] === 'string') { - return (properties[name] = `-webkit-${name}`) - } - throw new RangeError(`Unable to find "${name}" style property.`) - } - throw new TypeError('Expected a string.') - } - - getPrefixedCssProperty.clearCache = () => (properties = {}) - - return getPrefixedCssProperty -})() - -export default getPrefixedCssProp diff --git a/src/utils/get-scrolled.js b/src/utils/get-scrolled.js deleted file mode 100644 index f284059c..00000000 --- a/src/utils/get-scrolled.js +++ /dev/null @@ -1,11 +0,0 @@ -export default function getScrolled(container) { - let top, left - if (container.node === document.documentElement) { - top = window.pageYOffset - left = window.pageXOffset - } else { - top = container.node.scrollTop - left = container.node.scrollLeft - } - return { top, left } -} diff --git a/src/utils/is-element-visible.js b/src/utils/is-element-visible.js deleted file mode 100644 index 611192a5..00000000 --- a/src/utils/is-element-visible.js +++ /dev/null @@ -1,30 +0,0 @@ -export default function isElementVisible(element = {}) { - const container = this.store.containers[element.containerId] - if (!container) return - - const viewFactor = Math.max(0, Math.min(1, element.config.viewFactor)) - const viewOffset = element.config.viewOffset - - const elementBounds = { - top: element.geometry.bounds.top + element.geometry.height * viewFactor, - right: element.geometry.bounds.right - element.geometry.width * viewFactor, - bottom: element.geometry.bounds.bottom - element.geometry.height * viewFactor, - left: element.geometry.bounds.left + element.geometry.width * viewFactor - } - - const containerBounds = { - top: container.geometry.bounds.top + container.scroll.top + viewOffset.top, - right: container.geometry.bounds.right + container.scroll.left - viewOffset.right, - bottom: - container.geometry.bounds.bottom + container.scroll.top - viewOffset.bottom, - left: container.geometry.bounds.left + container.scroll.left + viewOffset.left - } - - return ( - (elementBounds.top < containerBounds.bottom && - elementBounds.right > containerBounds.left && - elementBounds.bottom > containerBounds.top && - elementBounds.left < containerBounds.right) || - element.styles.position === 'fixed' - ) -} diff --git a/src/utils/is-mobile.js b/src/utils/is-mobile.js deleted file mode 100644 index bd72c0a3..00000000 --- a/src/utils/is-mobile.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function isMobile(agent = navigator.userAgent) { - return /Android|iPhone|iPad|iPod/i.test(agent) -} diff --git a/src/utils/is-object.js b/src/utils/is-object.js deleted file mode 100644 index 9a39e331..00000000 --- a/src/utils/is-object.js +++ /dev/null @@ -1,8 +0,0 @@ -export default function isObject(x) { - return ( - x !== null && - x instanceof Object && - (x.constructor === Object || - Object.prototype.toString.call(x) === '[object Object]') - ) -} diff --git a/src/utils/is-transform-supported.js b/src/utils/is-transform-supported.js deleted file mode 100644 index d15b86ce..00000000 --- a/src/utils/is-transform-supported.js +++ /dev/null @@ -1,4 +0,0 @@ -export default function isTransformSupported() { - const style = document.documentElement.style - return 'transform' in style || 'WebkitTransform' in style -} diff --git a/src/utils/is-transition-supported.js b/src/utils/is-transition-supported.js deleted file mode 100644 index d15a23a9..00000000 --- a/src/utils/is-transition-supported.js +++ /dev/null @@ -1,4 +0,0 @@ -export default function isTransitionSupported() { - const style = document.documentElement.style - return 'transition' in style || 'WebkitTransition' in style -} diff --git a/src/utils/logger.js b/src/utils/logger.js deleted file mode 100644 index 3b79126d..00000000 --- a/src/utils/logger.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function logger(message, ...details) { - if (this.constructor.debug && console) { - let report = `%cScrollReveal: ${message}` - details.forEach(detail => (report += `\n — ${detail}`)) - console.log(report, 'color: #ea654b;') // eslint-disable-line no-console - } -} diff --git a/src/utils/next-unique-id.js b/src/utils/next-unique-id.js deleted file mode 100644 index a043eff4..00000000 --- a/src/utils/next-unique-id.js +++ /dev/null @@ -1,6 +0,0 @@ -const nextUniqueId = (() => { - let uid = 0 - return () => uid++ -})() - -export default nextUniqueId diff --git a/test/instance/constructor.spec.js b/test/instance/constructor.spec.js deleted file mode 100644 index f4456417..00000000 --- a/test/instance/constructor.spec.js +++ /dev/null @@ -1,175 +0,0 @@ -import ScrollReveal from '../../src/instance/constructor' -import isMobile from '../../src/utils/is-mobile' -import { version } from '../../package.json' - -describe('ScrollReveal', () => { - describe('Constructor', () => { - it('should return a new instance with `new` keyword', () => { - const sr = new ScrollReveal() - expect(sr).to.exist - }) - - it('should return a new instance without `new` keyword', () => { - const sr = ScrollReveal() - expect(sr).to.exist - }) - - it('should add the class `sr` to `` element', () => { - document.documentElement.classList.remove('sr') - ScrollReveal() - const result = document.documentElement.classList.contains('sr') - expect(result).to.be.true - }) - - it('should add `height: 100%` to `` element', () => { - document.body.style.height = 'auto' - ScrollReveal() - const result = document.body.style.height === '100%' - expect(result).to.be.true - }) - - it('should return a noop instance when not supported', () => { - const stubs = [ - sinon.stub(console, 'log'), - sinon.stub(ScrollReveal, 'isSupported') - ] - const sr = ScrollReveal() - stubs.forEach(stub => stub.restore()) - expect(sr.noop).to.be.true - }) - - it('should return a noop instance when device is disabled', () => { - isMobile() - ? expect(ScrollReveal({ mobile: false }).noop).to.be.true - : expect(ScrollReveal({ desktop: false }).noop).to.be.true - - ScrollReveal({ desktop: true, mobile: true }) - }) - - it('should return a noop instance when container is invalid', () => { - const stub = sinon.stub(console, 'log') - const sr = ScrollReveal({ container: null }) - stub.restore() - expect(sr.noop).to.be.true - }) - - it('should return a noop instance when passed non-object options', () => { - const stub = sinon.stub(console, 'log') - let sr - { - sr = ScrollReveal(null) - expect(sr.noop).to.be.true - sr = ScrollReveal('foo') - expect(sr.noop).to.be.true - } - stub.restore() - }) - - it('should return a singleton', () => { - const A = ScrollReveal() - const B = ScrollReveal() - expect(A === B).to.be.true - }) - - it('should not update the defaults when re-invoked with invalid options', () => { - ScrollReveal({ duration: 1000 }) - ScrollReveal(null) - expect(ScrollReveal().defaults.duration).to.equal(1000) - }) - - it('should update the defaults when re-invoked with valid options', () => { - ScrollReveal({ duration: 1000 }) - ScrollReveal({ duration: 5000 }) - expect(ScrollReveal().defaults.duration).to.equal(5000) - }) - - it('should have a static `debug` property', () => { - expect(ScrollReveal.debug).to.exist - expect(ScrollReveal.debug).to.be.a('boolean') - }) - - it('should accept boolean value for static `debug` property', () => { - ScrollReveal.debug = true - expect(ScrollReveal.debug).to.be.true - }) - - it('should ignore non-boolean values assigned to static `debug` property', () => { - ScrollReveal.debug = null - expect(ScrollReveal.debug).to.exist - expect(ScrollReveal.debug).to.be.a('boolean') - }) - }) - - describe('Instance', () => { - const sr = new ScrollReveal() - - it('should have a `clean` method', () => { - expect(sr.clean).to.exist - expect(sr.clean).to.be.a('function') - }) - - it('should have a `destroy` method', () => { - expect(sr.destroy).to.exist - expect(sr.destroy).to.be.a('function') - }) - - it('should have a `reveal` method', () => { - expect(sr.reveal).to.exist - expect(sr.reveal).to.be.a('function') - }) - - it('should have a `sync` method', () => { - expect(sr.sync).to.exist - expect(sr.sync).to.be.a('function') - }) - - it('should have a `delegate` property', () => { - expect(sr.delegate).to.exist - expect(sr.delegate).to.be.a('function') - }) - - it('should have a `version` property', () => { - expect(sr.version).to.exist - expect(sr.version).to.be.equal(version) - }) - - it('should have a `noop` property set to `false`', () => { - expect(sr.noop).to.exist - expect(sr.noop).to.be.false - }) - }) - - describe('Non-operational Instance', () => { - const stubs = [ - sinon.stub(console, 'log'), - sinon.stub(ScrollReveal, 'isSupported') - ] - const sr = ScrollReveal() - stubs.forEach(stub => stub.restore()) - - it('should have a `clean` method', () => { - expect(sr.clean).to.exist - expect(sr.clean).to.be.a('function') - }) - - it('should have a `destroy` method', () => { - expect(sr.destroy).to.exist - expect(sr.destroy).to.be.a('function') - }) - - it('should have a `reveal` method', () => { - expect(sr.reveal).to.exist - expect(sr.reveal).to.be.a('function') - }) - - it('should have a `sync` method', () => { - expect(sr.sync).to.exist - expect(sr.sync).to.be.a('function') - }) - - it('should have a `noop` property set to `true`', () => { - expect(sr.noop).to.exist - expect(sr.noop).to.be.true - }) - }) -}) diff --git a/test/karma.conf.js b/test/karma.conf.js deleted file mode 100644 index 7c3b0167..00000000 --- a/test/karma.conf.js +++ /dev/null @@ -1,95 +0,0 @@ -const rollupPlugins = [ - require('rollup-plugin-json')(), - require('rollup-plugin-node-resolve')({ jsnext: true, main: true }), - require('rollup-plugin-buble')() -] - -if (process.env.COVERAGE) { - rollupPlugins.push( - require('rollup-plugin-istanbul')({ - exclude: [ - '../package.json', - '../src/index.js', - './**/*.spec.js', - '**/node_modules/**' - ], - instrumenterConfig: { - embedSource: true - } - }) - ) -} - -module.exports = function(karma) { - karma.set({ - frameworks: ['mocha', 'sinon-chai'], - - preprocessors: { - './**/*.spec.js': ['rollup'] - }, - - files: [{ pattern: './**/*.spec.js', watched: false }], - - rollupPreprocessor: { - plugins: rollupPlugins, - output: { - format: 'iife', - name: 'ScrollReveal', - sourcemap: 'inline' - } - }, - - colors: true, - concurrency: 10, - logLevel: karma.LOG_ERROR, - singleRun: true, - - browserDisconnectTolerance: 1, - browserDisconnectTimeout: 60 * 1000, - browserNoActivityTimeout: 60 * 1000, - // browserNoActivityTimeout: 60 * 1000 * 10 * 6, // dev tools debugging - captureTimeout: 4 * 60 * 1000 - }) - - if (process.env.TRAVIS) { - if (process.env.COVERAGE) { - karma.set({ - autoWatch: false, - browsers: ['ChromeHeadless'], - coverageReporter: { - type: 'lcovonly', - dir: 'coverage/' - }, - reporters: ['mocha', 'coverage', 'coveralls'] - }) - } else { - const customLaunchers = require('./sauce.conf') - karma.set({ - autoWatch: false, - browsers: Object.keys(customLaunchers), - customLaunchers, - reporters: ['dots', 'saucelabs'], - hostname: 'localsauce', - sauceLabs: { - testName: 'ScrollReveal', - build: process.env.TRAVIS_BUILD_NUMBER || 'manual', - tunnelIdentifier: process.env.TRAVIS_BUILD_NUMBER || 'autoGeneratedTunnelID', - recordVideo: true, - connectOptions: { - tunnelDomains: 'localsauce' // because Android 8 has an SSL error? - } - } - }) - } - } else { - karma.set({ - browsers: ['ChromeHeadless'], - // browsers: ['Chrome'], // dev tools debugging - coverageReporter: { - type: 'lcov', - dir: '../.ignore/coverage/' - }, - reporters: ['mocha', 'coverage'] - }) - } -} diff --git a/test/polyfills/math-sign.spec.js b/test/polyfills/math-sign.spec.js deleted file mode 100644 index 6e59eefa..00000000 --- a/test/polyfills/math-sign.spec.js +++ /dev/null @@ -1,42 +0,0 @@ -import { polyfill } from '../../src/polyfills/math-sign' - -describe('Polyfills', () => { - describe('mathSign()', () => { - it('should be a function', () => { - expect(polyfill).to.be.a('function') - }) - - it('should return -1 when passed values smaller than 0', () => { - expect(polyfill(-500)).to.equal(-1) - }) - - it('should return 1 when passed values larger than 0', () => { - expect(polyfill(500)).to.equal(1) - }) - - it('should return 1 when passed true', () => { - expect(polyfill(true)).to.equal(1) - }) - - it('should return -0 when passed -0', () => { - expect(polyfill(-0)).to.equal(-0) - }) - - it('should return 0 when passed 0', () => { - expect(polyfill(0)).to.equal(0) - }) - - it('should return 0 when passed falsey values', () => { - expect(polyfill(false)).to.equal(0) - expect(polyfill('')).to.equal(0) - expect(polyfill([])).to.equal(0) - expect(polyfill(null)).to.equal(0) - }) - - it('should return NaN when passed non-falsey non-numbers', () => { - expect(polyfill('foo')).to.be.NaN - expect(polyfill({})).to.be.NaN - expect(polyfill([1, 2, 3])).to.be.NaN - }) - }) -}) diff --git a/test/sauce.conf.js b/test/sauce.conf.js deleted file mode 100644 index 37052252..00000000 --- a/test/sauce.conf.js +++ /dev/null @@ -1,73 +0,0 @@ -let launchers = {} - -let mobileLaunchers = [ - ['iOS', '10.3', 'Safari', 'iPhone 7 Simulator', '1.9.1'], - ['iOS', '11.3', 'Safari', 'iPhone 7 Simulator', '1.9.1'], - ['iOS', '12.2', 'Safari', 'iPhone 7 Simulator', '1.13.0'], - ['iOS', '13.0', 'Safari', 'iPhone 7 Simulator', '1.15.0'], - ['Android', '5.1', 'Browser', 'Android Emulator', '1.15.0'], - ['Android', '6.0', 'Chrome', 'Android Emulator', '1.15.0'], - ['Android', '8.0', 'Chrome', 'Android Emulator', '1.15.0'] -] - -for (let [platform, version, browser, device, appium] of mobileLaunchers) { - let launcher = `sl_${platform}_${version}_${browser}` - .replace(/[^a-z0-9]/gi, '_') - .toLowerCase() - - launchers[launcher] = { - name: `${browser}, ${platform} ${version}`, - platformName: platform, - platformVersion: version, - browserName: browser, - deviceName: device, - deviceOrientation: 'portrait', - appiumVersion: appium - } -} - -let desktopLaunchers = [ - ['Windows 8.1', 'Internet Explorer', '11.0'], - ['Windows 8', 'Internet Explorer', '10.0'], - ['macOS 10.12', 'Safari', '11.0'], - ['OS X 10.11', 'Safari', '10.0'], - ['OS X 10.11', 'Safari', '9.0'] -] - -for (let [platform, browser, version] of desktopLaunchers) { - let launcher = `sl_${platform}_${browser}_${version}` - .replace(/[^a-z0-9]/gi, '_') - .toLowerCase() - - launchers[launcher] = { - name: `${browser} ${version}, ${platform}`, - browserName: browser, - version, - platform - } -} - -for (let browser of ['Chrome', 'Firefox', 'MicrosoftEdge']) { - let pastVersions = 3 - do { - pastVersions-- - let postfix = pastVersions > 0 ? `-${pastVersions}` : '' - let version = 'latest' + postfix - - let browserName = browser === 'MicrosoftEdge' ? 'Edge' : browser - let launcher = `sl_win10_${browser}_latest${postfix}`.replace(/-/g, '_').toLowerCase() - - launchers[launcher] = { - name: `${browserName} ${version}, Windows 10`, - browserName: browser, - version, - platform: 'Windows 10' - } - } while (pastVersions) -} - -for (let launcher in launchers) { - launchers[launcher].base = 'SauceLabs' -} - -module.exports = launchers diff --git a/test/timeout.spec.js b/test/timeout.spec.js deleted file mode 100644 index 92c32611..00000000 --- a/test/timeout.spec.js +++ /dev/null @@ -1,8 +0,0 @@ -// describe('suite delay for DOM inspection', function () { -// it('should delay by 10 minutes', function (done) { -// document.documentElement.style = 'background-color: #eee; height: 100%' -// const time = 1000 * 60 * 10 * 6 -// this.timeout(time) -// setTimeout(done, time - 500) -// }) -// }) diff --git a/test/utils/deep-assign.spec.js b/test/utils/deep-assign.spec.js deleted file mode 100644 index 8c8552c6..00000000 --- a/test/utils/deep-assign.spec.js +++ /dev/null @@ -1,58 +0,0 @@ -import deepAssign from '../../src/utils/deep-assign' - -describe('Utilities', () => { - describe('deepAssign()', () => { - it('should assign source values to target object', () => { - const target = { foo: 'bar', bun: 'baz' } - const source = { foo: 'bonk!', bif: 'baff' } - const goal = { foo: 'bonk!', bun: 'baz', bif: 'baff' } - deepAssign(target, source) - expect(target).to.deep.equal(goal) - }) - - it('should assign nested source values to target object', () => { - // each property tests a - // different execution path - const target = { - foo: 'initial', - bar: 'initial', - kel: { pow: 'pop' }, - zad: null - } - const source = { - foo: 'bonk!', - bar: { baz: 'baff' }, - kel: { pow: 'lol' }, - zad: { min: 'max' } - } - const goal = { - foo: 'bonk!', - bar: { baz: 'baff' }, - kel: { pow: 'lol' }, - zad: { min: 'max' } - } - deepAssign(target, source) - expect(target).to.deep.equal(goal) - }) - - it('should accept multiple sources', () => { - const target = { foo: 'bar', bun: 'baz' } - const source1 = { foo: 'bonk!', bif: 'baff' } - const source2 = { foo: 'pow!' } - const goal = { foo: 'pow!', bun: 'baz', bif: 'baff' } - deepAssign(target, source1, source2) - expect(target).to.deep.equal(goal) - }) - - it('should throw a type error when not passed an object literal', () => { - let caught - try { - deepAssign(null, null) - } catch (error) { - caught = error - } - expect(caught).to.exist - expect(caught).to.be.an.instanceof(TypeError) - }) - }) -}) diff --git a/test/utils/each.spec.js b/test/utils/each.spec.js deleted file mode 100644 index 8c47d293..00000000 --- a/test/utils/each.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -import each from '../../src/utils/each' - -describe('Utilities', () => { - describe('each()', () => { - function Fixture() { - this.foo = 'bar' - this.baz = 'bun' - } - - describe('if passed an object literal...', () => { - it('should invoke callback for each property', () => { - const fixture = new Fixture() - const spy = sinon.spy() - each(fixture, spy) - expect(spy).to.have.been.calledTwice - }) - - it('should ignore properties on the prototype chain', () => { - Fixture.prototype.biff = 'baff' - const fixture = new Fixture() - const spy = sinon.spy() - each(fixture, spy) - expect(spy).to.have.been.calledTwice - }) - - it('should pass the value, key and collection to the callback', () => { - const fixture = new Fixture() - let _value, _key, _collection - each(fixture, (value, key, collection) => { - _value = value - _key = key - _collection = collection - }) - expect(_value).to.equal('bun') - expect(_key).to.equal('baz') - expect(_collection).to.deep.equal(fixture) - }) - }) - - describe('if passed an array...', () => { - const fixture = ['apple', 'orange', 'banana'] - - it('should invoke callback for each value', () => { - const spy = sinon.spy() - each(fixture, spy) - expect(spy).to.have.been.calledThrice - }) - - it('should pass the value, index and collection to the callback', () => { - let _value, _index, _collection - each(fixture, (value, index, collection) => { - _value = value - _index = index - _collection = collection - }) - expect(_value).to.equal('banana') - expect(_index).to.equal(2) - expect(_collection).to.deep.equal(fixture) - }) - }) - - describe('else', () => { - it('should throw a type error when passed an invalid collection', () => { - let caught - try { - each(null, () => {}) - } catch (error) { - caught = error - } - expect(caught).to.exist - expect(caught).to.be.an.instanceof(TypeError) - }) - }) - }) -}) diff --git a/test/utils/get-prefixed-css-prop.spec.js b/test/utils/get-prefixed-css-prop.spec.js deleted file mode 100644 index e3bf9c34..00000000 --- a/test/utils/get-prefixed-css-prop.spec.js +++ /dev/null @@ -1,53 +0,0 @@ -import getPrefixedCssProp from '../../src/utils/get-prefixed-css-prop' - -describe('Utilities', () => { - describe('getPrefixedCssProp()', () => { - beforeEach('clear cache', () => { - getPrefixedCssProp.clearCache() - }) - - it('should return unprefixed properties before prefixed', () => { - const source = { - transform: '', - '-webkit-transform': '' - } - const result = getPrefixedCssProp('transform', source) - expect(result).to.equal('transform') - }) - - it('should return prefixed property names', () => { - const source = { '-webkit-transform': '' } - const result = getPrefixedCssProp('transform', source) - expect(result).to.equal('-webkit-transform') - }) - - it('should return property names from cache when available', () => { - const source = { '-webkit-transform': '' } - getPrefixedCssProp('transform', source) - const result = getPrefixedCssProp('transform', {}) - expect(result).to.equal('-webkit-transform') - }) - - it('should throw a range error when no property is found', () => { - let caught - try { - getPrefixedCssProp('transform', {}) - } catch (error) { - caught = error - } - expect(caught).to.exist - expect(caught).to.be.an.instanceof(RangeError) - }) - - it('should throw a type error if not passed a string', () => { - let caught - try { - getPrefixedCssProp(null) - } catch (error) { - caught = error - } - expect(caught).to.exist - expect(caught).to.be.an.instanceof(TypeError) - }) - }) -}) diff --git a/test/utils/is-mobile.spec.js b/test/utils/is-mobile.spec.js deleted file mode 100644 index 37dd9389..00000000 --- a/test/utils/is-mobile.spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import isMobile from '../../src/utils/is-mobile' - -describe('Utilities', () => { - describe('isMobile()', () => { - it('should return true when passed a mobile user agent', () => { - const android = `Mozilla/5.0 (Linux; U; Android 4.2; en-us; - Android SDK built for x86 Build/JOP40C) AppleWebKit/534.30 - (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` - - const iPhone = `Mozilla/5.0 (iPhone; CPU iPhone OS 10_10_5 like Mac OS X) - AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B411 Safari/600.1.4` - - expect(isMobile(android)).to.be.true - expect(isMobile(iPhone)).to.be.true - }) - - it('should return false when passed a desktop user agent', () => { - const chrome = `Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 - (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36` - - const firefox = - 'Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0' - - const ie10 = `Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; - WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E)` - - expect(isMobile(chrome)).to.be.false - expect(isMobile(firefox)).to.be.false - expect(isMobile(ie10)).to.be.false - }) - - it('should work when not passed an explicit user agent', () => { - expect(isMobile()).to.be.a('boolean') - }) - }) -}) diff --git a/test/utils/is-object.spec.js b/test/utils/is-object.spec.js deleted file mode 100644 index 869b53bc..00000000 --- a/test/utils/is-object.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -import isObject from '../../src/utils/is-object' - -describe('Utilities', () => { - describe('isObject()', () => { - it('should return true when passed an object literal', () => { - const result = isObject({}) - expect(result).to.be.true - }) - - it('should return false when passed a function', () => { - const result = isObject(() => {}) - expect(result).to.be.false - }) - - it('should return false when passed an array', () => { - const result = isObject([]) - expect(result).to.be.false - }) - - it('should return false when passed null', () => { - const result = isObject(null) - expect(result).to.be.false - }) - - it('should return false when passed undefined', () => { - const result = isObject(undefined) - expect(result).to.be.false - }) - }) -}) diff --git a/test/utils/is-transform-supported.spec.js b/test/utils/is-transform-supported.spec.js deleted file mode 100644 index 4dcc5c20..00000000 --- a/test/utils/is-transform-supported.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -import isTransformSupported from '../../src/utils/is-transform-supported' - -describe('Utilities', () => { - describe('isTransformSupported()', () => { - it('should return true', () => { - expect(isTransformSupported()).to.be.true - }) - }) -}) diff --git a/test/utils/is-transition-supported.spec.js b/test/utils/is-transition-supported.spec.js deleted file mode 100644 index e0484e52..00000000 --- a/test/utils/is-transition-supported.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -import isTransitionSupported from '../../src/utils/is-transition-supported' - -describe('Utilities', () => { - describe('isTransitionSupported()', () => { - it('should return true', () => { - expect(isTransitionSupported()).to.be.true - }) - }) -}) diff --git a/test/utils/logger.spec.js b/test/utils/logger.spec.js deleted file mode 100644 index 75b7ca4f..00000000 --- a/test/utils/logger.spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import logger from '../../src/utils/logger' - -describe('Utilities', () => { - describe('logger()', () => { - const mock = { constructor: { debug: true } } - - let spy - let stub - - beforeEach('stub console log', () => { - spy = sinon.spy() - stub = sinon.stub(console, 'log').callsFake(spy) - }) - - it('should invoke console.log', () => { - logger.call(mock) - expect(spy).to.have.been.called - }) - - it('should prepend output with `ScrollReveal: `', () => { - logger.call(mock, 'test') - const result = '%cScrollReveal: test' - const style = 'color: #ea654b;' - expect(spy).to.have.been.calledWith(result, style) - }) - - it('should accept multiple arguments as message details', () => { - logger.call(mock, 'message', 'detail one', 'detail two') - const result = '%cScrollReveal: message\n — detail one\n — detail two' - const style = 'color: #ea654b;' - expect(spy).to.have.been.calledWith(result, style) - }) - - afterEach('restore console log', () => stub.restore()) - }) -}) diff --git a/test/utils/next-unique-id.spec.js b/test/utils/next-unique-id.spec.js deleted file mode 100644 index d31446d5..00000000 --- a/test/utils/next-unique-id.spec.js +++ /dev/null @@ -1,20 +0,0 @@ -import nextUniqueId from '../../src/utils/next-unique-id' - -describe('Utilities', () => { - describe('nextUniqueId()', () => { - it('should start at 0', () => { - const result = nextUniqueId() - expect(result).to.equal(0) - }) - - it('should increment by 1', () => { - const result = nextUniqueId() - expect(result).to.equal(1) - }) - - it('should return a number', () => { - const result = nextUniqueId() - expect(result).to.be.a('number') - }) - }) -})