wow.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*
  2. * WOW wow.js - v1.3.0 - 2016-10-04
  3. * https://wowjs.uk
  4. * Copyright (c) 2016 Thomas Grainger; Licensed MIT
  5. */
  6. (function (global, factory) {
  7. if (typeof define === "function" && define.amd) {
  8. define(['module', 'exports'], factory);
  9. } else if (typeof exports !== "undefined") {
  10. factory(module, exports);
  11. } else {
  12. var mod = {
  13. exports: {}
  14. };
  15. factory(mod, mod.exports);
  16. global.WOW = mod.exports;
  17. }
  18. })(this, function (module, exports) {
  19. 'use strict';
  20. Object.defineProperty(exports, "__esModule", {
  21. value: true
  22. });
  23. var _class, _temp;
  24. function _classCallCheck(instance, Constructor) {
  25. if (!(instance instanceof Constructor)) {
  26. throw new TypeError("Cannot call a class as a function");
  27. }
  28. }
  29. var _createClass = function () {
  30. function defineProperties(target, props) {
  31. for (var i = 0; i < props.length; i++) {
  32. var descriptor = props[i];
  33. descriptor.enumerable = descriptor.enumerable || false;
  34. descriptor.configurable = true;
  35. if ("value" in descriptor) descriptor.writable = true;
  36. Object.defineProperty(target, descriptor.key, descriptor);
  37. }
  38. }
  39. return function (Constructor, protoProps, staticProps) {
  40. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  41. if (staticProps) defineProperties(Constructor, staticProps);
  42. return Constructor;
  43. };
  44. }();
  45. function isIn(needle, haystack) {
  46. return haystack.indexOf(needle) >= 0;
  47. }
  48. function extend(custom, defaults) {
  49. for (var key in defaults) {
  50. if (custom[key] == null) {
  51. var value = defaults[key];
  52. custom[key] = value;
  53. }
  54. }
  55. return custom;
  56. }
  57. function isMobile(agent) {
  58. return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(agent)
  59. );
  60. }
  61. function createEvent(event) {
  62. var bubble = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
  63. var cancel = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
  64. var detail = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
  65. var customEvent = void 0;
  66. if (document.createEvent != null) {
  67. // W3C DOM
  68. customEvent = document.createEvent('CustomEvent');
  69. customEvent.initCustomEvent(event, bubble, cancel, detail);
  70. } else if (document.createEventObject != null) {
  71. // IE DOM < 9
  72. customEvent = document.createEventObject();
  73. customEvent.eventType = event;
  74. } else {
  75. customEvent.eventName = event;
  76. }
  77. return customEvent;
  78. }
  79. function emitEvent(elem, event) {
  80. if (elem.dispatchEvent != null) {
  81. // W3C DOM
  82. elem.dispatchEvent(event);
  83. } else if (event in (elem != null)) {
  84. elem[event]();
  85. } else if ('on' + event in (elem != null)) {
  86. elem['on' + event]();
  87. }
  88. }
  89. function addEvent(elem, event, fn) {
  90. if (elem.addEventListener != null) {
  91. // W3C DOM
  92. elem.addEventListener(event, fn, false);
  93. } else if (elem.attachEvent != null) {
  94. // IE DOM
  95. elem.attachEvent('on' + event, fn);
  96. } else {
  97. // fallback
  98. elem[event] = fn;
  99. }
  100. }
  101. function removeEvent(elem, event, fn) {
  102. if (elem.removeEventListener != null) {
  103. // W3C DOM
  104. elem.removeEventListener(event, fn, false);
  105. } else if (elem.detachEvent != null) {
  106. // IE DOM
  107. elem.detachEvent('on' + event, fn);
  108. } else {
  109. // fallback
  110. delete elem[event];
  111. }
  112. }
  113. function getInnerHeight() {
  114. if ('innerHeight' in window) {
  115. return window.innerHeight;
  116. }
  117. return document.documentElement.clientHeight;
  118. }
  119. // Minimalistic WeakMap shim, just in case.
  120. var WeakMap = window.WeakMap || window.MozWeakMap || function () {
  121. function WeakMap() {
  122. _classCallCheck(this, WeakMap);
  123. this.keys = [];
  124. this.values = [];
  125. }
  126. _createClass(WeakMap, [{
  127. key: 'get',
  128. value: function get(key) {
  129. for (var i = 0; i < this.keys.length; i++) {
  130. var item = this.keys[i];
  131. if (item === key) {
  132. return this.values[i];
  133. }
  134. }
  135. return undefined;
  136. }
  137. }, {
  138. key: 'set',
  139. value: function set(key, value) {
  140. for (var i = 0; i < this.keys.length; i++) {
  141. var item = this.keys[i];
  142. if (item === key) {
  143. this.values[i] = value;
  144. return this;
  145. }
  146. }
  147. this.keys.push(key);
  148. this.values.push(value);
  149. return this;
  150. }
  151. }]);
  152. return WeakMap;
  153. }();
  154. // Dummy MutationObserver, to avoid raising exceptions.
  155. var MutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver || (_temp = _class = function () {
  156. function MutationObserver() {
  157. _classCallCheck(this, MutationObserver);
  158. if (typeof console !== 'undefined' && console !== null) {
  159. console.warn('MutationObserver is not supported by your browser.');
  160. console.warn('WOW.js cannot detect dom mutations, please call .sync() after loading new content.');
  161. }
  162. }
  163. _createClass(MutationObserver, [{
  164. key: 'observe',
  165. value: function observe() {}
  166. }]);
  167. return MutationObserver;
  168. }(), _class.notSupported = true, _temp);
  169. // getComputedStyle shim, from http://stackoverflow.com/a/21797294
  170. var getComputedStyle = window.getComputedStyle || function getComputedStyle(el) {
  171. var getComputedStyleRX = /(\-([a-z]){1})/g;
  172. return {
  173. getPropertyValue: function getPropertyValue(prop) {
  174. if (prop === 'float') {
  175. prop = 'styleFloat';
  176. }
  177. if (getComputedStyleRX.test(prop)) {
  178. prop.replace(getComputedStyleRX, function (_, _char) {
  179. return _char.toUpperCase();
  180. });
  181. }
  182. var currentStyle = el.currentStyle;
  183. return (currentStyle != null ? currentStyle[prop] : void 0) || null;
  184. }
  185. };
  186. };
  187. var WOW = function () {
  188. function WOW() {
  189. var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
  190. _classCallCheck(this, WOW);
  191. this.defaults = {
  192. boxClass: 'wow',
  193. animateClass: 'animated',
  194. offset: 0,
  195. mobile: true,
  196. live: true,
  197. callback: null,
  198. scrollContainer: null,
  199. resetAnimation: true
  200. };
  201. this.animate = function animateFactory() {
  202. if ('requestAnimationFrame' in window) {
  203. return function (callback) {
  204. return window.requestAnimationFrame(callback);
  205. };
  206. }
  207. return function (callback) {
  208. return callback();
  209. };
  210. }();
  211. this.vendors = ['moz', 'webkit'];
  212. this.start = this.start.bind(this);
  213. this.resetAnimation = this.resetAnimation.bind(this);
  214. this.scrollHandler = this.scrollHandler.bind(this);
  215. this.scrollCallback = this.scrollCallback.bind(this);
  216. this.scrolled = true;
  217. this.config = extend(options, this.defaults);
  218. if (options.scrollContainer != null) {
  219. this.config.scrollContainer = document.querySelector(options.scrollContainer);
  220. }
  221. // Map of elements to animation names:
  222. this.animationNameCache = new WeakMap();
  223. this.wowEvent = createEvent(this.config.boxClass);
  224. }
  225. _createClass(WOW, [{
  226. key: 'init',
  227. value: function init() {
  228. this.element = window.document.documentElement;
  229. if (isIn(document.readyState, ['interactive', 'complete'])) {
  230. this.start();
  231. } else {
  232. addEvent(document, 'DOMContentLoaded', this.start);
  233. }
  234. this.finished = [];
  235. }
  236. }, {
  237. key: 'start',
  238. value: function start() {
  239. var _this = this;
  240. this.stopped = false;
  241. this.boxes = [].slice.call(this.element.querySelectorAll('.' + this.config.boxClass));
  242. this.all = this.boxes.slice(0);
  243. if (this.boxes.length) {
  244. if (this.disabled()) {
  245. this.resetStyle();
  246. } else {
  247. for (var i = 0; i < this.boxes.length; i++) {
  248. var box = this.boxes[i];
  249. this.applyStyle(box, true);
  250. }
  251. }
  252. }
  253. if (!this.disabled()) {
  254. addEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
  255. addEvent(window, 'resize', this.scrollHandler);
  256. this.interval = setInterval(this.scrollCallback, 50);
  257. }
  258. if (this.config.live) {
  259. var mut = new MutationObserver(function (records) {
  260. for (var j = 0; j < records.length; j++) {
  261. var record = records[j];
  262. for (var k = 0; k < record.addedNodes.length; k++) {
  263. var node = record.addedNodes[k];
  264. _this.doSync(node);
  265. }
  266. }
  267. return undefined;
  268. });
  269. mut.observe(document.body, {
  270. childList: true,
  271. subtree: true
  272. });
  273. }
  274. }
  275. }, {
  276. key: 'stop',
  277. value: function stop() {
  278. this.stopped = true;
  279. removeEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
  280. removeEvent(window, 'resize', this.scrollHandler);
  281. if (this.interval != null) {
  282. clearInterval(this.interval);
  283. }
  284. }
  285. }, {
  286. key: 'sync',
  287. value: function sync() {
  288. if (MutationObserver.notSupported) {
  289. this.doSync(this.element);
  290. }
  291. }
  292. }, {
  293. key: 'doSync',
  294. value: function doSync(element) {
  295. if (typeof element === 'undefined' || element === null) {
  296. element = this.element;
  297. }
  298. if (element.nodeType !== 1) {
  299. return;
  300. }
  301. element = element.parentNode || element;
  302. var iterable = element.querySelectorAll('.' + this.config.boxClass);
  303. for (var i = 0; i < iterable.length; i++) {
  304. var box = iterable[i];
  305. if (!isIn(box, this.all)) {
  306. this.boxes.push(box);
  307. this.all.push(box);
  308. if (this.stopped || this.disabled()) {
  309. this.resetStyle();
  310. } else {
  311. this.applyStyle(box, true);
  312. }
  313. this.scrolled = true;
  314. }
  315. }
  316. }
  317. }, {
  318. key: 'show',
  319. value: function show(box) {
  320. this.applyStyle(box);
  321. box.className = box.className + ' ' + this.config.animateClass;
  322. if (this.config.callback != null) {
  323. this.config.callback(box);
  324. }
  325. emitEvent(box, this.wowEvent);
  326. if (this.config.resetAnimation) {
  327. addEvent(box, 'animationend', this.resetAnimation);
  328. addEvent(box, 'oanimationend', this.resetAnimation);
  329. addEvent(box, 'webkitAnimationEnd', this.resetAnimation);
  330. addEvent(box, 'MSAnimationEnd', this.resetAnimation);
  331. }
  332. return box;
  333. }
  334. }, {
  335. key: 'applyStyle',
  336. value: function applyStyle(box, hidden) {
  337. var _this2 = this;
  338. var duration = box.getAttribute('data-wow-duration');
  339. var delay = box.getAttribute('data-wow-delay');
  340. var iteration = box.getAttribute('data-wow-iteration');
  341. return this.animate(function () {
  342. return _this2.customStyle(box, hidden, duration, delay, iteration);
  343. });
  344. }
  345. }, {
  346. key: 'resetStyle',
  347. value: function resetStyle() {
  348. for (var i = 0; i < this.boxes.length; i++) {
  349. var box = this.boxes[i];
  350. box.style.visibility = 'visible';
  351. }
  352. return undefined;
  353. }
  354. }, {
  355. key: 'resetAnimation',
  356. value: function resetAnimation(event) {
  357. if (event.type.toLowerCase().indexOf('animationend') >= 0) {
  358. var target = event.target || event.srcElement;
  359. target.className = target.className.replace(this.config.animateClass, '').trim();
  360. }
  361. }
  362. }, {
  363. key: 'customStyle',
  364. value: function customStyle(box, hidden, duration, delay, iteration) {
  365. if (hidden) {
  366. this.cacheAnimationName(box);
  367. }
  368. box.style.visibility = hidden ? 'hidden' : 'visible';
  369. if (duration) {
  370. this.vendorSet(box.style, { animationDuration: duration });
  371. }
  372. if (delay) {
  373. this.vendorSet(box.style, { animationDelay: delay });
  374. }
  375. if (iteration) {
  376. this.vendorSet(box.style, { animationIterationCount: iteration });
  377. }
  378. this.vendorSet(box.style, { animationName: hidden ? 'none' : this.cachedAnimationName(box) });
  379. return box;
  380. }
  381. }, {
  382. key: 'vendorSet',
  383. value: function vendorSet(elem, properties) {
  384. for (var name in properties) {
  385. if (properties.hasOwnProperty(name)) {
  386. var value = properties[name];
  387. elem['' + name] = value;
  388. for (var i = 0; i < this.vendors.length; i++) {
  389. var vendor = this.vendors[i];
  390. elem['' + vendor + name.charAt(0).toUpperCase() + name.substr(1)] = value;
  391. }
  392. }
  393. }
  394. }
  395. }, {
  396. key: 'vendorCSS',
  397. value: function vendorCSS(elem, property) {
  398. var style = getComputedStyle(elem);
  399. var result = style.getPropertyCSSValue(property);
  400. for (var i = 0; i < this.vendors.length; i++) {
  401. var vendor = this.vendors[i];
  402. result = result || style.getPropertyCSSValue('-' + vendor + '-' + property);
  403. }
  404. return result;
  405. }
  406. }, {
  407. key: 'animationName',
  408. value: function animationName(box) {
  409. var aName = void 0;
  410. try {
  411. aName = this.vendorCSS(box, 'animation-name').cssText;
  412. } catch (error) {
  413. // Opera, fall back to plain property value
  414. aName = getComputedStyle(box).getPropertyValue('animation-name');
  415. }
  416. if (aName === 'none') {
  417. return ''; // SVG/Firefox, unable to get animation name?
  418. }
  419. return aName;
  420. }
  421. }, {
  422. key: 'cacheAnimationName',
  423. value: function cacheAnimationName(box) {
  424. // https://bugzilla.mozilla.org/show_bug.cgi?id=921834
  425. // box.dataset is not supported for SVG elements in Firefox
  426. return this.animationNameCache.set(box, this.animationName(box));
  427. }
  428. }, {
  429. key: 'cachedAnimationName',
  430. value: function cachedAnimationName(box) {
  431. return this.animationNameCache.get(box);
  432. }
  433. }, {
  434. key: 'scrollHandler',
  435. value: function scrollHandler() {
  436. this.scrolled = true;
  437. }
  438. }, {
  439. key: 'scrollCallback',
  440. value: function scrollCallback() {
  441. if (this.scrolled) {
  442. this.scrolled = false;
  443. var results = [];
  444. for (var i = 0; i < this.boxes.length; i++) {
  445. var box = this.boxes[i];
  446. if (box) {
  447. if (this.isVisible(box)) {
  448. this.show(box);
  449. continue;
  450. }
  451. results.push(box);
  452. }
  453. }
  454. this.boxes = results;
  455. if (!this.boxes.length && !this.config.live) {
  456. this.stop();
  457. }
  458. }
  459. }
  460. }, {
  461. key: 'offsetTop',
  462. value: function offsetTop(element) {
  463. // SVG elements don't have an offsetTop in Firefox.
  464. // This will use their nearest parent that has an offsetTop.
  465. // Also, using ('offsetTop' of element) causes an exception in Firefox.
  466. while (element.offsetTop === undefined) {
  467. element = element.parentNode;
  468. }
  469. var top = element.offsetTop;
  470. while (element.offsetParent) {
  471. element = element.offsetParent;
  472. top += element.offsetTop;
  473. }
  474. return top;
  475. }
  476. }, {
  477. key: 'isVisible',
  478. value: function isVisible(box) {
  479. var offset = box.getAttribute('data-wow-offset') || this.config.offset;
  480. var viewTop = this.config.scrollContainer && this.config.scrollContainer.scrollTop || window.pageYOffset;
  481. var viewBottom = viewTop + Math.min(this.element.clientHeight, getInnerHeight()) - offset;
  482. var top = this.offsetTop(box);
  483. var bottom = top + box.clientHeight;
  484. return top <= viewBottom && bottom >= viewTop;
  485. }
  486. }, {
  487. key: 'disabled',
  488. value: function disabled() {
  489. return !this.config.mobile && isMobile(navigator.userAgent);
  490. }
  491. }]);
  492. return WOW;
  493. }();
  494. exports.default = WOW;
  495. module.exports = exports['default'];
  496. });