ratchet.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. /*!
  2. * =====================================================
  3. * Ratchet v2.0.2 (http://goratchet.com)
  4. * Copyright 2014 Connor Sears
  5. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  6. *
  7. * v2.0.2 designed by @connors.
  8. * =====================================================
  9. */
  10. /* ========================================================================
  11. * Ratchet: modals.js v2.0.2
  12. * http://goratchet.com/components#modals
  13. * ========================================================================
  14. * Copyright 2014 Connor Sears
  15. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  16. * ======================================================================== */
  17. !(function () {
  18. 'use strict';
  19. var findModals = function (target) {
  20. var i;
  21. var modals = document.querySelectorAll('a');
  22. for (; target && target !== document; target = target.parentNode) {
  23. for (i = modals.length; i--;) {
  24. if (modals[i] === target) {
  25. return target;
  26. }
  27. }
  28. }
  29. };
  30. var getModal = function (event) {
  31. var modalToggle = findModals(event.target);
  32. if (modalToggle && modalToggle.hash) {
  33. return document.querySelector(modalToggle.hash);
  34. }
  35. };
  36. window.addEventListener('touchend', function (event) {
  37. var modal = getModal(event);
  38. if (modal) {
  39. if (modal && modal.classList.contains('modal')) {
  40. modal.classList.toggle('active');
  41. }
  42. event.preventDefault(); // prevents rewriting url (apps can still use hash values in url)
  43. }
  44. });
  45. }());
  46. /* ========================================================================
  47. * Ratchet: popovers.js v2.0.2
  48. * http://goratchet.com/components#popovers
  49. * ========================================================================
  50. * Copyright 2014 Connor Sears
  51. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  52. * ======================================================================== */
  53. !(function () {
  54. 'use strict';
  55. var popover;
  56. var findPopovers = function (target) {
  57. var i;
  58. var popovers = document.querySelectorAll('a');
  59. for (; target && target !== document; target = target.parentNode) {
  60. for (i = popovers.length; i--;) {
  61. if (popovers[i] === target) {
  62. return target;
  63. }
  64. }
  65. }
  66. };
  67. var onPopoverHidden = function () {
  68. popover.style.display = 'none';
  69. popover.removeEventListener('webkitTransitionEnd', onPopoverHidden);
  70. };
  71. var backdrop = (function () {
  72. var element = document.createElement('div');
  73. element.classList.add('backdrop');
  74. element.addEventListener('touchend', function () {
  75. popover.addEventListener('webkitTransitionEnd', onPopoverHidden);
  76. popover.classList.remove('visible');
  77. popover.parentNode.removeChild(backdrop);
  78. });
  79. return element;
  80. }());
  81. var getPopover = function (e) {
  82. var anchor = findPopovers(e.target);
  83. if (!anchor || !anchor.hash || (anchor.hash.indexOf('/') > 0)) {
  84. return;
  85. }
  86. try {
  87. popover = document.querySelector(anchor.hash);
  88. }
  89. catch (error) {
  90. popover = null;
  91. }
  92. if (popover === null) {
  93. return;
  94. }
  95. if (!popover || !popover.classList.contains('popover')) {
  96. return;
  97. }
  98. return popover;
  99. };
  100. var showHidePopover = function (e) {
  101. var popover = getPopover(e);
  102. if (!popover) {
  103. return;
  104. }
  105. popover.style.display = 'block';
  106. popover.offsetHeight;
  107. popover.classList.add('visible');
  108. popover.parentNode.appendChild(backdrop);
  109. };
  110. window.addEventListener('touchend', showHidePopover);
  111. }());
  112. /* ========================================================================
  113. * Ratchet: push.js v2.0.2
  114. * http://goratchet.com/components#push
  115. * ========================================================================
  116. * inspired by @defunkt's jquery.pjax.js
  117. * Copyright 2014 Connor Sears
  118. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  119. * ======================================================================== */
  120. /* global _gaq: true */
  121. !(function () {
  122. 'use strict';
  123. var noop = function () {};
  124. // Pushstate caching
  125. // ==================
  126. var isScrolling;
  127. var maxCacheLength = 20;
  128. var cacheMapping = sessionStorage;
  129. var domCache = {};
  130. var transitionMap = {
  131. slideIn : 'slide-out',
  132. slideOut : 'slide-in',
  133. fade : 'fade'
  134. };
  135. var bars = {
  136. bartab : '.bar-tab',
  137. barnav : '.bar-nav',
  138. barfooter : '.bar-footer',
  139. barheadersecondary : '.bar-header-secondary'
  140. };
  141. var cacheReplace = function (data, updates) {
  142. PUSH.id = data.id;
  143. if (updates) {
  144. data = getCached(data.id);
  145. }
  146. cacheMapping[data.id] = JSON.stringify(data);
  147. window.history.replaceState(data.id, data.title, data.url);
  148. domCache[data.id] = document.body.cloneNode(true);
  149. };
  150. var cachePush = function () {
  151. var id = PUSH.id;
  152. var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]');
  153. var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]');
  154. cacheBackStack.push(id);
  155. while (cacheForwardStack.length) {
  156. delete cacheMapping[cacheForwardStack.shift()];
  157. }
  158. while (cacheBackStack.length > maxCacheLength) {
  159. delete cacheMapping[cacheBackStack.shift()];
  160. }
  161. window.history.pushState(null, '', cacheMapping[PUSH.id].url);
  162. cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack);
  163. cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack);
  164. };
  165. var cachePop = function (id, direction) {
  166. var forward = direction === 'forward';
  167. var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]');
  168. var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]');
  169. var pushStack = forward ? cacheBackStack : cacheForwardStack;
  170. var popStack = forward ? cacheForwardStack : cacheBackStack;
  171. if (PUSH.id) {
  172. pushStack.push(PUSH.id);
  173. }
  174. popStack.pop();
  175. cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack);
  176. cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack);
  177. };
  178. var getCached = function (id) {
  179. return JSON.parse(cacheMapping[id] || null) || {};
  180. };
  181. var getTarget = function (e) {
  182. var target = findTarget(e.target);
  183. if (!target ||
  184. e.which > 1 ||
  185. e.metaKey ||
  186. e.ctrlKey ||
  187. isScrolling ||
  188. location.protocol !== target.protocol ||
  189. location.host !== target.host ||
  190. !target.hash && /#/.test(target.href) ||
  191. target.hash && target.href.replace(target.hash, '') === location.href.replace(location.hash, '') ||
  192. target.getAttribute('data-ignore') === 'push') { return; }
  193. return target;
  194. };
  195. // Main event handlers (touchend, popstate)
  196. // ==========================================
  197. var touchend = function (e) {
  198. var target = getTarget(e);
  199. if (!target) {
  200. return;
  201. }
  202. e.preventDefault();
  203. PUSH({
  204. url : target.href,
  205. hash : target.hash,
  206. timeout : target.getAttribute('data-timeout'),
  207. transition : target.getAttribute('data-transition')
  208. });
  209. };
  210. var popstate = function (e) {
  211. var key;
  212. var barElement;
  213. var activeObj;
  214. var activeDom;
  215. var direction;
  216. var transition;
  217. var transitionFrom;
  218. var transitionFromObj;
  219. var id = e.state;
  220. if (!id || !cacheMapping[id]) {
  221. return;
  222. }
  223. direction = PUSH.id < id ? 'forward' : 'back';
  224. cachePop(id, direction);
  225. activeObj = getCached(id);
  226. activeDom = domCache[id];
  227. if (activeObj.title) {
  228. document.title = activeObj.title;
  229. }
  230. if (direction === 'back') {
  231. transitionFrom = JSON.parse(direction === 'back' ? cacheMapping.cacheForwardStack : cacheMapping.cacheBackStack);
  232. transitionFromObj = getCached(transitionFrom[transitionFrom.length - 1]);
  233. } else {
  234. transitionFromObj = activeObj;
  235. }
  236. if (direction === 'back' && !transitionFromObj.id) {
  237. return (PUSH.id = id);
  238. }
  239. transition = direction === 'back' ? transitionMap[transitionFromObj.transition] : transitionFromObj.transition;
  240. if (!activeDom) {
  241. return PUSH({
  242. id : activeObj.id,
  243. url : activeObj.url,
  244. title : activeObj.title,
  245. timeout : activeObj.timeout,
  246. transition : transition,
  247. ignorePush : true
  248. });
  249. }
  250. if (transitionFromObj.transition) {
  251. activeObj = extendWithDom(activeObj, '.content', activeDom.cloneNode(true));
  252. for (key in bars) {
  253. if (bars.hasOwnProperty(key)) {
  254. barElement = document.querySelector(bars[key]);
  255. if (activeObj[key]) {
  256. swapContent(activeObj[key], barElement);
  257. } else if (barElement) {
  258. barElement.parentNode.removeChild(barElement);
  259. }
  260. }
  261. }
  262. }
  263. swapContent(
  264. (activeObj.contents || activeDom).cloneNode(true),
  265. document.querySelector('.content'),
  266. transition
  267. );
  268. PUSH.id = id;
  269. document.body.offsetHeight; // force reflow to prevent scroll
  270. };
  271. // Core PUSH functionality
  272. // =======================
  273. var PUSH = function (options) {
  274. var key;
  275. var xhr = PUSH.xhr;
  276. options.container = options.container || options.transition ? document.querySelector('.content') : document.body;
  277. for (key in bars) {
  278. if (bars.hasOwnProperty(key)) {
  279. options[key] = options[key] || document.querySelector(bars[key]);
  280. }
  281. }
  282. if (xhr && xhr.readyState < 4) {
  283. xhr.onreadystatechange = noop;
  284. xhr.abort();
  285. }
  286. xhr = new XMLHttpRequest();
  287. xhr.open('GET', options.url, true);
  288. xhr.setRequestHeader('X-PUSH', 'true');
  289. xhr.onreadystatechange = function () {
  290. if (options._timeout) {
  291. clearTimeout(options._timeout);
  292. }
  293. if (xhr.readyState === 4) {
  294. xhr.status === 200 ? success(xhr, options) : failure(options.url);
  295. }
  296. };
  297. if (!PUSH.id) {
  298. cacheReplace({
  299. id : +new Date(),
  300. url : window.location.href,
  301. title : document.title,
  302. timeout : options.timeout,
  303. transition : null
  304. });
  305. }
  306. if (options.timeout) {
  307. options._timeout = setTimeout(function () { xhr.abort('timeout'); }, options.timeout);
  308. }
  309. xhr.send();
  310. if (xhr.readyState && !options.ignorePush) {
  311. cachePush();
  312. }
  313. };
  314. // Main XHR handlers
  315. // =================
  316. var success = function (xhr, options) {
  317. var key;
  318. var barElement;
  319. var data = parseXHR(xhr, options);
  320. if (!data.contents) {
  321. return locationReplace(options.url);
  322. }
  323. if (data.title) {
  324. document.title = data.title;
  325. }
  326. if (options.transition) {
  327. for (key in bars) {
  328. if (bars.hasOwnProperty(key)) {
  329. barElement = document.querySelector(bars[key]);
  330. if (data[key]) {
  331. swapContent(data[key], barElement);
  332. } else if (barElement) {
  333. barElement.parentNode.removeChild(barElement);
  334. }
  335. }
  336. }
  337. }
  338. swapContent(data.contents, options.container, options.transition, function () {
  339. cacheReplace({
  340. id : options.id || +new Date(),
  341. url : data.url,
  342. title : data.title,
  343. timeout : options.timeout,
  344. transition : options.transition
  345. }, options.id);
  346. triggerStateChange();
  347. });
  348. if (!options.ignorePush && window._gaq) {
  349. _gaq.push(['_trackPageview']); // google analytics
  350. }
  351. if (!options.hash) {
  352. return;
  353. }
  354. };
  355. var failure = function (url) {
  356. throw new Error('Could not get: ' + url);
  357. };
  358. // PUSH helpers
  359. // ============
  360. var swapContent = function (swap, container, transition, complete) {
  361. var enter;
  362. var containerDirection;
  363. var swapDirection;
  364. if (!transition) {
  365. if (container) {
  366. container.innerHTML = swap.innerHTML;
  367. } else if (swap.classList.contains('content')) {
  368. document.body.appendChild(swap);
  369. } else {
  370. document.body.insertBefore(swap, document.querySelector('.content'));
  371. }
  372. } else {
  373. enter = /in$/.test(transition);
  374. if (transition === 'fade') {
  375. container.classList.add('in');
  376. container.classList.add('fade');
  377. swap.classList.add('fade');
  378. }
  379. if (/slide/.test(transition)) {
  380. swap.classList.add('sliding-in', enter ? 'right' : 'left');
  381. swap.classList.add('sliding');
  382. container.classList.add('sliding');
  383. }
  384. container.parentNode.insertBefore(swap, container);
  385. }
  386. if (!transition) {
  387. complete && complete();
  388. }
  389. if (transition === 'fade') {
  390. container.offsetWidth; // force reflow
  391. container.classList.remove('in');
  392. var fadeContainerEnd = function () {
  393. container.removeEventListener('webkitTransitionEnd', fadeContainerEnd);
  394. swap.classList.add('in');
  395. swap.addEventListener('webkitTransitionEnd', fadeSwapEnd);
  396. };
  397. var fadeSwapEnd = function () {
  398. swap.removeEventListener('webkitTransitionEnd', fadeSwapEnd);
  399. container.parentNode.removeChild(container);
  400. swap.classList.remove('fade');
  401. swap.classList.remove('in');
  402. complete && complete();
  403. };
  404. container.addEventListener('webkitTransitionEnd', fadeContainerEnd);
  405. }
  406. if (/slide/.test(transition)) {
  407. var slideEnd = function () {
  408. swap.removeEventListener('webkitTransitionEnd', slideEnd);
  409. swap.classList.remove('sliding', 'sliding-in');
  410. swap.classList.remove(swapDirection);
  411. container.parentNode.removeChild(container);
  412. complete && complete();
  413. };
  414. container.offsetWidth; // force reflow
  415. swapDirection = enter ? 'right' : 'left';
  416. containerDirection = enter ? 'left' : 'right';
  417. container.classList.add(containerDirection);
  418. swap.classList.remove(swapDirection);
  419. swap.addEventListener('webkitTransitionEnd', slideEnd);
  420. }
  421. };
  422. var triggerStateChange = function () {
  423. var e = new CustomEvent('push', {
  424. detail: { state: getCached(PUSH.id) },
  425. bubbles: true,
  426. cancelable: true
  427. });
  428. window.dispatchEvent(e);
  429. };
  430. var findTarget = function (target) {
  431. var i;
  432. var toggles = document.querySelectorAll('a');
  433. for (; target && target !== document; target = target.parentNode) {
  434. for (i = toggles.length; i--;) {
  435. if (toggles[i] === target) {
  436. return target;
  437. }
  438. }
  439. }
  440. };
  441. var locationReplace = function (url) {
  442. window.history.replaceState(null, '', '#');
  443. window.location.replace(url);
  444. };
  445. var extendWithDom = function (obj, fragment, dom) {
  446. var i;
  447. var result = {};
  448. for (i in obj) {
  449. if (obj.hasOwnProperty(i)) {
  450. result[i] = obj[i];
  451. }
  452. }
  453. Object.keys(bars).forEach(function (key) {
  454. var el = dom.querySelector(bars[key]);
  455. if (el) {
  456. el.parentNode.removeChild(el);
  457. }
  458. result[key] = el;
  459. });
  460. result.contents = dom.querySelector(fragment);
  461. return result;
  462. };
  463. var parseXHR = function (xhr, options) {
  464. var head;
  465. var body;
  466. var data = {};
  467. var responseText = xhr.responseText;
  468. data.url = options.url;
  469. if (!responseText) {
  470. return data;
  471. }
  472. if (/<html/i.test(responseText)) {
  473. head = document.createElement('div');
  474. body = document.createElement('div');
  475. head.innerHTML = responseText.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0];
  476. body.innerHTML = responseText.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0];
  477. } else {
  478. head = body = document.createElement('div');
  479. head.innerHTML = responseText;
  480. }
  481. data.title = head.querySelector('title');
  482. var text = 'innerText' in data.title ? 'innerText' : 'textContent';
  483. data.title = data.title && data.title[text].trim();
  484. if (options.transition) {
  485. data = extendWithDom(data, '.content', body);
  486. } else {
  487. data.contents = body;
  488. }
  489. return data;
  490. };
  491. // Attach PUSH event handlers
  492. // ==========================
  493. window.addEventListener('touchstart', function () { isScrolling = false; });
  494. window.addEventListener('touchmove', function () { isScrolling = true; });
  495. window.addEventListener('touchend', touchend);
  496. window.addEventListener('click', function (e) { if (getTarget(e)) {e.preventDefault();} });
  497. window.addEventListener('popstate', popstate);
  498. window.PUSH = PUSH;
  499. }());
  500. /* ========================================================================
  501. * Ratchet: segmented-controllers.js v2.0.2
  502. * http://goratchet.com/components#segmentedControls
  503. * ========================================================================
  504. * Copyright 2014 Connor Sears
  505. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  506. * ======================================================================== */
  507. !(function () {
  508. 'use strict';
  509. var getTarget = function (target) {
  510. var i;
  511. var segmentedControls = document.querySelectorAll('.segmented-control .control-item');
  512. for (; target && target !== document; target = target.parentNode) {
  513. for (i = segmentedControls.length; i--;) {
  514. if (segmentedControls[i] === target) {
  515. return target;
  516. }
  517. }
  518. }
  519. };
  520. window.addEventListener('touchend', function (e) {
  521. var activeTab;
  522. var activeBodies;
  523. var targetBody;
  524. var targetTab = getTarget(e.target);
  525. var className = 'active';
  526. var classSelector = '.' + className;
  527. if (!targetTab) {
  528. return;
  529. }
  530. activeTab = targetTab.parentNode.querySelector(classSelector);
  531. if (activeTab) {
  532. activeTab.classList.remove(className);
  533. }
  534. targetTab.classList.add(className);
  535. if (!targetTab.hash) {
  536. return;
  537. }
  538. targetBody = document.querySelector(targetTab.hash);
  539. if (!targetBody) {
  540. return;
  541. }
  542. activeBodies = targetBody.parentNode.querySelectorAll(classSelector);
  543. for (var i = 0; i < activeBodies.length; i++) {
  544. activeBodies[i].classList.remove(className);
  545. }
  546. targetBody.classList.add(className);
  547. });
  548. window.addEventListener('click', function (e) { if (getTarget(e.target)) {e.preventDefault();} });
  549. }());
  550. /* ========================================================================
  551. * Ratchet: sliders.js v2.0.2
  552. * http://goratchet.com/components#sliders
  553. * ========================================================================
  554. Adapted from Brad Birdsall's swipe
  555. * Copyright 2014 Connor Sears
  556. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  557. * ======================================================================== */
  558. !(function () {
  559. 'use strict';
  560. var pageX;
  561. var pageY;
  562. var slider;
  563. var deltaX;
  564. var deltaY;
  565. var offsetX;
  566. var lastSlide;
  567. var startTime;
  568. var resistance;
  569. var sliderWidth;
  570. var slideNumber;
  571. var isScrolling;
  572. var scrollableArea;
  573. var getSlider = function (target) {
  574. var i;
  575. var sliders = document.querySelectorAll('.slider > .slide-group');
  576. for (; target && target !== document; target = target.parentNode) {
  577. for (i = sliders.length; i--;) {
  578. if (sliders[i] === target) {
  579. return target;
  580. }
  581. }
  582. }
  583. };
  584. var getScroll = function () {
  585. if ('webkitTransform' in slider.style) {
  586. var translate3d = slider.style.webkitTransform.match(/translate3d\(([^,]*)/);
  587. var ret = translate3d ? translate3d[1] : 0;
  588. return parseInt(ret, 10);
  589. }
  590. };
  591. var setSlideNumber = function (offset) {
  592. var round = offset ? (deltaX < 0 ? 'ceil' : 'floor') : 'round';
  593. slideNumber = Math[round](getScroll() / (scrollableArea / slider.children.length));
  594. slideNumber += offset;
  595. slideNumber = Math.min(slideNumber, 0);
  596. slideNumber = Math.max(-(slider.children.length - 1), slideNumber);
  597. };
  598. var onTouchStart = function (e) {
  599. slider = getSlider(e.target);
  600. if (!slider) {
  601. return;
  602. }
  603. var firstItem = slider.querySelector('.slide');
  604. scrollableArea = firstItem.offsetWidth * slider.children.length;
  605. isScrolling = undefined;
  606. sliderWidth = slider.offsetWidth;
  607. resistance = 1;
  608. lastSlide = -(slider.children.length - 1);
  609. startTime = +new Date();
  610. pageX = e.touches[0].pageX;
  611. pageY = e.touches[0].pageY;
  612. deltaX = 0;
  613. deltaY = 0;
  614. setSlideNumber(0);
  615. slider.style['-webkit-transition-duration'] = 0;
  616. };
  617. var onTouchMove = function (e) {
  618. if (e.touches.length > 1 || !slider) {
  619. return; // Exit if a pinch || no slider
  620. }
  621. deltaX = e.touches[0].pageX - pageX;
  622. deltaY = e.touches[0].pageY - pageY;
  623. pageX = e.touches[0].pageX;
  624. pageY = e.touches[0].pageY;
  625. if (typeof isScrolling === 'undefined') {
  626. isScrolling = Math.abs(deltaY) > Math.abs(deltaX);
  627. }
  628. if (isScrolling) {
  629. return;
  630. }
  631. offsetX = (deltaX / resistance) + getScroll();
  632. e.preventDefault();
  633. resistance = slideNumber === 0 && deltaX > 0 ? (pageX / sliderWidth) + 1.25 :
  634. slideNumber === lastSlide && deltaX < 0 ? (Math.abs(pageX) / sliderWidth) + 1.25 : 1;
  635. slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
  636. };
  637. var onTouchEnd = function (e) {
  638. if (!slider || isScrolling) {
  639. return;
  640. }
  641. setSlideNumber(
  642. (+new Date()) - startTime < 1000 && Math.abs(deltaX) > 15 ? (deltaX < 0 ? -1 : 1) : 0
  643. );
  644. offsetX = slideNumber * sliderWidth;
  645. slider.style['-webkit-transition-duration'] = '.2s';
  646. slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
  647. e = new CustomEvent('slide', {
  648. detail: { slideNumber: Math.abs(slideNumber) },
  649. bubbles: true,
  650. cancelable: true
  651. });
  652. slider.parentNode.dispatchEvent(e);
  653. };
  654. window.addEventListener('touchstart', onTouchStart);
  655. window.addEventListener('touchmove', onTouchMove);
  656. window.addEventListener('touchend', onTouchEnd);
  657. }());
  658. /* ========================================================================
  659. * Ratchet: toggles.js v2.0.2
  660. * http://goratchet.com/components#toggles
  661. * ========================================================================
  662. Adapted from Brad Birdsall's swipe
  663. * Copyright 2014 Connor Sears
  664. * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
  665. * ======================================================================== */
  666. !(function () {
  667. 'use strict';
  668. var start = {};
  669. var touchMove = false;
  670. var distanceX = false;
  671. var toggle = false;
  672. var findToggle = function (target) {
  673. var i;
  674. var toggles = document.querySelectorAll('.toggle');
  675. for (; target && target !== document; target = target.parentNode) {
  676. for (i = toggles.length; i--;) {
  677. if (toggles[i] === target) {
  678. return target;
  679. }
  680. }
  681. }
  682. };
  683. window.addEventListener('touchstart', function (e) {
  684. e = e.originalEvent || e;
  685. toggle = findToggle(e.target);
  686. if (!toggle) {
  687. return;
  688. }
  689. var handle = toggle.querySelector('.toggle-handle');
  690. var toggleWidth = toggle.clientWidth;
  691. var handleWidth = handle.clientWidth;
  692. var offset = toggle.classList.contains('active') ? (toggleWidth - handleWidth) : 0;
  693. start = { pageX : e.touches[0].pageX - offset, pageY : e.touches[0].pageY };
  694. touchMove = false;
  695. });
  696. window.addEventListener('touchmove', function (e) {
  697. e = e.originalEvent || e;
  698. if (e.touches.length > 1) {
  699. return; // Exit if a pinch
  700. }
  701. if (!toggle) {
  702. return;
  703. }
  704. var handle = toggle.querySelector('.toggle-handle');
  705. var current = e.touches[0];
  706. var toggleWidth = toggle.clientWidth;
  707. var handleWidth = handle.clientWidth;
  708. var offset = toggleWidth - handleWidth;
  709. touchMove = true;
  710. distanceX = current.pageX - start.pageX;
  711. if (Math.abs(distanceX) < Math.abs(current.pageY - start.pageY)) {
  712. return;
  713. }
  714. e.preventDefault();
  715. if (distanceX < 0) {
  716. return (handle.style.webkitTransform = 'translate3d(0,0,0)');
  717. }
  718. if (distanceX > offset) {
  719. return (handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)');
  720. }
  721. handle.style.webkitTransform = 'translate3d(' + distanceX + 'px,0,0)';
  722. toggle.classList[(distanceX > (toggleWidth / 2 - handleWidth / 2)) ? 'add' : 'remove']('active');
  723. });
  724. window.addEventListener('touchend', function (e) {
  725. if (!toggle) {
  726. return;
  727. }
  728. var handle = toggle.querySelector('.toggle-handle');
  729. var toggleWidth = toggle.clientWidth;
  730. var handleWidth = handle.clientWidth;
  731. var offset = (toggleWidth - handleWidth);
  732. var slideOn = (!touchMove && !toggle.classList.contains('active')) || (touchMove && (distanceX > (toggleWidth / 2 - handleWidth / 2)));
  733. if (slideOn) {
  734. handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)';
  735. } else {
  736. handle.style.webkitTransform = 'translate3d(0,0,0)';
  737. }
  738. toggle.classList[slideOn ? 'add' : 'remove']('active');
  739. e = new CustomEvent('toggle', {
  740. detail: { isActive: slideOn },
  741. bubbles: true,
  742. cancelable: true
  743. });
  744. toggle.dispatchEvent(e);
  745. touchMove = false;
  746. toggle = false;
  747. });
  748. }());