├── .gitignore
├── demos
├── performances
│ ├── index.js
│ ├── custom.js
│ ├── index.html
│ └── build.js
├── scale
│ ├── index.js
│ ├── index.html
│ ├── custom.js
│ └── build.js
├── opacity
│ ├── index.js
│ ├── index.html
│ └── custom.js
├── parallax-page
│ ├── index.js
│ ├── index.html
│ └── custom.js
├── split
│ ├── index.js
│ ├── custom.js
│ └── index.html
├── native-horizontal
│ ├── index.js
│ ├── index.html
│ └── custom.js
├── horizontal
│ ├── index.js
│ ├── index.html
│ └── custom.js
├── parallax
│ ├── index.js
│ ├── index.html
│ └── custom.js
├── main.css
├── callback
│ └── index.html
├── native-scrollbar
│ └── index.html
└── gsap
│ └── index.html
├── LICENSE
├── package.json
├── README.md
├── index.js
└── smooth-scrolling.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | .DS_Store
--------------------------------------------------------------------------------
/demos/performances/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | extends: true,
5 | section: document.querySelector('.vs-section')
6 | })
7 |
8 | scroll.init()
--------------------------------------------------------------------------------
/demos/scale/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const image = document.querySelector('img');
4 | const scroll = new Custom({
5 | extends: true,
6 | img: image
7 | })
8 |
9 | scroll.init()
--------------------------------------------------------------------------------
/demos/opacity/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | extends: true,
5 | section: document.querySelector('.vs-section'),
6 | opacity: document.querySelector('h1')
7 | })
8 |
9 | scroll.init()
--------------------------------------------------------------------------------
/demos/parallax-page/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | preload: true,
5 | native: true,
6 | section: document.querySelector('.vs-section'),
7 | divs: document.querySelectorAll('.vs-div')
8 | })
9 |
10 | scroll.init()
--------------------------------------------------------------------------------
/demos/split/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | extends: true,
5 | native: true,
6 | section: document.querySelector('.vs-sections'),
7 | sections: document.querySelectorAll('.vs-split')
8 | })
9 |
10 | scroll.init()
--------------------------------------------------------------------------------
/demos/native-horizontal/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | preload: false,
5 | native: true,
6 | direction: 'vertical',
7 | section: document.querySelector('.vs-section'),
8 | divs: document.querySelectorAll('.vs-div')
9 | })
10 |
11 | scroll.init()
--------------------------------------------------------------------------------
/demos/horizontal/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | preload: false,
5 | native: false,
6 | direction: 'horizontal',
7 | section: document.querySelector('.vs-section'),
8 | divs: document.querySelectorAll('.vs-div')
9 | })
10 |
11 | scroll.init()
--------------------------------------------------------------------------------
/demos/parallax/index.js:
--------------------------------------------------------------------------------
1 | import Custom from './custom'
2 |
3 | const scroll = new Custom({
4 | extends: true,
5 | preload: true,
6 | noscrollbar: true,
7 | section: document.querySelector('.vs-section'),
8 | divs: document.querySelectorAll('.vs-div')
9 | })
10 |
11 | scroll.init()
12 |
13 | // setTimeout(() => {
14 | // scroll.destroy()
15 | // }, 1500)
--------------------------------------------------------------------------------
/demos/scale/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | scale demo | smooth-scrolling
7 |
8 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demos/scale/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Custom extends Smooth {
4 |
5 | constructor(opt) {
6 | super(opt)
7 | this.dom.img = opt.img
8 | }
9 |
10 | init() {
11 | super.init()
12 | }
13 |
14 | run() {
15 | super.run()
16 | const current = Math.round(Math.abs(this.vars.current));
17 | const scale = Math.max(0.8, Math.min(0.8 + current / window.innerHeight * 1.5, 10))
18 | this.dom.img.style[this.prefix] = `scale3d(${scale},${scale},${scale})`;
19 | }
20 |
21 | resize() {
22 | this.vars.bounding = window.innerHeight * 1.5
23 | super.resize()
24 | }
25 | }
26 |
27 | export default Custom
--------------------------------------------------------------------------------
/demos/opacity/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | opacity demo | smooth-scrolling
7 |
8 |
23 |
24 |
25 |
26 |
Opacity
27 |

28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/demos/performances/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Custom extends Smooth {
4 |
5 | constructor(opt) {
6 | super(opt)
7 | this.perfs = {
8 | now: null,
9 | last: null
10 | }
11 | this.dom.section = opt.section
12 | }
13 |
14 | init() {
15 | super.init();
16 | }
17 |
18 | run() {
19 | this.perfs.now = window.performance.now()
20 | super.run()
21 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2))
22 | console.log(this.perfs.now - this.perfs.last)
23 | this.perfs.last = this.perfs.now
24 | }
25 |
26 | resize() {
27 | this.vars.bounding = this.dom.section.getBoundingClientRect().height - this.vars.height
28 | super.resize()
29 | }
30 | }
31 |
32 | export default Custom
--------------------------------------------------------------------------------
/demos/opacity/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Custom extends Smooth {
4 |
5 | constructor(opt) {
6 | super(opt)
7 | this.dom.section = opt.section
8 | this.dom.opacity = opt.opacity
9 | }
10 |
11 | init() {
12 | super.init()
13 | }
14 |
15 | run() {
16 | super.run()
17 | const current = Math.round(Math.abs(this.vars.current))
18 | const opacity = Math.max(0, Math.min(1 - current / (this.vars.height * .5), 1))
19 | this.dom.opacity.style.opacity = opacity.toFixed(2);
20 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2))
21 | }
22 |
23 | resize() {
24 | this.vars.bounding = this.dom.section.getBoundingClientRect().height - this.vars.height
25 | super.resize()
26 | }
27 | }
28 |
29 | export default Custom
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Baptiste Briel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demos/parallax/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | parallax demo | smooth-scrolling
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demos/main.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | }
4 |
5 | html,
6 | body {
7 | width: 100%;
8 | height: 100%;
9 | }
10 |
11 | .is-virtual-scroll {
12 | overflow: hidden;
13 | }
14 |
15 | .is-native-scroll.y-scroll {
16 | overflow-y: scroll;
17 | overflow-x: hidden;
18 | }
19 |
20 | .is-native-scroll.x-scroll {
21 | overflow-y: hidden;
22 | overflow-x: scroll;
23 | }
24 |
25 | .vs-section {
26 | position: fixed;
27 | top: 0; right: 0; left: 0;
28 | width: 100%; height: auto;
29 | margin: auto;
30 | text-align: center;
31 | will-change: transform;
32 | }
33 |
34 | .vs-scrollbar {
35 | display: block;
36 | position: absolute;
37 | transition: transform .6s;
38 | }
39 |
40 | .vs-scrollbar.vs-vertical {
41 | top: 0; right: -5px; bottom: 0;
42 | width: 15px; height: 100%;
43 | transform: translate3d(5px,0,0);
44 | }
45 |
46 | .vs-scrollbar.vs-horizontal {
47 | bottom: -5px; left: 0; right: 0;
48 | width: 100%; height: 15px;
49 | transform: translate3d(0,5px,0);
50 | }
51 |
52 | .is-dragging .vs-scrollbar.vs-horizontal,
53 | .is-dragging .vs-scrollbar.vs-vertical,
54 | .vs-scrollbar.vs-horizontal:hover,
55 | .vs-scrollbar.vs-vertical:hover {
56 | transform: none;
57 | }
58 |
59 | .vs-scrollbar .vs-scrolldrag {
60 | width: 100%;
61 | height: auto;
62 | background: #ccc;
63 | cursor: pointer;
64 | }
65 |
66 | .vs-scroll-view {
67 | position: relative;
68 | width: 1px;
69 | }
--------------------------------------------------------------------------------
/demos/parallax-page/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | parallax page demo | smooth-scrolling
7 |
8 |
17 |
18 |
19 |
20 |
vs-section + vs.div parallax example
21 |

22 |

23 |

24 |

25 |

26 |

27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/demos/callback/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | callback demo | smooth-scrolling
7 |
8 |
31 |
32 |
33 | current scroll: 0px
34 |
35 |
callback
36 |

37 |
38 |
39 |
48 |
49 |
--------------------------------------------------------------------------------
/demos/performances/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | performances demo | smooth-scrolling
7 |
8 |
43 |
44 |
45 |
46 |

47 |

48 |

49 |

50 |

51 |

52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/demos/native-horizontal/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | native horizontal demo | smooth-scrolling
7 |
8 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/demos/native-scrollbar/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | native scrollbar demo | smooth-scrolling
7 |
8 |
38 |
39 |
40 |
41 |

42 |

43 |

44 |

45 |

46 |

47 |
48 |
49 |
53 |
54 |
--------------------------------------------------------------------------------
/demos/horizontal/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | horizontal demo | smooth-scrolling
7 |
8 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smooth-scrolling",
3 | "version": "2.3.12",
4 | "description": "Smooth is a small JavaScript module based on VirtualScroll to create smooth scrolling and parallax effects on scroll.",
5 | "main": "index.js",
6 | "dependencies": {
7 | "dom-classes": "github:npm-dom/dom-classes",
8 | "dom-create-element": "^1.0.2",
9 | "dom-events": "^0.1.1",
10 | "prefix": "^1.0.0",
11 | "virtual-scroll": "^1.2.1"
12 | },
13 | "devDependencies": {
14 | "@babel/core": "^7.4.4",
15 | "@babel/preset-env": "^7.4.5",
16 | "babelify": "^10.0.0",
17 | "dom-css": "^2.1.0",
18 | "uglifyjs": "^2.4.11",
19 | "watchify": "^3.11.1"
20 | },
21 | "scripts": {
22 | "dev": "watchify -v -t babelify index.js -o smooth-scrolling.js",
23 | "demo-parallax": "watchify -v -t babelify demos/parallax/index.js -o demos/parallax/build.js",
24 | "demo-parallax-page": "watchify -v -t babelify demos/parallax-page/index.js -o demos/parallax-page/build.js",
25 | "demo-horizontal": "watchify -v -t babelify demos/horizontal/index.js -o demos/horizontal/build.js",
26 | "demo-native-horizontal": "watchify -v -t babelify demos/native-horizontal/index.js -o demos/native-horizontal/build.js",
27 | "demo-opacity": "watchify -v -t babelify demos/opacity/index.js -o demos/opacity/build.js",
28 | "demo-scale": "watchify -v -t babelify demos/scale/index.js -o demos/scale/build.js",
29 | "demo-split": "watchify -v -t babelify demos/split/index.js -o demos/split/build.js",
30 | "demo-performances": "watchify -v -t babelify demos/performances/index.js -o demos/performances/build.js"
31 | },
32 | "browserify": {
33 | "transform": [
34 | [
35 | "babelify",
36 | {
37 | "presets": [
38 | "@babel/preset-env"
39 | ]
40 | }
41 | ]
42 | ]
43 | },
44 | "author": "Baptiste Briel",
45 | "license": "MIT"
46 | }
47 |
--------------------------------------------------------------------------------
/demos/native-horizontal/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Parallax extends Smooth {
4 |
5 | constructor(opt) {
6 | super(opt)
7 | this.createExtraBound()
8 | this.resizing = false
9 | this.cache = null
10 | this.dom.divs = Array.prototype.slice.call(opt.divs, 0)
11 | }
12 |
13 | createExtraBound() {
14 | ['getCache', 'inViewport']
15 | .forEach((fn) => this[fn] = this[fn].bind(this))
16 | }
17 |
18 | resize() {
19 | this.resizing = true
20 | this.getCache()
21 | super.resize()
22 | this.dom.scroll.style.width = ''
23 | this.dom.scroll.style.height = `${this.vars.bounding}px`
24 | this.resizing = false
25 | }
26 |
27 | getCache() {
28 | this.cache = []
29 | const unit = (this.vars.width / 3)
30 | this.dom.divs.forEach((el, index) => {
31 | el.style.display = 'inline-block'
32 | el.style.transform = 'none'
33 | el.style.width = `${unit}px`
34 | const scrollX = this.vars.target
35 | const bounding = el.getBoundingClientRect()
36 | const bounds = {
37 | el: el,
38 | state: true,
39 | left: bounding.left + scrollX,
40 | right: bounding.right + scrollX,
41 | center: unit / 2
42 | }
43 | this.cache.push(bounds)
44 | })
45 | this.dom.section.style.width = `${this.vars.width}px`
46 | this.vars.bounding = (unit * this.dom.divs.length)
47 | }
48 |
49 | run() {
50 | this.dom.divs.forEach(this.inViewport)
51 | this.dom.section.style[this.prefix] = `translate3d(${this.vars.current * -1}px,0,0)`
52 | super.run()
53 | }
54 |
55 | inViewport(el, index) {
56 | if(!this.cache || this.resizing) return
57 | const cache = this.cache[index]
58 | const current = this.vars.current
59 | const left = Math.round(cache.left - current)
60 | const right = Math.round(cache.right - current)
61 | const inview = right > 0 && left < this.vars.width
62 | if(inview) {
63 | if(!el.state) {
64 | el.innerHTML = 'in viewport'
65 | el.state = true
66 | }
67 | } else {
68 | el.state = false
69 | el.innerHTML = ''
70 | }
71 | }
72 | }
73 |
74 | export default Parallax
--------------------------------------------------------------------------------
/demos/split/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 | import css from 'dom-css'
3 |
4 | class Split extends Smooth {
5 |
6 | constructor(opt) {
7 | super(opt)
8 | this.createExtraBound()
9 | this.sections = null
10 | this.dom.sections = Array.prototype.slice.call(opt.sections, 0)
11 | }
12 |
13 | createExtraBound() {
14 | ['getCache', 'inViewport']
15 | .forEach((fn) => this[fn] = this[fn].bind(this))
16 | }
17 |
18 | resize() {
19 | this.dom.sections.forEach((el, index) => css(el, {
20 | 'display': 'block',
21 | 'position': 'relative',
22 | 'top': 0,
23 | 'transform': 'none'
24 | }))
25 | this.vars.bounding = this.dom.sections[this.dom.sections.length - 1].getBoundingClientRect().bottom - (this.vars.native ? 0 : this.vars.height)
26 | css(this.dom.section, 'height', this.vars.bounding)
27 | this.getCache()
28 | this.dom.sections.forEach((el, index) => css(el, {
29 | 'position': 'fixed',
30 | 'width': '100%',
31 | 'top': this.sections[index].top
32 | }))
33 | super.resize()
34 | }
35 |
36 | getCache() {
37 | this.sections = []
38 | this.dom.sections.forEach((el, index) => {
39 | const bounding = el.getBoundingClientRect();
40 | const bounds = {
41 | el: el,
42 | state: true,
43 | top: bounding.top,
44 | bottom: bounding.bottom,
45 | speed: '-1'
46 | }
47 | this.sections.push(bounds)
48 | })
49 | }
50 |
51 | run() {
52 | this.dom.sections.forEach(this.inViewport)
53 | super.run()
54 | }
55 |
56 | inViewport(el, index) {
57 | if(!this.sections) return
58 | const cache = this.sections[index]
59 | const current = this.vars.current
60 | const transform = current * cache.speed
61 | const top = Math.round(cache.top + transform)
62 | const bottom = Math.round(cache.bottom + transform)
63 | const inview = bottom > 0 && top < this.vars.height
64 | if(inview) {
65 | // !cache.state && (this.dom.section.appendChild(cache.el), cache.state = true);
66 | el.style.display = 'block'
67 | el.style[this.prefix] = this.getTransform(transform)
68 | } else {
69 | el.style.display = 'none'
70 | el.style[this.prefix] = 'none'
71 | // cache.state && cache.el.parentNode && (cache.el.parentNode.removeChild(cache.el), cache.state = false);
72 | }
73 | }
74 | }
75 |
76 | export default Split
--------------------------------------------------------------------------------
/demos/parallax/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Parallax extends Smooth {
4 |
5 | constructor(opt) {
6 | super(opt)
7 | this.createExtraBound()
8 | this.resizing = false
9 | this.cache = null
10 | this.dom.divs = Array.prototype.slice.call(opt.divs, 0)
11 | }
12 |
13 | createExtraBound() {
14 | ['getCache', 'inViewport']
15 | .forEach((fn) => this[fn] = this[fn].bind(this))
16 | }
17 |
18 | init() {
19 | super.init()
20 | }
21 |
22 | resize() {
23 | this.resizing = true
24 | this.reset()
25 | this.getCache()
26 | super.resize()
27 | this.resizing = false
28 | }
29 |
30 | reset() {
31 | if(!this.cache) return
32 | this.dom.divs.forEach((el, index) => {
33 | const cache = this.cache[index]
34 | !cache.state && (document.body.appendChild(cache.el), cache.state = true)
35 | el.style.display = 'block'
36 | })
37 | }
38 |
39 | getCache() {
40 | this.cache = []
41 | this.dom.divs.forEach((el, index) => {
42 | el.style.display = 'block'
43 | el.style.transform = 'none'
44 | const bounding = el.getBoundingClientRect()
45 | const bounds = {
46 | el: el,
47 | state: true,
48 | top: bounding.top,
49 | left: bounding.left,
50 | bottom: bounding.bottom,
51 | speed: el.getAttribute('data-speed') || '-1'
52 | }
53 | this.vars.bounding = bounding.bottom > this.vars.bounding ? bounding.bottom - window.innerHeight : this.vars.bounding
54 | this.cache.push(bounds)
55 | })
56 | }
57 |
58 | run() {
59 | this.dom.divs.forEach(this.inViewport)
60 | super.run()
61 | }
62 |
63 | inViewport(el, index) {
64 | if(!this.cache || this.resizing) return
65 | const cache = this.cache[index]
66 | const current = this.vars.current
67 | const transform = current * cache.speed
68 | const top = Math.round(cache.top + transform)
69 | const bottom = Math.round(cache.bottom + transform)
70 | const inview = bottom > -100 && top < this.vars.height + 100
71 | if(inview) {
72 | !cache.state && (document.body.appendChild(cache.el), cache.state = true)
73 | el.style.display = 'block'
74 | el.style[this.prefix] = this.getTransform(transform)
75 | } else {
76 | // el.style.display = 'none'
77 | // el.style[this.prefix] = 'none'
78 | cache.state && cache.el.parentNode && (cache.el.parentNode.removeChild(cache.el), cache.state = false)
79 | }
80 | }
81 | }
82 |
83 | export default Parallax
--------------------------------------------------------------------------------
/demos/parallax-page/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Parallax extends Smooth {
4 |
5 | constructor(opt) {
6 | super(opt)
7 | this.createExtraBound()
8 | this.resizing = false
9 | this.cache = null
10 | this.dom.divs = Array.prototype.slice.call(opt.divs, 0)
11 | }
12 |
13 | createExtraBound() {
14 | ['getCache', 'inViewport']
15 | .forEach((fn) => this[fn] = this[fn].bind(this))
16 | }
17 |
18 | resize() {
19 | this.resizing = true
20 | this.getCache()
21 | super.resize()
22 | this.resizing = false
23 | }
24 |
25 | getCache() {
26 | this.cache = []
27 | this.dom.divs.forEach((el, index) => {
28 | el.style.display = 'block'
29 | el.style.transform = 'none'
30 | const scrollY = this.vars.target
31 | const bounding = el.getBoundingClientRect()
32 | const bounds = {
33 | el: el,
34 | state: true,
35 | top: bounding.top + scrollY,
36 | left: bounding.left,
37 | center: bounding.height / 2,
38 | bottom: bounding.bottom + scrollY,
39 | speed: el.getAttribute('data-speed') || '-1'
40 | }
41 | if(index === 4) {
42 | console.log(bounding.top, scrollY, bounds.top)
43 | }
44 | // this.vars.bounding = bounding.bottom > this.vars.bounding ? bounding.bottom - window.innerHeight : this.vars.bounding;
45 | this.cache.push(bounds)
46 | })
47 | // get bounding value based on the container (.vs-section) height
48 | this.vars.bounding = this.dom.section.getBoundingClientRect().height - (this.vars.native ? 0 : this.vars.height)
49 | }
50 |
51 | run() {
52 | this.dom.divs.forEach(this.inViewport)
53 | this.dom.section.style[this.prefix] = this.getTransform(this.vars.current * -1)
54 | super.run()
55 | }
56 |
57 | inViewport(el, index) {
58 | if(!this.cache || this.resizing) return
59 | const cache = this.cache[index]
60 | const current = this.vars.current
61 | const transform = ((cache.top + cache.center) - current) * cache.speed
62 | const top = Math.round((cache.top + transform) - current)
63 | const bottom = Math.round((cache.bottom + transform) - current)
64 | const inview = bottom > 0 && top < this.vars.height
65 | if(inview) {
66 | el.style.border = '2px solid green'
67 | el.style.display = 'block'
68 | el.style[this.prefix] = this.getTransform(transform)
69 | } else {
70 | // add red border if out of viewport
71 | el.style.border = '2px solid red'
72 | }
73 | }
74 | }
75 |
76 | export default Parallax
--------------------------------------------------------------------------------
/demos/horizontal/custom.js:
--------------------------------------------------------------------------------
1 | import Smooth from '../../index'
2 |
3 | class Parallax extends Smooth {
4 |
5 | constructor(opt) {
6 |
7 | super(opt)
8 |
9 | this.createExtraBound()
10 |
11 | this.resizing = false
12 | this.cache = null
13 | this.dom.divs = Array.prototype.slice.call(opt.divs, 0)
14 | }
15 |
16 | createExtraBound() {
17 |
18 | ['getCache', 'inViewport']
19 | .forEach((fn) => this[fn] = this[fn].bind(this))
20 | }
21 |
22 | resize() {
23 |
24 | this.resizing = true
25 |
26 | this.getCache()
27 | super.resize()
28 |
29 | this.resizing = false
30 | }
31 |
32 | getCache() {
33 |
34 | this.cache = []
35 |
36 | const unit = (this.vars.width / 3)
37 |
38 | this.dom.divs.forEach((el, index) => {
39 |
40 | el.style.display = 'inline-block'
41 | el.style.transform = 'none'
42 | el.style.width = `${unit}px`
43 |
44 | const scrollX = this.vars.target
45 | const bounding = el.getBoundingClientRect()
46 | const bounds = {
47 | el: el,
48 | state: true,
49 | left: bounding.left + scrollX,
50 | right: bounding.right + scrollX,
51 | center: unit / 2
52 | }
53 |
54 | this.cache.push(bounds)
55 | })
56 |
57 | this.dom.section.style.width = `${this.vars.width}px`
58 | this.vars.bounding = (unit * this.dom.divs.length) - this.vars.width
59 | }
60 |
61 | run() {
62 |
63 | this.dom.divs.forEach(this.inViewport);
64 |
65 | this.dom.section.style[this.prefix] = this.getTransform(this.vars.current * -1)
66 |
67 | super.run()
68 | }
69 |
70 | inViewport(el, index) {
71 |
72 | if(!this.cache || this.resizing) return
73 |
74 | const cache = this.cache[index]
75 | const current = this.vars.current
76 | const left = Math.round(cache.left - current)
77 | const right = Math.round(cache.right - current)
78 | const inview = right > 0 && left < this.vars.width
79 |
80 | if(inview) {
81 |
82 | if(!el.state) {
83 | el.innerHTML = 'in viewport'
84 | el.state = true
85 | }
86 |
87 | } else {
88 |
89 | el.state = false
90 | el.innerHTML = ''
91 | }
92 | }
93 | }
94 |
95 | export default Parallax
--------------------------------------------------------------------------------
/demos/gsap/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | gsap scrolltrigger demo | smooth-scrolling
7 |
8 |
38 |
39 |
40 |
41 |

42 |

43 |

44 |

45 |

46 |

47 |
48 |
49 |
50 |
51 |
108 |
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # smooth
2 |
3 | Smooth is a small JavaScript module based on [VirtualScroll](http://www.everyday3d.com/blog/index.php/2014/08/18/smooth-scrolling-with-virtualscroll/) to create smooth scrolling and parallax effects on scroll.
4 | It works both with fake scrollbars and native scrolling.
5 |
6 | ### Usage
7 |
8 | `npm install smooth-scrolling`
9 |
10 | ```javascript
11 | import Smooth from 'smooth-scrolling'
12 |
13 | const section = document.querySelector('.vs-section')
14 | const smooth = new Smooth({
15 | native: true,
16 | section: section,
17 | ease: 0.1
18 | })
19 |
20 | smooth.init()
21 | ```
22 |
23 | ### Options
24 |
25 | - `listener`: on-scroll events listener & parent container for all elements
26 | - `direction` : vertical or horizontal scrolling behavior
27 | - `native`: use the default scrollbar
28 | - `section` : the element to transform
29 | - `ease` : the easing value (usually between 0 and 1)
30 | - `vs` : you can pass some option for virtuall-scroll: limitInertia, mouseMultiplier, etc
31 | - `preload` : if set to false, there will be no resize function called after all images loaded
32 | - `noscrollbar` : if using virtual-scroll and set to true, it will not build a custom scrollbar
33 | - `callback`: function called on requestAnimationFrame
34 |
35 | ### Methods
36 |
37 | #### `smooth.init()`
38 |
39 | Will add all event listeners and DOM elements.
40 |
41 | #### `smooth.on()`
42 |
43 | Will listen to either window scroll event (if native), otherwise VirtualScroll
44 |
45 | #### `smooth.off()`
46 |
47 | Will stop listening to onscroll/wheel events.
48 |
49 | #### `smooth.destroy()`
50 |
51 | Will remove all event listeners and DOM elements.
52 |
53 | #### `smooth.scrollTo(offset)`
54 |
55 | Basic scrollTo function.
56 |
57 | ### Extends Smooth
58 |
59 | ```javascript
60 | import Smooth from 'smooth-scrolling'
61 |
62 | class Custom extends Smooth {
63 |
64 | constructor(opt = {}) {
65 | super(opt)
66 | this.dom.section = opt.section
67 | this.dom.opacity = opt.opacity
68 | }
69 |
70 | run() {
71 | super.run()
72 |
73 | const current = Math.round(Math.abs(this.vars.current))
74 | const opacity = Math.max(0, Math.min(1 - current / (this.vars.height * .5), 1))
75 |
76 | this.dom.opacity.style.opacity = opacity.toFixed(2)
77 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2))
78 | }
79 |
80 | resize() {
81 | this.vars.bounding = this.dom.section.getBoundingClientRect().height - this.vars.height
82 | super.resize()
83 | }
84 | }
85 |
86 | export default Custom
87 | ```
88 |
89 | ```javascript
90 | // ...and later on
91 | import Custom from './custom-smooth-scrolling'
92 |
93 | const section = document.querySelector('.vs-section')
94 | const opacity = document.querySelector('.vs-opacity')
95 |
96 | const smooth = new Custom({
97 | section: section,
98 | opacity: opacity,
99 | ease: 0.1
100 | })
101 |
102 | smooth.init()
103 | ```
104 |
105 | ### Development
106 |
107 | `git clone git@github.com:baptistebriel/smooth-scrolling.git`
108 |
109 | `cd smooth-scrolling/ && npm i && npm run dev`
110 |
111 | You can use `[http-server](https://www.npmjs.com/package/http-server)` or [MAMP](https://www.mamp.info) to preview the demos.
112 |
113 | ### Demos
114 |
115 | `npm run demo-parallax`
116 |
117 | `npm run demo-parallax-page`
118 |
119 | `npm run demo-horizontal`
120 |
121 | `npm run demo-native-horizontal`
122 |
123 | `npm run demo-opacity`
124 |
125 | `npm run demo-scale`
126 |
127 | `npm run demo-split`
128 |
129 | `npm run demo-performances`
130 |
131 | ### Examples
132 |
133 | - [etq.store](http://etq.store)
134 | - [femmefatale.paris](http://femmefatale.paris)
135 | - [buildin.amsterdam](http://buildin.amsterdam)
136 | - [romainpsd.com](https://romainpsd.com)
137 | - [flavinsky.com](http://flavinsky.com)
138 | - [alisharaf.com](http://alisharaf.com)
139 | - [bbriel.me](http://bbriel.me)
140 | - [studiochevojon.com](http://studiochevojon.com)
141 | - [andeinerseite.video](http://andeinerseite.video)
142 | - [eginstill.com](http://eginstill.com)
143 | - [blackballoon.fr](http://www.blackballoon.fr)
144 | - & more to come!
145 |
146 | ## Further understanding
147 |
148 | If you didn't already read [the tutorial](http://www.everyday3d.com/blog/index.php/2014/08/18/smooth-scrolling-with-virtualscroll/), I highly recommend it.
149 | Smooth.js is basically what's explained on the blog post. I just needed a simple script to get things done without having to write lots of code every time I wanted to use this technique.
150 |
151 | ## License
152 |
153 | MIT, see [LICENSE.md](https://github.com/BaptisteBriel/smooth/blob/master/LICENSE).
154 |
--------------------------------------------------------------------------------
/demos/split/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | split view demo | smooth-scrolling
7 |
8 |
23 |
24 |
25 |
26 |
27 |

28 |
29 |
30 |

31 |
32 |
33 |

34 |
35 |
36 |

37 |
38 |
39 |

40 |
41 |
42 |

43 |
44 |
45 |

46 |
47 |
48 |

49 |
50 |
51 |

52 |
53 |
54 |

55 |
56 |
57 |

58 |
59 |
60 |

61 |
62 |
63 |

64 |
65 |
66 |

67 |
68 |
69 |

70 |
71 |
72 |

73 |
74 |
75 |

76 |
77 |
78 |

79 |
80 |
81 |

82 |
83 |
84 |

85 |
86 |
87 |

88 |
89 |
90 |

91 |
92 |
93 |

94 |
95 |
96 |

97 |
98 |
99 |

100 |
101 |
102 |

103 |
104 |
105 |

106 |
107 |
108 |

109 |
110 |
111 |

112 |
113 |
114 |

115 |
116 |
117 |

118 |
119 |
120 |

121 |
122 |
123 |

124 |
125 |
126 |

127 |
128 |
129 |

130 |
131 |
132 |

133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import classes from 'dom-classes'
2 | import create from 'dom-create-element'
3 | import prefix from 'prefix'
4 | import vs from 'virtual-scroll'
5 | import event from 'dom-events'
6 |
7 | export default class Smooth {
8 |
9 | constructor(opt = {}) {
10 | this.createBound()
11 | this.options = opt
12 | this.prefix = prefix('transform')
13 | this.rAF = undefined
14 | // It seems that under heavy load, Firefox will still call the RAF callback even though the RAF has been canceled
15 | // To prevent that we set a flag to prevent any callback to be executed when RAF is removed
16 | this.isRAFCanceled = false
17 | const constructorName = this.constructor.name ? this.constructor.name : 'Smooth'
18 | this.extends = typeof opt.extends === 'undefined' ? this.constructor !== Smooth : opt.extends
19 | this.callback = this.options.callback || null
20 | this.vars = {
21 | direction: this.options.direction || 'vertical',
22 | native: this.options.native || false,
23 | ease: this.options.ease || 0.075,
24 | preload: this.options.preload || false,
25 | current: 0,
26 | last: 0,
27 | target: 0,
28 | height: window.innerHeight,
29 | width: window.innerWidth,
30 | bounding: 0,
31 | timer: null,
32 | ticking: false
33 | }
34 | this.vs = this.vars.native ? null : new vs({
35 | limitInertia: this.options.vs && this.options.vs.limitInertia || false,
36 | mouseMultiplier: this.options.vs && this.options.vs.mouseMultiplier || 1,
37 | touchMultiplier: this.options.vs && this.options.vs.touchMultiplier || 1.5,
38 | firefoxMultiplier: this.options.vs && this.options.vs.firefoxMultiplier || 30,
39 | preventTouch: this.options.vs && this.options.vs.preventTouch || true
40 | })
41 | this.dom = {
42 | listener: this.options.listener || document.body,
43 | section: this.options.section || document.querySelector('.vs-section') || null,
44 | scrollbar: this.vars.native || this.options.noscrollbar ? null : {
45 | state: {
46 | clicked: false,
47 | x: 0
48 | },
49 | el: create({ selector: 'div', styles: `vs-scrollbar vs-${this.vars.direction} vs-scrollbar-${constructorName.toLowerCase()}` }),
50 | drag: {
51 | el: create({ selector: 'div', styles: 'vs-scrolldrag' }),
52 | delta: 0,
53 | height: 50
54 | }
55 | }
56 | }
57 | }
58 |
59 | createBound() {
60 | ['run', 'calc', 'debounce', 'resize', 'mouseUp', 'mouseDown', 'mouseMove', 'calcScroll', 'scrollTo']
61 | .forEach((fn) => this[fn] = this[fn].bind(this));
62 | }
63 |
64 | init() {
65 | this.addClasses()
66 | this.vars.preload && this.preloadImages()
67 | this.vars.native ? this.addFakeScrollHeight() : !this.options.noscrollbar && this.addFakeScrollBar()
68 | this.addEvents()
69 | this.resize()
70 | }
71 |
72 | addClasses() {
73 | const type = this.vars.native ? 'native' : 'virtual'
74 | const direction = this.vars.direction === 'vertical' ? 'y' : 'x'
75 | classes.add(this.dom.listener, `is-${type}-scroll`)
76 | classes.add(this.dom.listener, `${direction}-scroll`)
77 | }
78 |
79 | preloadImages() {
80 | const images = Array.prototype.slice.call(this.dom.listener.querySelectorAll('img'), 0)
81 | images.forEach((image) => {
82 | const img = document.createElement('img')
83 | event.once(img, 'load', () => {
84 | images.splice(images.indexOf(image), 1)
85 | images.length === 0 && this.resize()
86 | })
87 | img.src = image.getAttribute('src')
88 | })
89 | }
90 |
91 | calc(e) {
92 | const delta = this.vars.direction == 'horizontal' ? e.deltaX : e.deltaY
93 | this.vars.target += delta * -1
94 | this.clampTarget()
95 | }
96 |
97 | debounce() {
98 | const win = this.dom.listener === document.body
99 | this.vars.target = this.vars.direction === 'vertical' ? win ? window.scrollY || window.pageYOffset : this.dom.listener.scrollTop : win ? window.scrollX || window.pageXOffset : this.dom.listener.scrollLeft
100 | clearTimeout(this.vars.timer)
101 | if(!this.vars.ticking) {
102 | this.vars.ticking = true;
103 | classes.add(this.dom.listener, 'is-scrolling')
104 | }
105 | this.vars.timer = setTimeout(() => {
106 | this.vars.ticking = false
107 | classes.remove(this.dom.listener, 'is-scrolling')
108 | }, 200)
109 | }
110 |
111 | run() {
112 | if (this.isRAFCanceled) return
113 | this.vars.current += (this.vars.target - this.vars.current) * this.vars.ease
114 | this.vars.current < .1 && (this.vars.current = 0)
115 | this.requestAnimationFrame()
116 | if(!this.extends){
117 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2))
118 | }
119 | if(!this.vars.native && !this.options.noscrollbar) {
120 | const size = this.dom.scrollbar.drag.height
121 | const bounds = this.vars.direction === 'vertical' ? this.vars.height : this.vars.width
122 | const value = (Math.abs(this.vars.current) / (this.vars.bounding / (bounds - size))) + (size / .5) - size
123 | const clamp = Math.max(0, Math.min(value-size, value+size))
124 | this.dom.scrollbar.drag.el.style[this.prefix] = this.getTransform(clamp.toFixed(2))
125 | }
126 | if (this.callback && this.vars.current !== this.vars.last) {
127 | this.callback(this.vars.current)
128 | }
129 | this.vars.last = this.vars.current
130 | }
131 |
132 | getTransform(value) {
133 | return this.vars.direction === 'vertical' ? `translate3d(0,${value}px,0)` : `translate3d(${value}px,0,0)`
134 | }
135 |
136 | on(requestAnimationFrame = true) {
137 | if (this.isRAFCanceled) {
138 | this.isRAFCanceled = false
139 | }
140 | const node = this.dom.listener === document.body ? window : this.dom.listener
141 | this.vars.native ? event.on(node, 'scroll', this.debounce) : (this.vs && this.vs.on(this.calc))
142 | requestAnimationFrame && this.requestAnimationFrame()
143 | }
144 |
145 | off(cancelAnimationFrame = true) {
146 | const node = this.dom.listener === document.body ? window : this.dom.listener
147 | this.vars.native ? event.off(node, 'scroll', this.debounce) : (this.vs && this.vs.off(this.calc))
148 | cancelAnimationFrame && this.cancelAnimationFrame()
149 | }
150 |
151 | requestAnimationFrame() {
152 | this.rAF = requestAnimationFrame(this.run)
153 | }
154 |
155 | cancelAnimationFrame() {
156 | this.isRAFCanceled = true
157 | cancelAnimationFrame(this.rAF)
158 | }
159 |
160 | addEvents() {
161 | this.on()
162 | event.on(window, 'resize', this.resize)
163 | }
164 |
165 | removeEvents() {
166 | this.off()
167 | event.off(window, 'resize', this.resize)
168 | }
169 |
170 | addFakeScrollBar() {
171 | this.dom.listener.appendChild(this.dom.scrollbar.el)
172 | this.dom.scrollbar.el.appendChild(this.dom.scrollbar.drag.el)
173 | event.on(this.dom.scrollbar.el, 'click', this.calcScroll)
174 | event.on(this.dom.scrollbar.el, 'mousedown', this.mouseDown)
175 | event.on(document, 'mousemove', this.mouseMove)
176 | event.on(document, 'mouseup', this.mouseUp)
177 | }
178 |
179 | removeFakeScrollBar() {
180 | event.off(this.dom.scrollbar.el, 'click', this.calcScroll)
181 | event.off(this.dom.scrollbar.el, 'mousedown', this.mouseDown)
182 | event.off(document, 'mousemove', this.mouseMove)
183 | event.off(document, 'mouseup', this.mouseUp)
184 | this.dom.listener.removeChild(this.dom.scrollbar.el)
185 | }
186 |
187 | mouseDown(e) {
188 | e.preventDefault()
189 | e.which == 1 && (this.dom.scrollbar.state.clicked = true)
190 | }
191 |
192 | mouseUp(e) {
193 | this.dom.scrollbar.state.clicked = false
194 | classes.remove(this.dom.listener, 'is-dragging')
195 | }
196 |
197 | mouseMove(e) {
198 | this.dom.scrollbar.state.clicked && this.calcScroll(e)
199 | }
200 |
201 | addFakeScrollHeight() {
202 | this.dom.scroll = create({
203 | selector: 'div',
204 | styles: 'vs-scroll-view'
205 | })
206 | this.dom.listener.appendChild(this.dom.scroll)
207 | }
208 |
209 | removeFakeScrollHeight() {
210 | this.dom.listener.removeChild(this.dom.scroll)
211 | }
212 |
213 | calcScroll(e) {
214 | const client = this.vars.direction == 'vertical' ? e.clientY : e.clientX
215 | const bounds = this.vars.direction == 'vertical' ? this.vars.height : this.vars.width
216 | const delta = client * (this.vars.bounding / bounds)
217 | classes.add(this.dom.listener, 'is-dragging')
218 | this.vars.target = delta
219 | this.clampTarget()
220 | this.dom.scrollbar && (this.dom.scrollbar.drag.delta = this.vars.target)
221 | }
222 |
223 | scrollTo(offset) {
224 | if(this.vars.native) {
225 | this.vars.direction == 'vertical' ? window.scrollTo(0, offset) : window.scrollTo(offset, 0)
226 | } else {
227 | this.vars.target = offset
228 | this.clampTarget()
229 | }
230 | }
231 |
232 | resize() {
233 | const prop = this.vars.direction === 'vertical' ? 'height' : 'width';
234 | this.vars.height = window.innerHeight
235 | this.vars.width = window.innerWidth
236 | if(!this.extends) {
237 | const bounding = this.dom.section.getBoundingClientRect()
238 | this.vars.bounding = this.vars.direction === 'vertical' ? bounding.height - (this.vars.native ? 0 : this.vars.height) : bounding.right - (this.vars.native ? 0 : this.vars.width)
239 | }
240 | if(!this.vars.native && !this.options.noscrollbar) {
241 | this.dom.scrollbar.drag.height = this.vars.height * (this.vars.height / (this.vars.bounding + this.vars.height))
242 | this.dom.scrollbar.drag.el.style[prop] = `${this.dom.scrollbar.drag.height}px`
243 | } else if(this.vars.native) {
244 | this.dom.scroll.style[prop] = `${this.vars.bounding}px`
245 | }
246 | !this.vars.native && this.clampTarget();
247 | }
248 |
249 | clampTarget() {
250 | this.vars.target = Math.round(Math.max(0, Math.min(this.vars.target, this.vars.bounding)))
251 | }
252 |
253 | destroy() {
254 | if(this.vars.native) {
255 | classes.remove(this.dom.listener, 'is-native-scroll')
256 | this.removeFakeScrollHeight()
257 | } else {
258 | classes.remove(this.dom.listener, 'is-virtual-scroll')
259 | !this.options.noscrollbar && this.removeFakeScrollBar()
260 | }
261 | this.vars.direction === 'vertical' ? classes.remove(this.dom.listener, 'y-scroll') : classes.remove(this.dom.listener, 'x-scroll')
262 | this.vars.current = 0
263 | this.vs && (this.vs.destroy(), this.vs = null)
264 | this.removeEvents()
265 | }
266 | }
267 |
268 | window.Smooth = Smooth
--------------------------------------------------------------------------------
/smooth-scrolling.js:
--------------------------------------------------------------------------------
1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {};
32 |
33 | _classCallCheck(this, Smooth);
34 |
35 | this.createBound();
36 | this.options = opt;
37 | this.prefix = (0, _prefix["default"])('transform');
38 | this.rAF = undefined; // It seems that under heavy load, Firefox will still call the RAF callback even though the RAF has been canceled
39 | // To prevent that we set a flag to prevent any callback to be executed when RAF is removed
40 |
41 | this.isRAFCanceled = false;
42 | var constructorName = this.constructor.name ? this.constructor.name : 'Smooth';
43 | this["extends"] = typeof opt["extends"] === 'undefined' ? this.constructor !== Smooth : opt["extends"];
44 | this.callback = this.options.callback || null;
45 | this.vars = {
46 | direction: this.options.direction || 'vertical',
47 | "native": this.options["native"] || false,
48 | ease: this.options.ease || 0.075,
49 | preload: this.options.preload || false,
50 | current: 0,
51 | last: 0,
52 | target: 0,
53 | height: window.innerHeight,
54 | width: window.innerWidth,
55 | bounding: 0,
56 | timer: null,
57 | ticking: false
58 | };
59 | this.vs = this.vars["native"] ? null : new _virtualScroll["default"]({
60 | limitInertia: this.options.vs && this.options.vs.limitInertia || false,
61 | mouseMultiplier: this.options.vs && this.options.vs.mouseMultiplier || 1,
62 | touchMultiplier: this.options.vs && this.options.vs.touchMultiplier || 1.5,
63 | firefoxMultiplier: this.options.vs && this.options.vs.firefoxMultiplier || 30,
64 | preventTouch: this.options.vs && this.options.vs.preventTouch || true
65 | });
66 | this.dom = {
67 | listener: this.options.listener || document.body,
68 | section: this.options.section || document.querySelector('.vs-section') || null,
69 | scrollbar: this.vars["native"] || this.options.noscrollbar ? null : {
70 | state: {
71 | clicked: false,
72 | x: 0
73 | },
74 | el: (0, _domCreateElement["default"])({
75 | selector: 'div',
76 | styles: "vs-scrollbar vs-".concat(this.vars.direction, " vs-scrollbar-").concat(constructorName.toLowerCase())
77 | }),
78 | drag: {
79 | el: (0, _domCreateElement["default"])({
80 | selector: 'div',
81 | styles: 'vs-scrolldrag'
82 | }),
83 | delta: 0,
84 | height: 50
85 | }
86 | }
87 | };
88 | }
89 |
90 | _createClass(Smooth, [{
91 | key: "createBound",
92 | value: function createBound() {
93 | var _this = this;
94 |
95 | ['run', 'calc', 'debounce', 'resize', 'mouseUp', 'mouseDown', 'mouseMove', 'calcScroll', 'scrollTo'].forEach(function (fn) {
96 | return _this[fn] = _this[fn].bind(_this);
97 | });
98 | }
99 | }, {
100 | key: "init",
101 | value: function init() {
102 | this.addClasses();
103 | this.vars.preload && this.preloadImages();
104 | this.vars["native"] ? this.addFakeScrollHeight() : !this.options.noscrollbar && this.addFakeScrollBar();
105 | this.addEvents();
106 | this.resize();
107 | }
108 | }, {
109 | key: "addClasses",
110 | value: function addClasses() {
111 | var type = this.vars["native"] ? 'native' : 'virtual';
112 | var direction = this.vars.direction === 'vertical' ? 'y' : 'x';
113 |
114 | _domClasses["default"].add(this.dom.listener, "is-".concat(type, "-scroll"));
115 |
116 | _domClasses["default"].add(this.dom.listener, "".concat(direction, "-scroll"));
117 | }
118 | }, {
119 | key: "preloadImages",
120 | value: function preloadImages() {
121 | var _this2 = this;
122 |
123 | var images = Array.prototype.slice.call(this.dom.listener.querySelectorAll('img'), 0);
124 | images.forEach(function (image) {
125 | var img = document.createElement('img');
126 |
127 | _domEvents["default"].once(img, 'load', function () {
128 | images.splice(images.indexOf(image), 1);
129 | images.length === 0 && _this2.resize();
130 | });
131 |
132 | img.src = image.getAttribute('src');
133 | });
134 | }
135 | }, {
136 | key: "calc",
137 | value: function calc(e) {
138 | var delta = this.vars.direction == 'horizontal' ? e.deltaX : e.deltaY;
139 | this.vars.target += delta * -1;
140 | this.clampTarget();
141 | }
142 | }, {
143 | key: "debounce",
144 | value: function debounce() {
145 | var _this3 = this;
146 |
147 | var win = this.dom.listener === document.body;
148 | this.vars.target = this.vars.direction === 'vertical' ? win ? window.scrollY || window.pageYOffset : this.dom.listener.scrollTop : win ? window.scrollX || window.pageXOffset : this.dom.listener.scrollLeft;
149 | clearTimeout(this.vars.timer);
150 |
151 | if (!this.vars.ticking) {
152 | this.vars.ticking = true;
153 |
154 | _domClasses["default"].add(this.dom.listener, 'is-scrolling');
155 | }
156 |
157 | this.vars.timer = setTimeout(function () {
158 | _this3.vars.ticking = false;
159 |
160 | _domClasses["default"].remove(_this3.dom.listener, 'is-scrolling');
161 | }, 200);
162 | }
163 | }, {
164 | key: "run",
165 | value: function run() {
166 | if (this.isRAFCanceled) return;
167 | this.vars.current += (this.vars.target - this.vars.current) * this.vars.ease;
168 | this.vars.current < .1 && (this.vars.current = 0);
169 | this.requestAnimationFrame();
170 |
171 | if (!this["extends"]) {
172 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2));
173 | }
174 |
175 | if (!this.vars["native"] && !this.options.noscrollbar) {
176 | var size = this.dom.scrollbar.drag.height;
177 | var bounds = this.vars.direction === 'vertical' ? this.vars.height : this.vars.width;
178 | var value = Math.abs(this.vars.current) / (this.vars.bounding / (bounds - size)) + size / .5 - size;
179 | var clamp = Math.max(0, Math.min(value - size, value + size));
180 | this.dom.scrollbar.drag.el.style[this.prefix] = this.getTransform(clamp.toFixed(2));
181 | }
182 |
183 | if (this.callback && this.vars.current !== this.vars.last) {
184 | this.callback(this.vars.current);
185 | }
186 |
187 | this.vars.last = this.vars.current;
188 | }
189 | }, {
190 | key: "getTransform",
191 | value: function getTransform(value) {
192 | return this.vars.direction === 'vertical' ? "translate3d(0,".concat(value, "px,0)") : "translate3d(".concat(value, "px,0,0)");
193 | }
194 | }, {
195 | key: "on",
196 | value: function on() {
197 | var requestAnimationFrame = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
198 |
199 | if (this.isRAFCanceled) {
200 | this.isRAFCanceled = false;
201 | }
202 |
203 | var node = this.dom.listener === document.body ? window : this.dom.listener;
204 | this.vars["native"] ? _domEvents["default"].on(node, 'scroll', this.debounce) : this.vs && this.vs.on(this.calc);
205 | requestAnimationFrame && this.requestAnimationFrame();
206 | }
207 | }, {
208 | key: "off",
209 | value: function off() {
210 | var cancelAnimationFrame = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
211 | var node = this.dom.listener === document.body ? window : this.dom.listener;
212 | this.vars["native"] ? _domEvents["default"].off(node, 'scroll', this.debounce) : this.vs && this.vs.off(this.calc);
213 | cancelAnimationFrame && this.cancelAnimationFrame();
214 | }
215 | }, {
216 | key: "requestAnimationFrame",
217 | value: function (_requestAnimationFrame) {
218 | function requestAnimationFrame() {
219 | return _requestAnimationFrame.apply(this, arguments);
220 | }
221 |
222 | requestAnimationFrame.toString = function () {
223 | return _requestAnimationFrame.toString();
224 | };
225 |
226 | return requestAnimationFrame;
227 | }(function () {
228 | this.rAF = requestAnimationFrame(this.run);
229 | })
230 | }, {
231 | key: "cancelAnimationFrame",
232 | value: function (_cancelAnimationFrame) {
233 | function cancelAnimationFrame() {
234 | return _cancelAnimationFrame.apply(this, arguments);
235 | }
236 |
237 | cancelAnimationFrame.toString = function () {
238 | return _cancelAnimationFrame.toString();
239 | };
240 |
241 | return cancelAnimationFrame;
242 | }(function () {
243 | this.isRAFCanceled = true;
244 | cancelAnimationFrame(this.rAF);
245 | })
246 | }, {
247 | key: "addEvents",
248 | value: function addEvents() {
249 | this.on();
250 |
251 | _domEvents["default"].on(window, 'resize', this.resize);
252 | }
253 | }, {
254 | key: "removeEvents",
255 | value: function removeEvents() {
256 | this.off();
257 |
258 | _domEvents["default"].off(window, 'resize', this.resize);
259 | }
260 | }, {
261 | key: "addFakeScrollBar",
262 | value: function addFakeScrollBar() {
263 | this.dom.listener.appendChild(this.dom.scrollbar.el);
264 | this.dom.scrollbar.el.appendChild(this.dom.scrollbar.drag.el);
265 |
266 | _domEvents["default"].on(this.dom.scrollbar.el, 'click', this.calcScroll);
267 |
268 | _domEvents["default"].on(this.dom.scrollbar.el, 'mousedown', this.mouseDown);
269 |
270 | _domEvents["default"].on(document, 'mousemove', this.mouseMove);
271 |
272 | _domEvents["default"].on(document, 'mouseup', this.mouseUp);
273 | }
274 | }, {
275 | key: "removeFakeScrollBar",
276 | value: function removeFakeScrollBar() {
277 | _domEvents["default"].off(this.dom.scrollbar.el, 'click', this.calcScroll);
278 |
279 | _domEvents["default"].off(this.dom.scrollbar.el, 'mousedown', this.mouseDown);
280 |
281 | _domEvents["default"].off(document, 'mousemove', this.mouseMove);
282 |
283 | _domEvents["default"].off(document, 'mouseup', this.mouseUp);
284 |
285 | this.dom.listener.removeChild(this.dom.scrollbar.el);
286 | }
287 | }, {
288 | key: "mouseDown",
289 | value: function mouseDown(e) {
290 | e.preventDefault();
291 | e.which == 1 && (this.dom.scrollbar.state.clicked = true);
292 | }
293 | }, {
294 | key: "mouseUp",
295 | value: function mouseUp(e) {
296 | this.dom.scrollbar.state.clicked = false;
297 |
298 | _domClasses["default"].remove(this.dom.listener, 'is-dragging');
299 | }
300 | }, {
301 | key: "mouseMove",
302 | value: function mouseMove(e) {
303 | this.dom.scrollbar.state.clicked && this.calcScroll(e);
304 | }
305 | }, {
306 | key: "addFakeScrollHeight",
307 | value: function addFakeScrollHeight() {
308 | this.dom.scroll = (0, _domCreateElement["default"])({
309 | selector: 'div',
310 | styles: 'vs-scroll-view'
311 | });
312 | this.dom.listener.appendChild(this.dom.scroll);
313 | }
314 | }, {
315 | key: "removeFakeScrollHeight",
316 | value: function removeFakeScrollHeight() {
317 | this.dom.listener.removeChild(this.dom.scroll);
318 | }
319 | }, {
320 | key: "calcScroll",
321 | value: function calcScroll(e) {
322 | var client = this.vars.direction == 'vertical' ? e.clientY : e.clientX;
323 | var bounds = this.vars.direction == 'vertical' ? this.vars.height : this.vars.width;
324 | var delta = client * (this.vars.bounding / bounds);
325 |
326 | _domClasses["default"].add(this.dom.listener, 'is-dragging');
327 |
328 | this.vars.target = delta;
329 | this.clampTarget();
330 | this.dom.scrollbar && (this.dom.scrollbar.drag.delta = this.vars.target);
331 | }
332 | }, {
333 | key: "scrollTo",
334 | value: function scrollTo(offset) {
335 | if (this.vars["native"]) {
336 | this.vars.direction == 'vertical' ? window.scrollTo(0, offset) : window.scrollTo(offset, 0);
337 | } else {
338 | this.vars.target = offset;
339 | this.clampTarget();
340 | }
341 | }
342 | }, {
343 | key: "resize",
344 | value: function resize() {
345 | var prop = this.vars.direction === 'vertical' ? 'height' : 'width';
346 | this.vars.height = window.innerHeight;
347 | this.vars.width = window.innerWidth;
348 |
349 | if (!this["extends"]) {
350 | var bounding = this.dom.section.getBoundingClientRect();
351 | this.vars.bounding = this.vars.direction === 'vertical' ? bounding.height - (this.vars["native"] ? 0 : this.vars.height) : bounding.right - (this.vars["native"] ? 0 : this.vars.width);
352 | }
353 |
354 | if (!this.vars["native"] && !this.options.noscrollbar) {
355 | this.dom.scrollbar.drag.height = this.vars.height * (this.vars.height / (this.vars.bounding + this.vars.height));
356 | this.dom.scrollbar.drag.el.style[prop] = "".concat(this.dom.scrollbar.drag.height, "px");
357 | } else if (this.vars["native"]) {
358 | this.dom.scroll.style[prop] = "".concat(this.vars.bounding, "px");
359 | }
360 |
361 | !this.vars["native"] && this.clampTarget();
362 | }
363 | }, {
364 | key: "clampTarget",
365 | value: function clampTarget() {
366 | this.vars.target = Math.round(Math.max(0, Math.min(this.vars.target, this.vars.bounding)));
367 | }
368 | }, {
369 | key: "destroy",
370 | value: function destroy() {
371 | if (this.vars["native"]) {
372 | _domClasses["default"].remove(this.dom.listener, 'is-native-scroll');
373 |
374 | this.removeFakeScrollHeight();
375 | } else {
376 | _domClasses["default"].remove(this.dom.listener, 'is-virtual-scroll');
377 |
378 | !this.options.noscrollbar && this.removeFakeScrollBar();
379 | }
380 |
381 | this.vars.direction === 'vertical' ? _domClasses["default"].remove(this.dom.listener, 'y-scroll') : _domClasses["default"].remove(this.dom.listener, 'x-scroll');
382 | this.vars.current = 0;
383 | this.vs && (this.vs.destroy(), this.vs = null);
384 | this.removeEvents();
385 | }
386 | }]);
387 |
388 | return Smooth;
389 | }();
390 |
391 | exports["default"] = Smooth;
392 | window.Smooth = Smooth;
393 |
394 | },{"dom-classes":3,"dom-create-element":4,"dom-events":5,"prefix":9,"virtual-scroll":15}],2:[function(require,module,exports){
395 | 'use strict';
396 |
397 | var toString = Object.prototype.toString,
398 | hasOwnProperty = Object.prototype.hasOwnProperty;
399 |
400 | module.exports = function(object) {
401 | if(!object) return console.warn('bindAll requires at least one argument.');
402 |
403 | var functions = Array.prototype.slice.call(arguments, 1);
404 |
405 | if (functions.length === 0) {
406 |
407 | for (var method in object) {
408 | if(hasOwnProperty.call(object, method)) {
409 | if(typeof object[method] == 'function' && toString.call(object[method]) == "[object Function]") {
410 | functions.push(method);
411 | }
412 | }
413 | }
414 | }
415 |
416 | for(var i = 0; i < functions.length; i++) {
417 | var f = functions[i];
418 | object[f] = bind(object[f], object);
419 | }
420 | };
421 |
422 | /*
423 | Faster bind without specific-case checking. (see https://coderwall.com/p/oi3j3w).
424 | bindAll is only needed for events binding so no need to make slow fixes for constructor
425 | or partial application.
426 | */
427 | function bind(func, context) {
428 | return function() {
429 | return func.apply(context, arguments);
430 | };
431 | }
432 | },{}],3:[function(require,module,exports){
433 | /**
434 | * Module dependencies.
435 | */
436 |
437 | var index = require('indexof');
438 |
439 | /**
440 | * Whitespace regexp.
441 | */
442 |
443 | var whitespaceRe = /\s+/;
444 |
445 | /**
446 | * toString reference.
447 | */
448 |
449 | var toString = Object.prototype.toString;
450 |
451 | module.exports = classes;
452 | module.exports.add = add;
453 | module.exports.contains = has;
454 | module.exports.has = has;
455 | module.exports.toggle = toggle;
456 | module.exports.remove = remove;
457 | module.exports.removeMatching = removeMatching;
458 |
459 | function classes (el) {
460 | if (el.classList) {
461 | return el.classList;
462 | }
463 |
464 | var str = el.className.replace(/^\s+|\s+$/g, '');
465 | var arr = str.split(whitespaceRe);
466 | if ('' === arr[0]) arr.shift();
467 | return arr;
468 | }
469 |
470 | function add (el, name) {
471 | // classList
472 | if (el.classList) {
473 | el.classList.add(name);
474 | return;
475 | }
476 |
477 | // fallback
478 | var arr = classes(el);
479 | var i = index(arr, name);
480 | if (!~i) arr.push(name);
481 | el.className = arr.join(' ');
482 | }
483 |
484 | function has (el, name) {
485 | return el.classList
486 | ? el.classList.contains(name)
487 | : !! ~index(classes(el), name);
488 | }
489 |
490 | function remove (el, name) {
491 | if ('[object RegExp]' == toString.call(name)) {
492 | return removeMatching(el, name);
493 | }
494 |
495 | // classList
496 | if (el.classList) {
497 | el.classList.remove(name);
498 | return;
499 | }
500 |
501 | // fallback
502 | var arr = classes(el);
503 | var i = index(arr, name);
504 | if (~i) arr.splice(i, 1);
505 | el.className = arr.join(' ');
506 | }
507 |
508 | function removeMatching (el, re, ref) {
509 | var arr = Array.prototype.slice.call(classes(el));
510 | for (var i = 0; i < arr.length; i++) {
511 | if (re.test(arr[i])) {
512 | remove(el, arr[i]);
513 | }
514 | }
515 | }
516 |
517 | function toggle (el, name) {
518 | // classList
519 | if (el.classList) {
520 | return el.classList.toggle(name);
521 | }
522 |
523 | // fallback
524 | if (has(el, name)) {
525 | remove(el, name);
526 | } else {
527 | add(el, name);
528 | }
529 | }
530 |
531 | },{"indexof":6}],4:[function(require,module,exports){
532 | /*
533 | `dom-create-element`
534 |
535 | var create = require('dom-create-element');
536 |
537 | var el = create({
538 | selector: 'div',
539 | styles: 'preloader',
540 | html: 'Text'
541 | });
542 | */
543 |
544 | module.exports = create;
545 |
546 | function create(opt) {
547 |
548 | opt = opt || {};
549 |
550 | var el = document.createElement(opt.selector);
551 |
552 | if(opt.attr) for(var index in opt.attr)
553 | opt.attr.hasOwnProperty(index) && el.setAttribute(index, opt.attr[index]);
554 |
555 | "a" == opt.selector && opt.link && (
556 | el.href = opt.link,
557 | opt.target && el.setAttribute("target", opt.target)
558 | );
559 |
560 | "img" == opt.selector && opt.src && (
561 | el.src = opt.src,
562 | opt.lazyload && (
563 | el.style.opacity = 0,
564 | el.onload = function(){
565 | el.style.opacity = 1;
566 | }
567 | )
568 | );
569 |
570 | opt.id && (el.id = opt.id);
571 | opt.styles && (el.className = opt.styles);
572 |
573 | opt.html && (el.innerHTML = opt.html);
574 | opt.children && (el.appendChild(opt.children));
575 |
576 | return el;
577 | };
578 | },{}],5:[function(require,module,exports){
579 |
580 | var synth = require('synthetic-dom-events');
581 |
582 | var on = function(element, name, fn, capture) {
583 | return element.addEventListener(name, fn, capture || false);
584 | };
585 |
586 | var off = function(element, name, fn, capture) {
587 | return element.removeEventListener(name, fn, capture || false);
588 | };
589 |
590 | var once = function (element, name, fn, capture) {
591 | function tmp (ev) {
592 | off(element, name, tmp, capture);
593 | fn(ev);
594 | }
595 | on(element, name, tmp, capture);
596 | };
597 |
598 | var emit = function(element, name, opt) {
599 | var ev = synth(name, opt);
600 | element.dispatchEvent(ev);
601 | };
602 |
603 | if (!document.addEventListener) {
604 | on = function(element, name, fn) {
605 | return element.attachEvent('on' + name, fn);
606 | };
607 | }
608 |
609 | if (!document.removeEventListener) {
610 | off = function(element, name, fn) {
611 | return element.detachEvent('on' + name, fn);
612 | };
613 | }
614 |
615 | if (!document.dispatchEvent) {
616 | emit = function(element, name, opt) {
617 | var ev = synth(name, opt);
618 | return element.fireEvent('on' + ev.type, ev);
619 | };
620 | }
621 |
622 | module.exports = {
623 | on: on,
624 | off: off,
625 | once: once,
626 | emit: emit
627 | };
628 |
629 | },{"synthetic-dom-events":10}],6:[function(require,module,exports){
630 |
631 | var indexOf = [].indexOf;
632 |
633 | module.exports = function(arr, obj){
634 | if (indexOf) return arr.indexOf(obj);
635 | for (var i = 0; i < arr.length; ++i) {
636 | if (arr[i] === obj) return i;
637 | }
638 | return -1;
639 | };
640 | },{}],7:[function(require,module,exports){
641 | // Generated by CoffeeScript 1.9.2
642 | (function() {
643 | var root;
644 |
645 | root = typeof exports !== "undefined" && exports !== null ? exports : this;
646 |
647 | root.Lethargy = (function() {
648 | function Lethargy(stability, sensitivity, tolerance, delay) {
649 | this.stability = stability != null ? Math.abs(stability) : 8;
650 | this.sensitivity = sensitivity != null ? 1 + Math.abs(sensitivity) : 100;
651 | this.tolerance = tolerance != null ? 1 + Math.abs(tolerance) : 1.1;
652 | this.delay = delay != null ? delay : 150;
653 | this.lastUpDeltas = (function() {
654 | var i, ref, results;
655 | results = [];
656 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
657 | results.push(null);
658 | }
659 | return results;
660 | }).call(this);
661 | this.lastDownDeltas = (function() {
662 | var i, ref, results;
663 | results = [];
664 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
665 | results.push(null);
666 | }
667 | return results;
668 | }).call(this);
669 | this.deltasTimestamp = (function() {
670 | var i, ref, results;
671 | results = [];
672 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
673 | results.push(null);
674 | }
675 | return results;
676 | }).call(this);
677 | }
678 |
679 | Lethargy.prototype.check = function(e) {
680 | var lastDelta;
681 | e = e.originalEvent || e;
682 | if (e.wheelDelta != null) {
683 | lastDelta = e.wheelDelta;
684 | } else if (e.deltaY != null) {
685 | lastDelta = e.deltaY * -40;
686 | } else if ((e.detail != null) || e.detail === 0) {
687 | lastDelta = e.detail * -40;
688 | }
689 | this.deltasTimestamp.push(Date.now());
690 | this.deltasTimestamp.shift();
691 | if (lastDelta > 0) {
692 | this.lastUpDeltas.push(lastDelta);
693 | this.lastUpDeltas.shift();
694 | return this.isInertia(1);
695 | } else {
696 | this.lastDownDeltas.push(lastDelta);
697 | this.lastDownDeltas.shift();
698 | return this.isInertia(-1);
699 | }
700 | return false;
701 | };
702 |
703 | Lethargy.prototype.isInertia = function(direction) {
704 | var lastDeltas, lastDeltasNew, lastDeltasOld, newAverage, newSum, oldAverage, oldSum;
705 | lastDeltas = direction === -1 ? this.lastDownDeltas : this.lastUpDeltas;
706 | if (lastDeltas[0] === null) {
707 | return direction;
708 | }
709 | if (this.deltasTimestamp[(this.stability * 2) - 2] + this.delay > Date.now() && lastDeltas[0] === lastDeltas[(this.stability * 2) - 1]) {
710 | return false;
711 | }
712 | lastDeltasOld = lastDeltas.slice(0, this.stability);
713 | lastDeltasNew = lastDeltas.slice(this.stability, this.stability * 2);
714 | oldSum = lastDeltasOld.reduce(function(t, s) {
715 | return t + s;
716 | });
717 | newSum = lastDeltasNew.reduce(function(t, s) {
718 | return t + s;
719 | });
720 | oldAverage = oldSum / lastDeltasOld.length;
721 | newAverage = newSum / lastDeltasNew.length;
722 | if (Math.abs(oldAverage) < Math.abs(newAverage * this.tolerance) && (this.sensitivity < Math.abs(newAverage))) {
723 | return direction;
724 | } else {
725 | return false;
726 | }
727 | };
728 |
729 | Lethargy.prototype.showLastUpDeltas = function() {
730 | return this.lastUpDeltas;
731 | };
732 |
733 | Lethargy.prototype.showLastDownDeltas = function() {
734 | return this.lastDownDeltas;
735 | };
736 |
737 | return Lethargy;
738 |
739 | })();
740 |
741 | }).call(this);
742 |
743 | },{}],8:[function(require,module,exports){
744 | /*
745 | object-assign
746 | (c) Sindre Sorhus
747 | @license MIT
748 | */
749 |
750 | 'use strict';
751 | /* eslint-disable no-unused-vars */
752 | var getOwnPropertySymbols = Object.getOwnPropertySymbols;
753 | var hasOwnProperty = Object.prototype.hasOwnProperty;
754 | var propIsEnumerable = Object.prototype.propertyIsEnumerable;
755 |
756 | function toObject(val) {
757 | if (val === null || val === undefined) {
758 | throw new TypeError('Object.assign cannot be called with null or undefined');
759 | }
760 |
761 | return Object(val);
762 | }
763 |
764 | function shouldUseNative() {
765 | try {
766 | if (!Object.assign) {
767 | return false;
768 | }
769 |
770 | // Detect buggy property enumeration order in older V8 versions.
771 |
772 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118
773 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
774 | test1[5] = 'de';
775 | if (Object.getOwnPropertyNames(test1)[0] === '5') {
776 | return false;
777 | }
778 |
779 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
780 | var test2 = {};
781 | for (var i = 0; i < 10; i++) {
782 | test2['_' + String.fromCharCode(i)] = i;
783 | }
784 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
785 | return test2[n];
786 | });
787 | if (order2.join('') !== '0123456789') {
788 | return false;
789 | }
790 |
791 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
792 | var test3 = {};
793 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
794 | test3[letter] = letter;
795 | });
796 | if (Object.keys(Object.assign({}, test3)).join('') !==
797 | 'abcdefghijklmnopqrst') {
798 | return false;
799 | }
800 |
801 | return true;
802 | } catch (err) {
803 | // We don't expect any of the above to throw, but better to be safe.
804 | return false;
805 | }
806 | }
807 |
808 | module.exports = shouldUseNative() ? Object.assign : function (target, source) {
809 | var from;
810 | var to = toObject(target);
811 | var symbols;
812 |
813 | for (var s = 1; s < arguments.length; s++) {
814 | from = Object(arguments[s]);
815 |
816 | for (var key in from) {
817 | if (hasOwnProperty.call(from, key)) {
818 | to[key] = from[key];
819 | }
820 | }
821 |
822 | if (getOwnPropertySymbols) {
823 | symbols = getOwnPropertySymbols(from);
824 | for (var i = 0; i < symbols.length; i++) {
825 | if (propIsEnumerable.call(from, symbols[i])) {
826 | to[symbols[i]] = from[symbols[i]];
827 | }
828 | }
829 | }
830 | }
831 |
832 | return to;
833 | };
834 |
835 | },{}],9:[function(require,module,exports){
836 | // check document first so it doesn't error in node.js
837 | var style = typeof document != 'undefined'
838 | ? document.createElement('p').style
839 | : {}
840 |
841 | var prefixes = ['O', 'ms', 'Moz', 'Webkit']
842 | var upper = /([A-Z])/g
843 | var memo = {}
844 |
845 | /**
846 | * prefix `key`
847 | *
848 | * prefix('transform') // => WebkitTransform
849 | *
850 | * @param {String} key
851 | * @return {String}
852 | * @api public
853 | */
854 | function prefix(key){
855 | // Camel case
856 | key = key.replace(/-([a-z])/g, function(_, char){
857 | return char.toUpperCase()
858 | })
859 |
860 | // Without prefix
861 | if (style[key] !== undefined) return key
862 |
863 | // With prefix
864 | var Key = key.charAt(0).toUpperCase() + key.slice(1)
865 | var i = prefixes.length
866 | while (i--) {
867 | var name = prefixes[i] + Key
868 | if (style[name] !== undefined) return name
869 | }
870 |
871 | return key
872 | }
873 |
874 | /**
875 | * Memoized version of `prefix`
876 | *
877 | * @param {String} key
878 | * @return {String}
879 | * @api public
880 | */
881 | function prefixMemozied(key){
882 | return key in memo
883 | ? memo[key]
884 | : memo[key] = prefix(key)
885 | }
886 |
887 | /**
888 | * Create a dashed prefix
889 | *
890 | * @param {String} key
891 | * @return {String}
892 | * @api public
893 | */
894 | function prefixDashed(key){
895 | key = prefix(key)
896 | if (upper.test(key)) {
897 | key = '-' + key.replace(upper, '-$1')
898 | upper.lastIndex = 0
899 | }
900 | return key.toLowerCase()
901 | }
902 |
903 | module.exports = prefixMemozied
904 | module.exports.dash = prefixDashed
905 |
906 | },{}],10:[function(require,module,exports){
907 |
908 | // for compression
909 | var win = window;
910 | var doc = document || {};
911 | var root = doc.documentElement || {};
912 |
913 | // detect if we need to use firefox KeyEvents vs KeyboardEvents
914 | var use_key_event = true;
915 | try {
916 | doc.createEvent('KeyEvents');
917 | }
918 | catch (err) {
919 | use_key_event = false;
920 | }
921 |
922 | // Workaround for https://bugs.webkit.org/show_bug.cgi?id=16735
923 | function check_kb(ev, opts) {
924 | if (ev.ctrlKey != (opts.ctrlKey || false) ||
925 | ev.altKey != (opts.altKey || false) ||
926 | ev.shiftKey != (opts.shiftKey || false) ||
927 | ev.metaKey != (opts.metaKey || false) ||
928 | ev.keyCode != (opts.keyCode || 0) ||
929 | ev.charCode != (opts.charCode || 0)) {
930 |
931 | ev = document.createEvent('Event');
932 | ev.initEvent(opts.type, opts.bubbles, opts.cancelable);
933 | ev.ctrlKey = opts.ctrlKey || false;
934 | ev.altKey = opts.altKey || false;
935 | ev.shiftKey = opts.shiftKey || false;
936 | ev.metaKey = opts.metaKey || false;
937 | ev.keyCode = opts.keyCode || 0;
938 | ev.charCode = opts.charCode || 0;
939 | }
940 |
941 | return ev;
942 | }
943 |
944 | // modern browsers, do a proper dispatchEvent()
945 | var modern = function(type, opts) {
946 | opts = opts || {};
947 |
948 | // which init fn do we use
949 | var family = typeOf(type);
950 | var init_fam = family;
951 | if (family === 'KeyboardEvent' && use_key_event) {
952 | family = 'KeyEvents';
953 | init_fam = 'KeyEvent';
954 | }
955 |
956 | var ev = doc.createEvent(family);
957 | var init_fn = 'init' + init_fam;
958 | var init = typeof ev[init_fn] === 'function' ? init_fn : 'initEvent';
959 |
960 | var sig = initSignatures[init];
961 | var args = [];
962 | var used = {};
963 |
964 | opts.type = type;
965 | for (var i = 0; i < sig.length; ++i) {
966 | var key = sig[i];
967 | var val = opts[key];
968 | // if no user specified value, then use event default
969 | if (val === undefined) {
970 | val = ev[key];
971 | }
972 | used[key] = true;
973 | args.push(val);
974 | }
975 | ev[init].apply(ev, args);
976 |
977 | // webkit key event issue workaround
978 | if (family === 'KeyboardEvent') {
979 | ev = check_kb(ev, opts);
980 | }
981 |
982 | // attach remaining unused options to the object
983 | for (var key in opts) {
984 | if (!used[key]) {
985 | ev[key] = opts[key];
986 | }
987 | }
988 |
989 | return ev;
990 | };
991 |
992 | var legacy = function (type, opts) {
993 | opts = opts || {};
994 | var ev = doc.createEventObject();
995 |
996 | ev.type = type;
997 | for (var key in opts) {
998 | if (opts[key] !== undefined) {
999 | ev[key] = opts[key];
1000 | }
1001 | }
1002 |
1003 | return ev;
1004 | };
1005 |
1006 | // expose either the modern version of event generation or legacy
1007 | // depending on what we support
1008 | // avoids if statements in the code later
1009 | module.exports = doc.createEvent ? modern : legacy;
1010 |
1011 | var initSignatures = require('./init.json');
1012 | var types = require('./types.json');
1013 | var typeOf = (function () {
1014 | var typs = {};
1015 | for (var key in types) {
1016 | var ts = types[key];
1017 | for (var i = 0; i < ts.length; i++) {
1018 | typs[ts[i]] = key;
1019 | }
1020 | }
1021 |
1022 | return function (name) {
1023 | return typs[name] || 'Event';
1024 | };
1025 | })();
1026 |
1027 | },{"./init.json":11,"./types.json":12}],11:[function(require,module,exports){
1028 | module.exports={
1029 | "initEvent" : [
1030 | "type",
1031 | "bubbles",
1032 | "cancelable"
1033 | ],
1034 | "initUIEvent" : [
1035 | "type",
1036 | "bubbles",
1037 | "cancelable",
1038 | "view",
1039 | "detail"
1040 | ],
1041 | "initMouseEvent" : [
1042 | "type",
1043 | "bubbles",
1044 | "cancelable",
1045 | "view",
1046 | "detail",
1047 | "screenX",
1048 | "screenY",
1049 | "clientX",
1050 | "clientY",
1051 | "ctrlKey",
1052 | "altKey",
1053 | "shiftKey",
1054 | "metaKey",
1055 | "button",
1056 | "relatedTarget"
1057 | ],
1058 | "initMutationEvent" : [
1059 | "type",
1060 | "bubbles",
1061 | "cancelable",
1062 | "relatedNode",
1063 | "prevValue",
1064 | "newValue",
1065 | "attrName",
1066 | "attrChange"
1067 | ],
1068 | "initKeyboardEvent" : [
1069 | "type",
1070 | "bubbles",
1071 | "cancelable",
1072 | "view",
1073 | "ctrlKey",
1074 | "altKey",
1075 | "shiftKey",
1076 | "metaKey",
1077 | "keyCode",
1078 | "charCode"
1079 | ],
1080 | "initKeyEvent" : [
1081 | "type",
1082 | "bubbles",
1083 | "cancelable",
1084 | "view",
1085 | "ctrlKey",
1086 | "altKey",
1087 | "shiftKey",
1088 | "metaKey",
1089 | "keyCode",
1090 | "charCode"
1091 | ]
1092 | }
1093 |
1094 | },{}],12:[function(require,module,exports){
1095 | module.exports={
1096 | "MouseEvent" : [
1097 | "click",
1098 | "mousedown",
1099 | "mouseup",
1100 | "mouseover",
1101 | "mousemove",
1102 | "mouseout"
1103 | ],
1104 | "KeyboardEvent" : [
1105 | "keydown",
1106 | "keyup",
1107 | "keypress"
1108 | ],
1109 | "MutationEvent" : [
1110 | "DOMSubtreeModified",
1111 | "DOMNodeInserted",
1112 | "DOMNodeRemoved",
1113 | "DOMNodeRemovedFromDocument",
1114 | "DOMNodeInsertedIntoDocument",
1115 | "DOMAttrModified",
1116 | "DOMCharacterDataModified"
1117 | ],
1118 | "HTMLEvents" : [
1119 | "load",
1120 | "unload",
1121 | "abort",
1122 | "error",
1123 | "select",
1124 | "change",
1125 | "submit",
1126 | "reset",
1127 | "focus",
1128 | "blur",
1129 | "resize",
1130 | "scroll"
1131 | ],
1132 | "UIEvent" : [
1133 | "DOMFocusIn",
1134 | "DOMFocusOut",
1135 | "DOMActivate"
1136 | ]
1137 | }
1138 |
1139 | },{}],13:[function(require,module,exports){
1140 | function E () {
1141 | // Keep this empty so it's easier to inherit from
1142 | // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
1143 | }
1144 |
1145 | E.prototype = {
1146 | on: function (name, callback, ctx) {
1147 | var e = this.e || (this.e = {});
1148 |
1149 | (e[name] || (e[name] = [])).push({
1150 | fn: callback,
1151 | ctx: ctx
1152 | });
1153 |
1154 | return this;
1155 | },
1156 |
1157 | once: function (name, callback, ctx) {
1158 | var self = this;
1159 | function listener () {
1160 | self.off(name, listener);
1161 | callback.apply(ctx, arguments);
1162 | };
1163 |
1164 | listener._ = callback
1165 | return this.on(name, listener, ctx);
1166 | },
1167 |
1168 | emit: function (name) {
1169 | var data = [].slice.call(arguments, 1);
1170 | var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
1171 | var i = 0;
1172 | var len = evtArr.length;
1173 |
1174 | for (i; i < len; i++) {
1175 | evtArr[i].fn.apply(evtArr[i].ctx, data);
1176 | }
1177 |
1178 | return this;
1179 | },
1180 |
1181 | off: function (name, callback) {
1182 | var e = this.e || (this.e = {});
1183 | var evts = e[name];
1184 | var liveEvents = [];
1185 |
1186 | if (evts && callback) {
1187 | for (var i = 0, len = evts.length; i < len; i++) {
1188 | if (evts[i].fn !== callback && evts[i].fn._ !== callback)
1189 | liveEvents.push(evts[i]);
1190 | }
1191 | }
1192 |
1193 | // Remove event from queue to prevent memory leak
1194 | // Suggested by https://github.com/lazd
1195 | // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
1196 |
1197 | (liveEvents.length)
1198 | ? e[name] = liveEvents
1199 | : delete e[name];
1200 |
1201 | return this;
1202 | }
1203 | };
1204 |
1205 | module.exports = E;
1206 |
1207 | },{}],14:[function(require,module,exports){
1208 | 'use strict';
1209 |
1210 | module.exports = function(source) {
1211 | return JSON.parse(JSON.stringify(source));
1212 | };
1213 | },{}],15:[function(require,module,exports){
1214 | 'use strict';
1215 |
1216 | var objectAssign = require('object-assign');
1217 | var Emitter = require('tiny-emitter');
1218 | var Lethargy = require('lethargy').Lethargy;
1219 | var support = require('./support');
1220 | var clone = require('./clone');
1221 | var bindAll = require('bindall-standalone');
1222 | var EVT_ID = 'virtualscroll';
1223 |
1224 | module.exports = VirtualScroll;
1225 |
1226 | var keyCodes = {
1227 | LEFT: 37,
1228 | UP: 38,
1229 | RIGHT: 39,
1230 | DOWN: 40,
1231 | SPACE: 32
1232 | };
1233 |
1234 | function VirtualScroll(options) {
1235 | bindAll(this, '_onWheel', '_onMouseWheel', '_onTouchStart', '_onTouchMove', '_onKeyDown');
1236 |
1237 | this.el = window;
1238 | if (options && options.el) {
1239 | this.el = options.el;
1240 | delete options.el;
1241 | }
1242 | this.options = objectAssign({
1243 | mouseMultiplier: 1,
1244 | touchMultiplier: 2,
1245 | firefoxMultiplier: 15,
1246 | keyStep: 120,
1247 | preventTouch: false,
1248 | unpreventTouchClass: 'vs-touchmove-allowed',
1249 | limitInertia: false
1250 | }, options);
1251 |
1252 | if (this.options.limitInertia) this._lethargy = new Lethargy();
1253 |
1254 | this._emitter = new Emitter();
1255 | this._event = {
1256 | y: 0,
1257 | x: 0,
1258 | deltaX: 0,
1259 | deltaY: 0
1260 | };
1261 | this.touchStartX = null;
1262 | this.touchStartY = null;
1263 | this.bodyTouchAction = null;
1264 |
1265 | if (this.options.passive !== undefined) {
1266 | this.listenerOptions = {passive: this.options.passive};
1267 | }
1268 | }
1269 |
1270 | VirtualScroll.prototype._notify = function(e) {
1271 | var evt = this._event;
1272 | evt.x += evt.deltaX;
1273 | evt.y += evt.deltaY;
1274 |
1275 | this._emitter.emit(EVT_ID, {
1276 | x: evt.x,
1277 | y: evt.y,
1278 | deltaX: evt.deltaX,
1279 | deltaY: evt.deltaY,
1280 | originalEvent: e
1281 | });
1282 | };
1283 |
1284 | VirtualScroll.prototype._onWheel = function(e) {
1285 | var options = this.options;
1286 | if (this._lethargy && this._lethargy.check(e) === false) return;
1287 | var evt = this._event;
1288 |
1289 | // In Chrome and in Firefox (at least the new one)
1290 | evt.deltaX = e.wheelDeltaX || e.deltaX * -1;
1291 | evt.deltaY = e.wheelDeltaY || e.deltaY * -1;
1292 |
1293 | // for our purpose deltamode = 1 means user is on a wheel mouse, not touch pad
1294 | // real meaning: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent#Delta_modes
1295 | if(support.isFirefox && e.deltaMode == 1) {
1296 | evt.deltaX *= options.firefoxMultiplier;
1297 | evt.deltaY *= options.firefoxMultiplier;
1298 | }
1299 |
1300 | evt.deltaX *= options.mouseMultiplier;
1301 | evt.deltaY *= options.mouseMultiplier;
1302 |
1303 | this._notify(e);
1304 | };
1305 |
1306 | VirtualScroll.prototype._onMouseWheel = function(e) {
1307 | if (this.options.limitInertia && this._lethargy.check(e) === false) return;
1308 |
1309 | var evt = this._event;
1310 |
1311 | // In Safari, IE and in Chrome if 'wheel' isn't defined
1312 | evt.deltaX = (e.wheelDeltaX) ? e.wheelDeltaX : 0;
1313 | evt.deltaY = (e.wheelDeltaY) ? e.wheelDeltaY : e.wheelDelta;
1314 |
1315 | this._notify(e);
1316 | };
1317 |
1318 | VirtualScroll.prototype._onTouchStart = function(e) {
1319 | var t = (e.targetTouches) ? e.targetTouches[0] : e;
1320 | this.touchStartX = t.pageX;
1321 | this.touchStartY = t.pageY;
1322 | };
1323 |
1324 | VirtualScroll.prototype._onTouchMove = function(e) {
1325 | var options = this.options;
1326 | if(options.preventTouch
1327 | && !e.target.classList.contains(options.unpreventTouchClass)) {
1328 | e.preventDefault();
1329 | }
1330 |
1331 | var evt = this._event;
1332 |
1333 | var t = (e.targetTouches) ? e.targetTouches[0] : e;
1334 |
1335 | evt.deltaX = (t.pageX - this.touchStartX) * options.touchMultiplier;
1336 | evt.deltaY = (t.pageY - this.touchStartY) * options.touchMultiplier;
1337 |
1338 | this.touchStartX = t.pageX;
1339 | this.touchStartY = t.pageY;
1340 |
1341 | this._notify(e);
1342 | };
1343 |
1344 | VirtualScroll.prototype._onKeyDown = function(e) {
1345 | var evt = this._event;
1346 | evt.deltaX = evt.deltaY = 0;
1347 | var windowHeight = window.innerHeight - 40
1348 |
1349 | switch(e.keyCode) {
1350 | case keyCodes.LEFT:
1351 | case keyCodes.UP:
1352 | evt.deltaY = this.options.keyStep;
1353 | break;
1354 |
1355 | case keyCodes.RIGHT:
1356 | case keyCodes.DOWN:
1357 | evt.deltaY = - this.options.keyStep;
1358 | break;
1359 | case keyCodes.SPACE && e.shiftKey:
1360 | evt.deltaY = windowHeight;
1361 | break;
1362 | case keyCodes.SPACE:
1363 | evt.deltaY = - windowHeight;
1364 | break;
1365 | default:
1366 | return;
1367 | }
1368 |
1369 | this._notify(e);
1370 | };
1371 |
1372 | VirtualScroll.prototype._bind = function() {
1373 | if(support.hasWheelEvent) this.el.addEventListener('wheel', this._onWheel, this.listenerOptions);
1374 | if(support.hasMouseWheelEvent) this.el.addEventListener('mousewheel', this._onMouseWheel, this.listenerOptions);
1375 |
1376 | if(support.hasTouch) {
1377 | this.el.addEventListener('touchstart', this._onTouchStart, this.listenerOptions);
1378 | this.el.addEventListener('touchmove', this._onTouchMove, this.listenerOptions);
1379 | }
1380 |
1381 | if(support.hasPointer && support.hasTouchWin) {
1382 | this.bodyTouchAction = document.body.style.msTouchAction;
1383 | document.body.style.msTouchAction = 'none';
1384 | this.el.addEventListener('MSPointerDown', this._onTouchStart, true);
1385 | this.el.addEventListener('MSPointerMove', this._onTouchMove, true);
1386 | }
1387 |
1388 | if(support.hasKeyDown) document.addEventListener('keydown', this._onKeyDown);
1389 | };
1390 |
1391 | VirtualScroll.prototype._unbind = function() {
1392 | if(support.hasWheelEvent) this.el.removeEventListener('wheel', this._onWheel);
1393 | if(support.hasMouseWheelEvent) this.el.removeEventListener('mousewheel', this._onMouseWheel);
1394 |
1395 | if(support.hasTouch) {
1396 | this.el.removeEventListener('touchstart', this._onTouchStart);
1397 | this.el.removeEventListener('touchmove', this._onTouchMove);
1398 | }
1399 |
1400 | if(support.hasPointer && support.hasTouchWin) {
1401 | document.body.style.msTouchAction = this.bodyTouchAction;
1402 | this.el.removeEventListener('MSPointerDown', this._onTouchStart, true);
1403 | this.el.removeEventListener('MSPointerMove', this._onTouchMove, true);
1404 | }
1405 |
1406 | if(support.hasKeyDown) document.removeEventListener('keydown', this._onKeyDown);
1407 | };
1408 |
1409 | VirtualScroll.prototype.on = function(cb, ctx) {
1410 | this._emitter.on(EVT_ID, cb, ctx);
1411 |
1412 | var events = this._emitter.e;
1413 | if (events && events[EVT_ID] && events[EVT_ID].length === 1) this._bind();
1414 | };
1415 |
1416 | VirtualScroll.prototype.off = function(cb, ctx) {
1417 | this._emitter.off(EVT_ID, cb, ctx);
1418 |
1419 | var events = this._emitter.e;
1420 | if (!events[EVT_ID] || events[EVT_ID].length <= 0) this._unbind();
1421 | };
1422 |
1423 | VirtualScroll.prototype.reset = function() {
1424 | var evt = this._event;
1425 | evt.x = 0;
1426 | evt.y = 0;
1427 | };
1428 |
1429 | VirtualScroll.prototype.destroy = function() {
1430 | this._emitter.off();
1431 | this._unbind();
1432 | };
1433 |
1434 | },{"./clone":14,"./support":16,"bindall-standalone":2,"lethargy":7,"object-assign":8,"tiny-emitter":13}],16:[function(require,module,exports){
1435 | 'use strict';
1436 |
1437 | module.exports = (function getSupport() {
1438 | return {
1439 | hasWheelEvent: 'onwheel' in document,
1440 | hasMouseWheelEvent: 'onmousewheel' in document,
1441 | hasTouch: 'ontouchstart' in document,
1442 | hasTouchWin: navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 1,
1443 | hasPointer: !!window.navigator.msPointerEnabled,
1444 | hasKeyDown: 'onkeydown' in document,
1445 | isFirefox: navigator.userAgent.indexOf('Firefox') > -1
1446 | };
1447 | })();
1448 |
1449 | },{}]},{},[1]);
1450 |
--------------------------------------------------------------------------------
/demos/scale/build.js:
--------------------------------------------------------------------------------
1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {};
124 |
125 | _classCallCheck(this, Smooth);
126 |
127 | this.createBound();
128 | this.options = opt;
129 | this.prefix = (0, _prefix["default"])('transform');
130 | this.rAF = undefined; // It seems that under heavy load, Firefox will still call the RAF callback even though the RAF has been canceled
131 | // To prevent that we set a flag to prevent any callback to be executed when RAF is removed
132 |
133 | this.isRAFCanceled = false;
134 | var constructorName = this.constructor.name ? this.constructor.name : 'Smooth';
135 | this["extends"] = typeof opt["extends"] === 'undefined' ? this.constructor !== Smooth : opt["extends"];
136 | this.callback = this.options.callback || null;
137 | this.vars = {
138 | direction: this.options.direction || 'vertical',
139 | "native": this.options["native"] || false,
140 | ease: this.options.ease || 0.075,
141 | preload: this.options.preload || false,
142 | current: 0,
143 | last: 0,
144 | target: 0,
145 | height: window.innerHeight,
146 | width: window.innerWidth,
147 | bounding: 0,
148 | timer: null,
149 | ticking: false
150 | };
151 | this.vs = this.vars["native"] ? null : new _virtualScroll["default"]({
152 | limitInertia: this.options.vs && this.options.vs.limitInertia || false,
153 | mouseMultiplier: this.options.vs && this.options.vs.mouseMultiplier || 1,
154 | touchMultiplier: this.options.vs && this.options.vs.touchMultiplier || 1.5,
155 | firefoxMultiplier: this.options.vs && this.options.vs.firefoxMultiplier || 30,
156 | preventTouch: this.options.vs && this.options.vs.preventTouch || true
157 | });
158 | this.dom = {
159 | listener: this.options.listener || document.body,
160 | section: this.options.section || document.querySelector('.vs-section') || null,
161 | scrollbar: this.vars["native"] || this.options.noscrollbar ? null : {
162 | state: {
163 | clicked: false,
164 | x: 0
165 | },
166 | el: (0, _domCreateElement["default"])({
167 | selector: 'div',
168 | styles: "vs-scrollbar vs-".concat(this.vars.direction, " vs-scrollbar-").concat(constructorName.toLowerCase())
169 | }),
170 | drag: {
171 | el: (0, _domCreateElement["default"])({
172 | selector: 'div',
173 | styles: 'vs-scrolldrag'
174 | }),
175 | delta: 0,
176 | height: 50
177 | }
178 | }
179 | };
180 | }
181 |
182 | _createClass(Smooth, [{
183 | key: "createBound",
184 | value: function createBound() {
185 | var _this = this;
186 |
187 | ['run', 'calc', 'debounce', 'resize', 'mouseUp', 'mouseDown', 'mouseMove', 'calcScroll', 'scrollTo'].forEach(function (fn) {
188 | return _this[fn] = _this[fn].bind(_this);
189 | });
190 | }
191 | }, {
192 | key: "init",
193 | value: function init() {
194 | this.addClasses();
195 | this.vars.preload && this.preloadImages();
196 | this.vars["native"] ? this.addFakeScrollHeight() : !this.options.noscrollbar && this.addFakeScrollBar();
197 | this.addEvents();
198 | this.resize();
199 | }
200 | }, {
201 | key: "addClasses",
202 | value: function addClasses() {
203 | var type = this.vars["native"] ? 'native' : 'virtual';
204 | var direction = this.vars.direction === 'vertical' ? 'y' : 'x';
205 |
206 | _domClasses["default"].add(this.dom.listener, "is-".concat(type, "-scroll"));
207 |
208 | _domClasses["default"].add(this.dom.listener, "".concat(direction, "-scroll"));
209 | }
210 | }, {
211 | key: "preloadImages",
212 | value: function preloadImages() {
213 | var _this2 = this;
214 |
215 | var images = Array.prototype.slice.call(this.dom.listener.querySelectorAll('img'), 0);
216 | images.forEach(function (image) {
217 | var img = document.createElement('img');
218 |
219 | _domEvents["default"].once(img, 'load', function () {
220 | images.splice(images.indexOf(image), 1);
221 | images.length === 0 && _this2.resize();
222 | });
223 |
224 | img.src = image.getAttribute('src');
225 | });
226 | }
227 | }, {
228 | key: "calc",
229 | value: function calc(e) {
230 | var delta = this.vars.direction == 'horizontal' ? e.deltaX : e.deltaY;
231 | this.vars.target += delta * -1;
232 | this.clampTarget();
233 | }
234 | }, {
235 | key: "debounce",
236 | value: function debounce() {
237 | var _this3 = this;
238 |
239 | var win = this.dom.listener === document.body;
240 | this.vars.target = this.vars.direction === 'vertical' ? win ? window.scrollY || window.pageYOffset : this.dom.listener.scrollTop : win ? window.scrollX || window.pageXOffset : this.dom.listener.scrollLeft;
241 | clearTimeout(this.vars.timer);
242 |
243 | if (!this.vars.ticking) {
244 | this.vars.ticking = true;
245 |
246 | _domClasses["default"].add(this.dom.listener, 'is-scrolling');
247 | }
248 |
249 | this.vars.timer = setTimeout(function () {
250 | _this3.vars.ticking = false;
251 |
252 | _domClasses["default"].remove(_this3.dom.listener, 'is-scrolling');
253 | }, 200);
254 | }
255 | }, {
256 | key: "run",
257 | value: function run() {
258 | if (this.isRAFCanceled) return;
259 | this.vars.current += (this.vars.target - this.vars.current) * this.vars.ease;
260 | this.vars.current < .1 && (this.vars.current = 0);
261 | this.requestAnimationFrame();
262 |
263 | if (!this["extends"]) {
264 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2));
265 | }
266 |
267 | if (!this.vars["native"] && !this.options.noscrollbar) {
268 | var size = this.dom.scrollbar.drag.height;
269 | var bounds = this.vars.direction === 'vertical' ? this.vars.height : this.vars.width;
270 | var value = Math.abs(this.vars.current) / (this.vars.bounding / (bounds - size)) + size / .5 - size;
271 | var clamp = Math.max(0, Math.min(value - size, value + size));
272 | this.dom.scrollbar.drag.el.style[this.prefix] = this.getTransform(clamp.toFixed(2));
273 | }
274 |
275 | if (this.callback && this.vars.current !== this.vars.last) {
276 | this.callback(this.vars.current);
277 | }
278 |
279 | this.vars.last = this.vars.current;
280 | }
281 | }, {
282 | key: "getTransform",
283 | value: function getTransform(value) {
284 | return this.vars.direction === 'vertical' ? "translate3d(0,".concat(value, "px,0)") : "translate3d(".concat(value, "px,0,0)");
285 | }
286 | }, {
287 | key: "on",
288 | value: function on() {
289 | var requestAnimationFrame = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
290 |
291 | if (this.isRAFCanceled) {
292 | this.isRAFCanceled = false;
293 | }
294 |
295 | var node = this.dom.listener === document.body ? window : this.dom.listener;
296 | this.vars["native"] ? _domEvents["default"].on(node, 'scroll', this.debounce) : this.vs && this.vs.on(this.calc);
297 | requestAnimationFrame && this.requestAnimationFrame();
298 | }
299 | }, {
300 | key: "off",
301 | value: function off() {
302 | var cancelAnimationFrame = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
303 | var node = this.dom.listener === document.body ? window : this.dom.listener;
304 | this.vars["native"] ? _domEvents["default"].off(node, 'scroll', this.debounce) : this.vs && this.vs.off(this.calc);
305 | cancelAnimationFrame && this.cancelAnimationFrame();
306 | }
307 | }, {
308 | key: "requestAnimationFrame",
309 | value: function (_requestAnimationFrame) {
310 | function requestAnimationFrame() {
311 | return _requestAnimationFrame.apply(this, arguments);
312 | }
313 |
314 | requestAnimationFrame.toString = function () {
315 | return _requestAnimationFrame.toString();
316 | };
317 |
318 | return requestAnimationFrame;
319 | }(function () {
320 | this.rAF = requestAnimationFrame(this.run);
321 | })
322 | }, {
323 | key: "cancelAnimationFrame",
324 | value: function (_cancelAnimationFrame) {
325 | function cancelAnimationFrame() {
326 | return _cancelAnimationFrame.apply(this, arguments);
327 | }
328 |
329 | cancelAnimationFrame.toString = function () {
330 | return _cancelAnimationFrame.toString();
331 | };
332 |
333 | return cancelAnimationFrame;
334 | }(function () {
335 | this.isRAFCanceled = true;
336 | cancelAnimationFrame(this.rAF);
337 | })
338 | }, {
339 | key: "addEvents",
340 | value: function addEvents() {
341 | this.on();
342 |
343 | _domEvents["default"].on(window, 'resize', this.resize);
344 | }
345 | }, {
346 | key: "removeEvents",
347 | value: function removeEvents() {
348 | this.off();
349 |
350 | _domEvents["default"].off(window, 'resize', this.resize);
351 | }
352 | }, {
353 | key: "addFakeScrollBar",
354 | value: function addFakeScrollBar() {
355 | this.dom.listener.appendChild(this.dom.scrollbar.el);
356 | this.dom.scrollbar.el.appendChild(this.dom.scrollbar.drag.el);
357 |
358 | _domEvents["default"].on(this.dom.scrollbar.el, 'click', this.calcScroll);
359 |
360 | _domEvents["default"].on(this.dom.scrollbar.el, 'mousedown', this.mouseDown);
361 |
362 | _domEvents["default"].on(document, 'mousemove', this.mouseMove);
363 |
364 | _domEvents["default"].on(document, 'mouseup', this.mouseUp);
365 | }
366 | }, {
367 | key: "removeFakeScrollBar",
368 | value: function removeFakeScrollBar() {
369 | _domEvents["default"].off(this.dom.scrollbar.el, 'click', this.calcScroll);
370 |
371 | _domEvents["default"].off(this.dom.scrollbar.el, 'mousedown', this.mouseDown);
372 |
373 | _domEvents["default"].off(document, 'mousemove', this.mouseMove);
374 |
375 | _domEvents["default"].off(document, 'mouseup', this.mouseUp);
376 |
377 | this.dom.listener.removeChild(this.dom.scrollbar.el);
378 | }
379 | }, {
380 | key: "mouseDown",
381 | value: function mouseDown(e) {
382 | e.preventDefault();
383 | e.which == 1 && (this.dom.scrollbar.state.clicked = true);
384 | }
385 | }, {
386 | key: "mouseUp",
387 | value: function mouseUp(e) {
388 | this.dom.scrollbar.state.clicked = false;
389 |
390 | _domClasses["default"].remove(this.dom.listener, 'is-dragging');
391 | }
392 | }, {
393 | key: "mouseMove",
394 | value: function mouseMove(e) {
395 | this.dom.scrollbar.state.clicked && this.calcScroll(e);
396 | }
397 | }, {
398 | key: "addFakeScrollHeight",
399 | value: function addFakeScrollHeight() {
400 | this.dom.scroll = (0, _domCreateElement["default"])({
401 | selector: 'div',
402 | styles: 'vs-scroll-view'
403 | });
404 | this.dom.listener.appendChild(this.dom.scroll);
405 | }
406 | }, {
407 | key: "removeFakeScrollHeight",
408 | value: function removeFakeScrollHeight() {
409 | this.dom.listener.removeChild(this.dom.scroll);
410 | }
411 | }, {
412 | key: "calcScroll",
413 | value: function calcScroll(e) {
414 | var client = this.vars.direction == 'vertical' ? e.clientY : e.clientX;
415 | var bounds = this.vars.direction == 'vertical' ? this.vars.height : this.vars.width;
416 | var delta = client * (this.vars.bounding / bounds);
417 |
418 | _domClasses["default"].add(this.dom.listener, 'is-dragging');
419 |
420 | this.vars.target = delta;
421 | this.clampTarget();
422 | this.dom.scrollbar && (this.dom.scrollbar.drag.delta = this.vars.target);
423 | }
424 | }, {
425 | key: "scrollTo",
426 | value: function scrollTo(offset) {
427 | if (this.vars["native"]) {
428 | this.vars.direction == 'vertical' ? window.scrollTo(0, offset) : window.scrollTo(offset, 0);
429 | } else {
430 | this.vars.target = offset;
431 | this.clampTarget();
432 | }
433 | }
434 | }, {
435 | key: "resize",
436 | value: function resize() {
437 | var prop = this.vars.direction === 'vertical' ? 'height' : 'width';
438 | this.vars.height = window.innerHeight;
439 | this.vars.width = window.innerWidth;
440 |
441 | if (!this["extends"]) {
442 | var bounding = this.dom.section.getBoundingClientRect();
443 | this.vars.bounding = this.vars.direction === 'vertical' ? bounding.height - (this.vars["native"] ? 0 : this.vars.height) : bounding.right - (this.vars["native"] ? 0 : this.vars.width);
444 | }
445 |
446 | if (!this.vars["native"] && !this.options.noscrollbar) {
447 | this.dom.scrollbar.drag.height = this.vars.height * (this.vars.height / (this.vars.bounding + this.vars.height));
448 | this.dom.scrollbar.drag.el.style[prop] = "".concat(this.dom.scrollbar.drag.height, "px");
449 | } else if (this.vars["native"]) {
450 | this.dom.scroll.style[prop] = "".concat(this.vars.bounding, "px");
451 | }
452 |
453 | !this.vars["native"] && this.clampTarget();
454 | }
455 | }, {
456 | key: "clampTarget",
457 | value: function clampTarget() {
458 | this.vars.target = Math.round(Math.max(0, Math.min(this.vars.target, this.vars.bounding)));
459 | }
460 | }, {
461 | key: "destroy",
462 | value: function destroy() {
463 | if (this.vars["native"]) {
464 | _domClasses["default"].remove(this.dom.listener, 'is-native-scroll');
465 |
466 | this.removeFakeScrollHeight();
467 | } else {
468 | _domClasses["default"].remove(this.dom.listener, 'is-virtual-scroll');
469 |
470 | !this.options.noscrollbar && this.removeFakeScrollBar();
471 | }
472 |
473 | this.vars.direction === 'vertical' ? _domClasses["default"].remove(this.dom.listener, 'y-scroll') : _domClasses["default"].remove(this.dom.listener, 'x-scroll');
474 | this.vars.current = 0;
475 | this.vs && (this.vs.destroy(), this.vs = null);
476 | this.removeEvents();
477 | }
478 | }]);
479 |
480 | return Smooth;
481 | }();
482 |
483 | exports["default"] = Smooth;
484 | window.Smooth = Smooth;
485 |
486 | },{"dom-classes":5,"dom-create-element":6,"dom-events":7,"prefix":11,"virtual-scroll":17}],4:[function(require,module,exports){
487 | 'use strict';
488 |
489 | var toString = Object.prototype.toString,
490 | hasOwnProperty = Object.prototype.hasOwnProperty;
491 |
492 | module.exports = function(object) {
493 | if(!object) return console.warn('bindAll requires at least one argument.');
494 |
495 | var functions = Array.prototype.slice.call(arguments, 1);
496 |
497 | if (functions.length === 0) {
498 |
499 | for (var method in object) {
500 | if(hasOwnProperty.call(object, method)) {
501 | if(typeof object[method] == 'function' && toString.call(object[method]) == "[object Function]") {
502 | functions.push(method);
503 | }
504 | }
505 | }
506 | }
507 |
508 | for(var i = 0; i < functions.length; i++) {
509 | var f = functions[i];
510 | object[f] = bind(object[f], object);
511 | }
512 | };
513 |
514 | /*
515 | Faster bind without specific-case checking. (see https://coderwall.com/p/oi3j3w).
516 | bindAll is only needed for events binding so no need to make slow fixes for constructor
517 | or partial application.
518 | */
519 | function bind(func, context) {
520 | return function() {
521 | return func.apply(context, arguments);
522 | };
523 | }
524 | },{}],5:[function(require,module,exports){
525 | /**
526 | * Module dependencies.
527 | */
528 |
529 | var index = require('indexof');
530 |
531 | /**
532 | * Whitespace regexp.
533 | */
534 |
535 | var whitespaceRe = /\s+/;
536 |
537 | /**
538 | * toString reference.
539 | */
540 |
541 | var toString = Object.prototype.toString;
542 |
543 | module.exports = classes;
544 | module.exports.add = add;
545 | module.exports.contains = has;
546 | module.exports.has = has;
547 | module.exports.toggle = toggle;
548 | module.exports.remove = remove;
549 | module.exports.removeMatching = removeMatching;
550 |
551 | function classes (el) {
552 | if (el.classList) {
553 | return el.classList;
554 | }
555 |
556 | var str = el.className.replace(/^\s+|\s+$/g, '');
557 | var arr = str.split(whitespaceRe);
558 | if ('' === arr[0]) arr.shift();
559 | return arr;
560 | }
561 |
562 | function add (el, name) {
563 | // classList
564 | if (el.classList) {
565 | el.classList.add(name);
566 | return;
567 | }
568 |
569 | // fallback
570 | var arr = classes(el);
571 | var i = index(arr, name);
572 | if (!~i) arr.push(name);
573 | el.className = arr.join(' ');
574 | }
575 |
576 | function has (el, name) {
577 | return el.classList
578 | ? el.classList.contains(name)
579 | : !! ~index(classes(el), name);
580 | }
581 |
582 | function remove (el, name) {
583 | if ('[object RegExp]' == toString.call(name)) {
584 | return removeMatching(el, name);
585 | }
586 |
587 | // classList
588 | if (el.classList) {
589 | el.classList.remove(name);
590 | return;
591 | }
592 |
593 | // fallback
594 | var arr = classes(el);
595 | var i = index(arr, name);
596 | if (~i) arr.splice(i, 1);
597 | el.className = arr.join(' ');
598 | }
599 |
600 | function removeMatching (el, re, ref) {
601 | var arr = Array.prototype.slice.call(classes(el));
602 | for (var i = 0; i < arr.length; i++) {
603 | if (re.test(arr[i])) {
604 | remove(el, arr[i]);
605 | }
606 | }
607 | }
608 |
609 | function toggle (el, name) {
610 | // classList
611 | if (el.classList) {
612 | return el.classList.toggle(name);
613 | }
614 |
615 | // fallback
616 | if (has(el, name)) {
617 | remove(el, name);
618 | } else {
619 | add(el, name);
620 | }
621 | }
622 |
623 | },{"indexof":8}],6:[function(require,module,exports){
624 | /*
625 | `dom-create-element`
626 |
627 | var create = require('dom-create-element');
628 |
629 | var el = create({
630 | selector: 'div',
631 | styles: 'preloader',
632 | html: 'Text'
633 | });
634 | */
635 |
636 | module.exports = create;
637 |
638 | function create(opt) {
639 |
640 | opt = opt || {};
641 |
642 | var el = document.createElement(opt.selector);
643 |
644 | if(opt.attr) for(var index in opt.attr)
645 | opt.attr.hasOwnProperty(index) && el.setAttribute(index, opt.attr[index]);
646 |
647 | "a" == opt.selector && opt.link && (
648 | el.href = opt.link,
649 | opt.target && el.setAttribute("target", opt.target)
650 | );
651 |
652 | "img" == opt.selector && opt.src && (
653 | el.src = opt.src,
654 | opt.lazyload && (
655 | el.style.opacity = 0,
656 | el.onload = function(){
657 | el.style.opacity = 1;
658 | }
659 | )
660 | );
661 |
662 | opt.id && (el.id = opt.id);
663 | opt.styles && (el.className = opt.styles);
664 |
665 | opt.html && (el.innerHTML = opt.html);
666 | opt.children && (el.appendChild(opt.children));
667 |
668 | return el;
669 | };
670 | },{}],7:[function(require,module,exports){
671 |
672 | var synth = require('synthetic-dom-events');
673 |
674 | var on = function(element, name, fn, capture) {
675 | return element.addEventListener(name, fn, capture || false);
676 | };
677 |
678 | var off = function(element, name, fn, capture) {
679 | return element.removeEventListener(name, fn, capture || false);
680 | };
681 |
682 | var once = function (element, name, fn, capture) {
683 | function tmp (ev) {
684 | off(element, name, tmp, capture);
685 | fn(ev);
686 | }
687 | on(element, name, tmp, capture);
688 | };
689 |
690 | var emit = function(element, name, opt) {
691 | var ev = synth(name, opt);
692 | element.dispatchEvent(ev);
693 | };
694 |
695 | if (!document.addEventListener) {
696 | on = function(element, name, fn) {
697 | return element.attachEvent('on' + name, fn);
698 | };
699 | }
700 |
701 | if (!document.removeEventListener) {
702 | off = function(element, name, fn) {
703 | return element.detachEvent('on' + name, fn);
704 | };
705 | }
706 |
707 | if (!document.dispatchEvent) {
708 | emit = function(element, name, opt) {
709 | var ev = synth(name, opt);
710 | return element.fireEvent('on' + ev.type, ev);
711 | };
712 | }
713 |
714 | module.exports = {
715 | on: on,
716 | off: off,
717 | once: once,
718 | emit: emit
719 | };
720 |
721 | },{"synthetic-dom-events":12}],8:[function(require,module,exports){
722 |
723 | var indexOf = [].indexOf;
724 |
725 | module.exports = function(arr, obj){
726 | if (indexOf) return arr.indexOf(obj);
727 | for (var i = 0; i < arr.length; ++i) {
728 | if (arr[i] === obj) return i;
729 | }
730 | return -1;
731 | };
732 | },{}],9:[function(require,module,exports){
733 | // Generated by CoffeeScript 1.9.2
734 | (function() {
735 | var root;
736 |
737 | root = typeof exports !== "undefined" && exports !== null ? exports : this;
738 |
739 | root.Lethargy = (function() {
740 | function Lethargy(stability, sensitivity, tolerance, delay) {
741 | this.stability = stability != null ? Math.abs(stability) : 8;
742 | this.sensitivity = sensitivity != null ? 1 + Math.abs(sensitivity) : 100;
743 | this.tolerance = tolerance != null ? 1 + Math.abs(tolerance) : 1.1;
744 | this.delay = delay != null ? delay : 150;
745 | this.lastUpDeltas = (function() {
746 | var i, ref, results;
747 | results = [];
748 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
749 | results.push(null);
750 | }
751 | return results;
752 | }).call(this);
753 | this.lastDownDeltas = (function() {
754 | var i, ref, results;
755 | results = [];
756 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
757 | results.push(null);
758 | }
759 | return results;
760 | }).call(this);
761 | this.deltasTimestamp = (function() {
762 | var i, ref, results;
763 | results = [];
764 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
765 | results.push(null);
766 | }
767 | return results;
768 | }).call(this);
769 | }
770 |
771 | Lethargy.prototype.check = function(e) {
772 | var lastDelta;
773 | e = e.originalEvent || e;
774 | if (e.wheelDelta != null) {
775 | lastDelta = e.wheelDelta;
776 | } else if (e.deltaY != null) {
777 | lastDelta = e.deltaY * -40;
778 | } else if ((e.detail != null) || e.detail === 0) {
779 | lastDelta = e.detail * -40;
780 | }
781 | this.deltasTimestamp.push(Date.now());
782 | this.deltasTimestamp.shift();
783 | if (lastDelta > 0) {
784 | this.lastUpDeltas.push(lastDelta);
785 | this.lastUpDeltas.shift();
786 | return this.isInertia(1);
787 | } else {
788 | this.lastDownDeltas.push(lastDelta);
789 | this.lastDownDeltas.shift();
790 | return this.isInertia(-1);
791 | }
792 | return false;
793 | };
794 |
795 | Lethargy.prototype.isInertia = function(direction) {
796 | var lastDeltas, lastDeltasNew, lastDeltasOld, newAverage, newSum, oldAverage, oldSum;
797 | lastDeltas = direction === -1 ? this.lastDownDeltas : this.lastUpDeltas;
798 | if (lastDeltas[0] === null) {
799 | return direction;
800 | }
801 | if (this.deltasTimestamp[(this.stability * 2) - 2] + this.delay > Date.now() && lastDeltas[0] === lastDeltas[(this.stability * 2) - 1]) {
802 | return false;
803 | }
804 | lastDeltasOld = lastDeltas.slice(0, this.stability);
805 | lastDeltasNew = lastDeltas.slice(this.stability, this.stability * 2);
806 | oldSum = lastDeltasOld.reduce(function(t, s) {
807 | return t + s;
808 | });
809 | newSum = lastDeltasNew.reduce(function(t, s) {
810 | return t + s;
811 | });
812 | oldAverage = oldSum / lastDeltasOld.length;
813 | newAverage = newSum / lastDeltasNew.length;
814 | if (Math.abs(oldAverage) < Math.abs(newAverage * this.tolerance) && (this.sensitivity < Math.abs(newAverage))) {
815 | return direction;
816 | } else {
817 | return false;
818 | }
819 | };
820 |
821 | Lethargy.prototype.showLastUpDeltas = function() {
822 | return this.lastUpDeltas;
823 | };
824 |
825 | Lethargy.prototype.showLastDownDeltas = function() {
826 | return this.lastDownDeltas;
827 | };
828 |
829 | return Lethargy;
830 |
831 | })();
832 |
833 | }).call(this);
834 |
835 | },{}],10:[function(require,module,exports){
836 | /*
837 | object-assign
838 | (c) Sindre Sorhus
839 | @license MIT
840 | */
841 |
842 | 'use strict';
843 | /* eslint-disable no-unused-vars */
844 | var getOwnPropertySymbols = Object.getOwnPropertySymbols;
845 | var hasOwnProperty = Object.prototype.hasOwnProperty;
846 | var propIsEnumerable = Object.prototype.propertyIsEnumerable;
847 |
848 | function toObject(val) {
849 | if (val === null || val === undefined) {
850 | throw new TypeError('Object.assign cannot be called with null or undefined');
851 | }
852 |
853 | return Object(val);
854 | }
855 |
856 | function shouldUseNative() {
857 | try {
858 | if (!Object.assign) {
859 | return false;
860 | }
861 |
862 | // Detect buggy property enumeration order in older V8 versions.
863 |
864 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118
865 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
866 | test1[5] = 'de';
867 | if (Object.getOwnPropertyNames(test1)[0] === '5') {
868 | return false;
869 | }
870 |
871 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
872 | var test2 = {};
873 | for (var i = 0; i < 10; i++) {
874 | test2['_' + String.fromCharCode(i)] = i;
875 | }
876 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
877 | return test2[n];
878 | });
879 | if (order2.join('') !== '0123456789') {
880 | return false;
881 | }
882 |
883 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
884 | var test3 = {};
885 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
886 | test3[letter] = letter;
887 | });
888 | if (Object.keys(Object.assign({}, test3)).join('') !==
889 | 'abcdefghijklmnopqrst') {
890 | return false;
891 | }
892 |
893 | return true;
894 | } catch (err) {
895 | // We don't expect any of the above to throw, but better to be safe.
896 | return false;
897 | }
898 | }
899 |
900 | module.exports = shouldUseNative() ? Object.assign : function (target, source) {
901 | var from;
902 | var to = toObject(target);
903 | var symbols;
904 |
905 | for (var s = 1; s < arguments.length; s++) {
906 | from = Object(arguments[s]);
907 |
908 | for (var key in from) {
909 | if (hasOwnProperty.call(from, key)) {
910 | to[key] = from[key];
911 | }
912 | }
913 |
914 | if (getOwnPropertySymbols) {
915 | symbols = getOwnPropertySymbols(from);
916 | for (var i = 0; i < symbols.length; i++) {
917 | if (propIsEnumerable.call(from, symbols[i])) {
918 | to[symbols[i]] = from[symbols[i]];
919 | }
920 | }
921 | }
922 | }
923 |
924 | return to;
925 | };
926 |
927 | },{}],11:[function(require,module,exports){
928 | // check document first so it doesn't error in node.js
929 | var style = typeof document != 'undefined'
930 | ? document.createElement('p').style
931 | : {}
932 |
933 | var prefixes = ['O', 'ms', 'Moz', 'Webkit']
934 | var upper = /([A-Z])/g
935 | var memo = {}
936 |
937 | /**
938 | * prefix `key`
939 | *
940 | * prefix('transform') // => WebkitTransform
941 | *
942 | * @param {String} key
943 | * @return {String}
944 | * @api public
945 | */
946 | function prefix(key){
947 | // Camel case
948 | key = key.replace(/-([a-z])/g, function(_, char){
949 | return char.toUpperCase()
950 | })
951 |
952 | // Without prefix
953 | if (style[key] !== undefined) return key
954 |
955 | // With prefix
956 | var Key = key.charAt(0).toUpperCase() + key.slice(1)
957 | var i = prefixes.length
958 | while (i--) {
959 | var name = prefixes[i] + Key
960 | if (style[name] !== undefined) return name
961 | }
962 |
963 | return key
964 | }
965 |
966 | /**
967 | * Memoized version of `prefix`
968 | *
969 | * @param {String} key
970 | * @return {String}
971 | * @api public
972 | */
973 | function prefixMemozied(key){
974 | return key in memo
975 | ? memo[key]
976 | : memo[key] = prefix(key)
977 | }
978 |
979 | /**
980 | * Create a dashed prefix
981 | *
982 | * @param {String} key
983 | * @return {String}
984 | * @api public
985 | */
986 | function prefixDashed(key){
987 | key = prefix(key)
988 | if (upper.test(key)) {
989 | key = '-' + key.replace(upper, '-$1')
990 | upper.lastIndex = 0
991 | }
992 | return key.toLowerCase()
993 | }
994 |
995 | module.exports = prefixMemozied
996 | module.exports.dash = prefixDashed
997 |
998 | },{}],12:[function(require,module,exports){
999 |
1000 | // for compression
1001 | var win = window;
1002 | var doc = document || {};
1003 | var root = doc.documentElement || {};
1004 |
1005 | // detect if we need to use firefox KeyEvents vs KeyboardEvents
1006 | var use_key_event = true;
1007 | try {
1008 | doc.createEvent('KeyEvents');
1009 | }
1010 | catch (err) {
1011 | use_key_event = false;
1012 | }
1013 |
1014 | // Workaround for https://bugs.webkit.org/show_bug.cgi?id=16735
1015 | function check_kb(ev, opts) {
1016 | if (ev.ctrlKey != (opts.ctrlKey || false) ||
1017 | ev.altKey != (opts.altKey || false) ||
1018 | ev.shiftKey != (opts.shiftKey || false) ||
1019 | ev.metaKey != (opts.metaKey || false) ||
1020 | ev.keyCode != (opts.keyCode || 0) ||
1021 | ev.charCode != (opts.charCode || 0)) {
1022 |
1023 | ev = document.createEvent('Event');
1024 | ev.initEvent(opts.type, opts.bubbles, opts.cancelable);
1025 | ev.ctrlKey = opts.ctrlKey || false;
1026 | ev.altKey = opts.altKey || false;
1027 | ev.shiftKey = opts.shiftKey || false;
1028 | ev.metaKey = opts.metaKey || false;
1029 | ev.keyCode = opts.keyCode || 0;
1030 | ev.charCode = opts.charCode || 0;
1031 | }
1032 |
1033 | return ev;
1034 | }
1035 |
1036 | // modern browsers, do a proper dispatchEvent()
1037 | var modern = function(type, opts) {
1038 | opts = opts || {};
1039 |
1040 | // which init fn do we use
1041 | var family = typeOf(type);
1042 | var init_fam = family;
1043 | if (family === 'KeyboardEvent' && use_key_event) {
1044 | family = 'KeyEvents';
1045 | init_fam = 'KeyEvent';
1046 | }
1047 |
1048 | var ev = doc.createEvent(family);
1049 | var init_fn = 'init' + init_fam;
1050 | var init = typeof ev[init_fn] === 'function' ? init_fn : 'initEvent';
1051 |
1052 | var sig = initSignatures[init];
1053 | var args = [];
1054 | var used = {};
1055 |
1056 | opts.type = type;
1057 | for (var i = 0; i < sig.length; ++i) {
1058 | var key = sig[i];
1059 | var val = opts[key];
1060 | // if no user specified value, then use event default
1061 | if (val === undefined) {
1062 | val = ev[key];
1063 | }
1064 | used[key] = true;
1065 | args.push(val);
1066 | }
1067 | ev[init].apply(ev, args);
1068 |
1069 | // webkit key event issue workaround
1070 | if (family === 'KeyboardEvent') {
1071 | ev = check_kb(ev, opts);
1072 | }
1073 |
1074 | // attach remaining unused options to the object
1075 | for (var key in opts) {
1076 | if (!used[key]) {
1077 | ev[key] = opts[key];
1078 | }
1079 | }
1080 |
1081 | return ev;
1082 | };
1083 |
1084 | var legacy = function (type, opts) {
1085 | opts = opts || {};
1086 | var ev = doc.createEventObject();
1087 |
1088 | ev.type = type;
1089 | for (var key in opts) {
1090 | if (opts[key] !== undefined) {
1091 | ev[key] = opts[key];
1092 | }
1093 | }
1094 |
1095 | return ev;
1096 | };
1097 |
1098 | // expose either the modern version of event generation or legacy
1099 | // depending on what we support
1100 | // avoids if statements in the code later
1101 | module.exports = doc.createEvent ? modern : legacy;
1102 |
1103 | var initSignatures = require('./init.json');
1104 | var types = require('./types.json');
1105 | var typeOf = (function () {
1106 | var typs = {};
1107 | for (var key in types) {
1108 | var ts = types[key];
1109 | for (var i = 0; i < ts.length; i++) {
1110 | typs[ts[i]] = key;
1111 | }
1112 | }
1113 |
1114 | return function (name) {
1115 | return typs[name] || 'Event';
1116 | };
1117 | })();
1118 |
1119 | },{"./init.json":13,"./types.json":14}],13:[function(require,module,exports){
1120 | module.exports={
1121 | "initEvent" : [
1122 | "type",
1123 | "bubbles",
1124 | "cancelable"
1125 | ],
1126 | "initUIEvent" : [
1127 | "type",
1128 | "bubbles",
1129 | "cancelable",
1130 | "view",
1131 | "detail"
1132 | ],
1133 | "initMouseEvent" : [
1134 | "type",
1135 | "bubbles",
1136 | "cancelable",
1137 | "view",
1138 | "detail",
1139 | "screenX",
1140 | "screenY",
1141 | "clientX",
1142 | "clientY",
1143 | "ctrlKey",
1144 | "altKey",
1145 | "shiftKey",
1146 | "metaKey",
1147 | "button",
1148 | "relatedTarget"
1149 | ],
1150 | "initMutationEvent" : [
1151 | "type",
1152 | "bubbles",
1153 | "cancelable",
1154 | "relatedNode",
1155 | "prevValue",
1156 | "newValue",
1157 | "attrName",
1158 | "attrChange"
1159 | ],
1160 | "initKeyboardEvent" : [
1161 | "type",
1162 | "bubbles",
1163 | "cancelable",
1164 | "view",
1165 | "ctrlKey",
1166 | "altKey",
1167 | "shiftKey",
1168 | "metaKey",
1169 | "keyCode",
1170 | "charCode"
1171 | ],
1172 | "initKeyEvent" : [
1173 | "type",
1174 | "bubbles",
1175 | "cancelable",
1176 | "view",
1177 | "ctrlKey",
1178 | "altKey",
1179 | "shiftKey",
1180 | "metaKey",
1181 | "keyCode",
1182 | "charCode"
1183 | ]
1184 | }
1185 |
1186 | },{}],14:[function(require,module,exports){
1187 | module.exports={
1188 | "MouseEvent" : [
1189 | "click",
1190 | "mousedown",
1191 | "mouseup",
1192 | "mouseover",
1193 | "mousemove",
1194 | "mouseout"
1195 | ],
1196 | "KeyboardEvent" : [
1197 | "keydown",
1198 | "keyup",
1199 | "keypress"
1200 | ],
1201 | "MutationEvent" : [
1202 | "DOMSubtreeModified",
1203 | "DOMNodeInserted",
1204 | "DOMNodeRemoved",
1205 | "DOMNodeRemovedFromDocument",
1206 | "DOMNodeInsertedIntoDocument",
1207 | "DOMAttrModified",
1208 | "DOMCharacterDataModified"
1209 | ],
1210 | "HTMLEvents" : [
1211 | "load",
1212 | "unload",
1213 | "abort",
1214 | "error",
1215 | "select",
1216 | "change",
1217 | "submit",
1218 | "reset",
1219 | "focus",
1220 | "blur",
1221 | "resize",
1222 | "scroll"
1223 | ],
1224 | "UIEvent" : [
1225 | "DOMFocusIn",
1226 | "DOMFocusOut",
1227 | "DOMActivate"
1228 | ]
1229 | }
1230 |
1231 | },{}],15:[function(require,module,exports){
1232 | function E () {
1233 | // Keep this empty so it's easier to inherit from
1234 | // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
1235 | }
1236 |
1237 | E.prototype = {
1238 | on: function (name, callback, ctx) {
1239 | var e = this.e || (this.e = {});
1240 |
1241 | (e[name] || (e[name] = [])).push({
1242 | fn: callback,
1243 | ctx: ctx
1244 | });
1245 |
1246 | return this;
1247 | },
1248 |
1249 | once: function (name, callback, ctx) {
1250 | var self = this;
1251 | function listener () {
1252 | self.off(name, listener);
1253 | callback.apply(ctx, arguments);
1254 | };
1255 |
1256 | listener._ = callback
1257 | return this.on(name, listener, ctx);
1258 | },
1259 |
1260 | emit: function (name) {
1261 | var data = [].slice.call(arguments, 1);
1262 | var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
1263 | var i = 0;
1264 | var len = evtArr.length;
1265 |
1266 | for (i; i < len; i++) {
1267 | evtArr[i].fn.apply(evtArr[i].ctx, data);
1268 | }
1269 |
1270 | return this;
1271 | },
1272 |
1273 | off: function (name, callback) {
1274 | var e = this.e || (this.e = {});
1275 | var evts = e[name];
1276 | var liveEvents = [];
1277 |
1278 | if (evts && callback) {
1279 | for (var i = 0, len = evts.length; i < len; i++) {
1280 | if (evts[i].fn !== callback && evts[i].fn._ !== callback)
1281 | liveEvents.push(evts[i]);
1282 | }
1283 | }
1284 |
1285 | // Remove event from queue to prevent memory leak
1286 | // Suggested by https://github.com/lazd
1287 | // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
1288 |
1289 | (liveEvents.length)
1290 | ? e[name] = liveEvents
1291 | : delete e[name];
1292 |
1293 | return this;
1294 | }
1295 | };
1296 |
1297 | module.exports = E;
1298 |
1299 | },{}],16:[function(require,module,exports){
1300 | 'use strict';
1301 |
1302 | module.exports = function(source) {
1303 | return JSON.parse(JSON.stringify(source));
1304 | };
1305 | },{}],17:[function(require,module,exports){
1306 | 'use strict';
1307 |
1308 | var objectAssign = require('object-assign');
1309 | var Emitter = require('tiny-emitter');
1310 | var Lethargy = require('lethargy').Lethargy;
1311 | var support = require('./support');
1312 | var clone = require('./clone');
1313 | var bindAll = require('bindall-standalone');
1314 | var EVT_ID = 'virtualscroll';
1315 |
1316 | module.exports = VirtualScroll;
1317 |
1318 | var keyCodes = {
1319 | LEFT: 37,
1320 | UP: 38,
1321 | RIGHT: 39,
1322 | DOWN: 40,
1323 | SPACE: 32
1324 | };
1325 |
1326 | function VirtualScroll(options) {
1327 | bindAll(this, '_onWheel', '_onMouseWheel', '_onTouchStart', '_onTouchMove', '_onKeyDown');
1328 |
1329 | this.el = window;
1330 | if (options && options.el) {
1331 | this.el = options.el;
1332 | delete options.el;
1333 | }
1334 | this.options = objectAssign({
1335 | mouseMultiplier: 1,
1336 | touchMultiplier: 2,
1337 | firefoxMultiplier: 15,
1338 | keyStep: 120,
1339 | preventTouch: false,
1340 | unpreventTouchClass: 'vs-touchmove-allowed',
1341 | limitInertia: false
1342 | }, options);
1343 |
1344 | if (this.options.limitInertia) this._lethargy = new Lethargy();
1345 |
1346 | this._emitter = new Emitter();
1347 | this._event = {
1348 | y: 0,
1349 | x: 0,
1350 | deltaX: 0,
1351 | deltaY: 0
1352 | };
1353 | this.touchStartX = null;
1354 | this.touchStartY = null;
1355 | this.bodyTouchAction = null;
1356 |
1357 | if (this.options.passive !== undefined) {
1358 | this.listenerOptions = {passive: this.options.passive};
1359 | }
1360 | }
1361 |
1362 | VirtualScroll.prototype._notify = function(e) {
1363 | var evt = this._event;
1364 | evt.x += evt.deltaX;
1365 | evt.y += evt.deltaY;
1366 |
1367 | this._emitter.emit(EVT_ID, {
1368 | x: evt.x,
1369 | y: evt.y,
1370 | deltaX: evt.deltaX,
1371 | deltaY: evt.deltaY,
1372 | originalEvent: e
1373 | });
1374 | };
1375 |
1376 | VirtualScroll.prototype._onWheel = function(e) {
1377 | var options = this.options;
1378 | if (this._lethargy && this._lethargy.check(e) === false) return;
1379 | var evt = this._event;
1380 |
1381 | // In Chrome and in Firefox (at least the new one)
1382 | evt.deltaX = e.wheelDeltaX || e.deltaX * -1;
1383 | evt.deltaY = e.wheelDeltaY || e.deltaY * -1;
1384 |
1385 | // for our purpose deltamode = 1 means user is on a wheel mouse, not touch pad
1386 | // real meaning: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent#Delta_modes
1387 | if(support.isFirefox && e.deltaMode == 1) {
1388 | evt.deltaX *= options.firefoxMultiplier;
1389 | evt.deltaY *= options.firefoxMultiplier;
1390 | }
1391 |
1392 | evt.deltaX *= options.mouseMultiplier;
1393 | evt.deltaY *= options.mouseMultiplier;
1394 |
1395 | this._notify(e);
1396 | };
1397 |
1398 | VirtualScroll.prototype._onMouseWheel = function(e) {
1399 | if (this.options.limitInertia && this._lethargy.check(e) === false) return;
1400 |
1401 | var evt = this._event;
1402 |
1403 | // In Safari, IE and in Chrome if 'wheel' isn't defined
1404 | evt.deltaX = (e.wheelDeltaX) ? e.wheelDeltaX : 0;
1405 | evt.deltaY = (e.wheelDeltaY) ? e.wheelDeltaY : e.wheelDelta;
1406 |
1407 | this._notify(e);
1408 | };
1409 |
1410 | VirtualScroll.prototype._onTouchStart = function(e) {
1411 | var t = (e.targetTouches) ? e.targetTouches[0] : e;
1412 | this.touchStartX = t.pageX;
1413 | this.touchStartY = t.pageY;
1414 | };
1415 |
1416 | VirtualScroll.prototype._onTouchMove = function(e) {
1417 | var options = this.options;
1418 | if(options.preventTouch
1419 | && !e.target.classList.contains(options.unpreventTouchClass)) {
1420 | e.preventDefault();
1421 | }
1422 |
1423 | var evt = this._event;
1424 |
1425 | var t = (e.targetTouches) ? e.targetTouches[0] : e;
1426 |
1427 | evt.deltaX = (t.pageX - this.touchStartX) * options.touchMultiplier;
1428 | evt.deltaY = (t.pageY - this.touchStartY) * options.touchMultiplier;
1429 |
1430 | this.touchStartX = t.pageX;
1431 | this.touchStartY = t.pageY;
1432 |
1433 | this._notify(e);
1434 | };
1435 |
1436 | VirtualScroll.prototype._onKeyDown = function(e) {
1437 | var evt = this._event;
1438 | evt.deltaX = evt.deltaY = 0;
1439 | var windowHeight = window.innerHeight - 40
1440 |
1441 | switch(e.keyCode) {
1442 | case keyCodes.LEFT:
1443 | case keyCodes.UP:
1444 | evt.deltaY = this.options.keyStep;
1445 | break;
1446 |
1447 | case keyCodes.RIGHT:
1448 | case keyCodes.DOWN:
1449 | evt.deltaY = - this.options.keyStep;
1450 | break;
1451 | case keyCodes.SPACE && e.shiftKey:
1452 | evt.deltaY = windowHeight;
1453 | break;
1454 | case keyCodes.SPACE:
1455 | evt.deltaY = - windowHeight;
1456 | break;
1457 | default:
1458 | return;
1459 | }
1460 |
1461 | this._notify(e);
1462 | };
1463 |
1464 | VirtualScroll.prototype._bind = function() {
1465 | if(support.hasWheelEvent) this.el.addEventListener('wheel', this._onWheel, this.listenerOptions);
1466 | if(support.hasMouseWheelEvent) this.el.addEventListener('mousewheel', this._onMouseWheel, this.listenerOptions);
1467 |
1468 | if(support.hasTouch) {
1469 | this.el.addEventListener('touchstart', this._onTouchStart, this.listenerOptions);
1470 | this.el.addEventListener('touchmove', this._onTouchMove, this.listenerOptions);
1471 | }
1472 |
1473 | if(support.hasPointer && support.hasTouchWin) {
1474 | this.bodyTouchAction = document.body.style.msTouchAction;
1475 | document.body.style.msTouchAction = 'none';
1476 | this.el.addEventListener('MSPointerDown', this._onTouchStart, true);
1477 | this.el.addEventListener('MSPointerMove', this._onTouchMove, true);
1478 | }
1479 |
1480 | if(support.hasKeyDown) document.addEventListener('keydown', this._onKeyDown);
1481 | };
1482 |
1483 | VirtualScroll.prototype._unbind = function() {
1484 | if(support.hasWheelEvent) this.el.removeEventListener('wheel', this._onWheel);
1485 | if(support.hasMouseWheelEvent) this.el.removeEventListener('mousewheel', this._onMouseWheel);
1486 |
1487 | if(support.hasTouch) {
1488 | this.el.removeEventListener('touchstart', this._onTouchStart);
1489 | this.el.removeEventListener('touchmove', this._onTouchMove);
1490 | }
1491 |
1492 | if(support.hasPointer && support.hasTouchWin) {
1493 | document.body.style.msTouchAction = this.bodyTouchAction;
1494 | this.el.removeEventListener('MSPointerDown', this._onTouchStart, true);
1495 | this.el.removeEventListener('MSPointerMove', this._onTouchMove, true);
1496 | }
1497 |
1498 | if(support.hasKeyDown) document.removeEventListener('keydown', this._onKeyDown);
1499 | };
1500 |
1501 | VirtualScroll.prototype.on = function(cb, ctx) {
1502 | this._emitter.on(EVT_ID, cb, ctx);
1503 |
1504 | var events = this._emitter.e;
1505 | if (events && events[EVT_ID] && events[EVT_ID].length === 1) this._bind();
1506 | };
1507 |
1508 | VirtualScroll.prototype.off = function(cb, ctx) {
1509 | this._emitter.off(EVT_ID, cb, ctx);
1510 |
1511 | var events = this._emitter.e;
1512 | if (!events[EVT_ID] || events[EVT_ID].length <= 0) this._unbind();
1513 | };
1514 |
1515 | VirtualScroll.prototype.reset = function() {
1516 | var evt = this._event;
1517 | evt.x = 0;
1518 | evt.y = 0;
1519 | };
1520 |
1521 | VirtualScroll.prototype.destroy = function() {
1522 | this._emitter.off();
1523 | this._unbind();
1524 | };
1525 |
1526 | },{"./clone":16,"./support":18,"bindall-standalone":4,"lethargy":9,"object-assign":10,"tiny-emitter":15}],18:[function(require,module,exports){
1527 | 'use strict';
1528 |
1529 | module.exports = (function getSupport() {
1530 | return {
1531 | hasWheelEvent: 'onwheel' in document,
1532 | hasMouseWheelEvent: 'onmousewheel' in document,
1533 | hasTouch: 'ontouchstart' in document,
1534 | hasTouchWin: navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 1,
1535 | hasPointer: !!window.navigator.msPointerEnabled,
1536 | hasKeyDown: 'onkeydown' in document,
1537 | isFirefox: navigator.userAgent.indexOf('Firefox') > -1
1538 | };
1539 | })();
1540 |
1541 | },{}]},{},[2]);
1542 |
--------------------------------------------------------------------------------
/demos/performances/build.js:
--------------------------------------------------------------------------------
1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {};
129 |
130 | _classCallCheck(this, Smooth);
131 |
132 | this.createBound();
133 | this.options = opt;
134 | this.prefix = (0, _prefix["default"])('transform');
135 | this.rAF = undefined; // It seems that under heavy load, Firefox will still call the RAF callback even though the RAF has been canceled
136 | // To prevent that we set a flag to prevent any callback to be executed when RAF is removed
137 |
138 | this.isRAFCanceled = false;
139 | var constructorName = this.constructor.name ? this.constructor.name : 'Smooth';
140 | this["extends"] = typeof opt["extends"] === 'undefined' ? this.constructor !== Smooth : opt["extends"];
141 | this.callback = this.options.callback || null;
142 | this.vars = {
143 | direction: this.options.direction || 'vertical',
144 | "native": this.options["native"] || false,
145 | ease: this.options.ease || 0.075,
146 | preload: this.options.preload || false,
147 | current: 0,
148 | last: 0,
149 | target: 0,
150 | height: window.innerHeight,
151 | width: window.innerWidth,
152 | bounding: 0,
153 | timer: null,
154 | ticking: false
155 | };
156 | this.vs = this.vars["native"] ? null : new _virtualScroll["default"]({
157 | limitInertia: this.options.vs && this.options.vs.limitInertia || false,
158 | mouseMultiplier: this.options.vs && this.options.vs.mouseMultiplier || 1,
159 | touchMultiplier: this.options.vs && this.options.vs.touchMultiplier || 1.5,
160 | firefoxMultiplier: this.options.vs && this.options.vs.firefoxMultiplier || 30,
161 | preventTouch: this.options.vs && this.options.vs.preventTouch || true
162 | });
163 | this.dom = {
164 | listener: this.options.listener || document.body,
165 | section: this.options.section || document.querySelector('.vs-section') || null,
166 | scrollbar: this.vars["native"] || this.options.noscrollbar ? null : {
167 | state: {
168 | clicked: false,
169 | x: 0
170 | },
171 | el: (0, _domCreateElement["default"])({
172 | selector: 'div',
173 | styles: "vs-scrollbar vs-".concat(this.vars.direction, " vs-scrollbar-").concat(constructorName.toLowerCase())
174 | }),
175 | drag: {
176 | el: (0, _domCreateElement["default"])({
177 | selector: 'div',
178 | styles: 'vs-scrolldrag'
179 | }),
180 | delta: 0,
181 | height: 50
182 | }
183 | }
184 | };
185 | }
186 |
187 | _createClass(Smooth, [{
188 | key: "createBound",
189 | value: function createBound() {
190 | var _this = this;
191 |
192 | ['run', 'calc', 'debounce', 'resize', 'mouseUp', 'mouseDown', 'mouseMove', 'calcScroll', 'scrollTo'].forEach(function (fn) {
193 | return _this[fn] = _this[fn].bind(_this);
194 | });
195 | }
196 | }, {
197 | key: "init",
198 | value: function init() {
199 | this.addClasses();
200 | this.vars.preload && this.preloadImages();
201 | this.vars["native"] ? this.addFakeScrollHeight() : !this.options.noscrollbar && this.addFakeScrollBar();
202 | this.addEvents();
203 | this.resize();
204 | }
205 | }, {
206 | key: "addClasses",
207 | value: function addClasses() {
208 | var type = this.vars["native"] ? 'native' : 'virtual';
209 | var direction = this.vars.direction === 'vertical' ? 'y' : 'x';
210 |
211 | _domClasses["default"].add(this.dom.listener, "is-".concat(type, "-scroll"));
212 |
213 | _domClasses["default"].add(this.dom.listener, "".concat(direction, "-scroll"));
214 | }
215 | }, {
216 | key: "preloadImages",
217 | value: function preloadImages() {
218 | var _this2 = this;
219 |
220 | var images = Array.prototype.slice.call(this.dom.listener.querySelectorAll('img'), 0);
221 | images.forEach(function (image) {
222 | var img = document.createElement('img');
223 |
224 | _domEvents["default"].once(img, 'load', function () {
225 | images.splice(images.indexOf(image), 1);
226 | images.length === 0 && _this2.resize();
227 | });
228 |
229 | img.src = image.getAttribute('src');
230 | });
231 | }
232 | }, {
233 | key: "calc",
234 | value: function calc(e) {
235 | var delta = this.vars.direction == 'horizontal' ? e.deltaX : e.deltaY;
236 | this.vars.target += delta * -1;
237 | this.clampTarget();
238 | }
239 | }, {
240 | key: "debounce",
241 | value: function debounce() {
242 | var _this3 = this;
243 |
244 | var win = this.dom.listener === document.body;
245 | this.vars.target = this.vars.direction === 'vertical' ? win ? window.scrollY || window.pageYOffset : this.dom.listener.scrollTop : win ? window.scrollX || window.pageXOffset : this.dom.listener.scrollLeft;
246 | clearTimeout(this.vars.timer);
247 |
248 | if (!this.vars.ticking) {
249 | this.vars.ticking = true;
250 |
251 | _domClasses["default"].add(this.dom.listener, 'is-scrolling');
252 | }
253 |
254 | this.vars.timer = setTimeout(function () {
255 | _this3.vars.ticking = false;
256 |
257 | _domClasses["default"].remove(_this3.dom.listener, 'is-scrolling');
258 | }, 200);
259 | }
260 | }, {
261 | key: "run",
262 | value: function run() {
263 | if (this.isRAFCanceled) return;
264 | this.vars.current += (this.vars.target - this.vars.current) * this.vars.ease;
265 | this.vars.current < .1 && (this.vars.current = 0);
266 | this.requestAnimationFrame();
267 |
268 | if (!this["extends"]) {
269 | this.dom.section.style[this.prefix] = this.getTransform(-this.vars.current.toFixed(2));
270 | }
271 |
272 | if (!this.vars["native"] && !this.options.noscrollbar) {
273 | var size = this.dom.scrollbar.drag.height;
274 | var bounds = this.vars.direction === 'vertical' ? this.vars.height : this.vars.width;
275 | var value = Math.abs(this.vars.current) / (this.vars.bounding / (bounds - size)) + size / .5 - size;
276 | var clamp = Math.max(0, Math.min(value - size, value + size));
277 | this.dom.scrollbar.drag.el.style[this.prefix] = this.getTransform(clamp.toFixed(2));
278 | }
279 |
280 | if (this.callback && this.vars.current !== this.vars.last) {
281 | this.callback(this.vars.current);
282 | }
283 |
284 | this.vars.last = this.vars.current;
285 | }
286 | }, {
287 | key: "getTransform",
288 | value: function getTransform(value) {
289 | return this.vars.direction === 'vertical' ? "translate3d(0,".concat(value, "px,0)") : "translate3d(".concat(value, "px,0,0)");
290 | }
291 | }, {
292 | key: "on",
293 | value: function on() {
294 | var requestAnimationFrame = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
295 |
296 | if (this.isRAFCanceled) {
297 | this.isRAFCanceled = false;
298 | }
299 |
300 | var node = this.dom.listener === document.body ? window : this.dom.listener;
301 | this.vars["native"] ? _domEvents["default"].on(node, 'scroll', this.debounce) : this.vs && this.vs.on(this.calc);
302 | requestAnimationFrame && this.requestAnimationFrame();
303 | }
304 | }, {
305 | key: "off",
306 | value: function off() {
307 | var cancelAnimationFrame = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
308 | var node = this.dom.listener === document.body ? window : this.dom.listener;
309 | this.vars["native"] ? _domEvents["default"].off(node, 'scroll', this.debounce) : this.vs && this.vs.off(this.calc);
310 | cancelAnimationFrame && this.cancelAnimationFrame();
311 | }
312 | }, {
313 | key: "requestAnimationFrame",
314 | value: function (_requestAnimationFrame) {
315 | function requestAnimationFrame() {
316 | return _requestAnimationFrame.apply(this, arguments);
317 | }
318 |
319 | requestAnimationFrame.toString = function () {
320 | return _requestAnimationFrame.toString();
321 | };
322 |
323 | return requestAnimationFrame;
324 | }(function () {
325 | this.rAF = requestAnimationFrame(this.run);
326 | })
327 | }, {
328 | key: "cancelAnimationFrame",
329 | value: function (_cancelAnimationFrame) {
330 | function cancelAnimationFrame() {
331 | return _cancelAnimationFrame.apply(this, arguments);
332 | }
333 |
334 | cancelAnimationFrame.toString = function () {
335 | return _cancelAnimationFrame.toString();
336 | };
337 |
338 | return cancelAnimationFrame;
339 | }(function () {
340 | this.isRAFCanceled = true;
341 | cancelAnimationFrame(this.rAF);
342 | })
343 | }, {
344 | key: "addEvents",
345 | value: function addEvents() {
346 | this.on();
347 |
348 | _domEvents["default"].on(window, 'resize', this.resize);
349 | }
350 | }, {
351 | key: "removeEvents",
352 | value: function removeEvents() {
353 | this.off();
354 |
355 | _domEvents["default"].off(window, 'resize', this.resize);
356 | }
357 | }, {
358 | key: "addFakeScrollBar",
359 | value: function addFakeScrollBar() {
360 | this.dom.listener.appendChild(this.dom.scrollbar.el);
361 | this.dom.scrollbar.el.appendChild(this.dom.scrollbar.drag.el);
362 |
363 | _domEvents["default"].on(this.dom.scrollbar.el, 'click', this.calcScroll);
364 |
365 | _domEvents["default"].on(this.dom.scrollbar.el, 'mousedown', this.mouseDown);
366 |
367 | _domEvents["default"].on(document, 'mousemove', this.mouseMove);
368 |
369 | _domEvents["default"].on(document, 'mouseup', this.mouseUp);
370 | }
371 | }, {
372 | key: "removeFakeScrollBar",
373 | value: function removeFakeScrollBar() {
374 | _domEvents["default"].off(this.dom.scrollbar.el, 'click', this.calcScroll);
375 |
376 | _domEvents["default"].off(this.dom.scrollbar.el, 'mousedown', this.mouseDown);
377 |
378 | _domEvents["default"].off(document, 'mousemove', this.mouseMove);
379 |
380 | _domEvents["default"].off(document, 'mouseup', this.mouseUp);
381 |
382 | this.dom.listener.removeChild(this.dom.scrollbar.el);
383 | }
384 | }, {
385 | key: "mouseDown",
386 | value: function mouseDown(e) {
387 | e.preventDefault();
388 | e.which == 1 && (this.dom.scrollbar.state.clicked = true);
389 | }
390 | }, {
391 | key: "mouseUp",
392 | value: function mouseUp(e) {
393 | this.dom.scrollbar.state.clicked = false;
394 |
395 | _domClasses["default"].remove(this.dom.listener, 'is-dragging');
396 | }
397 | }, {
398 | key: "mouseMove",
399 | value: function mouseMove(e) {
400 | this.dom.scrollbar.state.clicked && this.calcScroll(e);
401 | }
402 | }, {
403 | key: "addFakeScrollHeight",
404 | value: function addFakeScrollHeight() {
405 | this.dom.scroll = (0, _domCreateElement["default"])({
406 | selector: 'div',
407 | styles: 'vs-scroll-view'
408 | });
409 | this.dom.listener.appendChild(this.dom.scroll);
410 | }
411 | }, {
412 | key: "removeFakeScrollHeight",
413 | value: function removeFakeScrollHeight() {
414 | this.dom.listener.removeChild(this.dom.scroll);
415 | }
416 | }, {
417 | key: "calcScroll",
418 | value: function calcScroll(e) {
419 | var client = this.vars.direction == 'vertical' ? e.clientY : e.clientX;
420 | var bounds = this.vars.direction == 'vertical' ? this.vars.height : this.vars.width;
421 | var delta = client * (this.vars.bounding / bounds);
422 |
423 | _domClasses["default"].add(this.dom.listener, 'is-dragging');
424 |
425 | this.vars.target = delta;
426 | this.clampTarget();
427 | this.dom.scrollbar && (this.dom.scrollbar.drag.delta = this.vars.target);
428 | }
429 | }, {
430 | key: "scrollTo",
431 | value: function scrollTo(offset) {
432 | if (this.vars["native"]) {
433 | this.vars.direction == 'vertical' ? window.scrollTo(0, offset) : window.scrollTo(offset, 0);
434 | } else {
435 | this.vars.target = offset;
436 | this.clampTarget();
437 | }
438 | }
439 | }, {
440 | key: "resize",
441 | value: function resize() {
442 | var prop = this.vars.direction === 'vertical' ? 'height' : 'width';
443 | this.vars.height = window.innerHeight;
444 | this.vars.width = window.innerWidth;
445 |
446 | if (!this["extends"]) {
447 | var bounding = this.dom.section.getBoundingClientRect();
448 | this.vars.bounding = this.vars.direction === 'vertical' ? bounding.height - (this.vars["native"] ? 0 : this.vars.height) : bounding.right - (this.vars["native"] ? 0 : this.vars.width);
449 | }
450 |
451 | if (!this.vars["native"] && !this.options.noscrollbar) {
452 | this.dom.scrollbar.drag.height = this.vars.height * (this.vars.height / (this.vars.bounding + this.vars.height));
453 | this.dom.scrollbar.drag.el.style[prop] = "".concat(this.dom.scrollbar.drag.height, "px");
454 | } else if (this.vars["native"]) {
455 | this.dom.scroll.style[prop] = "".concat(this.vars.bounding, "px");
456 | }
457 |
458 | !this.vars["native"] && this.clampTarget();
459 | }
460 | }, {
461 | key: "clampTarget",
462 | value: function clampTarget() {
463 | this.vars.target = Math.round(Math.max(0, Math.min(this.vars.target, this.vars.bounding)));
464 | }
465 | }, {
466 | key: "destroy",
467 | value: function destroy() {
468 | if (this.vars["native"]) {
469 | _domClasses["default"].remove(this.dom.listener, 'is-native-scroll');
470 |
471 | this.removeFakeScrollHeight();
472 | } else {
473 | _domClasses["default"].remove(this.dom.listener, 'is-virtual-scroll');
474 |
475 | !this.options.noscrollbar && this.removeFakeScrollBar();
476 | }
477 |
478 | this.vars.direction === 'vertical' ? _domClasses["default"].remove(this.dom.listener, 'y-scroll') : _domClasses["default"].remove(this.dom.listener, 'x-scroll');
479 | this.vars.current = 0;
480 | this.vs && (this.vs.destroy(), this.vs = null);
481 | this.removeEvents();
482 | }
483 | }]);
484 |
485 | return Smooth;
486 | }();
487 |
488 | exports["default"] = Smooth;
489 | window.Smooth = Smooth;
490 |
491 | },{"dom-classes":5,"dom-create-element":6,"dom-events":7,"prefix":11,"virtual-scroll":17}],4:[function(require,module,exports){
492 | 'use strict';
493 |
494 | var toString = Object.prototype.toString,
495 | hasOwnProperty = Object.prototype.hasOwnProperty;
496 |
497 | module.exports = function(object) {
498 | if(!object) return console.warn('bindAll requires at least one argument.');
499 |
500 | var functions = Array.prototype.slice.call(arguments, 1);
501 |
502 | if (functions.length === 0) {
503 |
504 | for (var method in object) {
505 | if(hasOwnProperty.call(object, method)) {
506 | if(typeof object[method] == 'function' && toString.call(object[method]) == "[object Function]") {
507 | functions.push(method);
508 | }
509 | }
510 | }
511 | }
512 |
513 | for(var i = 0; i < functions.length; i++) {
514 | var f = functions[i];
515 | object[f] = bind(object[f], object);
516 | }
517 | };
518 |
519 | /*
520 | Faster bind without specific-case checking. (see https://coderwall.com/p/oi3j3w).
521 | bindAll is only needed for events binding so no need to make slow fixes for constructor
522 | or partial application.
523 | */
524 | function bind(func, context) {
525 | return function() {
526 | return func.apply(context, arguments);
527 | };
528 | }
529 | },{}],5:[function(require,module,exports){
530 | /**
531 | * Module dependencies.
532 | */
533 |
534 | var index = require('indexof');
535 |
536 | /**
537 | * Whitespace regexp.
538 | */
539 |
540 | var whitespaceRe = /\s+/;
541 |
542 | /**
543 | * toString reference.
544 | */
545 |
546 | var toString = Object.prototype.toString;
547 |
548 | module.exports = classes;
549 | module.exports.add = add;
550 | module.exports.contains = has;
551 | module.exports.has = has;
552 | module.exports.toggle = toggle;
553 | module.exports.remove = remove;
554 | module.exports.removeMatching = removeMatching;
555 |
556 | function classes (el) {
557 | if (el.classList) {
558 | return el.classList;
559 | }
560 |
561 | var str = el.className.replace(/^\s+|\s+$/g, '');
562 | var arr = str.split(whitespaceRe);
563 | if ('' === arr[0]) arr.shift();
564 | return arr;
565 | }
566 |
567 | function add (el, name) {
568 | // classList
569 | if (el.classList) {
570 | el.classList.add(name);
571 | return;
572 | }
573 |
574 | // fallback
575 | var arr = classes(el);
576 | var i = index(arr, name);
577 | if (!~i) arr.push(name);
578 | el.className = arr.join(' ');
579 | }
580 |
581 | function has (el, name) {
582 | return el.classList
583 | ? el.classList.contains(name)
584 | : !! ~index(classes(el), name);
585 | }
586 |
587 | function remove (el, name) {
588 | if ('[object RegExp]' == toString.call(name)) {
589 | return removeMatching(el, name);
590 | }
591 |
592 | // classList
593 | if (el.classList) {
594 | el.classList.remove(name);
595 | return;
596 | }
597 |
598 | // fallback
599 | var arr = classes(el);
600 | var i = index(arr, name);
601 | if (~i) arr.splice(i, 1);
602 | el.className = arr.join(' ');
603 | }
604 |
605 | function removeMatching (el, re, ref) {
606 | var arr = Array.prototype.slice.call(classes(el));
607 | for (var i = 0; i < arr.length; i++) {
608 | if (re.test(arr[i])) {
609 | remove(el, arr[i]);
610 | }
611 | }
612 | }
613 |
614 | function toggle (el, name) {
615 | // classList
616 | if (el.classList) {
617 | return el.classList.toggle(name);
618 | }
619 |
620 | // fallback
621 | if (has(el, name)) {
622 | remove(el, name);
623 | } else {
624 | add(el, name);
625 | }
626 | }
627 |
628 | },{"indexof":8}],6:[function(require,module,exports){
629 | /*
630 | `dom-create-element`
631 |
632 | var create = require('dom-create-element');
633 |
634 | var el = create({
635 | selector: 'div',
636 | styles: 'preloader',
637 | html: 'Text'
638 | });
639 | */
640 |
641 | module.exports = create;
642 |
643 | function create(opt) {
644 |
645 | opt = opt || {};
646 |
647 | var el = document.createElement(opt.selector);
648 |
649 | if(opt.attr) for(var index in opt.attr)
650 | opt.attr.hasOwnProperty(index) && el.setAttribute(index, opt.attr[index]);
651 |
652 | "a" == opt.selector && opt.link && (
653 | el.href = opt.link,
654 | opt.target && el.setAttribute("target", opt.target)
655 | );
656 |
657 | "img" == opt.selector && opt.src && (
658 | el.src = opt.src,
659 | opt.lazyload && (
660 | el.style.opacity = 0,
661 | el.onload = function(){
662 | el.style.opacity = 1;
663 | }
664 | )
665 | );
666 |
667 | opt.id && (el.id = opt.id);
668 | opt.styles && (el.className = opt.styles);
669 |
670 | opt.html && (el.innerHTML = opt.html);
671 | opt.children && (el.appendChild(opt.children));
672 |
673 | return el;
674 | };
675 | },{}],7:[function(require,module,exports){
676 |
677 | var synth = require('synthetic-dom-events');
678 |
679 | var on = function(element, name, fn, capture) {
680 | return element.addEventListener(name, fn, capture || false);
681 | };
682 |
683 | var off = function(element, name, fn, capture) {
684 | return element.removeEventListener(name, fn, capture || false);
685 | };
686 |
687 | var once = function (element, name, fn, capture) {
688 | function tmp (ev) {
689 | off(element, name, tmp, capture);
690 | fn(ev);
691 | }
692 | on(element, name, tmp, capture);
693 | };
694 |
695 | var emit = function(element, name, opt) {
696 | var ev = synth(name, opt);
697 | element.dispatchEvent(ev);
698 | };
699 |
700 | if (!document.addEventListener) {
701 | on = function(element, name, fn) {
702 | return element.attachEvent('on' + name, fn);
703 | };
704 | }
705 |
706 | if (!document.removeEventListener) {
707 | off = function(element, name, fn) {
708 | return element.detachEvent('on' + name, fn);
709 | };
710 | }
711 |
712 | if (!document.dispatchEvent) {
713 | emit = function(element, name, opt) {
714 | var ev = synth(name, opt);
715 | return element.fireEvent('on' + ev.type, ev);
716 | };
717 | }
718 |
719 | module.exports = {
720 | on: on,
721 | off: off,
722 | once: once,
723 | emit: emit
724 | };
725 |
726 | },{"synthetic-dom-events":12}],8:[function(require,module,exports){
727 |
728 | var indexOf = [].indexOf;
729 |
730 | module.exports = function(arr, obj){
731 | if (indexOf) return arr.indexOf(obj);
732 | for (var i = 0; i < arr.length; ++i) {
733 | if (arr[i] === obj) return i;
734 | }
735 | return -1;
736 | };
737 | },{}],9:[function(require,module,exports){
738 | // Generated by CoffeeScript 1.9.2
739 | (function() {
740 | var root;
741 |
742 | root = typeof exports !== "undefined" && exports !== null ? exports : this;
743 |
744 | root.Lethargy = (function() {
745 | function Lethargy(stability, sensitivity, tolerance, delay) {
746 | this.stability = stability != null ? Math.abs(stability) : 8;
747 | this.sensitivity = sensitivity != null ? 1 + Math.abs(sensitivity) : 100;
748 | this.tolerance = tolerance != null ? 1 + Math.abs(tolerance) : 1.1;
749 | this.delay = delay != null ? delay : 150;
750 | this.lastUpDeltas = (function() {
751 | var i, ref, results;
752 | results = [];
753 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
754 | results.push(null);
755 | }
756 | return results;
757 | }).call(this);
758 | this.lastDownDeltas = (function() {
759 | var i, ref, results;
760 | results = [];
761 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
762 | results.push(null);
763 | }
764 | return results;
765 | }).call(this);
766 | this.deltasTimestamp = (function() {
767 | var i, ref, results;
768 | results = [];
769 | for (i = 1, ref = this.stability * 2; 1 <= ref ? i <= ref : i >= ref; 1 <= ref ? i++ : i--) {
770 | results.push(null);
771 | }
772 | return results;
773 | }).call(this);
774 | }
775 |
776 | Lethargy.prototype.check = function(e) {
777 | var lastDelta;
778 | e = e.originalEvent || e;
779 | if (e.wheelDelta != null) {
780 | lastDelta = e.wheelDelta;
781 | } else if (e.deltaY != null) {
782 | lastDelta = e.deltaY * -40;
783 | } else if ((e.detail != null) || e.detail === 0) {
784 | lastDelta = e.detail * -40;
785 | }
786 | this.deltasTimestamp.push(Date.now());
787 | this.deltasTimestamp.shift();
788 | if (lastDelta > 0) {
789 | this.lastUpDeltas.push(lastDelta);
790 | this.lastUpDeltas.shift();
791 | return this.isInertia(1);
792 | } else {
793 | this.lastDownDeltas.push(lastDelta);
794 | this.lastDownDeltas.shift();
795 | return this.isInertia(-1);
796 | }
797 | return false;
798 | };
799 |
800 | Lethargy.prototype.isInertia = function(direction) {
801 | var lastDeltas, lastDeltasNew, lastDeltasOld, newAverage, newSum, oldAverage, oldSum;
802 | lastDeltas = direction === -1 ? this.lastDownDeltas : this.lastUpDeltas;
803 | if (lastDeltas[0] === null) {
804 | return direction;
805 | }
806 | if (this.deltasTimestamp[(this.stability * 2) - 2] + this.delay > Date.now() && lastDeltas[0] === lastDeltas[(this.stability * 2) - 1]) {
807 | return false;
808 | }
809 | lastDeltasOld = lastDeltas.slice(0, this.stability);
810 | lastDeltasNew = lastDeltas.slice(this.stability, this.stability * 2);
811 | oldSum = lastDeltasOld.reduce(function(t, s) {
812 | return t + s;
813 | });
814 | newSum = lastDeltasNew.reduce(function(t, s) {
815 | return t + s;
816 | });
817 | oldAverage = oldSum / lastDeltasOld.length;
818 | newAverage = newSum / lastDeltasNew.length;
819 | if (Math.abs(oldAverage) < Math.abs(newAverage * this.tolerance) && (this.sensitivity < Math.abs(newAverage))) {
820 | return direction;
821 | } else {
822 | return false;
823 | }
824 | };
825 |
826 | Lethargy.prototype.showLastUpDeltas = function() {
827 | return this.lastUpDeltas;
828 | };
829 |
830 | Lethargy.prototype.showLastDownDeltas = function() {
831 | return this.lastDownDeltas;
832 | };
833 |
834 | return Lethargy;
835 |
836 | })();
837 |
838 | }).call(this);
839 |
840 | },{}],10:[function(require,module,exports){
841 | /*
842 | object-assign
843 | (c) Sindre Sorhus
844 | @license MIT
845 | */
846 |
847 | 'use strict';
848 | /* eslint-disable no-unused-vars */
849 | var getOwnPropertySymbols = Object.getOwnPropertySymbols;
850 | var hasOwnProperty = Object.prototype.hasOwnProperty;
851 | var propIsEnumerable = Object.prototype.propertyIsEnumerable;
852 |
853 | function toObject(val) {
854 | if (val === null || val === undefined) {
855 | throw new TypeError('Object.assign cannot be called with null or undefined');
856 | }
857 |
858 | return Object(val);
859 | }
860 |
861 | function shouldUseNative() {
862 | try {
863 | if (!Object.assign) {
864 | return false;
865 | }
866 |
867 | // Detect buggy property enumeration order in older V8 versions.
868 |
869 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118
870 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
871 | test1[5] = 'de';
872 | if (Object.getOwnPropertyNames(test1)[0] === '5') {
873 | return false;
874 | }
875 |
876 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
877 | var test2 = {};
878 | for (var i = 0; i < 10; i++) {
879 | test2['_' + String.fromCharCode(i)] = i;
880 | }
881 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
882 | return test2[n];
883 | });
884 | if (order2.join('') !== '0123456789') {
885 | return false;
886 | }
887 |
888 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
889 | var test3 = {};
890 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
891 | test3[letter] = letter;
892 | });
893 | if (Object.keys(Object.assign({}, test3)).join('') !==
894 | 'abcdefghijklmnopqrst') {
895 | return false;
896 | }
897 |
898 | return true;
899 | } catch (err) {
900 | // We don't expect any of the above to throw, but better to be safe.
901 | return false;
902 | }
903 | }
904 |
905 | module.exports = shouldUseNative() ? Object.assign : function (target, source) {
906 | var from;
907 | var to = toObject(target);
908 | var symbols;
909 |
910 | for (var s = 1; s < arguments.length; s++) {
911 | from = Object(arguments[s]);
912 |
913 | for (var key in from) {
914 | if (hasOwnProperty.call(from, key)) {
915 | to[key] = from[key];
916 | }
917 | }
918 |
919 | if (getOwnPropertySymbols) {
920 | symbols = getOwnPropertySymbols(from);
921 | for (var i = 0; i < symbols.length; i++) {
922 | if (propIsEnumerable.call(from, symbols[i])) {
923 | to[symbols[i]] = from[symbols[i]];
924 | }
925 | }
926 | }
927 | }
928 |
929 | return to;
930 | };
931 |
932 | },{}],11:[function(require,module,exports){
933 | // check document first so it doesn't error in node.js
934 | var style = typeof document != 'undefined'
935 | ? document.createElement('p').style
936 | : {}
937 |
938 | var prefixes = ['O', 'ms', 'Moz', 'Webkit']
939 | var upper = /([A-Z])/g
940 | var memo = {}
941 |
942 | /**
943 | * prefix `key`
944 | *
945 | * prefix('transform') // => WebkitTransform
946 | *
947 | * @param {String} key
948 | * @return {String}
949 | * @api public
950 | */
951 | function prefix(key){
952 | // Camel case
953 | key = key.replace(/-([a-z])/g, function(_, char){
954 | return char.toUpperCase()
955 | })
956 |
957 | // Without prefix
958 | if (style[key] !== undefined) return key
959 |
960 | // With prefix
961 | var Key = key.charAt(0).toUpperCase() + key.slice(1)
962 | var i = prefixes.length
963 | while (i--) {
964 | var name = prefixes[i] + Key
965 | if (style[name] !== undefined) return name
966 | }
967 |
968 | return key
969 | }
970 |
971 | /**
972 | * Memoized version of `prefix`
973 | *
974 | * @param {String} key
975 | * @return {String}
976 | * @api public
977 | */
978 | function prefixMemozied(key){
979 | return key in memo
980 | ? memo[key]
981 | : memo[key] = prefix(key)
982 | }
983 |
984 | /**
985 | * Create a dashed prefix
986 | *
987 | * @param {String} key
988 | * @return {String}
989 | * @api public
990 | */
991 | function prefixDashed(key){
992 | key = prefix(key)
993 | if (upper.test(key)) {
994 | key = '-' + key.replace(upper, '-$1')
995 | upper.lastIndex = 0
996 | }
997 | return key.toLowerCase()
998 | }
999 |
1000 | module.exports = prefixMemozied
1001 | module.exports.dash = prefixDashed
1002 |
1003 | },{}],12:[function(require,module,exports){
1004 |
1005 | // for compression
1006 | var win = window;
1007 | var doc = document || {};
1008 | var root = doc.documentElement || {};
1009 |
1010 | // detect if we need to use firefox KeyEvents vs KeyboardEvents
1011 | var use_key_event = true;
1012 | try {
1013 | doc.createEvent('KeyEvents');
1014 | }
1015 | catch (err) {
1016 | use_key_event = false;
1017 | }
1018 |
1019 | // Workaround for https://bugs.webkit.org/show_bug.cgi?id=16735
1020 | function check_kb(ev, opts) {
1021 | if (ev.ctrlKey != (opts.ctrlKey || false) ||
1022 | ev.altKey != (opts.altKey || false) ||
1023 | ev.shiftKey != (opts.shiftKey || false) ||
1024 | ev.metaKey != (opts.metaKey || false) ||
1025 | ev.keyCode != (opts.keyCode || 0) ||
1026 | ev.charCode != (opts.charCode || 0)) {
1027 |
1028 | ev = document.createEvent('Event');
1029 | ev.initEvent(opts.type, opts.bubbles, opts.cancelable);
1030 | ev.ctrlKey = opts.ctrlKey || false;
1031 | ev.altKey = opts.altKey || false;
1032 | ev.shiftKey = opts.shiftKey || false;
1033 | ev.metaKey = opts.metaKey || false;
1034 | ev.keyCode = opts.keyCode || 0;
1035 | ev.charCode = opts.charCode || 0;
1036 | }
1037 |
1038 | return ev;
1039 | }
1040 |
1041 | // modern browsers, do a proper dispatchEvent()
1042 | var modern = function(type, opts) {
1043 | opts = opts || {};
1044 |
1045 | // which init fn do we use
1046 | var family = typeOf(type);
1047 | var init_fam = family;
1048 | if (family === 'KeyboardEvent' && use_key_event) {
1049 | family = 'KeyEvents';
1050 | init_fam = 'KeyEvent';
1051 | }
1052 |
1053 | var ev = doc.createEvent(family);
1054 | var init_fn = 'init' + init_fam;
1055 | var init = typeof ev[init_fn] === 'function' ? init_fn : 'initEvent';
1056 |
1057 | var sig = initSignatures[init];
1058 | var args = [];
1059 | var used = {};
1060 |
1061 | opts.type = type;
1062 | for (var i = 0; i < sig.length; ++i) {
1063 | var key = sig[i];
1064 | var val = opts[key];
1065 | // if no user specified value, then use event default
1066 | if (val === undefined) {
1067 | val = ev[key];
1068 | }
1069 | used[key] = true;
1070 | args.push(val);
1071 | }
1072 | ev[init].apply(ev, args);
1073 |
1074 | // webkit key event issue workaround
1075 | if (family === 'KeyboardEvent') {
1076 | ev = check_kb(ev, opts);
1077 | }
1078 |
1079 | // attach remaining unused options to the object
1080 | for (var key in opts) {
1081 | if (!used[key]) {
1082 | ev[key] = opts[key];
1083 | }
1084 | }
1085 |
1086 | return ev;
1087 | };
1088 |
1089 | var legacy = function (type, opts) {
1090 | opts = opts || {};
1091 | var ev = doc.createEventObject();
1092 |
1093 | ev.type = type;
1094 | for (var key in opts) {
1095 | if (opts[key] !== undefined) {
1096 | ev[key] = opts[key];
1097 | }
1098 | }
1099 |
1100 | return ev;
1101 | };
1102 |
1103 | // expose either the modern version of event generation or legacy
1104 | // depending on what we support
1105 | // avoids if statements in the code later
1106 | module.exports = doc.createEvent ? modern : legacy;
1107 |
1108 | var initSignatures = require('./init.json');
1109 | var types = require('./types.json');
1110 | var typeOf = (function () {
1111 | var typs = {};
1112 | for (var key in types) {
1113 | var ts = types[key];
1114 | for (var i = 0; i < ts.length; i++) {
1115 | typs[ts[i]] = key;
1116 | }
1117 | }
1118 |
1119 | return function (name) {
1120 | return typs[name] || 'Event';
1121 | };
1122 | })();
1123 |
1124 | },{"./init.json":13,"./types.json":14}],13:[function(require,module,exports){
1125 | module.exports={
1126 | "initEvent" : [
1127 | "type",
1128 | "bubbles",
1129 | "cancelable"
1130 | ],
1131 | "initUIEvent" : [
1132 | "type",
1133 | "bubbles",
1134 | "cancelable",
1135 | "view",
1136 | "detail"
1137 | ],
1138 | "initMouseEvent" : [
1139 | "type",
1140 | "bubbles",
1141 | "cancelable",
1142 | "view",
1143 | "detail",
1144 | "screenX",
1145 | "screenY",
1146 | "clientX",
1147 | "clientY",
1148 | "ctrlKey",
1149 | "altKey",
1150 | "shiftKey",
1151 | "metaKey",
1152 | "button",
1153 | "relatedTarget"
1154 | ],
1155 | "initMutationEvent" : [
1156 | "type",
1157 | "bubbles",
1158 | "cancelable",
1159 | "relatedNode",
1160 | "prevValue",
1161 | "newValue",
1162 | "attrName",
1163 | "attrChange"
1164 | ],
1165 | "initKeyboardEvent" : [
1166 | "type",
1167 | "bubbles",
1168 | "cancelable",
1169 | "view",
1170 | "ctrlKey",
1171 | "altKey",
1172 | "shiftKey",
1173 | "metaKey",
1174 | "keyCode",
1175 | "charCode"
1176 | ],
1177 | "initKeyEvent" : [
1178 | "type",
1179 | "bubbles",
1180 | "cancelable",
1181 | "view",
1182 | "ctrlKey",
1183 | "altKey",
1184 | "shiftKey",
1185 | "metaKey",
1186 | "keyCode",
1187 | "charCode"
1188 | ]
1189 | }
1190 |
1191 | },{}],14:[function(require,module,exports){
1192 | module.exports={
1193 | "MouseEvent" : [
1194 | "click",
1195 | "mousedown",
1196 | "mouseup",
1197 | "mouseover",
1198 | "mousemove",
1199 | "mouseout"
1200 | ],
1201 | "KeyboardEvent" : [
1202 | "keydown",
1203 | "keyup",
1204 | "keypress"
1205 | ],
1206 | "MutationEvent" : [
1207 | "DOMSubtreeModified",
1208 | "DOMNodeInserted",
1209 | "DOMNodeRemoved",
1210 | "DOMNodeRemovedFromDocument",
1211 | "DOMNodeInsertedIntoDocument",
1212 | "DOMAttrModified",
1213 | "DOMCharacterDataModified"
1214 | ],
1215 | "HTMLEvents" : [
1216 | "load",
1217 | "unload",
1218 | "abort",
1219 | "error",
1220 | "select",
1221 | "change",
1222 | "submit",
1223 | "reset",
1224 | "focus",
1225 | "blur",
1226 | "resize",
1227 | "scroll"
1228 | ],
1229 | "UIEvent" : [
1230 | "DOMFocusIn",
1231 | "DOMFocusOut",
1232 | "DOMActivate"
1233 | ]
1234 | }
1235 |
1236 | },{}],15:[function(require,module,exports){
1237 | function E () {
1238 | // Keep this empty so it's easier to inherit from
1239 | // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
1240 | }
1241 |
1242 | E.prototype = {
1243 | on: function (name, callback, ctx) {
1244 | var e = this.e || (this.e = {});
1245 |
1246 | (e[name] || (e[name] = [])).push({
1247 | fn: callback,
1248 | ctx: ctx
1249 | });
1250 |
1251 | return this;
1252 | },
1253 |
1254 | once: function (name, callback, ctx) {
1255 | var self = this;
1256 | function listener () {
1257 | self.off(name, listener);
1258 | callback.apply(ctx, arguments);
1259 | };
1260 |
1261 | listener._ = callback
1262 | return this.on(name, listener, ctx);
1263 | },
1264 |
1265 | emit: function (name) {
1266 | var data = [].slice.call(arguments, 1);
1267 | var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
1268 | var i = 0;
1269 | var len = evtArr.length;
1270 |
1271 | for (i; i < len; i++) {
1272 | evtArr[i].fn.apply(evtArr[i].ctx, data);
1273 | }
1274 |
1275 | return this;
1276 | },
1277 |
1278 | off: function (name, callback) {
1279 | var e = this.e || (this.e = {});
1280 | var evts = e[name];
1281 | var liveEvents = [];
1282 |
1283 | if (evts && callback) {
1284 | for (var i = 0, len = evts.length; i < len; i++) {
1285 | if (evts[i].fn !== callback && evts[i].fn._ !== callback)
1286 | liveEvents.push(evts[i]);
1287 | }
1288 | }
1289 |
1290 | // Remove event from queue to prevent memory leak
1291 | // Suggested by https://github.com/lazd
1292 | // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
1293 |
1294 | (liveEvents.length)
1295 | ? e[name] = liveEvents
1296 | : delete e[name];
1297 |
1298 | return this;
1299 | }
1300 | };
1301 |
1302 | module.exports = E;
1303 |
1304 | },{}],16:[function(require,module,exports){
1305 | 'use strict';
1306 |
1307 | module.exports = function(source) {
1308 | return JSON.parse(JSON.stringify(source));
1309 | };
1310 | },{}],17:[function(require,module,exports){
1311 | 'use strict';
1312 |
1313 | var objectAssign = require('object-assign');
1314 | var Emitter = require('tiny-emitter');
1315 | var Lethargy = require('lethargy').Lethargy;
1316 | var support = require('./support');
1317 | var clone = require('./clone');
1318 | var bindAll = require('bindall-standalone');
1319 | var EVT_ID = 'virtualscroll';
1320 |
1321 | module.exports = VirtualScroll;
1322 |
1323 | var keyCodes = {
1324 | LEFT: 37,
1325 | UP: 38,
1326 | RIGHT: 39,
1327 | DOWN: 40,
1328 | SPACE: 32
1329 | };
1330 |
1331 | function VirtualScroll(options) {
1332 | bindAll(this, '_onWheel', '_onMouseWheel', '_onTouchStart', '_onTouchMove', '_onKeyDown');
1333 |
1334 | this.el = window;
1335 | if (options && options.el) {
1336 | this.el = options.el;
1337 | delete options.el;
1338 | }
1339 | this.options = objectAssign({
1340 | mouseMultiplier: 1,
1341 | touchMultiplier: 2,
1342 | firefoxMultiplier: 15,
1343 | keyStep: 120,
1344 | preventTouch: false,
1345 | unpreventTouchClass: 'vs-touchmove-allowed',
1346 | limitInertia: false
1347 | }, options);
1348 |
1349 | if (this.options.limitInertia) this._lethargy = new Lethargy();
1350 |
1351 | this._emitter = new Emitter();
1352 | this._event = {
1353 | y: 0,
1354 | x: 0,
1355 | deltaX: 0,
1356 | deltaY: 0
1357 | };
1358 | this.touchStartX = null;
1359 | this.touchStartY = null;
1360 | this.bodyTouchAction = null;
1361 |
1362 | if (this.options.passive !== undefined) {
1363 | this.listenerOptions = {passive: this.options.passive};
1364 | }
1365 | }
1366 |
1367 | VirtualScroll.prototype._notify = function(e) {
1368 | var evt = this._event;
1369 | evt.x += evt.deltaX;
1370 | evt.y += evt.deltaY;
1371 |
1372 | this._emitter.emit(EVT_ID, {
1373 | x: evt.x,
1374 | y: evt.y,
1375 | deltaX: evt.deltaX,
1376 | deltaY: evt.deltaY,
1377 | originalEvent: e
1378 | });
1379 | };
1380 |
1381 | VirtualScroll.prototype._onWheel = function(e) {
1382 | var options = this.options;
1383 | if (this._lethargy && this._lethargy.check(e) === false) return;
1384 | var evt = this._event;
1385 |
1386 | // In Chrome and in Firefox (at least the new one)
1387 | evt.deltaX = e.wheelDeltaX || e.deltaX * -1;
1388 | evt.deltaY = e.wheelDeltaY || e.deltaY * -1;
1389 |
1390 | // for our purpose deltamode = 1 means user is on a wheel mouse, not touch pad
1391 | // real meaning: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent#Delta_modes
1392 | if(support.isFirefox && e.deltaMode == 1) {
1393 | evt.deltaX *= options.firefoxMultiplier;
1394 | evt.deltaY *= options.firefoxMultiplier;
1395 | }
1396 |
1397 | evt.deltaX *= options.mouseMultiplier;
1398 | evt.deltaY *= options.mouseMultiplier;
1399 |
1400 | this._notify(e);
1401 | };
1402 |
1403 | VirtualScroll.prototype._onMouseWheel = function(e) {
1404 | if (this.options.limitInertia && this._lethargy.check(e) === false) return;
1405 |
1406 | var evt = this._event;
1407 |
1408 | // In Safari, IE and in Chrome if 'wheel' isn't defined
1409 | evt.deltaX = (e.wheelDeltaX) ? e.wheelDeltaX : 0;
1410 | evt.deltaY = (e.wheelDeltaY) ? e.wheelDeltaY : e.wheelDelta;
1411 |
1412 | this._notify(e);
1413 | };
1414 |
1415 | VirtualScroll.prototype._onTouchStart = function(e) {
1416 | var t = (e.targetTouches) ? e.targetTouches[0] : e;
1417 | this.touchStartX = t.pageX;
1418 | this.touchStartY = t.pageY;
1419 | };
1420 |
1421 | VirtualScroll.prototype._onTouchMove = function(e) {
1422 | var options = this.options;
1423 | if(options.preventTouch
1424 | && !e.target.classList.contains(options.unpreventTouchClass)) {
1425 | e.preventDefault();
1426 | }
1427 |
1428 | var evt = this._event;
1429 |
1430 | var t = (e.targetTouches) ? e.targetTouches[0] : e;
1431 |
1432 | evt.deltaX = (t.pageX - this.touchStartX) * options.touchMultiplier;
1433 | evt.deltaY = (t.pageY - this.touchStartY) * options.touchMultiplier;
1434 |
1435 | this.touchStartX = t.pageX;
1436 | this.touchStartY = t.pageY;
1437 |
1438 | this._notify(e);
1439 | };
1440 |
1441 | VirtualScroll.prototype._onKeyDown = function(e) {
1442 | var evt = this._event;
1443 | evt.deltaX = evt.deltaY = 0;
1444 | var windowHeight = window.innerHeight - 40
1445 |
1446 | switch(e.keyCode) {
1447 | case keyCodes.LEFT:
1448 | case keyCodes.UP:
1449 | evt.deltaY = this.options.keyStep;
1450 | break;
1451 |
1452 | case keyCodes.RIGHT:
1453 | case keyCodes.DOWN:
1454 | evt.deltaY = - this.options.keyStep;
1455 | break;
1456 | case keyCodes.SPACE && e.shiftKey:
1457 | evt.deltaY = windowHeight;
1458 | break;
1459 | case keyCodes.SPACE:
1460 | evt.deltaY = - windowHeight;
1461 | break;
1462 | default:
1463 | return;
1464 | }
1465 |
1466 | this._notify(e);
1467 | };
1468 |
1469 | VirtualScroll.prototype._bind = function() {
1470 | if(support.hasWheelEvent) this.el.addEventListener('wheel', this._onWheel, this.listenerOptions);
1471 | if(support.hasMouseWheelEvent) this.el.addEventListener('mousewheel', this._onMouseWheel, this.listenerOptions);
1472 |
1473 | if(support.hasTouch) {
1474 | this.el.addEventListener('touchstart', this._onTouchStart, this.listenerOptions);
1475 | this.el.addEventListener('touchmove', this._onTouchMove, this.listenerOptions);
1476 | }
1477 |
1478 | if(support.hasPointer && support.hasTouchWin) {
1479 | this.bodyTouchAction = document.body.style.msTouchAction;
1480 | document.body.style.msTouchAction = 'none';
1481 | this.el.addEventListener('MSPointerDown', this._onTouchStart, true);
1482 | this.el.addEventListener('MSPointerMove', this._onTouchMove, true);
1483 | }
1484 |
1485 | if(support.hasKeyDown) document.addEventListener('keydown', this._onKeyDown);
1486 | };
1487 |
1488 | VirtualScroll.prototype._unbind = function() {
1489 | if(support.hasWheelEvent) this.el.removeEventListener('wheel', this._onWheel);
1490 | if(support.hasMouseWheelEvent) this.el.removeEventListener('mousewheel', this._onMouseWheel);
1491 |
1492 | if(support.hasTouch) {
1493 | this.el.removeEventListener('touchstart', this._onTouchStart);
1494 | this.el.removeEventListener('touchmove', this._onTouchMove);
1495 | }
1496 |
1497 | if(support.hasPointer && support.hasTouchWin) {
1498 | document.body.style.msTouchAction = this.bodyTouchAction;
1499 | this.el.removeEventListener('MSPointerDown', this._onTouchStart, true);
1500 | this.el.removeEventListener('MSPointerMove', this._onTouchMove, true);
1501 | }
1502 |
1503 | if(support.hasKeyDown) document.removeEventListener('keydown', this._onKeyDown);
1504 | };
1505 |
1506 | VirtualScroll.prototype.on = function(cb, ctx) {
1507 | this._emitter.on(EVT_ID, cb, ctx);
1508 |
1509 | var events = this._emitter.e;
1510 | if (events && events[EVT_ID] && events[EVT_ID].length === 1) this._bind();
1511 | };
1512 |
1513 | VirtualScroll.prototype.off = function(cb, ctx) {
1514 | this._emitter.off(EVT_ID, cb, ctx);
1515 |
1516 | var events = this._emitter.e;
1517 | if (!events[EVT_ID] || events[EVT_ID].length <= 0) this._unbind();
1518 | };
1519 |
1520 | VirtualScroll.prototype.reset = function() {
1521 | var evt = this._event;
1522 | evt.x = 0;
1523 | evt.y = 0;
1524 | };
1525 |
1526 | VirtualScroll.prototype.destroy = function() {
1527 | this._emitter.off();
1528 | this._unbind();
1529 | };
1530 |
1531 | },{"./clone":16,"./support":18,"bindall-standalone":4,"lethargy":9,"object-assign":10,"tiny-emitter":15}],18:[function(require,module,exports){
1532 | 'use strict';
1533 |
1534 | module.exports = (function getSupport() {
1535 | return {
1536 | hasWheelEvent: 'onwheel' in document,
1537 | hasMouseWheelEvent: 'onmousewheel' in document,
1538 | hasTouch: 'ontouchstart' in document,
1539 | hasTouchWin: navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 1,
1540 | hasPointer: !!window.navigator.msPointerEnabled,
1541 | hasKeyDown: 'onkeydown' in document,
1542 | isFirefox: navigator.userAgent.indexOf('Firefox') > -1
1543 | };
1544 | })();
1545 |
1546 | },{}]},{},[2]);
1547 |
--------------------------------------------------------------------------------