543 lines
17 KiB
JavaScript
543 lines
17 KiB
JavaScript
/*
|
|
* WOW wow.js - v1.3.0 - 2016-10-04
|
|
* https://wowjs.uk
|
|
* Copyright (c) 2016 Thomas Grainger; Licensed MIT
|
|
*/
|
|
|
|
(function (global, factory) {
|
|
if (typeof define === "function" && define.amd) {
|
|
define(['module', 'exports'], factory);
|
|
} else if (typeof exports !== "undefined") {
|
|
factory(module, exports);
|
|
} else {
|
|
var mod = {
|
|
exports: {}
|
|
};
|
|
factory(mod, mod.exports);
|
|
global.WOW = mod.exports;
|
|
}
|
|
})(this, function (module, exports) {
|
|
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
var _class, _temp;
|
|
|
|
function _classCallCheck(instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
}
|
|
|
|
var _createClass = function () {
|
|
function defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
function isIn(needle, haystack) {
|
|
return haystack.indexOf(needle) >= 0;
|
|
}
|
|
|
|
function extend(custom, defaults) {
|
|
for (var key in defaults) {
|
|
if (custom[key] == null) {
|
|
var value = defaults[key];
|
|
custom[key] = value;
|
|
}
|
|
}
|
|
return custom;
|
|
}
|
|
|
|
function isMobile(agent) {
|
|
return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(agent)
|
|
);
|
|
}
|
|
|
|
function createEvent(event) {
|
|
var bubble = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
|
|
var cancel = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
|
|
var detail = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
|
|
|
|
var customEvent = void 0;
|
|
if (document.createEvent != null) {
|
|
// W3C DOM
|
|
customEvent = document.createEvent('CustomEvent');
|
|
customEvent.initCustomEvent(event, bubble, cancel, detail);
|
|
} else if (document.createEventObject != null) {
|
|
// IE DOM < 9
|
|
customEvent = document.createEventObject();
|
|
customEvent.eventType = event;
|
|
} else {
|
|
customEvent.eventName = event;
|
|
}
|
|
|
|
return customEvent;
|
|
}
|
|
|
|
function emitEvent(elem, event) {
|
|
if (elem.dispatchEvent != null) {
|
|
// W3C DOM
|
|
elem.dispatchEvent(event);
|
|
} else if (event in (elem != null)) {
|
|
elem[event]();
|
|
} else if ('on' + event in (elem != null)) {
|
|
elem['on' + event]();
|
|
}
|
|
}
|
|
|
|
function addEvent(elem, event, fn) {
|
|
if (elem.addEventListener != null) {
|
|
// W3C DOM
|
|
elem.addEventListener(event, fn, false);
|
|
} else if (elem.attachEvent != null) {
|
|
// IE DOM
|
|
elem.attachEvent('on' + event, fn);
|
|
} else {
|
|
// fallback
|
|
elem[event] = fn;
|
|
}
|
|
}
|
|
|
|
function removeEvent(elem, event, fn) {
|
|
if (elem.removeEventListener != null) {
|
|
// W3C DOM
|
|
elem.removeEventListener(event, fn, false);
|
|
} else if (elem.detachEvent != null) {
|
|
// IE DOM
|
|
elem.detachEvent('on' + event, fn);
|
|
} else {
|
|
// fallback
|
|
delete elem[event];
|
|
}
|
|
}
|
|
|
|
function getInnerHeight() {
|
|
if ('innerHeight' in window) {
|
|
return window.innerHeight;
|
|
}
|
|
|
|
return document.documentElement.clientHeight;
|
|
}
|
|
|
|
// Minimalistic WeakMap shim, just in case.
|
|
var WeakMap = window.WeakMap || window.MozWeakMap || function () {
|
|
function WeakMap() {
|
|
_classCallCheck(this, WeakMap);
|
|
|
|
this.keys = [];
|
|
this.values = [];
|
|
}
|
|
|
|
_createClass(WeakMap, [{
|
|
key: 'get',
|
|
value: function get(key) {
|
|
for (var i = 0; i < this.keys.length; i++) {
|
|
var item = this.keys[i];
|
|
if (item === key) {
|
|
return this.values[i];
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
}, {
|
|
key: 'set',
|
|
value: function set(key, value) {
|
|
for (var i = 0; i < this.keys.length; i++) {
|
|
var item = this.keys[i];
|
|
if (item === key) {
|
|
this.values[i] = value;
|
|
return this;
|
|
}
|
|
}
|
|
this.keys.push(key);
|
|
this.values.push(value);
|
|
return this;
|
|
}
|
|
}]);
|
|
|
|
return WeakMap;
|
|
}();
|
|
|
|
// Dummy MutationObserver, to avoid raising exceptions.
|
|
var MutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver || (_temp = _class = function () {
|
|
function MutationObserver() {
|
|
_classCallCheck(this, MutationObserver);
|
|
|
|
if (typeof console !== 'undefined' && console !== null) {
|
|
console.warn('MutationObserver is not supported by your browser.');
|
|
console.warn('WOW.js cannot detect dom mutations, please call .sync() after loading new content.');
|
|
}
|
|
}
|
|
|
|
_createClass(MutationObserver, [{
|
|
key: 'observe',
|
|
value: function observe() {}
|
|
}]);
|
|
|
|
return MutationObserver;
|
|
}(), _class.notSupported = true, _temp);
|
|
|
|
// getComputedStyle shim, from http://stackoverflow.com/a/21797294
|
|
var getComputedStyle = window.getComputedStyle || function getComputedStyle(el) {
|
|
var getComputedStyleRX = /(\-([a-z]){1})/g;
|
|
return {
|
|
getPropertyValue: function getPropertyValue(prop) {
|
|
if (prop === 'float') {
|
|
prop = 'styleFloat';
|
|
}
|
|
if (getComputedStyleRX.test(prop)) {
|
|
prop.replace(getComputedStyleRX, function (_, _char) {
|
|
return _char.toUpperCase();
|
|
});
|
|
}
|
|
var currentStyle = el.currentStyle;
|
|
|
|
return (currentStyle != null ? currentStyle[prop] : void 0) || null;
|
|
}
|
|
};
|
|
};
|
|
|
|
var WOW = function () {
|
|
function WOW() {
|
|
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
|
|
|
_classCallCheck(this, WOW);
|
|
|
|
this.defaults = {
|
|
boxClass: 'wow',
|
|
animateClass: 'animated',
|
|
offset: 0,
|
|
mobile: true,
|
|
live: true,
|
|
callback: null,
|
|
scrollContainer: null,
|
|
resetAnimation: true
|
|
};
|
|
|
|
this.animate = function animateFactory() {
|
|
if ('requestAnimationFrame' in window) {
|
|
return function (callback) {
|
|
return window.requestAnimationFrame(callback);
|
|
};
|
|
}
|
|
return function (callback) {
|
|
return callback();
|
|
};
|
|
}();
|
|
|
|
this.vendors = ['moz', 'webkit'];
|
|
|
|
this.start = this.start.bind(this);
|
|
this.resetAnimation = this.resetAnimation.bind(this);
|
|
this.scrollHandler = this.scrollHandler.bind(this);
|
|
this.scrollCallback = this.scrollCallback.bind(this);
|
|
this.scrolled = true;
|
|
this.config = extend(options, this.defaults);
|
|
if (options.scrollContainer != null) {
|
|
this.config.scrollContainer = document.querySelector(options.scrollContainer);
|
|
}
|
|
// Map of elements to animation names:
|
|
this.animationNameCache = new WeakMap();
|
|
this.wowEvent = createEvent(this.config.boxClass);
|
|
}
|
|
|
|
_createClass(WOW, [{
|
|
key: 'init',
|
|
value: function init() {
|
|
this.element = window.document.documentElement;
|
|
if (isIn(document.readyState, ['interactive', 'complete'])) {
|
|
this.start();
|
|
} else {
|
|
addEvent(document, 'DOMContentLoaded', this.start);
|
|
}
|
|
this.finished = [];
|
|
}
|
|
}, {
|
|
key: 'start',
|
|
value: function start() {
|
|
var _this = this;
|
|
|
|
this.stopped = false;
|
|
this.boxes = [].slice.call(this.element.querySelectorAll('.' + this.config.boxClass));
|
|
this.all = this.boxes.slice(0);
|
|
if (this.boxes.length) {
|
|
if (this.disabled()) {
|
|
this.resetStyle();
|
|
} else {
|
|
for (var i = 0; i < this.boxes.length; i++) {
|
|
var box = this.boxes[i];
|
|
this.applyStyle(box, true);
|
|
}
|
|
}
|
|
}
|
|
if (!this.disabled()) {
|
|
addEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
|
|
addEvent(window, 'resize', this.scrollHandler);
|
|
this.interval = setInterval(this.scrollCallback, 50);
|
|
}
|
|
if (this.config.live) {
|
|
var mut = new MutationObserver(function (records) {
|
|
for (var j = 0; j < records.length; j++) {
|
|
var record = records[j];
|
|
for (var k = 0; k < record.addedNodes.length; k++) {
|
|
var node = record.addedNodes[k];
|
|
_this.doSync(node);
|
|
}
|
|
}
|
|
return undefined;
|
|
});
|
|
mut.observe(document.body, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'stop',
|
|
value: function stop() {
|
|
this.stopped = true;
|
|
removeEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
|
|
removeEvent(window, 'resize', this.scrollHandler);
|
|
if (this.interval != null) {
|
|
clearInterval(this.interval);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'sync',
|
|
value: function sync() {
|
|
if (MutationObserver.notSupported) {
|
|
this.doSync(this.element);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'doSync',
|
|
value: function doSync(element) {
|
|
if (typeof element === 'undefined' || element === null) {
|
|
element = this.element;
|
|
}
|
|
if (element.nodeType !== 1) {
|
|
return;
|
|
}
|
|
element = element.parentNode || element;
|
|
var iterable = element.querySelectorAll('.' + this.config.boxClass);
|
|
for (var i = 0; i < iterable.length; i++) {
|
|
var box = iterable[i];
|
|
if (!isIn(box, this.all)) {
|
|
this.boxes.push(box);
|
|
this.all.push(box);
|
|
if (this.stopped || this.disabled()) {
|
|
this.resetStyle();
|
|
} else {
|
|
this.applyStyle(box, true);
|
|
}
|
|
this.scrolled = true;
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'show',
|
|
value: function show(box) {
|
|
this.applyStyle(box);
|
|
box.className = box.className + ' ' + this.config.animateClass;
|
|
if (this.config.callback != null) {
|
|
this.config.callback(box);
|
|
}
|
|
emitEvent(box, this.wowEvent);
|
|
|
|
if (this.config.resetAnimation) {
|
|
addEvent(box, 'animationend', this.resetAnimation);
|
|
addEvent(box, 'oanimationend', this.resetAnimation);
|
|
addEvent(box, 'webkitAnimationEnd', this.resetAnimation);
|
|
addEvent(box, 'MSAnimationEnd', this.resetAnimation);
|
|
}
|
|
|
|
return box;
|
|
}
|
|
}, {
|
|
key: 'applyStyle',
|
|
value: function applyStyle(box, hidden) {
|
|
var _this2 = this;
|
|
|
|
var duration = box.getAttribute('data-wow-duration');
|
|
var delay = box.getAttribute('data-wow-delay');
|
|
var iteration = box.getAttribute('data-wow-iteration');
|
|
|
|
return this.animate(function () {
|
|
return _this2.customStyle(box, hidden, duration, delay, iteration);
|
|
});
|
|
}
|
|
}, {
|
|
key: 'resetStyle',
|
|
value: function resetStyle() {
|
|
for (var i = 0; i < this.boxes.length; i++) {
|
|
var box = this.boxes[i];
|
|
box.style.visibility = 'visible';
|
|
}
|
|
return undefined;
|
|
}
|
|
}, {
|
|
key: 'resetAnimation',
|
|
value: function resetAnimation(event) {
|
|
if (event.type.toLowerCase().indexOf('animationend') >= 0) {
|
|
var target = event.target || event.srcElement;
|
|
target.className = target.className.replace(this.config.animateClass, '').trim();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'customStyle',
|
|
value: function customStyle(box, hidden, duration, delay, iteration) {
|
|
if (hidden) {
|
|
this.cacheAnimationName(box);
|
|
}
|
|
box.style.visibility = hidden ? 'hidden' : 'visible';
|
|
|
|
if (duration) {
|
|
this.vendorSet(box.style, { animationDuration: duration });
|
|
}
|
|
if (delay) {
|
|
this.vendorSet(box.style, { animationDelay: delay });
|
|
}
|
|
if (iteration) {
|
|
this.vendorSet(box.style, { animationIterationCount: iteration });
|
|
}
|
|
this.vendorSet(box.style, { animationName: hidden ? 'none' : this.cachedAnimationName(box) });
|
|
|
|
return box;
|
|
}
|
|
}, {
|
|
key: 'vendorSet',
|
|
value: function vendorSet(elem, properties) {
|
|
for (var name in properties) {
|
|
if (properties.hasOwnProperty(name)) {
|
|
var value = properties[name];
|
|
elem['' + name] = value;
|
|
for (var i = 0; i < this.vendors.length; i++) {
|
|
var vendor = this.vendors[i];
|
|
elem['' + vendor + name.charAt(0).toUpperCase() + name.substr(1)] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'vendorCSS',
|
|
value: function vendorCSS(elem, property) {
|
|
var style = getComputedStyle(elem);
|
|
var result = style.getPropertyCSSValue(property);
|
|
for (var i = 0; i < this.vendors.length; i++) {
|
|
var vendor = this.vendors[i];
|
|
result = result || style.getPropertyCSSValue('-' + vendor + '-' + property);
|
|
}
|
|
return result;
|
|
}
|
|
}, {
|
|
key: 'animationName',
|
|
value: function animationName(box) {
|
|
var aName = void 0;
|
|
try {
|
|
aName = this.vendorCSS(box, 'animation-name').cssText;
|
|
} catch (error) {
|
|
// Opera, fall back to plain property value
|
|
aName = getComputedStyle(box).getPropertyValue('animation-name');
|
|
}
|
|
|
|
if (aName === 'none') {
|
|
return ''; // SVG/Firefox, unable to get animation name?
|
|
}
|
|
|
|
return aName;
|
|
}
|
|
}, {
|
|
key: 'cacheAnimationName',
|
|
value: function cacheAnimationName(box) {
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=921834
|
|
// box.dataset is not supported for SVG elements in Firefox
|
|
return this.animationNameCache.set(box, this.animationName(box));
|
|
}
|
|
}, {
|
|
key: 'cachedAnimationName',
|
|
value: function cachedAnimationName(box) {
|
|
return this.animationNameCache.get(box);
|
|
}
|
|
}, {
|
|
key: 'scrollHandler',
|
|
value: function scrollHandler() {
|
|
this.scrolled = true;
|
|
}
|
|
}, {
|
|
key: 'scrollCallback',
|
|
value: function scrollCallback() {
|
|
if (this.scrolled) {
|
|
this.scrolled = false;
|
|
var results = [];
|
|
for (var i = 0; i < this.boxes.length; i++) {
|
|
var box = this.boxes[i];
|
|
if (box) {
|
|
if (this.isVisible(box)) {
|
|
this.show(box);
|
|
continue;
|
|
}
|
|
results.push(box);
|
|
}
|
|
}
|
|
this.boxes = results;
|
|
if (!this.boxes.length && !this.config.live) {
|
|
this.stop();
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'offsetTop',
|
|
value: function offsetTop(element) {
|
|
// SVG elements don't have an offsetTop in Firefox.
|
|
// This will use their nearest parent that has an offsetTop.
|
|
// Also, using ('offsetTop' of element) causes an exception in Firefox.
|
|
while (element.offsetTop === undefined) {
|
|
element = element.parentNode;
|
|
}
|
|
var top = element.offsetTop;
|
|
while (element.offsetParent) {
|
|
element = element.offsetParent;
|
|
top += element.offsetTop;
|
|
}
|
|
return top;
|
|
}
|
|
}, {
|
|
key: 'isVisible',
|
|
value: function isVisible(box) {
|
|
var offset = box.getAttribute('data-wow-offset') || this.config.offset;
|
|
var viewTop = this.config.scrollContainer && this.config.scrollContainer.scrollTop || window.pageYOffset;
|
|
var viewBottom = viewTop + Math.min(this.element.clientHeight, getInnerHeight()) - offset;
|
|
var top = this.offsetTop(box);
|
|
var bottom = top + box.clientHeight;
|
|
|
|
return top <= viewBottom && bottom >= viewTop;
|
|
}
|
|
}, {
|
|
key: 'disabled',
|
|
value: function disabled() {
|
|
return !this.config.mobile && isMobile(navigator.userAgent);
|
|
}
|
|
}]);
|
|
|
|
return WOW;
|
|
}();
|
|
|
|
exports.default = WOW;
|
|
module.exports = exports['default'];
|
|
});
|