国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

17550 lines
567KB

  1. /*! Amaze UI v2.1.0 | by Amaze UI Team | (c) 2015 AllMobilize, Inc. | Licensed under MIT | 2015-01-13T02:01:01 UTC */
  2. (function e(t, n, r) {
  3. function s(o, u) {
  4. if (!n[o]) {
  5. if (!t[o]) {
  6. var a = typeof require == "function" && require;
  7. if (!u && a) return a(o, !0);
  8. if (i) return i(o, !0);
  9. var f = new Error("Cannot find module '" + o + "'");
  10. throw f.code = "MODULE_NOT_FOUND", f
  11. }
  12. var l = n[o] = {
  13. exports: {}
  14. };
  15. t[o][0].call(l.exports, function(e) {
  16. var n = t[o][1][e];
  17. return s(n ? n : e)
  18. }, l, l.exports, e, t, n, r)
  19. }
  20. return n[o].exports
  21. }
  22. var i = typeof require == "function" && require;
  23. for (var o = 0; o < r.length; o++) s(r[o]);
  24. return s
  25. })({
  26. 1: [
  27. function(require, module, exports) {
  28. (function(global) {
  29. 'use strict';
  30. require('./core');
  31. require('./ui.collapse');
  32. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  33. "undefined" ? global.jQuery : null);
  34. var UI = $.AMUI;
  35. function accordionInit() {
  36. var $accordion = $('[data-am-widget="accordion"]');
  37. var selector = {
  38. item: '.am-accordion-item',
  39. title: '.am-accordion-title',
  40. body: '.am-accordion-bd'
  41. };
  42. $accordion.each(function(i, item) {
  43. var options = UI.utils.parseOptions($(item).attr(
  44. 'data-am-accordion'));
  45. var $title = $(item).find(selector.title);
  46. $title.on('click.accordion.amui', function() {
  47. var $collapse = $(this).next(selector.body);
  48. var $parent = $(this).parent(selector.item);
  49. var data = $collapse.data('amui.collapse');
  50. $parent.toggleClass('am-active');
  51. if (!data) {
  52. $collapse.collapse();
  53. } else {
  54. $collapse.collapse('toggle');
  55. }
  56. !options.multiple &&
  57. $(item).children('.am-active').
  58. not($parent).removeClass('am-active').
  59. find(selector.body + '.am-in').collapse('close');
  60. });
  61. });
  62. }
  63. // Init on DOM ready
  64. $(function() {
  65. accordionInit();
  66. });
  67. module.exports = $.AMUI.accordion = {
  68. VERSION: '2.0.0',
  69. init: accordionInit
  70. };
  71. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  72. "undefined" ? self : typeof window !== "undefined" ? window : {})
  73. }, {
  74. "./core": 4,
  75. "./ui.collapse": 26
  76. }
  77. ],
  78. 2: [
  79. function(require, module, exports) {
  80. (function(global) {
  81. 'use strict';
  82. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  83. "undefined" ? global.jQuery : null);
  84. require('./core');
  85. require('./util.fastclick');
  86. require('./util.hammer');
  87. require('./amazeui');
  88. require('./amazeui.legacy');
  89. require('./ui.add2home');
  90. require('./ui.alert');
  91. require('./ui.button');
  92. require('./ui.collapse');
  93. require('./ui.datepicker');
  94. require('./ui.dimmer');
  95. require('./ui.dropdown');
  96. require('./ui.flexslider');
  97. require('./ui.iscroll-lite');
  98. require('./ui.modal');
  99. require('./ui.offcanvas');
  100. require('./ui.pinchzoom');
  101. require('./ui.popover');
  102. require('./ui.progress');
  103. require('./ui.pureview');
  104. require('./ui.scrollspy');
  105. require('./ui.scrollspynav');
  106. require('./ui.selected');
  107. require('./ui.share');
  108. require('./ui.smooth-scroll');
  109. require('./ui.sticky');
  110. require('./ui.tabs');
  111. require('./ui.ucheck');
  112. require('./ui.validator');
  113. require('./util.cookie');
  114. require('./util.fullscreen');
  115. require('./util.qrcode');
  116. require('./util.store');
  117. require('./accordion');
  118. require('./divider');
  119. require('./duoshuo');
  120. require('./figure');
  121. require('./footer');
  122. require('./gallery');
  123. require('./gotop');
  124. require('./header');
  125. require('./intro');
  126. require('./list_news');
  127. require('./map');
  128. require('./mechat');
  129. require('./menu');
  130. require('./navbar');
  131. require('./pagination');
  132. require('./paragraph');
  133. require('./slider');
  134. require('./tabs');
  135. require('./titlebar');
  136. module.exports = $.AMUI;
  137. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  138. "undefined" ? self : typeof window !== "undefined" ? window : {})
  139. }, {
  140. "./accordion": 1,
  141. "./amazeui": 2,
  142. "./amazeui.legacy": 3,
  143. "./core": 4,
  144. "./divider": 5,
  145. "./duoshuo": 6,
  146. "./figure": 7,
  147. "./footer": 8,
  148. "./gallery": 9,
  149. "./gotop": 10,
  150. "./header": 11,
  151. "./intro": 12,
  152. "./list_news": 13,
  153. "./map": 14,
  154. "./mechat": 15,
  155. "./menu": 16,
  156. "./navbar": 17,
  157. "./pagination": 18,
  158. "./paragraph": 19,
  159. "./slider": 20,
  160. "./tabs": 21,
  161. "./titlebar": 22,
  162. "./ui.add2home": 23,
  163. "./ui.alert": 24,
  164. "./ui.button": 25,
  165. "./ui.collapse": 26,
  166. "./ui.datepicker": 27,
  167. "./ui.dimmer": 28,
  168. "./ui.dropdown": 29,
  169. "./ui.flexslider": 30,
  170. "./ui.iscroll-lite": 31,
  171. "./ui.modal": 32,
  172. "./ui.offcanvas": 33,
  173. "./ui.pinchzoom": 34,
  174. "./ui.popover": 35,
  175. "./ui.progress": 36,
  176. "./ui.pureview": 37,
  177. "./ui.scrollspy": 38,
  178. "./ui.scrollspynav": 39,
  179. "./ui.selected": 40,
  180. "./ui.share": 41,
  181. "./ui.smooth-scroll": 42,
  182. "./ui.sticky": 43,
  183. "./ui.tabs": 44,
  184. "./ui.ucheck": 45,
  185. "./ui.validator": 46,
  186. "./util.cookie": 47,
  187. "./util.fastclick": 48,
  188. "./util.fullscreen": 49,
  189. "./util.hammer": 50,
  190. "./util.qrcode": 51,
  191. "./util.store": 52
  192. }
  193. ],
  194. 3: [
  195. function(require, module, exports) {
  196. (function(global) {
  197. // Amaze UI JavaScript for IE8
  198. 'use strict';
  199. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  200. "undefined" ? global.jQuery : null);
  201. require('./core');
  202. require('./ui.alert');
  203. require('./ui.button');
  204. require('./ui.collapse');
  205. require('./ui.dimmer');
  206. require('./ui.dropdown');
  207. require('./ui.flexslider');
  208. require('./ui.modal');
  209. require('./ui.offcanvas');
  210. require('./ui.popover');
  211. require('./ui.progress');
  212. require('./ui.scrollspynav');
  213. require('./ui.sticky');
  214. require('./util.cookie');
  215. module.exports = $.AMUI;
  216. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  217. "undefined" ? self : typeof window !== "undefined" ? window : {})
  218. }, {
  219. "./core": 4,
  220. "./ui.alert": 24,
  221. "./ui.button": 25,
  222. "./ui.collapse": 26,
  223. "./ui.dimmer": 28,
  224. "./ui.dropdown": 29,
  225. "./ui.flexslider": 30,
  226. "./ui.modal": 32,
  227. "./ui.offcanvas": 33,
  228. "./ui.popover": 35,
  229. "./ui.progress": 36,
  230. "./ui.scrollspynav": 39,
  231. "./ui.sticky": 43,
  232. "./util.cookie": 47
  233. }
  234. ],
  235. 4: [
  236. function(require, module, exports) {
  237. (function(global) {
  238. 'use strict';
  239. /* jshint -W040 */
  240. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  241. "undefined" ? global.jQuery : null);
  242. if (typeof $ === 'undefined') {
  243. throw new Error('Amaze UI 2.x requires jQuery :-(\n' +
  244. '\u7231\u4e0a\u4e00\u5339\u91ce\u9a6c\uff0c\u53ef\u4f60' +
  245. '\u7684\u5bb6\u91cc\u6ca1\u6709\u8349\u539f\u2026');
  246. }
  247. var UI = $.AMUI || {};
  248. var $win = $(window);
  249. var doc = window.document;
  250. var $html = $('html');
  251. UI.VERSION = '2.0.0';
  252. UI.support = {};
  253. UI.support.transition = (function() {
  254. var transitionEnd = (function() {
  255. // https://developer.mozilla.org/en-US/docs/Web/Events/transitionend#Browser_compatibility
  256. var element = doc.body || doc.documentElement;
  257. var transEndEventNames = {
  258. WebkitTransition: 'webkitTransitionEnd',
  259. MozTransition: 'transitionend',
  260. OTransition: 'oTransitionEnd otransitionend',
  261. transition: 'transitionend'
  262. };
  263. for (var name in transEndEventNames) {
  264. if (element.style[name] !== undefined) {
  265. return transEndEventNames[name];
  266. }
  267. }
  268. })();
  269. return transitionEnd && {
  270. end: transitionEnd
  271. };
  272. })();
  273. UI.support.animation = (function() {
  274. var animationEnd = (function() {
  275. var element = doc.body || doc.documentElement;
  276. var animEndEventNames = {
  277. WebkitAnimation: 'webkitAnimationEnd',
  278. MozAnimation: 'animationend',
  279. OAnimation: 'oAnimationEnd oanimationend',
  280. animation: 'animationend'
  281. };
  282. for (var name in animEndEventNames) {
  283. if (element.style[name] !== undefined) {
  284. return animEndEventNames[name];
  285. }
  286. }
  287. })();
  288. return animationEnd && {
  289. end: animationEnd
  290. };
  291. })();
  292. /* jshint -W069 */
  293. UI.support.touch = (
  294. ('ontouchstart' in window &&
  295. navigator.userAgent.toLowerCase().match(/mobile|tablet/)) ||
  296. (window.DocumentTouch && document instanceof window.DocumentTouch) ||
  297. (window.navigator['msPointerEnabled'] &&
  298. window.navigator['msMaxTouchPoints'] > 0) || //IE 10
  299. (window.navigator['pointerEnabled'] &&
  300. window.navigator['maxTouchPoints'] > 0) || //IE >=11
  301. false);
  302. // https://developer.mozilla.org/zh-CN/docs/DOM/MutationObserver
  303. UI.support.mutationobserver = (window.MutationObserver ||
  304. window.WebKitMutationObserver || null);
  305. // https://github.com/Modernizr/Modernizr/blob/924c7611c170ef2dc502582e5079507aff61e388/feature-detects/forms/validation.js#L20
  306. UI.support.formValidation = (typeof document.createElement('form').checkValidity ===
  307. 'function');
  308. UI.utils = {};
  309. /**
  310. * Debounce function
  311. * @param {function} func Function to be debounced
  312. * @param {number} wait Function execution threshold in milliseconds
  313. * @param {bool} immediate Whether the function should be called at
  314. * the beginning of the delay instead of the
  315. * end. Default is false.
  316. * @desc Executes a function when it stops being invoked for n seconds
  317. * @via _.debounce() http://underscorejs.org
  318. */
  319. UI.utils.debounce = function(func, wait, immediate) {
  320. var timeout;
  321. return function() {
  322. var context = this;
  323. var args = arguments;
  324. var later = function() {
  325. timeout = null;
  326. if (!immediate) {
  327. func.apply(context, args);
  328. }
  329. };
  330. var callNow = immediate && !timeout;
  331. clearTimeout(timeout);
  332. timeout = setTimeout(later, wait);
  333. if (callNow) {
  334. func.apply(context, args);
  335. }
  336. };
  337. };
  338. UI.utils.isInView = function(element, options) {
  339. var $element = $(element);
  340. var visible = !!($element.width() || $element.height()) &&
  341. $element.css('display') !== 'none';
  342. if (!visible) {
  343. return false;
  344. }
  345. var windowLeft = $win.scrollLeft();
  346. var windowTop = $win.scrollTop();
  347. var offset = $element.offset();
  348. var left = offset.left;
  349. var top = offset.top;
  350. options = $.extend({
  351. topOffset: 0,
  352. leftOffset: 0
  353. }, options);
  354. return (top + $element.height() >= windowTop &&
  355. top - options.topOffset <= windowTop + $win.height() &&
  356. left + $element.width() >= windowLeft &&
  357. left - options.leftOffset <= windowLeft + $win.width());
  358. };
  359. /* jshint -W054 */
  360. UI.utils.parseOptions = UI.utils.options = function(string) {
  361. if ($.isPlainObject(string)) {
  362. return string;
  363. }
  364. var start = (string ? string.indexOf('{') : -1);
  365. var options = {};
  366. if (start != -1) {
  367. try {
  368. options = (new Function('',
  369. 'var json = ' + string.substr(start) +
  370. '; return JSON.parse(JSON.stringify(json));'))();
  371. } catch (e) {}
  372. }
  373. return options;
  374. };
  375. /* jshint +W054 */
  376. UI.utils.generateGUID = function(namespace) {
  377. var uid = namespace + '-' || 'am-';
  378. do {
  379. uid += Math.random().toString(36).substring(2, 7);
  380. } while (document.getElementById(uid));
  381. return uid;
  382. };
  383. // http://blog.alexmaccaw.com/css-transitions
  384. $.fn.emulateTransitionEnd = function(duration) {
  385. var called = false;
  386. var $el = this;
  387. $(this).one(UI.support.transition.end, function() {
  388. called = true;
  389. });
  390. var callback = function() {
  391. if (!called) {
  392. $($el).trigger(UI.support.transition.end);
  393. }
  394. $el.transitionEndTimmer = undefined;
  395. };
  396. this.transitionEndTimmer = setTimeout(callback, duration);
  397. return this;
  398. };
  399. $.fn.redraw = function() {
  400. $(this).each(function() {
  401. /* jshint unused:false */
  402. var redraw = this.offsetHeight;
  403. });
  404. return this;
  405. };
  406. /* jshint unused:true */
  407. $.fn.transitionEnd = function(callback) {
  408. var endEvent = UI.support.transition.end;
  409. var dom = this;
  410. function fireCallBack(e) {
  411. callback.call(this, e);
  412. endEvent && dom.off(endEvent, fireCallBack);
  413. }
  414. if (callback && endEvent) {
  415. dom.on(endEvent, fireCallBack);
  416. }
  417. return this;
  418. };
  419. $.fn.removeClassRegEx = function() {
  420. return this.each(function(regex) {
  421. var classes = $(this).attr('class');
  422. if (!classes || !regex) {
  423. return false;
  424. }
  425. var classArray = [];
  426. classes = classes.split(' ');
  427. for (var i = 0, len = classes.length; i < len; i++) {
  428. if (!classes[i].match(regex)) {
  429. classArray.push(classes[i]);
  430. }
  431. }
  432. $(this).attr('class', classArray.join(' '));
  433. });
  434. };
  435. //
  436. $.fn.alterClass = function(removals, additions) {
  437. var self = this;
  438. if (removals.indexOf('*') === -1) {
  439. // Use native jQuery methods if there is no wildcard matching
  440. self.removeClass(removals);
  441. return !additions ? self : self.addClass(additions);
  442. }
  443. var classPattern = new RegExp('\\s' +
  444. removals.replace(/\*/g, '[A-Za-z0-9-_]+').split(' ').join(
  445. '\\s|\\s') +
  446. '\\s', 'g');
  447. self.each(function(i, it) {
  448. var cn = ' ' + it.className + ' ';
  449. while (classPattern.test(cn)) {
  450. cn = cn.replace(classPattern, ' ');
  451. }
  452. it.className = $.trim(cn);
  453. });
  454. return !additions ? self : self.addClass(additions);
  455. };
  456. // handle multiple browsers for requestAnimationFrame()
  457. // http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
  458. // https://github.com/gnarf/jquery-requestAnimationFrame
  459. UI.utils.rAF = (function() {
  460. return window.requestAnimationFrame ||
  461. window.webkitRequestAnimationFrame ||
  462. window.mozRequestAnimationFrame ||
  463. window.oRequestAnimationFrame ||
  464. // if all else fails, use setTimeout
  465. function(callback) {
  466. return window.setTimeout(callback, 1000 / 60); // shoot for 60 fps
  467. };
  468. })();
  469. // handle multiple browsers for cancelAnimationFrame()
  470. UI.utils.cancelAF = (function() {
  471. return window.cancelAnimationFrame ||
  472. window.webkitCancelAnimationFrame ||
  473. window.mozCancelAnimationFrame ||
  474. window.oCancelAnimationFrame ||
  475. function(id) {
  476. window.clearTimeout(id);
  477. };
  478. })();
  479. // via http://davidwalsh.name/detect-scrollbar-width
  480. UI.utils.measureScrollbar = function() {
  481. if (document.body.clientWidth >= window.innerWidth) {
  482. return 0;
  483. }
  484. // if ($html.width() >= window.innerWidth) return;
  485. // var scrollbarWidth = window.innerWidth - $html.width();
  486. var $measure = $('<div ' +
  487. 'style="width: 100px;height: 100px;overflow: scroll;' +
  488. 'position: absolute;top: -9999px;"></div>');
  489. $(document.body).append($measure);
  490. var scrollbarWidth = $measure[0].offsetWidth - $measure[0].clientWidth;
  491. $measure.remove();
  492. return scrollbarWidth;
  493. };
  494. UI.utils.imageLoader = function($image, callback) {
  495. function loaded() {
  496. callback($image[0]);
  497. }
  498. function bindLoad() {
  499. this.one('load', loaded);
  500. if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
  501. var src = this.attr('src');
  502. var param = src.match(/\?/) ? '&' : '?';
  503. param += 'random=' + (new Date()).getTime();
  504. this.attr('src', src + param);
  505. }
  506. }
  507. if (!$image.attr('src')) {
  508. loaded();
  509. return;
  510. }
  511. if ($image[0].complete || $image[0].readyState === 4) {
  512. loaded();
  513. } else {
  514. bindLoad.call($image);
  515. }
  516. };
  517. /**
  518. * https://github.com/cho45/micro-template.js
  519. * (c) cho45 http://cho45.github.com/mit-license
  520. */
  521. /* jshint -W109 */
  522. UI.template = function(id, data) {
  523. var me = UI.template;
  524. if (!me.cache[id]) {
  525. me.cache[id] = (function() {
  526. var name = id;
  527. var string = /^[\w\-]+$/.test(id) ?
  528. me.get(id) : (name = 'template(string)', id); // no warnings
  529. var line = 1;
  530. var body = ('try { ' + (me.variable ?
  531. 'var ' + me.variable + ' = this.stash;' :
  532. 'with (this.stash) { ') +
  533. "this.ret += '" +
  534. string.replace(/<%/g, '\x11').replace(/%>/g, '\x13'). // if you want other tag, just edit this line
  535. replace(/'(?![^\x11\x13]+?\x13)/g, '\\x27').replace(
  536. /^\s*|\s*$/g, '').replace(/\n/g, function() {
  537. return "';\nthis.line = " + (++line) +
  538. "; this.ret += '\\n";
  539. }).replace(/\x11-(.+?)\x13/g, "' + ($1) + '").replace(
  540. /\x11=(.+?)\x13/g, "' + this.escapeHTML($1) + '").replace(
  541. /\x11(.+?)\x13/g, "'; $1; this.ret += '") +
  542. "'; " + (me.variable ? "" : "}") + "return this.ret;" +
  543. "} catch (e) { throw 'TemplateError: ' + e + ' (on " +
  544. name +
  545. "' + ' line ' + this.line + ')'; } " +
  546. "//@ sourceURL=" + name + "\n" // source map
  547. ).replace(/this\.ret \+= '';/g, '');
  548. /* jshint -W054 */
  549. var func = new Function(body);
  550. var map = {
  551. '&': '&amp;',
  552. '<': '&lt;',
  553. '>': '&gt;',
  554. '\x22': '&#x22;',
  555. '\x27': '&#x27;'
  556. };
  557. var escapeHTML = function(string) {
  558. return ('' + string).replace(/[&<>\'\"]/g, function(_) {
  559. return map[_];
  560. });
  561. };
  562. return function(stash) {
  563. return func.call(me.context = {
  564. escapeHTML: escapeHTML,
  565. line: 1,
  566. ret: '',
  567. stash: stash
  568. });
  569. };
  570. })();
  571. }
  572. return data ? me.cache[id](data) : me.cache[id];
  573. };
  574. /* jshint +W109 */
  575. /* jshint +W054 */
  576. UI.template.cache = {};
  577. UI.template.get = function(id) {
  578. if (id) {
  579. var element = document.getElementById(id);
  580. return element && element.innerHTML || '';
  581. }
  582. };
  583. // Dom mutation watchers
  584. UI.DOMWatchers = [];
  585. UI.DOMReady = false;
  586. UI.ready = function(callback) {
  587. UI.DOMWatchers.push(callback);
  588. if (UI.DOMReady) {
  589. console.log('ready call');
  590. callback(document);
  591. }
  592. };
  593. UI.DOMObserve = function(elements, options, callback) {
  594. var Observer = UI.support.mutationobserver;
  595. if (!Observer) {
  596. return;
  597. }
  598. options = $.isPlainObject(options) ?
  599. options : {
  600. childList: true,
  601. subtree: true
  602. };
  603. callback = typeof callback === 'function' && callback || function() {};
  604. $(elements).each(function() {
  605. var element = this;
  606. var $element = $(element);
  607. if ($element.data('am.observer')) {
  608. return;
  609. }
  610. try {
  611. var observer = new Observer(UI.utils.debounce(
  612. function(mutations, instance) {
  613. callback.call(element, mutations, instance);
  614. // trigger this event manually if MutationObserver not supported
  615. $element.trigger('changed.dom.amui');
  616. }, 50));
  617. observer.observe(element, options);
  618. $element.data('am.observer', observer);
  619. } catch (e) {}
  620. });
  621. };
  622. $.fn.DOMObserve = function(options, callback) {
  623. return this.each(function() {
  624. UI.DOMObserve(this, options, callback);
  625. });
  626. };
  627. // Attach FastClick on touch devices
  628. if (UI.support.touch) {
  629. $html.addClass('am-touch');
  630. $(function() {
  631. var FastClick = $.AMUI.FastClick;
  632. FastClick && FastClick.attach(document.body);
  633. });
  634. }
  635. $(document).on('changed.dom.amui', function(e) {
  636. var element = e.target;
  637. // TODO: just call changed element's watcher
  638. // every watcher callback should have a key
  639. // use like this: <div data-am-observe='key1, key2'>
  640. // get keys via $(element).data('amObserve')
  641. // call functions store with these keys
  642. $.each(UI.DOMWatchers, function(i, watcher) {
  643. watcher(element);
  644. });
  645. });
  646. $(function() {
  647. var $body = $('body');
  648. UI.DOMReady = true;
  649. // Run default init
  650. $.each(UI.DOMWatchers, function(i, watcher) {
  651. watcher(document);
  652. });
  653. // watches DOM
  654. UI.DOMObserve('[data-am-observe]');
  655. $html.removeClass('no-js').addClass('js');
  656. UI.support.animation && $html.addClass('cssanimations');
  657. // iOS standalone mode
  658. if (window.navigator.standalone) {
  659. $html.addClass('am-standalone');
  660. }
  661. $('.am-topbar-fixed-top').length &&
  662. $body.addClass('am-with-topbar-fixed-top');
  663. $('.am-topbar-fixed-bottom').length &&
  664. $body.addClass('am-with-topbar-fixed-bottom');
  665. // Remove responsive classes in .am-layout
  666. var $layout = $('.am-layout');
  667. $layout.find('[class*="md-block-grid"]').alterClass(
  668. 'md-block-grid-*');
  669. $layout.find('[class*="lg-block-grid"]').alterClass(
  670. 'lg-block-grid');
  671. // widgets not in .am-layout
  672. $('[data-am-widget]').each(function() {
  673. var $widget = $(this);
  674. // console.log($widget.parents('.am-layout').length)
  675. if ($widget.parents('.am-layout').length === 0) {
  676. $widget.addClass('am-no-layout');
  677. }
  678. });
  679. });
  680. $.AMUI = UI;
  681. module.exports = UI;
  682. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  683. "undefined" ? self : typeof window !== "undefined" ? window : {})
  684. }, {}
  685. ],
  686. 5: [
  687. function(require, module, exports) {
  688. 'use strict';
  689. module.exports = {
  690. VERSION: '2.0.0'
  691. };
  692. }, {}
  693. ],
  694. 6: [
  695. function(require, module, exports) {
  696. (function(global) {
  697. 'use strict';
  698. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  699. "undefined" ? global.jQuery : null);
  700. require('./core');
  701. function duoshuoInit() {
  702. var $dsThread = $('.ds-thread');
  703. var dsShortName = $dsThread.parent('[data-am-widget="duoshuo"]').
  704. attr('data-ds-short-name');
  705. var dsSrc = (document.location.protocol == 'https:' ? 'https:' :
  706. 'http:') +
  707. '//static.duoshuo.com/embed.js';
  708. if (!$dsThread.length || !dsShortName) {
  709. return;
  710. }
  711. window.duoshuoQuery = {
  712. short_name: dsShortName
  713. };
  714. // 已经有多说脚本
  715. if ($('script[src="' + dsSrc + '"]').length) {
  716. return;
  717. }
  718. var $dsJS = $('<script>', {
  719. async: true,
  720. type: 'text/javascript',
  721. src: dsSrc,
  722. charset: 'utf-8'
  723. });
  724. $('body').append($dsJS);
  725. }
  726. $(window).on('load', duoshuoInit);
  727. module.exports = $.AMUI.duoshuo = {
  728. VERSION: '2.0.0',
  729. init: duoshuoInit
  730. };
  731. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  732. "undefined" ? self : typeof window !== "undefined" ? window : {})
  733. }, {
  734. "./core": 4
  735. }
  736. ],
  737. 7: [
  738. function(require, module, exports) {
  739. (function(global) {
  740. 'use strict';
  741. require('./core');
  742. require('./ui.pureview');
  743. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  744. "undefined" ? global.jQuery : null);
  745. var UI = $.AMUI;
  746. /**
  747. * Is Images zoomable
  748. * @return {Boolean}
  749. */
  750. $.isImgZoomAble = function(element) {
  751. var t = new Image();
  752. t.src = element.src;
  753. var zoomAble = ($(element).width() < t.width);
  754. if (zoomAble) {
  755. $(element).closest('.am-figure').addClass('am-figure-zoomable');
  756. }
  757. return zoomAble;
  758. };
  759. function figureInit() {
  760. $('.am-figure').each(function(i, item) {
  761. var options = UI.utils.parseOptions($(item).attr(
  762. 'data-am-figure'));
  763. if (options.pureview) {
  764. if (options.pureview === 'auto') {
  765. var zoomAble = $.isImgZoomAble($(item).find('img')[0]);
  766. zoomAble && $(item).pureview();
  767. } else {
  768. $(item).addClass('am-figure-zoomable').pureview();
  769. }
  770. }
  771. });
  772. }
  773. $(window).on('load', function() {
  774. figureInit();
  775. });
  776. module.exports = $.AMUI.figure = {
  777. VERSION: '2.0.1',
  778. init: figureInit
  779. };
  780. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  781. "undefined" ? self : typeof window !== "undefined" ? window : {})
  782. }, {
  783. "./core": 4,
  784. "./ui.pureview": 37
  785. }
  786. ],
  787. 8: [
  788. function(require, module, exports) {
  789. (function(global) {
  790. 'use strict';
  791. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  792. "undefined" ? global.jQuery : null);
  793. var UI = require('./core');
  794. require('./ui.modal');
  795. var addToHS = require('./ui.add2home');
  796. var cookie = require('./util.cookie');
  797. function footerInit() {
  798. // modal mode
  799. $('.am-footer-ysp').on('click', function() {
  800. $('#am-footer-modal').modal();
  801. });
  802. var options = UI.utils.parseOptions($('.am-footer').data(
  803. 'amFooter'));
  804. options.addToHS && addToHS();
  805. // switch mode
  806. // switch to desktop
  807. $('[data-rel="desktop"]').on('click', function(e) {
  808. e.preventDefault();
  809. if (window.AMPlatform) { // front end
  810. window.AMPlatform.util.goDesktop();
  811. } else { // back end
  812. cookie.set('allmobilize', 'desktop', '', '/');
  813. window.location = window.location;
  814. }
  815. });
  816. }
  817. $(function() {
  818. footerInit();
  819. });
  820. module.exports = $.AMUI.footer = {
  821. VERSION: '3.1.1',
  822. init: footerInit
  823. };
  824. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  825. "undefined" ? self : typeof window !== "undefined" ? window : {})
  826. }, {
  827. "./core": 4,
  828. "./ui.add2home": 23,
  829. "./ui.modal": 32,
  830. "./util.cookie": 47
  831. }
  832. ],
  833. 9: [
  834. function(require, module, exports) {
  835. (function(global) {
  836. 'use strict';
  837. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  838. "undefined" ? global.jQuery : null);
  839. require('./core');
  840. require('./ui.pureview');
  841. var UI = $.AMUI;
  842. function galleryInit() {
  843. var $gallery = $('[data-am-widget="gallery"]');
  844. var $galleryOne = $gallery.filter('.am-gallery-one');
  845. $gallery.each(function() {
  846. var options = UI.utils.parseOptions($(this).attr(
  847. 'data-am-gallery'));
  848. if (options.pureview) {
  849. (typeof options.pureview === 'object') ?
  850. $(this).pureview(options.pureview) : $(this).pureview();
  851. }
  852. });
  853. $galleryOne.each(function() {
  854. galleryMore($(this));
  855. });
  856. }
  857. function galleryMore($elements) {
  858. var moreData = $('<li class=\'am-gallery-more\'>' +
  859. '<a href="javascript:;">更多 &gt;&gt;</a></li>');
  860. if ($elements.children().length > 6) {
  861. $elements.children().each(function(index) {
  862. if (index > 5) {
  863. $(this).hide();
  864. }
  865. });
  866. $elements.find('.am-gallery-more').remove();
  867. $elements.append(moreData);
  868. }
  869. $elements.find('.am-gallery-more').on('click', function() {
  870. $elements.children().show();
  871. $(this).hide();
  872. });
  873. }
  874. $(function() {
  875. galleryInit();
  876. });
  877. module.exports = $.AMUI.gallery = {
  878. VERSION: '2.0.0',
  879. init: galleryInit
  880. };
  881. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  882. "undefined" ? self : typeof window !== "undefined" ? window : {})
  883. }, {
  884. "./core": 4,
  885. "./ui.pureview": 37
  886. }
  887. ],
  888. 10: [
  889. function(require, module, exports) {
  890. (function(global) {
  891. 'use strict';
  892. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  893. "undefined" ? global.jQuery : null);
  894. require('./core');
  895. require('./ui.smooth-scroll');
  896. function goTopInit() {
  897. var $goTop = $('[data-am-widget="gotop"]');
  898. var $fixed = $goTop.filter('.am-gotop-fixed');
  899. var $win = $(window);
  900. $goTop.find('a').on('click', function(e) {
  901. e.preventDefault();
  902. $win.smoothScroll();
  903. });
  904. function checkPosition() {
  905. $fixed[($win.scrollTop() > 50 ? 'add' : 'remove') + 'Class'](
  906. 'am-active');
  907. }
  908. checkPosition();
  909. $win.on('scroll.gotop.amui', $.AMUI.utils.debounce(checkPosition,
  910. 100));
  911. }
  912. $(function() {
  913. goTopInit();
  914. });
  915. module.exports = $.AMUI.gotop = {
  916. VERSION: '4.0.1',
  917. init: goTopInit
  918. };
  919. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  920. "undefined" ? self : typeof window !== "undefined" ? window : {})
  921. }, {
  922. "./core": 4,
  923. "./ui.smooth-scroll": 42
  924. }
  925. ],
  926. 11: [
  927. function(require, module, exports) {
  928. (function(global) {
  929. 'use strict';
  930. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  931. "undefined" ? global.jQuery : null);
  932. require('./core');
  933. function headerInit() {
  934. $('[data-am-widget="header"]').each(function() {
  935. if ($(this).hasClass('am-header-fixed')) {
  936. $('body').addClass('am-with-fixed-header');
  937. return false;
  938. }
  939. });
  940. }
  941. $(function() {
  942. headerInit();
  943. });
  944. module.exports = $.AMUI.header = {
  945. VERSION: '2.0.0',
  946. init: headerInit
  947. };
  948. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  949. "undefined" ? self : typeof window !== "undefined" ? window : {})
  950. }, {
  951. "./core": 4
  952. }
  953. ],
  954. 12: [
  955. function(require, module, exports) {
  956. (function(global) {
  957. 'use strict';
  958. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  959. "undefined" ? global.jQuery : null);
  960. require('./core');
  961. module.exports = $.AMUI.intro = {
  962. VERSION: '4.0.0'
  963. };
  964. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  965. "undefined" ? self : typeof window !== "undefined" ? window : {})
  966. }, {
  967. "./core": 4
  968. }
  969. ],
  970. 13: [
  971. function(require, module, exports) {
  972. (function(global) {
  973. 'use strict';
  974. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  975. "undefined" ? global.jQuery : null);
  976. require('./core');
  977. function listNewsInit() {
  978. $('.am-list-news-one').each(function() {
  979. amListNewsMore($(this));
  980. });
  981. }
  982. function amListNewsMore($element) {
  983. var $amList = $element.find('.am-list');
  984. var $listMore =
  985. '<a class="am-list-news-more am-btn am-btn-default" ' +
  986. 'href="javascript:;">更多 &gt;&gt;</a>';
  987. if ($amList.children().length > 6) {
  988. $amList.children().each(function(index) {
  989. if (index > 5) {
  990. $(this).hide();
  991. }
  992. });
  993. $element.find('.am-list-news-more').remove();
  994. $element.append($listMore);
  995. }
  996. $element.find('.am-list-news-more').on('click', function() {
  997. $amList.children().show();
  998. $(this).hide();
  999. });
  1000. }
  1001. $(function() {
  1002. listNewsInit();
  1003. });
  1004. module.exports = $.AMUI.listNews = {
  1005. VERSION: '3.0.0',
  1006. init: listNewsInit
  1007. };
  1008. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1009. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1010. }, {
  1011. "./core": 4
  1012. }
  1013. ],
  1014. 14: [
  1015. function(require, module, exports) {
  1016. (function(global) {
  1017. /* jshint strict: false, maxlen: 200 */
  1018. /* global BMap */
  1019. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1020. "undefined" ? global.jQuery : null);
  1021. require('./core');
  1022. function addMapApi(callback) {
  1023. var $mapApi0 = $('<script />', {
  1024. id: 'am-map-api-0'
  1025. });
  1026. $('body').append($mapApi0);
  1027. $mapApi0.on('load', function() {
  1028. console.log('load');
  1029. var $mapApi1 = $('<script/>', {
  1030. id: 'am-map-api-1'
  1031. });
  1032. $('body').append($mapApi1);
  1033. $mapApi1.on('load', function() {
  1034. var script = document.createElement('script');
  1035. script.textContent = '(' + callback.toString() + ')();';
  1036. $('body')[0].appendChild(script);
  1037. }).attr('src', 'http://api.map.baidu.com/getscript' +
  1038. '?type=quick&file=feature' +
  1039. '&ak=WVAXZ05oyNRXS5egLImmentg&t=20140109092002');
  1040. }).attr('src', 'http://api.map.baidu.com/getscript' +
  1041. '?type=quick&file=api&ak=WVAXZ05oyNRXS5egLImmentg&t=20140109092002'
  1042. );
  1043. // jQuery 中 `load` 事件触发有问题,动态设置 src 属性才会触发 `load` 事件
  1044. // $mapApi0 = $('<script />', {src: 'xxx'}); 这样的写法在 Zepto.js 中则没有问题
  1045. }
  1046. function addBdMap() {
  1047. // 如果使用 $ 选择符,minify 以后会报错: $ is undefined
  1048. // 即使传入 $ 也无效,改为使用原生方法
  1049. // 这个函数作为 callback 会插入到 body 以后才执行,应该是 $ 引用错误导致
  1050. var content = document.querySelector('.am-map');
  1051. var defaultLng = 116.331398; // 经度默认值
  1052. var defaultLat = 39.897445; // 纬度默认值
  1053. var name = content.getAttribute('data-name');
  1054. var address = content.getAttribute('data-address');
  1055. var lng = content.getAttribute('data-longitude') || defaultLng;
  1056. var lat = content.getAttribute('data-latitude') || defaultLat;
  1057. var setZoom = content.getAttribute('data-setZoom') || 17;
  1058. var icon = content.getAttribute('data-icon');
  1059. var map = new BMap.Map('bd-map');
  1060. // 实例化一个地理坐标点
  1061. var point = new BMap.Point(lng, lat);
  1062. // 设初始化地图, options: 3-18
  1063. map.centerAndZoom(point, setZoom);
  1064. // 添加地图缩放控件
  1065. if (content.getAttribute('data-zoomControl')) {
  1066. map.addControl(new BMap.ZoomControl());
  1067. }
  1068. // 添加比例尺控件
  1069. if (content.getAttribute('data-scaleControl')) {
  1070. map.addControl(new BMap.ScaleControl());
  1071. }
  1072. // 创建标准与自定义 icon
  1073. var marker = new BMap.Marker(point);
  1074. if (icon) {
  1075. marker.setIcon(new BMap.Icon(icon, new BMap.Size(40, 40)));
  1076. }
  1077. var opts = {
  1078. width: 200, // 信息窗口宽度
  1079. // height: 'auto', // 信息窗口高度
  1080. title: name // 信息窗口标题
  1081. };
  1082. // 创建信息窗口对象
  1083. var infoWindow = new BMap.InfoWindow('地址:' + address, opts);
  1084. // 创建地址解析器实例
  1085. var myGeo = new BMap.Geocoder();
  1086. // 判断有没有使用经纬度
  1087. if (lng == defaultLng && lat == defaultLat) {
  1088. // 使用地址反解析来设置地图
  1089. // 将地址解析结果显示在地图上,并调整地图视野
  1090. myGeo.getPoint(address, function(point) {
  1091. if (point) {
  1092. map.centerAndZoom(point, setZoom);
  1093. marker.setPosition(point);
  1094. map.addOverlay(marker);
  1095. map.openInfoWindow(infoWindow, point); // 开启信息窗口
  1096. }
  1097. }, '');
  1098. } else {
  1099. // 使用经纬度来设置地图
  1100. myGeo.getLocation(point, function(result) {
  1101. map.centerAndZoom(point, setZoom);
  1102. marker.setPosition(point);
  1103. map.addOverlay(marker);
  1104. if (address) {
  1105. map.openInfoWindow(infoWindow, point); // 开启信息窗口
  1106. } else {
  1107. map.openInfoWindow(new BMap.InfoWindow(address, opts),
  1108. point); // 开启信息窗口
  1109. }
  1110. });
  1111. }
  1112. }
  1113. var mapInit = function() {
  1114. $('.am-map').length && addMapApi(addBdMap);
  1115. };
  1116. $(document).on('ready', mapInit);
  1117. module.exports = $.AMUI.map = {
  1118. VERSION: '2.0.1',
  1119. init: mapInit
  1120. };
  1121. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1122. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1123. }, {
  1124. "./core": 4
  1125. }
  1126. ],
  1127. 15: [
  1128. function(require, module, exports) {
  1129. (function(global) {
  1130. 'use strict';
  1131. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1132. "undefined" ? global.jQuery : null);
  1133. require('./core');
  1134. function mechatInit() {
  1135. if (!$('#mechat').length) {
  1136. return;
  1137. }
  1138. var $mechat = $('[data-am-widget="mechat"]');
  1139. var unitid = $mechat.data('am-mechat-unitid');
  1140. var $mechatData = $('<script>', {
  1141. charset: 'utf-8',
  1142. src: 'http://mechatim.com/js/unit/button.js?id=' + unitid
  1143. });
  1144. $('body').append($mechatData);
  1145. }
  1146. // Lazy load
  1147. $(window).on('load', mechatInit);
  1148. module.exports = $.AMUI.mechat = {
  1149. VERSION: '2.0.0',
  1150. init: mechatInit
  1151. };
  1152. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1153. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1154. }, {
  1155. "./core": 4
  1156. }
  1157. ],
  1158. 16: [
  1159. function(require, module, exports) {
  1160. (function(global) {
  1161. 'use strict';
  1162. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1163. "undefined" ? global.jQuery : null);
  1164. require('./core');
  1165. require('./ui.offcanvas');
  1166. require('./ui.collapse');
  1167. var IScroll = require('./ui.iscroll-lite');
  1168. var menuInit = function() {
  1169. var $menus = $('[data-am-widget="menu"]');
  1170. $menus.find('.am-menu-nav .am-parent > a').on('click', function(
  1171. e) {
  1172. e.preventDefault();
  1173. var $clicked = $(this);
  1174. var $parent = $clicked.parent();
  1175. var $subMenu = $clicked.next('.am-menu-sub');
  1176. $parent.toggleClass('am-open');
  1177. $subMenu.collapse('toggle');
  1178. $parent.siblings('.am-parent').removeClass('am-open')
  1179. .children('.am-menu-sub.am-in').collapse('close');
  1180. });
  1181. // Dropdown/slideDown menu
  1182. $menus.
  1183. filter('[data-am-menu-collapse]').
  1184. find('> .am-menu-toggle').
  1185. on('click', function(e) {
  1186. e.preventDefault();
  1187. var $this = $(this);
  1188. var $nav = $this.next('.am-menu-nav');
  1189. $this.toggleClass('am-active');
  1190. $nav.collapse('toggle');
  1191. });
  1192. // OffCanvas menu
  1193. $menus.
  1194. filter('[data-am-menu-offcanvas]').
  1195. find('> .am-menu-toggle').
  1196. on('click', function(e) {
  1197. e.preventDefault();
  1198. var $this = $(this);
  1199. var $nav = $this.next('.am-offcanvas');
  1200. $this.toggleClass('am-active');
  1201. $nav.offCanvas('open');
  1202. });
  1203. // Close offCanvas when link clicked
  1204. var autoCloseOffCanvas =
  1205. '.am-offcanvas[data-dismiss-on="click"]';
  1206. var $autoCloseOffCanvas = $(autoCloseOffCanvas);
  1207. $autoCloseOffCanvas.find('a').not('.am-parent>a').on('click',
  1208. function(e) {
  1209. $(this).parents(autoCloseOffCanvas).offCanvas('close');
  1210. });
  1211. // one theme
  1212. $menus.filter('.am-menu-one').each(function(index) {
  1213. var $this = $(this);
  1214. var $wrap = $('<div class="am-menu-nav-sub-wrap"></div>');
  1215. var allWidth = 0;
  1216. var $nav = $this.find('.am-menu-nav');
  1217. var $navTopItem = $nav.children('li');
  1218. var prevIndex;
  1219. $navTopItem.filter('.am-parent').each(function(index) {
  1220. $(this).attr('data-rel', '#am-menu-sub-' + index);
  1221. $(this).
  1222. find('.am-menu-sub').
  1223. attr('id', 'am-menu-sub-' + index).
  1224. appendTo($wrap);
  1225. });
  1226. $this.append($wrap);
  1227. $nav.wrap('<div class="am-menu-nav-wrap" id="am-menu-' +
  1228. index + '">');
  1229. // $navTopItem.eq(0).addClass('am-active');
  1230. // 计算出所有 li 宽度
  1231. $navTopItem.each(function(i) {
  1232. allWidth += parseFloat($(this).css('width'));
  1233. });
  1234. $nav.width(allWidth);
  1235. var menuScroll = new IScroll('#am-menu-' + index, {
  1236. eventPassthrough: true,
  1237. scrollX: true,
  1238. scrollY: false,
  1239. preventDefault: false
  1240. });
  1241. $navTopItem.on('click', function() {
  1242. var $clicked = $(this);
  1243. $clicked.addClass('am-active').siblings().removeClass(
  1244. 'am-active');
  1245. $wrap.find('.am-menu-sub.am-in').collapse('close');
  1246. if ($clicked.is('.am-parent')) {
  1247. !$clicked.hasClass('.am-open') &&
  1248. $wrap.find($clicked.attr('data-rel')).collapse(
  1249. 'open');
  1250. } else {
  1251. $clicked.siblings().removeClass('am-open');
  1252. }
  1253. // 第一次调用,没有prevIndex
  1254. if (prevIndex === undefined) {
  1255. prevIndex = $(this).index() ? 0 : 1;
  1256. }
  1257. // 判断方向
  1258. var dir = $(this).index() > prevIndex;
  1259. var target = $(this)[dir ? 'next' : 'prev']();
  1260. // 点击的按钮,显示一半
  1261. var offset = target.offset() || $(this).offset();
  1262. var within = $this.offset();
  1263. // 父类左边距
  1264. var listOffset;
  1265. var parentLeft = parseInt($this.css('padding-left'));
  1266. if (dir ? offset.left + offset.width > within.left +
  1267. within.width :
  1268. offset.left < within.left) {
  1269. listOffset = $nav.offset();
  1270. menuScroll.scrollTo(dir ?
  1271. within.width - offset.left + listOffset.left -
  1272. offset.width - parentLeft :
  1273. listOffset.left - offset.left, 0, 400);
  1274. }
  1275. prevIndex = $(this).index();
  1276. });
  1277. $this.on('touchmove', function(event) {
  1278. event.preventDefault();
  1279. });
  1280. });
  1281. };
  1282. $(function() {
  1283. menuInit();
  1284. });
  1285. module.exports = $.AMUI.menu = {
  1286. VERSION: '4.0.0',
  1287. init: menuInit
  1288. };
  1289. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1290. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1291. }, {
  1292. "./core": 4,
  1293. "./ui.collapse": 26,
  1294. "./ui.iscroll-lite": 31,
  1295. "./ui.offcanvas": 33
  1296. }
  1297. ],
  1298. 17: [
  1299. function(require, module, exports) {
  1300. (function(global) {
  1301. 'use strict';
  1302. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1303. "undefined" ? global.jQuery : null);
  1304. require('./core');
  1305. require('./ui.modal');
  1306. var share = require('./ui.share');
  1307. var QRCode = require('./util.qrcode');
  1308. var UI = $.AMUI;
  1309. function navbarInit() {
  1310. var $navBar = $('[data-am-widget="navbar"]');
  1311. if (!$navBar.length) {
  1312. return;
  1313. }
  1314. var $win = $(window);
  1315. var $body = $('body');
  1316. var $navBarNav = $navBar.find('.am-navbar-nav');
  1317. var $navItems = $navBar.find('li');
  1318. var navItemsCounter = $navItems.length;
  1319. var configItems = $navBarNav.attr('class') &&
  1320. parseInt($navBarNav.attr('class').match(/am-avg-sm-(\d+)/)[1]) ||
  1321. 3;
  1322. var navMinWidth = 60; // 每个 li 最小宽度
  1323. var offsetWidth = 16;
  1324. var $share = $navItems.filter('[data-am-navbar-share]');
  1325. var $qrcode = $navItems.filter('[data-am-navbar-qrcode]');
  1326. var activeStatus = 'am-active';
  1327. var $moreActions = $('<ul class="am-navbar-actions"></ul>', {
  1328. id: UI.utils.generateGUID('am-navbar-actions')
  1329. });
  1330. var $moreLink = $('<li class="am-navbar-labels am-navbar-more">' +
  1331. '<a href="javascript: void(0);">' +
  1332. '<span class="am-icon-angle-up"></span>' +
  1333. '<span class="am-navbar-label">更多</span></a></li>');
  1334. // 如果有 Fix 的工具栏则设置 body 的 padding-bottom
  1335. if ($navBar.css('position') == 'fixed') {
  1336. $body.addClass('am-with-fixed-navbar');
  1337. }
  1338. if ($qrcode.length) {
  1339. var qrId = 'am-navbar-qrcode';
  1340. $qrModal = $('#' + qrId);
  1341. if (!$qrModal.length) {
  1342. var qrImg = $qrcode.attr('data-am-navbar-qrcode');
  1343. var $qrModal = $(
  1344. '<div class="am-modal am-modal-no-btn" id="">' +
  1345. '<div class="am-modal-dialog">' +
  1346. '<div class="am-modal-bd"></div></div>' +
  1347. '</div>', {
  1348. id: qrId
  1349. });
  1350. var $qrContainer = $qrModal.find('.am-modal-bd');
  1351. // 判断上传自定义的二维码没有,否则生成二维码
  1352. if (qrImg) {
  1353. $qrContainer.html('<img src="' + qrImg + '"/>');
  1354. } else {
  1355. var qrnode = new QRCode({
  1356. render: 'canvas',
  1357. correctLevel: 0,
  1358. text: window.location.href,
  1359. width: 200,
  1360. height: 200,
  1361. background: '#fff',
  1362. foreground: '#000'
  1363. });
  1364. $qrContainer.html(qrnode);
  1365. }
  1366. $body.append($qrModal);
  1367. }
  1368. $qrcode.on('click', function(e) {
  1369. e.preventDefault();
  1370. $qrModal.modal();
  1371. });
  1372. }
  1373. if (navItemsCounter > configItems && navItemsCounter >
  1374. calcSuiteItems()) {
  1375. initActions();
  1376. }
  1377. // console.log('NavItems: %d, config: %d, best: %d',
  1378. // navItemsCounter, configItems, calcSuiteItems());
  1379. function initActions() {
  1380. $navBarNav.append($moreLink);
  1381. $navBarNav.
  1382. find('li').
  1383. not('.am-navbar-more').
  1384. slice(calcSuiteItems() - 1).
  1385. appendTo($moreActions);
  1386. // Append more actions
  1387. $navBar.append($moreActions);
  1388. }
  1389. function checkNavBarItems() {
  1390. if (calcSuiteItems() >= navItemsCounter) {
  1391. // 显示所有链接,隐藏 more
  1392. $moreLink.hide();
  1393. $moreActions.find('li').insertBefore($moreLink);
  1394. return;
  1395. }
  1396. !$navBar.find('.am-navbar-actions').length && initActions();
  1397. $moreLink.show();
  1398. if ($navBarNav.find('li').length < calcSuiteItems()) {
  1399. $moreActions.find('li').
  1400. slice(0, calcSuiteItems() - $navBarNav.find('li').length).
  1401. insertBefore($moreLink);
  1402. } else if ($navBarNav.find('li').length > calcSuiteItems()) {
  1403. if ($moreActions.find('li').length) {
  1404. $navBarNav.find('li').not($moreLink).slice(calcSuiteItems() -
  1405. 1).
  1406. insertBefore($moreActions.find('li').first());
  1407. } else {
  1408. $navBarNav.find('li').not($moreLink).slice(calcSuiteItems() -
  1409. 1).
  1410. appendTo($moreActions);
  1411. }
  1412. }
  1413. }
  1414. /**
  1415. * 计算最适合显示的条目个数
  1416. * @returns {number}
  1417. */
  1418. function calcSuiteItems() {
  1419. return Math.floor(($win.width() - offsetWidth) / navMinWidth);
  1420. }
  1421. $navBar.on('click.navbar.amui', '.am-navbar-more', function(e) {
  1422. e.preventDefault();
  1423. $moreLink[$moreActions.hasClass(activeStatus) ?
  1424. 'removeClass' : 'addClass'](activeStatus);
  1425. $moreActions.toggleClass(activeStatus);
  1426. });
  1427. if ($share.length) {
  1428. $share.on('click.navbar.amui', function(e) {
  1429. e.preventDefault();
  1430. share.toggle();
  1431. });
  1432. }
  1433. $win.on('resize.navbar.amui orientationchange.navbar.amui',
  1434. UI.utils.debounce(checkNavBarItems, 150));
  1435. }
  1436. // DOMContent ready
  1437. $(function() {
  1438. navbarInit();
  1439. });
  1440. module.exports = $.AMUI.navbar = {
  1441. VERSION: '2.0.0',
  1442. init: navbarInit
  1443. };
  1444. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1445. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1446. }, {
  1447. "./core": 4,
  1448. "./ui.modal": 32,
  1449. "./ui.share": 41,
  1450. "./util.qrcode": 51
  1451. }
  1452. ],
  1453. 18: [
  1454. function(require, module, exports) {
  1455. (function(global) {
  1456. 'use strict';
  1457. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1458. "undefined" ? global.jQuery : null);
  1459. require('./core');
  1460. module.exports = $.AMUI.pagination = {
  1461. VERSION: '4.0.0'
  1462. };
  1463. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1464. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1465. }, {
  1466. "./core": 4
  1467. }
  1468. ],
  1469. 19: [
  1470. function(require, module, exports) {
  1471. (function(global) {
  1472. 'use strict';
  1473. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1474. "undefined" ? global.jQuery : null);
  1475. require('./core');
  1476. require('./ui.pureview');
  1477. var IScroll = require('./ui.iscroll-lite');
  1478. var UI = $.AMUI;
  1479. /**
  1480. * 表格滚动
  1481. * @param index ID 标识,多个 paragraph 里面多个 table
  1482. */
  1483. $.fn.scrollTable = function(index) {
  1484. var $this = $(this);
  1485. var $parent;
  1486. $this.wrap('<div class="am-paragraph-table-container" ' +
  1487. 'id="am-paragraph-table-' + index + '">' +
  1488. '<div class="am-paragraph-table-scroller"></div></div>');
  1489. $parent = $this.parent();
  1490. $parent.width($this.width());
  1491. $parent.height($this.height());
  1492. new IScroll('#am-paragraph-table-' + index, {
  1493. eventPassthrough: true,
  1494. scrollX: true,
  1495. scrollY: false,
  1496. preventDefault: false
  1497. });
  1498. };
  1499. function paragraphInit() {
  1500. var $paragraph = $('[data-am-widget="paragraph"]');
  1501. $paragraph.each(function(index) {
  1502. var $this = $(this);
  1503. var options = UI.utils.parseOptions($this.attr(
  1504. 'data-am-paragraph'));
  1505. var $index = index;
  1506. if (options.pureview) {
  1507. $this.pureview();
  1508. }
  1509. if (options.tableScrollable) {
  1510. $this.find('table').each(function(index) {
  1511. if ($(this).width() > $(window).width()) {
  1512. $(this).scrollTable($index + '-' + index);
  1513. }
  1514. });
  1515. }
  1516. });
  1517. }
  1518. $(window).on('load', function() {
  1519. paragraphInit();
  1520. });
  1521. module.exports = $.AMUI.paragraph = {
  1522. VERSION: '2.0.0',
  1523. init: paragraphInit
  1524. };
  1525. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1526. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1527. }, {
  1528. "./core": 4,
  1529. "./ui.iscroll-lite": 31,
  1530. "./ui.pureview": 37
  1531. }
  1532. ],
  1533. 20: [
  1534. function(require, module, exports) {
  1535. (function(global) {
  1536. 'use strict';
  1537. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1538. "undefined" ? global.jQuery : null);
  1539. require('./core');
  1540. require('./ui.flexslider');
  1541. var UI = $.AMUI;
  1542. function sliderInit() {
  1543. var $sliders = $('[data-am-widget="slider"]');
  1544. $sliders.not('.am-slider-manual').each(function(i, item) {
  1545. var options = UI.utils.parseOptions($(item).attr(
  1546. 'data-am-slider'));
  1547. $(item).flexslider(options);
  1548. });
  1549. }
  1550. $(document).on('ready', sliderInit);
  1551. module.exports = $.AMUI.slider = {
  1552. VERSION: '3.0.0',
  1553. init: sliderInit
  1554. };
  1555. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1556. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1557. }, {
  1558. "./core": 4,
  1559. "./ui.flexslider": 30
  1560. }
  1561. ],
  1562. 21: [
  1563. function(require, module, exports) {
  1564. (function(global) {
  1565. 'use strict';
  1566. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1567. "undefined" ? global.jQuery : null);
  1568. require('./core');
  1569. require('./ui.tabs');
  1570. function tabsInit() {
  1571. $('[data-am-widget="tabs"]').each(function() {
  1572. var options = $(this).data('amTabsNoswipe') ? {
  1573. noSwipe: 1
  1574. } : {};
  1575. $(this).tabs(options);
  1576. });
  1577. }
  1578. $(function() {
  1579. tabsInit();
  1580. });
  1581. module.exports = $.AMUI.tab = {
  1582. VERSION: '4.0.0',
  1583. init: tabsInit
  1584. };
  1585. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1586. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1587. }, {
  1588. "./core": 4,
  1589. "./ui.tabs": 44
  1590. }
  1591. ],
  1592. 22: [
  1593. function(require, module, exports) {
  1594. (function(global) {
  1595. 'use strict';
  1596. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1597. "undefined" ? global.jQuery : null);
  1598. require('./core');
  1599. module.exports = $.AMUI.titlebar = {
  1600. VERSION: '4.0.0'
  1601. };
  1602. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  1603. "undefined" ? self : typeof window !== "undefined" ? window : {})
  1604. }, {
  1605. "./core": 4
  1606. }
  1607. ],
  1608. 23: [
  1609. function(require, module, exports) {
  1610. (function(global) {
  1611. 'use strict';
  1612. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  1613. "undefined" ? global.jQuery : null);
  1614. require('./core');
  1615. /* jshint -W101, -W106 */
  1616. /* Add to Homescreen v3.0.8 ~ (c) 2014 Matteo Spinelli ~ @license: http://cubiq.org/license */
  1617. // Check if document is loaded, needed by autostart
  1618. var _DOMReady = false;
  1619. if (document.readyState === 'complete') {
  1620. _DOMReady = true;
  1621. } else {
  1622. window.addEventListener('load', loaded, false);
  1623. }
  1624. function loaded() {
  1625. window.removeEventListener('load', loaded, false);
  1626. _DOMReady = true;
  1627. }
  1628. // regex used to detect if app has been added to the homescreen
  1629. var _reSmartURL = /\/ath(\/)?$/;
  1630. var _reQueryString = /([\?&]ath=[^&]*$|&ath=[^&]*(&))/;
  1631. // singleton
  1632. var _instance;
  1633. function ath(options) {
  1634. _instance = _instance || new ath.Class(options);
  1635. return _instance;
  1636. }
  1637. // message in all supported languages
  1638. ath.intl = {
  1639. en_us: {
  1640. message: 'To add this web app to the home screen: tap %icon and then <strong>%action</strong>.',
  1641. action: {
  1642. ios: 'Add to Home Screen',
  1643. android: 'Add to homescreen',
  1644. windows: 'pin to start'
  1645. }
  1646. },
  1647. zh_cn: {
  1648. message: '如要把应用程式加至主屏幕,请点击%icon, 然后<strong>%action</strong>',
  1649. action: {
  1650. ios: '加至主屏幕',
  1651. android: '加至主屏幕',
  1652. windows: '按住启动'
  1653. }
  1654. },
  1655. zh_tw: {
  1656. message: '如要把應用程式加至主屏幕, 請點擊%icon, 然後<strong>%action</strong>.',
  1657. action: {
  1658. ios: '加至主屏幕',
  1659. android: '加至主屏幕',
  1660. windows: '按住啟動'
  1661. }
  1662. }
  1663. };
  1664. // Add 2 characters language support (Android mostly)
  1665. for (var lang in ath.intl) {
  1666. ath.intl[lang.substr(0, 2)] = ath.intl[lang];
  1667. }
  1668. // default options
  1669. ath.defaults = {
  1670. appID: 'org.cubiq.addtohome', // local storage name (no need to change)
  1671. fontSize: 15, // base font size, used to properly resize the popup based on viewport scale factor
  1672. debug: false, // override browser checks
  1673. modal: false, // prevent further actions until the message is closed
  1674. mandatory: false, // you can't proceed if you don't add the app to the homescreen
  1675. autostart: true, // show the message automatically
  1676. skipFirstVisit: false, // show only to returning visitors (ie: skip the first time you visit)
  1677. startDelay: 1, // display the message after that many seconds from page load
  1678. lifespan: 15, // life of the message in seconds
  1679. displayPace: 1440, // minutes before the message is shown again (0: display every time, default 24 hours)
  1680. maxDisplayCount: 0, // absolute maximum number of times the message will be shown to the user (0: no limit)
  1681. icon: true, // add touch icon to the message
  1682. message: '', // the message can be customized
  1683. validLocation: [], // list of pages where the message will be shown (array of regexes)
  1684. onInit: null, // executed on instance creation
  1685. onShow: null, // executed when the message is shown
  1686. onRemove: null, // executed when the message is removed
  1687. onAdd: null, // when the application is launched the first time from the homescreen (guesstimate)
  1688. onPrivate: null, // executed if user is in private mode
  1689. detectHomescreen: false // try to detect if the site has been added to the homescreen (false | true | 'hash' | 'queryString' | 'smartURL')
  1690. };
  1691. // browser info and capability
  1692. var _ua = window.navigator.userAgent;
  1693. var _nav = window.navigator;
  1694. _extend(ath, {
  1695. hasToken: document.location.hash == '#ath' || _reSmartURL.test(
  1696. document.location.href) || _reQueryString.test(document.location
  1697. .search),
  1698. isRetina: window.devicePixelRatio && window.devicePixelRatio >
  1699. 1,
  1700. isIDevice: (/iphone|ipod|ipad/i).test(_ua),
  1701. isMobileChrome: _ua.indexOf('Android') > -1 && (
  1702. /Chrome\/[.0-9]*/).test(_ua),
  1703. isMobileIE: _ua.indexOf('Windows Phone') > -1,
  1704. language: _nav.language && _nav.language.toLowerCase().replace(
  1705. '-', '_') || ''
  1706. });
  1707. // falls back to en_us if language is unsupported
  1708. ath.language = ath.language && ath.language in ath.intl ? ath.language :
  1709. 'en_us';
  1710. ath.isMobileSafari = ath.isIDevice && _ua.indexOf('Safari') > -1 &&
  1711. _ua.indexOf('CriOS') < 0;
  1712. ath.OS = ath.isIDevice ? 'ios' : ath.isMobileChrome ? 'android' :
  1713. ath.isMobileIE ? 'windows' : 'unsupported';
  1714. ath.OSVersion = _ua.match(/(OS|Android) (\d+[_\.]\d+)/);
  1715. ath.OSVersion = ath.OSVersion && ath.OSVersion[2] ? +ath.OSVersion[
  1716. 2].replace('_', '.') : 0;
  1717. ath.isStandalone = window.navigator.standalone || (ath.isMobileChrome &&
  1718. (screen.height - document.documentElement.clientHeight < 40)); // TODO: check the lame polyfill
  1719. ath.isTablet = (ath.isMobileSafari && _ua.indexOf('iPad') > -1) ||
  1720. (ath.isMobileChrome && _ua.indexOf('Mobile') < 0);
  1721. ath.isCompatible = (ath.isMobileSafari && ath.OSVersion >= 6) ||
  1722. ath.isMobileChrome; // TODO: add winphone
  1723. var _defaultSession = {
  1724. lastDisplayTime: 0, // last time we displayed the message
  1725. returningVisitor: false, // is this the first time you visit
  1726. displayCount: 0, // number of times the message has been shown
  1727. optedout: false, // has the user opted out
  1728. added: false // has been actually added to the homescreen
  1729. };
  1730. ath.removeSession = function(appID) {
  1731. try {
  1732. localStorage.removeItem(appID || ath.defaults.appID);
  1733. } catch (e) {
  1734. // we are most likely in private mode
  1735. }
  1736. };
  1737. ath.Class = function(options) {
  1738. // merge default options with user config
  1739. this.options = _extend({}, ath.defaults);
  1740. _extend(this.options, options);
  1741. // normalize some options
  1742. this.options.mandatory = this.options.mandatory && ('standalone' in
  1743. window.navigator || this.options.debug);
  1744. this.options.modal = this.options.modal || this.options.mandatory;
  1745. if (this.options.mandatory) {
  1746. this.options.startDelay = -0.5; // make the popup hasty
  1747. }
  1748. this.options.detectHomescreen = this.options.detectHomescreen ===
  1749. true ? 'hash' : this.options.detectHomescreen;
  1750. // setup the debug environment
  1751. if (this.options.debug) {
  1752. ath.isCompatible = true;
  1753. ath.OS = typeof this.options.debug == 'string' ? this.options.debug :
  1754. ath.OS == 'unsupported' ? 'android' : ath.OS;
  1755. ath.OSVersion = ath.OS == 'ios' ? '8' : '4';
  1756. }
  1757. // the element the message will be appended to
  1758. this.container = document.documentElement;
  1759. // load session
  1760. this.session = localStorage.getItem(this.options.appID);
  1761. this.session = this.session ? JSON.parse(this.session) :
  1762. undefined;
  1763. // user most likely came from a direct link containing our token, we don't need it and we remove it
  1764. if (ath.hasToken && (!ath.isCompatible || !this.session)) {
  1765. ath.hasToken = false;
  1766. _removeToken();
  1767. }
  1768. // the device is not supported
  1769. if (!ath.isCompatible) {
  1770. return;
  1771. }
  1772. this.session = this.session || _defaultSession;
  1773. // check if we can use the local storage
  1774. try {
  1775. localStorage.setItem(this.options.appID, JSON.stringify(this.session));
  1776. ath.hasLocalStorage = true;
  1777. } catch (e) {
  1778. // we are most likely in private mode
  1779. ath.hasLocalStorage = false;
  1780. if (this.options.onPrivate) {
  1781. this.options.onPrivate.call(this);
  1782. }
  1783. }
  1784. // check if this is a valid location
  1785. var isValidLocation = !this.options.validLocation.length;
  1786. for (var i = this.options.validLocation.length; i--;) {
  1787. if (this.options.validLocation[i].test(document.location.href)) {
  1788. isValidLocation = true;
  1789. break;
  1790. }
  1791. }
  1792. // check compatibility with old versions of add to homescreen. Opt-out if an old session is found
  1793. if (localStorage.getItem('addToHome')) {
  1794. this.optOut();
  1795. }
  1796. // critical errors:
  1797. // user opted out, already added to the homescreen, not a valid location
  1798. if (this.session.optedout || this.session.added || !
  1799. isValidLocation) {
  1800. return;
  1801. }
  1802. // check if the app is in stand alone mode
  1803. if (ath.isStandalone) {
  1804. // execute the onAdd event if we haven't already
  1805. if (!this.session.added) {
  1806. this.session.added = true;
  1807. this.updateSession();
  1808. if (this.options.onAdd && ath.hasLocalStorage) { // double check on localstorage to avoid multiple calls to the custom event
  1809. this.options.onAdd.call(this);
  1810. }
  1811. }
  1812. return;
  1813. }
  1814. // (try to) check if the page has been added to the homescreen
  1815. if (this.options.detectHomescreen) {
  1816. // the URL has the token, we are likely coming from the homescreen
  1817. if (ath.hasToken) {
  1818. _removeToken(); // we don't actually need the token anymore, we remove it to prevent redistribution
  1819. // this is called the first time the user opens the app from the homescreen
  1820. if (!this.session.added) {
  1821. this.session.added = true;
  1822. this.updateSession();
  1823. if (this.options.onAdd && ath.hasLocalStorage) { // double check on localstorage to avoid multiple calls to the custom event
  1824. this.options.onAdd.call(this);
  1825. }
  1826. }
  1827. return;
  1828. }
  1829. // URL doesn't have the token, so add it
  1830. if (this.options.detectHomescreen == 'hash') {
  1831. history.replaceState('', window.document.title, document.location
  1832. .href + '#ath');
  1833. } else if (this.options.detectHomescreen == 'smartURL') {
  1834. history.replaceState('', window.document.title, document.location
  1835. .href.replace(/(\/)?$/, '/ath$1'));
  1836. } else {
  1837. history.replaceState('', window.document.title, document.location
  1838. .href + (document.location.search ? '&' : '?') + 'ath=');
  1839. }
  1840. }
  1841. // check if this is a returning visitor
  1842. if (!this.session.returningVisitor) {
  1843. this.session.returningVisitor = true;
  1844. this.updateSession();
  1845. // we do not show the message if this is your first visit
  1846. if (this.options.skipFirstVisit) {
  1847. return;
  1848. }
  1849. }
  1850. // we do no show the message in private mode
  1851. if (!ath.hasLocalStorage) {
  1852. return;
  1853. }
  1854. // all checks passed, ready to display
  1855. this.ready = true;
  1856. if (this.options.onInit) {
  1857. this.options.onInit.call(this);
  1858. }
  1859. if (this.options.autostart) {
  1860. this.show();
  1861. }
  1862. };
  1863. ath.Class.prototype = {
  1864. // event type to method conversion
  1865. events: {
  1866. load: '_delayedShow',
  1867. error: '_delayedShow',
  1868. orientationchange: 'resize',
  1869. resize: 'resize',
  1870. scroll: 'resize',
  1871. click: 'remove',
  1872. touchmove: '_preventDefault',
  1873. transitionend: '_removeElements',
  1874. webkitTransitionEnd: '_removeElements',
  1875. MSTransitionEnd: '_removeElements'
  1876. },
  1877. handleEvent: function(e) {
  1878. var type = this.events[e.type];
  1879. if (type) {
  1880. this[type](e);
  1881. }
  1882. },
  1883. show: function(force) {
  1884. // in autostart mode wait for the document to be ready
  1885. if (this.options.autostart && !_DOMReady) {
  1886. setTimeout(this.show.bind(this), 50);
  1887. return;
  1888. }
  1889. // message already on screen
  1890. if (this.shown) {
  1891. return;
  1892. }
  1893. var now = Date.now();
  1894. var lastDisplayTime = this.session.lastDisplayTime;
  1895. if (force !== true) {
  1896. // this is needed if autostart is disabled and you programmatically call the show() method
  1897. if (!this.ready) {
  1898. return;
  1899. }
  1900. // we obey the display pace (prevent the message to popup too often)
  1901. if (now - lastDisplayTime < this.options.displayPace * 60000) {
  1902. return;
  1903. }
  1904. // obey the maximum number of display count
  1905. if (this.options.maxDisplayCount && this.session.displayCount >=
  1906. this.options.maxDisplayCount) {
  1907. return;
  1908. }
  1909. }
  1910. this.shown = true;
  1911. // increment the display count
  1912. this.session.lastDisplayTime = now;
  1913. this.session.displayCount++;
  1914. this.updateSession();
  1915. // try to get the highest resolution application icon
  1916. if (!this.applicationIcon) {
  1917. if (ath.OS == 'ios') {
  1918. this.applicationIcon = document.querySelector(
  1919. 'head link[rel^=apple-touch-icon][sizes="152x152"],head link[rel^=apple-touch-icon][sizes="144x144"],head link[rel^=apple-touch-icon][sizes="120x120"],head link[rel^=apple-touch-icon][sizes="114x114"],head link[rel^=apple-touch-icon]'
  1920. );
  1921. } else {
  1922. this.applicationIcon = document.querySelector(
  1923. 'head link[rel^="shortcut icon"][sizes="196x196"],head link[rel^=apple-touch-icon]'
  1924. );
  1925. }
  1926. }
  1927. var message = '';
  1928. if (this.options.message in ath.intl) { // you can force the locale
  1929. message = ath.intl[this.options.message].message.replace(
  1930. '%action', ath.intl[this.options.message].action[ath.OS]);
  1931. } else if (this.options.message !== '') { // or use a custom message
  1932. message = this.options.message;
  1933. } else { // otherwise we use our message
  1934. message = ath.intl[ath.language].message.replace('%action',
  1935. ath.intl[ath.language].action[ath.OS]);
  1936. }
  1937. // add the action icon
  1938. message = '<p>' + message.replace('%icon',
  1939. '<span class="ath-action-icon">icon</span>') + '</p>';
  1940. // create the message container
  1941. this.viewport = document.createElement('div');
  1942. this.viewport.className = 'ath-viewport';
  1943. if (this.options.modal) {
  1944. this.viewport.className += ' ath-modal';
  1945. }
  1946. if (this.options.mandatory) {
  1947. this.viewport.className += ' ath-mandatory';
  1948. }
  1949. this.viewport.style.position = 'absolute';
  1950. // create the actual message element
  1951. this.element = document.createElement('div');
  1952. this.element.className = 'ath-container ath-' + ath.OS +
  1953. ' ath-' + ath.OS + (ath.OSVersion + '').substr(0, 1) +
  1954. ' ath-' + (ath.isTablet ? 'tablet' : 'phone');
  1955. this.element.style.cssText =
  1956. '-webkit-transition-property:-webkit-transform,opacity;-webkit-transition-duration:0;-webkit-transform:translate3d(0,0,0);transition-property:transform,opacity;transition-duration:0;transform:translate3d(0,0,0);-webkit-transition-timing-function:ease-out';
  1957. this.element.style.webkitTransform = 'translate3d(0,-' + window
  1958. .innerHeight + 'px,0)';
  1959. this.element.style.webkitTransitionDuration = '0s';
  1960. // add the application icon
  1961. if (this.options.icon && this.applicationIcon) {
  1962. this.element.className += ' ath-icon';
  1963. this.img = document.createElement('img');
  1964. this.img.className = 'ath-application-icon';
  1965. this.img.addEventListener('load', this, false);
  1966. this.img.addEventListener('error', this, false);
  1967. this.img.src = this.applicationIcon.href;
  1968. this.element.appendChild(this.img);
  1969. }
  1970. this.element.innerHTML += message;
  1971. // we are not ready to show, place the message out of sight
  1972. this.viewport.style.left = '-99999em';
  1973. // attach all elements to the DOM
  1974. this.viewport.appendChild(this.element);
  1975. this.container.appendChild(this.viewport);
  1976. // if we don't have to wait for an image to load, show the message right away
  1977. if (!this.img) {
  1978. this._delayedShow();
  1979. }
  1980. },
  1981. _delayedShow: function(e) {
  1982. setTimeout(this._show.bind(this), this.options.startDelay *
  1983. 1000 + 500);
  1984. },
  1985. _show: function() {
  1986. var that = this;
  1987. // update the viewport size and orientation
  1988. this.updateViewport();
  1989. // reposition/resize the message on orientation change
  1990. window.addEventListener('resize', this, false);
  1991. window.addEventListener('scroll', this, false);
  1992. window.addEventListener('orientationchange', this, false);
  1993. if (this.options.modal) {
  1994. // lock any other interaction
  1995. document.addEventListener('touchmove', this, true);
  1996. }
  1997. // Enable closing after 1 second
  1998. if (!this.options.mandatory) {
  1999. setTimeout(function() {
  2000. that.element.addEventListener('click', that, true);
  2001. }, 1000);
  2002. }
  2003. // kick the animation
  2004. setTimeout(function() {
  2005. that.element.style.webkitTransform = 'translate3d(0,0,0)';
  2006. that.element.style.webkitTransitionDuration = '1.2s';
  2007. }, 0);
  2008. // set the destroy timer
  2009. if (this.options.lifespan) {
  2010. this.removeTimer = setTimeout(this.remove.bind(this), this.options
  2011. .lifespan * 1000);
  2012. }
  2013. // fire the custom onShow event
  2014. if (this.options.onShow) {
  2015. this.options.onShow.call(this);
  2016. }
  2017. },
  2018. remove: function() {
  2019. clearTimeout(this.removeTimer);
  2020. // clear up the event listeners
  2021. if (this.img) {
  2022. this.img.removeEventListener('load', this, false);
  2023. this.img.removeEventListener('error', this, false);
  2024. }
  2025. window.removeEventListener('resize', this, false);
  2026. window.removeEventListener('scroll', this, false);
  2027. window.removeEventListener('orientationchange', this, false);
  2028. document.removeEventListener('touchmove', this, true);
  2029. this.element.removeEventListener('click', this, true);
  2030. // remove the message element on transition end
  2031. this.element.addEventListener('transitionend', this, false);
  2032. this.element.addEventListener('webkitTransitionEnd', this,
  2033. false);
  2034. this.element.addEventListener('MSTransitionEnd', this, false);
  2035. // start the fade out animation
  2036. this.element.style.webkitTransitionDuration = '0.3s';
  2037. this.element.style.opacity = '0';
  2038. },
  2039. _removeElements: function() {
  2040. this.element.removeEventListener('transitionend', this, false);
  2041. this.element.removeEventListener('webkitTransitionEnd', this,
  2042. false);
  2043. this.element.removeEventListener('MSTransitionEnd', this, false);
  2044. // remove the message from the DOM
  2045. this.container.removeChild(this.viewport);
  2046. this.shown = false;
  2047. // fire the custom onRemove event
  2048. if (this.options.onRemove) {
  2049. this.options.onRemove.call(this);
  2050. }
  2051. },
  2052. updateViewport: function() {
  2053. if (!this.shown) {
  2054. return;
  2055. }
  2056. this.viewport.style.width = window.innerWidth + 'px';
  2057. this.viewport.style.height = window.innerHeight + 'px';
  2058. this.viewport.style.left = window.scrollX + 'px';
  2059. this.viewport.style.top = window.scrollY + 'px';
  2060. var clientWidth = document.documentElement.clientWidth;
  2061. this.orientation = clientWidth > document.documentElement.clientHeight ?
  2062. 'landscape' : 'portrait';
  2063. var screenWidth = ath.OS == 'ios' ? this.orientation ==
  2064. 'portrait' ? screen.width : screen.height : screen.width;
  2065. this.scale = screen.width > clientWidth ? 1 : screenWidth /
  2066. window.innerWidth;
  2067. this.element.style.fontSize = this.options.fontSize / this.scale +
  2068. 'px';
  2069. },
  2070. resize: function() {
  2071. clearTimeout(this.resizeTimer);
  2072. this.resizeTimer = setTimeout(this.updateViewport.bind(this),
  2073. 100);
  2074. },
  2075. updateSession: function() {
  2076. if (ath.hasLocalStorage === false) {
  2077. return;
  2078. }
  2079. localStorage.setItem(this.options.appID, JSON.stringify(this.session));
  2080. },
  2081. clearSession: function() {
  2082. this.session = _defaultSession;
  2083. this.updateSession();
  2084. },
  2085. optOut: function() {
  2086. this.session.optedout = true;
  2087. this.updateSession();
  2088. },
  2089. optIn: function() {
  2090. this.session.optedout = false;
  2091. this.updateSession();
  2092. },
  2093. clearDisplayCount: function() {
  2094. this.session.displayCount = 0;
  2095. this.updateSession();
  2096. },
  2097. _preventDefault: function(e) {
  2098. e.preventDefault();
  2099. e.stopPropagation();
  2100. }
  2101. };
  2102. // utility
  2103. function _extend(target, obj) {
  2104. for (var i in obj) {
  2105. target[i] = obj[i];
  2106. }
  2107. return target;
  2108. }
  2109. function _removeToken() {
  2110. if (document.location.hash == '#ath') {
  2111. history.replaceState('', window.document.title, document.location
  2112. .href.split('#')[0]);
  2113. }
  2114. if (_reSmartURL.test(document.location.href)) {
  2115. history.replaceState('', window.document.title, document.location
  2116. .href.replace(_reSmartURL, '$1'));
  2117. }
  2118. if (_reQueryString.test(document.location.search)) {
  2119. history.replaceState('', window.document.title, document.location
  2120. .href.replace(_reQueryString, '$2'));
  2121. }
  2122. }
  2123. /* jshint +W101, +W106 */
  2124. $.AMUI.addToHomescreen = ath;
  2125. module.exports = ath;
  2126. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  2127. "undefined" ? self : typeof window !== "undefined" ? window : {})
  2128. }, {
  2129. "./core": 4
  2130. }
  2131. ],
  2132. 24: [
  2133. function(require, module, exports) {
  2134. (function(global) {
  2135. 'use strict';
  2136. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  2137. "undefined" ? global.jQuery : null);
  2138. var UI = require('./core');
  2139. /**
  2140. * @via https://github.com/Minwe/bootstrap/blob/master/js/alert.js
  2141. * @copyright Copyright 2013 Twitter, Inc.
  2142. * @license Apache 2.0
  2143. */
  2144. // Alert Class
  2145. // NOTE: removeElement option is unavailable now
  2146. var Alert = function(element, options) {
  2147. this.options = $.extend({}, Alert.DEFAULTS, options);
  2148. this.$element = $(element);
  2149. this.$element.
  2150. addClass('am-fade am-in').
  2151. on('click.alert.amui', '.am-close', $.proxy(this.close, this));
  2152. };
  2153. Alert.DEFAULTS = {
  2154. removeElement: true
  2155. };
  2156. Alert.prototype.close = function() {
  2157. var $this = $(this);
  2158. var $target = $this.hasClass('am-alert') ?
  2159. $this :
  2160. $this.parent('.am-alert');
  2161. $target.trigger('close.alert.amui');
  2162. $target.removeClass('am-in');
  2163. function processAlert() {
  2164. $target.trigger('closed.alert.amui').remove();
  2165. }
  2166. UI.support.transition && $target.hasClass('am-fade') ?
  2167. $target.
  2168. one(UI.support.transition.end, processAlert).
  2169. emulateTransitionEnd(200) : processAlert();
  2170. };
  2171. // Alert Plugin
  2172. $.fn.alert = function(option) {
  2173. return this.each(function() {
  2174. var $this = $(this);
  2175. var data = $this.data('amui.alert');
  2176. var options = typeof option == 'object' && option;
  2177. if (!data) {
  2178. $this.data('amui.alert', (data = new Alert(this, options || {})));
  2179. }
  2180. if (typeof option == 'string') {
  2181. data[option].call($this);
  2182. }
  2183. });
  2184. };
  2185. // Init code
  2186. $(document).on('click.alert.amui.data-api', '[data-am-alert]',
  2187. function(e) {
  2188. var $target = $(e.target);
  2189. $(this).addClass('am-fade am-in');
  2190. $target.is('.am-close') && $(this).alert('close');
  2191. });
  2192. $.AMUI.alert = Alert;
  2193. module.exports = Alert;
  2194. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  2195. "undefined" ? self : typeof window !== "undefined" ? window : {})
  2196. }, {
  2197. "./core": 4
  2198. }
  2199. ],
  2200. 25: [
  2201. function(require, module, exports) {
  2202. (function(global) {
  2203. 'use strict';
  2204. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  2205. "undefined" ? global.jQuery : null);
  2206. var UI = require('./core');
  2207. /**
  2208. * @via https://github.com/twbs/bootstrap/blob/master/js/button.js
  2209. * @copyright (c) 2011-2014 Twitter, Inc
  2210. * @license The MIT License
  2211. */
  2212. var Button = function(element, options) {
  2213. this.$element = $(element);
  2214. this.options = $.extend({}, Button.DEFAULTS, options);
  2215. this.isLoading = false;
  2216. this.hasSpinner = false;
  2217. };
  2218. Button.DEFAULTS = {
  2219. loadingText: 'loading...',
  2220. className: {
  2221. loading: 'am-btn-loading',
  2222. disabled: 'am-disabled'
  2223. },
  2224. spinner: undefined
  2225. };
  2226. Button.prototype.setState = function(state) {
  2227. var disabled = 'disabled';
  2228. var $element = this.$element;
  2229. var options = this.options;
  2230. var val = $element.is('input') ? 'val' : 'html';
  2231. var loadingClassName = options.className.disabled + ' ' +
  2232. options.className.loading;
  2233. state = state + 'Text';
  2234. if (!options.resetText) {
  2235. options.resetText = $element[val]();
  2236. }
  2237. // add spinner for element with html()
  2238. if (UI.support.animation && options.spinner &&
  2239. val === 'html' && !this.hasSpinner) {
  2240. options.loadingText = '<span class="am-icon-' +
  2241. options.spinner +
  2242. ' am-icon-spin"></span>' + options.loadingText;
  2243. this.hasSpinner = true;
  2244. }
  2245. $element[val](options[state]);
  2246. // push to event loop to allow forms to submit
  2247. setTimeout($.proxy(function() {
  2248. if (state == 'loadingText') {
  2249. $element.addClass(loadingClassName).attr(disabled,
  2250. disabled);
  2251. this.isLoading = true;
  2252. } else if (this.isLoading) {
  2253. $element.removeClass(loadingClassName).removeAttr(
  2254. disabled);
  2255. this.isLoading = false;
  2256. }
  2257. }, this), 0);
  2258. };
  2259. Button.prototype.toggle = function() {
  2260. var changed = true;
  2261. var $element = this.$element;
  2262. var $parent = this.$element.parent('.am-btn-group');
  2263. if ($parent.length) {
  2264. var $input = this.$element.find('input');
  2265. if ($input.prop('type') == 'radio') {
  2266. if ($input.prop('checked') && $element.hasClass('am-active')) {
  2267. changed = false;
  2268. } else {
  2269. $parent.find('.am-active').removeClass('am-active');
  2270. }
  2271. }
  2272. if (changed) {
  2273. $input.prop('checked', !$element.hasClass('am-active')).trigger(
  2274. 'change');
  2275. }
  2276. }
  2277. if (changed) {
  2278. $element.toggleClass('am-active');
  2279. if (!$element.hasClass('am-active')) {
  2280. $element.blur();
  2281. }
  2282. }
  2283. };
  2284. // Button plugin
  2285. function Plugin(option) {
  2286. return this.each(function() {
  2287. var $this = $(this);
  2288. var data = $this.data('amui.button');
  2289. var options = typeof option == 'object' && option || {};
  2290. if (!data) {
  2291. $this.data('amui.button', (data = new Button(this,
  2292. options)));
  2293. }
  2294. if (option == 'toggle') {
  2295. data.toggle();
  2296. } else if (typeof option == 'string') {
  2297. data.setState(option);
  2298. }
  2299. });
  2300. }
  2301. $.fn.button = Plugin;
  2302. // Init code
  2303. $(document).on('click.button.amui.data-api', '[data-am-button]',
  2304. function(e) {
  2305. var $btn = $(e.target);
  2306. if (!$btn.hasClass('am-btn')) {
  2307. $btn = $btn.closest('.am-btn');
  2308. }
  2309. Plugin.call($btn, 'toggle');
  2310. e.preventDefault();
  2311. });
  2312. UI.ready(function(context) {
  2313. $('[data-am-loading]', context).each(function() {
  2314. $(this).button(UI.utils.parseOptions($(this).data(
  2315. 'amLoading')));
  2316. });
  2317. });
  2318. $.AMUI.button = Button;
  2319. module.exports = Button;
  2320. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  2321. "undefined" ? self : typeof window !== "undefined" ? window : {})
  2322. }, {
  2323. "./core": 4
  2324. }
  2325. ],
  2326. 26: [
  2327. function(require, module, exports) {
  2328. (function(global) {
  2329. 'use strict';
  2330. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  2331. "undefined" ? global.jQuery : null);
  2332. var UI = require('./core');
  2333. /**
  2334. * @via https://github.com/twbs/bootstrap/blob/master/js/collapse.js
  2335. * @copyright (c) 2011-2014 Twitter, Inc
  2336. * @license The MIT License
  2337. */
  2338. var Collapse = function(element, options) {
  2339. this.$element = $(element);
  2340. this.options = $.extend({}, Collapse.DEFAULTS, options);
  2341. this.transitioning = null;
  2342. if (this.options.parent) {
  2343. this.$parent = $(this.options.parent);
  2344. }
  2345. if (this.options.toggle) {
  2346. this.toggle();
  2347. }
  2348. };
  2349. Collapse.DEFAULTS = {
  2350. toggle: true
  2351. };
  2352. Collapse.prototype.open = function() {
  2353. if (this.transitioning || this.$element.hasClass('am-in')) {
  2354. return;
  2355. }
  2356. var startEvent = $.Event('open.collapse.amui');
  2357. this.$element.trigger(startEvent);
  2358. if (startEvent.isDefaultPrevented()) {
  2359. return;
  2360. }
  2361. var actives = this.$parent && this.$parent.find(
  2362. '> .am-panel > .am-in');
  2363. if (actives && actives.length) {
  2364. var hasData = actives.data('amui.collapse');
  2365. if (hasData && hasData.transitioning) {
  2366. return;
  2367. }
  2368. Plugin.call(actives, 'close');
  2369. hasData || actives.data('amui.collapse', null);
  2370. }
  2371. this.$element
  2372. .removeClass('am-collapse')
  2373. .addClass('am-collapsing').height(0);
  2374. this.transitioning = 1;
  2375. var complete = function() {
  2376. this.$element.
  2377. removeClass('am-collapsing').
  2378. addClass('am-collapse am-in').
  2379. height('');
  2380. this.transitioning = 0;
  2381. this.$element.trigger('opened.collapse.amui');
  2382. };
  2383. if (!UI.support.transition) {
  2384. return complete.call(this);
  2385. }
  2386. var scrollHeight = this.$element[0].scrollHeight;
  2387. this.$element
  2388. .one(UI.support.transition.end, $.proxy(complete, this))
  2389. .emulateTransitionEnd(300).
  2390. css({
  2391. height: scrollHeight
  2392. }); // 当折叠的容器有 padding 时,如果用 height() 只能设置内容的宽度
  2393. };
  2394. Collapse.prototype.close = function() {
  2395. if (this.transitioning || !this.$element.hasClass('am-in')) {
  2396. return;
  2397. }
  2398. var startEvent = $.Event('close.collapse.amui');
  2399. this.$element.trigger(startEvent);
  2400. if (startEvent.isDefaultPrevented()) {
  2401. return;
  2402. }
  2403. this.$element.height(this.$element.height()).redraw();
  2404. this.$element.addClass('am-collapsing').
  2405. removeClass('am-collapse am-in');
  2406. this.transitioning = 1;
  2407. var complete = function() {
  2408. this.transitioning = 0;
  2409. this.$element.trigger('closed.collapse.amui').
  2410. removeClass('am-collapsing').
  2411. addClass('am-collapse');
  2412. // css({height: '0'});
  2413. };
  2414. if (!UI.support.transition) {
  2415. return complete.call(this);
  2416. }
  2417. this.$element.height(0)
  2418. .one(UI.support.transition.end, $.proxy(complete, this))
  2419. .emulateTransitionEnd(300);
  2420. };
  2421. Collapse.prototype.toggle = function() {
  2422. this[this.$element.hasClass('am-in') ? 'close' : 'open']();
  2423. };
  2424. // Collapse Plugin
  2425. function Plugin(option) {
  2426. return this.each(function() {
  2427. var $this = $(this);
  2428. var data = $this.data('amui.collapse');
  2429. var options = $.extend({}, Collapse.DEFAULTS,
  2430. UI.utils.options($this.attr('data-am-collapse')),
  2431. typeof option == 'object' && option);
  2432. if (!data && options.toggle && option == 'open') {
  2433. option = !option;
  2434. }
  2435. if (!data) {
  2436. $this.data('amui.collapse', (data = new Collapse(this,
  2437. options)));
  2438. }
  2439. if (typeof option == 'string') {
  2440. data[option]();
  2441. }
  2442. });
  2443. }
  2444. $.fn.collapse = Plugin;
  2445. // Init code
  2446. $(document).on('click.collapse.amui.data-api', '[data-am-collapse]',
  2447. function(e) {
  2448. var href;
  2449. var $this = $(this);
  2450. var options = UI.utils.options($this.attr('data-am-collapse'));
  2451. var target = options.target ||
  2452. e.preventDefault() ||
  2453. (href = $this.attr('href')) &&
  2454. href.replace(/.*(?=#[^\s]+$)/, '');
  2455. var $target = $(target);
  2456. var data = $target.data('amui.collapse');
  2457. var option = data ? 'toggle' : options;
  2458. var parent = options.parent;
  2459. var $parent = parent && $(parent);
  2460. if (!data || !data.transitioning) {
  2461. if ($parent) {
  2462. // '[data-am-collapse*="{parent: \'' + parent + '"]
  2463. $parent.find('[data-am-collapse]').not($this).addClass(
  2464. 'am-collapsed');
  2465. }
  2466. $this[$target.hasClass('am-in') ? 'addClass' :
  2467. 'removeClass']('am-collapsed');
  2468. }
  2469. Plugin.call($target, option);
  2470. });
  2471. $.AMUI.collapse = Collapse;
  2472. module.exports = Collapse;
  2473. // TODO: 更好的 target 选择方式
  2474. // 折叠的容器必须没有 border/padding 才能正常处理,否则动画会有一些小问题
  2475. // 寻找更好的未知高度 transition 动画解决方案,max-height 之类的就算了
  2476. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  2477. "undefined" ? self : typeof window !== "undefined" ? window : {})
  2478. }, {
  2479. "./core": 4
  2480. }
  2481. ],
  2482. 27: [
  2483. function(require, module, exports) {
  2484. (function(global) {
  2485. 'use strict';
  2486. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  2487. "undefined" ? global.jQuery : null);
  2488. var UI = require('./core');
  2489. var $doc = $(document);
  2490. /**
  2491. * bootstrap-datepicker.js
  2492. * @via http://www.eyecon.ro/bootstrap-datepicker
  2493. * @license http://www.apache.org/licenses/LICENSE-2.0
  2494. */
  2495. var Datepicker = function(element, options) {
  2496. this.$element = $(element);
  2497. this.options = $.extend({}, Datepicker.DEFAULTS, options);
  2498. this.format = DPGlobal.parseFormat(this.options.format);
  2499. this.$element.data('date', this.options.date);
  2500. this.language = this.getLocale(this.options.locale);
  2501. this.theme = this.options.theme;
  2502. this.$picker = $(DPGlobal.template).appendTo('body').on({
  2503. click: $.proxy(this.click, this)
  2504. // mousedown: $.proxy(this.mousedown, this)
  2505. });
  2506. this.isInput = this.$element.is('input');
  2507. this.component = this.$element.is('.am-datepicker-date') ?
  2508. this.$element.find('.am-datepicker-add-on') : false;
  2509. if (this.isInput) {
  2510. this.$element.on({
  2511. 'click.datepicker.amui': $.proxy(this.open, this),
  2512. // blur: $.proxy(this.close, this),
  2513. 'keyup.datepicker.amui': $.proxy(this.update, this)
  2514. });
  2515. } else {
  2516. if (this.component) {
  2517. this.component.on('click.datepicker.amui', $.proxy(this.open,
  2518. this));
  2519. } else {
  2520. this.$element.on('click.datepicker.amui', $.proxy(this.open,
  2521. this));
  2522. }
  2523. }
  2524. this.minViewMode = this.options.minViewMode;
  2525. if (typeof this.minViewMode === 'string') {
  2526. switch (this.minViewMode) {
  2527. case 'months':
  2528. this.minViewMode = 1;
  2529. break;
  2530. case 'years':
  2531. this.minViewMode = 2;
  2532. break;
  2533. default:
  2534. this.minViewMode = 0;
  2535. break;
  2536. }
  2537. }
  2538. this.viewMode = this.options.viewMode;
  2539. if (typeof this.viewMode === 'string') {
  2540. switch (this.viewMode) {
  2541. case 'months':
  2542. this.viewMode = 1;
  2543. break;
  2544. case 'years':
  2545. this.viewMode = 2;
  2546. break;
  2547. default:
  2548. this.viewMode = 0;
  2549. break;
  2550. }
  2551. }
  2552. this.startViewMode = this.viewMode;
  2553. this.weekStart = ((this.options.weekStart ||
  2554. Datepicker.locales[this.language].weekStart || 0) % 7);
  2555. this.weekEnd = ((this.weekStart + 6) % 7);
  2556. this.onRender = this.options.onRender;
  2557. this.setTheme();
  2558. this.fillDow();
  2559. this.fillMonths();
  2560. this.update();
  2561. this.showMode();
  2562. };
  2563. Datepicker.DEFAULTS = {
  2564. locale: 'zh_CN',
  2565. format: 'yyyy-mm-dd',
  2566. weekStart: undefined,
  2567. viewMode: 0,
  2568. minViewMode: 0,
  2569. date: '',
  2570. theme: '',
  2571. autoClose: 1,
  2572. onRender: function(date) {
  2573. return '';
  2574. }
  2575. };
  2576. Datepicker.prototype.open = function(e) {
  2577. this.$picker.show();
  2578. this.height = this.component ?
  2579. this.component.outerHeight() : this.$element.outerHeight();
  2580. this.place();
  2581. $(window).on('resize.datepicker.amui', $.proxy(this.place, this));
  2582. if (e) {
  2583. e.stopPropagation();
  2584. e.preventDefault();
  2585. }
  2586. var that = this;
  2587. $(document).on('click.datepicker.amui', function(ev) {
  2588. if ($(ev.target).closest('.am-datepicker').length === 0) {
  2589. that.close();
  2590. }
  2591. });
  2592. this.$element.trigger({
  2593. type: 'open.datepicker.amui',
  2594. date: this.date
  2595. });
  2596. };
  2597. Datepicker.prototype.close = function() {
  2598. this.$picker.hide();
  2599. $(window).off('resize.datepicker.amui', this.place);
  2600. this.viewMode = this.startViewMode;
  2601. this.showMode();
  2602. if (!this.isInput) {
  2603. $(document).off('click.datepicker.amui', this.close);
  2604. }
  2605. // this.set();
  2606. this.$element.trigger({
  2607. type: 'close.datepicker.amui',
  2608. date: this.date
  2609. });
  2610. };
  2611. Datepicker.prototype.set = function() {
  2612. var formated = DPGlobal.formatDate(this.date, this.format);
  2613. if (!this.isInput) {
  2614. if (this.component) {
  2615. this.$element.find('input').prop('value', formated);
  2616. }
  2617. this.$element.data('date', formated);
  2618. } else {
  2619. this.$element.prop('value', formated);
  2620. }
  2621. };
  2622. Datepicker.prototype.setValue = function(newDate) {
  2623. if (typeof newDate === 'string') {
  2624. this.date = DPGlobal.parseDate(newDate, this.format);
  2625. } else {
  2626. this.date = new Date(newDate);
  2627. }
  2628. this.set();
  2629. this.viewDate = new Date(this.date.getFullYear(),
  2630. this.date.getMonth(), 1, 0, 0, 0, 0);
  2631. this.fill();
  2632. };
  2633. Datepicker.prototype.place = function() {
  2634. var offset = this.component ?
  2635. this.component.offset() : this.$element.offset();
  2636. var $width = this.component ?
  2637. this.component.width() : this.$element.width();
  2638. var top = offset.top + this.height;
  2639. var left = offset.left;
  2640. var right = $doc.width() - offset.left - $width;
  2641. var isOutView = this.isOutView();
  2642. this.$picker.removeClass('am-datepicker-right');
  2643. this.$picker.removeClass('am-datepicker-up');
  2644. if ($doc.width() > 640) {
  2645. if (isOutView.outRight) {
  2646. this.$picker.addClass('am-datepicker-right');
  2647. this.$picker.css({
  2648. top: top,
  2649. left: 'auto',
  2650. right: right
  2651. });
  2652. return;
  2653. }
  2654. if (isOutView.outBottom) {
  2655. this.$picker.addClass('am-datepicker-up');
  2656. top = offset.top - this.$picker.outerHeight(true);
  2657. }
  2658. } else {
  2659. left = 0;
  2660. }
  2661. this.$picker.css({
  2662. top: top,
  2663. left: left
  2664. });
  2665. };
  2666. Datepicker.prototype.update = function(newDate) {
  2667. this.date = DPGlobal.parseDate(
  2668. typeof newDate === 'string' ? newDate : (this.isInput ?
  2669. this.$element.prop('value') : this.$element.data('date')),
  2670. this.format
  2671. );
  2672. this.viewDate = new Date(this.date.getFullYear(),
  2673. this.date.getMonth(), 1, 0, 0, 0, 0);
  2674. this.fill();
  2675. };
  2676. // Days of week
  2677. Datepicker.prototype.fillDow = function() {
  2678. var dowCount = this.weekStart;
  2679. var html = '<tr>';
  2680. while (dowCount < this.weekStart + 7) {
  2681. // NOTE: do % then add 1
  2682. html += '<th class="am-datepicker-dow">' +
  2683. Datepicker.locales[this.language].daysMin[(dowCount++) % 7] +
  2684. '</th>';
  2685. }
  2686. html += '</tr>';
  2687. this.$picker.find('.am-datepicker-days thead').append(html);
  2688. };
  2689. Datepicker.prototype.fillMonths = function() {
  2690. var html = '';
  2691. var i = 0;
  2692. while (i < 12) {
  2693. html += '<span class="am-datepicker-month">' +
  2694. Datepicker.locales[this.language].monthsShort[i++] +
  2695. '</span>';
  2696. }
  2697. this.$picker.find('.am-datepicker-months td').append(html);
  2698. };
  2699. Datepicker.prototype.fill = function() {
  2700. var d = new Date(this.viewDate);
  2701. var year = d.getFullYear();
  2702. var month = d.getMonth();
  2703. var currentDate = this.date.valueOf();
  2704. var prevMonth = new Date(year, month - 1, 28, 0, 0, 0, 0);
  2705. var day = DPGlobal
  2706. .getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
  2707. var daysSelect = this.$picker
  2708. .find('.am-datepicker-days .am-datepicker-select');
  2709. if (this.language === 'zh_CN') {
  2710. daysSelect.text(year + Datepicker.locales[this.language].year[0] +
  2711. ' ' + Datepicker.locales[this.language].months[month]);
  2712. } else {
  2713. daysSelect.text(Datepicker.locales[this.language].months[month] +
  2714. ' ' + year);
  2715. }
  2716. prevMonth.setDate(day);
  2717. prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7) %
  2718. 7);
  2719. var nextMonth = new Date(prevMonth);
  2720. nextMonth.setDate(nextMonth.getDate() + 42);
  2721. nextMonth = nextMonth.valueOf();
  2722. var html = [];
  2723. var className;
  2724. var prevY;
  2725. var prevM;
  2726. while (prevMonth.valueOf() < nextMonth) {
  2727. if (prevMonth.getDay() === this.weekStart) {
  2728. html.push('<tr>');
  2729. }
  2730. className = this.onRender(prevMonth);
  2731. prevY = prevMonth.getFullYear();
  2732. prevM = prevMonth.getMonth();
  2733. if ((prevM < month && prevY === year) || prevY < year) {
  2734. className += ' am-datepicker-old';
  2735. } else if ((prevM > month && prevY === year) || prevY > year) {
  2736. className += ' am-datepicker-new';
  2737. }
  2738. if (prevMonth.valueOf() === currentDate) {
  2739. className += ' am-active';
  2740. }
  2741. html.push('<td class="am-datepicker-day ' +
  2742. className + '">' + prevMonth.getDate() + '</td>');
  2743. if (prevMonth.getDay() === this.weekEnd) {
  2744. html.push('</tr>');
  2745. }
  2746. prevMonth.setDate(prevMonth.getDate() + 1);
  2747. }
  2748. this.$picker.find('.am-datepicker-days tbody')
  2749. .empty().append(html.join(''));
  2750. var currentYear = this.date.getFullYear();
  2751. var months = this.$picker.find('.am-datepicker-months')
  2752. .find('.am-datepicker-select')
  2753. .text(year);
  2754. months = months.end()
  2755. .find('span').removeClass('am-active');
  2756. if (currentYear === year) {
  2757. months.eq(this.date.getMonth()).addClass('am-active');
  2758. }
  2759. html = '';
  2760. year = parseInt(year / 10, 10) * 10;
  2761. var yearCont = this.$picker
  2762. .find('.am-datepicker-years')
  2763. .find('.am-datepicker-select')
  2764. .text(year + '-' + (year + 9))
  2765. .end()
  2766. .find('td');
  2767. year -= 1;
  2768. for (var i = -1; i < 11; i++) {
  2769. html += '<span class="' +
  2770. (i === -1 || i === 10 ? ' am-datepicker-old' : '') +
  2771. (currentYear === year ? ' am-active' : '') + '">' + year +
  2772. '</span>';
  2773. year += 1;
  2774. }
  2775. yearCont.html(html);
  2776. };
  2777. Datepicker.prototype.click = function(event) {
  2778. event.stopPropagation();
  2779. event.preventDefault();
  2780. var month;
  2781. var year;
  2782. var $target = $(event.target).closest('span, td, th');
  2783. if ($target.length === 1) {
  2784. switch ($target[0].nodeName.toLowerCase()) {
  2785. case 'th':
  2786. switch ($target[0].className) {
  2787. case 'am-datepicker-switch':
  2788. this.showMode(1);
  2789. break;
  2790. case 'am-datepicker-prev':
  2791. case 'am-datepicker-next':
  2792. this.viewDate['set' + DPGlobal.modes[this.viewMode].navFnc]
  2793. .call(
  2794. this.viewDate,
  2795. this.viewDate['get' + DPGlobal.modes[this.viewMode]
  2796. .navFnc]
  2797. .call(this.viewDate) +
  2798. DPGlobal.modes[this.viewMode].navStep *
  2799. ($target[0].className === 'am-datepicker-prev' ? -1 :
  2800. 1)
  2801. );
  2802. this.fill();
  2803. this.set();
  2804. break;
  2805. }
  2806. break;
  2807. case 'span':
  2808. if ($target.is('.am-datepicker-month')) {
  2809. month = $target.parent().find('span').index($target);
  2810. this.viewDate.setMonth(month);
  2811. } else {
  2812. year = parseInt($target.text(), 10) || 0;
  2813. this.viewDate.setFullYear(year);
  2814. }
  2815. if (this.viewMode !== 0) {
  2816. this.date = new Date(this.viewDate);
  2817. this.$element.trigger({
  2818. type: 'changeDate.datepicker.amui',
  2819. date: this.date,
  2820. viewMode: DPGlobal.modes[this.viewMode].clsName
  2821. });
  2822. }
  2823. this.showMode(-1);
  2824. this.fill();
  2825. this.set();
  2826. break;
  2827. case 'td':
  2828. if ($target.is('.am-datepicker-day') && !$target.is(
  2829. '.am-disabled')) {
  2830. var day = parseInt($target.text(), 10) || 1;
  2831. month = this.viewDate.getMonth();
  2832. if ($target.is('.am-datepicker-old')) {
  2833. month -= 1;
  2834. } else if ($target.is('.am-datepicker-new')) {
  2835. month += 1;
  2836. }
  2837. year = this.viewDate.getFullYear();
  2838. this.date = new Date(year, month, day, 0, 0, 0, 0);
  2839. this.viewDate = new Date(year, month, Math.min(28, day),
  2840. 0, 0, 0, 0);
  2841. this.fill();
  2842. this.set();
  2843. this.$element.trigger({
  2844. type: 'changeDate.datepicker.amui',
  2845. date: this.date,
  2846. viewMode: DPGlobal.modes[this.viewMode].clsName
  2847. });
  2848. this.options.autoClose && this.close();
  2849. }
  2850. break;
  2851. }
  2852. }
  2853. };
  2854. Datepicker.prototype.mousedown = function(event) {
  2855. event.stopPropagation();
  2856. event.preventDefault();
  2857. };
  2858. Datepicker.prototype.showMode = function(dir) {
  2859. if (dir) {
  2860. this.viewMode = Math.max(this.minViewMode,
  2861. Math.min(2, this.viewMode + dir));
  2862. }
  2863. this.$picker.find('>div').hide().
  2864. filter('.am-datepicker-' + DPGlobal.modes[this.viewMode].clsName)
  2865. .show();
  2866. };
  2867. Datepicker.prototype.isOutView = function() {
  2868. var offset = this.component ?
  2869. this.component.offset() : this.$element.offset();
  2870. var isOutView = {
  2871. outRight: false,
  2872. outBottom: false
  2873. };
  2874. var $picker = this.$picker;
  2875. var width = offset.left + $picker.outerWidth(true);
  2876. var height = offset.top + $picker.outerHeight(true) +
  2877. this.$element.innerHeight();
  2878. if (width > $doc.width()) {
  2879. isOutView.outRight = true;
  2880. }
  2881. if (height > $doc.height()) {
  2882. isOutView.outBottom = true;
  2883. }
  2884. return isOutView;
  2885. };
  2886. Datepicker.prototype.getLocale = function(locale) {
  2887. if (!locale) {
  2888. locale = navigator.language && navigator.language.split('-');
  2889. locale[1] = locale[1].toUpperCase();
  2890. locale = locale.join('_');
  2891. }
  2892. if (!Datepicker.locales[locale]) {
  2893. locale = 'en_US';
  2894. }
  2895. return locale;
  2896. };
  2897. Datepicker.prototype.setTheme = function() {
  2898. if (this.theme) {
  2899. this.$picker.addClass('am-datepicker-' + this.theme);
  2900. }
  2901. };
  2902. // Datepicker locales
  2903. Datepicker.locales = {
  2904. en_US: {
  2905. days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
  2906. 'Friday', 'Saturday'
  2907. ],
  2908. daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  2909. daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
  2910. months: ['January', 'February', 'March', 'April', 'May', 'June',
  2911. 'July', 'August', 'September', 'October', 'November',
  2912. 'December'
  2913. ],
  2914. monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  2915. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
  2916. ],
  2917. weekStart: 0
  2918. },
  2919. zh_CN: {
  2920. days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
  2921. daysShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
  2922. daysMin: ['日', '一', '二', '三', '四', '五', '六'],
  2923. months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月',
  2924. '八月', '九月', '十月', '十一月', '十二月'
  2925. ],
  2926. monthsShort: ['一月', '二月', '三月', '四月', '五月', '六月',
  2927. '七月', '八月', '九月', '十月', '十一月', '十二月'
  2928. ],
  2929. weekStart: 1,
  2930. year: ['年']
  2931. }
  2932. };
  2933. var DPGlobal = {
  2934. modes: [{
  2935. clsName: 'days',
  2936. navFnc: 'Month',
  2937. navStep: 1
  2938. }, {
  2939. clsName: 'months',
  2940. navFnc: 'FullYear',
  2941. navStep: 1
  2942. }, {
  2943. clsName: 'years',
  2944. navFnc: 'FullYear',
  2945. navStep: 10
  2946. }],
  2947. isLeapYear: function(year) {
  2948. return (((year % 4 === 0) && (year % 100 !== 0)) || (year %
  2949. 400 === 0));
  2950. },
  2951. getDaysInMonth: function(year, month) {
  2952. return [31, (DPGlobal.isLeapYear(year) ? 29 : 28),
  2953. 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  2954. ][month];
  2955. },
  2956. parseFormat: function(format) {
  2957. var separator = format.match(/[.\/\-\s].*?/);
  2958. var parts = format.split(/\W+/);
  2959. if (!separator || !parts || parts.length === 0) {
  2960. throw new Error('Invalid date format.');
  2961. }
  2962. return {
  2963. separator: separator,
  2964. parts: parts
  2965. };
  2966. },
  2967. parseDate: function(date, format) {
  2968. var parts = date.split(format.separator);
  2969. var val;
  2970. date = new Date();
  2971. date.setHours(0);
  2972. date.setMinutes(0);
  2973. date.setSeconds(0);
  2974. date.setMilliseconds(0);
  2975. if (parts.length === format.parts.length) {
  2976. var year = date.getFullYear();
  2977. var day = date.getDate();
  2978. var month = date.getMonth();
  2979. for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
  2980. val = parseInt(parts[i], 10) || 1;
  2981. switch (format.parts[i]) {
  2982. case 'dd':
  2983. case 'd':
  2984. day = val;
  2985. date.setDate(val);
  2986. break;
  2987. case 'mm':
  2988. case 'm':
  2989. month = val - 1;
  2990. date.setMonth(val - 1);
  2991. break;
  2992. case 'yy':
  2993. year = 2000 + val;
  2994. date.setFullYear(2000 + val);
  2995. break;
  2996. case 'yyyy':
  2997. year = val;
  2998. date.setFullYear(val);
  2999. break;
  3000. }
  3001. }
  3002. date = new Date(year, month, day, 0, 0, 0);
  3003. }
  3004. return date;
  3005. },
  3006. formatDate: function(date, format) {
  3007. var val = {
  3008. d: date.getDate(),
  3009. m: date.getMonth() + 1,
  3010. yy: date.getFullYear().toString().substring(2),
  3011. yyyy: date.getFullYear()
  3012. };
  3013. var dateArray = [];
  3014. val.dd = (val.d < 10 ? '0' : '') + val.d;
  3015. val.mm = (val.m < 10 ? '0' : '') + val.m;
  3016. for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
  3017. dateArray.push(val[format.parts[i]]);
  3018. }
  3019. return dateArray.join(format.separator);
  3020. },
  3021. headTemplate: '<thead>' +
  3022. '<tr class="am-datepicker-header">' +
  3023. '<th class="am-datepicker-prev">' +
  3024. '<i class="am-datepicker-prev-icon"></i></th>' +
  3025. '<th colspan="5" class="am-datepicker-switch">' +
  3026. '<div class="am-datepicker-select"></div></th>' +
  3027. '<th class="am-datepicker-next"><i class="am-datepicker-next-icon"></i>' +
  3028. '</th></tr></thead>',
  3029. contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
  3030. };
  3031. DPGlobal.template =
  3032. '<div class="am-datepicker am-datepicker-dropdown">' +
  3033. '<div class="am-datepicker-caret"></div>' +
  3034. '<div class="am-datepicker-days">' +
  3035. '<table class="am-datepicker-table">' +
  3036. DPGlobal.headTemplate +
  3037. '<tbody></tbody>' +
  3038. '</table>' +
  3039. '</div>' +
  3040. '<div class="am-datepicker-months">' +
  3041. '<table class="am-datepicker-table">' +
  3042. DPGlobal.headTemplate +
  3043. DPGlobal.contTemplate +
  3044. '</table>' +
  3045. '</div>' +
  3046. '<div class="am-datepicker-years">' +
  3047. '<table class="am-datepicker-table">' +
  3048. DPGlobal.headTemplate +
  3049. DPGlobal.contTemplate +
  3050. '</table>' +
  3051. '</div>' +
  3052. '</div>';
  3053. $.fn.datepicker = function(option, val) {
  3054. return this.each(function() {
  3055. var $this = $(this);
  3056. var data = $this.data('amui.datepicker');
  3057. var options = $.extend({},
  3058. UI.utils.options($this.data('amDatepicker')),
  3059. typeof option === 'object' && option);
  3060. if (!data) {
  3061. $this.data('amui.datepicker', (data = new Datepicker(this,
  3062. options)));
  3063. }
  3064. if (typeof option === 'string') {
  3065. data[option] && data[option](val);
  3066. }
  3067. });
  3068. };
  3069. $.fn.datepicker.Constructor = Datepicker;
  3070. // Init code
  3071. $(document).on('ready', function(e) {
  3072. $('[data-am-datepicker]').datepicker();
  3073. });
  3074. $.AMUI.datepicker = Datepicker;
  3075. module.exports = Datepicker;
  3076. // TODO: 1. 载入动画
  3077. // 2. less 优化
  3078. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  3079. "undefined" ? self : typeof window !== "undefined" ? window : {})
  3080. }, {
  3081. "./core": 4
  3082. }
  3083. ],
  3084. 28: [
  3085. function(require, module, exports) {
  3086. (function(global) {
  3087. 'use strict';
  3088. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  3089. "undefined" ? global.jQuery : null);
  3090. var UI = require('./core');
  3091. var $doc = $(document);
  3092. var transition = UI.support.transition;
  3093. var Dimmer = function() {
  3094. this.id = UI.utils.generateGUID('am-dimmer');
  3095. this.$element = $(Dimmer.DEFAULTS.tpl, {
  3096. id: this.id
  3097. });
  3098. this.inited = false;
  3099. this.scrollbarWidth = 0;
  3100. this.$used = $([]);
  3101. };
  3102. Dimmer.DEFAULTS = {
  3103. tpl: '<div class="am-dimmer" data-am-dimmer></div>'
  3104. };
  3105. Dimmer.prototype.init = function() {
  3106. if (!this.inited) {
  3107. $(document.body).append(this.$element);
  3108. this.inited = true;
  3109. $doc.trigger('init.dimmer.amui');
  3110. }
  3111. return this;
  3112. };
  3113. Dimmer.prototype.open = function(relatedElement) {
  3114. if (!this.inited) {
  3115. this.init();
  3116. }
  3117. var $element = this.$element;
  3118. // 用于多重调用
  3119. if (relatedElement) {
  3120. this.$used = this.$used.add($(relatedElement));
  3121. }
  3122. this.checkScrollbar().setScrollbar();
  3123. $element.off(transition.end).show().trigger('open.dimmer.amui');
  3124. setTimeout(function() {
  3125. $element.addClass('am-active');
  3126. }, 0);
  3127. return this;
  3128. };
  3129. Dimmer.prototype.close = function(relatedElement, force) {
  3130. this.$used = this.$used.not($(relatedElement));
  3131. if (!force && this.$used.length) {
  3132. return this;
  3133. }
  3134. var $element = this.$element;
  3135. $element.removeClass('am-active').trigger('close.dimmer.amui');
  3136. function complete() {
  3137. $element.hide();
  3138. this.resetScrollbar();
  3139. }
  3140. // transition ? $element.one(transition.end, $.proxy(complete, this)) :
  3141. complete.call(this);
  3142. return this;
  3143. };
  3144. Dimmer.prototype.checkScrollbar = function() {
  3145. this.scrollbarWidth = UI.utils.measureScrollbar();
  3146. return this;
  3147. };
  3148. Dimmer.prototype.setScrollbar = function() {
  3149. var $body = $(document.body);
  3150. var bodyPaddingRight = parseInt(($body.css('padding-right') || 0),
  3151. 10);
  3152. if (this.scrollbarWidth) {
  3153. $body.css('padding-right', bodyPaddingRight + this.scrollbarWidth);
  3154. }
  3155. $body.addClass('am-dimmer-active');
  3156. return this;
  3157. };
  3158. Dimmer.prototype.resetScrollbar = function() {
  3159. $(document.body).css('padding-right', '').removeClass(
  3160. 'am-dimmer-active');
  3161. return this;
  3162. };
  3163. var dimmer = new Dimmer();
  3164. $.AMUI.dimmer = dimmer;
  3165. module.exports = dimmer;
  3166. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  3167. "undefined" ? self : typeof window !== "undefined" ? window : {})
  3168. }, {
  3169. "./core": 4
  3170. }
  3171. ],
  3172. 29: [
  3173. function(require, module, exports) {
  3174. (function(global) {
  3175. 'use strict';
  3176. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  3177. "undefined" ? global.jQuery : null);
  3178. var UI = require('./core');
  3179. var animation = UI.support.animation;
  3180. /**
  3181. * @via https://github.com/Minwe/bootstrap/blob/master/js/dropdown.js
  3182. * @copyright (c) 2011-2014 Twitter, Inc
  3183. * @license The MIT License
  3184. */
  3185. // var toggle = '[data-am-dropdown] > .am-dropdown-toggle';
  3186. var Dropdown = function(element, options) {
  3187. this.options = $.extend({}, Dropdown.DEFAULTS, options);
  3188. options = this.options;
  3189. this.$element = $(element);
  3190. this.$toggle = this.$element.find(options.selector.toggle);
  3191. this.$dropdown = this.$element.find(options.selector.dropdown);
  3192. this.$boundary = (options.boundary === window) ? $(window) :
  3193. this.$element.closest(options.boundary);
  3194. this.$justify = (options.justify && $(options.justify).length &&
  3195. $(options.justify)) || undefined;
  3196. !this.$boundary.length && (this.$boundary = $(window));
  3197. this.active = this.$element.hasClass('am-active') ? true :
  3198. false;
  3199. this.animating = null;
  3200. this.events();
  3201. };
  3202. Dropdown.DEFAULTS = {
  3203. animation: 'am-animation-slide-top-fixed',
  3204. boundary: window,
  3205. justify: undefined,
  3206. selector: {
  3207. dropdown: '.am-dropdown-content',
  3208. toggle: '.am-dropdown-toggle'
  3209. },
  3210. trigger: 'click'
  3211. };
  3212. Dropdown.prototype.toggle = function() {
  3213. this.clear();
  3214. if (this.animating) {
  3215. return;
  3216. }
  3217. this[this.active ? 'close' : 'open']();
  3218. };
  3219. Dropdown.prototype.open = function(e) {
  3220. var $toggle = this.$toggle;
  3221. var $element = this.$element;
  3222. var $dropdown = this.$dropdown;
  3223. if ($toggle.is('.am-disabled, :disabled')) {
  3224. return;
  3225. }
  3226. if (this.active) {
  3227. return;
  3228. }
  3229. $element.trigger('open.dropdown.amui').addClass('am-active');
  3230. $toggle.trigger('focus');
  3231. this.checkDimensions();
  3232. var complete = $.proxy(function() {
  3233. $element.trigger('opened.dropdown.amui');
  3234. this.active = true;
  3235. this.animating = 0;
  3236. }, this);
  3237. if (animation) {
  3238. this.animating = 1;
  3239. $dropdown.addClass(this.options.animation).
  3240. on(animation.end + '.open.dropdown.amui', $.proxy(function() {
  3241. complete();
  3242. $dropdown.removeClass(this.options.animation);
  3243. }, this));
  3244. } else {
  3245. complete();
  3246. }
  3247. };
  3248. Dropdown.prototype.close = function() {
  3249. if (!this.active) {
  3250. return;
  3251. }
  3252. // fix #165
  3253. // var animationName = this.options.animation + ' am-animation-reverse';
  3254. var animationName = 'am-dropdown-animation';
  3255. var $element = this.$element;
  3256. var $dropdown = this.$dropdown;
  3257. $element.trigger('close.dropdown.amui');
  3258. var complete = $.proxy(function complete() {
  3259. $element.
  3260. removeClass('am-active').
  3261. trigger('closed.dropdown.amui');
  3262. this.active = false;
  3263. this.animating = 0;
  3264. this.$toggle.blur();
  3265. }, this);
  3266. if (animation) {
  3267. $dropdown.removeClass(this.options.animation);
  3268. $dropdown.addClass(animationName);
  3269. this.animating = 1;
  3270. // animation
  3271. $dropdown.one(animation.end + '.close.dropdown.amui', function() {
  3272. $dropdown.removeClass(animationName);
  3273. complete();
  3274. });
  3275. } else {
  3276. complete();
  3277. }
  3278. };
  3279. Dropdown.prototype.checkDimensions = function() {
  3280. if (!this.$dropdown.length) {
  3281. return;
  3282. }
  3283. var $dropdown = this.$dropdown;
  3284. var offset = $dropdown.offset();
  3285. var width = $dropdown.outerWidth();
  3286. var boundaryWidth = this.$boundary.width();
  3287. var boundaryOffset = $.isWindow(this.boundary) && this.$boundary.offset() ?
  3288. this.$boundary.offset().left : 0;
  3289. if (this.$justify) {
  3290. // jQuery.fn.width() is really...
  3291. $dropdown.css({
  3292. 'min-width': this.$justify.css('width')
  3293. });
  3294. }
  3295. if ((width + (offset.left - boundaryOffset)) > boundaryWidth) {
  3296. this.$element.addClass('am-dropdown-flip');
  3297. }
  3298. };
  3299. Dropdown.prototype.clear = function() {
  3300. $('[data-am-dropdown]').not(this.$element).each(function() {
  3301. var data = $(this).data('amui.dropdown');
  3302. data && data.close();
  3303. });
  3304. };
  3305. Dropdown.prototype.events = function() {
  3306. var eventNS = 'dropdown.amui';
  3307. // triggers = this.options.trigger.split(' '),
  3308. var $toggle = this.$toggle;
  3309. $toggle.on('click.' + eventNS, $.proxy(function(e) {
  3310. e.preventDefault();
  3311. this.toggle();
  3312. }, this));
  3313. /*for (var i = triggers.length; i--;) {
  3314. var trigger = triggers[i];
  3315. if (trigger === 'click') {
  3316. $toggle.on('click.' + eventNS, $.proxy(this.toggle, this))
  3317. }
  3318. if (trigger === 'focus' || trigger === 'hover') {
  3319. var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
  3320. var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
  3321. this.$element.on(eventIn + '.' + eventNS, $.proxy(this.open, this))
  3322. .on(eventOut + '.' + eventNS, $.proxy(this.close, this));
  3323. }
  3324. }*/
  3325. $(document).on('keydown.dropdown.amui', $.proxy(function(e) {
  3326. e.keyCode === 27 && this.active && this.close();
  3327. }, this)).on('click.outer.dropdown.amui', $.proxy(function(e) {
  3328. // var $target = $(e.target);
  3329. if (this.active &&
  3330. (this.$element[0] === e.target || !this.$element.find(e.target)
  3331. .length)) {
  3332. this.close();
  3333. }
  3334. }, this));
  3335. };
  3336. // Dropdown Plugin
  3337. function Plugin(option) {
  3338. return this.each(function() {
  3339. var $this = $(this);
  3340. var data = $this.data('amui.dropdown');
  3341. var options = $.extend({},
  3342. UI.utils.parseOptions($this.attr('data-am-dropdown')),
  3343. typeof option == 'object' && option);
  3344. if (!data) {
  3345. $this.data('amui.dropdown', (data = new Dropdown(this,
  3346. options)));
  3347. }
  3348. if (typeof option == 'string') {
  3349. data[option]();
  3350. }
  3351. });
  3352. }
  3353. $.fn.dropdown = Plugin;
  3354. // Init code
  3355. UI.ready(function(context) {
  3356. $('[data-am-dropdown]', context).dropdown();
  3357. });
  3358. $(document).on('click.dropdown.amui.data-api', '.am-dropdown form',
  3359. function(e) {
  3360. e.stopPropagation();
  3361. });
  3362. $.AMUI.dropdown = Dropdown;
  3363. module.exports = Dropdown;
  3364. // TODO: 1. 处理链接 focus
  3365. // 2. 增加 mouseenter / mouseleave 选项
  3366. // 3. 宽度适应
  3367. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  3368. "undefined" ? self : typeof window !== "undefined" ? window : {})
  3369. }, {
  3370. "./core": 4
  3371. }
  3372. ],
  3373. 30: [
  3374. function(require, module, exports) {
  3375. (function(global) {
  3376. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  3377. "undefined" ? global.jQuery : null);
  3378. var UI = require('./core');
  3379. // MODIFIED:
  3380. // - LINE 226: add `<i></i>`
  3381. // - namespace
  3382. // - Init code
  3383. // TODO: start after x ms when pause on actions
  3384. /*
  3385. * jQuery FlexSlider v2.2.2
  3386. * Copyright 2012 WooThemes
  3387. * Contributing Author: Tyler Smith
  3388. */
  3389. // FlexSlider: Object Instance
  3390. $.flexslider = function(el, options) {
  3391. var slider = $(el);
  3392. // making variables public
  3393. slider.vars = $.extend({}, $.flexslider.defaults, options);
  3394. var namespace = slider.vars.namespace,
  3395. msGesture = window.navigator && window.navigator.msPointerEnabled &&
  3396. window.MSGesture,
  3397. touch = (("ontouchstart" in window) || msGesture || window.DocumentTouch &&
  3398. document instanceof DocumentTouch) && slider.vars.touch,
  3399. // depricating this idea, as devices are being released with both of these events
  3400. //eventType = (touch) ? "touchend" : "click",
  3401. eventType = "click touchend MSPointerUp keyup",
  3402. watchedEvent = "",
  3403. watchedEventClearTimer,
  3404. vertical = slider.vars.direction === "vertical",
  3405. reverse = slider.vars.reverse,
  3406. carousel = (slider.vars.itemWidth > 0),
  3407. fade = slider.vars.animation === "fade",
  3408. asNav = slider.vars.asNavFor !== "",
  3409. methods = {},
  3410. focused = true;
  3411. // Store a reference to the slider object
  3412. $.data(el, 'flexslider', slider);
  3413. // Private slider methods
  3414. methods = {
  3415. init: function() {
  3416. slider.animating = false;
  3417. // Get current slide and make sure it is a number
  3418. slider.currentSlide = parseInt((slider.vars.startAt ? slider.vars
  3419. .startAt : 0), 10);
  3420. if (isNaN(slider.currentSlide)) {
  3421. slider.currentSlide = 0;
  3422. }
  3423. slider.animatingTo = slider.currentSlide;
  3424. slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide ===
  3425. slider.last);
  3426. slider.containerSelector = slider.vars.selector.substr(0,
  3427. slider.vars.selector.search(' '));
  3428. slider.slides = $(slider.vars.selector, slider);
  3429. slider.container = $(slider.containerSelector, slider);
  3430. slider.count = slider.slides.length;
  3431. // SYNC:
  3432. slider.syncExists = $(slider.vars.sync).length > 0;
  3433. // SLIDE:
  3434. if (slider.vars.animation === "slide") slider.vars.animation =
  3435. "swing";
  3436. slider.prop = (vertical) ? "top" : "marginLeft";
  3437. slider.args = {};
  3438. // SLIDESHOW:
  3439. slider.manualPause = false;
  3440. slider.stopped = false;
  3441. //PAUSE WHEN INVISIBLE
  3442. slider.started = false;
  3443. slider.startTimeout = null;
  3444. // TOUCH/USECSS:
  3445. slider.transitions = !slider.vars.video && !fade && slider.vars
  3446. .useCSS && (function() {
  3447. var obj = document.createElement('div'),
  3448. props = ['perspectiveProperty', 'WebkitPerspective',
  3449. 'MozPerspective', 'OPerspective', 'msPerspective'
  3450. ];
  3451. for (var i in props) {
  3452. if (obj.style[props[i]] !== undefined) {
  3453. slider.pfx = props[i].replace('Perspective', '').toLowerCase();
  3454. slider.prop = "-" + slider.pfx + "-transform";
  3455. return true;
  3456. }
  3457. }
  3458. return false;
  3459. }());
  3460. slider.ensureAnimationEnd = '';
  3461. // CONTROLSCONTAINER:
  3462. if (slider.vars.controlsContainer !== "") slider.controlsContainer =
  3463. $(slider.vars.controlsContainer).length > 0 && $(slider.vars
  3464. .controlsContainer);
  3465. // MANUAL:
  3466. if (slider.vars.manualControls !== "") slider.manualControls =
  3467. $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls);
  3468. // RANDOMIZE:
  3469. if (slider.vars.randomize) {
  3470. slider.slides.sort(function() {
  3471. return (Math.round(Math.random()) - 0.5);
  3472. });
  3473. slider.container.empty().append(slider.slides);
  3474. }
  3475. slider.doMath();
  3476. // INIT
  3477. slider.setup("init");
  3478. // CONTROLNAV:
  3479. if (slider.vars.controlNav) methods.controlNav.setup();
  3480. // DIRECTIONNAV:
  3481. if (slider.vars.directionNav) methods.directionNav.setup();
  3482. // KEYBOARD:
  3483. if (slider.vars.keyboard && ($(slider.containerSelector).length ===
  3484. 1 || slider.vars.multipleKeyboard)) {
  3485. $(document).bind('keyup', function(event) {
  3486. var keycode = event.keyCode;
  3487. if (!slider.animating && (keycode === 39 || keycode ===
  3488. 37)) {
  3489. var target = (keycode === 39) ? slider.getTarget(
  3490. 'next') :
  3491. (keycode === 37) ? slider.getTarget('prev') : false;
  3492. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3493. }
  3494. });
  3495. }
  3496. // MOUSEWHEEL:
  3497. if (slider.vars.mousewheel) {
  3498. slider.bind('mousewheel', function(event, delta, deltaX,
  3499. deltaY) {
  3500. event.preventDefault();
  3501. var target = (delta < 0) ? slider.getTarget('next') :
  3502. slider.getTarget('prev');
  3503. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3504. });
  3505. }
  3506. // PAUSEPLAY
  3507. if (slider.vars.pausePlay) methods.pausePlay.setup();
  3508. //PAUSE WHEN INVISIBLE
  3509. if (slider.vars.slideshow && slider.vars.pauseInvisible)
  3510. methods.pauseInvisible.init();
  3511. // SLIDSESHOW
  3512. if (slider.vars.slideshow) {
  3513. if (slider.vars.pauseOnHover) {
  3514. slider.hover(function() {
  3515. if (!slider.manualPlay && !slider.manualPause) slider
  3516. .pause();
  3517. }, function() {
  3518. if (!slider.manualPause && !slider.manualPlay && !
  3519. slider.stopped) slider.play();
  3520. });
  3521. }
  3522. // initialize animation
  3523. //If we're visible, or we don't use PageVisibility API
  3524. if (!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) {
  3525. (slider.vars.initDelay > 0) ? slider.startTimeout =
  3526. setTimeout(slider.play, slider.vars.initDelay) : slider
  3527. .play();
  3528. }
  3529. }
  3530. // ASNAV:
  3531. if (asNav) methods.asNav.setup();
  3532. // TOUCH
  3533. if (touch && slider.vars.touch) methods.touch();
  3534. // FADE&&SMOOTHHEIGHT || SLIDE:
  3535. if (!fade || (fade && slider.vars.smoothHeight)) $(window).bind(
  3536. "resize orientationchange focus", methods.resize);
  3537. slider.find("img").attr("draggable", "false");
  3538. // API: start() Callback
  3539. setTimeout(function() {
  3540. slider.vars.start(slider);
  3541. }, 200);
  3542. },
  3543. asNav: {
  3544. setup: function() {
  3545. slider.asNav = true;
  3546. slider.animatingTo = Math.floor(slider.currentSlide /
  3547. slider.move);
  3548. slider.currentItem = slider.currentSlide;
  3549. slider.slides.removeClass(namespace + "active-slide").eq(
  3550. slider.currentItem).addClass(namespace + "active-slide");
  3551. if (!msGesture) {
  3552. slider.slides.on(eventType, function(e) {
  3553. e.preventDefault();
  3554. var $slide = $(this),
  3555. target = $slide.index();
  3556. var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container
  3557. if (posFromLeft <= 0 && $slide.hasClass(namespace +
  3558. 'active-slide')) {
  3559. slider.flexAnimate(slider.getTarget("prev"), true);
  3560. } else if (!$(slider.vars.asNavFor).data('flexslider')
  3561. .animating && !$slide.hasClass(namespace +
  3562. "active-slide")) {
  3563. slider.direction = (slider.currentItem < target) ?
  3564. "next" : "prev";
  3565. slider.flexAnimate(target, slider.vars.pauseOnAction,
  3566. false, true, true);
  3567. }
  3568. });
  3569. } else {
  3570. el._slider = slider;
  3571. slider.slides.each(function() {
  3572. var that = this;
  3573. that._gesture = new MSGesture();
  3574. that._gesture.target = that;
  3575. that.addEventListener("MSPointerDown", function(e) {
  3576. e.preventDefault();
  3577. if (e.currentTarget._gesture)
  3578. e.currentTarget._gesture.addPointer(e.pointerId);
  3579. }, false);
  3580. that.addEventListener("MSGestureTap", function(e) {
  3581. e.preventDefault();
  3582. var $slide = $(this),
  3583. target = $slide.index();
  3584. if (!$(slider.vars.asNavFor).data('flexslider').animating &&
  3585. !$slide.hasClass('active')) {
  3586. slider.direction = (slider.currentItem < target) ?
  3587. "next" : "prev";
  3588. slider.flexAnimate(target, slider.vars.pauseOnAction,
  3589. false, true, true);
  3590. }
  3591. });
  3592. });
  3593. }
  3594. }
  3595. },
  3596. controlNav: {
  3597. setup: function() {
  3598. if (!slider.manualControls) {
  3599. methods.controlNav.setupPaging();
  3600. } else { // MANUALCONTROLS:
  3601. methods.controlNav.setupManual();
  3602. }
  3603. },
  3604. setupPaging: function() {
  3605. var type = (slider.vars.controlNav === "thumbnails") ?
  3606. 'control-thumbs' : 'control-paging',
  3607. j = 1,
  3608. item,
  3609. slide;
  3610. slider.controlNavScaffold = $('<ol class="' + namespace +
  3611. 'control-nav ' + namespace + type + '"></ol>');
  3612. if (slider.pagingCount > 1) {
  3613. for (var i = 0; i < slider.pagingCount; i++) {
  3614. slide = slider.slides.eq(i);
  3615. item = (slider.vars.controlNav === "thumbnails") ?
  3616. '<img src="' + slide.attr('data-thumb') + '"/>' :
  3617. '<a>' + j + '</a>';
  3618. if ('thumbnails' === slider.vars.controlNav && true ===
  3619. slider.vars.thumbCaptions) {
  3620. var captn = slide.attr('data-thumbcaption');
  3621. if ('' != captn && undefined != captn) item +=
  3622. '<span class="' + namespace + 'caption">' + captn +
  3623. '</span>';
  3624. }
  3625. // slider.controlNavScaffold.append('<li>' + item + '</li>');
  3626. slider.controlNavScaffold.append('<li>' + item +
  3627. '<i></i></li>');
  3628. j++;
  3629. }
  3630. }
  3631. // CONTROLSCONTAINER:
  3632. (slider.controlsContainer) ? $(slider.controlsContainer).append(
  3633. slider.controlNavScaffold) : slider.append(slider.controlNavScaffold);
  3634. methods.controlNav.set();
  3635. methods.controlNav.active();
  3636. slider.controlNavScaffold.delegate('a, img', eventType,
  3637. function(event) {
  3638. event.preventDefault();
  3639. if (watchedEvent === "" || watchedEvent === event.type) {
  3640. var $this = $(this),
  3641. target = slider.controlNav.index($this);
  3642. if (!$this.hasClass(namespace + 'active')) {
  3643. slider.direction = (target > slider.currentSlide) ?
  3644. "next" : "prev";
  3645. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3646. }
  3647. }
  3648. // setup flags to prevent event duplication
  3649. if (watchedEvent === "") {
  3650. watchedEvent = event.type;
  3651. }
  3652. methods.setToClearWatchedEvent();
  3653. });
  3654. },
  3655. setupManual: function() {
  3656. slider.controlNav = slider.manualControls;
  3657. methods.controlNav.active();
  3658. slider.controlNav.bind(eventType, function(event) {
  3659. event.preventDefault();
  3660. if (watchedEvent === "" || watchedEvent === event.type) {
  3661. var $this = $(this),
  3662. target = slider.controlNav.index($this);
  3663. if (!$this.hasClass(namespace + 'active')) {
  3664. (target > slider.currentSlide) ? slider.direction =
  3665. "next" : slider.direction = "prev";
  3666. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3667. }
  3668. }
  3669. // setup flags to prevent event duplication
  3670. if (watchedEvent === "") {
  3671. watchedEvent = event.type;
  3672. }
  3673. methods.setToClearWatchedEvent();
  3674. });
  3675. },
  3676. set: function() {
  3677. var selector = (slider.vars.controlNav === "thumbnails") ?
  3678. 'img' : 'a';
  3679. slider.controlNav = $('.' + namespace + 'control-nav li ' +
  3680. selector, (slider.controlsContainer) ? slider.controlsContainer :
  3681. slider);
  3682. },
  3683. active: function() {
  3684. slider.controlNav.removeClass(namespace + "active").eq(
  3685. slider.animatingTo).addClass(namespace + "active");
  3686. },
  3687. update: function(action, pos) {
  3688. if (slider.pagingCount > 1 && action === "add") {
  3689. slider.controlNavScaffold.append($('<li><a>' + slider.count +
  3690. '</a></li>'));
  3691. } else if (slider.pagingCount === 1) {
  3692. slider.controlNavScaffold.find('li').remove();
  3693. } else {
  3694. slider.controlNav.eq(pos).closest('li').remove();
  3695. }
  3696. methods.controlNav.set();
  3697. (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav
  3698. .length) ? slider.update(pos, action) : methods.controlNav
  3699. .active();
  3700. }
  3701. },
  3702. directionNav: {
  3703. setup: function() {
  3704. var directionNavScaffold = $('<ul class="' + namespace +
  3705. 'direction-nav"><li><a class="' + namespace +
  3706. 'prev" href="#">' + slider.vars.prevText +
  3707. '</a></li><li><a class="' + namespace +
  3708. 'next" href="#">' + slider.vars.nextText +
  3709. '</a></li></ul>');
  3710. // CONTROLSCONTAINER:
  3711. if (slider.controlsContainer) {
  3712. $(slider.controlsContainer).append(directionNavScaffold);
  3713. slider.directionNav = $('.' + namespace +
  3714. 'direction-nav li a', slider.controlsContainer);
  3715. } else {
  3716. slider.append(directionNavScaffold);
  3717. slider.directionNav = $('.' + namespace +
  3718. 'direction-nav li a', slider);
  3719. }
  3720. methods.directionNav.update();
  3721. slider.directionNav.bind(eventType, function(event) {
  3722. event.preventDefault();
  3723. var target;
  3724. if (watchedEvent === "" || watchedEvent === event.type) {
  3725. target = ($(this).hasClass(namespace + 'next')) ?
  3726. slider.getTarget('next') : slider.getTarget('prev');
  3727. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3728. }
  3729. // setup flags to prevent event duplication
  3730. if (watchedEvent === "") {
  3731. watchedEvent = event.type;
  3732. }
  3733. methods.setToClearWatchedEvent();
  3734. });
  3735. },
  3736. update: function() {
  3737. var disabledClass = namespace + 'disabled';
  3738. if (slider.pagingCount === 1) {
  3739. slider.directionNav.addClass(disabledClass).attr(
  3740. 'tabindex', '-1');
  3741. } else if (!slider.vars.animationLoop) {
  3742. if (slider.animatingTo === 0) {
  3743. slider.directionNav.removeClass(disabledClass).filter(
  3744. '.' + namespace + "prev").addClass(disabledClass).attr(
  3745. 'tabindex', '-1');
  3746. } else if (slider.animatingTo === slider.last) {
  3747. slider.directionNav.removeClass(disabledClass).filter(
  3748. '.' + namespace + "next").addClass(disabledClass).attr(
  3749. 'tabindex', '-1');
  3750. } else {
  3751. slider.directionNav.removeClass(disabledClass).removeAttr(
  3752. 'tabindex');
  3753. }
  3754. } else {
  3755. slider.directionNav.removeClass(disabledClass).removeAttr(
  3756. 'tabindex');
  3757. }
  3758. }
  3759. },
  3760. pausePlay: {
  3761. setup: function() {
  3762. var pausePlayScaffold = $('<div class="' + namespace +
  3763. 'pauseplay"><a></a></div>');
  3764. // CONTROLSCONTAINER:
  3765. if (slider.controlsContainer) {
  3766. slider.controlsContainer.append(pausePlayScaffold);
  3767. slider.pausePlay = $('.' + namespace + 'pauseplay a',
  3768. slider.controlsContainer);
  3769. } else {
  3770. slider.append(pausePlayScaffold);
  3771. slider.pausePlay = $('.' + namespace + 'pauseplay a',
  3772. slider);
  3773. }
  3774. methods.pausePlay.update((slider.vars.slideshow) ?
  3775. namespace + 'pause' : namespace + 'play');
  3776. slider.pausePlay.bind(eventType, function(event) {
  3777. event.preventDefault();
  3778. if (watchedEvent === "" || watchedEvent === event.type) {
  3779. if ($(this).hasClass(namespace + 'pause')) {
  3780. slider.manualPause = true;
  3781. slider.manualPlay = false;
  3782. slider.pause();
  3783. } else {
  3784. slider.manualPause = false;
  3785. slider.manualPlay = true;
  3786. slider.play();
  3787. }
  3788. }
  3789. // setup flags to prevent event duplication
  3790. if (watchedEvent === "") {
  3791. watchedEvent = event.type;
  3792. }
  3793. methods.setToClearWatchedEvent();
  3794. });
  3795. },
  3796. update: function(state) {
  3797. (state === "play") ? slider.pausePlay.removeClass(namespace +
  3798. 'pause').addClass(namespace + 'play').html(slider.vars.playText) :
  3799. slider.pausePlay.removeClass(namespace + 'play').addClass(
  3800. namespace + 'pause').html(slider.vars.pauseText);
  3801. }
  3802. },
  3803. touch: function() {
  3804. var startX,
  3805. startY,
  3806. offset,
  3807. cwidth,
  3808. dx,
  3809. startT,
  3810. scrolling = false,
  3811. localX = 0,
  3812. localY = 0,
  3813. accDx = 0;
  3814. if (!msGesture) {
  3815. el.addEventListener('touchstart', onTouchStart, false);
  3816. function onTouchStart(e) {
  3817. if (slider.animating) {
  3818. e.preventDefault();
  3819. } else if ((window.navigator.msPointerEnabled) || e.touches
  3820. .length === 1) {
  3821. slider.pause();
  3822. // CAROUSEL:
  3823. cwidth = (vertical) ? slider.h : slider.w;
  3824. startT = Number(new Date());
  3825. // CAROUSEL:
  3826. // Local vars for X and Y points.
  3827. localX = e.touches[0].pageX;
  3828. localY = e.touches[0].pageY;
  3829. offset = (carousel && reverse && slider.animatingTo ===
  3830. slider.last) ? 0 :
  3831. (carousel && reverse) ? slider.limit - (((slider.itemW +
  3832. slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
  3833. (carousel && slider.currentSlide === slider.last) ?
  3834. slider.limit :
  3835. (carousel) ? ((slider.itemW + slider.vars.itemMargin) *
  3836. slider.move) * slider.currentSlide :
  3837. (reverse) ? (slider.last - slider.currentSlide +
  3838. slider.cloneOffset) * cwidth : (slider.currentSlide +
  3839. slider.cloneOffset) * cwidth;
  3840. startX = (vertical) ? localY : localX;
  3841. startY = (vertical) ? localX : localY;
  3842. el.addEventListener('touchmove', onTouchMove, false);
  3843. el.addEventListener('touchend', onTouchEnd, false);
  3844. }
  3845. }
  3846. function onTouchMove(e) {
  3847. // Local vars for X and Y points.
  3848. localX = e.touches[0].pageX;
  3849. localY = e.touches[0].pageY;
  3850. dx = (vertical) ? startX - localY : startX - localX;
  3851. scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX -
  3852. startY)) : (Math.abs(dx) < Math.abs(localY - startY));
  3853. var fxms = 500;
  3854. if (!scrolling || Number(new Date()) - startT > fxms) {
  3855. e.preventDefault();
  3856. if (!fade && slider.transitions) {
  3857. if (!slider.vars.animationLoop) {
  3858. dx = dx / ((slider.currentSlide === 0 && dx < 0 ||
  3859. slider.currentSlide === slider.last && dx > 0) ?
  3860. (Math.abs(dx) / cwidth + 2) : 1);
  3861. }
  3862. slider.setProps(offset + dx, "setTouch");
  3863. }
  3864. }
  3865. }
  3866. function onTouchEnd(e) {
  3867. // finish the touch by undoing the touch session
  3868. el.removeEventListener('touchmove', onTouchMove, false);
  3869. if (slider.animatingTo === slider.currentSlide && !
  3870. scrolling && !(dx === null)) {
  3871. var updateDx = (reverse) ? -dx : dx,
  3872. target = (updateDx > 0) ? slider.getTarget('next') :
  3873. slider.getTarget('prev');
  3874. if (slider.canAdvance(target) && (Number(new Date()) -
  3875. startT < 550 && Math.abs(updateDx) > 50 || Math.abs(
  3876. updateDx) > cwidth / 2)) {
  3877. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3878. } else {
  3879. if (!fade) slider.flexAnimate(slider.currentSlide,
  3880. slider.vars.pauseOnAction, true);
  3881. }
  3882. }
  3883. el.removeEventListener('touchend', onTouchEnd, false);
  3884. startX = null;
  3885. startY = null;
  3886. dx = null;
  3887. offset = null;
  3888. }
  3889. } else {
  3890. el.style.msTouchAction = "none";
  3891. el._gesture = new MSGesture();
  3892. el._gesture.target = el;
  3893. el.addEventListener("MSPointerDown", onMSPointerDown, false);
  3894. el._slider = slider;
  3895. el.addEventListener("MSGestureChange", onMSGestureChange,
  3896. false);
  3897. el.addEventListener("MSGestureEnd", onMSGestureEnd, false);
  3898. function onMSPointerDown(e) {
  3899. e.stopPropagation();
  3900. if (slider.animating) {
  3901. e.preventDefault();
  3902. } else {
  3903. slider.pause();
  3904. el._gesture.addPointer(e.pointerId);
  3905. accDx = 0;
  3906. cwidth = (vertical) ? slider.h : slider.w;
  3907. startT = Number(new Date());
  3908. // CAROUSEL:
  3909. offset = (carousel && reverse && slider.animatingTo ===
  3910. slider.last) ? 0 :
  3911. (carousel && reverse) ? slider.limit - (((slider.itemW +
  3912. slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
  3913. (carousel && slider.currentSlide === slider.last) ?
  3914. slider.limit :
  3915. (carousel) ? ((slider.itemW + slider.vars.itemMargin) *
  3916. slider.move) * slider.currentSlide :
  3917. (reverse) ? (slider.last - slider.currentSlide +
  3918. slider.cloneOffset) * cwidth : (slider.currentSlide +
  3919. slider.cloneOffset) * cwidth;
  3920. }
  3921. }
  3922. function onMSGestureChange(e) {
  3923. e.stopPropagation();
  3924. var slider = e.target._slider;
  3925. if (!slider) {
  3926. return;
  3927. }
  3928. var transX = -e.translationX,
  3929. transY = -e.translationY;
  3930. //Accumulate translations.
  3931. accDx = accDx + ((vertical) ? transY : transX);
  3932. dx = accDx;
  3933. scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-
  3934. transX)) : (Math.abs(accDx) < Math.abs(-transY));
  3935. if (e.detail === e.MSGESTURE_FLAG_INERTIA) {
  3936. setImmediate(function() {
  3937. el._gesture.stop();
  3938. });
  3939. return;
  3940. }
  3941. if (!scrolling || Number(new Date()) - startT > 500) {
  3942. e.preventDefault();
  3943. if (!fade && slider.transitions) {
  3944. if (!slider.vars.animationLoop) {
  3945. dx = accDx / ((slider.currentSlide === 0 && accDx <
  3946. 0 || slider.currentSlide === slider.last &&
  3947. accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1);
  3948. }
  3949. slider.setProps(offset + dx, "setTouch");
  3950. }
  3951. }
  3952. }
  3953. function onMSGestureEnd(e) {
  3954. e.stopPropagation();
  3955. var slider = e.target._slider;
  3956. if (!slider) {
  3957. return;
  3958. }
  3959. if (slider.animatingTo === slider.currentSlide && !
  3960. scrolling && !(dx === null)) {
  3961. var updateDx = (reverse) ? -dx : dx,
  3962. target = (updateDx > 0) ? slider.getTarget('next') :
  3963. slider.getTarget('prev');
  3964. if (slider.canAdvance(target) && (Number(new Date()) -
  3965. startT < 550 && Math.abs(updateDx) > 50 || Math.abs(
  3966. updateDx) > cwidth / 2)) {
  3967. slider.flexAnimate(target, slider.vars.pauseOnAction);
  3968. } else {
  3969. if (!fade) slider.flexAnimate(slider.currentSlide,
  3970. slider.vars.pauseOnAction, true);
  3971. }
  3972. }
  3973. startX = null;
  3974. startY = null;
  3975. dx = null;
  3976. offset = null;
  3977. accDx = 0;
  3978. }
  3979. }
  3980. },
  3981. resize: function() {
  3982. if (!slider.animating && slider.is(':visible')) {
  3983. if (!carousel) slider.doMath();
  3984. if (fade) {
  3985. // SMOOTH HEIGHT:
  3986. methods.smoothHeight();
  3987. } else if (carousel) { //CAROUSEL:
  3988. slider.slides.width(slider.computedW);
  3989. slider.update(slider.pagingCount);
  3990. slider.setProps();
  3991. } else if (vertical) { //VERTICAL:
  3992. slider.viewport.height(slider.h);
  3993. slider.setProps(slider.h, "setTotal");
  3994. } else {
  3995. // SMOOTH HEIGHT:
  3996. if (slider.vars.smoothHeight) methods.smoothHeight();
  3997. slider.newSlides.width(slider.computedW);
  3998. slider.setProps(slider.computedW, "setTotal");
  3999. }
  4000. }
  4001. },
  4002. smoothHeight: function(dur) {
  4003. if (!vertical || fade) {
  4004. var $obj = (fade) ? slider : slider.viewport;
  4005. (dur) ? $obj.animate({
  4006. "height": slider.slides.eq(slider.animatingTo).height()
  4007. }, dur) : $obj.height(slider.slides.eq(slider.animatingTo).height());
  4008. }
  4009. },
  4010. sync: function(action) {
  4011. var $obj = $(slider.vars.sync).data("flexslider"),
  4012. target = slider.animatingTo;
  4013. switch (action) {
  4014. case "animate":
  4015. $obj.flexAnimate(target, slider.vars.pauseOnAction, false,
  4016. true);
  4017. break;
  4018. case "play":
  4019. if (!$obj.playing && !$obj.asNav) {
  4020. $obj.play();
  4021. }
  4022. break;
  4023. case "pause":
  4024. $obj.pause();
  4025. break;
  4026. }
  4027. },
  4028. uniqueID: function($clone) {
  4029. // Append _clone to current level and children elements with id attributes
  4030. $clone.filter('[id]').add($clone.find('[id]')).each(function() {
  4031. var $this = $(this);
  4032. $this.attr('id', $this.attr('id') + '_clone');
  4033. });
  4034. return $clone;
  4035. },
  4036. pauseInvisible: {
  4037. visProp: null,
  4038. init: function() {
  4039. var prefixes = ['webkit', 'moz', 'ms', 'o'];
  4040. if ('hidden' in document) return 'hidden';
  4041. for (var i = 0; i < prefixes.length; i++) {
  4042. if ((prefixes[i] + 'Hidden') in document)
  4043. methods.pauseInvisible.visProp = prefixes[i] + 'Hidden';
  4044. }
  4045. if (methods.pauseInvisible.visProp) {
  4046. var evtname = methods.pauseInvisible.visProp.replace(
  4047. /[H|h]idden/, '') + 'visibilitychange';
  4048. document.addEventListener(evtname, function() {
  4049. if (methods.pauseInvisible.isHidden()) {
  4050. if (slider.startTimeout) clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible
  4051. else slider.pause(); //Or just pause
  4052. } else {
  4053. if (slider.started) slider.play(); //Initiated before, just play
  4054. else(slider.vars.initDelay > 0) ? setTimeout(slider
  4055. .play, slider.vars.initDelay) : slider.play(); //Didn't init before: simply init or wait for it
  4056. }
  4057. });
  4058. }
  4059. },
  4060. isHidden: function() {
  4061. return document[methods.pauseInvisible.visProp] || false;
  4062. }
  4063. },
  4064. setToClearWatchedEvent: function() {
  4065. clearTimeout(watchedEventClearTimer);
  4066. watchedEventClearTimer = setTimeout(function() {
  4067. watchedEvent = "";
  4068. }, 3000);
  4069. }
  4070. };
  4071. // public methods
  4072. slider.flexAnimate = function(target, pause, override, withSync,
  4073. fromNav) {
  4074. if (!slider.vars.animationLoop && target !== slider.currentSlide) {
  4075. slider.direction = (target > slider.currentSlide) ? "next" :
  4076. "prev";
  4077. }
  4078. if (asNav && slider.pagingCount === 1) slider.direction = (
  4079. slider.currentItem < target) ? "next" : "prev";
  4080. if (!slider.animating && (slider.canAdvance(target, fromNav) ||
  4081. override) && slider.is(":visible")) {
  4082. if (asNav && withSync) {
  4083. var master = $(slider.vars.asNavFor).data('flexslider');
  4084. slider.atEnd = target === 0 || target === slider.count - 1;
  4085. master.flexAnimate(target, true, false, true, fromNav);
  4086. slider.direction = (slider.currentItem < target) ? "next" :
  4087. "prev";
  4088. master.direction = slider.direction;
  4089. if (Math.ceil((target + 1) / slider.visible) - 1 !== slider
  4090. .currentSlide && target !== 0) {
  4091. slider.currentItem = target;
  4092. slider.slides.removeClass(namespace + "active-slide").eq(
  4093. target).addClass(namespace + "active-slide");
  4094. target = Math.floor(target / slider.visible);
  4095. } else {
  4096. slider.currentItem = target;
  4097. slider.slides.removeClass(namespace + "active-slide").eq(
  4098. target).addClass(namespace + "active-slide");
  4099. return false;
  4100. }
  4101. }
  4102. slider.animating = true;
  4103. slider.animatingTo = target;
  4104. // SLIDESHOW:
  4105. if (pause) slider.pause();
  4106. // API: before() animation Callback
  4107. slider.vars.before(slider);
  4108. // SYNC:
  4109. if (slider.syncExists && !fromNav) methods.sync("animate");
  4110. // CONTROLNAV
  4111. if (slider.vars.controlNav) methods.controlNav.active();
  4112. // !CAROUSEL:
  4113. // CANDIDATE: slide active class (for add/remove slide)
  4114. if (!carousel) slider.slides.removeClass(namespace +
  4115. 'active-slide').eq(target).addClass(namespace +
  4116. 'active-slide');
  4117. // INFINITE LOOP:
  4118. // CANDIDATE: atEnd
  4119. slider.atEnd = target === 0 || target === slider.last;
  4120. // DIRECTIONNAV:
  4121. if (slider.vars.directionNav) methods.directionNav.update();
  4122. if (target === slider.last) {
  4123. // API: end() of cycle Callback
  4124. slider.vars.end(slider);
  4125. // SLIDESHOW && !INFINITE LOOP:
  4126. if (!slider.vars.animationLoop) slider.pause();
  4127. }
  4128. // SLIDE:
  4129. if (!fade) {
  4130. var dimension = (vertical) ? slider.slides.filter(':first')
  4131. .height() : slider.computedW,
  4132. margin, slideString, calcNext;
  4133. // INFINITE LOOP / REVERSE:
  4134. if (carousel) {
  4135. //margin = (slider.vars.itemWidth > slider.w) ? slider.vars.itemMargin * 2 : slider.vars.itemMargin;
  4136. margin = slider.vars.itemMargin;
  4137. calcNext = ((slider.itemW + margin) * slider.move) *
  4138. slider.animatingTo;
  4139. slideString = (calcNext > slider.limit && slider.visible !==
  4140. 1) ? slider.limit : calcNext;
  4141. } else if (slider.currentSlide === 0 && target === slider.count -
  4142. 1 && slider.vars.animationLoop && slider.direction !==
  4143. "next") {
  4144. slideString = (reverse) ? (slider.count + slider.cloneOffset) *
  4145. dimension : 0;
  4146. } else if (slider.currentSlide === slider.last && target ===
  4147. 0 && slider.vars.animationLoop && slider.direction !==
  4148. "prev") {
  4149. slideString = (reverse) ? 0 : (slider.count + 1) *
  4150. dimension;
  4151. } else {
  4152. slideString = (reverse) ? ((slider.count - 1) - target +
  4153. slider.cloneOffset) * dimension : (target + slider.cloneOffset) *
  4154. dimension;
  4155. }
  4156. slider.setProps(slideString, "", slider.vars.animationSpeed);
  4157. if (slider.transitions) {
  4158. if (!slider.vars.animationLoop || !slider.atEnd) {
  4159. slider.animating = false;
  4160. slider.currentSlide = slider.animatingTo;
  4161. }
  4162. // Unbind previous transitionEnd events and re-bind new transitionEnd event
  4163. slider.container.unbind(
  4164. "webkitTransitionEnd transitionend");
  4165. slider.container.bind("webkitTransitionEnd transitionend",
  4166. function() {
  4167. clearTimeout(slider.ensureAnimationEnd);
  4168. slider.wrapup(dimension);
  4169. });
  4170. // Insurance for the ever-so-fickle transitionEnd event
  4171. clearTimeout(slider.ensureAnimationEnd);
  4172. slider.ensureAnimationEnd = setTimeout(function() {
  4173. slider.wrapup(dimension);
  4174. }, slider.vars.animationSpeed + 100);
  4175. } else {
  4176. slider.container.animate(slider.args, slider.vars.animationSpeed,
  4177. slider.vars.easing, function() {
  4178. slider.wrapup(dimension);
  4179. });
  4180. }
  4181. } else { // FADE:
  4182. if (!touch) {
  4183. //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing);
  4184. //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
  4185. slider.slides.eq(slider.currentSlide).css({
  4186. "zIndex": 1
  4187. }).animate({
  4188. "opacity": 0
  4189. }, slider.vars.animationSpeed, slider.vars.easing);
  4190. slider.slides.eq(target).css({
  4191. "zIndex": 2
  4192. }).animate({
  4193. "opacity": 1
  4194. }, slider.vars.animationSpeed, slider.vars.easing,
  4195. slider.wrapup);
  4196. } else {
  4197. slider.slides.eq(slider.currentSlide).css({
  4198. "opacity": 0,
  4199. "zIndex": 1
  4200. });
  4201. slider.slides.eq(target).css({
  4202. "opacity": 1,
  4203. "zIndex": 2
  4204. });
  4205. slider.wrapup(dimension);
  4206. }
  4207. }
  4208. // SMOOTH HEIGHT:
  4209. if (slider.vars.smoothHeight) methods.smoothHeight(slider.vars
  4210. .animationSpeed);
  4211. }
  4212. };
  4213. slider.wrapup = function(dimension) {
  4214. // SLIDE:
  4215. if (!fade && !carousel) {
  4216. if (slider.currentSlide === 0 && slider.animatingTo ===
  4217. slider.last && slider.vars.animationLoop) {
  4218. slider.setProps(dimension, "jumpEnd");
  4219. } else if (slider.currentSlide === slider.last && slider.animatingTo ===
  4220. 0 && slider.vars.animationLoop) {
  4221. slider.setProps(dimension, "jumpStart");
  4222. }
  4223. }
  4224. slider.animating = false;
  4225. slider.currentSlide = slider.animatingTo;
  4226. // API: after() animation Callback
  4227. slider.vars.after(slider);
  4228. };
  4229. // SLIDESHOW:
  4230. slider.animateSlides = function() {
  4231. if (!slider.animating && focused) slider.flexAnimate(slider.getTarget(
  4232. "next"));
  4233. };
  4234. // SLIDESHOW:
  4235. slider.pause = function() {
  4236. clearInterval(slider.animatedSlides);
  4237. slider.animatedSlides = null;
  4238. slider.playing = false;
  4239. // PAUSEPLAY:
  4240. if (slider.vars.pausePlay) methods.pausePlay.update("play");
  4241. // SYNC:
  4242. if (slider.syncExists) methods.sync("pause");
  4243. };
  4244. // SLIDESHOW:
  4245. slider.play = function() {
  4246. if (slider.playing) clearInterval(slider.animatedSlides);
  4247. slider.animatedSlides = slider.animatedSlides || setInterval(
  4248. slider.animateSlides, slider.vars.slideshowSpeed);
  4249. slider.started = slider.playing = true;
  4250. // PAUSEPLAY:
  4251. if (slider.vars.pausePlay) methods.pausePlay.update("pause");
  4252. // SYNC:
  4253. if (slider.syncExists) methods.sync("play");
  4254. };
  4255. // STOP:
  4256. slider.stop = function() {
  4257. slider.pause();
  4258. slider.stopped = true;
  4259. };
  4260. slider.canAdvance = function(target, fromNav) {
  4261. // ASNAV:
  4262. var last = (asNav) ? slider.pagingCount - 1 : slider.last;
  4263. return (fromNav) ? true :
  4264. (asNav && slider.currentItem === slider.count - 1 && target ===
  4265. 0 && slider.direction === "prev") ? true :
  4266. (asNav && slider.currentItem === 0 && target === slider.pagingCount -
  4267. 1 && slider.direction !== "next") ? false :
  4268. (target === slider.currentSlide && !asNav) ? false :
  4269. (slider.vars.animationLoop) ? true :
  4270. (slider.atEnd && slider.currentSlide === 0 && target === last &&
  4271. slider.direction !== "next") ? false :
  4272. (slider.atEnd && slider.currentSlide === last && target === 0 &&
  4273. slider.direction === "next") ? false :
  4274. true;
  4275. };
  4276. slider.getTarget = function(dir) {
  4277. slider.direction = dir;
  4278. if (dir === "next") {
  4279. return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide +
  4280. 1;
  4281. } else {
  4282. return (slider.currentSlide === 0) ? slider.last : slider.currentSlide -
  4283. 1;
  4284. }
  4285. };
  4286. // SLIDE:
  4287. slider.setProps = function(pos, special, dur) {
  4288. var target = (function() {
  4289. var posCheck = (pos) ? pos : ((slider.itemW + slider.vars
  4290. .itemMargin) * slider.move) * slider.animatingTo,
  4291. posCalc = (function() {
  4292. if (carousel) {
  4293. return (special === "setTouch") ? pos :
  4294. (reverse && slider.animatingTo === slider.last) ?
  4295. 0 :
  4296. (reverse) ? slider.limit - (((slider.itemW +
  4297. slider.vars.itemMargin) * slider.move) *
  4298. slider.animatingTo) :
  4299. (slider.animatingTo === slider.last) ? slider.limit :
  4300. posCheck;
  4301. } else {
  4302. switch (special) {
  4303. case "setTotal":
  4304. return (reverse) ? ((slider.count - 1) -
  4305. slider.currentSlide + slider.cloneOffset) *
  4306. pos : (slider.currentSlide + slider.cloneOffset) *
  4307. pos;
  4308. case "setTouch":
  4309. return (reverse) ? pos : pos;
  4310. case "jumpEnd":
  4311. return (reverse) ? pos : slider.count * pos;
  4312. case "jumpStart":
  4313. return (reverse) ? slider.count * pos : pos;
  4314. default:
  4315. return pos;
  4316. }
  4317. }
  4318. }());
  4319. return (posCalc * -1) + "px";
  4320. }());
  4321. if (slider.transitions) {
  4322. target = (vertical) ? "translate3d(0," + target + ",0)" :
  4323. "translate3d(" + target + ",0,0)";
  4324. dur = (dur !== undefined) ? (dur / 1000) + "s" : "0s";
  4325. slider.container.css("-" + slider.pfx +
  4326. "-transition-duration", dur);
  4327. slider.container.css("transition-duration", dur);
  4328. }
  4329. slider.args[slider.prop] = target;
  4330. if (slider.transitions || dur === undefined) slider.container.css(
  4331. slider.args);
  4332. slider.container.css('transform', target);
  4333. };
  4334. slider.setup = function(type) {
  4335. // SLIDE:
  4336. if (!fade) {
  4337. var sliderOffset, arr;
  4338. if (type === "init") {
  4339. slider.viewport = $('<div class="' + namespace +
  4340. 'viewport"></div>').css({
  4341. "overflow": "hidden",
  4342. "position": "relative"
  4343. }).appendTo(slider).append(slider.container);
  4344. // INFINITE LOOP:
  4345. slider.cloneCount = 0;
  4346. slider.cloneOffset = 0;
  4347. // REVERSE:
  4348. if (reverse) {
  4349. arr = $.makeArray(slider.slides).reverse();
  4350. slider.slides = $(arr);
  4351. slider.container.empty().append(slider.slides);
  4352. }
  4353. }
  4354. // INFINITE LOOP && !CAROUSEL:
  4355. if (slider.vars.animationLoop && !carousel) {
  4356. slider.cloneCount = 2;
  4357. slider.cloneOffset = 1;
  4358. // clear out old clones
  4359. if (type !== "init") slider.container.find('.clone').remove();
  4360. slider.container.append(methods.uniqueID(slider.slides.first()
  4361. .clone().addClass('clone')).attr('aria-hidden', 'true'))
  4362. .prepend(methods.uniqueID(slider.slides.last().clone().addClass(
  4363. 'clone')).attr('aria-hidden', 'true'));
  4364. }
  4365. slider.newSlides = $(slider.vars.selector, slider);
  4366. sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide +
  4367. slider.cloneOffset : slider.currentSlide + slider.cloneOffset;
  4368. // VERTICAL:
  4369. if (vertical && !carousel) {
  4370. slider.container.height((slider.count + slider.cloneCount) *
  4371. 200 + "%").css("position", "absolute").width("100%");
  4372. setTimeout(function() {
  4373. slider.newSlides.css({
  4374. "display": "block"
  4375. });
  4376. slider.doMath();
  4377. slider.viewport.height(slider.h);
  4378. slider.setProps(sliderOffset * slider.h, "init");
  4379. }, (type === "init") ? 100 : 0);
  4380. } else {
  4381. slider.container.width((slider.count + slider.cloneCount) *
  4382. 200 + "%");
  4383. slider.setProps(sliderOffset * slider.computedW, "init");
  4384. setTimeout(function() {
  4385. slider.doMath();
  4386. slider.newSlides.css({
  4387. "width": slider.computedW,
  4388. "float": "left",
  4389. "display": "block"
  4390. });
  4391. // SMOOTH HEIGHT:
  4392. if (slider.vars.smoothHeight) methods.smoothHeight();
  4393. }, (type === "init") ? 100 : 0);
  4394. }
  4395. } else { // FADE:
  4396. slider.slides.css({
  4397. "width": "100%",
  4398. "float": "left",
  4399. "marginRight": "-100%",
  4400. "position": "relative"
  4401. });
  4402. if (type === "init") {
  4403. if (!touch) {
  4404. //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing);
  4405. if (slider.vars.fadeFirstSlide == false) {
  4406. slider.slides.css({
  4407. "opacity": 0,
  4408. "display": "block",
  4409. "zIndex": 1
  4410. }).eq(slider.currentSlide).css({
  4411. "zIndex": 2
  4412. }).css({
  4413. "opacity": 1
  4414. });
  4415. } else {
  4416. slider.slides.css({
  4417. "opacity": 0,
  4418. "display": "block",
  4419. "zIndex": 1
  4420. }).eq(slider.currentSlide).css({
  4421. "zIndex": 2
  4422. }).animate({
  4423. "opacity": 1
  4424. }, slider.vars.animationSpeed, slider.vars.easing);
  4425. }
  4426. } else {
  4427. slider.slides.css({
  4428. "opacity": 0,
  4429. "display": "block",
  4430. "webkitTransition": "opacity " + slider.vars.animationSpeed /
  4431. 1000 + "s ease",
  4432. "zIndex": 1
  4433. }).eq(slider.currentSlide).css({
  4434. "opacity": 1,
  4435. "zIndex": 2
  4436. });
  4437. }
  4438. }
  4439. // SMOOTH HEIGHT:
  4440. if (slider.vars.smoothHeight) methods.smoothHeight();
  4441. }
  4442. // !CAROUSEL:
  4443. // CANDIDATE: active slide
  4444. if (!carousel) slider.slides.removeClass(namespace +
  4445. "active-slide").eq(slider.currentSlide).addClass(namespace +
  4446. "active-slide");
  4447. //FlexSlider: init() Callback
  4448. slider.vars.init(slider);
  4449. };
  4450. slider.doMath = function() {
  4451. var slide = slider.slides.first(),
  4452. slideMargin = slider.vars.itemMargin,
  4453. minItems = slider.vars.minItems,
  4454. maxItems = slider.vars.maxItems;
  4455. slider.w = (slider.viewport === undefined) ? slider.width() :
  4456. slider.viewport.width();
  4457. slider.h = slide.height();
  4458. slider.boxPadding = slide.outerWidth() - slide.width();
  4459. // CAROUSEL:
  4460. if (carousel) {
  4461. slider.itemT = slider.vars.itemWidth + slideMargin;
  4462. slider.minW = (minItems) ? minItems * slider.itemT : slider.w;
  4463. slider.maxW = (maxItems) ? (maxItems * slider.itemT) -
  4464. slideMargin : slider.w;
  4465. slider.itemW = (slider.minW > slider.w) ? (slider.w - (
  4466. slideMargin * (minItems - 1))) / minItems :
  4467. (slider.maxW < slider.w) ? (slider.w - (slideMargin * (
  4468. maxItems - 1))) / maxItems :
  4469. (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars
  4470. .itemWidth;
  4471. slider.visible = Math.floor(slider.w / (slider.itemW));
  4472. slider.move = (slider.vars.move > 0 && slider.vars.move <
  4473. slider.visible) ? slider.vars.move : slider.visible;
  4474. slider.pagingCount = Math.ceil(((slider.count - slider.visible) /
  4475. slider.move) + 1);
  4476. slider.last = slider.pagingCount - 1;
  4477. slider.limit = (slider.pagingCount === 1) ? 0 :
  4478. (slider.vars.itemWidth > slider.w) ? (slider.itemW * (
  4479. slider.count - 1)) + (slideMargin * (slider.count - 1)) : (
  4480. (slider.itemW + slideMargin) * slider.count) - slider.w -
  4481. slideMargin;
  4482. } else {
  4483. slider.itemW = slider.w;
  4484. slider.pagingCount = slider.count;
  4485. slider.last = slider.count - 1;
  4486. }
  4487. slider.computedW = slider.itemW - slider.boxPadding;
  4488. };
  4489. slider.update = function(pos, action) {
  4490. slider.doMath();
  4491. // update currentSlide and slider.animatingTo if necessary
  4492. if (!carousel) {
  4493. if (pos < slider.currentSlide) {
  4494. slider.currentSlide += 1;
  4495. } else if (pos <= slider.currentSlide && pos !== 0) {
  4496. slider.currentSlide -= 1;
  4497. }
  4498. slider.animatingTo = slider.currentSlide;
  4499. }
  4500. // update controlNav
  4501. if (slider.vars.controlNav && !slider.manualControls) {
  4502. if ((action === "add" && !carousel) || slider.pagingCount >
  4503. slider.controlNav.length) {
  4504. methods.controlNav.update("add");
  4505. } else if ((action === "remove" && !carousel) || slider.pagingCount <
  4506. slider.controlNav.length) {
  4507. if (carousel && slider.currentSlide > slider.last) {
  4508. slider.currentSlide -= 1;
  4509. slider.animatingTo -= 1;
  4510. }
  4511. methods.controlNav.update("remove", slider.last);
  4512. }
  4513. }
  4514. // update directionNav
  4515. if (slider.vars.directionNav) methods.directionNav.update();
  4516. };
  4517. slider.addSlide = function(obj, pos) {
  4518. var $obj = $(obj);
  4519. slider.count += 1;
  4520. slider.last = slider.count - 1;
  4521. // append new slide
  4522. if (vertical && reverse) {
  4523. (pos !== undefined) ? slider.slides.eq(slider.count - pos).after(
  4524. $obj) : slider.container.prepend($obj);
  4525. } else {
  4526. (pos !== undefined) ? slider.slides.eq(pos).before($obj) :
  4527. slider.container.append($obj);
  4528. }
  4529. // update currentSlide, animatingTo, controlNav, and directionNav
  4530. slider.update(pos, "add");
  4531. // update slider.slides
  4532. slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
  4533. // re-setup the slider to accomdate new slide
  4534. slider.setup();
  4535. //FlexSlider: added() Callback
  4536. slider.vars.added(slider);
  4537. };
  4538. slider.removeSlide = function(obj) {
  4539. var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj;
  4540. // update count
  4541. slider.count -= 1;
  4542. slider.last = slider.count - 1;
  4543. // remove slide
  4544. if (isNaN(obj)) {
  4545. $(obj, slider.slides).remove();
  4546. } else {
  4547. (vertical && reverse) ? slider.slides.eq(slider.last).remove() :
  4548. slider.slides.eq(obj).remove();
  4549. }
  4550. // update currentSlide, animatingTo, controlNav, and directionNav
  4551. slider.doMath();
  4552. slider.update(pos, "remove");
  4553. // update slider.slides
  4554. slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
  4555. // re-setup the slider to accomdate new slide
  4556. slider.setup();
  4557. // FlexSlider: removed() Callback
  4558. slider.vars.removed(slider);
  4559. };
  4560. //FlexSlider: Initialize
  4561. methods.init();
  4562. };
  4563. // Ensure the slider isn't focussed if the window loses focus.
  4564. $(window).blur(function(e) {
  4565. focused = false;
  4566. }).focus(function(e) {
  4567. focused = true;
  4568. });
  4569. // FlexSlider: Default Settings
  4570. $.flexslider.defaults = {
  4571. namespace: "am-", //{NEW} String: Prefix string attached to the class of every element generated by the plugin
  4572. selector: ".am-slides > li", //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril
  4573. animation: "slide", //String: Select your animation type, "fade" or "slide"
  4574. easing: "swing", //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported!
  4575. direction: "horizontal", //String: Select the sliding direction, "horizontal" or "vertical"
  4576. reverse: false, //{NEW} Boolean: Reverse the animation direction
  4577. animationLoop: true, //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end
  4578. smoothHeight: false, //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode
  4579. startAt: 0, //Integer: The slide that the slider should start on. Array notation (0 = first slide)
  4580. slideshow: true, //Boolean: Animate slider automatically
  4581. slideshowSpeed: 5000, //Integer: Set the speed of the slideshow cycling, in milliseconds
  4582. animationSpeed: 600, //Integer: Set the speed of animations, in milliseconds
  4583. initDelay: 0, //{NEW} Integer: Set an initialization delay, in milliseconds
  4584. randomize: false, //Boolean: Randomize slide order
  4585. fadeFirstSlide: true, //Boolean: Fade in the first slide when animation type is "fade"
  4586. thumbCaptions: false, //Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav.
  4587. // Usability features
  4588. pauseOnAction: true, //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
  4589. pauseOnHover: false, //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
  4590. pauseInvisible: true, //{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage.
  4591. useCSS: true, //{NEW} Boolean: Slider will use CSS3 transitions if available
  4592. touch: true, //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
  4593. video: false, //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
  4594. // Primary Controls
  4595. controlNav: true, //Boolean: Create navigation for paging control of each slide? Note: Leave true for manualControls usage
  4596. directionNav: true, //Boolean: Create navigation for previous/next navigation? (true/false)
  4597. prevText: "Previous", //String: Set the text for the "previous" directionNav item
  4598. nextText: "Next", //String: Set the text for the "next" directionNav item
  4599. // Secondary Navigation
  4600. keyboard: true, //Boolean: Allow slider navigating via keyboard left/right keys
  4601. multipleKeyboard: false, //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present.
  4602. mousewheel: false, //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
  4603. pausePlay: false, //Boolean: Create pause/play dynamic element
  4604. pauseText: "Pause", //String: Set the text for the "pause" pausePlay item
  4605. playText: "Play", //String: Set the text for the "play" pausePlay item
  4606. // Special properties
  4607. controlsContainer: "", //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found.
  4608. manualControls: "", //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
  4609. sync: "", //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
  4610. asNavFor: "", //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
  4611. // Carousel Options
  4612. itemWidth: 0, //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
  4613. itemMargin: 0, //{NEW} Integer: Margin between carousel items.
  4614. minItems: 1, //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this.
  4615. maxItems: 0, //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit.
  4616. move: 0, //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items.
  4617. allowOneSlide: true, //{NEW} Boolean: Whether or not to allow a slider comprised of a single slide
  4618. // Callback API
  4619. start: function() {}, //Callback: function(slider) - Fires when the slider loads the first slide
  4620. before: function() {}, //Callback: function(slider) - Fires asynchronously with each slider animation
  4621. after: function() {}, //Callback: function(slider) - Fires after each slider animation completes
  4622. end: function() {}, //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous)
  4623. added: function() {}, //{NEW} Callback: function(slider) - Fires after a slide is added
  4624. removed: function() {}, //{NEW} Callback: function(slider) - Fires after a slide is removed
  4625. init: function() {} //{NEW} Callback: function(slider) - Fires after the slider is initially setup
  4626. };
  4627. // FlexSlider: Plugin Function
  4628. $.fn.flexslider = function(options) {
  4629. if (options === undefined) options = {};
  4630. if (typeof options === "object") {
  4631. return this.each(function() {
  4632. var $this = $(this),
  4633. selector = (options.selector) ? options.selector :
  4634. ".am-slides > li",
  4635. $slides = $this.find(selector);
  4636. if (($slides.length === 1 && options.allowOneSlide ===
  4637. true) || $slides.length === 0) {
  4638. $slides.fadeIn(400);
  4639. if (options.start) options.start($this);
  4640. } else if ($this.data('flexslider') === undefined) {
  4641. new $.flexslider(this, options);
  4642. }
  4643. });
  4644. } else {
  4645. // Helper strings to quickly pecdrform functions on the slider
  4646. var $slider = $(this).data('flexslider');
  4647. switch (options) {
  4648. case 'play':
  4649. $slider.play();
  4650. break;
  4651. case 'pause':
  4652. $slider.pause();
  4653. break;
  4654. case 'stop':
  4655. $slider.stop();
  4656. break;
  4657. case 'next':
  4658. $slider.flexAnimate($slider.getTarget('next'), true);
  4659. break;
  4660. case 'prev':
  4661. case 'previous':
  4662. $slider.flexAnimate($slider.getTarget('prev'), true);
  4663. break;
  4664. default:
  4665. if (typeof options === 'number') {
  4666. $slider.flexAnimate(options, true);
  4667. }
  4668. }
  4669. }
  4670. };
  4671. // Init code
  4672. UI.ready(function(context) {
  4673. $('[data-am-flexslider]', context).each(function(i, item) {
  4674. var $slider = $(item);
  4675. var options = UI.utils.parseOptions($slider.data(
  4676. 'amFlexslider'));
  4677. options.before = function(slider) {
  4678. if (slider._pausedTimer) {
  4679. window.clearTimeout(slider._pausedTimer);
  4680. slider._pausedTimer = null;
  4681. }
  4682. };
  4683. options.after = function(slider) {
  4684. var pauseTime = slider.vars.playAfterPaused;
  4685. if (pauseTime && !isNaN(pauseTime) && !slider.playing) {
  4686. if (!slider.manualPause && !slider.manualPlay && !
  4687. slider.stopped) {
  4688. slider._pausedTimer = window.setTimeout(function() {
  4689. slider.play();
  4690. }, pauseTime);
  4691. }
  4692. }
  4693. };
  4694. $slider.flexslider(options);
  4695. });
  4696. });
  4697. // if (!slider.manualPause && !slider.manualPlay && !slider.stopped) slider.play();
  4698. module.exports = $.flexslider;
  4699. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  4700. "undefined" ? self : typeof window !== "undefined" ? window : {})
  4701. }, {
  4702. "./core": 4
  4703. }
  4704. ],
  4705. 31: [
  4706. function(require, module, exports) {
  4707. (function(global) {
  4708. 'use strict';
  4709. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  4710. "undefined" ? global.jQuery : null);
  4711. var UI = require('./core');
  4712. /* jshint unused: false */
  4713. /* jshint -W101, -W116, -W109 */
  4714. /*! iScroll v5.1.3
  4715. * (c) 2008-2014 Matteo Spinelli
  4716. * http://cubiq.org/license
  4717. */
  4718. var rAF = window.requestAnimationFrame ||
  4719. window.webkitRequestAnimationFrame ||
  4720. window.mozRequestAnimationFrame ||
  4721. window.oRequestAnimationFrame ||
  4722. window.msRequestAnimationFrame ||
  4723. function(callback) {
  4724. window.setTimeout(callback, 1000 / 60);
  4725. };
  4726. var utils = (function() {
  4727. var me = {};
  4728. var _elementStyle = document.createElement('div').style;
  4729. var _vendor = (function() {
  4730. var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
  4731. transform,
  4732. i = 0,
  4733. l = vendors.length;
  4734. for (; i < l; i++) {
  4735. transform = vendors[i] + 'ransform';
  4736. if (transform in _elementStyle) return vendors[i].substr(
  4737. 0, vendors[i].length - 1);
  4738. }
  4739. return false;
  4740. })();
  4741. function _prefixStyle(style) {
  4742. if (_vendor === false) return false;
  4743. if (_vendor === '') return style;
  4744. return _vendor + style.charAt(0).toUpperCase() + style.substr(
  4745. 1);
  4746. }
  4747. me.getTime = Date.now || function getTime() {
  4748. return new Date().getTime();
  4749. };
  4750. me.extend = function(target, obj) {
  4751. for (var i in obj) {
  4752. target[i] = obj[i];
  4753. }
  4754. };
  4755. me.addEvent = function(el, type, fn, capture) {
  4756. el.addEventListener(type, fn, !!capture);
  4757. };
  4758. me.removeEvent = function(el, type, fn, capture) {
  4759. el.removeEventListener(type, fn, !!capture);
  4760. };
  4761. me.prefixPointerEvent = function(pointerEvent) {
  4762. return window.MSPointerEvent ?
  4763. 'MSPointer' + pointerEvent.charAt(9).toUpperCase() +
  4764. pointerEvent.substr(10) :
  4765. pointerEvent;
  4766. };
  4767. me.momentum = function(current, start, time, lowerMargin,
  4768. wrapperSize, deceleration) {
  4769. var distance = current - start,
  4770. speed = Math.abs(distance) / time,
  4771. destination,
  4772. duration;
  4773. deceleration = deceleration === undefined ? 0.0006 :
  4774. deceleration;
  4775. destination = current + (speed * speed) / (2 * deceleration) *
  4776. (distance < 0 ? -1 : 1);
  4777. duration = speed / deceleration;
  4778. if (destination < lowerMargin) {
  4779. destination = wrapperSize ? lowerMargin - (wrapperSize /
  4780. 2.5 * (speed / 8)) : lowerMargin;
  4781. distance = Math.abs(destination - current);
  4782. duration = distance / speed;
  4783. } else if (destination > 0) {
  4784. destination = wrapperSize ? wrapperSize / 2.5 * (speed /
  4785. 8) : 0;
  4786. distance = Math.abs(current) + destination;
  4787. duration = distance / speed;
  4788. }
  4789. return {
  4790. destination: Math.round(destination),
  4791. duration: duration
  4792. };
  4793. };
  4794. var _transform = _prefixStyle('transform');
  4795. me.extend(me, {
  4796. hasTransform: _transform !== false,
  4797. hasPerspective: _prefixStyle('perspective') in
  4798. _elementStyle,
  4799. hasTouch: 'ontouchstart' in window,
  4800. hasPointer: window.PointerEvent || window.MSPointerEvent, // IE10 is prefixed
  4801. hasTransition: _prefixStyle('transition') in
  4802. _elementStyle
  4803. });
  4804. // This should find all Android browsers lower than build 535.19 (both stock browser and webview)
  4805. me.isBadAndroid = /Android /.test(window.navigator.appVersion) &&
  4806. !(/Chrome\/\d/.test(window.navigator.appVersion));
  4807. me.extend(me.style = {}, {
  4808. transform: _transform,
  4809. transitionTimingFunction: _prefixStyle(
  4810. 'transitionTimingFunction'),
  4811. transitionDuration: _prefixStyle('transitionDuration'),
  4812. transitionDelay: _prefixStyle('transitionDelay'),
  4813. transformOrigin: _prefixStyle('transformOrigin')
  4814. });
  4815. me.hasClass = function(e, c) {
  4816. var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
  4817. return re.test(e.className);
  4818. };
  4819. me.addClass = function(e, c) {
  4820. if (me.hasClass(e, c)) {
  4821. return;
  4822. }
  4823. var newclass = e.className.split(' ');
  4824. newclass.push(c);
  4825. e.className = newclass.join(' ');
  4826. };
  4827. me.removeClass = function(e, c) {
  4828. if (!me.hasClass(e, c)) {
  4829. return;
  4830. }
  4831. var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
  4832. e.className = e.className.replace(re, ' ');
  4833. };
  4834. me.offset = function(el) {
  4835. var left = -el.offsetLeft,
  4836. top = -el.offsetTop;
  4837. // jshint -W084
  4838. while (el = el.offsetParent) {
  4839. left -= el.offsetLeft;
  4840. top -= el.offsetTop;
  4841. }
  4842. // jshint +W084
  4843. return {
  4844. left: left,
  4845. top: top
  4846. };
  4847. };
  4848. me.preventDefaultException = function(el, exceptions) {
  4849. for (var i in exceptions) {
  4850. if (exceptions[i].test(el[i])) {
  4851. return true;
  4852. }
  4853. }
  4854. return false;
  4855. };
  4856. me.extend(me.eventType = {}, {
  4857. touchstart: 1,
  4858. touchmove: 1,
  4859. touchend: 1,
  4860. mousedown: 2,
  4861. mousemove: 2,
  4862. mouseup: 2,
  4863. pointerdown: 3,
  4864. pointermove: 3,
  4865. pointerup: 3,
  4866. MSPointerDown: 3,
  4867. MSPointerMove: 3,
  4868. MSPointerUp: 3
  4869. });
  4870. me.extend(me.ease = {}, {
  4871. quadratic: {
  4872. style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
  4873. fn: function(k) {
  4874. return k * (2 - k);
  4875. }
  4876. },
  4877. circular: {
  4878. style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
  4879. fn: function(k) {
  4880. return Math.sqrt(1 - (--k * k));
  4881. }
  4882. },
  4883. back: {
  4884. style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
  4885. fn: function(k) {
  4886. var b = 4;
  4887. return (k = k - 1) * k * ((b + 1) * k + b) + 1;
  4888. }
  4889. },
  4890. bounce: {
  4891. style: '',
  4892. fn: function(k) {
  4893. if ((k /= 1) < (1 / 2.75)) {
  4894. return 7.5625 * k * k;
  4895. } else if (k < (2 / 2.75)) {
  4896. return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
  4897. } else if (k < (2.5 / 2.75)) {
  4898. return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
  4899. } else {
  4900. return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
  4901. }
  4902. }
  4903. },
  4904. elastic: {
  4905. style: '',
  4906. fn: function(k) {
  4907. var f = 0.22,
  4908. e = 0.4;
  4909. if (k === 0) {
  4910. return 0;
  4911. }
  4912. if (k == 1) {
  4913. return 1;
  4914. }
  4915. return (e * Math.pow(2, -10 * k) * Math.sin((k - f /
  4916. 4) * (2 * Math.PI) / f) + 1);
  4917. }
  4918. }
  4919. });
  4920. me.tap = function(e, eventName) {
  4921. var ev = document.createEvent('Event');
  4922. ev.initEvent(eventName, true, true);
  4923. ev.pageX = e.pageX;
  4924. ev.pageY = e.pageY;
  4925. e.target.dispatchEvent(ev);
  4926. };
  4927. me.click = function(e) {
  4928. var target = e.target,
  4929. ev;
  4930. if (!(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName)) {
  4931. ev = document.createEvent('MouseEvents');
  4932. ev.initMouseEvent('click', true, true, e.view, 1,
  4933. target.screenX, target.screenY, target.clientX, target.clientY,
  4934. e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
  4935. 0, null);
  4936. ev._constructed = true;
  4937. target.dispatchEvent(ev);
  4938. }
  4939. };
  4940. return me;
  4941. })();
  4942. function IScroll(el, options) {
  4943. this.wrapper = typeof el == 'string' ? document.querySelector(el) :
  4944. el;
  4945. this.scroller = this.wrapper.children[0];
  4946. this.scrollerStyle = this.scroller.style; // cache style for better performance
  4947. this.options = {
  4948. // INSERT POINT: OPTIONS
  4949. startX: 0,
  4950. startY: 0,
  4951. scrollY: true,
  4952. directionLockThreshold: 5,
  4953. momentum: true,
  4954. bounce: true,
  4955. bounceTime: 600,
  4956. bounceEasing: '',
  4957. preventDefault: true,
  4958. preventDefaultException: {
  4959. tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/
  4960. },
  4961. HWCompositing: true,
  4962. useTransition: true,
  4963. useTransform: true
  4964. };
  4965. for (var i in options) {
  4966. this.options[i] = options[i];
  4967. }
  4968. // Normalize options
  4969. this.translateZ = this.options.HWCompositing && utils.hasPerspective ?
  4970. ' translateZ(0)' : '';
  4971. this.options.useTransition = utils.hasTransition && this.options.useTransition;
  4972. this.options.useTransform = utils.hasTransform && this.options.useTransform;
  4973. this.options.eventPassthrough = this.options.eventPassthrough ===
  4974. true ? 'vertical' : this.options.eventPassthrough;
  4975. this.options.preventDefault = !this.options.eventPassthrough &&
  4976. this.options.preventDefault;
  4977. // If you want eventPassthrough I have to lock one of the axes
  4978. this.options.scrollY = this.options.eventPassthrough ==
  4979. 'vertical' ? false : this.options.scrollY;
  4980. this.options.scrollX = this.options.eventPassthrough ==
  4981. 'horizontal' ? false : this.options.scrollX;
  4982. // With eventPassthrough we also need lockDirection mechanism
  4983. this.options.freeScroll = this.options.freeScroll && !this.options
  4984. .eventPassthrough;
  4985. this.options.directionLockThreshold = this.options.eventPassthrough ?
  4986. 0 : this.options.directionLockThreshold;
  4987. this.options.bounceEasing = typeof this.options.bounceEasing ==
  4988. 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular :
  4989. this.options.bounceEasing;
  4990. this.options.resizePolling = this.options.resizePolling ===
  4991. undefined ? 60 : this.options.resizePolling;
  4992. if (this.options.tap === true) {
  4993. this.options.tap = 'tap';
  4994. }
  4995. // INSERT POINT: NORMALIZATION
  4996. // Some defaults
  4997. this.x = 0;
  4998. this.y = 0;
  4999. this.directionX = 0;
  5000. this.directionY = 0;
  5001. this._events = {};
  5002. // INSERT POINT: DEFAULTS
  5003. this._init();
  5004. this.refresh();
  5005. this.scrollTo(this.options.startX, this.options.startY);
  5006. this.enable();
  5007. }
  5008. IScroll.prototype = {
  5009. version: '5.1.3',
  5010. _init: function() {
  5011. this._initEvents();
  5012. // INSERT POINT: _init
  5013. },
  5014. destroy: function() {
  5015. this._initEvents(true);
  5016. this._execEvent('destroy');
  5017. },
  5018. _transitionEnd: function(e) {
  5019. if (e.target != this.scroller || !this.isInTransition) {
  5020. return;
  5021. }
  5022. this._transitionTime();
  5023. if (!this.resetPosition(this.options.bounceTime)) {
  5024. this.isInTransition = false;
  5025. this._execEvent('scrollEnd');
  5026. }
  5027. },
  5028. _start: function(e) {
  5029. // React to left mouse button only
  5030. if (utils.eventType[e.type] != 1) {
  5031. if (e.button !== 0) {
  5032. return;
  5033. }
  5034. }
  5035. if (!this.enabled || (this.initiated && utils.eventType[e.type] !==
  5036. this.initiated)) {
  5037. return;
  5038. }
  5039. if (this.options.preventDefault && !utils.isBadAndroid && !
  5040. utils.preventDefaultException(e.target, this.options.preventDefaultException)
  5041. ) {
  5042. e.preventDefault();
  5043. }
  5044. var point = e.touches ? e.touches[0] : e,
  5045. pos;
  5046. this.initiated = utils.eventType[e.type];
  5047. this.moved = false;
  5048. this.distX = 0;
  5049. this.distY = 0;
  5050. this.directionX = 0;
  5051. this.directionY = 0;
  5052. this.directionLocked = 0;
  5053. this._transitionTime();
  5054. this.startTime = utils.getTime();
  5055. if (this.options.useTransition && this.isInTransition) {
  5056. this.isInTransition = false;
  5057. pos = this.getComputedPosition();
  5058. this._translate(Math.round(pos.x), Math.round(pos.y));
  5059. this._execEvent('scrollEnd');
  5060. } else if (!this.options.useTransition && this.isAnimating) {
  5061. this.isAnimating = false;
  5062. this._execEvent('scrollEnd');
  5063. }
  5064. this.startX = this.x;
  5065. this.startY = this.y;
  5066. this.absStartX = this.x;
  5067. this.absStartY = this.y;
  5068. this.pointX = point.pageX;
  5069. this.pointY = point.pageY;
  5070. this._execEvent('beforeScrollStart');
  5071. },
  5072. _move: function(e) {
  5073. if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
  5074. return;
  5075. }
  5076. if (this.options.preventDefault) { // increases performance on Android? TODO: check!
  5077. e.preventDefault();
  5078. }
  5079. var point = e.touches ? e.touches[0] : e,
  5080. deltaX = point.pageX - this.pointX,
  5081. deltaY = point.pageY - this.pointY,
  5082. timestamp = utils.getTime(),
  5083. newX, newY,
  5084. absDistX, absDistY;
  5085. this.pointX = point.pageX;
  5086. this.pointY = point.pageY;
  5087. this.distX += deltaX;
  5088. this.distY += deltaY;
  5089. absDistX = Math.abs(this.distX);
  5090. absDistY = Math.abs(this.distY);
  5091. // We need to move at least 10 pixels for the scrolling to initiate
  5092. if (timestamp - this.endTime > 300 && (absDistX < 10 &&
  5093. absDistY < 10)) {
  5094. return;
  5095. }
  5096. // If you are scrolling in one direction lock the other
  5097. if (!this.directionLocked && !this.options.freeScroll) {
  5098. if (absDistX > absDistY + this.options.directionLockThreshold) {
  5099. this.directionLocked = 'h'; // lock horizontally
  5100. } else if (absDistY >= absDistX + this.options.directionLockThreshold) {
  5101. this.directionLocked = 'v'; // lock vertically
  5102. } else {
  5103. this.directionLocked = 'n'; // no lock
  5104. }
  5105. }
  5106. if (this.directionLocked == 'h') {
  5107. if (this.options.eventPassthrough == 'vertical') {
  5108. e.preventDefault();
  5109. } else if (this.options.eventPassthrough == 'horizontal') {
  5110. this.initiated = false;
  5111. return;
  5112. }
  5113. deltaY = 0;
  5114. } else if (this.directionLocked == 'v') {
  5115. if (this.options.eventPassthrough == 'horizontal') {
  5116. e.preventDefault();
  5117. } else if (this.options.eventPassthrough == 'vertical') {
  5118. this.initiated = false;
  5119. return;
  5120. }
  5121. deltaX = 0;
  5122. }
  5123. deltaX = this.hasHorizontalScroll ? deltaX : 0;
  5124. deltaY = this.hasVerticalScroll ? deltaY : 0;
  5125. newX = this.x + deltaX;
  5126. newY = this.y + deltaY;
  5127. // Slow down if outside of the boundaries
  5128. if (newX > 0 || newX < this.maxScrollX) {
  5129. newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ?
  5130. 0 : this.maxScrollX;
  5131. }
  5132. if (newY > 0 || newY < this.maxScrollY) {
  5133. newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ?
  5134. 0 : this.maxScrollY;
  5135. }
  5136. this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
  5137. this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
  5138. if (!this.moved) {
  5139. this._execEvent('scrollStart');
  5140. }
  5141. this.moved = true;
  5142. this._translate(newX, newY);
  5143. /* REPLACE START: _move */
  5144. if (timestamp - this.startTime > 300) {
  5145. this.startTime = timestamp;
  5146. this.startX = this.x;
  5147. this.startY = this.y;
  5148. }
  5149. /* REPLACE END: _move */
  5150. },
  5151. _end: function(e) {
  5152. if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
  5153. return;
  5154. }
  5155. if (this.options.preventDefault && !utils.preventDefaultException(
  5156. e.target, this.options.preventDefaultException)) {
  5157. e.preventDefault();
  5158. }
  5159. var point = e.changedTouches ? e.changedTouches[0] : e,
  5160. momentumX,
  5161. momentumY,
  5162. duration = utils.getTime() - this.startTime,
  5163. newX = Math.round(this.x),
  5164. newY = Math.round(this.y),
  5165. distanceX = Math.abs(newX - this.startX),
  5166. distanceY = Math.abs(newY - this.startY),
  5167. time = 0,
  5168. easing = '';
  5169. this.isInTransition = 0;
  5170. this.initiated = 0;
  5171. this.endTime = utils.getTime();
  5172. // reset if we are outside of the boundaries
  5173. if (this.resetPosition(this.options.bounceTime)) {
  5174. return;
  5175. }
  5176. this.scrollTo(newX, newY); // ensures that the last position is rounded
  5177. // we scrolled less than 10 pixels
  5178. if (!this.moved) {
  5179. if (this.options.tap) {
  5180. utils.tap(e, this.options.tap);
  5181. }
  5182. if (this.options.click) {
  5183. utils.click(e);
  5184. }
  5185. this._execEvent('scrollCancel');
  5186. return;
  5187. }
  5188. if (this._events.flick && duration < 200 && distanceX < 100 &&
  5189. distanceY < 100) {
  5190. this._execEvent('flick');
  5191. return;
  5192. }
  5193. // start momentum animation if needed
  5194. if (this.options.momentum && duration < 300) {
  5195. momentumX = this.hasHorizontalScroll ? utils.momentum(this.x,
  5196. this.startX, duration, this.maxScrollX, this.options.bounce ?
  5197. this.wrapperWidth : 0, this.options.deceleration) : {
  5198. destination: newX,
  5199. duration: 0
  5200. };
  5201. momentumY = this.hasVerticalScroll ? utils.momentum(this.y,
  5202. this.startY, duration, this.maxScrollY, this.options.bounce ?
  5203. this.wrapperHeight : 0, this.options.deceleration) : {
  5204. destination: newY,
  5205. duration: 0
  5206. };
  5207. newX = momentumX.destination;
  5208. newY = momentumY.destination;
  5209. time = Math.max(momentumX.duration, momentumY.duration);
  5210. this.isInTransition = 1;
  5211. }
  5212. // INSERT POINT: _end
  5213. if (newX != this.x || newY != this.y) {
  5214. // change easing function when scroller goes out of the boundaries
  5215. if (newX > 0 || newX < this.maxScrollX || newY > 0 || newY <
  5216. this.maxScrollY) {
  5217. easing = utils.ease.quadratic;
  5218. }
  5219. this.scrollTo(newX, newY, time, easing);
  5220. return;
  5221. }
  5222. this._execEvent('scrollEnd');
  5223. },
  5224. _resize: function() {
  5225. var that = this;
  5226. clearTimeout(this.resizeTimeout);
  5227. this.resizeTimeout = setTimeout(function() {
  5228. that.refresh();
  5229. }, this.options.resizePolling);
  5230. },
  5231. resetPosition: function(time) {
  5232. var x = this.x,
  5233. y = this.y;
  5234. time = time || 0;
  5235. if (!this.hasHorizontalScroll || this.x > 0) {
  5236. x = 0;
  5237. } else if (this.x < this.maxScrollX) {
  5238. x = this.maxScrollX;
  5239. }
  5240. if (!this.hasVerticalScroll || this.y > 0) {
  5241. y = 0;
  5242. } else if (this.y < this.maxScrollY) {
  5243. y = this.maxScrollY;
  5244. }
  5245. if (x == this.x && y == this.y) {
  5246. return false;
  5247. }
  5248. this.scrollTo(x, y, time, this.options.bounceEasing);
  5249. return true;
  5250. },
  5251. disable: function() {
  5252. this.enabled = false;
  5253. },
  5254. enable: function() {
  5255. this.enabled = true;
  5256. },
  5257. refresh: function() {
  5258. var rf = this.wrapper.offsetHeight; // Force reflow
  5259. this.wrapperWidth = this.wrapper.clientWidth;
  5260. this.wrapperHeight = this.wrapper.clientHeight;
  5261. /* REPLACE START: refresh */
  5262. this.scrollerWidth = this.scroller.offsetWidth;
  5263. this.scrollerHeight = this.scroller.offsetHeight;
  5264. this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
  5265. this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
  5266. /* REPLACE END: refresh */
  5267. this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX <
  5268. 0;
  5269. this.hasVerticalScroll = this.options.scrollY && this.maxScrollY <
  5270. 0;
  5271. if (!this.hasHorizontalScroll) {
  5272. this.maxScrollX = 0;
  5273. this.scrollerWidth = this.wrapperWidth;
  5274. }
  5275. if (!this.hasVerticalScroll) {
  5276. this.maxScrollY = 0;
  5277. this.scrollerHeight = this.wrapperHeight;
  5278. }
  5279. this.endTime = 0;
  5280. this.directionX = 0;
  5281. this.directionY = 0;
  5282. this.wrapperOffset = utils.offset(this.wrapper);
  5283. this._execEvent('refresh');
  5284. this.resetPosition();
  5285. // INSERT POINT: _refresh
  5286. },
  5287. on: function(type, fn) {
  5288. if (!this._events[type]) {
  5289. this._events[type] = [];
  5290. }
  5291. this._events[type].push(fn);
  5292. },
  5293. off: function(type, fn) {
  5294. if (!this._events[type]) {
  5295. return;
  5296. }
  5297. var index = this._events[type].indexOf(fn);
  5298. if (index > -1) {
  5299. this._events[type].splice(index, 1);
  5300. }
  5301. },
  5302. _execEvent: function(type) {
  5303. if (!this._events[type]) {
  5304. return;
  5305. }
  5306. var i = 0,
  5307. l = this._events[type].length;
  5308. if (!l) {
  5309. return;
  5310. }
  5311. for (; i < l; i++) {
  5312. this._events[type][i].apply(this, [].slice.call(arguments, 1));
  5313. }
  5314. },
  5315. scrollBy: function(x, y, time, easing) {
  5316. x = this.x + x;
  5317. y = this.y + y;
  5318. time = time || 0;
  5319. this.scrollTo(x, y, time, easing);
  5320. },
  5321. scrollTo: function(x, y, time, easing) {
  5322. easing = easing || utils.ease.circular;
  5323. this.isInTransition = this.options.useTransition && time > 0;
  5324. if (!time || (this.options.useTransition && easing.style)) {
  5325. this._transitionTimingFunction(easing.style);
  5326. this._transitionTime(time);
  5327. this._translate(x, y);
  5328. } else {
  5329. this._animate(x, y, time, easing.fn);
  5330. }
  5331. },
  5332. scrollToElement: function(el, time, offsetX, offsetY, easing) {
  5333. el = el.nodeType ? el : this.scroller.querySelector(el);
  5334. if (!el) {
  5335. return;
  5336. }
  5337. var pos = utils.offset(el);
  5338. pos.left -= this.wrapperOffset.left;
  5339. pos.top -= this.wrapperOffset.top;
  5340. // if offsetX/Y are true we center the element to the screen
  5341. if (offsetX === true) {
  5342. offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth /
  5343. 2);
  5344. }
  5345. if (offsetY === true) {
  5346. offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight /
  5347. 2);
  5348. }
  5349. pos.left -= offsetX || 0;
  5350. pos.top -= offsetY || 0;
  5351. pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this
  5352. .maxScrollX : pos.left;
  5353. pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY :
  5354. pos.top;
  5355. time = time === undefined || time === null || time === 'auto' ?
  5356. Math.max(Math.abs(this.x - pos.left), Math.abs(this.y - pos.top)) :
  5357. time;
  5358. this.scrollTo(pos.left, pos.top, time, easing);
  5359. },
  5360. _transitionTime: function(time) {
  5361. time = time || 0;
  5362. this.scrollerStyle[utils.style.transitionDuration] = time +
  5363. 'ms';
  5364. if (!time && utils.isBadAndroid) {
  5365. this.scrollerStyle[utils.style.transitionDuration] = '0.001s';
  5366. }
  5367. // INSERT POINT: _transitionTime
  5368. },
  5369. _transitionTimingFunction: function(easing) {
  5370. this.scrollerStyle[utils.style.transitionTimingFunction] =
  5371. easing;
  5372. // INSERT POINT: _transitionTimingFunction
  5373. },
  5374. _translate: function(x, y) {
  5375. if (this.options.useTransform) {
  5376. /* REPLACE START: _translate */
  5377. this.scrollerStyle[utils.style.transform] = 'translate(' + x +
  5378. 'px,' + y + 'px)' + this.translateZ;
  5379. /* REPLACE END: _translate */
  5380. } else {
  5381. x = Math.round(x);
  5382. y = Math.round(y);
  5383. this.scrollerStyle.left = x + 'px';
  5384. this.scrollerStyle.top = y + 'px';
  5385. }
  5386. this.x = x;
  5387. this.y = y;
  5388. // INSERT POINT: _translate
  5389. },
  5390. _initEvents: function(remove) {
  5391. var eventType = remove ? utils.removeEvent : utils.addEvent,
  5392. target = this.options.bindToWrapper ? this.wrapper : window;
  5393. eventType(window, 'orientationchange', this);
  5394. eventType(window, 'resize', this);
  5395. if (this.options.click) {
  5396. eventType(this.wrapper, 'click', this, true);
  5397. }
  5398. if (!this.options.disableMouse) {
  5399. eventType(this.wrapper, 'mousedown', this);
  5400. eventType(target, 'mousemove', this);
  5401. eventType(target, 'mousecancel', this);
  5402. eventType(target, 'mouseup', this);
  5403. }
  5404. if (utils.hasPointer && !this.options.disablePointer) {
  5405. eventType(this.wrapper, utils.prefixPointerEvent(
  5406. 'pointerdown'), this);
  5407. eventType(target, utils.prefixPointerEvent('pointermove'),
  5408. this);
  5409. eventType(target, utils.prefixPointerEvent('pointercancel'),
  5410. this);
  5411. eventType(target, utils.prefixPointerEvent('pointerup'), this);
  5412. }
  5413. if (utils.hasTouch && !this.options.disableTouch) {
  5414. eventType(this.wrapper, 'touchstart', this);
  5415. eventType(target, 'touchmove', this);
  5416. eventType(target, 'touchcancel', this);
  5417. eventType(target, 'touchend', this);
  5418. }
  5419. eventType(this.scroller, 'transitionend', this);
  5420. eventType(this.scroller, 'webkitTransitionEnd', this);
  5421. eventType(this.scroller, 'oTransitionEnd', this);
  5422. eventType(this.scroller, 'MSTransitionEnd', this);
  5423. },
  5424. getComputedPosition: function() {
  5425. var matrix = window.getComputedStyle(this.scroller, null),
  5426. x, y;
  5427. if (this.options.useTransform) {
  5428. matrix = matrix[utils.style.transform].split(')')[0].split(
  5429. ', ');
  5430. x = +(matrix[12] || matrix[4]);
  5431. y = +(matrix[13] || matrix[5]);
  5432. } else {
  5433. x = +matrix.left.replace(/[^-\d.]/g, '');
  5434. y = +matrix.top.replace(/[^-\d.]/g, '');
  5435. }
  5436. return {
  5437. x: x,
  5438. y: y
  5439. };
  5440. },
  5441. _animate: function(destX, destY, duration, easingFn) {
  5442. var that = this,
  5443. startX = this.x,
  5444. startY = this.y,
  5445. startTime = utils.getTime(),
  5446. destTime = startTime + duration;
  5447. function step() {
  5448. var now = utils.getTime(),
  5449. newX, newY,
  5450. easing;
  5451. if (now >= destTime) {
  5452. that.isAnimating = false;
  5453. that._translate(destX, destY);
  5454. if (!that.resetPosition(that.options.bounceTime)) {
  5455. that._execEvent('scrollEnd');
  5456. }
  5457. return;
  5458. }
  5459. now = (now - startTime) / duration;
  5460. easing = easingFn(now);
  5461. newX = (destX - startX) * easing + startX;
  5462. newY = (destY - startY) * easing + startY;
  5463. that._translate(newX, newY);
  5464. if (that.isAnimating) {
  5465. rAF(step);
  5466. }
  5467. }
  5468. this.isAnimating = true;
  5469. step();
  5470. },
  5471. handleEvent: function(e) {
  5472. switch (e.type) {
  5473. case 'touchstart':
  5474. case 'pointerdown':
  5475. case 'MSPointerDown':
  5476. case 'mousedown':
  5477. this._start(e);
  5478. break;
  5479. case 'touchmove':
  5480. case 'pointermove':
  5481. case 'MSPointerMove':
  5482. case 'mousemove':
  5483. this._move(e);
  5484. break;
  5485. case 'touchend':
  5486. case 'pointerup':
  5487. case 'MSPointerUp':
  5488. case 'mouseup':
  5489. case 'touchcancel':
  5490. case 'pointercancel':
  5491. case 'MSPointerCancel':
  5492. case 'mousecancel':
  5493. this._end(e);
  5494. break;
  5495. case 'orientationchange':
  5496. case 'resize':
  5497. this._resize();
  5498. break;
  5499. case 'transitionend':
  5500. case 'webkitTransitionEnd':
  5501. case 'oTransitionEnd':
  5502. case 'MSTransitionEnd':
  5503. this._transitionEnd(e);
  5504. break;
  5505. case 'wheel':
  5506. case 'DOMMouseScroll':
  5507. case 'mousewheel':
  5508. this._wheel(e);
  5509. break;
  5510. case 'keydown':
  5511. this._key(e);
  5512. break;
  5513. case 'click':
  5514. if (!e._constructed) {
  5515. e.preventDefault();
  5516. e.stopPropagation();
  5517. }
  5518. break;
  5519. }
  5520. }
  5521. };
  5522. IScroll.utils = utils;
  5523. $.AMUI.iScroll = IScroll;
  5524. module.exports = IScroll;
  5525. /* jshint unused: true */
  5526. /* jshint +W101, +W116, +W109 */
  5527. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  5528. "undefined" ? self : typeof window !== "undefined" ? window : {})
  5529. }, {
  5530. "./core": 4
  5531. }
  5532. ],
  5533. 32: [
  5534. function(require, module, exports) {
  5535. (function(global) {
  5536. 'use strict';
  5537. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  5538. "undefined" ? global.jQuery : null);
  5539. var UI = require('./core');
  5540. var dimmer = require('./ui.dimmer');
  5541. var $doc = $(document);
  5542. var supportTransition = UI.support.transition;
  5543. /**
  5544. * @reference https://github.com/nolimits4web/Framework7/blob/master/src/js/modals.js
  5545. * @license https://github.com/nolimits4web/Framework7/blob/master/LICENSE
  5546. */
  5547. var Modal = function(element, options) {
  5548. this.options = $.extend({}, Modal.DEFAULTS, options || {});
  5549. this.$element = $(element);
  5550. this.$dialog = this.$element.find('.am-modal-dialog');
  5551. if (!this.$element.attr('id')) {
  5552. this.$element.attr('id', UI.utils.generateGUID('am-modal'));
  5553. }
  5554. this.isPopup = this.$element.hasClass('am-popup');
  5555. this.isActions = this.$element.hasClass('am-modal-actions');
  5556. this.active = this.transitioning = this.relatedTarget = null;
  5557. this.events();
  5558. };
  5559. Modal.DEFAULTS = {
  5560. className: {
  5561. active: 'am-modal-active',
  5562. out: 'am-modal-out'
  5563. },
  5564. selector: {
  5565. modal: '.am-modal',
  5566. active: '.am-modal-active'
  5567. },
  5568. closeViaDimmer: true,
  5569. cancelable: true,
  5570. onConfirm: function() {},
  5571. onCancel: function() {},
  5572. height: undefined,
  5573. width: undefined,
  5574. duration: 300, // must equal the CSS transition duration
  5575. transitionEnd: supportTransition && supportTransition.end +
  5576. '.modal.amui'
  5577. };
  5578. Modal.prototype.toggle = function(relatedTarget) {
  5579. return this.active ? this.close() : this.open(relatedTarget);
  5580. };
  5581. Modal.prototype.open = function(relatedTarget) {
  5582. var $element = this.$element;
  5583. var options = this.options;
  5584. var isPopup = this.isPopup;
  5585. var width = options.width;
  5586. var height = options.height;
  5587. var style = {};
  5588. if (this.active) {
  5589. return;
  5590. }
  5591. if (!this.$element.length) {
  5592. return;
  5593. }
  5594. // callback hook
  5595. relatedTarget && (this.relatedTarget = relatedTarget);
  5596. // 判断如果还在动画,就先触发之前的closed事件
  5597. if (this.transitioning) {
  5598. clearTimeout($element.transitionEndTimmer);
  5599. $element.transitionEndTimmer = null;
  5600. $element.trigger(options.transitionEnd).off(options.transitionEnd);
  5601. }
  5602. isPopup && this.$element.show();
  5603. this.active = true;
  5604. $element.trigger($.Event('open.modal.amui', {
  5605. relatedTarget: relatedTarget
  5606. }));
  5607. dimmer.open($element);
  5608. $element.show().redraw();
  5609. // apply Modal width/height if set
  5610. if (!isPopup && !this.isActions) {
  5611. if (width) {
  5612. width = parseInt(width, 10);
  5613. style.width = width + 'px';
  5614. style.marginLeft = -parseInt(width / 2) + 'px';
  5615. }
  5616. if (height) {
  5617. height = parseInt(height, 10);
  5618. // style.height = height + 'px';
  5619. style.marginTop = -parseInt(height / 2) + 'px';
  5620. // the background color is styled to $dialog
  5621. // so the height should set to $dialog
  5622. this.$dialog.css({
  5623. height: height + 'px'
  5624. });
  5625. } else {
  5626. style.marginTop = -parseInt($element.height() / 2, 10) + 'px';
  5627. }
  5628. $element.css(style);
  5629. }
  5630. $element.
  5631. removeClass(options.className.out).
  5632. addClass(options.className.active);
  5633. this.transitioning = 1;
  5634. var complete = function() {
  5635. $element.trigger($.Event('opened.modal.amui', {
  5636. relatedTarget: relatedTarget
  5637. }));
  5638. this.transitioning = 0;
  5639. };
  5640. if (!supportTransition) {
  5641. return complete.call(this);
  5642. }
  5643. $element.
  5644. one(options.transitionEnd, $.proxy(complete, this)).
  5645. emulateTransitionEnd(options.duration);
  5646. };
  5647. Modal.prototype.close = function(relatedTarget) {
  5648. if (!this.active) {
  5649. return;
  5650. }
  5651. var $element = this.$element;
  5652. var options = this.options;
  5653. var isPopup = this.isPopup;
  5654. // 判断如果还在动画,就先触发之前的opened事件
  5655. if (this.transitioning) {
  5656. clearTimeout($element.transitionEndTimmer);
  5657. $element.transitionEndTimmer = null;
  5658. $element.trigger(options.transitionEnd).off(options.transitionEnd);
  5659. dimmer.close($element, true);
  5660. }
  5661. this.$element.trigger($.Event('close.modal.amui', {
  5662. relatedTarget: relatedTarget
  5663. }));
  5664. this.transitioning = 1;
  5665. var complete = function() {
  5666. $element.trigger('closed.modal.amui');
  5667. isPopup && $element.removeClass(options.className.out);
  5668. $element.hide();
  5669. this.transitioning = 0;
  5670. // 不强制关闭 Dimmer,以便多个 Modal 可以共享 Dimmer
  5671. dimmer.close($element, false);
  5672. this.active = false;
  5673. };
  5674. $element.removeClass(options.className.active).
  5675. addClass(options.className.out);
  5676. if (!supportTransition) {
  5677. return complete.call(this);
  5678. }
  5679. $element.one(options.transitionEnd, $.proxy(complete, this)).
  5680. emulateTransitionEnd(options.duration);
  5681. };
  5682. Modal.prototype.events = function() {
  5683. var that = this;
  5684. var $element = this.$element;
  5685. var $ipt = $element.find('.am-modal-prompt-input');
  5686. var getData = function() {
  5687. var data = [];
  5688. $ipt.each(function() {
  5689. data.push($(this).val());
  5690. });
  5691. return (data.length === 0) ? undefined :
  5692. ((data.length === 1) ? data[0] : data);
  5693. };
  5694. // close via Esc key
  5695. if (this.options.cancelable) {
  5696. $element.on('keyup.modal.amui', function(e) {
  5697. if (that.active && e.which === 27) {
  5698. $element.trigger('cancel.modal.amui');
  5699. that.close();
  5700. }
  5701. });
  5702. }
  5703. // Close Modal when dimmer clicked
  5704. if (this.options.closeViaDimmer) {
  5705. dimmer.$element.on('click.dimmer.modal.amui', function(e) {
  5706. that.close();
  5707. });
  5708. }
  5709. // Close Modal when button clicked
  5710. $element.find('[data-am-modal-close], .am-modal-btn').
  5711. on('click.close.modal.amui', function(e) {
  5712. e.preventDefault();
  5713. that.close();
  5714. });
  5715. $element.find('[data-am-modal-confirm]').on(
  5716. 'click.confirm.modal.amui',
  5717. function() {
  5718. $element.trigger($.Event('confirm.modal.amui', {
  5719. trigger: this
  5720. }));
  5721. });
  5722. $element.find('[data-am-modal-cancel]').
  5723. on('click.cancel.modal.amui', function() {
  5724. $element.trigger($.Event('cancel.modal.amui', {
  5725. trigger: this
  5726. }));
  5727. });
  5728. $element.on('confirm.modal.amui', function(e) {
  5729. e.data = getData();
  5730. that.options.onConfirm.call(that, e);
  5731. }).on('cancel.modal.amui', function(e) {
  5732. e.data = getData();
  5733. that.options.onCancel.call(that, e);
  5734. });
  5735. };
  5736. function Plugin(option, relatedTarget) {
  5737. return this.each(function() {
  5738. var $this = $(this);
  5739. var data = $this.data('amui.modal');
  5740. var options = $.extend({},
  5741. Modal.DEFAULTS, typeof option == 'object' && option);
  5742. if (!data) {
  5743. $this.data('amui.modal', (data = new Modal(this, options)));
  5744. }
  5745. if (typeof option == 'string') {
  5746. data[option] && data[option](relatedTarget);
  5747. } else {
  5748. data.toggle(option && option.relatedTarget || undefined);
  5749. }
  5750. });
  5751. }
  5752. $.fn.modal = Plugin;
  5753. // Init
  5754. $doc.on('click.modal.amui.data-api', '[data-am-modal]', function() {
  5755. var $this = $(this);
  5756. var options = UI.utils.parseOptions($this.attr('data-am-modal'));
  5757. var $target = $(options.target ||
  5758. (this.href && this.href.replace(/.*(?=#[^\s]+$)/, '')));
  5759. var option = $target.data('amui.modal') ? 'toggle' : options;
  5760. Plugin.call($target, option, this);
  5761. });
  5762. $.AMUI.modal = Modal;
  5763. module.exports = Modal;
  5764. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  5765. "undefined" ? self : typeof window !== "undefined" ? window : {})
  5766. }, {
  5767. "./core": 4,
  5768. "./ui.dimmer": 28
  5769. }
  5770. ],
  5771. 33: [
  5772. function(require, module, exports) {
  5773. (function(global) {
  5774. 'use strict';
  5775. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  5776. "undefined" ? global.jQuery : null);
  5777. var UI = require('./core');
  5778. var Hammer = require('./util.hammer');
  5779. var $win = $(window);
  5780. var $doc = $(document);
  5781. var scrollPos;
  5782. /**
  5783. * @via https://github.com/uikit/uikit/blob/master/src/js/offcanvas.js
  5784. * @license https://github.com/uikit/uikit/blob/master/LICENSE.md
  5785. */
  5786. var OffCanvas = function(element, options) {
  5787. this.$element = $(element);
  5788. this.options = $.extend({}, OffCanvas.DEFAULTS, options);
  5789. this.active = null;
  5790. this.bindEvents();
  5791. };
  5792. OffCanvas.DEFAULTS = {
  5793. duration: 300,
  5794. effect: 'overlay' // {push|overlay}, push is too expensive
  5795. };
  5796. OffCanvas.prototype.open = function(relatedElement) {
  5797. var _this = this;
  5798. var $element = this.$element;
  5799. if (!$element.length || $element.hasClass('am-active')) {
  5800. return;
  5801. }
  5802. var effect = this.options.effect;
  5803. var $html = $('html');
  5804. var $body = $('body');
  5805. var $bar = $element.find('.am-offcanvas-bar').first();
  5806. var dir = $bar.hasClass('am-offcanvas-bar-flip') ? -1 : 1;
  5807. $bar.addClass('am-offcanvas-bar-' + effect);
  5808. scrollPos = {
  5809. x: window.scrollX,
  5810. y: window.scrollY
  5811. };
  5812. $element.addClass('am-active');
  5813. $body.css({
  5814. width: window.innerWidth,
  5815. height: $win.height()
  5816. }).addClass('am-offcanvas-page');
  5817. if (effect !== 'overlay') {
  5818. $body.css({
  5819. 'margin-left': $bar.outerWidth() * dir
  5820. }).width(); // force redraw
  5821. }
  5822. $html.css('margin-top', scrollPos.y * -1);
  5823. setTimeout(function() {
  5824. $bar.addClass('am-offcanvas-bar-active').width();
  5825. }, 0);
  5826. $element.trigger('open.offcanvas.amui');
  5827. this.active = 1;
  5828. // Close OffCanvas when none content area clicked
  5829. $element.on('click.offcanvas.amui', function(e) {
  5830. var $target = $(e.target);
  5831. if ($target.hasClass('am-offcanvas-bar')) {
  5832. return;
  5833. }
  5834. if ($target.parents('.am-offcanvas-bar').first().length) {
  5835. return;
  5836. }
  5837. // https://developer.mozilla.org/zh-CN/docs/DOM/event.stopImmediatePropagation
  5838. e.stopImmediatePropagation();
  5839. _this.close();
  5840. });
  5841. $html.on('keydown.offcanvas.amui', function(e) {
  5842. (e.keyCode === 27) && _this.close();
  5843. });
  5844. };
  5845. OffCanvas.prototype.close = function(relatedElement) {
  5846. var _this = this;
  5847. var $html = $('html');
  5848. var $body = $('body');
  5849. var $element = this.$element;
  5850. var $bar = $element.find('.am-offcanvas-bar').first();
  5851. if (!$element.length || !$element.hasClass('am-active')) {
  5852. return;
  5853. }
  5854. $element.trigger('close.offcanvas.amui');
  5855. function complete() {
  5856. $body.removeClass('am-offcanvas-page').
  5857. css({
  5858. width: '',
  5859. height: '',
  5860. 'margin-left': '',
  5861. 'margin-right': ''
  5862. });
  5863. $element.removeClass('am-active');
  5864. $bar.removeClass('am-offcanvas-bar-active');
  5865. $html.css('margin-top', '');
  5866. window.scrollTo(scrollPos.x, scrollPos.y);
  5867. $element.trigger('closed.offcanvas.amui');
  5868. _this.active = 0;
  5869. }
  5870. if (UI.support.transition) {
  5871. setTimeout(function() {
  5872. $bar.removeClass('am-offcanvas-bar-active');
  5873. }, 0);
  5874. $body.css('margin-left', '').one(UI.support.transition.end,
  5875. function() {
  5876. complete();
  5877. }).emulateTransitionEnd(this.options.duration);
  5878. } else {
  5879. complete();
  5880. }
  5881. $element.off('click.offcanvas.amui');
  5882. $html.off('.offcanvas.amui');
  5883. };
  5884. OffCanvas.prototype.bindEvents = function() {
  5885. var _this = this;
  5886. $doc.on('click.offcanvas.amui', '[data-am-dismiss="offcanvas"]',
  5887. function(e) {
  5888. e.preventDefault();
  5889. _this.close();
  5890. });
  5891. $win.on('resize.offcanvas.amui orientationchange.offcanvas.amui',
  5892. function() {
  5893. _this.active && _this.close();
  5894. });
  5895. this.$element.hammer().on('swipeleft swipeleft', function(e) {
  5896. e.preventDefault();
  5897. _this.close();
  5898. });
  5899. return this;
  5900. };
  5901. function Plugin(option, relatedElement) {
  5902. return this.each(function() {
  5903. var $this = $(this);
  5904. var data = $this.data('amui.offcanvas');
  5905. var options = $.extend({}, typeof option == 'object' &&
  5906. option);
  5907. if (!data) {
  5908. $this.data('amui.offcanvas', (data = new OffCanvas(this,
  5909. options)));
  5910. data.open(relatedElement);
  5911. }
  5912. if (typeof option == 'string') {
  5913. data[option] && data[option](relatedElement);
  5914. }
  5915. });
  5916. }
  5917. $.fn.offCanvas = Plugin;
  5918. // Init code
  5919. $doc.on('click.offcanvas.amui', '[data-am-offcanvas]', function(e) {
  5920. e.preventDefault();
  5921. var $this = $(this);
  5922. var options = UI.utils.parseOptions($this.data('amOffcanvas'));
  5923. var $target = $(options.target ||
  5924. (this.href && this.href.replace(/.*(?=#[^\s]+$)/, '')));
  5925. var option = $target.data('amui.offcanvas') ? 'open' : options;
  5926. Plugin.call($target, option, this);
  5927. });
  5928. $.AMUI.offcanvas = OffCanvas;
  5929. module.exports = OffCanvas;
  5930. // TODO: 优化动画效果
  5931. // http://dbushell.github.io/Responsive-Off-Canvas-Menu/step4.html
  5932. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  5933. "undefined" ? self : typeof window !== "undefined" ? window : {})
  5934. }, {
  5935. "./core": 4,
  5936. "./util.hammer": 50
  5937. }
  5938. ],
  5939. 34: [
  5940. function(require, module, exports) {
  5941. (function(global) {
  5942. 'use strict';
  5943. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  5944. "undefined" ? global.jQuery : null);
  5945. var UI = require('./core');
  5946. /**
  5947. * @via https://github.com/manuelstofer/pinchzoom/blob/master/src/pinchzoom.js
  5948. * @license the MIT License.
  5949. */
  5950. var definePinchZoom = function($) {
  5951. /**
  5952. * Pinch zoom using jQuery
  5953. * @version 0.0.2
  5954. * @author Manuel Stofer <mst@rtp.ch>
  5955. * @param el
  5956. * @param options
  5957. * @constructor
  5958. */
  5959. var PinchZoom = function(el, options) {
  5960. this.el = $(el);
  5961. this.zoomFactor = 1;
  5962. this.lastScale = 1;
  5963. this.offset = {
  5964. x: 0,
  5965. y: 0
  5966. };
  5967. this.options = $.extend({}, this.defaults, options);
  5968. this.setupMarkup();
  5969. this.bindEvents();
  5970. this.update();
  5971. // default enable.
  5972. this.enable();
  5973. },
  5974. sum = function(a, b) {
  5975. return a + b;
  5976. },
  5977. isCloseTo = function(value, expected) {
  5978. return value > expected - 0.01 && value < expected + 0.01;
  5979. };
  5980. PinchZoom.prototype = {
  5981. defaults: {
  5982. tapZoomFactor: 2,
  5983. zoomOutFactor: 1.3,
  5984. animationDuration: 300,
  5985. animationInterval: 5,
  5986. maxZoom: 5,
  5987. minZoom: 0.5,
  5988. lockDragAxis: false,
  5989. use2d: false,
  5990. zoomStartEventName: 'pz_zoomstart',
  5991. zoomEndEventName: 'pz_zoomend',
  5992. dragStartEventName: 'pz_dragstart',
  5993. dragEndEventName: 'pz_dragend',
  5994. doubleTapEventName: 'pz_doubletap'
  5995. },
  5996. /**
  5997. * Event handler for 'dragstart'
  5998. * @param event
  5999. */
  6000. handleDragStart: function(event) {
  6001. this.el.trigger(this.options.dragStartEventName);
  6002. this.stopAnimation();
  6003. this.lastDragPosition = false;
  6004. this.hasInteraction = true;
  6005. this.handleDrag(event);
  6006. },
  6007. /**
  6008. * Event handler for 'drag'
  6009. * @param event
  6010. */
  6011. handleDrag: function(event) {
  6012. if (this.zoomFactor > 1.0) {
  6013. var touch = this.getTouches(event)[0];
  6014. this.drag(touch, this.lastDragPosition);
  6015. this.offset = this.sanitizeOffset(this.offset);
  6016. this.lastDragPosition = touch;
  6017. }
  6018. },
  6019. handleDragEnd: function() {
  6020. this.el.trigger(this.options.dragEndEventName);
  6021. this.end();
  6022. },
  6023. /**
  6024. * Event handler for 'zoomstart'
  6025. * @param event
  6026. */
  6027. handleZoomStart: function(event) {
  6028. this.el.trigger(this.options.zoomStartEventName);
  6029. this.stopAnimation();
  6030. this.lastScale = 1;
  6031. this.nthZoom = 0;
  6032. this.lastZoomCenter = false;
  6033. this.hasInteraction = true;
  6034. },
  6035. /**
  6036. * Event handler for 'zoom'
  6037. * @param event
  6038. */
  6039. handleZoom: function(event, newScale) {
  6040. // a relative scale factor is used
  6041. var touchCenter = this.getTouchCenter(this.getTouches(event)),
  6042. scale = newScale / this.lastScale;
  6043. this.lastScale = newScale;
  6044. // the first touch events are thrown away since they are not precise
  6045. this.nthZoom += 1;
  6046. if (this.nthZoom > 3) {
  6047. this.scale(scale, touchCenter);
  6048. this.drag(touchCenter, this.lastZoomCenter);
  6049. }
  6050. this.lastZoomCenter = touchCenter;
  6051. },
  6052. handleZoomEnd: function() {
  6053. this.el.trigger(this.options.zoomEndEventName);
  6054. this.end();
  6055. },
  6056. /**
  6057. * Event handler for 'doubletap'
  6058. * @param event
  6059. */
  6060. handleDoubleTap: function(event) {
  6061. var center = this.getTouches(event)[0],
  6062. zoomFactor = this.zoomFactor > 1 ? 1 : this.options.tapZoomFactor,
  6063. startZoomFactor = this.zoomFactor,
  6064. updateProgress = (function(progress) {
  6065. this.scaleTo(startZoomFactor + progress * (zoomFactor -
  6066. startZoomFactor), center);
  6067. }).bind(this);
  6068. if (this.hasInteraction) {
  6069. return;
  6070. }
  6071. if (startZoomFactor > zoomFactor) {
  6072. center = this.getCurrentZoomCenter();
  6073. }
  6074. this.animate(this.options.animationDuration, this.options.animationInterval,
  6075. updateProgress, this.swing);
  6076. this.el.trigger(this.options.doubleTapEventName);
  6077. },
  6078. /**
  6079. * Max / min values for the offset
  6080. * @param offset
  6081. * @return {Object} the sanitized offset
  6082. */
  6083. sanitizeOffset: function(offset) {
  6084. var maxX = (this.zoomFactor - 1) * this.getContainerX(),
  6085. maxY = (this.zoomFactor - 1) * this.getContainerY(),
  6086. maxOffsetX = Math.max(maxX, 0),
  6087. maxOffsetY = Math.max(maxY, 0),
  6088. minOffsetX = Math.min(maxX, 0),
  6089. minOffsetY = Math.min(maxY, 0);
  6090. return {
  6091. x: Math.min(Math.max(offset.x, minOffsetX), maxOffsetX),
  6092. y: Math.min(Math.max(offset.y, minOffsetY), maxOffsetY)
  6093. };
  6094. },
  6095. /**
  6096. * Scale to a specific zoom factor (not relative)
  6097. * @param zoomFactor
  6098. * @param center
  6099. */
  6100. scaleTo: function(zoomFactor, center) {
  6101. this.scale(zoomFactor / this.zoomFactor, center);
  6102. },
  6103. /**
  6104. * Scales the element from specified center
  6105. * @param scale
  6106. * @param center
  6107. */
  6108. scale: function(scale, center) {
  6109. scale = this.scaleZoomFactor(scale);
  6110. this.addOffset({
  6111. x: (scale - 1) * (center.x + this.offset.x),
  6112. y: (scale - 1) * (center.y + this.offset.y)
  6113. });
  6114. },
  6115. /**
  6116. * Scales the zoom factor relative to current state
  6117. * @param scale
  6118. * @return the actual scale (can differ because of max min zoom factor)
  6119. */
  6120. scaleZoomFactor: function(scale) {
  6121. var originalZoomFactor = this.zoomFactor;
  6122. this.zoomFactor *= scale;
  6123. this.zoomFactor = Math.min(this.options.maxZoom, Math.max(
  6124. this.zoomFactor, this.options.minZoom));
  6125. return this.zoomFactor / originalZoomFactor;
  6126. },
  6127. /**
  6128. * Drags the element
  6129. * @param center
  6130. * @param lastCenter
  6131. */
  6132. drag: function(center, lastCenter) {
  6133. if (lastCenter) {
  6134. if (this.options.lockDragAxis) {
  6135. // lock scroll to position that was changed the most
  6136. if (Math.abs(center.x - lastCenter.x) > Math.abs(center
  6137. .y - lastCenter.y)) {
  6138. this.addOffset({
  6139. x: -(center.x - lastCenter.x),
  6140. y: 0
  6141. });
  6142. } else {
  6143. this.addOffset({
  6144. y: -(center.y - lastCenter.y),
  6145. x: 0
  6146. });
  6147. }
  6148. } else {
  6149. this.addOffset({
  6150. y: -(center.y - lastCenter.y),
  6151. x: -(center.x - lastCenter.x)
  6152. });
  6153. }
  6154. }
  6155. },
  6156. /**
  6157. * Calculates the touch center of multiple touches
  6158. * @param touches
  6159. * @return {Object}
  6160. */
  6161. getTouchCenter: function(touches) {
  6162. return this.getVectorAvg(touches);
  6163. },
  6164. /**
  6165. * Calculates the average of multiple vectors (x, y values)
  6166. */
  6167. getVectorAvg: function(vectors) {
  6168. return {
  6169. x: vectors.map(function(v) {
  6170. return v.x;
  6171. }).reduce(sum) / vectors.length,
  6172. y: vectors.map(function(v) {
  6173. return v.y;
  6174. }).reduce(sum) / vectors.length
  6175. };
  6176. },
  6177. /**
  6178. * Adds an offset
  6179. * @param offset the offset to add
  6180. * @return return true when the offset change was accepted
  6181. */
  6182. addOffset: function(offset) {
  6183. this.offset = {
  6184. x: this.offset.x + offset.x,
  6185. y: this.offset.y + offset.y
  6186. };
  6187. },
  6188. sanitize: function() {
  6189. if (this.zoomFactor < this.options.zoomOutFactor) {
  6190. this.zoomOutAnimation();
  6191. } else if (this.isInsaneOffset(this.offset)) {
  6192. this.sanitizeOffsetAnimation();
  6193. }
  6194. },
  6195. /**
  6196. * Checks if the offset is ok with the current zoom factor
  6197. * @param offset
  6198. * @return {Boolean}
  6199. */
  6200. isInsaneOffset: function(offset) {
  6201. var sanitizedOffset = this.sanitizeOffset(offset);
  6202. return sanitizedOffset.x !== offset.x ||
  6203. sanitizedOffset.y !== offset.y;
  6204. },
  6205. /**
  6206. * Creates an animation moving to a sane offset
  6207. */
  6208. sanitizeOffsetAnimation: function() {
  6209. var targetOffset = this.sanitizeOffset(this.offset),
  6210. startOffset = {
  6211. x: this.offset.x,
  6212. y: this.offset.y
  6213. },
  6214. updateProgress = (function(progress) {
  6215. this.offset.x = startOffset.x + progress * (
  6216. targetOffset.x - startOffset.x);
  6217. this.offset.y = startOffset.y + progress * (
  6218. targetOffset.y - startOffset.y);
  6219. this.update();
  6220. }).bind(this);
  6221. this.animate(
  6222. this.options.animationDuration,
  6223. this.options.animationInterval,
  6224. updateProgress,
  6225. this.swing
  6226. );
  6227. },
  6228. /**
  6229. * Zooms back to the original position,
  6230. * (no offset and zoom factor 1)
  6231. */
  6232. zoomOutAnimation: function() {
  6233. var startZoomFactor = this.zoomFactor,
  6234. zoomFactor = 1,
  6235. center = this.getCurrentZoomCenter(),
  6236. updateProgress = (function(progress) {
  6237. this.scaleTo(startZoomFactor + progress * (zoomFactor -
  6238. startZoomFactor), center);
  6239. }).bind(this);
  6240. this.animate(
  6241. this.options.animationDuration,
  6242. this.options.animationInterval,
  6243. updateProgress,
  6244. this.swing
  6245. );
  6246. },
  6247. /**
  6248. * Updates the aspect ratio
  6249. */
  6250. updateAspectRatio: function() {
  6251. // this.setContainerY(this.getContainerX() / this.getAspectRatio());
  6252. // @modified
  6253. this.setContainerY()
  6254. },
  6255. /**
  6256. * Calculates the initial zoom factor (for the element to fit into the container)
  6257. * @return the initial zoom factor
  6258. */
  6259. getInitialZoomFactor: function() {
  6260. // use .offsetWidth instead of width()
  6261. // because jQuery-width() return the original width but Zepto-width() will calculate width with transform.
  6262. // the same as .height()
  6263. return this.container[0].offsetWidth / this.el[0].offsetWidth;
  6264. },
  6265. /**
  6266. * Calculates the aspect ratio of the element
  6267. * @return the aspect ratio
  6268. */
  6269. getAspectRatio: function() {
  6270. return this.el[0].offsetWidth / this.el[0].offsetHeight;
  6271. },
  6272. /**
  6273. * Calculates the virtual zoom center for the current offset and zoom factor
  6274. * (used for reverse zoom)
  6275. * @return {Object} the current zoom center
  6276. */
  6277. getCurrentZoomCenter: function() {
  6278. // uses following formula to calculate the zoom center x value
  6279. // offset_left / offset_right = zoomcenter_x / (container_x - zoomcenter_x)
  6280. var length = this.container[0].offsetWidth * this.zoomFactor,
  6281. offsetLeft = this.offset.x,
  6282. offsetRight = length - offsetLeft - this.container[0].offsetWidth,
  6283. widthOffsetRatio = offsetLeft / offsetRight,
  6284. centerX = widthOffsetRatio * this.container[0].offsetWidth /
  6285. (widthOffsetRatio + 1),
  6286. // the same for the zoomcenter y
  6287. height = this.container[0].offsetHeight * this.zoomFactor,
  6288. offsetTop = this.offset.y,
  6289. offsetBottom = height - offsetTop - this.container[0].offsetHeight,
  6290. heightOffsetRatio = offsetTop / offsetBottom,
  6291. centerY = heightOffsetRatio * this.container[0].offsetHeight /
  6292. (heightOffsetRatio + 1);
  6293. // prevents division by zero
  6294. if (offsetRight === 0) {
  6295. centerX = this.container[0].offsetWidth;
  6296. }
  6297. if (offsetBottom === 0) {
  6298. centerY = this.container[0].offsetHeight;
  6299. }
  6300. return {
  6301. x: centerX,
  6302. y: centerY
  6303. };
  6304. },
  6305. canDrag: function() {
  6306. return !isCloseTo(this.zoomFactor, 1);
  6307. },
  6308. /**
  6309. * Returns the touches of an event relative to the container offset
  6310. * @param event
  6311. * @return array touches
  6312. */
  6313. getTouches: function(event) {
  6314. var position = this.container.offset();
  6315. return Array.prototype.slice.call(event.touches).map(
  6316. function(touch) {
  6317. return {
  6318. x: touch.pageX - position.left,
  6319. y: touch.pageY - position.top
  6320. };
  6321. });
  6322. },
  6323. /**
  6324. * Animation loop
  6325. * does not support simultaneous animations
  6326. * @param duration
  6327. * @param interval
  6328. * @param framefn
  6329. * @param timefn
  6330. * @param callback
  6331. */
  6332. animate: function(duration, interval, framefn, timefn,
  6333. callback) {
  6334. var startTime = new Date().getTime(),
  6335. renderFrame = (function() {
  6336. if (!this.inAnimation) {
  6337. return;
  6338. }
  6339. var frameTime = new Date().getTime() - startTime,
  6340. progress = frameTime / duration;
  6341. if (frameTime >= duration) {
  6342. framefn(1);
  6343. if (callback) {
  6344. callback();
  6345. }
  6346. this.update();
  6347. this.stopAnimation();
  6348. this.update();
  6349. } else {
  6350. if (timefn) {
  6351. progress = timefn(progress);
  6352. }
  6353. framefn(progress);
  6354. this.update();
  6355. setTimeout(renderFrame, interval);
  6356. }
  6357. }).bind(this);
  6358. this.inAnimation = true;
  6359. renderFrame();
  6360. },
  6361. /**
  6362. * Stops the animation
  6363. */
  6364. stopAnimation: function() {
  6365. this.inAnimation = false;
  6366. },
  6367. /**
  6368. * Swing timing function for animations
  6369. * @param p
  6370. * @return {Number}
  6371. */
  6372. swing: function(p) {
  6373. return -Math.cos(p * Math.PI) / 2 + 0.5;
  6374. },
  6375. getContainerX: function() {
  6376. // return this.container[0].offsetWidth;
  6377. // @modified
  6378. return window.innerWidth
  6379. },
  6380. getContainerY: function() {
  6381. // return this.container[0].offsetHeight;
  6382. // @modified
  6383. return window.innerHeight
  6384. },
  6385. setContainerY: function(y) {
  6386. // return this.container.height(y);
  6387. // @modified
  6388. var t = window.innerHeight;
  6389. return this.el.css({
  6390. height: t
  6391. }), this.container.height(t);
  6392. },
  6393. /**
  6394. * Creates the expected html structure
  6395. */
  6396. setupMarkup: function() {
  6397. this.container = $(
  6398. '<div class="pinch-zoom-container"></div>');
  6399. this.el.before(this.container);
  6400. this.container.append(this.el);
  6401. this.container.css({
  6402. 'overflow': 'hidden',
  6403. 'position': 'relative'
  6404. });
  6405. // Zepto doesn't recognize `webkitTransform..` style
  6406. this.el.css({
  6407. '-webkit-transform-origin': '0% 0%',
  6408. '-moz-transform-origin': '0% 0%',
  6409. '-ms-transform-origin': '0% 0%',
  6410. '-o-transform-origin': '0% 0%',
  6411. 'transform-origin': '0% 0%',
  6412. 'position': 'absolute'
  6413. });
  6414. },
  6415. end: function() {
  6416. this.hasInteraction = false;
  6417. this.sanitize();
  6418. this.update();
  6419. },
  6420. /**
  6421. * Binds all required event listeners
  6422. */
  6423. bindEvents: function() {
  6424. detectGestures(this.container.get(0), this);
  6425. // Zepto and jQuery both know about `on`
  6426. $(window).on('resize', this.update.bind(this));
  6427. $(this.el).find('img').on('load', this.update.bind(this));
  6428. },
  6429. /**
  6430. * Updates the css values according to the current zoom factor and offset
  6431. */
  6432. update: function() {
  6433. if (this.updatePlaned) {
  6434. return;
  6435. }
  6436. this.updatePlaned = true;
  6437. setTimeout((function() {
  6438. this.updatePlaned = false;
  6439. this.updateAspectRatio();
  6440. var zoomFactor = this.getInitialZoomFactor() * this.zoomFactor,
  6441. offsetX = -this.offset.x / zoomFactor,
  6442. offsetY = -this.offset.y / zoomFactor,
  6443. transform3d = 'scale3d(' + zoomFactor + ', ' +
  6444. zoomFactor + ',1) ' +
  6445. 'translate3d(' + offsetX + 'px,' + offsetY +
  6446. 'px,0px)',
  6447. transform2d = 'scale(' + zoomFactor + ', ' +
  6448. zoomFactor + ') ' +
  6449. 'translate(' + offsetX + 'px,' + offsetY + 'px)',
  6450. removeClone = (function() {
  6451. if (this.clone) {
  6452. this.clone.remove();
  6453. delete this.clone;
  6454. }
  6455. }).bind(this);
  6456. // Scale 3d and translate3d are faster (at least on ios)
  6457. // but they also reduce the quality.
  6458. // PinchZoom uses the 3d transformations during interactions
  6459. // after interactions it falls back to 2d transformations
  6460. if (!this.options.use2d || this.hasInteraction ||
  6461. this.inAnimation) {
  6462. this.is3d = true;
  6463. removeClone();
  6464. this.el.css({
  6465. '-webkit-transform': transform3d,
  6466. '-o-transform': transform2d,
  6467. '-ms-transform': transform2d,
  6468. '-moz-transform': transform2d,
  6469. 'transform': transform3d
  6470. });
  6471. } else {
  6472. // When changing from 3d to 2d transform webkit has some glitches.
  6473. // To avoid this, a copy of the 3d transformed element is displayed in the
  6474. // foreground while the element is converted from 3d to 2d transform
  6475. if (this.is3d) {
  6476. this.clone = this.el.clone();
  6477. this.clone.css('pointer-events', 'none');
  6478. this.clone.appendTo(this.container);
  6479. setTimeout(removeClone, 200);
  6480. }
  6481. this.el.css({
  6482. '-webkit-transform': transform2d,
  6483. '-o-transform': transform2d,
  6484. '-ms-transform': transform2d,
  6485. '-moz-transform': transform2d,
  6486. 'transform': transform2d
  6487. });
  6488. this.is3d = false;
  6489. }
  6490. }).bind(this), 0);
  6491. },
  6492. /**
  6493. * Enables event handling for gestures
  6494. */
  6495. enable: function() {
  6496. this.enabled = true;
  6497. },
  6498. /**
  6499. * Disables event handling for gestures
  6500. */
  6501. disable: function() {
  6502. this.enabled = false;
  6503. }
  6504. };
  6505. var detectGestures = function(el, target) {
  6506. var interaction = null,
  6507. fingers = 0,
  6508. lastTouchStart = null,
  6509. startTouches = null,
  6510. setInteraction = function(newInteraction, event) {
  6511. if (interaction !== newInteraction) {
  6512. if (interaction && !newInteraction) {
  6513. switch (interaction) {
  6514. case "zoom":
  6515. target.handleZoomEnd(event);
  6516. break;
  6517. case 'drag':
  6518. target.handleDragEnd(event);
  6519. break;
  6520. }
  6521. }
  6522. switch (newInteraction) {
  6523. case 'zoom':
  6524. target.handleZoomStart(event);
  6525. break;
  6526. case 'drag':
  6527. target.handleDragStart(event);
  6528. break;
  6529. }
  6530. }
  6531. interaction = newInteraction;
  6532. },
  6533. updateInteraction = function(event) {
  6534. if (fingers === 2) {
  6535. setInteraction('zoom');
  6536. } else if (fingers === 1 && target.canDrag()) {
  6537. setInteraction('drag', event);
  6538. } else {
  6539. setInteraction(null, event);
  6540. }
  6541. },
  6542. targetTouches = function(touches) {
  6543. return Array.prototype.slice.call(touches).map(function(
  6544. touch) {
  6545. return {
  6546. x: touch.pageX,
  6547. y: touch.pageY
  6548. };
  6549. });
  6550. },
  6551. getDistance = function(a, b) {
  6552. var x, y;
  6553. x = a.x - b.x;
  6554. y = a.y - b.y;
  6555. return Math.sqrt(x * x + y * y);
  6556. },
  6557. calculateScale = function(startTouches, endTouches) {
  6558. var startDistance = getDistance(startTouches[0],
  6559. startTouches[1]),
  6560. endDistance = getDistance(endTouches[0], endTouches[1]);
  6561. return endDistance / startDistance;
  6562. },
  6563. cancelEvent = function(event) {
  6564. event.stopPropagation();
  6565. event.preventDefault();
  6566. },
  6567. detectDoubleTap = function(event) {
  6568. var time = (new Date()).getTime();
  6569. if (fingers > 1) {
  6570. lastTouchStart = null;
  6571. }
  6572. if (time - lastTouchStart < 300) {
  6573. cancelEvent(event);
  6574. target.handleDoubleTap(event);
  6575. switch (interaction) {
  6576. case "zoom":
  6577. target.handleZoomEnd(event);
  6578. break;
  6579. case 'drag':
  6580. target.handleDragEnd(event);
  6581. break;
  6582. }
  6583. }
  6584. if (fingers === 1) {
  6585. lastTouchStart = time;
  6586. }
  6587. },
  6588. firstMove = true;
  6589. el.addEventListener('touchstart', function(event) {
  6590. if (target.enabled) {
  6591. firstMove = true;
  6592. fingers = event.touches.length;
  6593. detectDoubleTap(event);
  6594. }
  6595. });
  6596. el.addEventListener('touchmove', function(event) {
  6597. if (target.enabled) {
  6598. if (firstMove) {
  6599. updateInteraction(event);
  6600. if (interaction) {
  6601. cancelEvent(event);
  6602. }
  6603. startTouches = targetTouches(event.touches);
  6604. } else {
  6605. switch (interaction) {
  6606. case 'zoom':
  6607. target.handleZoom(event, calculateScale(
  6608. startTouches, targetTouches(event.touches)));
  6609. break;
  6610. case 'drag':
  6611. target.handleDrag(event);
  6612. break;
  6613. }
  6614. if (interaction) {
  6615. cancelEvent(event);
  6616. target.update();
  6617. }
  6618. }
  6619. firstMove = false;
  6620. }
  6621. });
  6622. el.addEventListener('touchend', function(event) {
  6623. if (target.enabled) {
  6624. fingers = event.touches.length;
  6625. updateInteraction(event);
  6626. }
  6627. });
  6628. };
  6629. return PinchZoom;
  6630. };
  6631. $.AMUI.pichzoom = definePinchZoom($);
  6632. module.exports = definePinchZoom($);
  6633. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  6634. "undefined" ? self : typeof window !== "undefined" ? window : {})
  6635. }, {
  6636. "./core": 4
  6637. }
  6638. ],
  6639. 35: [
  6640. function(require, module, exports) {
  6641. (function(global) {
  6642. 'use strict';
  6643. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  6644. "undefined" ? global.jQuery : null);
  6645. var UI = require('./core');
  6646. var $w = $(window);
  6647. /**
  6648. * @reference https://github.com/nolimits4web/Framework7/blob/master/src/js/modals.js
  6649. * @license https://github.com/nolimits4web/Framework7/blob/master/LICENSE
  6650. */
  6651. var Popover = function(element, options) {
  6652. this.options = $.extend({}, Popover.DEFAULTS, options || {});
  6653. this.$element = $(element);
  6654. this.active = null;
  6655. this.$popover = (this.options.target && $(this.options.target)) ||
  6656. null;
  6657. this.init();
  6658. this.events();
  6659. };
  6660. Popover.DEFAULTS = {
  6661. theme: undefined,
  6662. trigger: 'click',
  6663. content: '',
  6664. open: false,
  6665. target: undefined,
  6666. tpl: '<div class="am-popover">' +
  6667. '<div class="am-popover-inner"></div>' +
  6668. '<div class="am-popover-caret"></div></div>'
  6669. };
  6670. Popover.prototype.init = function() {
  6671. var me = this;
  6672. var $element = this.$element;
  6673. var $popover;
  6674. if (!this.options.target) {
  6675. this.$popover = this.getPopover();
  6676. this.setContent();
  6677. }
  6678. $popover = this.$popover;
  6679. $popover.appendTo($('body'));
  6680. this.sizePopover();
  6681. function sizePopover() {
  6682. me.sizePopover();
  6683. }
  6684. // TODO: 监听页面内容变化,重新调整位置
  6685. $element.on('open.popover.amui', function() {
  6686. $(window).on('resize.popover.amui', UI.utils.debounce(
  6687. sizePopover, 50));
  6688. });
  6689. $element.on('close.popover.amui', function() {
  6690. $(window).off('resize.popover.amui', sizePopover);
  6691. });
  6692. this.options.open && this.open();
  6693. };
  6694. Popover.prototype.sizePopover = function sizePopover() {
  6695. var $element = this.$element;
  6696. var $popover = this.$popover;
  6697. if (!$popover || !$popover.length) {
  6698. return;
  6699. }
  6700. var popWidth = $popover.outerWidth();
  6701. var popHeight = $popover.outerHeight();
  6702. var $popCaret = $popover.find('.am-popover-caret');
  6703. var popCaretSize = ($popCaret.outerWidth() / 2) || 8;
  6704. // 取不到 $popCaret.outerHeight() 的值,所以直接加 8
  6705. var popTotalHeight = popHeight + 8; // $popCaret.outerHeight();
  6706. var triggerWidth = $element.outerWidth();
  6707. var triggerHeight = $element.outerHeight();
  6708. var triggerOffset = $element.offset();
  6709. var triggerRect = $element[0].getBoundingClientRect();
  6710. var winHeight = $w.height();
  6711. var winWidth = $w.width();
  6712. var popTop = 0;
  6713. var popLeft = 0;
  6714. var diff = 0;
  6715. var spacing = 2;
  6716. var popPosition = 'top';
  6717. $popover.css({
  6718. left: '',
  6719. top: ''
  6720. }).removeClass('am-popover-left ' +
  6721. 'am-popover-right am-popover-top am-popover-bottom');
  6722. $popCaret.css({
  6723. left: '',
  6724. top: ''
  6725. });
  6726. if (popTotalHeight - spacing < triggerRect.top + spacing) {
  6727. // Popover on the top of trigger
  6728. popTop = triggerOffset.top - popTotalHeight - spacing;
  6729. } else if (popTotalHeight <
  6730. winHeight - triggerRect.top - triggerRect.height) {
  6731. // On bottom
  6732. popPosition = 'bottom';
  6733. popTop = triggerOffset.top + triggerHeight + popCaretSize +
  6734. spacing;
  6735. } else { // On middle
  6736. popPosition = 'middle';
  6737. popTop = triggerHeight / 2 + triggerOffset.top - popHeight / 2;
  6738. }
  6739. // Horizontal Position
  6740. if (popPosition === 'top' || popPosition === 'bottom') {
  6741. popLeft = triggerWidth / 2 + triggerOffset.left - popWidth / 2;
  6742. diff = popLeft;
  6743. if (popLeft < 5) {
  6744. popLeft = 5;
  6745. }
  6746. if (popLeft + popWidth > winWidth) {
  6747. popLeft = (winWidth - popWidth - 20);
  6748. // console.log('left %d, win %d, popw %d', popLeft, winWidth, popWidth);
  6749. }
  6750. if (popPosition === 'top') {
  6751. // This is the Popover position, NOT caret position
  6752. // Popover on the Top of trigger, caret on the bottom of Popover
  6753. $popover.addClass('am-popover-top');
  6754. }
  6755. if (popPosition === 'bottom') {
  6756. $popover.addClass('am-popover-bottom');
  6757. }
  6758. diff = diff - popLeft;
  6759. $popCaret.css({
  6760. left: (popWidth / 2 - popCaretSize + diff) + 'px'
  6761. });
  6762. } else if (popPosition === 'middle') {
  6763. popLeft = triggerOffset.left - popWidth - popCaretSize;
  6764. $popover.addClass('am-popover-left');
  6765. if (popLeft < 5) {
  6766. popLeft = triggerOffset.left + triggerWidth + popCaretSize;
  6767. $popover.removeClass('am-popover-left').addClass(
  6768. 'am-popover-right');
  6769. }
  6770. if (popLeft + popWidth > winWidth) {
  6771. popLeft = winWidth - popWidth - 5;
  6772. $popover.removeClass('am-popover-left').addClass(
  6773. 'am-popover-right');
  6774. }
  6775. $popCaret.css({
  6776. top: (popHeight / 2 - popCaretSize / 2) + 'px'
  6777. });
  6778. }
  6779. // Apply position style
  6780. $popover.css({
  6781. top: popTop + 'px',
  6782. left: popLeft + 'px'
  6783. });
  6784. };
  6785. Popover.prototype.toggle = function() {
  6786. return this[this.active ? 'close' : 'open']();
  6787. };
  6788. Popover.prototype.open = function() {
  6789. var $popover = this.$popover;
  6790. this.$element.trigger('open.popover.amui');
  6791. this.sizePopover();
  6792. $popover.show().addClass('am-active');
  6793. this.active = true;
  6794. };
  6795. Popover.prototype.close = function() {
  6796. var $popover = this.$popover;
  6797. this.$element.trigger('close.popover.amui');
  6798. $popover.
  6799. removeClass('am-active').
  6800. trigger('closed.popover.amui').
  6801. hide();
  6802. this.active = false;
  6803. };
  6804. Popover.prototype.getPopover = function() {
  6805. var uid = UI.utils.generateGUID('am-popover');
  6806. var theme = [];
  6807. if (this.options.theme) {
  6808. $.each(this.options.theme.split(','), function(i, item) {
  6809. theme.push('am-popover-' + $.trim(item));
  6810. });
  6811. }
  6812. return $(this.options.tpl).attr('id', uid).addClass(theme.join(
  6813. ' '));
  6814. };
  6815. Popover.prototype.setContent = function(content) {
  6816. content = content || this.options.content;
  6817. this.$popover && this.$popover.find('.am-popover-inner').empty().
  6818. html(content);
  6819. };
  6820. Popover.prototype.events = function() {
  6821. var eventNS = 'popover.amui';
  6822. var triggers = this.options.trigger.split(' ');
  6823. for (var i = triggers.length; i--;) {
  6824. var trigger = triggers[i];
  6825. if (trigger === 'click') {
  6826. this.$element.on('click.' + eventNS, $.proxy(this.toggle,
  6827. this));
  6828. } else { // hover or focus
  6829. var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
  6830. var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
  6831. this.$element.on(eventIn + '.' + eventNS, $.proxy(this.open,
  6832. this));
  6833. this.$element.on(eventOut + '.' + eventNS, $.proxy(this.close,
  6834. this));
  6835. }
  6836. }
  6837. };
  6838. function Plugin(option) {
  6839. return this.each(function() {
  6840. var $this = $(this);
  6841. var data = $this.data('amui.popover');
  6842. var options = $.extend({},
  6843. UI.utils.parseOptions($this.attr('data-am-popover')),
  6844. typeof option == 'object' && option);
  6845. if (!data) {
  6846. $this.data('amui.popover', (data = new Popover(this,
  6847. options)));
  6848. }
  6849. if (typeof option == 'string') {
  6850. data[option] && data[option]();
  6851. }
  6852. });
  6853. }
  6854. $.fn.popover = Plugin;
  6855. // Init code
  6856. UI.ready(function(context) {
  6857. $('[data-am-popover]', context).popover();
  6858. });
  6859. $.AMUI.popover = Popover;
  6860. module.exports = Popover;
  6861. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  6862. "undefined" ? self : typeof window !== "undefined" ? window : {})
  6863. }, {
  6864. "./core": 4
  6865. }
  6866. ],
  6867. 36: [
  6868. function(require, module, exports) {
  6869. (function(global) {
  6870. 'use strict';
  6871. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  6872. "undefined" ? global.jQuery : null);
  6873. var UI = require('./core');
  6874. var Progress = (function() {
  6875. /**
  6876. * NProgress (c) 2013, Rico Sta. Cruz
  6877. * @via http://ricostacruz.com/nprogress
  6878. */
  6879. var NProgress = {};
  6880. var $html = $('html');
  6881. NProgress.version = '0.1.6';
  6882. var Settings = NProgress.settings = {
  6883. minimum: 0.08,
  6884. easing: 'ease',
  6885. positionUsing: '',
  6886. speed: 200,
  6887. trickle: true,
  6888. trickleRate: 0.02,
  6889. trickleSpeed: 800,
  6890. showSpinner: true,
  6891. parent: 'body',
  6892. barSelector: '[role="nprogress-bar"]',
  6893. spinnerSelector: '[role="nprogress-spinner"]',
  6894. template: '<div class="nprogress-bar" role="nprogress-bar">' +
  6895. '<div class="nprogress-peg"></div></div>' +
  6896. '<div class="nprogress-spinner" role="nprogress-spinner">' +
  6897. '<div class="nprogress-spinner-icon"></div></div>'
  6898. };
  6899. /**
  6900. * Updates configuration.
  6901. *
  6902. * NProgress.configure({
  6903. * minimum: 0.1
  6904. * });
  6905. */
  6906. NProgress.configure = function(options) {
  6907. var key, value;
  6908. for (key in options) {
  6909. value = options[key];
  6910. if (value !== undefined && options.hasOwnProperty(key))
  6911. Settings[key] = value;
  6912. }
  6913. return this;
  6914. };
  6915. /**
  6916. * Last number.
  6917. */
  6918. NProgress.status = null;
  6919. /**
  6920. * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
  6921. *
  6922. * NProgress.set(0.4);
  6923. * NProgress.set(1.0);
  6924. */
  6925. NProgress.set = function(n) {
  6926. var started = NProgress.isStarted();
  6927. n = clamp(n, Settings.minimum, 1);
  6928. NProgress.status = (n === 1 ? null : n);
  6929. var progress = NProgress.render(!started),
  6930. bar = progress.querySelector(Settings.barSelector),
  6931. speed = Settings.speed,
  6932. ease = Settings.easing;
  6933. progress.offsetWidth;
  6934. /* Repaint */
  6935. queue(function(next) {
  6936. // Set positionUsing if it hasn't already been set
  6937. if (Settings.positionUsing === '') Settings.positionUsing =
  6938. NProgress.getPositioningCSS();
  6939. // Add transition
  6940. css(bar, barPositionCSS(n, speed, ease));
  6941. if (n === 1) {
  6942. // Fade out
  6943. css(progress, {
  6944. transition: 'none',
  6945. opacity: 1
  6946. });
  6947. progress.offsetWidth;
  6948. /* Repaint */
  6949. setTimeout(function() {
  6950. css(progress, {
  6951. transition: 'all ' + speed + 'ms linear',
  6952. opacity: 0
  6953. });
  6954. setTimeout(function() {
  6955. NProgress.remove();
  6956. next();
  6957. }, speed);
  6958. }, speed);
  6959. } else {
  6960. setTimeout(next, speed);
  6961. }
  6962. });
  6963. return this;
  6964. };
  6965. NProgress.isStarted = function() {
  6966. return typeof NProgress.status === 'number';
  6967. };
  6968. /**
  6969. * Shows the progress bar.
  6970. * This is the same as setting the status to 0%, except that it doesn't go backwards.
  6971. *
  6972. * NProgress.start();
  6973. *
  6974. */
  6975. NProgress.start = function() {
  6976. if (!NProgress.status) NProgress.set(0);
  6977. var work = function() {
  6978. setTimeout(function() {
  6979. if (!NProgress.status) return;
  6980. NProgress.trickle();
  6981. work();
  6982. }, Settings.trickleSpeed);
  6983. };
  6984. if (Settings.trickle) work();
  6985. return this;
  6986. };
  6987. /**
  6988. * Hides the progress bar.
  6989. * This is the *sort of* the same as setting the status to 100%, with the
  6990. * difference being `done()` makes some placebo effect of some realistic motion.
  6991. *
  6992. * NProgress.done();
  6993. *
  6994. * If `true` is passed, it will show the progress bar even if its hidden.
  6995. *
  6996. * NProgress.done(true);
  6997. */
  6998. NProgress.done = function(force) {
  6999. if (!force && !NProgress.status) return this;
  7000. return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
  7001. };
  7002. /**
  7003. * Increments by a random amount.
  7004. */
  7005. NProgress.inc = function(amount) {
  7006. var n = NProgress.status;
  7007. if (!n) {
  7008. return NProgress.start();
  7009. } else {
  7010. if (typeof amount !== 'number') {
  7011. amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);
  7012. }
  7013. n = clamp(n + amount, 0, 0.994);
  7014. return NProgress.set(n);
  7015. }
  7016. };
  7017. NProgress.trickle = function() {
  7018. return NProgress.inc(Math.random() * Settings.trickleRate);
  7019. };
  7020. /**
  7021. * (Internal) renders the progress bar markup based on the `template`
  7022. * setting.
  7023. */
  7024. NProgress.render = function(fromStart) {
  7025. if (NProgress.isRendered()) return document.getElementById(
  7026. 'nprogress');
  7027. $html.addClass('nprogress-busy');
  7028. var progress = document.createElement('div');
  7029. progress.id = 'nprogress';
  7030. progress.innerHTML = Settings.template;
  7031. var bar = progress.querySelector(Settings.barSelector),
  7032. perc = fromStart ? '-100' : toBarPerc(NProgress.status ||
  7033. 0),
  7034. parent = document.querySelector(Settings.parent),
  7035. spinner;
  7036. css(bar, {
  7037. transition: 'all 0 linear',
  7038. transform: 'translate3d(' + perc + '%,0,0)'
  7039. });
  7040. if (!Settings.showSpinner) {
  7041. spinner = progress.querySelector(Settings.spinnerSelector);
  7042. spinner && $(spinner).remove();
  7043. }
  7044. if (parent != document.body) {
  7045. $(parent).addClass('nprogress-custom-parent');
  7046. }
  7047. parent.appendChild(progress);
  7048. return progress;
  7049. };
  7050. /**
  7051. * Removes the element. Opposite of render().
  7052. */
  7053. NProgress.remove = function() {
  7054. $html.removeClass('nprogress-busy');
  7055. $(Settings.parent).removeClass('nprogress-custom-parent');
  7056. var progress = document.getElementById('nprogress');
  7057. progress && $(progress).remove();
  7058. };
  7059. /**
  7060. * Checks if the progress bar is rendered.
  7061. */
  7062. NProgress.isRendered = function() {
  7063. return !!document.getElementById('nprogress');
  7064. };
  7065. /**
  7066. * Determine which positioning CSS rule to use.
  7067. */
  7068. NProgress.getPositioningCSS = function() {
  7069. // Sniff on document.body.style
  7070. var bodyStyle = document.body.style;
  7071. // Sniff prefixes
  7072. var vendorPrefix = ('WebkitTransform' in bodyStyle) ?
  7073. 'Webkit' :
  7074. ('MozTransform' in bodyStyle) ? 'Moz' :
  7075. ('msTransform' in bodyStyle) ? 'ms' :
  7076. ('OTransform' in bodyStyle) ? 'O' : '';
  7077. if (vendorPrefix + 'Perspective' in bodyStyle) {
  7078. // Modern browsers with 3D support, e.g. Webkit, IE10
  7079. return 'translate3d';
  7080. } else if (vendorPrefix + 'Transform' in bodyStyle) {
  7081. // Browsers without 3D support, e.g. IE9
  7082. return 'translate';
  7083. } else {
  7084. // Browsers without translate() support, e.g. IE7-8
  7085. return 'margin';
  7086. }
  7087. };
  7088. /**
  7089. * Helpers
  7090. */
  7091. function clamp(n, min, max) {
  7092. if (n < min) return min;
  7093. if (n > max) return max;
  7094. return n;
  7095. }
  7096. /**
  7097. * (Internal) converts a percentage (`0..1`) to a bar translateX
  7098. * percentage (`-100%..0%`).
  7099. */
  7100. function toBarPerc(n) {
  7101. return (-1 + n) * 100;
  7102. }
  7103. /**
  7104. * (Internal) returns the correct CSS for changing the bar's
  7105. * position given an n percentage, and speed and ease from Settings
  7106. */
  7107. function barPositionCSS(n, speed, ease) {
  7108. var barCSS;
  7109. if (Settings.positionUsing === 'translate3d') {
  7110. barCSS = {
  7111. transform: 'translate3d(' + toBarPerc(n) + '%,0,0)'
  7112. };
  7113. } else if (Settings.positionUsing === 'translate') {
  7114. barCSS = {
  7115. transform: 'translate(' + toBarPerc(n) + '%,0)'
  7116. };
  7117. } else {
  7118. barCSS = {
  7119. 'margin-left': toBarPerc(n) + '%'
  7120. };
  7121. }
  7122. barCSS.transition = 'all ' + speed + 'ms ' + ease;
  7123. return barCSS;
  7124. }
  7125. /**
  7126. * (Internal) Queues a function to be executed.
  7127. */
  7128. var queue = (function() {
  7129. var pending = [];
  7130. function next() {
  7131. var fn = pending.shift();
  7132. if (fn) {
  7133. fn(next);
  7134. }
  7135. }
  7136. return function(fn) {
  7137. pending.push(fn);
  7138. if (pending.length == 1) next();
  7139. };
  7140. })();
  7141. /**
  7142. * (Internal) Applies css properties to an element, similar to the jQuery
  7143. * css method.
  7144. *
  7145. * While this helper does assist with vendor prefixed property names, it
  7146. * does not perform any manipulation of values prior to setting styles.
  7147. */
  7148. var css = (function() {
  7149. var cssPrefixes = ['Webkit', 'O', 'Moz', 'ms'],
  7150. cssProps = {};
  7151. function camelCase(string) {
  7152. return string.replace(/^-ms-/, 'ms-').replace(
  7153. /-([\da-z])/gi, function(match, letter) {
  7154. return letter.toUpperCase();
  7155. });
  7156. }
  7157. function getVendorProp(name) {
  7158. var style = document.body.style;
  7159. if (name in style) return name;
  7160. var i = cssPrefixes.length,
  7161. capName = name.charAt(0).toUpperCase() + name.slice(
  7162. 1),
  7163. vendorName;
  7164. while (i--) {
  7165. vendorName = cssPrefixes[i] + capName;
  7166. if (vendorName in style) return vendorName;
  7167. }
  7168. return name;
  7169. }
  7170. function getStyleProp(name) {
  7171. name = camelCase(name);
  7172. return cssProps[name] || (cssProps[name] =
  7173. getVendorProp(name));
  7174. }
  7175. function applyCss(element, prop, value) {
  7176. prop = getStyleProp(prop);
  7177. element.style[prop] = value;
  7178. }
  7179. return function(element, properties) {
  7180. var args = arguments,
  7181. prop,
  7182. value;
  7183. if (args.length == 2) {
  7184. for (prop in properties) {
  7185. value = properties[prop];
  7186. if (value !== undefined && properties.hasOwnProperty(
  7187. prop)) applyCss(element, prop, value);
  7188. }
  7189. } else {
  7190. applyCss(element, args[1], args[2]);
  7191. }
  7192. }
  7193. })();
  7194. return NProgress;
  7195. })();
  7196. $.AMUI.progress = Progress;
  7197. module.exports = Progress;
  7198. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  7199. "undefined" ? self : typeof window !== "undefined" ? window : {})
  7200. }, {
  7201. "./core": 4
  7202. }
  7203. ],
  7204. 37: [
  7205. function(require, module, exports) {
  7206. (function(global) {
  7207. 'use strict';
  7208. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  7209. "undefined" ? global.jQuery : null);
  7210. var UI = require('./core');
  7211. var PinchZoom = require('./ui.pinchzoom');
  7212. var Hammer = require('./util.hammer');
  7213. var animation = UI.support.animation;
  7214. var transition = UI.support.transition;
  7215. /**
  7216. * PureView
  7217. * @desc Image browser for Mobile
  7218. * @param element
  7219. * @param options
  7220. * @constructor
  7221. */
  7222. var PureView = function(element, options) {
  7223. this.$element = $(element);
  7224. this.$body = $(document.body);
  7225. this.options = $.extend({}, PureView.DEFAULTS, options);
  7226. this.$pureview = $(this.options.tpl).attr('id',
  7227. UI.utils.generateGUID('am-pureview'));
  7228. this.$slides = null;
  7229. this.transitioning = null;
  7230. this.scrollbarWidth = 0;
  7231. this.init();
  7232. };
  7233. PureView.DEFAULTS = {
  7234. tpl: '<div class="am-pureview am-pureview-bar-active">' +
  7235. '<ul class="am-pureview-slider"></ul>' +
  7236. '<ul class="am-pureview-direction">' +
  7237. '<li class="am-pureview-prev"><a href=""></a></li>' +
  7238. '<li class="am-pureview-next"><a href=""></a></li></ul>' +
  7239. '<ol class="am-pureview-nav"></ol>' +
  7240. '<div class="am-pureview-bar am-active">' +
  7241. '<span class="am-pureview-title"></span>' +
  7242. '<div class="am-pureview-counter"><span class="am-pureview-current"></span> / ' +
  7243. '<span class="am-pureview-total"></span></div></div>' +
  7244. '<div class="am-pureview-actions am-active">' +
  7245. '<a href="javascript: void(0)" class="am-icon-chevron-left" ' +
  7246. 'data-am-close="pureview"></a></div>' +
  7247. '</div>',
  7248. className: {
  7249. prevSlide: 'am-pureview-slide-prev',
  7250. nextSlide: 'am-pureview-slide-next',
  7251. onlyOne: 'am-pureview-only',
  7252. active: 'am-active',
  7253. barActive: 'am-pureview-bar-active',
  7254. activeBody: 'am-pureview-active'
  7255. },
  7256. selector: {
  7257. slider: '.am-pureview-slider',
  7258. close: '[data-am-close="pureview"]',
  7259. total: '.am-pureview-total',
  7260. current: '.am-pureview-current',
  7261. title: '.am-pureview-title',
  7262. actions: '.am-pureview-actions',
  7263. bar: '.am-pureview-bar',
  7264. pinchZoom: '.am-pinch-zoom',
  7265. nav: '.am-pureview-nav'
  7266. },
  7267. shareBtn: false,
  7268. // press to toggle Toolbar
  7269. toggleToolbar: true,
  7270. // 从何处获取图片,img 可以使用 data-rel 指定大图
  7271. target: 'img',
  7272. // 微信 Webview 中调用微信的图片浏览器
  7273. // 实现图片保存、分享好友、收藏图片等功能
  7274. weChatImagePreview: true
  7275. };
  7276. PureView.prototype.init = function() {
  7277. var _this = this;
  7278. var options = this.options;
  7279. var $element = this.$element;
  7280. var $pureview = this.$pureview;
  7281. this.refreshSlides();
  7282. $('body').append($pureview);
  7283. this.$title = $pureview.find(options.selector.title);
  7284. this.$current = $pureview.find(options.selector.current);
  7285. this.$bar = $pureview.find(options.selector.bar);
  7286. this.$actions = $pureview.find(options.selector.actions);
  7287. if (options.shareBtn) {
  7288. this.$actions.append('<a href="javascript: void(0)" ' +
  7289. 'class="am-icon-share-square-o" data-am-toggle="share"></a>');
  7290. }
  7291. this.$element.on('click.pureview.amui', options.target, function(
  7292. e) {
  7293. e.preventDefault();
  7294. var clicked = _this.$images.index(this);
  7295. // Invoke WeChat ImagePreview in WeChat
  7296. // TODO: detect WeChat before init
  7297. if (options.weChatImagePreview && window.WeixinJSBridge) {
  7298. window.WeixinJSBridge.invoke('imagePreview', {
  7299. current: _this.imgUrls[clicked],
  7300. urls: _this.imgUrls
  7301. });
  7302. } else {
  7303. _this.open(clicked);
  7304. }
  7305. });
  7306. $pureview.find('.am-pureview-direction').
  7307. on('click.direction.pureview.amui', 'li', function(e) {
  7308. e.preventDefault();
  7309. if ($(this).is('.am-pureview-prev')) {
  7310. _this.prevSlide();
  7311. } else {
  7312. _this.nextSlide();
  7313. }
  7314. });
  7315. // Nav Contorl
  7316. $pureview.find(options.selector.nav).on('click.nav.pureview.amui',
  7317. 'li',
  7318. function() {
  7319. var index = _this.$navItems.index($(this));
  7320. _this.activate(_this.$slides.eq(index));
  7321. });
  7322. // Close Icon
  7323. $pureview.find(options.selector.close).
  7324. on('click.close.pureview.amui', function(e) {
  7325. e.preventDefault();
  7326. _this.close();
  7327. });
  7328. this.$slider.hammer().on('swipeleft.pureview.amui', function(e) {
  7329. e.preventDefault();
  7330. _this.nextSlide();
  7331. }).on('swiperight.pureview.amui', function(e) {
  7332. e.preventDefault();
  7333. _this.prevSlide();
  7334. }).on('press.pureview.amui', function(e) {
  7335. e.preventDefault();
  7336. options.toggleToolbar && _this.toggleToolBar();
  7337. });
  7338. this.$slider.data('hammer').get('swipe').set({
  7339. direction: Hammer.DIRECTION_HORIZONTAL,
  7340. velocity: 0.35
  7341. });
  7342. // Observe DOM
  7343. $element.DOMObserve({
  7344. childList: true,
  7345. subtree: true
  7346. }, function(mutations, observer) {
  7347. // _this.refreshSlides();
  7348. // console.log('mutations[0].type);
  7349. });
  7350. // NOTE:
  7351. // trigger this event manually if MutationObserver not supported
  7352. // when new images appended, or call refreshSlides()
  7353. // if (!UI.support.mutationobserver) $element.trigger('changed.dom.amui')
  7354. $element.on('changed.dom.amui', function(e) {
  7355. e.stopPropagation();
  7356. _this.refreshSlides();
  7357. });
  7358. $(document).on('keydown.pureview.amui', $.proxy(function(e) {
  7359. var keyCode = e.keyCode;
  7360. if (keyCode == 37) {
  7361. this.prevSlide();
  7362. } else if (keyCode == 39) {
  7363. this.nextSlide();
  7364. } else if (keyCode == 27) {
  7365. this.close();
  7366. }
  7367. }, this));
  7368. };
  7369. PureView.prototype.refreshSlides = function() {
  7370. // update images collections
  7371. this.$images = this.$element.find(this.options.target);
  7372. var _this = this;
  7373. var options = this.options;
  7374. var $pureview = this.$pureview;
  7375. var $slides = $([]);
  7376. var $navItems = $([]);
  7377. var $images = this.$images;
  7378. var total = $images.length;
  7379. this.$slider = $pureview.find(options.selector.slider);
  7380. this.$nav = $pureview.find(options.selector.nav);
  7381. this.imgUrls = []; // for WeChat Image Preview
  7382. var viewedFlag = 'data-am-pureviewed';
  7383. if (!total) {
  7384. return;
  7385. }
  7386. if (total === 1) {
  7387. $pureview.addClass(options.className.onlyOne);
  7388. }
  7389. $images.not('[' + viewedFlag + ']').each(function(i, item) {
  7390. var src;
  7391. var title;
  7392. // get image URI from link's href attribute
  7393. if (item.nodeName === 'A') {
  7394. src = item.href; // to absolute path
  7395. title = item.title || '';
  7396. } else {
  7397. src = $(item).data('rel') || item.src; // <img src='' data-rel='' />
  7398. title = $(item).attr('alt') || '';
  7399. }
  7400. // add pureviewed flag
  7401. item.setAttribute(viewedFlag, '1');
  7402. // hide bar: wechat_webview_type=1
  7403. // http://tmt.io/wechat/ not working?
  7404. _this.imgUrls.push(src);
  7405. $slides = $slides.add($('<li data-src="' + src +
  7406. '" data-title="' + title +
  7407. '"></li>'));
  7408. $navItems = $navItems.add($('<li>' + (i + 1) + '</li>'));
  7409. });
  7410. $pureview.find(options.selector.total).text(total);
  7411. this.$slider.append($slides);
  7412. this.$nav.append($navItems);
  7413. this.$navItems = this.$nav.find('li');
  7414. this.$slides = this.$slider.find('li');
  7415. };
  7416. PureView.prototype.loadImage = function($slide, callback) {
  7417. var appendedFlag = 'image-appended';
  7418. if (!$slide.data(appendedFlag)) {
  7419. var $img = $('<img>', {
  7420. src: $slide.data('src'),
  7421. alt: $slide.data('title')
  7422. });
  7423. $slide.html($img).wrapInner('<div class="am-pinch-zoom"></div>')
  7424. .redraw();
  7425. var $pinchWrapper = $slide.find(this.options.selector.pinchZoom);
  7426. $pinchWrapper.data('amui.pinchzoom', new PinchZoom(
  7427. $pinchWrapper[0], {}));
  7428. $slide.data('image-appended', true);
  7429. }
  7430. callback && callback.call(this);
  7431. };
  7432. PureView.prototype.activate = function($slide) {
  7433. var options = this.options;
  7434. var $slides = this.$slides;
  7435. var activeIndex = $slides.index($slide);
  7436. var title = $slide.data('title') || '';
  7437. var active = options.className.active;
  7438. if ($slides.find('.' + active).is($slide)) {
  7439. return;
  7440. }
  7441. if (this.transitioning) {
  7442. return;
  7443. }
  7444. this.loadImage($slide, function() {
  7445. UI.utils.imageLoader($slide.find('img'), function(image) {
  7446. $(image).addClass('am-img-loaded');
  7447. });
  7448. });
  7449. this.transitioning = 1;
  7450. this.$title.text(title);
  7451. this.$current.text(activeIndex + 1);
  7452. $slides.removeClass();
  7453. $slide.addClass(active);
  7454. $slides.eq(activeIndex - 1).addClass(options.className.prevSlide);
  7455. $slides.eq(activeIndex + 1).addClass(options.className.nextSlide);
  7456. this.$navItems.removeClass().
  7457. eq(activeIndex).addClass(options.className.active);
  7458. if (transition) {
  7459. $slide.one(transition.end, $.proxy(function() {
  7460. this.transitioning = 0;
  7461. }, this)).emulateTransitionEnd(300);
  7462. } else {
  7463. this.transitioning = 0;
  7464. }
  7465. // TODO: pre-load next image
  7466. };
  7467. PureView.prototype.nextSlide = function() {
  7468. if (this.$slides.length === 1) {
  7469. return;
  7470. }
  7471. var $slides = this.$slides;
  7472. var $active = $slides.filter('.am-active');
  7473. var activeIndex = $slides.index($active);
  7474. var rightSpring = 'am-animation-right-spring';
  7475. if (activeIndex + 1 >= $slides.length) { // last one
  7476. animation && $active.addClass(rightSpring).on(animation.end,
  7477. function() {
  7478. $active.removeClass(rightSpring);
  7479. });
  7480. } else {
  7481. this.activate($slides.eq(activeIndex + 1));
  7482. }
  7483. };
  7484. PureView.prototype.prevSlide = function() {
  7485. if (this.$slides.length === 1) {
  7486. return;
  7487. }
  7488. var $slides = this.$slides;
  7489. var $active = $slides.filter('.am-active');
  7490. var activeIndex = this.$slides.index(($active));
  7491. var leftSpring = 'am-animation-left-spring';
  7492. if (activeIndex === 0) { // first one
  7493. animation && $active.addClass(leftSpring).on(animation.end,
  7494. function() {
  7495. $active.removeClass(leftSpring);
  7496. });
  7497. } else {
  7498. this.activate($slides.eq(activeIndex - 1));
  7499. }
  7500. };
  7501. PureView.prototype.toggleToolBar = function() {
  7502. this.$pureview.toggleClass(this.options.className.barActive);
  7503. };
  7504. PureView.prototype.open = function(index) {
  7505. var active = index || 0;
  7506. this.checkScrollbar();
  7507. this.setScrollbar();
  7508. this.activate(this.$slides.eq(active));
  7509. this.$pureview.show().redraw().addClass(this.options.className.active);
  7510. this.$body.addClass(this.options.className.activeBody);
  7511. };
  7512. PureView.prototype.close = function() {
  7513. var options = this.options;
  7514. this.$pureview.removeClass(options.className.active);
  7515. this.$slides.removeClass();
  7516. function resetBody() {
  7517. this.$pureview.hide();
  7518. this.$body.removeClass(options.className.activeBody);
  7519. this.resetScrollbar();
  7520. }
  7521. if (transition) {
  7522. this.$pureview.one(transition.end, $.proxy(resetBody, this)).
  7523. emulateTransitionEnd(300);
  7524. } else {
  7525. resetBody.call(this);
  7526. }
  7527. };
  7528. PureView.prototype.checkScrollbar = function() {
  7529. this.scrollbarWidth = UI.utils.measureScrollbar();
  7530. };
  7531. PureView.prototype.setScrollbar = function() {
  7532. var bodyPaddingRight = parseInt((this.$body.css('padding-right') ||
  7533. 0), 10);
  7534. if (this.scrollbarWidth) {
  7535. this.$body.css('padding-right', bodyPaddingRight + this.scrollbarWidth);
  7536. }
  7537. };
  7538. PureView.prototype.resetScrollbar = function() {
  7539. this.$body.css('padding-right', '');
  7540. };
  7541. function Plugin(option) {
  7542. return this.each(function() {
  7543. var $this = $(this);
  7544. var data = $this.data('amui.pureview');
  7545. var options = $.extend({},
  7546. UI.utils.parseOptions($this.data('amPureview')),
  7547. typeof option == 'object' && option);
  7548. if (!data) {
  7549. $this.data('amui.pureview', (data = new PureView(this,
  7550. options)));
  7551. }
  7552. if (typeof option == 'string') {
  7553. data[option]();
  7554. }
  7555. });
  7556. }
  7557. $.fn.pureview = Plugin;
  7558. // Init code
  7559. UI.ready(function(context) {
  7560. $('[data-am-pureview]', context).pureview();
  7561. });
  7562. $.AMUI.pureview = PureView;
  7563. module.exports = PureView;
  7564. // TODO: 1. 动画改进
  7565. // 2. 改变图片的时候恢复 Zoom
  7566. // 3. 选项
  7567. // 4. 图片高度问题:由于 PinchZoom 的原因,过高的图片如果设置看了滚动,则放大以后显示不全
  7568. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  7569. "undefined" ? self : typeof window !== "undefined" ? window : {})
  7570. }, {
  7571. "./core": 4,
  7572. "./ui.pinchzoom": 34,
  7573. "./util.hammer": 50
  7574. }
  7575. ],
  7576. 38: [
  7577. function(require, module, exports) {
  7578. (function(global) {
  7579. 'use strict';
  7580. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  7581. "undefined" ? global.jQuery : null);
  7582. var UI = require('./core');
  7583. /**
  7584. * @via https://github.com/uikit/uikit/blob/master/src/js/scrollspy.js
  7585. * @license https://github.com/uikit/uikit/blob/master/LICENSE.md
  7586. */
  7587. var ScrollSpy = function(element, options) {
  7588. if (!UI.support.animation) {
  7589. return;
  7590. }
  7591. this.options = $.extend({}, ScrollSpy.DEFAULTS, options);
  7592. this.$element = $(element);
  7593. var checkViewRAF = function() {
  7594. UI.utils.rAF.call(window, $.proxy(this.checkView, this));
  7595. }.bind(this);
  7596. this.$window = $(window).on('scroll.scrollspy.amui',
  7597. checkViewRAF)
  7598. .on('resize.scrollspy.amui orientationchange.scrollspy.amui',
  7599. UI.utils.debounce(checkViewRAF, 50));
  7600. this.timer = this.inViewState = this.initInView = null;
  7601. checkViewRAF();
  7602. };
  7603. ScrollSpy.DEFAULTS = {
  7604. animation: 'fade',
  7605. className: {
  7606. inView: 'am-scrollspy-inview',
  7607. init: 'am-scrollspy-init'
  7608. },
  7609. repeat: true,
  7610. delay: 0,
  7611. topOffset: 0,
  7612. leftOffset: 0
  7613. };
  7614. ScrollSpy.prototype.checkView = function() {
  7615. var $element = this.$element;
  7616. var options = this.options;
  7617. var inView = UI.utils.isInView($element, options);
  7618. var animation = options.animation ?
  7619. ' am-animation-' + options.animation : '';
  7620. if (inView && !this.inViewState) {
  7621. if (this.timer) {
  7622. clearTimeout(this.timer);
  7623. }
  7624. if (!this.initInView) {
  7625. $element.addClass(options.className.init);
  7626. this.offset = $element.offset();
  7627. this.initInView = true;
  7628. $element.trigger('init.scrollspy.amui');
  7629. }
  7630. this.timer = setTimeout(function() {
  7631. if (inView) {
  7632. $element.addClass(options.className.inView + animation).width();
  7633. }
  7634. }, options.delay);
  7635. this.inViewState = true;
  7636. $element.trigger('inview.scrollspy.amui');
  7637. }
  7638. if (!inView && this.inViewState && options.repeat) {
  7639. $element.removeClass(options.className.inView + animation);
  7640. this.inViewState = false;
  7641. $element.trigger('outview.scrollspy.amui');
  7642. }
  7643. };
  7644. ScrollSpy.prototype.check = function() {
  7645. UI.utils.rAF.call(window, $.proxy(this.checkView, this));
  7646. };
  7647. // Sticky Plugin
  7648. function Plugin(option) {
  7649. return this.each(function() {
  7650. var $this = $(this);
  7651. var data = $this.data('am.scrollspy');
  7652. var options = typeof option == 'object' && option;
  7653. if (!data) {
  7654. $this.data('am.scrollspy', (data = new ScrollSpy(this,
  7655. options)));
  7656. }
  7657. if (typeof option == 'string') {
  7658. data[option]();
  7659. }
  7660. });
  7661. }
  7662. $.fn.scrollspy = Plugin;
  7663. // Init code
  7664. UI.ready(function(context) {
  7665. $('[data-am-scrollspy]', context).each(function() {
  7666. var $this = $(this);
  7667. var options = UI.utils.options($this.data('amScrollspy'));
  7668. $this.scrollspy(options);
  7669. });
  7670. });
  7671. $.AMUI.scrollspy = ScrollSpy;
  7672. module.exports = ScrollSpy;
  7673. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  7674. "undefined" ? self : typeof window !== "undefined" ? window : {})
  7675. }, {
  7676. "./core": 4
  7677. }
  7678. ],
  7679. 39: [
  7680. function(require, module, exports) {
  7681. (function(global) {
  7682. 'use strict';
  7683. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  7684. "undefined" ? global.jQuery : null);
  7685. var UI = require('./core');
  7686. require('./ui.smooth-scroll');
  7687. /**
  7688. * @via https://github.com/uikit/uikit/
  7689. * @license https://github.com/uikit/uikit/blob/master/LICENSE.md
  7690. */
  7691. // ScrollSpyNav Class
  7692. var ScrollSpyNav = function(element, options) {
  7693. this.options = $.extend({}, ScrollSpyNav.DEFAULTS, options);
  7694. this.$element = $(element);
  7695. this.anchors = [];
  7696. this.$links = this.$element.find('a[href^="#"]').each(function(
  7697. i, link) {
  7698. this.anchors.push($(link).attr('href'));
  7699. }.bind(this));
  7700. this.$targets = $(this.anchors.join(', '));
  7701. var processRAF = function() {
  7702. UI.utils.rAF.call(window, $.proxy(this.process, this));
  7703. }.bind(this);
  7704. this.$window = $(window).on('scroll.scrollspynav.amui',
  7705. processRAF)
  7706. .on(
  7707. 'resize.scrollspynav.amui orientationchange.scrollspynav.amui',
  7708. UI.utils.debounce(processRAF, 50));
  7709. processRAF();
  7710. this.scrollProcess();
  7711. };
  7712. ScrollSpyNav.DEFAULTS = {
  7713. className: {
  7714. active: 'am-active'
  7715. },
  7716. closest: false,
  7717. smooth: true
  7718. };
  7719. ScrollSpyNav.prototype.process = function() {
  7720. var scrollTop = this.$window.scrollTop();
  7721. var options = this.options;
  7722. var inViews = [];
  7723. var $links = this.$links;
  7724. var $targets = this.$targets;
  7725. $targets.each(function(i, target) {
  7726. if (UI.utils.isInView(target, options)) {
  7727. inViews.push(target);
  7728. }
  7729. });
  7730. // console.log(inViews.length);
  7731. if (inViews.length) {
  7732. var $target;
  7733. $.each(inViews, function(i, item) {
  7734. if ($(item).offset().top >= scrollTop) {
  7735. $target = $(item);
  7736. return false; // break
  7737. }
  7738. });
  7739. if (!$target) {
  7740. return;
  7741. }
  7742. if (options.closest) {
  7743. $links.closest(options.closest).removeClass(options.className
  7744. .active);
  7745. $links.filter('a[href="#' + $target.attr('id') + '"]').
  7746. closest(options.closest).addClass(options.className.active);
  7747. } else {
  7748. $links.removeClass(options.className.active).
  7749. filter('a[href="#' + $target.attr('id') + '"]').
  7750. addClass(options.className.active);
  7751. }
  7752. }
  7753. };
  7754. ScrollSpyNav.prototype.scrollProcess = function() {
  7755. var $links = this.$links;
  7756. // smoothScroll
  7757. if (this.options.smooth) {
  7758. $links.on('click', function(e) {
  7759. e.preventDefault();
  7760. var $this = $(this);
  7761. var $target = $($this.attr('href'));
  7762. if (!$target) {
  7763. return;
  7764. }
  7765. $(window).smoothScroll({
  7766. position: $target.offset().top
  7767. });
  7768. });
  7769. }
  7770. };
  7771. // ScrollSpyNav Plugin
  7772. function Plugin(option) {
  7773. return this.each(function() {
  7774. var $this = $(this);
  7775. var data = $this.data('amui.scrollspynav');
  7776. var options = typeof option == 'object' && option;
  7777. if (!data) {
  7778. $this.data('amui.scrollspynav', (data = new ScrollSpyNav(
  7779. this, options)));
  7780. }
  7781. if (typeof option == 'string') {
  7782. data[option]();
  7783. }
  7784. });
  7785. }
  7786. $.fn.scrollspynav = Plugin;
  7787. // Init code
  7788. UI.ready(function(context) {
  7789. $('[data-am-scrollspy-nav]', context).each(function() {
  7790. var $this = $(this);
  7791. var options = UI.utils.options($this.attr(
  7792. 'data-am-scrollspy-nav'));
  7793. Plugin.call($this, options);
  7794. });
  7795. });
  7796. $.AMUI.scrollspynav = ScrollSpyNav;
  7797. module.exports = ScrollSpyNav;
  7798. // TODO: 1. 算法改进
  7799. // 2. 多级菜单支持
  7800. // 3. smooth scroll pushState
  7801. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  7802. "undefined" ? self : typeof window !== "undefined" ? window : {})
  7803. }, {
  7804. "./core": 4,
  7805. "./ui.smooth-scroll": 42
  7806. }
  7807. ],
  7808. 40: [
  7809. function(require, module, exports) {
  7810. (function(global) {
  7811. 'use strict';
  7812. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  7813. "undefined" ? global.jQuery : null);
  7814. var UI = require('./core');
  7815. // Make jQuery :contains Case-Insensitive
  7816. $.expr[':'].containsNC = function(elem, i, match, array) {
  7817. return (elem.textContent || elem.innerText || '').toLowerCase().
  7818. indexOf((match[3] || '').toLowerCase()) >= 0;
  7819. };
  7820. /**
  7821. * Selected
  7822. * @desc HTML select replacer
  7823. * @via https://github.com/silviomoreto/bootstrap-select
  7824. * @license https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE
  7825. * @param element
  7826. * @param options
  7827. * @constructor
  7828. */
  7829. var Selected = function(element, options) {
  7830. this.$element = $(element);
  7831. this.options = $.extend({}, Selected.DEFAULTS, options);
  7832. this.$originalOptions = this.$element.find('option');
  7833. this.multiple = element.multiple;
  7834. this.$selector = null;
  7835. this.init();
  7836. };
  7837. Selected.DEFAULTS = {
  7838. btnWidth: null,
  7839. btnSize: null,
  7840. btnStyle: 'default',
  7841. dropUp: 0,
  7842. maxHeight: null,
  7843. noSelectedText: '点击选择...',
  7844. selectedClass: 'am-checked',
  7845. searchBox: false,
  7846. tpl: '<div class="am-selected am-dropdown ' +
  7847. '<%= dropUp ? \'am-dropdown-up\': \'\' %>" id="<%= id %>" data-am-dropdown>' +
  7848. ' <button type="button" class="am-selected-btn am-btn am-dropdown-toggle">' +
  7849. ' <span class="am-selected-status am-fl"></span>' +
  7850. ' <i class="am-selected-icon am-icon-caret-' +
  7851. '<%= dropUp ? \'up\' : \'down\' %>"></i>' +
  7852. ' </button>' +
  7853. ' <div class="am-selected-content am-dropdown-content">' +
  7854. ' <h2 class="am-selected-header">' +
  7855. '<span class="am-icon-chevron-left">返回</span></h2>' +
  7856. ' <% if (searchBox) { %>' +
  7857. ' <div class="am-selected-search">' +
  7858. ' <input type="text" autocomplete="off" class="am-form-field" />' +
  7859. ' </div>' +
  7860. ' <% } %>' +
  7861. ' <ul class="am-selected-list">' +
  7862. ' <% for (var i = 0; i < options.length; i++) { %>' +
  7863. ' <% var option = options[i] %>' +
  7864. ' <% if (option.header) { %>' +
  7865. ' <li data-group="<%= option.group %>" class="am-selected-list-header">' +
  7866. ' <%= option.text %></li>' +
  7867. ' <% } else { %>' +
  7868. ' <li class=<%= option.active %> ' +
  7869. ' data-index="<%= option.index %>" ' +
  7870. ' data-group="<%= option.group || 0 %>" ' +
  7871. ' data-value="<%= option.value %>" >' +
  7872. ' <span class="am-selected-text"><%= option.text %></span>' +
  7873. ' <i class="am-icon-check"></i></li>' +
  7874. ' <% } %>' +
  7875. ' <% } %>' +
  7876. ' </ul>' +
  7877. ' <div class="am-selected-hint"></div>' +
  7878. ' </div>' +
  7879. '</div>'
  7880. };
  7881. Selected.prototype.init = function() {
  7882. var $element = this.$element;
  7883. var options = this.options;
  7884. var optionItems = [];
  7885. var $optgroup = $element.find('optgroup');
  7886. $element.hide();
  7887. function pushOption(index, item, group) {
  7888. optionItems.push({
  7889. group: group,
  7890. index: index,
  7891. active: item.selected ? options.selectedClass : '',
  7892. text: item.text,
  7893. value: item.value
  7894. });
  7895. }
  7896. // select with option groups
  7897. if ($optgroup.length) {
  7898. $optgroup.each(function(i) {
  7899. // push group name
  7900. optionItems.push({
  7901. header: true,
  7902. group: i + 1,
  7903. text: this.label
  7904. });
  7905. $optgroup.eq(i).find('option').each(function(index, item) {
  7906. pushOption(index, item, i);
  7907. });
  7908. });
  7909. } else {
  7910. // without option groups
  7911. $element.find('option').each(function(index, item) {
  7912. pushOption(index, item, null);
  7913. });
  7914. }
  7915. var data = {
  7916. id: UI.utils.generateGUID('am-selected'),
  7917. multiple: $element.get(0).multiple,
  7918. options: optionItems,
  7919. searchBox: options.searchBox,
  7920. dropUp: options.dropUp
  7921. };
  7922. this.$selector = $(this.render(data));
  7923. this.$searchField = this.$selector.find(
  7924. '.am-selected-search input');
  7925. this.$hint = this.$selector.find('.am-selected-hint');
  7926. // set select button styles
  7927. var $selectorBtn = this.$selector.find('.am-selected-btn').
  7928. css({
  7929. width: this.options.btnWidth
  7930. });
  7931. var btnClassNames = [];
  7932. options.btnSize && btnClassNames.push('am-btn-' + options.btnSize);
  7933. options.btnStyle && btnClassNames.push('am-btn-' + options.btnStyle);
  7934. $selectorBtn.addClass(btnClassNames.join(' '));
  7935. this.$selector.dropdown({
  7936. justify: $selectorBtn
  7937. });
  7938. // set list height
  7939. if (options.maxHeight) {
  7940. this.$selector.find('.am-selected-list').css({
  7941. 'max-height': options.maxHeight,
  7942. 'overflow-y': 'scroll'
  7943. });
  7944. }
  7945. // set hint text
  7946. var hint = [];
  7947. var min = $element.attr('minchecked');
  7948. var max = $element.attr('maxchecked');
  7949. if ($element[0].required) {
  7950. hint.push('必选');
  7951. }
  7952. if (min || max) {
  7953. min && hint.push('至少选择 ' + min + ' 项');
  7954. max && hint.push('至多选择 ' + max + ' 项');
  7955. }
  7956. this.$hint.text(hint.join(','));
  7957. // append $selector after <select>
  7958. this.$element.after(this.$selector);
  7959. this.dropdown = this.$selector.data('amui.dropdown');
  7960. this.$status = this.$selector.find('.am-selected-status');
  7961. this.getShadowOptions();
  7962. this.syncData();
  7963. this.bindEvents();
  7964. };
  7965. Selected.prototype.render = function(data) {
  7966. return UI.template(this.options.tpl, data);
  7967. };
  7968. Selected.prototype.getShadowOptions = function() {
  7969. this.$shadowOptions = this.$selector.find('.am-selected-list li')
  7970. .
  7971. not('.am-selected-list-header');
  7972. };
  7973. Selected.prototype.setChecked = function(item) {
  7974. var options = this.options;
  7975. var $item = $(item);
  7976. var isChecked = $item.hasClass(options.selectedClass);
  7977. if (!this.multiple) {
  7978. if (!isChecked) {
  7979. this.dropdown.close();
  7980. this.$shadowOptions.not($item).removeClass(options.selectedClass);
  7981. } else {
  7982. return;
  7983. }
  7984. }
  7985. $item.toggleClass(options.selectedClass);
  7986. this.syncData(item);
  7987. };
  7988. /**
  7989. * syncData
  7990. * @desc if `item` set, only sync `item` related option
  7991. * @param {Object} item
  7992. */
  7993. Selected.prototype.syncData = function(item) {
  7994. var _this = this;
  7995. var options = this.options;
  7996. var status = [];
  7997. var $checked = $([]);
  7998. this.$shadowOptions.filter('.' + options.selectedClass).each(
  7999. function() {
  8000. var $this = $(this);
  8001. status.push($this.find('.am-selected-text').text());
  8002. if (!item) {
  8003. $checked = $checked.add(_this.$originalOptions.filter(
  8004. '[value="' + $this.data('value') + '"]').prop(
  8005. 'selected', true));
  8006. }
  8007. });
  8008. if (item) {
  8009. var $item = $(item);
  8010. this.$originalOptions.filter('[value="' + $item.data('value') +
  8011. '"]').
  8012. prop('selected', $item.hasClass(options.selectedClass));
  8013. } else {
  8014. this.$originalOptions.not($checked).prop('selected', false);
  8015. }
  8016. // nothing selected
  8017. if (!this.$element.val()) {
  8018. status.push(options.noSelectedText);
  8019. }
  8020. this.$status.text(status.join(', '));
  8021. this.$element.trigger('change');
  8022. };
  8023. Selected.prototype.bindEvents = function() {
  8024. var _this = this;
  8025. var handleKeyup = UI.utils.debounce(function(e) {
  8026. _this.$shadowOptions.not('.am-selcted-list-header').hide().
  8027. filter(':containsNC("' + e.target.value + '")').show();
  8028. }, 100);
  8029. this.$shadowOptions.on('click', function(e) {
  8030. _this.setChecked(this);
  8031. });
  8032. // simple search with jQuery :contains
  8033. this.$searchField.on('keyup.selected.amui', handleKeyup);
  8034. // empty search keywords
  8035. this.$selector.on('closed.dropdown.amui', function() {
  8036. _this.$searchField.val('');
  8037. _this.$shadowOptions.css({
  8038. display: ''
  8039. });
  8040. });
  8041. };
  8042. Selected.prototype.destroy = function() {
  8043. this.$element.removeData('amui.selected').show();
  8044. this.$selector.remove();
  8045. };
  8046. function Plugin(option) {
  8047. return this.each(function() {
  8048. var $this = $(this);
  8049. var data = $this.data('amui.selected');
  8050. var options = $.extend({}, UI.utils.parseOptions($this.data(
  8051. 'amSelected')),
  8052. UI.utils.parseOptions($this.data('amSelectit')),
  8053. typeof option === 'object' && option);
  8054. if (!data && option === 'destroy') {
  8055. return;
  8056. }
  8057. if (!data) {
  8058. $this.data('amui.selected', (data = new Selected(this,
  8059. options)));
  8060. }
  8061. if (typeof option == 'string') {
  8062. data[option] && data[option]();
  8063. }
  8064. });
  8065. }
  8066. // Conflict with jQuery form
  8067. // https://github.com/malsup/form/blob/6bf24a5f6d8be65f4e5491863180c09356d9dadd/jquery.form.js#L1240-L1258
  8068. // https://github.com/allmobilize/amazeui/issues/379
  8069. $.fn.selected = $.fn.selectIt = Plugin;
  8070. UI.ready(function(context) {
  8071. $('[data-am-selected]', context).selectIt();
  8072. });
  8073. $.AMUI.selected = Selected;
  8074. module.exports = Selected;
  8075. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  8076. "undefined" ? self : typeof window !== "undefined" ? window : {})
  8077. }, {
  8078. "./core": 4
  8079. }
  8080. ],
  8081. 41: [
  8082. function(require, module, exports) {
  8083. (function(global) {
  8084. 'use strict';
  8085. require('./ui.modal');
  8086. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  8087. "undefined" ? global.jQuery : null);
  8088. var UI = require('./core');
  8089. var QRCode = require('./util.qrcode');
  8090. var doc = document;
  8091. var $doc = $(doc);
  8092. var Share = function(options) {
  8093. this.options = $.extend({}, Share.DEFAULTS, options || {});
  8094. this.$element = null;
  8095. this.$wechatQr = null;
  8096. this.pics = null;
  8097. this.inited = false;
  8098. this.active = false;
  8099. // this.init();
  8100. };
  8101. Share.DEFAULTS = {
  8102. sns: ['weibo', 'qq', 'qzone', 'tqq', 'wechat', 'renren'],
  8103. title: '分享到',
  8104. cancel: '取消',
  8105. closeOnShare: true,
  8106. id: UI.utils.generateGUID('am-share'),
  8107. desc: 'Hi,孤夜观天象,发现一个不错的西西,分享一下下 ;-)',
  8108. via: 'Amaze UI',
  8109. tpl: '<div class="am-share am-modal-actions" id="<%= id %>">' +
  8110. '<h3 class="am-share-title"><%= title %></h3>' +
  8111. '<ul class="am-share-sns am-avg-sm-3">' +
  8112. '<% for(var i = 0; i < sns.length; i++) {%>' +
  8113. '<li>' +
  8114. '<a href="<%= sns[i].shareUrl %>" ' +
  8115. 'data-am-share-to="<%= sns[i].id %>" >' +
  8116. '<i class="am-icon-<%= sns[i].icon %>"></i>' +
  8117. '<span><%= sns[i].title %></span>' +
  8118. '</a></li>' +
  8119. '<% } %></ul>' +
  8120. '<div class="am-share-footer">' +
  8121. '<button class="am-btn am-btn-default am-btn-block" ' +
  8122. 'data-am-share-close><%= cancel %></button></div>' +
  8123. '</div>'
  8124. };
  8125. Share.SNS = {
  8126. weibo: {
  8127. title: '新浪微博',
  8128. url: 'http://service.weibo.com/share/share.php',
  8129. width: 620,
  8130. height: 450,
  8131. icon: 'weibo'
  8132. },
  8133. // url 链接地址
  8134. // title:”, 分享的文字内容(可选,默认为所在页面的title)
  8135. // appkey:”, 您申请的应用appkey,显示分享来源(可选)
  8136. // pic:”, 分享图片的路径(可选)
  8137. // ralateUid:”, 关联用户的UID,分享微博会@该用户(可选)
  8138. // NOTE: 会自动抓取图片,不用指定 pic
  8139. qq: {
  8140. title: 'QQ 好友',
  8141. url: 'http://connect.qq.com/widget/shareqq/index.html',
  8142. icon: 'qq'
  8143. },
  8144. // url:,
  8145. // title:'', 分享标题(可选)
  8146. // pics:'', 分享图片的路径(可选)
  8147. // summary:'', 分享摘要(可选)
  8148. // site:'', 分享来源 如:腾讯网(可选)
  8149. // desc: '' 发送给用户的消息
  8150. // NOTE: 经过测试,最终发给用户的只有 url 和 desc
  8151. qzone: {
  8152. title: 'QQ 空间',
  8153. url: 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey',
  8154. icon: 'star'
  8155. },
  8156. // http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=xxx&title=xxx&desc=&summary=&site=
  8157. // url:,
  8158. // title:'', 分享标题(可选)
  8159. // desc:'', 默认分享理由(可选)
  8160. // summary:'', 分享摘要(可选)
  8161. // site:'', 分享来源 如:腾讯网(可选)
  8162. // pics:'', 分享图片的路径(可选),不会自动抓取,多个图片用|分隔
  8163. tqq: {
  8164. title: '腾讯微博',
  8165. url: 'http://v.t.qq.com/share/share.php',
  8166. icon: 'tencent-weibo'
  8167. },
  8168. // url=xx&title=&appkey=801cf76d3cfc44ada52ec13114e84a96
  8169. // url
  8170. // title
  8171. // pic 多个图片用 | 分隔
  8172. // appkey
  8173. // NOTE: 不会自动抓取图片
  8174. wechat: {
  8175. title: '微信',
  8176. url: '[qrcode]',
  8177. icon: 'wechat'
  8178. },
  8179. // 生成一个二维码 供用户扫描
  8180. // 相关接口 https://github.com/zxlie/WeixinApi
  8181. renren: {
  8182. title: '人人网',
  8183. url: 'http://widget.renren.com/dialog/share',
  8184. icon: 'renren'
  8185. },
  8186. // http://widget.renren.com/dialog/share?resourceUrl=www&srcUrl=www&title=ww&description=xxx
  8187. // 550 * 400
  8188. // resourceUrl : '', // 分享的资源Url
  8189. // srcUrl : '', // 分享的资源来源Url,
  8190. // // 默认为header中的Referer,如果分享失败可以调整此值为resourceUrl试试
  8191. // pic : '', // 分享的主题图片,会自动抓取
  8192. // title : '', // 分享的标题
  8193. // description : '' // 分享的详细描述
  8194. // NOTE: 经过测试,直接使用 url 参数即可
  8195. douban: {
  8196. title: '豆瓣',
  8197. url: 'http://www.douban.com/recommend/',
  8198. icon: 'share-alt'
  8199. },
  8200. // http://www.douban.com/service/sharebutton
  8201. // 450 * 330
  8202. // http://www.douban.com/share/service?bm=1&image=&href=xxx&updated=&name=
  8203. // href 链接
  8204. // name 标题
  8205. /* void (function() {
  8206. var d = document, e = encodeURIComponent,
  8207. s1 = window.getSelection, s2 = d.getSelection,
  8208. s3 = d.selection, s = s1 ? s1()
  8209. : s2 ? s2() : s3 ? s3.createRange().text : '',
  8210. r = 'http://www.douban.com/recommend/?url=&title=&sel=&v=1&r=1'
  8211. })();
  8212. */
  8213. // tsohu: '',
  8214. // http://t.sohu.com/third/post.jsp?url=&title=&content=utf-8&pic=
  8215. // print: '',
  8216. mail: {
  8217. title: '邮件分享',
  8218. url: 'mailto:',
  8219. icon: 'envelope-o'
  8220. },
  8221. sms: {
  8222. title: '短信分享',
  8223. url: 'sms:',
  8224. icon: 'comment'
  8225. }
  8226. };
  8227. Share.prototype.render = function() {
  8228. var options = this.options;
  8229. var snsData = [];
  8230. var title = encodeURIComponent(doc.title);
  8231. var link = encodeURIComponent(doc.location);
  8232. var msgBody = '?body=' + title + link;
  8233. options.sns.forEach(function(item, i) {
  8234. if (Share.SNS[item]) {
  8235. var tmp = Share.SNS[item];
  8236. var shareUrl;
  8237. tmp.id = item;
  8238. if (item === 'mail') {
  8239. shareUrl = msgBody + '&subject=' + options.desc;
  8240. } else if (item === 'sms') {
  8241. shareUrl = msgBody;
  8242. } else {
  8243. shareUrl = '?url=' + link + '&title=' + title;
  8244. }
  8245. tmp.shareUrl = tmp.url + shareUrl;
  8246. snsData.push(tmp);
  8247. }
  8248. });
  8249. return UI.template(options.tpl, $.extend({}, options, {
  8250. sns: snsData
  8251. }));
  8252. };
  8253. Share.prototype.init = function() {
  8254. if (this.inited) {
  8255. return;
  8256. }
  8257. var me = this;
  8258. var shareItem = '[data-am-share-to]';
  8259. $doc.ready($.proxy(function() {
  8260. $('body').append(this.render()); // append share DOM to body
  8261. this.$element = $('#' + this.options.id);
  8262. this.$element.find('[data-am-share-close]').
  8263. on('click.share.amui', function() {
  8264. me.close();
  8265. });
  8266. }, this));
  8267. $doc.on('click.share.amui', shareItem, $.proxy(function(e) {
  8268. var $clicked = $(e.target);
  8269. var $target = $clicked.is(shareItem) && $clicked ||
  8270. $clicked.parent(shareItem);
  8271. var sns = $target.attr('data-am-share-to');
  8272. if (!(sns === 'mail' || sns === 'sms')) {
  8273. e.preventDefault();
  8274. this.shareTo(sns, this.setData(sns));
  8275. }
  8276. this.close();
  8277. }, this));
  8278. this.inited = true;
  8279. };
  8280. Share.prototype.open = function() {
  8281. !this.inited && this.init();
  8282. this.$element && this.$element.modal('open');
  8283. this.$element.trigger('open.share.amui');
  8284. this.active = true;
  8285. };
  8286. Share.prototype.close = function() {
  8287. this.$element && this.$element.modal('close');
  8288. this.$element.trigger('close.share.amui');
  8289. this.active = false;
  8290. };
  8291. Share.prototype.toggle = function() {
  8292. this.active ? this.close() : this.open();
  8293. };
  8294. Share.prototype.setData = function(sns) {
  8295. if (!sns) {
  8296. return;
  8297. }
  8298. var shareData = {
  8299. url: doc.location,
  8300. title: doc.title
  8301. };
  8302. var desc = this.options.desc;
  8303. var imgSrc = this.pics || [];
  8304. var qqReg = /^(qzone|qq|tqq)$/;
  8305. if (qqReg.test(sns) && !imgSrc.length) {
  8306. var allImages = doc.images;
  8307. for (var i = 0; i < allImages.length && i < 10; i++) {
  8308. !!allImages[i].src && imgSrc.push(encodeURIComponent(
  8309. allImages[i].src));
  8310. }
  8311. this.pics = imgSrc; // 缓存图片
  8312. }
  8313. switch (sns) {
  8314. case 'qzone':
  8315. shareData.desc = desc;
  8316. shareData.site = this.options.via;
  8317. shareData.pics = imgSrc.join('|');
  8318. // TODO: 抓取图片多张
  8319. break;
  8320. case 'qq':
  8321. shareData.desc = desc;
  8322. shareData.site = this.options.via;
  8323. shareData.pics = imgSrc[0];
  8324. // 抓取一张图片
  8325. break;
  8326. case 'tqq':
  8327. // 抓取图片多张
  8328. shareData.pic = imgSrc.join('|');
  8329. break;
  8330. }
  8331. return shareData;
  8332. };
  8333. Share.prototype.shareTo = function(sns, data) {
  8334. var snsInfo = Share.SNS[sns];
  8335. if (!snsInfo) {
  8336. return;
  8337. }
  8338. if (sns === 'wechat' || sns === 'weixin') {
  8339. return this.wechatQr();
  8340. }
  8341. var query = [];
  8342. for (var key in data) {
  8343. if (data[key]) {
  8344. // 避免 encode 图片分隔符 |
  8345. query.push(key.toString() + '=' + ((key === 'pic' || key ===
  8346. 'pics') ?
  8347. data[key] : encodeURIComponent(data[key])));
  8348. }
  8349. }
  8350. window.open(snsInfo.url + '?' + query.join('&'));
  8351. };
  8352. Share.prototype.wechatQr = function() {
  8353. if (!this.$wechatQr) {
  8354. var qrId = UI.utils.generateGUID('am-share-wechat');
  8355. var $qr = $(
  8356. '<div class="am-modal am-modal-no-btn am-share-wechat-qr">' +
  8357. '<div class="am-modal-dialog"><div class="am-modal-hd">分享到微信 ' +
  8358. '<a href="" class="am-close am-close-spin" ' +
  8359. 'data-am-modal-close>&times;</a> </div>' +
  8360. '<div class="am-modal-bd">' +
  8361. '<div class="am-share-wx-qr"></div>' +
  8362. '<div class="am-share-wechat-tip">' +
  8363. '打开微信,点击底部的<em>发现</em>,<br/> ' +
  8364. '使用<em>扫一扫</em>将网页分享至朋友圈</div></div></div></div>', {
  8365. id: qrId
  8366. });
  8367. var qrNode = new QRCode({
  8368. render: 'canvas',
  8369. correctLevel: 0,
  8370. text: doc.location.href,
  8371. width: 180,
  8372. height: 180,
  8373. background: '#fff',
  8374. foreground: '#000'
  8375. });
  8376. $qr.find('.am-share-wx-qr').html(qrNode);
  8377. $qr.appendTo($('body'));
  8378. this.$wechatQr = $('#' + qrId);
  8379. }
  8380. this.$wechatQr.modal('open');
  8381. };
  8382. var share = new Share();
  8383. $doc.on('click.share.amui.data-api', '[data-am-toggle="share"]',
  8384. function(e) {
  8385. e.preventDefault();
  8386. share.toggle();
  8387. });
  8388. $.AMUI.share = share;
  8389. module.exports = share;
  8390. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  8391. "undefined" ? self : typeof window !== "undefined" ? window : {})
  8392. }, {
  8393. "./core": 4,
  8394. "./ui.modal": 32,
  8395. "./util.qrcode": 51
  8396. }
  8397. ],
  8398. 42: [
  8399. function(require, module, exports) {
  8400. (function(global) {
  8401. 'use strict';
  8402. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  8403. "undefined" ? global.jQuery : null);
  8404. var UI = require('./core');
  8405. var rAF = UI.utils.rAF;
  8406. var cAF = UI.utils.cancelAF;
  8407. /**
  8408. * Smooth Scroll
  8409. * @param position
  8410. * @via http://mir.aculo.us/2014/01/19/scrolling-dom-elements-to-the-top-a-zepto-plugin/
  8411. */
  8412. // Usage: $(window).smoothScroll([options])
  8413. // only allow one scroll to top operation to be in progress at a time,
  8414. // which is probably what you want
  8415. var smoothScrollInProgress = false;
  8416. var SmoothScroll = function(element, options) {
  8417. options = options || {};
  8418. var $this = $(element);
  8419. var targetY = parseInt(options.position) || SmoothScroll.DEFAULTS
  8420. .position;
  8421. var initialY = $this.scrollTop();
  8422. var lastY = initialY;
  8423. var delta = targetY - initialY;
  8424. // duration in ms, make it a bit shorter for short distances
  8425. // this is not scientific and you might want to adjust this for
  8426. // your preferences
  8427. var speed = options.speed ||
  8428. Math.min(750, Math.min(1500, Math.abs(initialY - targetY)));
  8429. // temp variables (t will be a position between 0 and 1, y is the calculated scrollTop)
  8430. var start;
  8431. var t;
  8432. var y;
  8433. var cancelScroll = function() {
  8434. abort();
  8435. };
  8436. // abort if already in progress or nothing to scroll
  8437. if (smoothScrollInProgress) {
  8438. return;
  8439. }
  8440. if (delta === 0) {
  8441. return;
  8442. }
  8443. // quint ease-in-out smoothing, from
  8444. // https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js#L127-L136
  8445. function smooth(pos) {
  8446. if ((pos /= 0.5) < 1) {
  8447. return 0.5 * Math.pow(pos, 5);
  8448. }
  8449. return 0.5 * (Math.pow((pos - 2), 5) + 2);
  8450. }
  8451. function abort() {
  8452. $this.off('touchstart.smoothscroll.amui', cancelScroll);
  8453. smoothScrollInProgress = false;
  8454. }
  8455. // when there's a touch detected while scrolling is in progress, abort
  8456. // the scrolling (emulates native scrolling behavior)
  8457. $this.on('touchstart.smoothscroll.amui', cancelScroll);
  8458. smoothScrollInProgress = true;
  8459. // start rendering away! note the function given to frame
  8460. // is named "render" so we can reference it again further down
  8461. function render(now) {
  8462. if (!smoothScrollInProgress) {
  8463. return;
  8464. }
  8465. if (!start) {
  8466. start = now;
  8467. }
  8468. // calculate t, position of animation in [0..1]
  8469. t = Math.min(1, Math.max((now - start) / speed, 0));
  8470. // calculate the new scrollTop position (don't forget to smooth)
  8471. y = Math.round(initialY + delta * smooth(t));
  8472. // bracket scrollTop so we're never over-scrolling
  8473. if (delta > 0 && y > targetY) {
  8474. y = targetY;
  8475. }
  8476. if (delta < 0 && y < targetY) {
  8477. y = targetY;
  8478. }
  8479. // only actually set scrollTop if there was a change fromt he last frame
  8480. if (lastY != y) {
  8481. $this.scrollTop(y);
  8482. }
  8483. lastY = y;
  8484. // if we're not done yet, queue up an other frame to render,
  8485. // or clean up
  8486. if (y !== targetY) {
  8487. cAF(scrollRAF);
  8488. scrollRAF = rAF(render);
  8489. } else {
  8490. cAF(scrollRAF);
  8491. abort();
  8492. }
  8493. }
  8494. var scrollRAF = rAF(render);
  8495. };
  8496. SmoothScroll.DEFAULTS = {
  8497. position: 0
  8498. };
  8499. $.fn.smoothScroll = function(option) {
  8500. return this.each(function() {
  8501. new SmoothScroll(this, option);
  8502. });
  8503. };
  8504. // Init code
  8505. $(document).on('click.smoothScroll.amui.data-api',
  8506. '[data-am-smooth-scroll]',
  8507. function(e) {
  8508. e.preventDefault();
  8509. var options = UI.utils.parseOptions($(this).data(
  8510. 'amSmoothScroll'));
  8511. $(window).smoothScroll(options);
  8512. });
  8513. module.exports = SmoothScroll;
  8514. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  8515. "undefined" ? self : typeof window !== "undefined" ? window : {})
  8516. }, {
  8517. "./core": 4
  8518. }
  8519. ],
  8520. 43: [
  8521. function(require, module, exports) {
  8522. (function(global) {
  8523. 'use strict';
  8524. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  8525. "undefined" ? global.jQuery : null);
  8526. var UI = require('./core');
  8527. /**
  8528. * @via https://github.com/uikit/uikit/blob/master/src/js/addons/sticky.js
  8529. * @license https://github.com/uikit/uikit/blob/master/LICENSE.md
  8530. */
  8531. // Sticky Class
  8532. var Sticky = function(element, options) {
  8533. var me = this;
  8534. this.options = $.extend({}, Sticky.DEFAULTS, options);
  8535. this.$element = $(element);
  8536. this.sticked = null;
  8537. this.inited = null;
  8538. this.$holder = undefined;
  8539. this.$window = $(window).
  8540. on('scroll.sticky.amui',
  8541. UI.utils.debounce($.proxy(this.checkPosition, this), 10)).
  8542. on('resize.sticky.amui orientationchange.sticky.amui',
  8543. UI.utils.debounce(function() {
  8544. me.reset(true, function() {
  8545. me.checkPosition();
  8546. });
  8547. }, 50)).
  8548. on('load.sticky.amui', $.proxy(this.checkPosition, this));
  8549. // the `.offset()` is diff between jQuery & Zepto.js
  8550. // jQuery: return `top` and `left`
  8551. // Zepto.js: return `top`, `left`, `width`, `height`
  8552. this.offset = this.$element.offset();
  8553. this.init();
  8554. };
  8555. Sticky.DEFAULTS = {
  8556. top: 0,
  8557. bottom: 0,
  8558. animation: '',
  8559. className: {
  8560. sticky: 'am-sticky',
  8561. resetting: 'am-sticky-resetting',
  8562. stickyBtm: 'am-sticky-bottom',
  8563. animationRev: 'am-animation-reverse'
  8564. }
  8565. };
  8566. Sticky.prototype.init = function() {
  8567. var result = this.check();
  8568. if (!result) {
  8569. return false;
  8570. }
  8571. var $element = this.$element;
  8572. var $holder = $('<div class="am-sticky-placeholder"></div>').css({
  8573. height: $element.css('position') != 'absolute' ?
  8574. $element.outerHeight() : '',
  8575. float: $element.css('float') != 'none' ? $element.css(
  8576. 'float') : '',
  8577. margin: $element.css('margin')
  8578. });
  8579. this.$holder = $element.css('margin', 0).wrap($holder).parent();
  8580. this.inited = 1;
  8581. return true;
  8582. };
  8583. Sticky.prototype.reset = function(force, cb) {
  8584. var options = this.options;
  8585. var $element = this.$element;
  8586. var animation = (options.animation) ?
  8587. ' am-animation-' + options.animation : '';
  8588. var complete = function() {
  8589. $element.css({
  8590. position: '',
  8591. top: '',
  8592. width: '',
  8593. left: '',
  8594. margin: 0
  8595. });
  8596. $element.removeClass([
  8597. animation,
  8598. options.className.animationRev,
  8599. options.className.sticky,
  8600. options.className.resetting
  8601. ].join(' '));
  8602. this.animating = false;
  8603. this.sticked = false;
  8604. this.offset = $element.offset();
  8605. cb && cb();
  8606. }.bind(this);
  8607. $element.addClass(options.className.resetting);
  8608. if (!force && options.animation && UI.support.animation) {
  8609. this.animating = true;
  8610. $element.removeClass(animation).one(UI.support.animation.end,
  8611. function() {
  8612. complete();
  8613. }).width(); // force redraw
  8614. $element.addClass(animation + ' ' + options.className.animationRev);
  8615. } else {
  8616. complete();
  8617. }
  8618. };
  8619. Sticky.prototype.check = function() {
  8620. if (!this.$element.is(':visible')) {
  8621. return false;
  8622. }
  8623. var media = this.options.media;
  8624. if (media) {
  8625. switch (typeof(media)) {
  8626. case 'number':
  8627. if (window.innerWidth < media) {
  8628. return false;
  8629. }
  8630. break;
  8631. case 'string':
  8632. if (window.matchMedia && !window.matchMedia(media).matches) {
  8633. return false;
  8634. }
  8635. break;
  8636. }
  8637. }
  8638. return true;
  8639. };
  8640. Sticky.prototype.checkPosition = function() {
  8641. if (!this.inited) {
  8642. var initialized = this.init();
  8643. if (!initialized) {
  8644. return;
  8645. }
  8646. }
  8647. var options = this.options;
  8648. var scrollTop = this.$window.scrollTop();
  8649. var offsetTop = options.top;
  8650. var offsetBottom = options.bottom;
  8651. var $element = this.$element;
  8652. var animation = (options.animation) ?
  8653. ' am-animation-' + options.animation : '';
  8654. var className = [options.className.sticky, animation].join(' ');
  8655. if (typeof offsetBottom == 'function') {
  8656. offsetBottom = offsetBottom(this.$element);
  8657. }
  8658. var checkResult = (scrollTop > this.$holder.offset().top);
  8659. if (!this.sticked && checkResult) {
  8660. $element.addClass(className);
  8661. } else if (this.sticked && !checkResult) {
  8662. this.reset();
  8663. }
  8664. this.$holder.height($element.is(':visible') ? $element.height() :
  8665. 0);
  8666. if (checkResult) {
  8667. $element.css({
  8668. top: offsetTop,
  8669. left: this.$holder.offset().left,
  8670. width: this.$holder.width()
  8671. });
  8672. /*
  8673. if (offsetBottom) {
  8674. // (底部边距 + 元素高度 > 窗口高度) 时定位到底部
  8675. if ((offsetBottom + this.offset.height > $(window).height()) &&
  8676. (scrollTop + $(window).height() >= scrollHeight - offsetBottom)) {
  8677. $element.addClass(options.className.stickyBtm).
  8678. css({top: $(window).height() - offsetBottom - this.offset.height});
  8679. } else {
  8680. $element.removeClass(options.className.stickyBtm).css({top: offsetTop});
  8681. }
  8682. }
  8683. */
  8684. }
  8685. this.sticked = checkResult;
  8686. };
  8687. // Sticky Plugin
  8688. function Plugin(option) {
  8689. return this.each(function() {
  8690. var $this = $(this);
  8691. var data = $this.data('amui.sticky');
  8692. var options = typeof option == 'object' && option;
  8693. if (!data) {
  8694. $this.data('amui.sticky', (data = new Sticky(this,
  8695. options)));
  8696. }
  8697. if (typeof option == 'string') {
  8698. data[option]();
  8699. }
  8700. });
  8701. }
  8702. $.fn.sticky = Plugin;
  8703. // Init code
  8704. $(window).on('load', function() {
  8705. $('[data-am-sticky]').each(function() {
  8706. var $this = $(this);
  8707. var options = UI.utils.options($this.attr('data-am-sticky'));
  8708. Plugin.call($this, options);
  8709. });
  8710. });
  8711. $.AMUI.sticky = Sticky;
  8712. module.exports = Sticky;
  8713. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  8714. "undefined" ? self : typeof window !== "undefined" ? window : {})
  8715. }, {
  8716. "./core": 4
  8717. }
  8718. ],
  8719. 44: [
  8720. function(require, module, exports) {
  8721. (function(global) {
  8722. 'use strict';
  8723. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  8724. "undefined" ? global.jQuery : null);
  8725. var UI = require('./core');
  8726. var Hammer = require('./util.hammer');
  8727. var supportTransition = UI.support.transition;
  8728. var animation = UI.support.animation;
  8729. /**
  8730. * @via https://github.com/twbs/bootstrap/blob/master/js/tab.js
  8731. * @copyright 2011-2014 Twitter, Inc.
  8732. * @license MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  8733. */
  8734. var Tabs = function(element, options) {
  8735. this.$element = $(element);
  8736. this.options = $.extend({}, Tabs.DEFAULTS, options || {});
  8737. this.$tabNav = this.$element.find(this.options.selector.nav);
  8738. this.$navs = this.$tabNav.find('a');
  8739. this.$content = this.$element.find(this.options.selector.content);
  8740. this.$tabPanels = this.$content.find(this.options.selector.panel);
  8741. this.transitioning = null;
  8742. this.init();
  8743. };
  8744. Tabs.DEFAULTS = {
  8745. selector: {
  8746. nav: '.am-tabs-nav',
  8747. content: '.am-tabs-bd',
  8748. panel: '.am-tab-panel'
  8749. },
  8750. className: {
  8751. active: 'am-active'
  8752. }
  8753. };
  8754. Tabs.prototype.init = function() {
  8755. var me = this;
  8756. var options = this.options;
  8757. // Activate the first Tab when no active Tab or multiple active Tabs
  8758. if (this.$tabNav.find('> .am-active').length !== 1) {
  8759. var $tabNav = this.$tabNav;
  8760. this.activate($tabNav.children('li').first(), $tabNav);
  8761. this.activate(this.$tabPanels.first(), this.$content);
  8762. }
  8763. this.$navs.on('click.tabs.amui', function(e) {
  8764. e.preventDefault();
  8765. me.open($(this));
  8766. });
  8767. if (!options.noSwipe) {
  8768. var hammer = new Hammer(this.$content[0]);
  8769. hammer.get('pan').set({
  8770. direction: Hammer.DIRECTION_HORIZONTAL,
  8771. threshold: 120
  8772. });
  8773. hammer.on('panleft', UI.utils.debounce(function(e) {
  8774. e.preventDefault();
  8775. var $target = $(e.target);
  8776. if (!$target.is(options.selector.panel)) {
  8777. $target = $target.closest(options.selector.panel);
  8778. }
  8779. $target.focus();
  8780. var $nav = me.getNextNav($target);
  8781. $nav && me.open($nav);
  8782. }, 100));
  8783. hammer.on('panright', UI.utils.debounce(function(e) {
  8784. e.preventDefault();
  8785. var $target = $(e.target);
  8786. if (!$target.is(options.selector.panel)) {
  8787. $target = $target.closest(options.selector.panel);
  8788. }
  8789. var $nav = me.getPrevNav($target);
  8790. $nav && me.open($nav);
  8791. }, 100));
  8792. }
  8793. };
  8794. Tabs.prototype.open = function($nav) {
  8795. if (!$nav ||
  8796. this.transitioning ||
  8797. $nav.parent('li').hasClass('am-active')) {
  8798. return;
  8799. }
  8800. var $tabNav = this.$tabNav;
  8801. var $navs = this.$navs;
  8802. var $tabContent = this.$content;
  8803. var href = $nav.attr('href');
  8804. var regexHash = /^#.+$/;
  8805. var $target = regexHash.test(href) && this.$content.find(href) ||
  8806. this.$tabPanels.eq($navs.index($nav));
  8807. var previous = $tabNav.find('.am-active a')[0];
  8808. var e = $.Event('open.tabs.amui', {
  8809. relatedTarget: previous
  8810. });
  8811. $nav.trigger(e);
  8812. if (e.isDefaultPrevented()) {
  8813. return;
  8814. }
  8815. // activate Tab nav
  8816. this.activate($nav.closest('li'), $tabNav);
  8817. // activate Tab content
  8818. this.activate($target, $tabContent, function() {
  8819. $nav.trigger({
  8820. type: 'opened.tabs.amui',
  8821. relatedTarget: previous
  8822. });
  8823. });
  8824. };
  8825. Tabs.prototype.activate = function($element, $container, callback) {
  8826. this.transitioning = true;
  8827. var $active = $container.find('> .am-active');
  8828. var transition = callback && supportTransition && !!$active.length;
  8829. $active.removeClass('am-active am-in');
  8830. $element.addClass('am-active');
  8831. if (transition) {
  8832. $element.redraw(); // reflow for transition
  8833. $element.addClass('am-in');
  8834. } else {
  8835. $element.removeClass('am-fade');
  8836. }
  8837. function complete() {
  8838. callback && callback();
  8839. this.transitioning = false;
  8840. }
  8841. transition ?
  8842. $active.one(supportTransition.end, $.proxy(complete, this)) :
  8843. $.proxy(complete, this)();
  8844. };
  8845. Tabs.prototype.getNextNav = function($panel) {
  8846. var navIndex = this.$tabPanels.index($panel);
  8847. var rightSpring = 'am-animation-right-spring';
  8848. if (navIndex + 1 >= this.$navs.length) { // last one
  8849. animation && $panel.addClass(rightSpring).on(animation.end,
  8850. function() {
  8851. $panel.removeClass(rightSpring);
  8852. });
  8853. return null;
  8854. } else {
  8855. return this.$navs.eq(navIndex + 1);
  8856. }
  8857. };
  8858. Tabs.prototype.getPrevNav = function($panel) {
  8859. var navIndex = this.$tabPanels.index($panel);
  8860. var leftSpring = 'am-animation-left-spring';
  8861. if (navIndex === 0) { // first one
  8862. animation && $panel.addClass(leftSpring).on(animation.end,
  8863. function() {
  8864. $panel.removeClass(leftSpring);
  8865. });
  8866. return null;
  8867. } else {
  8868. return this.$navs.eq(navIndex - 1);
  8869. }
  8870. };
  8871. // Plugin
  8872. function Plugin(option) {
  8873. return this.each(function() {
  8874. var $this = $(this);
  8875. var $tabs = $this.is('.am-tabs') && $this || $this.closest(
  8876. '.am-tabs');
  8877. var data = $tabs.data('amui.tabs');
  8878. var options = $.extend({}, $.isPlainObject(option) ? option : {},
  8879. UI.utils.parseOptions($this.data('amTabs')));
  8880. if (!data) {
  8881. $tabs.data('amui.tabs', (data = new Tabs($tabs[0],
  8882. options)));
  8883. }
  8884. if (typeof option == 'string' && $this.is('.am-tabs-nav a')) {
  8885. data[option]($this);
  8886. }
  8887. });
  8888. }
  8889. $.fn.tabs = Plugin;
  8890. // Init code
  8891. UI.ready(function(context) {
  8892. $('[data-am-tabs]', context).tabs();
  8893. });
  8894. $.AMUI.tabs = Tabs;
  8895. module.exports = Tabs;
  8896. // TODO: 1. Ajax 支持
  8897. // 2. touch 事件处理逻辑优化
  8898. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  8899. "undefined" ? self : typeof window !== "undefined" ? window : {})
  8900. }, {
  8901. "./core": 4,
  8902. "./util.hammer": 50
  8903. }
  8904. ],
  8905. 45: [
  8906. function(require, module, exports) {
  8907. (function(global) {
  8908. 'use strict';
  8909. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  8910. "undefined" ? global.jQuery : null);
  8911. var UI = require('./core');
  8912. /**
  8913. * UCheck
  8914. * @via https://github.com/designmodo/Flat-UI/blob/8ef98df23ba7f5033e596a9bd05b53b535a9fe99/js/radiocheck.js
  8915. * @license CC BY 3.0 & MIT
  8916. * @param element
  8917. * @param options
  8918. * @constructor
  8919. */
  8920. var UCheck = function(element, options) {
  8921. this.options = $.extend({}, UCheck.DEFAULTS, options);
  8922. // this.options = $.extend({}, UCheck.DEFAULTS, this.$element.data(), options);
  8923. this.$element = $(element);
  8924. this.init();
  8925. };
  8926. UCheck.DEFAULTS = {
  8927. checkboxClass: 'am-ucheck-checkbox',
  8928. radioClass: 'am-ucheck-radio',
  8929. checkboxTpl: '<span class="am-ucheck-icons">' +
  8930. '<i class="am-icon-unchecked"></i><i class="am-icon-checked"></i></span>',
  8931. radioTpl: '<span class="am-ucheck-icons">' +
  8932. '<i class="am-icon-unchecked"></i><i class="am-icon-checked"></i></span>'
  8933. };
  8934. UCheck.prototype.init = function() {
  8935. var $element = this.$element;
  8936. var element = $element[0];
  8937. var options = this.options;
  8938. if (element.type === 'checkbox') {
  8939. $element.addClass(options.checkboxClass).after(options.checkboxTpl);
  8940. } else if (element.type === 'radio') {
  8941. $element.addClass(options.radioClass).after(options.radioTpl);
  8942. }
  8943. };
  8944. UCheck.prototype.check = function() {
  8945. this.$element.prop('checked', true)
  8946. .trigger('change.ucheck.amui').trigger('checked.ucheck.amui');
  8947. },
  8948. UCheck.prototype.uncheck = function() {
  8949. this.$element.prop('checked', false)
  8950. .trigger('change.ucheck.amui').trigger('unchecked.ucheck.amui');
  8951. },
  8952. UCheck.prototype.toggle = function() {
  8953. this.$element.prop('checked', function(i, value) {
  8954. return !value;
  8955. }).trigger('change.ucheck.amui').trigger('toggled.ucheck.amui');
  8956. },
  8957. UCheck.prototype.disable = function() {
  8958. this.$element.prop('disabled', true).
  8959. trigger('change.ucheck.amui').trigger('disabled.ucheck.amui');
  8960. },
  8961. UCheck.prototype.enable = function() {
  8962. this.$element.prop('disabled', false);
  8963. this.$element.trigger('change.ucheck.amui').trigger(
  8964. 'enabled.ucheck.amui');
  8965. },
  8966. UCheck.prototype.destroy = function() {
  8967. this.$element.removeData('amui.ucheck').
  8968. removeClass(this.options.checkboxClass + ' ' + this.options.radioClass)
  8969. .
  8970. next('.am-ucheck-icons').remove().
  8971. end().trigger('destroyed.ucheck.amui');
  8972. };
  8973. function Plugin(option) {
  8974. return this.each(function() {
  8975. var $this = $(this);
  8976. var data = $this.data('amui.ucheck');
  8977. var options = $.extend({}, UI.utils.parseOptions($this.data(
  8978. 'amUcheck')),
  8979. typeof option === 'object' && option);
  8980. if (!data && option === 'destroy') {
  8981. return;
  8982. }
  8983. if (!data) {
  8984. $this.data('amui.ucheck', (data = new UCheck(this,
  8985. options)));
  8986. }
  8987. if (typeof option == 'string') {
  8988. data[option] && data[option]();
  8989. }
  8990. // Adding 'am-nohover' class for touch devices
  8991. if (UI.support.touch) {
  8992. $this.parent().hover(function() {
  8993. $this.addClass('am-nohover');
  8994. }, function() {
  8995. $this.removeClass('am-nohover');
  8996. });
  8997. }
  8998. });
  8999. }
  9000. $.fn.uCheck = Plugin;
  9001. UI.ready(function(context) {
  9002. $('[data-am-ucheck]', context).uCheck();
  9003. });
  9004. $.AMUI.uCheck = UCheck;
  9005. module.exports = UCheck;
  9006. // TODO: 与表单验证结合使用的情况
  9007. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  9008. "undefined" ? self : typeof window !== "undefined" ? window : {})
  9009. }, {
  9010. "./core": 4
  9011. }
  9012. ],
  9013. 46: [
  9014. function(require, module, exports) {
  9015. (function(global) {
  9016. 'use strict';
  9017. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  9018. "undefined" ? global.jQuery : null);
  9019. var UI = require('./core');
  9020. var Validator = function(element, options) {
  9021. this.options = $.extend({}, Validator.DEFAULTS, options);
  9022. this.options.patterns = $.extend({}, Validator.patterns,
  9023. this.options.patterns);
  9024. var locales = this.options.locales;
  9025. !Validator.validationMessages[locales] && (this.options.locales =
  9026. 'zh_CN');
  9027. this.$element = $(element);
  9028. this.init();
  9029. };
  9030. Validator.DEFAULTS = {
  9031. debug: false,
  9032. locales: 'zh_CN',
  9033. H5validation: false,
  9034. H5inputType: ['email', 'url', 'number'],
  9035. patterns: {},
  9036. patternClassPrefix: 'js-pattern-',
  9037. activeClass: 'am-active',
  9038. inValidClass: 'am-field-error',
  9039. validClass: 'am-field-valid',
  9040. validateOnSubmit: true,
  9041. // Elements to validate with allValid (only validating visible elements)
  9042. // :input: selects all input, textarea, select and button elements.
  9043. allFields: ':input:visible:not(:button, :disabled, .am-novalidate)',
  9044. // Custom events
  9045. customEvents: 'validate',
  9046. // Keyboard events
  9047. keyboardFields: ':input:not(:button, :disabled,.am-novalidate)',
  9048. keyboardEvents: 'focusout, change', // keyup, focusin
  9049. activeKeyup: true,
  9050. // Mouse events
  9051. pointerFields: 'input[type="range"]:not(:disabled, .am-novalidate), ' +
  9052. 'input[type="radio"]:not(:disabled, .am-novalidate), ' +
  9053. 'input[type="checkbox"]:not(:disabled, .am-novalidate), ' +
  9054. 'select:not(:disabled, .am-novalidate), ' +
  9055. 'option:not(:disabled, .am-novalidate)',
  9056. pointerEvents: 'click',
  9057. onValid: function(validity) {},
  9058. onInValid: function(validity) {},
  9059. markValid: function(validity) {
  9060. // this is Validator instance
  9061. var options = this.options;
  9062. var $field = $(validity.field);
  9063. var $parent = $field.closest('.am-form-group');
  9064. $field.addClass(options.validClass).removeClass(options.inValidClass);
  9065. $parent.addClass('am-form-success').removeClass('am-form-error');
  9066. options.onValid.call(this, validity);
  9067. },
  9068. markInValid: function(validity) {
  9069. var options = this.options;
  9070. var $field = $(validity.field);
  9071. var $parent = $field.closest('.am-form-group');
  9072. $field.addClass(options.inValidClass + ' ' + options.activeClass)
  9073. .
  9074. removeClass(options.validClass);
  9075. $parent.addClass('am-form-error').removeClass('am-form-success');
  9076. options.onInValid.call(this, validity);
  9077. },
  9078. validate: function(validity) {
  9079. // return validity;
  9080. },
  9081. submit: null
  9082. };
  9083. /* jshint -W101 */
  9084. Validator.patterns = {
  9085. email: /^((([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/,
  9086. url: /^(https?|ftp):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
  9087. // Number, including positive, negative, and floating decimal
  9088. number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/,
  9089. dateISO: /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,
  9090. integer: /^-?\d+$/
  9091. };
  9092. /* jshint +W101 */
  9093. Validator.validationMessages = {
  9094. zh_CN: {
  9095. valueMissing: '请填写此字段',
  9096. customError: {
  9097. tooShort: '至少填写 %s 个字符',
  9098. checkedOverflow: '至多选择 %s 项',
  9099. checkedUnderflow: '至少选择 %s 项'
  9100. },
  9101. patternMismatch: '请按照要求的格式填写',
  9102. rangeOverflow: '请填写小于等于 %s 的值',
  9103. rangeUnderflow: '请填写大于等于 %s 的值',
  9104. stepMismatch: '',
  9105. tooLong: '至多填写 %s 个字符',
  9106. typeMismatch: '请按照要求的类型填写'
  9107. }
  9108. };
  9109. // TODO: 考虑表单元素不是 form 子元素的情形
  9110. // TODO: change/click/focusout 同时触发时处理重复
  9111. // TODO: 显示提示信息
  9112. Validator.prototype.init = function() {
  9113. var _this = this;
  9114. var $element = this.$element;
  9115. var options = this.options;
  9116. // using H5 form validation if option set and supported
  9117. if (options.H5validation && UI.support.formValidation) {
  9118. return false;
  9119. }
  9120. // disable HTML5 form validation
  9121. $element.attr('novalidate', 'novalidate');
  9122. function regexToPattern(regex) {
  9123. var pattern = regex.toString();
  9124. return pattern.substring(1, pattern.length - 1);
  9125. }
  9126. // add pattern to H5 input type
  9127. $.each(options.H5inputType, function(i, type) {
  9128. var $field = $element.find('input[type=' + type + ']');
  9129. if (!$field.attr('pattern')) {
  9130. $field.attr('pattern', regexToPattern(options.patterns[type]));
  9131. }
  9132. });
  9133. // add pattern to .js-pattern-xx
  9134. $.each(options.patterns, function(key, value) {
  9135. var $field = $element.find('.' + options.patternClassPrefix +
  9136. key);
  9137. !$field.attr('pattern') && $field.attr('pattern',
  9138. regexToPattern(value));
  9139. });
  9140. $element.submit(function(e) {
  9141. if (typeof options.submit === 'function') {
  9142. return options.submit.call(_this, e);
  9143. }
  9144. if (options.validateOnSubmit) {
  9145. return _this.isFormValid();
  9146. }
  9147. });
  9148. function bindEvents(fields, eventFlags, debounce) {
  9149. var events = eventFlags.split(',');
  9150. var validate = function(e) {
  9151. // console.log(e.type);
  9152. _this.validate(this);
  9153. };
  9154. if (debounce) {
  9155. validate = UI.utils.debounce(validate, debounce);
  9156. }
  9157. $.each(events, function(i, event) {
  9158. $element.on(event + '.validator.amui', fields, validate);
  9159. });
  9160. }
  9161. bindEvents(':input', options.customEvents);
  9162. bindEvents(options.keyboardFields, options.keyboardEvents);
  9163. bindEvents(options.pointerFields, options.pointerEvents);
  9164. // active filed
  9165. bindEvents('.am-active', 'keyup', 50);
  9166. bindEvents('textarea[maxlength]', 'keyup', 50);
  9167. };
  9168. Validator.prototype.isValid = function(field) {
  9169. var $field = $(field);
  9170. // valid field not has been validated
  9171. if ($field.data('validity') === undefined) {
  9172. this.validate(field);
  9173. }
  9174. return $field.data('validity') && $field.data('validity').valid;
  9175. };
  9176. Validator.prototype.validate = function(field) {
  9177. var _this = this;
  9178. var $element = this.$element;
  9179. var options = this.options;
  9180. var $field = $(field);
  9181. // Validate equal, e.g. confirm password
  9182. var equalTo = $field.data('equalTo');
  9183. if (equalTo) {
  9184. $field.attr('pattern', '^' + $element.find(equalTo).val() + '$');
  9185. }
  9186. var pattern = $field.attr('pattern') || false;
  9187. var re = new RegExp(pattern);
  9188. var $radioGroup = null;
  9189. var $checkboxGroup = null;
  9190. // if checkbox, return `:chcked` length
  9191. var value = ($field.is('[type=checkbox]')) ?
  9192. ($checkboxGroup = $element.find('input[name="' + field.name +
  9193. '"]')).
  9194. filter(':checked').length: ($field.is('[type=radio]') ?
  9195. ($radioGroup = this.$element.find('input[name="' + field.name +
  9196. '"]')).filter(':checked').length > 0 : $field.val());
  9197. // if checkbox, valid the first input of checkbox group
  9198. $field = ($checkboxGroup && $checkboxGroup.length) ?
  9199. $checkboxGroup.first() : $field;
  9200. var required = ($field.attr('required') !== undefined) &&
  9201. ($field.attr('required') !== 'false');
  9202. var maxLength = parseInt($field.attr('maxlength'), 10);
  9203. var minLength = parseInt($field.attr('minlength'), 10);
  9204. var min = Number($field.attr('min'));
  9205. var max = Number($field.attr('max'));
  9206. var validity = this.createValidity({
  9207. field: $field[0],
  9208. valid: true
  9209. });
  9210. // Debug
  9211. if (options.debug && window.console) {
  9212. console.log('Validate: value -> [' + value + ', regex -> [' +
  9213. re +
  9214. '], required -> ' + required);
  9215. console.log('Regex test: ' + re.test(value) + ', Pattern: ' +
  9216. pattern);
  9217. }
  9218. // check value length
  9219. if (!isNaN(maxLength) && value.length > maxLength) {
  9220. validity.valid = false;
  9221. validity.tooLong = true;
  9222. }
  9223. if (!isNaN(minLength) && value.length < minLength) {
  9224. validity.valid = false;
  9225. validity.customError = 'tooShort';
  9226. }
  9227. // check minimum and maximum
  9228. // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input
  9229. // TODO: 日期验证最小值和最大值 min/max
  9230. if (!isNaN(min) && Number(value) < min) {
  9231. validity.valid = false;
  9232. validity.rangeUnderflow = true;
  9233. }
  9234. if (!isNaN(max) && Number(value) > max) {
  9235. validity.valid = false;
  9236. validity.rangeOverflow = true;
  9237. }
  9238. // check required
  9239. if (required && !value) {
  9240. validity.valid = false;
  9241. validity.valueMissing = true;
  9242. } else if (($checkboxGroup || $field.is(
  9243. 'select[multiple="multiple"]')) &&
  9244. value) {
  9245. // check checkboxes / multiple select with `minchecked`/`maxchecked` attr
  9246. // var $multipleField = $checkboxGroup ? $checkboxGroup.first() : $field;
  9247. // if is select[multiple="multiple"], return selected length
  9248. value = $checkboxGroup ? value : value.length;
  9249. // at least checked
  9250. var minChecked = parseInt($field.attr('minchecked'), 10);
  9251. // at most checked
  9252. var maxChecked = parseInt($field.attr('maxchecked'), 10);
  9253. if (!isNaN(minChecked) && value < minChecked) {
  9254. // console.log('At least [%d] items checked!', maxChecked);
  9255. validity.valid = false;
  9256. validity.customError = 'checkedUnderflow';
  9257. }
  9258. if (!isNaN(maxChecked) && value > maxChecked) {
  9259. // console.log('At most [%d] items checked!', maxChecked);
  9260. validity.valid = false;
  9261. validity.customError = 'checkedOverflow';
  9262. }
  9263. } else if (pattern && !re.test(value) && value) { // check pattern
  9264. validity.valid = false;
  9265. validity.patternMismatch = true;
  9266. }
  9267. var validateComplete = function(validity) {
  9268. this.markField(validity);
  9269. $field.trigger('validated.field.validator.amui', validity).
  9270. data('validity', validity);
  9271. // validate the radios/checkboxes with the same name
  9272. var $fields = $radioGroup || $checkboxGroup;
  9273. if ($fields) {
  9274. $fields.not($field).data('validity', validity).each(
  9275. function() {
  9276. validity.field = this;
  9277. _this.markField(validity);
  9278. });
  9279. }
  9280. };
  9281. // Run custom validate
  9282. var customValidate;
  9283. (typeof options.validate === 'function') &&
  9284. (customValidate = options.validate.call(this, validity));
  9285. if (customValidate) {
  9286. return $.when(customValidate).always(function(validity) {
  9287. validateComplete.call(_this, validity);
  9288. });
  9289. }
  9290. validateComplete.call(this, validity);
  9291. };
  9292. Validator.prototype.markField = function(validity) {
  9293. var options = this.options;
  9294. var flag = 'mark' + (validity.valid ? '' : 'In') + 'Valid';
  9295. options[flag] && options[flag].call(this, validity);
  9296. };
  9297. // check all fields in the form are valid
  9298. Validator.prototype.validateAll = function() {
  9299. var _this = this;
  9300. var $element = this.$element;
  9301. var options = this.options;
  9302. var $allFields = $element.find(options.allFields);
  9303. var radioNames = [];
  9304. var valid = true;
  9305. var formValidity = [];
  9306. var $inValidFields = $([]);
  9307. $element.trigger('validate.form.validator.amui');
  9308. // Filter radio with the same name and keep only one,
  9309. // since they will be checked as a group by isValid()
  9310. var $filteredFields = $allFields.filter(function(index) {
  9311. var name;
  9312. if (this.tagName === 'INPUT' && this.type === 'radio') {
  9313. name = this.name;
  9314. if (radioNames[name] === true) {
  9315. return false;
  9316. }
  9317. radioNames[name] = true;
  9318. }
  9319. return true;
  9320. });
  9321. $filteredFields.each(function() {
  9322. var fieldValid = _this.isValid(this);
  9323. valid = !!fieldValid && valid;
  9324. formValidity.push($(this).data('validity'));
  9325. if (!fieldValid) {
  9326. $inValidFields = $inValidFields.add($(this), $element);
  9327. }
  9328. });
  9329. var validity = {
  9330. valid: valid,
  9331. $invalidFields: $inValidFields,
  9332. validity: formValidity
  9333. };
  9334. $element.trigger('validated.form.validator.amui', validity);
  9335. return validity;
  9336. };
  9337. Validator.prototype.isFormValid = function() {
  9338. var formValid = this.validateAll();
  9339. if (!formValid.valid) {
  9340. formValid.$invalidFields.first().focus();
  9341. this.$element.trigger('invalid.validator.amui');
  9342. return false;
  9343. }
  9344. this.$element.trigger('valid.validator.amui');
  9345. return true;
  9346. };
  9347. // customErrors:
  9348. // 1. tooShort
  9349. // 2. checkedOverflow
  9350. // 3. checkedUnderflow
  9351. Validator.prototype.createValidity = function(validity) {
  9352. return $.extend({
  9353. customError: validity.customError || false,
  9354. patternMismatch: validity.patternMismatch || false,
  9355. rangeOverflow: validity.rangeOverflow || false, // higher than maximum
  9356. rangeUnderflow: validity.rangeUnderflow || false, // lower than minimum
  9357. stepMismatch: validity.stepMismatch || false,
  9358. tooLong: validity.tooLong || false,
  9359. // value is not in the correct syntax
  9360. typeMismatch: validity.typeMismatch || false,
  9361. valid: validity.valid || true,
  9362. // Returns true if the element has no value but is a required field
  9363. valueMissing: validity.valueMissing || false
  9364. }, validity);
  9365. };
  9366. function Plugin(option) {
  9367. return this.each(function() {
  9368. var $this = $(this);
  9369. var data = $this.data('amui.validator');
  9370. var options = $.extend({}, UI.utils.parseOptions($this.data(
  9371. 'amValidator')),
  9372. typeof option === 'object' && option);
  9373. if (!data) {
  9374. $this.data('amui.validator', (data = new Validator(this,
  9375. options)));
  9376. }
  9377. if (typeof option === 'string') {
  9378. data[option] && data[option]();
  9379. }
  9380. });
  9381. }
  9382. $.fn.validator = Plugin;
  9383. // init code
  9384. UI.ready(function(context) {
  9385. $('[data-am-validator]', context).validator();
  9386. });
  9387. $.AMUI.validator = Validator;
  9388. module.exports = Validator;
  9389. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  9390. "undefined" ? self : typeof window !== "undefined" ? window : {})
  9391. }, {
  9392. "./core": 4
  9393. }
  9394. ],
  9395. 47: [
  9396. function(require, module, exports) {
  9397. (function(global) {
  9398. 'use strict';
  9399. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  9400. "undefined" ? global.jQuery : null);
  9401. require('./core');
  9402. var cookie = {
  9403. get: function(name) {
  9404. var cookieName = encodeURIComponent(name) + '=';
  9405. var cookieStart = document.cookie.indexOf(cookieName);
  9406. var cookieValue = null;
  9407. var cookieEnd;
  9408. if (cookieStart > -1) {
  9409. cookieEnd = document.cookie.indexOf(';', cookieStart);
  9410. if (cookieEnd == -1) {
  9411. cookieEnd = document.cookie.length;
  9412. }
  9413. cookieValue = decodeURIComponent(document.cookie.substring(
  9414. cookieStart +
  9415. cookieName.length, cookieEnd));
  9416. }
  9417. return cookieValue;
  9418. },
  9419. set: function(name, value, expires, path, domain, secure) {
  9420. var cookieText = encodeURIComponent(name) + '=' +
  9421. encodeURIComponent(value);
  9422. if (expires instanceof Date) {
  9423. cookieText += '; expires=' + expires.toGMTString();
  9424. }
  9425. if (path) {
  9426. cookieText += '; path=' + path;
  9427. }
  9428. if (domain) {
  9429. cookieText += '; domain=' + domain;
  9430. }
  9431. if (secure) {
  9432. cookieText += '; secure';
  9433. }
  9434. document.cookie = cookieText;
  9435. },
  9436. unset: function(name, path, domain, secure) {
  9437. this.set(name, '', new Date(0), path, domain, secure);
  9438. }
  9439. };
  9440. $.AMUI.utils.cookie = cookie;
  9441. module.exports = cookie;
  9442. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  9443. "undefined" ? self : typeof window !== "undefined" ? window : {})
  9444. }, {
  9445. "./core": 4
  9446. }
  9447. ],
  9448. 48: [
  9449. function(require, module, exports) {
  9450. (function(global) {
  9451. 'use strict';
  9452. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  9453. "undefined" ? global.jQuery : null);
  9454. /**
  9455. * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
  9456. *
  9457. * @version 1.0.3
  9458. * @codingstandard ftlabs-jsv2
  9459. * @copyright The Financial Times Limited [All Rights Reserved]
  9460. * @license MIT License (see LICENSE.txt)
  9461. */
  9462. /*jslint browser:true, node:true*/
  9463. /*global define, Event, Node*/
  9464. /**
  9465. * Instantiate fast-clicking listeners on the specified layer.
  9466. *
  9467. * @constructor
  9468. * @param {Element} layer The layer to listen on
  9469. * @param {Object} options The options to override the defaults
  9470. */
  9471. function FastClick(layer, options) {
  9472. var oldOnClick;
  9473. options = options || {};
  9474. /**
  9475. * Whether a click is currently being tracked.
  9476. *
  9477. * @type boolean
  9478. */
  9479. this.trackingClick = false;
  9480. /**
  9481. * Timestamp for when click tracking started.
  9482. *
  9483. * @type number
  9484. */
  9485. this.trackingClickStart = 0;
  9486. /**
  9487. * The element being tracked for a click.
  9488. *
  9489. * @type EventTarget
  9490. */
  9491. this.targetElement = null;
  9492. /**
  9493. * X-coordinate of touch start event.
  9494. *
  9495. * @type number
  9496. */
  9497. this.touchStartX = 0;
  9498. /**
  9499. * Y-coordinate of touch start event.
  9500. *
  9501. * @type number
  9502. */
  9503. this.touchStartY = 0;
  9504. /**
  9505. * ID of the last touch, retrieved from Touch.identifier.
  9506. *
  9507. * @type number
  9508. */
  9509. this.lastTouchIdentifier = 0;
  9510. /**
  9511. * Touchmove boundary, beyond which a click will be cancelled.
  9512. *
  9513. * @type number
  9514. */
  9515. this.touchBoundary = options.touchBoundary || 10;
  9516. /**
  9517. * The FastClick layer.
  9518. *
  9519. * @type Element
  9520. */
  9521. this.layer = layer;
  9522. /**
  9523. * The minimum time between tap(touchstart and touchend) events
  9524. *
  9525. * @type number
  9526. */
  9527. this.tapDelay = options.tapDelay || 200;
  9528. if (FastClick.notNeeded(layer)) {
  9529. return;
  9530. }
  9531. // Some old versions of Android don't have Function.prototype.bind
  9532. function bind(method, context) {
  9533. return function() {
  9534. return method.apply(context, arguments);
  9535. };
  9536. }
  9537. var methods = ['onMouse', 'onClick', 'onTouchStart',
  9538. 'onTouchMove', 'onTouchEnd', 'onTouchCancel'
  9539. ];
  9540. var context = this;
  9541. for (var i = 0, l = methods.length; i < l; i++) {
  9542. context[methods[i]] = bind(context[methods[i]], context);
  9543. }
  9544. // Set up event handlers as required
  9545. if (deviceIsAndroid) {
  9546. layer.addEventListener('mouseover', this.onMouse, true);
  9547. layer.addEventListener('mousedown', this.onMouse, true);
  9548. layer.addEventListener('mouseup', this.onMouse, true);
  9549. }
  9550. layer.addEventListener('click', this.onClick, true);
  9551. layer.addEventListener('touchstart', this.onTouchStart, false);
  9552. layer.addEventListener('touchmove', this.onTouchMove, false);
  9553. layer.addEventListener('touchend', this.onTouchEnd, false);
  9554. layer.addEventListener('touchcancel', this.onTouchCancel, false);
  9555. // Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
  9556. // which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
  9557. // layer when they are cancelled.
  9558. if (!Event.prototype.stopImmediatePropagation) {
  9559. layer.removeEventListener = function(type, callback, capture) {
  9560. var rmv = Node.prototype.removeEventListener;
  9561. if (type === 'click') {
  9562. rmv.call(layer, type, callback.hijacked || callback,
  9563. capture);
  9564. } else {
  9565. rmv.call(layer, type, callback, capture);
  9566. }
  9567. };
  9568. layer.addEventListener = function(type, callback, capture) {
  9569. var adv = Node.prototype.addEventListener;
  9570. if (type === 'click') {
  9571. adv.call(layer, type, callback.hijacked || (callback.hijacked =
  9572. function(event) {
  9573. if (!event.propagationStopped) {
  9574. callback(event);
  9575. }
  9576. }), capture);
  9577. } else {
  9578. adv.call(layer, type, callback, capture);
  9579. }
  9580. };
  9581. }
  9582. // If a handler is already declared in the element's onclick attribute, it will be fired before
  9583. // FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
  9584. // adding it as listener.
  9585. if (typeof layer.onclick === 'function') {
  9586. // Android browser on at least 3.2 requires a new reference to the function in layer.onclick
  9587. // - the old one won't work if passed to addEventListener directly.
  9588. oldOnClick = layer.onclick;
  9589. layer.addEventListener('click', function(event) {
  9590. oldOnClick(event);
  9591. }, false);
  9592. layer.onclick = null;
  9593. }
  9594. }
  9595. /**
  9596. * Android requires exceptions.
  9597. *
  9598. * @type boolean
  9599. */
  9600. var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
  9601. /**
  9602. * iOS requires exceptions.
  9603. *
  9604. * @type boolean
  9605. */
  9606. var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
  9607. /**
  9608. * iOS 4 requires an exception for select elements.
  9609. *
  9610. * @type boolean
  9611. */
  9612. var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
  9613. /**
  9614. * iOS 6.0(+?) requires the target element to be manually derived
  9615. *
  9616. * @type boolean
  9617. */
  9618. var deviceIsIOSWithBadTarget = deviceIsIOS && (
  9619. /OS ([6-9]|\d{2})_\d/).test(navigator.userAgent);
  9620. /**
  9621. * BlackBerry requires exceptions.
  9622. *
  9623. * @type boolean
  9624. */
  9625. var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;
  9626. /**
  9627. * Determine whether a given element requires a native click.
  9628. *
  9629. * @param {EventTarget|Element} target Target DOM element
  9630. * @returns {boolean} Returns true if the element needs a native click
  9631. */
  9632. FastClick.prototype.needsClick = function(target) {
  9633. switch (target.nodeName.toLowerCase()) {
  9634. // Don't send a synthetic click to disabled inputs (issue #62)
  9635. case 'button':
  9636. case 'select':
  9637. case 'textarea':
  9638. if (target.disabled) {
  9639. return true;
  9640. }
  9641. break;
  9642. case 'input':
  9643. // File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
  9644. if ((deviceIsIOS && target.type === 'file') || target.disabled) {
  9645. return true;
  9646. }
  9647. break;
  9648. case 'label':
  9649. case 'video':
  9650. return true;
  9651. }
  9652. return (/\bneedsclick\b/).test(target.className);
  9653. };
  9654. /**
  9655. * Determine whether a given element requires a call to focus to simulate click into element.
  9656. *
  9657. * @param {EventTarget|Element} target Target DOM element
  9658. * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
  9659. */
  9660. FastClick.prototype.needsFocus = function(target) {
  9661. switch (target.nodeName.toLowerCase()) {
  9662. case 'textarea':
  9663. return true;
  9664. case 'select':
  9665. return !deviceIsAndroid;
  9666. case 'input':
  9667. switch (target.type) {
  9668. case 'button':
  9669. case 'checkbox':
  9670. case 'file':
  9671. case 'image':
  9672. case 'radio':
  9673. case 'submit':
  9674. return false;
  9675. }
  9676. // No point in attempting to focus disabled inputs
  9677. return !target.disabled && !target.readOnly;
  9678. default:
  9679. return (/\bneedsfocus\b/).test(target.className);
  9680. }
  9681. };
  9682. /**
  9683. * Send a click event to the specified element.
  9684. *
  9685. * @param {EventTarget|Element} targetElement
  9686. * @param {Event} event
  9687. */
  9688. FastClick.prototype.sendClick = function(targetElement, event) {
  9689. var clickEvent, touch;
  9690. // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
  9691. if (document.activeElement && document.activeElement !==
  9692. targetElement) {
  9693. document.activeElement.blur();
  9694. }
  9695. touch = event.changedTouches[0];
  9696. // Synthesise a click event, with an extra attribute so it can be tracked
  9697. clickEvent = document.createEvent('MouseEvents');
  9698. clickEvent.initMouseEvent(this.determineEventType(targetElement),
  9699. true, true, window, 1, touch.screenX, touch.screenY, touch.clientX,
  9700. touch.clientY, false, false, false, false, 0, null);
  9701. clickEvent.forwardedTouchEvent = true;
  9702. targetElement.dispatchEvent(clickEvent);
  9703. };
  9704. FastClick.prototype.determineEventType = function(targetElement) {
  9705. //Issue #159: Android Chrome Select Box does not open with a synthetic click event
  9706. if (deviceIsAndroid && targetElement.tagName.toLowerCase() ===
  9707. 'select') {
  9708. return 'mousedown';
  9709. }
  9710. return 'click';
  9711. };
  9712. /**
  9713. * @param {EventTarget|Element} targetElement
  9714. */
  9715. FastClick.prototype.focus = function(targetElement) {
  9716. var length;
  9717. // Issue #160: on iOS 7, some input elements (e.g. date datetime) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
  9718. if (deviceIsIOS && targetElement.setSelectionRange &&
  9719. targetElement.type.indexOf('date') !== 0 && targetElement.type !==
  9720. 'time') {
  9721. length = targetElement.value.length;
  9722. targetElement.setSelectionRange(length, length);
  9723. } else {
  9724. targetElement.focus();
  9725. }
  9726. };
  9727. /**
  9728. * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
  9729. *
  9730. * @param {EventTarget|Element} targetElement
  9731. */
  9732. FastClick.prototype.updateScrollParent = function(targetElement) {
  9733. var scrollParent, parentElement;
  9734. scrollParent = targetElement.fastClickScrollParent;
  9735. // Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
  9736. // target element was moved to another parent.
  9737. if (!scrollParent || !scrollParent.contains(targetElement)) {
  9738. parentElement = targetElement;
  9739. do {
  9740. if (parentElement.scrollHeight > parentElement.offsetHeight) {
  9741. scrollParent = parentElement;
  9742. targetElement.fastClickScrollParent = parentElement;
  9743. break;
  9744. }
  9745. parentElement = parentElement.parentElement;
  9746. } while (parentElement);
  9747. }
  9748. // Always update the scroll top tracker if possible.
  9749. if (scrollParent) {
  9750. scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
  9751. }
  9752. };
  9753. /**
  9754. * @param {EventTarget} targetElement
  9755. * @returns {Element|EventTarget}
  9756. */
  9757. FastClick.prototype.getTargetElementFromEventTarget = function(
  9758. eventTarget) {
  9759. // On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
  9760. if (eventTarget.nodeType === Node.TEXT_NODE) {
  9761. return eventTarget.parentNode;
  9762. }
  9763. return eventTarget;
  9764. };
  9765. /**
  9766. * On touch start, record the position and scroll offset.
  9767. *
  9768. * @param {Event} event
  9769. * @returns {boolean}
  9770. */
  9771. FastClick.prototype.onTouchStart = function(event) {
  9772. var targetElement, touch, selection;
  9773. // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
  9774. if (event.targetTouches.length > 1) {
  9775. return true;
  9776. }
  9777. targetElement = this.getTargetElementFromEventTarget(event.target);
  9778. touch = event.targetTouches[0];
  9779. if (deviceIsIOS) {
  9780. // Only trusted events will deselect text on iOS (issue #49)
  9781. selection = window.getSelection();
  9782. if (selection.rangeCount && !selection.isCollapsed) {
  9783. return true;
  9784. }
  9785. if (!deviceIsIOS4) {
  9786. // Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
  9787. // when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
  9788. // with the same identifier as the touch event that previously triggered the click that triggered the alert.
  9789. // Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
  9790. // immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
  9791. // Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,
  9792. // which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,
  9793. // random integers, it's safe to to continue if the identifier is 0 here.
  9794. if (touch.identifier && touch.identifier === this.lastTouchIdentifier) {
  9795. event.preventDefault();
  9796. return false;
  9797. }
  9798. this.lastTouchIdentifier = touch.identifier;
  9799. // If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
  9800. // 1) the user does a fling scroll on the scrollable layer
  9801. // 2) the user stops the fling scroll with another tap
  9802. // then the event.target of the last 'touchend' event will be the element that was under the user's finger
  9803. // when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
  9804. // is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
  9805. this.updateScrollParent(targetElement);
  9806. }
  9807. }
  9808. this.trackingClick = true;
  9809. this.trackingClickStart = event.timeStamp;
  9810. this.targetElement = targetElement;
  9811. this.touchStartX = touch.pageX;
  9812. this.touchStartY = touch.pageY;
  9813. // Prevent phantom clicks on fast double-tap (issue #36)
  9814. if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
  9815. event.preventDefault();
  9816. }
  9817. return true;
  9818. };
  9819. /**
  9820. * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
  9821. *
  9822. * @param {Event} event
  9823. * @returns {boolean}
  9824. */
  9825. FastClick.prototype.touchHasMoved = function(event) {
  9826. var touch = event.changedTouches[0],
  9827. boundary = this.touchBoundary;
  9828. if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(
  9829. touch.pageY - this.touchStartY) > boundary) {
  9830. return true;
  9831. }
  9832. return false;
  9833. };
  9834. /**
  9835. * Update the last position.
  9836. *
  9837. * @param {Event} event
  9838. * @returns {boolean}
  9839. */
  9840. FastClick.prototype.onTouchMove = function(event) {
  9841. if (!this.trackingClick) {
  9842. return true;
  9843. }
  9844. // If the touch has moved, cancel the click tracking
  9845. if (this.targetElement !== this.getTargetElementFromEventTarget(
  9846. event.target) || this.touchHasMoved(event)) {
  9847. this.trackingClick = false;
  9848. this.targetElement = null;
  9849. }
  9850. return true;
  9851. };
  9852. /**
  9853. * Attempt to find the labelled control for the given label element.
  9854. *
  9855. * @param {EventTarget|HTMLLabelElement} labelElement
  9856. * @returns {Element|null}
  9857. */
  9858. FastClick.prototype.findControl = function(labelElement) {
  9859. // Fast path for newer browsers supporting the HTML5 control attribute
  9860. if (labelElement.control !== undefined) {
  9861. return labelElement.control;
  9862. }
  9863. // All browsers under test that support touch events also support the HTML5 htmlFor attribute
  9864. if (labelElement.htmlFor) {
  9865. return document.getElementById(labelElement.htmlFor);
  9866. }
  9867. // If no for attribute exists, attempt to retrieve the first labellable descendant element
  9868. // the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
  9869. return labelElement.querySelector(
  9870. 'button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea'
  9871. );
  9872. };
  9873. /**
  9874. * On touch end, determine whether to send a click event at once.
  9875. *
  9876. * @param {Event} event
  9877. * @returns {boolean}
  9878. */
  9879. FastClick.prototype.onTouchEnd = function(event) {
  9880. var forElement, trackingClickStart, targetTagName, scrollParent,
  9881. touch, targetElement = this.targetElement;
  9882. if (!this.trackingClick) {
  9883. return true;
  9884. }
  9885. // Prevent phantom clicks on fast double-tap (issue #36)
  9886. if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
  9887. this.cancelNextClick = true;
  9888. return true;
  9889. }
  9890. // Reset to prevent wrong click cancel on input (issue #156).
  9891. this.cancelNextClick = false;
  9892. this.lastClickTime = event.timeStamp;
  9893. trackingClickStart = this.trackingClickStart;
  9894. this.trackingClick = false;
  9895. this.trackingClickStart = 0;
  9896. // On some iOS devices, the targetElement supplied with the event is invalid if the layer
  9897. // is performing a transition or scroll, and has to be re-detected manually. Note that
  9898. // for this to function correctly, it must be called *after* the event target is checked!
  9899. // See issue #57; also filed as rdar://13048589 .
  9900. if (deviceIsIOSWithBadTarget) {
  9901. touch = event.changedTouches[0];
  9902. // In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
  9903. targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset,
  9904. touch.pageY - window.pageYOffset) || targetElement;
  9905. targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
  9906. }
  9907. targetTagName = targetElement.tagName.toLowerCase();
  9908. if (targetTagName === 'label') {
  9909. forElement = this.findControl(targetElement);
  9910. if (forElement) {
  9911. this.focus(targetElement);
  9912. if (deviceIsAndroid) {
  9913. return false;
  9914. }
  9915. targetElement = forElement;
  9916. }
  9917. } else if (this.needsFocus(targetElement)) {
  9918. // Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
  9919. // Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
  9920. if ((event.timeStamp - trackingClickStart) > 100 || (
  9921. deviceIsIOS && window.top !== window && targetTagName ===
  9922. 'input')) {
  9923. this.targetElement = null;
  9924. return false;
  9925. }
  9926. this.focus(targetElement);
  9927. this.sendClick(targetElement, event);
  9928. // Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
  9929. // Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
  9930. if (!deviceIsIOS || targetTagName !== 'select') {
  9931. this.targetElement = null;
  9932. event.preventDefault();
  9933. }
  9934. return false;
  9935. }
  9936. if (deviceIsIOS && !deviceIsIOS4) {
  9937. // Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
  9938. // and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
  9939. scrollParent = targetElement.fastClickScrollParent;
  9940. if (scrollParent && scrollParent.fastClickLastScrollTop !==
  9941. scrollParent.scrollTop) {
  9942. return true;
  9943. }
  9944. }
  9945. // Prevent the actual click from going though - unless the target node is marked as requiring
  9946. // real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
  9947. if (!this.needsClick(targetElement)) {
  9948. event.preventDefault();
  9949. this.sendClick(targetElement, event);
  9950. }
  9951. return false;
  9952. };
  9953. /**
  9954. * On touch cancel, stop tracking the click.
  9955. *
  9956. * @returns {void}
  9957. */
  9958. FastClick.prototype.onTouchCancel = function() {
  9959. this.trackingClick = false;
  9960. this.targetElement = null;
  9961. };
  9962. /**
  9963. * Determine mouse events which should be permitted.
  9964. *
  9965. * @param {Event} event
  9966. * @returns {boolean}
  9967. */
  9968. FastClick.prototype.onMouse = function(event) {
  9969. // If a target element was never set (because a touch event was never fired) allow the event
  9970. if (!this.targetElement) {
  9971. return true;
  9972. }
  9973. if (event.forwardedTouchEvent) {
  9974. return true;
  9975. }
  9976. // Programmatically generated events targeting a specific element should be permitted
  9977. if (!event.cancelable) {
  9978. return true;
  9979. }
  9980. // Derive and check the target element to see whether the mouse event needs to be permitted;
  9981. // unless explicitly enabled, prevent non-touch click events from triggering actions,
  9982. // to prevent ghost/doubleclicks.
  9983. if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
  9984. // Prevent any user-added listeners declared on FastClick element from being fired.
  9985. if (event.stopImmediatePropagation) {
  9986. event.stopImmediatePropagation();
  9987. } else {
  9988. // Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
  9989. event.propagationStopped = true;
  9990. }
  9991. // Cancel the event
  9992. event.stopPropagation();
  9993. event.preventDefault();
  9994. return false;
  9995. }
  9996. // If the mouse event is permitted, return true for the action to go through.
  9997. return true;
  9998. };
  9999. /**
  10000. * On actual clicks, determine whether this is a touch-generated click, a click action occurring
  10001. * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
  10002. * an actual click which should be permitted.
  10003. *
  10004. * @param {Event} event
  10005. * @returns {boolean}
  10006. */
  10007. FastClick.prototype.onClick = function(event) {
  10008. var permitted;
  10009. // It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
  10010. if (this.trackingClick) {
  10011. this.targetElement = null;
  10012. this.trackingClick = false;
  10013. return true;
  10014. }
  10015. // Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
  10016. if (event.target.type === 'submit' && event.detail === 0) {
  10017. return true;
  10018. }
  10019. permitted = this.onMouse(event);
  10020. // Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
  10021. if (!permitted) {
  10022. this.targetElement = null;
  10023. }
  10024. // If clicks are permitted, return true for the action to go through.
  10025. return permitted;
  10026. };
  10027. /**
  10028. * Remove all FastClick's event listeners.
  10029. *
  10030. * @returns {void}
  10031. */
  10032. FastClick.prototype.destroy = function() {
  10033. var layer = this.layer;
  10034. if (deviceIsAndroid) {
  10035. layer.removeEventListener('mouseover', this.onMouse, true);
  10036. layer.removeEventListener('mousedown', this.onMouse, true);
  10037. layer.removeEventListener('mouseup', this.onMouse, true);
  10038. }
  10039. layer.removeEventListener('click', this.onClick, true);
  10040. layer.removeEventListener('touchstart', this.onTouchStart, false);
  10041. layer.removeEventListener('touchmove', this.onTouchMove, false);
  10042. layer.removeEventListener('touchend', this.onTouchEnd, false);
  10043. layer.removeEventListener('touchcancel', this.onTouchCancel,
  10044. false);
  10045. };
  10046. /**
  10047. * Check whether FastClick is needed.
  10048. *
  10049. * @param {Element} layer The layer to listen on
  10050. */
  10051. FastClick.notNeeded = function(layer) {
  10052. var metaViewport;
  10053. var chromeVersion;
  10054. var blackberryVersion;
  10055. // Devices that don't support touch don't need FastClick
  10056. if (typeof window.ontouchstart === 'undefined') {
  10057. return true;
  10058. }
  10059. // Chrome version - zero for other browsers
  10060. chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,
  10061. 0
  10062. ])[1];
  10063. if (chromeVersion) {
  10064. if (deviceIsAndroid) {
  10065. metaViewport = document.querySelector('meta[name=viewport]');
  10066. if (metaViewport) {
  10067. // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
  10068. if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
  10069. return true;
  10070. }
  10071. // Chrome 32 and above with width=device-width or less don't need FastClick
  10072. if (chromeVersion > 31 && document.documentElement.scrollWidth <=
  10073. window.outerWidth) {
  10074. return true;
  10075. }
  10076. }
  10077. // Chrome desktop doesn't need FastClick (issue #15)
  10078. } else {
  10079. return true;
  10080. }
  10081. }
  10082. if (deviceIsBlackBerry10) {
  10083. blackberryVersion = navigator.userAgent.match(
  10084. /Version\/([0-9]*)\.([0-9]*)/);
  10085. // BlackBerry 10.3+ does not require Fastclick library.
  10086. // https://github.com/ftlabs/fastclick/issues/251
  10087. if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
  10088. metaViewport = document.querySelector('meta[name=viewport]');
  10089. if (metaViewport) {
  10090. // user-scalable=no eliminates click delay.
  10091. if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
  10092. return true;
  10093. }
  10094. // width=device-width (or less than device-width) eliminates click delay.
  10095. if (document.documentElement.scrollWidth <= window.outerWidth) {
  10096. return true;
  10097. }
  10098. }
  10099. }
  10100. }
  10101. // IE10 with -ms-touch-action: none, which disables double-tap-to-zoom (issue #97)
  10102. if (layer.style.msTouchAction === 'none') {
  10103. return true;
  10104. }
  10105. return false;
  10106. };
  10107. /**
  10108. * Factory method for creating a FastClick object
  10109. *
  10110. * @param {Element} layer The layer to listen on
  10111. * @param {Object} options The options to override the defaults
  10112. */
  10113. FastClick.attach = function(layer, options) {
  10114. return new FastClick(layer, options);
  10115. };
  10116. $ && ($.AMUI ? $.AMUI.FastClick = FastClick : $.AMUI = {
  10117. FastClick: FastClick
  10118. });
  10119. module.exports = FastClick;
  10120. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  10121. "undefined" ? self : typeof window !== "undefined" ? window : {})
  10122. }, {}
  10123. ],
  10124. 49: [
  10125. function(require, module, exports) {
  10126. (function(global) {
  10127. 'use strict';
  10128. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  10129. "undefined" ? global.jQuery : null);
  10130. var UI = require('./core');
  10131. /**
  10132. * @via https://github.com/sindresorhus/screenfull.js
  10133. * @license MIT © Sindre Sorhus
  10134. * @version 2.0.0
  10135. */
  10136. var keyboardAllowed = typeof Element !== 'undefined' &&
  10137. 'ALLOW_KEYBOARD_INPUT' in Element;
  10138. var fn = (function() {
  10139. var val;
  10140. var valLength;
  10141. var fnMap = [
  10142. [
  10143. 'requestFullscreen',
  10144. 'exitFullscreen',
  10145. 'fullscreenElement',
  10146. 'fullscreenEnabled',
  10147. 'fullscreenchange',
  10148. 'fullscreenerror'
  10149. ],
  10150. // new WebKit
  10151. [
  10152. 'webkitRequestFullscreen',
  10153. 'webkitExitFullscreen',
  10154. 'webkitFullscreenElement',
  10155. 'webkitFullscreenEnabled',
  10156. 'webkitfullscreenchange',
  10157. 'webkitfullscreenerror'
  10158. ],
  10159. // old WebKit (Safari 5.1)
  10160. [
  10161. 'webkitRequestFullScreen',
  10162. 'webkitCancelFullScreen',
  10163. 'webkitCurrentFullScreenElement',
  10164. 'webkitCancelFullScreen',
  10165. 'webkitfullscreenchange',
  10166. 'webkitfullscreenerror'
  10167. ],
  10168. [
  10169. 'mozRequestFullScreen',
  10170. 'mozCancelFullScreen',
  10171. 'mozFullScreenElement',
  10172. 'mozFullScreenEnabled',
  10173. 'mozfullscreenchange',
  10174. 'mozfullscreenerror'
  10175. ],
  10176. [
  10177. 'msRequestFullscreen',
  10178. 'msExitFullscreen',
  10179. 'msFullscreenElement',
  10180. 'msFullscreenEnabled',
  10181. 'MSFullscreenChange',
  10182. 'MSFullscreenError'
  10183. ]
  10184. ];
  10185. var i = 0;
  10186. var l = fnMap.length;
  10187. var ret = {};
  10188. for (; i < l; i++) {
  10189. val = fnMap[i];
  10190. if (val && val[1] in document) {
  10191. for (i = 0, valLength = val.length; i < valLength; i++) {
  10192. ret[fnMap[0][i]] = val[i];
  10193. }
  10194. return ret;
  10195. }
  10196. }
  10197. return false;
  10198. })();
  10199. var screenfull = {
  10200. request: function(elem) {
  10201. var request = fn.requestFullscreen;
  10202. elem = elem || document.documentElement;
  10203. // Work around Safari 5.1 bug: reports support for
  10204. // keyboard in fullscreen even though it doesn't.
  10205. // Browser sniffing, since the alternative with
  10206. // setTimeout is even worse.
  10207. if (/5\.1[\.\d]* Safari/.test(navigator.userAgent)) {
  10208. elem[request]();
  10209. } else {
  10210. elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
  10211. }
  10212. },
  10213. exit: function() {
  10214. document[fn.exitFullscreen]();
  10215. },
  10216. toggle: function(elem) {
  10217. if (this.isFullscreen) {
  10218. this.exit();
  10219. } else {
  10220. this.request(elem);
  10221. }
  10222. },
  10223. raw: fn
  10224. };
  10225. if (!fn) {
  10226. module.exports = false;
  10227. return;
  10228. }
  10229. Object.defineProperties(screenfull, {
  10230. isFullscreen: {
  10231. get: function() {
  10232. return !!document[fn.fullscreenElement];
  10233. }
  10234. },
  10235. element: {
  10236. enumerable: true,
  10237. get: function() {
  10238. return document[fn.fullscreenElement];
  10239. }
  10240. },
  10241. enabled: {
  10242. enumerable: true,
  10243. get: function() {
  10244. // Coerce to boolean in case of old WebKit
  10245. return !!document[fn.fullscreenEnabled];
  10246. }
  10247. }
  10248. });
  10249. screenfull.VERSION = '2.0.0';
  10250. $.AMUI.fullscreen = screenfull;
  10251. module.exports = screenfull;
  10252. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  10253. "undefined" ? self : typeof window !== "undefined" ? window : {})
  10254. }, {
  10255. "./core": 4
  10256. }
  10257. ],
  10258. 50: [
  10259. function(require, module, exports) {
  10260. (function(global) {
  10261. /*! Hammer.JS - v2.0.4 - 2014-09-28
  10262. * http://hammerjs.github.io/
  10263. *
  10264. * Copyright (c) 2014 Jorik Tangelder;
  10265. * Licensed under the MIT license */
  10266. 'use strict';
  10267. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  10268. "undefined" ? global.jQuery : null);
  10269. var UI = require('./core');
  10270. var VENDOR_PREFIXES = ['', 'webkit', 'moz', 'MS', 'ms', 'o'];
  10271. var TEST_ELEMENT = document.createElement('div');
  10272. var TYPE_FUNCTION = 'function';
  10273. var round = Math.round;
  10274. var abs = Math.abs;
  10275. var now = Date.now;
  10276. /**
  10277. * set a timeout with a given scope
  10278. * @param {Function} fn
  10279. * @param {Number} timeout
  10280. * @param {Object} context
  10281. * @returns {number}
  10282. */
  10283. function setTimeoutContext(fn, timeout, context) {
  10284. return setTimeout(bindFn(fn, context), timeout);
  10285. }
  10286. /**
  10287. * if the argument is an array, we want to execute the fn on each entry
  10288. * if it aint an array we don't want to do a thing.
  10289. * this is used by all the methods that accept a single and array argument.
  10290. * @param {*|Array} arg
  10291. * @param {String} fn
  10292. * @param {Object} [context]
  10293. * @returns {Boolean}
  10294. */
  10295. function invokeArrayArg(arg, fn, context) {
  10296. if (Array.isArray(arg)) {
  10297. each(arg, context[fn], context);
  10298. return true;
  10299. }
  10300. return false;
  10301. }
  10302. /**
  10303. * walk objects and arrays
  10304. * @param {Object} obj
  10305. * @param {Function} iterator
  10306. * @param {Object} context
  10307. */
  10308. function each(obj, iterator, context) {
  10309. var i;
  10310. if (!obj) {
  10311. return;
  10312. }
  10313. if (obj.forEach) {
  10314. obj.forEach(iterator, context);
  10315. } else if (obj.length !== undefined) {
  10316. i = 0;
  10317. while (i < obj.length) {
  10318. iterator.call(context, obj[i], i, obj);
  10319. i++;
  10320. }
  10321. } else {
  10322. for (i in obj) {
  10323. obj.hasOwnProperty(i) && iterator.call(context, obj[i], i,
  10324. obj);
  10325. }
  10326. }
  10327. }
  10328. /**
  10329. * extend object.
  10330. * means that properties in dest will be overwritten by the ones in src.
  10331. * @param {Object} dest
  10332. * @param {Object} src
  10333. * @param {Boolean} [merge]
  10334. * @returns {Object} dest
  10335. */
  10336. function extend(dest, src, merge) {
  10337. var keys = Object.keys(src);
  10338. var i = 0;
  10339. while (i < keys.length) {
  10340. if (!merge || (merge && dest[keys[i]] === undefined)) {
  10341. dest[keys[i]] = src[keys[i]];
  10342. }
  10343. i++;
  10344. }
  10345. return dest;
  10346. }
  10347. /**
  10348. * merge the values from src in the dest.
  10349. * means that properties that exist in dest will not be overwritten by src
  10350. * @param {Object} dest
  10351. * @param {Object} src
  10352. * @returns {Object} dest
  10353. */
  10354. function merge(dest, src) {
  10355. return extend(dest, src, true);
  10356. }
  10357. /**
  10358. * simple class inheritance
  10359. * @param {Function} child
  10360. * @param {Function} base
  10361. * @param {Object} [properties]
  10362. */
  10363. function inherit(child, base, properties) {
  10364. var baseP = base.prototype,
  10365. childP;
  10366. childP = child.prototype = Object.create(baseP);
  10367. childP.constructor = child;
  10368. childP._super = baseP;
  10369. if (properties) {
  10370. extend(childP, properties);
  10371. }
  10372. }
  10373. /**
  10374. * simple function bind
  10375. * @param {Function} fn
  10376. * @param {Object} context
  10377. * @returns {Function}
  10378. */
  10379. function bindFn(fn, context) {
  10380. return function boundFn() {
  10381. return fn.apply(context, arguments);
  10382. };
  10383. }
  10384. /**
  10385. * let a boolean value also be a function that must return a boolean
  10386. * this first item in args will be used as the context
  10387. * @param {Boolean|Function} val
  10388. * @param {Array} [args]
  10389. * @returns {Boolean}
  10390. */
  10391. function boolOrFn(val, args) {
  10392. if (typeof val == TYPE_FUNCTION) {
  10393. return val.apply(args ? args[0] || undefined : undefined, args);
  10394. }
  10395. return val;
  10396. }
  10397. /**
  10398. * use the val2 when val1 is undefined
  10399. * @param {*} val1
  10400. * @param {*} val2
  10401. * @returns {*}
  10402. */
  10403. function ifUndefined(val1, val2) {
  10404. return (val1 === undefined) ? val2 : val1;
  10405. }
  10406. /**
  10407. * addEventListener with multiple events at once
  10408. * @param {EventTarget} target
  10409. * @param {String} types
  10410. * @param {Function} handler
  10411. */
  10412. function addEventListeners(target, types, handler) {
  10413. each(splitStr(types), function(type) {
  10414. target.addEventListener(type, handler, false);
  10415. });
  10416. }
  10417. /**
  10418. * removeEventListener with multiple events at once
  10419. * @param {EventTarget} target
  10420. * @param {String} types
  10421. * @param {Function} handler
  10422. */
  10423. function removeEventListeners(target, types, handler) {
  10424. each(splitStr(types), function(type) {
  10425. target.removeEventListener(type, handler, false);
  10426. });
  10427. }
  10428. /**
  10429. * find if a node is in the given parent
  10430. * @method hasParent
  10431. * @param {HTMLElement} node
  10432. * @param {HTMLElement} parent
  10433. * @return {Boolean} found
  10434. */
  10435. function hasParent(node, parent) {
  10436. while (node) {
  10437. if (node == parent) {
  10438. return true;
  10439. }
  10440. node = node.parentNode;
  10441. }
  10442. return false;
  10443. }
  10444. /**
  10445. * small indexOf wrapper
  10446. * @param {String} str
  10447. * @param {String} find
  10448. * @returns {Boolean} found
  10449. */
  10450. function inStr(str, find) {
  10451. return str.indexOf(find) > -1;
  10452. }
  10453. /**
  10454. * split string on whitespace
  10455. * @param {String} str
  10456. * @returns {Array} words
  10457. */
  10458. function splitStr(str) {
  10459. return str.trim().split(/\s+/g);
  10460. }
  10461. /**
  10462. * find if a array contains the object using indexOf or a simple polyFill
  10463. * @param {Array} src
  10464. * @param {String} find
  10465. * @param {String} [findByKey]
  10466. * @return {Boolean|Number} false when not found, or the index
  10467. */
  10468. function inArray(src, find, findByKey) {
  10469. if (src.indexOf && !findByKey) {
  10470. return src.indexOf(find);
  10471. } else {
  10472. var i = 0;
  10473. while (i < src.length) {
  10474. if ((findByKey && src[i][findByKey] == find) || (!findByKey &&
  10475. src[i] === find)) {
  10476. return i;
  10477. }
  10478. i++;
  10479. }
  10480. return -1;
  10481. }
  10482. }
  10483. /**
  10484. * convert array-like objects to real arrays
  10485. * @param {Object} obj
  10486. * @returns {Array}
  10487. */
  10488. function toArray(obj) {
  10489. return Array.prototype.slice.call(obj, 0);
  10490. }
  10491. /**
  10492. * unique array with objects based on a key (like 'id') or just by the array's value
  10493. * @param {Array} src [{id:1},{id:2},{id:1}]
  10494. * @param {String} [key]
  10495. * @param {Boolean} [sort=False]
  10496. * @returns {Array} [{id:1},{id:2}]
  10497. */
  10498. function uniqueArray(src, key, sort) {
  10499. var results = [];
  10500. var values = [];
  10501. var i = 0;
  10502. while (i < src.length) {
  10503. var val = key ? src[i][key] : src[i];
  10504. if (inArray(values, val) < 0) {
  10505. results.push(src[i]);
  10506. }
  10507. values[i] = val;
  10508. i++;
  10509. }
  10510. if (sort) {
  10511. if (!key) {
  10512. results = results.sort();
  10513. } else {
  10514. results = results.sort(function sortUniqueArray(a, b) {
  10515. return a[key] > b[key];
  10516. });
  10517. }
  10518. }
  10519. return results;
  10520. }
  10521. /**
  10522. * get the prefixed property
  10523. * @param {Object} obj
  10524. * @param {String} property
  10525. * @returns {String|Undefined} prefixed
  10526. */
  10527. function prefixed(obj, property) {
  10528. var prefix, prop;
  10529. var camelProp = property[0].toUpperCase() + property.slice(1);
  10530. var i = 0;
  10531. while (i < VENDOR_PREFIXES.length) {
  10532. prefix = VENDOR_PREFIXES[i];
  10533. prop = (prefix) ? prefix + camelProp : property;
  10534. if (prop in obj) {
  10535. return prop;
  10536. }
  10537. i++;
  10538. }
  10539. return undefined;
  10540. }
  10541. /**
  10542. * get a unique id
  10543. * @returns {number} uniqueId
  10544. */
  10545. var _uniqueId = 1;
  10546. function uniqueId() {
  10547. return _uniqueId++;
  10548. }
  10549. /**
  10550. * get the window object of an element
  10551. * @param {HTMLElement} element
  10552. * @returns {DocumentView|Window}
  10553. */
  10554. function getWindowForElement(element) {
  10555. var doc = element.ownerDocument;
  10556. return (doc.defaultView || doc.parentWindow);
  10557. }
  10558. var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
  10559. var SUPPORT_TOUCH = ('ontouchstart' in window);
  10560. var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !==
  10561. undefined;
  10562. var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(
  10563. navigator.userAgent);
  10564. var INPUT_TYPE_TOUCH = 'touch';
  10565. var INPUT_TYPE_PEN = 'pen';
  10566. var INPUT_TYPE_MOUSE = 'mouse';
  10567. var INPUT_TYPE_KINECT = 'kinect';
  10568. var COMPUTE_INTERVAL = 25;
  10569. var INPUT_START = 1;
  10570. var INPUT_MOVE = 2;
  10571. var INPUT_END = 4;
  10572. var INPUT_CANCEL = 8;
  10573. var DIRECTION_NONE = 1;
  10574. var DIRECTION_LEFT = 2;
  10575. var DIRECTION_RIGHT = 4;
  10576. var DIRECTION_UP = 8;
  10577. var DIRECTION_DOWN = 16;
  10578. var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
  10579. var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
  10580. var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
  10581. var PROPS_XY = ['x', 'y'];
  10582. var PROPS_CLIENT_XY = ['clientX', 'clientY'];
  10583. /**
  10584. * create new input type manager
  10585. * @param {Manager} manager
  10586. * @param {Function} callback
  10587. * @returns {Input}
  10588. * @constructor
  10589. */
  10590. function Input(manager, callback) {
  10591. var self = this;
  10592. this.manager = manager;
  10593. this.callback = callback;
  10594. this.element = manager.element;
  10595. this.target = manager.options.inputTarget;
  10596. // smaller wrapper around the handler, for the scope and the enabled state of the manager,
  10597. // so when disabled the input events are completely bypassed.
  10598. this.domHandler = function(ev) {
  10599. if (boolOrFn(manager.options.enable, [manager])) {
  10600. self.handler(ev);
  10601. }
  10602. };
  10603. this.init();
  10604. }
  10605. Input.prototype = {
  10606. /**
  10607. * should handle the inputEvent data and trigger the callback
  10608. * @virtual
  10609. */
  10610. handler: function() {},
  10611. /**
  10612. * bind the events
  10613. */
  10614. init: function() {
  10615. this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
  10616. this.evTarget && addEventListeners(this.target, this.evTarget,
  10617. this.domHandler);
  10618. this.evWin && addEventListeners(getWindowForElement(this.element),
  10619. this.evWin, this.domHandler);
  10620. },
  10621. /**
  10622. * unbind the events
  10623. */
  10624. destroy: function() {
  10625. this.evEl && removeEventListeners(this.element, this.evEl, this
  10626. .domHandler);
  10627. this.evTarget && removeEventListeners(this.target, this.evTarget,
  10628. this.domHandler);
  10629. this.evWin && removeEventListeners(getWindowForElement(this.element),
  10630. this.evWin, this.domHandler);
  10631. }
  10632. };
  10633. /**
  10634. * create new input type manager
  10635. * called by the Manager constructor
  10636. * @param {Hammer} manager
  10637. * @returns {Input}
  10638. */
  10639. function createInputInstance(manager) {
  10640. var Type;
  10641. var inputClass = manager.options.inputClass;
  10642. if (inputClass) {
  10643. Type = inputClass;
  10644. } else if (SUPPORT_POINTER_EVENTS) {
  10645. Type = PointerEventInput;
  10646. } else if (SUPPORT_ONLY_TOUCH) {
  10647. Type = TouchInput;
  10648. } else if (!SUPPORT_TOUCH) {
  10649. Type = MouseInput;
  10650. } else {
  10651. Type = TouchMouseInput;
  10652. }
  10653. return new(Type)(manager, inputHandler);
  10654. }
  10655. /**
  10656. * handle input events
  10657. * @param {Manager} manager
  10658. * @param {String} eventType
  10659. * @param {Object} input
  10660. */
  10661. function inputHandler(manager, eventType, input) {
  10662. var pointersLen = input.pointers.length;
  10663. var changedPointersLen = input.changedPointers.length;
  10664. var isFirst = (eventType & INPUT_START && (pointersLen -
  10665. changedPointersLen === 0));
  10666. var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (
  10667. pointersLen - changedPointersLen === 0));
  10668. input.isFirst = !!isFirst;
  10669. input.isFinal = !!isFinal;
  10670. if (isFirst) {
  10671. manager.session = {};
  10672. }
  10673. // source event is the normalized value of the domEvents
  10674. // like 'touchstart, mouseup, pointerdown'
  10675. input.eventType = eventType;
  10676. // compute scale, rotation etc
  10677. computeInputData(manager, input);
  10678. // emit secret event
  10679. manager.emit('hammer.input', input);
  10680. manager.recognize(input);
  10681. manager.session.prevInput = input;
  10682. }
  10683. /**
  10684. * extend the data with some usable properties like scale, rotate, velocity etc
  10685. * @param {Object} manager
  10686. * @param {Object} input
  10687. */
  10688. function computeInputData(manager, input) {
  10689. var session = manager.session;
  10690. var pointers = input.pointers;
  10691. var pointersLength = pointers.length;
  10692. // store the first input to calculate the distance and direction
  10693. if (!session.firstInput) {
  10694. session.firstInput = simpleCloneInputData(input);
  10695. }
  10696. // to compute scale and rotation we need to store the multiple touches
  10697. if (pointersLength > 1 && !session.firstMultiple) {
  10698. session.firstMultiple = simpleCloneInputData(input);
  10699. } else if (pointersLength === 1) {
  10700. session.firstMultiple = false;
  10701. }
  10702. var firstInput = session.firstInput;
  10703. var firstMultiple = session.firstMultiple;
  10704. var offsetCenter = firstMultiple ? firstMultiple.center :
  10705. firstInput.center;
  10706. var center = input.center = getCenter(pointers);
  10707. input.timeStamp = now();
  10708. input.deltaTime = input.timeStamp - firstInput.timeStamp;
  10709. input.angle = getAngle(offsetCenter, center);
  10710. input.distance = getDistance(offsetCenter, center);
  10711. computeDeltaXY(session, input);
  10712. input.offsetDirection = getDirection(input.deltaX, input.deltaY);
  10713. input.scale = firstMultiple ? getScale(firstMultiple.pointers,
  10714. pointers) : 1;
  10715. input.rotation = firstMultiple ? getRotation(firstMultiple.pointers,
  10716. pointers) : 0;
  10717. computeIntervalInputData(session, input);
  10718. // find the correct target
  10719. var target = manager.element;
  10720. if (hasParent(input.srcEvent.target, target)) {
  10721. target = input.srcEvent.target;
  10722. }
  10723. input.target = target;
  10724. }
  10725. function computeDeltaXY(session, input) {
  10726. var center = input.center;
  10727. var offset = session.offsetDelta || {};
  10728. var prevDelta = session.prevDelta || {};
  10729. var prevInput = session.prevInput || {};
  10730. if (input.eventType === INPUT_START || prevInput.eventType ===
  10731. INPUT_END) {
  10732. prevDelta = session.prevDelta = {
  10733. x: prevInput.deltaX || 0,
  10734. y: prevInput.deltaY || 0
  10735. };
  10736. offset = session.offsetDelta = {
  10737. x: center.x,
  10738. y: center.y
  10739. };
  10740. }
  10741. input.deltaX = prevDelta.x + (center.x - offset.x);
  10742. input.deltaY = prevDelta.y + (center.y - offset.y);
  10743. }
  10744. /**
  10745. * velocity is calculated every x ms
  10746. * @param {Object} session
  10747. * @param {Object} input
  10748. */
  10749. function computeIntervalInputData(session, input) {
  10750. var last = session.lastInterval || input,
  10751. deltaTime = input.timeStamp - last.timeStamp,
  10752. velocity, velocityX, velocityY, direction;
  10753. if (input.eventType != INPUT_CANCEL && (deltaTime >
  10754. COMPUTE_INTERVAL || last.velocity === undefined)) {
  10755. var deltaX = last.deltaX - input.deltaX;
  10756. var deltaY = last.deltaY - input.deltaY;
  10757. var v = getVelocity(deltaTime, deltaX, deltaY);
  10758. velocityX = v.x;
  10759. velocityY = v.y;
  10760. velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
  10761. direction = getDirection(deltaX, deltaY);
  10762. session.lastInterval = input;
  10763. } else {
  10764. // use latest velocity info if it doesn't overtake a minimum period
  10765. velocity = last.velocity;
  10766. velocityX = last.velocityX;
  10767. velocityY = last.velocityY;
  10768. direction = last.direction;
  10769. }
  10770. input.velocity = velocity;
  10771. input.velocityX = velocityX;
  10772. input.velocityY = velocityY;
  10773. input.direction = direction;
  10774. }
  10775. /**
  10776. * create a simple clone from the input used for storage of firstInput and firstMultiple
  10777. * @param {Object} input
  10778. * @returns {Object} clonedInputData
  10779. */
  10780. function simpleCloneInputData(input) {
  10781. // make a simple copy of the pointers because we will get a reference if we don't
  10782. // we only need clientXY for the calculations
  10783. var pointers = [];
  10784. var i = 0;
  10785. while (i < input.pointers.length) {
  10786. pointers[i] = {
  10787. clientX: round(input.pointers[i].clientX),
  10788. clientY: round(input.pointers[i].clientY)
  10789. };
  10790. i++;
  10791. }
  10792. return {
  10793. timeStamp: now(),
  10794. pointers: pointers,
  10795. center: getCenter(pointers),
  10796. deltaX: input.deltaX,
  10797. deltaY: input.deltaY
  10798. };
  10799. }
  10800. /**
  10801. * get the center of all the pointers
  10802. * @param {Array} pointers
  10803. * @return {Object} center contains `x` and `y` properties
  10804. */
  10805. function getCenter(pointers) {
  10806. var pointersLength = pointers.length;
  10807. // no need to loop when only one touch
  10808. if (pointersLength === 1) {
  10809. return {
  10810. x: round(pointers[0].clientX),
  10811. y: round(pointers[0].clientY)
  10812. };
  10813. }
  10814. var x = 0,
  10815. y = 0,
  10816. i = 0;
  10817. while (i < pointersLength) {
  10818. x += pointers[i].clientX;
  10819. y += pointers[i].clientY;
  10820. i++;
  10821. }
  10822. return {
  10823. x: round(x / pointersLength),
  10824. y: round(y / pointersLength)
  10825. };
  10826. }
  10827. /**
  10828. * calculate the velocity between two points. unit is in px per ms.
  10829. * @param {Number} deltaTime
  10830. * @param {Number} x
  10831. * @param {Number} y
  10832. * @return {Object} velocity `x` and `y`
  10833. */
  10834. function getVelocity(deltaTime, x, y) {
  10835. return {
  10836. x: x / deltaTime || 0,
  10837. y: y / deltaTime || 0
  10838. };
  10839. }
  10840. /**
  10841. * get the direction between two points
  10842. * @param {Number} x
  10843. * @param {Number} y
  10844. * @return {Number} direction
  10845. */
  10846. function getDirection(x, y) {
  10847. if (x === y) {
  10848. return DIRECTION_NONE;
  10849. }
  10850. if (abs(x) >= abs(y)) {
  10851. return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
  10852. }
  10853. return y > 0 ? DIRECTION_UP : DIRECTION_DOWN;
  10854. }
  10855. /**
  10856. * calculate the absolute distance between two points
  10857. * @param {Object} p1 {x, y}
  10858. * @param {Object} p2 {x, y}
  10859. * @param {Array} [props] containing x and y keys
  10860. * @return {Number} distance
  10861. */
  10862. function getDistance(p1, p2, props) {
  10863. if (!props) {
  10864. props = PROPS_XY;
  10865. }
  10866. var x = p2[props[0]] - p1[props[0]],
  10867. y = p2[props[1]] - p1[props[1]];
  10868. return Math.sqrt((x * x) + (y * y));
  10869. }
  10870. /**
  10871. * calculate the angle between two coordinates
  10872. * @param {Object} p1
  10873. * @param {Object} p2
  10874. * @param {Array} [props] containing x and y keys
  10875. * @return {Number} angle
  10876. */
  10877. function getAngle(p1, p2, props) {
  10878. if (!props) {
  10879. props = PROPS_XY;
  10880. }
  10881. var x = p2[props[0]] - p1[props[0]],
  10882. y = p2[props[1]] - p1[props[1]];
  10883. return Math.atan2(y, x) * 180 / Math.PI;
  10884. }
  10885. /**
  10886. * calculate the rotation degrees between two pointersets
  10887. * @param {Array} start array of pointers
  10888. * @param {Array} end array of pointers
  10889. * @return {Number} rotation
  10890. */
  10891. function getRotation(start, end) {
  10892. return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[
  10893. 1], start[0], PROPS_CLIENT_XY);
  10894. }
  10895. /**
  10896. * calculate the scale factor between two pointersets
  10897. * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
  10898. * @param {Array} start array of pointers
  10899. * @param {Array} end array of pointers
  10900. * @return {Number} scale
  10901. */
  10902. function getScale(start, end) {
  10903. return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(
  10904. start[0], start[1], PROPS_CLIENT_XY);
  10905. }
  10906. var MOUSE_INPUT_MAP = {
  10907. mousedown: INPUT_START,
  10908. mousemove: INPUT_MOVE,
  10909. mouseup: INPUT_END
  10910. };
  10911. var MOUSE_ELEMENT_EVENTS = 'mousedown';
  10912. var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
  10913. /**
  10914. * Mouse events input
  10915. * @constructor
  10916. * @extends Input
  10917. */
  10918. function MouseInput() {
  10919. this.evEl = MOUSE_ELEMENT_EVENTS;
  10920. this.evWin = MOUSE_WINDOW_EVENTS;
  10921. this.allow = true; // used by Input.TouchMouse to disable mouse events
  10922. this.pressed = false; // mousedown state
  10923. Input.apply(this, arguments);
  10924. }
  10925. inherit(MouseInput, Input, {
  10926. /**
  10927. * handle mouse events
  10928. * @param {Object} ev
  10929. */
  10930. handler: function MEhandler(ev) {
  10931. var eventType = MOUSE_INPUT_MAP[ev.type];
  10932. // on start we want to have the left mouse button down
  10933. if (eventType & INPUT_START && ev.button === 0) {
  10934. this.pressed = true;
  10935. }
  10936. if (eventType & INPUT_MOVE && ev.which !== 1) {
  10937. eventType = INPUT_END;
  10938. }
  10939. // mouse must be down, and mouse events are allowed (see the TouchMouse input)
  10940. if (!this.pressed || !this.allow) {
  10941. return;
  10942. }
  10943. if (eventType & INPUT_END) {
  10944. this.pressed = false;
  10945. }
  10946. this.callback(this.manager, eventType, {
  10947. pointers: [ev],
  10948. changedPointers: [ev],
  10949. pointerType: INPUT_TYPE_MOUSE,
  10950. srcEvent: ev
  10951. });
  10952. }
  10953. });
  10954. var POINTER_INPUT_MAP = {
  10955. pointerdown: INPUT_START,
  10956. pointermove: INPUT_MOVE,
  10957. pointerup: INPUT_END,
  10958. pointercancel: INPUT_CANCEL,
  10959. pointerout: INPUT_CANCEL
  10960. };
  10961. // in IE10 the pointer types is defined as an enum
  10962. var IE10_POINTER_TYPE_ENUM = {
  10963. 2: INPUT_TYPE_TOUCH,
  10964. 3: INPUT_TYPE_PEN,
  10965. 4: INPUT_TYPE_MOUSE,
  10966. 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
  10967. };
  10968. var POINTER_ELEMENT_EVENTS = 'pointerdown';
  10969. var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
  10970. // IE10 has prefixed support, and case-sensitive
  10971. if (window.MSPointerEvent) {
  10972. POINTER_ELEMENT_EVENTS = 'MSPointerDown';
  10973. POINTER_WINDOW_EVENTS =
  10974. 'MSPointerMove MSPointerUp MSPointerCancel';
  10975. }
  10976. /**
  10977. * Pointer events input
  10978. * @constructor
  10979. * @extends Input
  10980. */
  10981. function PointerEventInput() {
  10982. this.evEl = POINTER_ELEMENT_EVENTS;
  10983. this.evWin = POINTER_WINDOW_EVENTS;
  10984. Input.apply(this, arguments);
  10985. this.store = (this.manager.session.pointerEvents = []);
  10986. }
  10987. inherit(PointerEventInput, Input, {
  10988. /**
  10989. * handle mouse events
  10990. * @param {Object} ev
  10991. */
  10992. handler: function PEhandler(ev) {
  10993. var store = this.store;
  10994. var removePointer = false;
  10995. var eventTypeNormalized = ev.type.toLowerCase().replace('ms',
  10996. '');
  10997. var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
  10998. var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] ||
  10999. ev.pointerType;
  11000. var isTouch = (pointerType == INPUT_TYPE_TOUCH);
  11001. // get index of the event in the store
  11002. var storeIndex = inArray(store, ev.pointerId, 'pointerId');
  11003. // start and mouse must be down
  11004. if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
  11005. if (storeIndex < 0) {
  11006. store.push(ev);
  11007. storeIndex = store.length - 1;
  11008. }
  11009. } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
  11010. removePointer = true;
  11011. }
  11012. // it not found, so the pointer hasn't been down (so it's probably a hover)
  11013. if (storeIndex < 0) {
  11014. return;
  11015. }
  11016. // update the event in the store
  11017. store[storeIndex] = ev;
  11018. this.callback(this.manager, eventType, {
  11019. pointers: store,
  11020. changedPointers: [ev],
  11021. pointerType: pointerType,
  11022. srcEvent: ev
  11023. });
  11024. if (removePointer) {
  11025. // remove from the store
  11026. store.splice(storeIndex, 1);
  11027. }
  11028. }
  11029. });
  11030. var SINGLE_TOUCH_INPUT_MAP = {
  11031. touchstart: INPUT_START,
  11032. touchmove: INPUT_MOVE,
  11033. touchend: INPUT_END,
  11034. touchcancel: INPUT_CANCEL
  11035. };
  11036. var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
  11037. var SINGLE_TOUCH_WINDOW_EVENTS =
  11038. 'touchstart touchmove touchend touchcancel';
  11039. /**
  11040. * Touch events input
  11041. * @constructor
  11042. * @extends Input
  11043. */
  11044. function SingleTouchInput() {
  11045. this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
  11046. this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
  11047. this.started = false;
  11048. Input.apply(this, arguments);
  11049. }
  11050. inherit(SingleTouchInput, Input, {
  11051. handler: function TEhandler(ev) {
  11052. var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
  11053. // should we handle the touch events?
  11054. if (type === INPUT_START) {
  11055. this.started = true;
  11056. }
  11057. if (!this.started) {
  11058. return;
  11059. }
  11060. var touches = normalizeSingleTouches.call(this, ev, type);
  11061. // when done, reset the started state
  11062. if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length -
  11063. touches[1].length === 0) {
  11064. this.started = false;
  11065. }
  11066. this.callback(this.manager, type, {
  11067. pointers: touches[0],
  11068. changedPointers: touches[1],
  11069. pointerType: INPUT_TYPE_TOUCH,
  11070. srcEvent: ev
  11071. });
  11072. }
  11073. });
  11074. /**
  11075. * @this {TouchInput}
  11076. * @param {Object} ev
  11077. * @param {Number} type flag
  11078. * @returns {undefined|Array} [all, changed]
  11079. */
  11080. function normalizeSingleTouches(ev, type) {
  11081. var all = toArray(ev.touches);
  11082. var changed = toArray(ev.changedTouches);
  11083. if (type & (INPUT_END | INPUT_CANCEL)) {
  11084. all = uniqueArray(all.concat(changed), 'identifier', true);
  11085. }
  11086. return [all, changed];
  11087. }
  11088. var TOUCH_INPUT_MAP = {
  11089. touchstart: INPUT_START,
  11090. touchmove: INPUT_MOVE,
  11091. touchend: INPUT_END,
  11092. touchcancel: INPUT_CANCEL
  11093. };
  11094. var TOUCH_TARGET_EVENTS =
  11095. 'touchstart touchmove touchend touchcancel';
  11096. /**
  11097. * Multi-user touch events input
  11098. * @constructor
  11099. * @extends Input
  11100. */
  11101. function TouchInput() {
  11102. this.evTarget = TOUCH_TARGET_EVENTS;
  11103. this.targetIds = {};
  11104. Input.apply(this, arguments);
  11105. }
  11106. inherit(TouchInput, Input, {
  11107. handler: function MTEhandler(ev) {
  11108. var type = TOUCH_INPUT_MAP[ev.type];
  11109. var touches = getTouches.call(this, ev, type);
  11110. if (!touches) {
  11111. return;
  11112. }
  11113. this.callback(this.manager, type, {
  11114. pointers: touches[0],
  11115. changedPointers: touches[1],
  11116. pointerType: INPUT_TYPE_TOUCH,
  11117. srcEvent: ev
  11118. });
  11119. }
  11120. });
  11121. /**
  11122. * @this {TouchInput}
  11123. * @param {Object} ev
  11124. * @param {Number} type flag
  11125. * @returns {undefined|Array} [all, changed]
  11126. */
  11127. function getTouches(ev, type) {
  11128. var allTouches = toArray(ev.touches);
  11129. var targetIds = this.targetIds;
  11130. // when there is only one touch, the process can be simplified
  11131. if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
  11132. targetIds[allTouches[0].identifier] = true;
  11133. return [allTouches, allTouches];
  11134. }
  11135. var i,
  11136. targetTouches,
  11137. changedTouches = toArray(ev.changedTouches),
  11138. changedTargetTouches = [],
  11139. target = this.target;
  11140. // get target touches from touches
  11141. targetTouches = allTouches.filter(function(touch) {
  11142. return hasParent(touch.target, target);
  11143. });
  11144. // collect touches
  11145. if (type === INPUT_START) {
  11146. i = 0;
  11147. while (i < targetTouches.length) {
  11148. targetIds[targetTouches[i].identifier] = true;
  11149. i++;
  11150. }
  11151. }
  11152. // filter changed touches to only contain touches that exist in the collected target ids
  11153. i = 0;
  11154. while (i < changedTouches.length) {
  11155. if (targetIds[changedTouches[i].identifier]) {
  11156. changedTargetTouches.push(changedTouches[i]);
  11157. }
  11158. // cleanup removed touches
  11159. if (type & (INPUT_END | INPUT_CANCEL)) {
  11160. delete targetIds[changedTouches[i].identifier];
  11161. }
  11162. i++;
  11163. }
  11164. if (!changedTargetTouches.length) {
  11165. return;
  11166. }
  11167. return [
  11168. // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
  11169. uniqueArray(targetTouches.concat(changedTargetTouches),
  11170. 'identifier', true),
  11171. changedTargetTouches
  11172. ];
  11173. }
  11174. /**
  11175. * Combined touch and mouse input
  11176. *
  11177. * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
  11178. * This because touch devices also emit mouse events while doing a touch.
  11179. *
  11180. * @constructor
  11181. * @extends Input
  11182. */
  11183. function TouchMouseInput() {
  11184. Input.apply(this, arguments);
  11185. var handler = bindFn(this.handler, this);
  11186. this.touch = new TouchInput(this.manager, handler);
  11187. this.mouse = new MouseInput(this.manager, handler);
  11188. }
  11189. inherit(TouchMouseInput, Input, {
  11190. /**
  11191. * handle mouse and touch events
  11192. * @param {Hammer} manager
  11193. * @param {String} inputEvent
  11194. * @param {Object} inputData
  11195. */
  11196. handler: function TMEhandler(manager, inputEvent, inputData) {
  11197. var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
  11198. isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
  11199. // when we're in a touch event, so block all upcoming mouse events
  11200. // most mobile browser also emit mouseevents, right after touchstart
  11201. if (isTouch) {
  11202. this.mouse.allow = false;
  11203. } else if (isMouse && !this.mouse.allow) {
  11204. return;
  11205. }
  11206. // reset the allowMouse when we're done
  11207. if (inputEvent & (INPUT_END | INPUT_CANCEL)) {
  11208. this.mouse.allow = true;
  11209. }
  11210. this.callback(manager, inputEvent, inputData);
  11211. },
  11212. /**
  11213. * remove the event listeners
  11214. */
  11215. destroy: function destroy() {
  11216. this.touch.destroy();
  11217. this.mouse.destroy();
  11218. }
  11219. });
  11220. var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style,
  11221. 'touchAction');
  11222. var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
  11223. // magical touchAction value
  11224. var TOUCH_ACTION_COMPUTE = 'compute';
  11225. var TOUCH_ACTION_AUTO = 'auto';
  11226. var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
  11227. var TOUCH_ACTION_NONE = 'none';
  11228. var TOUCH_ACTION_PAN_X = 'pan-x';
  11229. var TOUCH_ACTION_PAN_Y = 'pan-y';
  11230. /**
  11231. * Touch Action
  11232. * sets the touchAction property or uses the js alternative
  11233. * @param {Manager} manager
  11234. * @param {String} value
  11235. * @constructor
  11236. */
  11237. function TouchAction(manager, value) {
  11238. this.manager = manager;
  11239. this.set(value);
  11240. }
  11241. TouchAction.prototype = {
  11242. /**
  11243. * set the touchAction value on the element or enable the polyfill
  11244. * @param {String} value
  11245. */
  11246. set: function(value) {
  11247. // find out the touch-action by the event handlers
  11248. if (value == TOUCH_ACTION_COMPUTE) {
  11249. value = this.compute();
  11250. }
  11251. if (NATIVE_TOUCH_ACTION) {
  11252. this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
  11253. }
  11254. this.actions = value.toLowerCase().trim();
  11255. },
  11256. /**
  11257. * just re-set the touchAction value
  11258. */
  11259. update: function() {
  11260. this.set(this.manager.options.touchAction);
  11261. },
  11262. /**
  11263. * compute the value for the touchAction property based on the recognizer's settings
  11264. * @returns {String} value
  11265. */
  11266. compute: function() {
  11267. var actions = [];
  11268. each(this.manager.recognizers, function(recognizer) {
  11269. if (boolOrFn(recognizer.options.enable, [recognizer])) {
  11270. actions = actions.concat(recognizer.getTouchAction());
  11271. }
  11272. });
  11273. return cleanTouchActions(actions.join(' '));
  11274. },
  11275. /**
  11276. * this method is called on each input cycle and provides the preventing of the browser behavior
  11277. * @param {Object} input
  11278. */
  11279. preventDefaults: function(input) {
  11280. // not needed with native support for the touchAction property
  11281. if (NATIVE_TOUCH_ACTION) {
  11282. return;
  11283. }
  11284. var srcEvent = input.srcEvent;
  11285. var direction = input.offsetDirection;
  11286. // if the touch action did prevented once this session
  11287. if (this.manager.session.prevented) {
  11288. srcEvent.preventDefault();
  11289. return;
  11290. }
  11291. var actions = this.actions;
  11292. var hasNone = inStr(actions, TOUCH_ACTION_NONE);
  11293. var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
  11294. var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
  11295. if (hasNone ||
  11296. (hasPanY && direction & DIRECTION_HORIZONTAL) ||
  11297. (hasPanX && direction & DIRECTION_VERTICAL)) {
  11298. return this.preventSrc(srcEvent);
  11299. }
  11300. },
  11301. /**
  11302. * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
  11303. * @param {Object} srcEvent
  11304. */
  11305. preventSrc: function(srcEvent) {
  11306. this.manager.session.prevented = true;
  11307. srcEvent.preventDefault();
  11308. }
  11309. };
  11310. /**
  11311. * when the touchActions are collected they are not a valid value, so we need to clean things up. *
  11312. * @param {String} actions
  11313. * @returns {*}
  11314. */
  11315. function cleanTouchActions(actions) {
  11316. // none
  11317. if (inStr(actions, TOUCH_ACTION_NONE)) {
  11318. return TOUCH_ACTION_NONE;
  11319. }
  11320. var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
  11321. var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
  11322. // pan-x and pan-y can be combined
  11323. if (hasPanX && hasPanY) {
  11324. return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y;
  11325. }
  11326. // pan-x OR pan-y
  11327. if (hasPanX || hasPanY) {
  11328. return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
  11329. }
  11330. // manipulation
  11331. if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
  11332. return TOUCH_ACTION_MANIPULATION;
  11333. }
  11334. return TOUCH_ACTION_AUTO;
  11335. }
  11336. /**
  11337. * Recognizer flow explained; *
  11338. * All recognizers have the initial state of POSSIBLE when a input session starts.
  11339. * The definition of a input session is from the first input until the last input, with all it's movement in it. *
  11340. * Example session for mouse-input: mousedown -> mousemove -> mouseup
  11341. *
  11342. * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
  11343. * which determines with state it should be.
  11344. *
  11345. * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
  11346. * POSSIBLE to give it another change on the next cycle.
  11347. *
  11348. * Possible
  11349. * |
  11350. * +-----+---------------+
  11351. * | |
  11352. * +-----+-----+ |
  11353. * | | |
  11354. * Failed Cancelled |
  11355. * +-------+------+
  11356. * | |
  11357. * Recognized Began
  11358. * |
  11359. * Changed
  11360. * |
  11361. * Ended/Recognized
  11362. */
  11363. var STATE_POSSIBLE = 1;
  11364. var STATE_BEGAN = 2;
  11365. var STATE_CHANGED = 4;
  11366. var STATE_ENDED = 8;
  11367. var STATE_RECOGNIZED = STATE_ENDED;
  11368. var STATE_CANCELLED = 16;
  11369. var STATE_FAILED = 32;
  11370. /**
  11371. * Recognizer
  11372. * Every recognizer needs to extend from this class.
  11373. * @constructor
  11374. * @param {Object} options
  11375. */
  11376. function Recognizer(options) {
  11377. this.id = uniqueId();
  11378. this.manager = null;
  11379. this.options = merge(options || {}, this.defaults);
  11380. // default is enable true
  11381. this.options.enable = ifUndefined(this.options.enable, true);
  11382. this.state = STATE_POSSIBLE;
  11383. this.simultaneous = {};
  11384. this.requireFail = [];
  11385. }
  11386. Recognizer.prototype = {
  11387. /**
  11388. * @virtual
  11389. * @type {Object}
  11390. */
  11391. defaults: {},
  11392. /**
  11393. * set options
  11394. * @param {Object} options
  11395. * @return {Recognizer}
  11396. */
  11397. set: function(options) {
  11398. extend(this.options, options);
  11399. // also update the touchAction, in case something changed about the directions/enabled state
  11400. this.manager && this.manager.touchAction.update();
  11401. return this;
  11402. },
  11403. /**
  11404. * recognize simultaneous with an other recognizer.
  11405. * @param {Recognizer} otherRecognizer
  11406. * @returns {Recognizer} this
  11407. */
  11408. recognizeWith: function(otherRecognizer) {
  11409. if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
  11410. return this;
  11411. }
  11412. var simultaneous = this.simultaneous;
  11413. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer,
  11414. this);
  11415. if (!simultaneous[otherRecognizer.id]) {
  11416. simultaneous[otherRecognizer.id] = otherRecognizer;
  11417. otherRecognizer.recognizeWith(this);
  11418. }
  11419. return this;
  11420. },
  11421. /**
  11422. * drop the simultaneous link. it doesnt remove the link on the other recognizer.
  11423. * @param {Recognizer} otherRecognizer
  11424. * @returns {Recognizer} this
  11425. */
  11426. dropRecognizeWith: function(otherRecognizer) {
  11427. if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
  11428. return this;
  11429. }
  11430. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer,
  11431. this);
  11432. delete this.simultaneous[otherRecognizer.id];
  11433. return this;
  11434. },
  11435. /**
  11436. * recognizer can only run when an other is failing
  11437. * @param {Recognizer} otherRecognizer
  11438. * @returns {Recognizer} this
  11439. */
  11440. requireFailure: function(otherRecognizer) {
  11441. if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
  11442. return this;
  11443. }
  11444. var requireFail = this.requireFail;
  11445. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer,
  11446. this);
  11447. if (inArray(requireFail, otherRecognizer) === -1) {
  11448. requireFail.push(otherRecognizer);
  11449. otherRecognizer.requireFailure(this);
  11450. }
  11451. return this;
  11452. },
  11453. /**
  11454. * drop the requireFailure link. it does not remove the link on the other recognizer.
  11455. * @param {Recognizer} otherRecognizer
  11456. * @returns {Recognizer} this
  11457. */
  11458. dropRequireFailure: function(otherRecognizer) {
  11459. if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
  11460. return this;
  11461. }
  11462. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer,
  11463. this);
  11464. var index = inArray(this.requireFail, otherRecognizer);
  11465. if (index > -1) {
  11466. this.requireFail.splice(index, 1);
  11467. }
  11468. return this;
  11469. },
  11470. /**
  11471. * has require failures boolean
  11472. * @returns {boolean}
  11473. */
  11474. hasRequireFailures: function() {
  11475. return this.requireFail.length > 0;
  11476. },
  11477. /**
  11478. * if the recognizer can recognize simultaneous with an other recognizer
  11479. * @param {Recognizer} otherRecognizer
  11480. * @returns {Boolean}
  11481. */
  11482. canRecognizeWith: function(otherRecognizer) {
  11483. return !!this.simultaneous[otherRecognizer.id];
  11484. },
  11485. /**
  11486. * You should use `tryEmit` instead of `emit` directly to check
  11487. * that all the needed recognizers has failed before emitting.
  11488. * @param {Object} input
  11489. */
  11490. emit: function(input) {
  11491. var self = this;
  11492. var state = this.state;
  11493. function emit(withState) {
  11494. self.manager.emit(self.options.event + (withState ? stateStr(
  11495. state) : ''), input);
  11496. }
  11497. // 'panstart' and 'panmove'
  11498. if (state < STATE_ENDED) {
  11499. emit(true);
  11500. }
  11501. emit(); // simple 'eventName' events
  11502. // panend and pancancel
  11503. if (state >= STATE_ENDED) {
  11504. emit(true);
  11505. }
  11506. },
  11507. /**
  11508. * Check that all the require failure recognizers has failed,
  11509. * if true, it emits a gesture event,
  11510. * otherwise, setup the state to FAILED.
  11511. * @param {Object} input
  11512. */
  11513. tryEmit: function(input) {
  11514. if (this.canEmit()) {
  11515. return this.emit(input);
  11516. }
  11517. // it's failing anyway
  11518. this.state = STATE_FAILED;
  11519. },
  11520. /**
  11521. * can we emit?
  11522. * @returns {boolean}
  11523. */
  11524. canEmit: function() {
  11525. var i = 0;
  11526. while (i < this.requireFail.length) {
  11527. if (!(this.requireFail[i].state & (STATE_FAILED |
  11528. STATE_POSSIBLE))) {
  11529. return false;
  11530. }
  11531. i++;
  11532. }
  11533. return true;
  11534. },
  11535. /**
  11536. * update the recognizer
  11537. * @param {Object} inputData
  11538. */
  11539. recognize: function(inputData) {
  11540. // make a new copy of the inputData
  11541. // so we can change the inputData without messing up the other recognizers
  11542. var inputDataClone = extend({}, inputData);
  11543. // is is enabled and allow recognizing?
  11544. if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
  11545. this.reset();
  11546. this.state = STATE_FAILED;
  11547. return;
  11548. }
  11549. // reset when we've reached the end
  11550. if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED |
  11551. STATE_FAILED)) {
  11552. this.state = STATE_POSSIBLE;
  11553. }
  11554. this.state = this.process(inputDataClone);
  11555. // the recognizer has recognized a gesture
  11556. // so trigger an event
  11557. if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED |
  11558. STATE_CANCELLED)) {
  11559. this.tryEmit(inputDataClone);
  11560. }
  11561. },
  11562. /**
  11563. * return the state of the recognizer
  11564. * the actual recognizing happens in this method
  11565. * @virtual
  11566. * @param {Object} inputData
  11567. * @returns {Const} STATE
  11568. */
  11569. process: function(inputData) {}, // jshint ignore:line
  11570. /**
  11571. * return the preferred touch-action
  11572. * @virtual
  11573. * @returns {Array}
  11574. */
  11575. getTouchAction: function() {},
  11576. /**
  11577. * called when the gesture isn't allowed to recognize
  11578. * like when another is being recognized or it is disabled
  11579. * @virtual
  11580. */
  11581. reset: function() {}
  11582. };
  11583. /**
  11584. * get a usable string, used as event postfix
  11585. * @param {Const} state
  11586. * @returns {String} state
  11587. */
  11588. function stateStr(state) {
  11589. if (state & STATE_CANCELLED) {
  11590. return 'cancel';
  11591. } else if (state & STATE_ENDED) {
  11592. return 'end';
  11593. } else if (state & STATE_CHANGED) {
  11594. return 'move';
  11595. } else if (state & STATE_BEGAN) {
  11596. return 'start';
  11597. }
  11598. return '';
  11599. }
  11600. /**
  11601. * direction cons to string
  11602. * @param {Const} direction
  11603. * @returns {String}
  11604. */
  11605. function directionStr(direction) {
  11606. if (direction == DIRECTION_DOWN) {
  11607. return 'down';
  11608. } else if (direction == DIRECTION_UP) {
  11609. return 'up';
  11610. } else if (direction == DIRECTION_LEFT) {
  11611. return 'left';
  11612. } else if (direction == DIRECTION_RIGHT) {
  11613. return 'right';
  11614. }
  11615. return '';
  11616. }
  11617. /**
  11618. * get a recognizer by name if it is bound to a manager
  11619. * @param {Recognizer|String} otherRecognizer
  11620. * @param {Recognizer} recognizer
  11621. * @returns {Recognizer}
  11622. */
  11623. function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
  11624. var manager = recognizer.manager;
  11625. if (manager) {
  11626. return manager.get(otherRecognizer);
  11627. }
  11628. return otherRecognizer;
  11629. }
  11630. /**
  11631. * This recognizer is just used as a base for the simple attribute recognizers.
  11632. * @constructor
  11633. * @extends Recognizer
  11634. */
  11635. function AttrRecognizer() {
  11636. Recognizer.apply(this, arguments);
  11637. }
  11638. inherit(AttrRecognizer, Recognizer, {
  11639. /**
  11640. * @namespace
  11641. * @memberof AttrRecognizer
  11642. */
  11643. defaults: {
  11644. /**
  11645. * @type {Number}
  11646. * @default 1
  11647. */
  11648. pointers: 1
  11649. },
  11650. /**
  11651. * Used to check if it the recognizer receives valid input, like input.distance > 10.
  11652. * @memberof AttrRecognizer
  11653. * @param {Object} input
  11654. * @returns {Boolean} recognized
  11655. */
  11656. attrTest: function(input) {
  11657. var optionPointers = this.options.pointers;
  11658. return optionPointers === 0 || input.pointers.length ===
  11659. optionPointers;
  11660. },
  11661. /**
  11662. * Process the input and return the state for the recognizer
  11663. * @memberof AttrRecognizer
  11664. * @param {Object} input
  11665. * @returns {*} State
  11666. */
  11667. process: function(input) {
  11668. var state = this.state;
  11669. var eventType = input.eventType;
  11670. var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
  11671. var isValid = this.attrTest(input);
  11672. // on cancel input and we've recognized before, return STATE_CANCELLED
  11673. if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
  11674. return state | STATE_CANCELLED;
  11675. } else if (isRecognized || isValid) {
  11676. if (eventType & INPUT_END) {
  11677. return state | STATE_ENDED;
  11678. } else if (!(state & STATE_BEGAN)) {
  11679. return STATE_BEGAN;
  11680. }
  11681. return state | STATE_CHANGED;
  11682. }
  11683. return STATE_FAILED;
  11684. }
  11685. });
  11686. /**
  11687. * Pan
  11688. * Recognized when the pointer is down and moved in the allowed direction.
  11689. * @constructor
  11690. * @extends AttrRecognizer
  11691. */
  11692. function PanRecognizer() {
  11693. AttrRecognizer.apply(this, arguments);
  11694. this.pX = null;
  11695. this.pY = null;
  11696. }
  11697. inherit(PanRecognizer, AttrRecognizer, {
  11698. /**
  11699. * @namespace
  11700. * @memberof PanRecognizer
  11701. */
  11702. defaults: {
  11703. event: 'pan',
  11704. threshold: 10,
  11705. pointers: 1,
  11706. direction: DIRECTION_ALL
  11707. },
  11708. getTouchAction: function() {
  11709. var direction = this.options.direction;
  11710. var actions = [];
  11711. if (direction & DIRECTION_HORIZONTAL) {
  11712. actions.push(TOUCH_ACTION_PAN_Y);
  11713. }
  11714. if (direction & DIRECTION_VERTICAL) {
  11715. actions.push(TOUCH_ACTION_PAN_X);
  11716. }
  11717. return actions;
  11718. },
  11719. directionTest: function(input) {
  11720. var options = this.options;
  11721. var hasMoved = true;
  11722. var distance = input.distance;
  11723. var direction = input.direction;
  11724. var x = input.deltaX;
  11725. var y = input.deltaY;
  11726. // lock to axis?
  11727. if (!(direction & options.direction)) {
  11728. if (options.direction & DIRECTION_HORIZONTAL) {
  11729. direction = (x === 0) ? DIRECTION_NONE : (x < 0) ?
  11730. DIRECTION_LEFT : DIRECTION_RIGHT;
  11731. hasMoved = x != this.pX;
  11732. distance = Math.abs(input.deltaX);
  11733. } else {
  11734. direction = (y === 0) ? DIRECTION_NONE : (y < 0) ?
  11735. DIRECTION_UP : DIRECTION_DOWN;
  11736. hasMoved = y != this.pY;
  11737. distance = Math.abs(input.deltaY);
  11738. }
  11739. }
  11740. input.direction = direction;
  11741. return hasMoved && distance > options.threshold && direction &
  11742. options.direction;
  11743. },
  11744. attrTest: function(input) {
  11745. return AttrRecognizer.prototype.attrTest.call(this, input) &&
  11746. (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) &&
  11747. this.directionTest(input)));
  11748. },
  11749. emit: function(input) {
  11750. this.pX = input.deltaX;
  11751. this.pY = input.deltaY;
  11752. var direction = directionStr(input.direction);
  11753. if (direction) {
  11754. this.manager.emit(this.options.event + direction, input);
  11755. }
  11756. this._super.emit.call(this, input);
  11757. }
  11758. });
  11759. /**
  11760. * Pinch
  11761. * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
  11762. * @constructor
  11763. * @extends AttrRecognizer
  11764. */
  11765. function PinchRecognizer() {
  11766. AttrRecognizer.apply(this, arguments);
  11767. }
  11768. inherit(PinchRecognizer, AttrRecognizer, {
  11769. /**
  11770. * @namespace
  11771. * @memberof PinchRecognizer
  11772. */
  11773. defaults: {
  11774. event: 'pinch',
  11775. threshold: 0,
  11776. pointers: 2
  11777. },
  11778. getTouchAction: function() {
  11779. return [TOUCH_ACTION_NONE];
  11780. },
  11781. attrTest: function(input) {
  11782. return this._super.attrTest.call(this, input) &&
  11783. (Math.abs(input.scale - 1) > this.options.threshold || this
  11784. .state & STATE_BEGAN);
  11785. },
  11786. emit: function(input) {
  11787. this._super.emit.call(this, input);
  11788. if (input.scale !== 1) {
  11789. var inOut = input.scale < 1 ? 'in' : 'out';
  11790. this.manager.emit(this.options.event + inOut, input);
  11791. }
  11792. }
  11793. });
  11794. /**
  11795. * Press
  11796. * Recognized when the pointer is down for x ms without any movement.
  11797. * @constructor
  11798. * @extends Recognizer
  11799. */
  11800. function PressRecognizer() {
  11801. Recognizer.apply(this, arguments);
  11802. this._timer = null;
  11803. this._input = null;
  11804. }
  11805. inherit(PressRecognizer, Recognizer, {
  11806. /**
  11807. * @namespace
  11808. * @memberof PressRecognizer
  11809. */
  11810. defaults: {
  11811. event: 'press',
  11812. pointers: 1,
  11813. time: 500, // minimal time of the pointer to be pressed
  11814. threshold: 5 // a minimal movement is ok, but keep it low
  11815. },
  11816. getTouchAction: function() {
  11817. return [TOUCH_ACTION_AUTO];
  11818. },
  11819. process: function(input) {
  11820. var options = this.options;
  11821. var validPointers = input.pointers.length === options.pointers;
  11822. var validMovement = input.distance < options.threshold;
  11823. var validTime = input.deltaTime > options.time;
  11824. this._input = input;
  11825. // we only allow little movement
  11826. // and we've reached an end event, so a tap is possible
  11827. if (!validMovement || !validPointers || (input.eventType & (
  11828. INPUT_END | INPUT_CANCEL) && !validTime)) {
  11829. this.reset();
  11830. } else if (input.eventType & INPUT_START) {
  11831. this.reset();
  11832. this._timer = setTimeoutContext(function() {
  11833. this.state = STATE_RECOGNIZED;
  11834. this.tryEmit();
  11835. }, options.time, this);
  11836. } else if (input.eventType & INPUT_END) {
  11837. return STATE_RECOGNIZED;
  11838. }
  11839. return STATE_FAILED;
  11840. },
  11841. reset: function() {
  11842. clearTimeout(this._timer);
  11843. },
  11844. emit: function(input) {
  11845. if (this.state !== STATE_RECOGNIZED) {
  11846. return;
  11847. }
  11848. if (input && (input.eventType & INPUT_END)) {
  11849. this.manager.emit(this.options.event + 'up', input);
  11850. } else {
  11851. this._input.timeStamp = now();
  11852. this.manager.emit(this.options.event, this._input);
  11853. }
  11854. }
  11855. });
  11856. /**
  11857. * Rotate
  11858. * Recognized when two or more pointer are moving in a circular motion.
  11859. * @constructor
  11860. * @extends AttrRecognizer
  11861. */
  11862. function RotateRecognizer() {
  11863. AttrRecognizer.apply(this, arguments);
  11864. }
  11865. inherit(RotateRecognizer, AttrRecognizer, {
  11866. /**
  11867. * @namespace
  11868. * @memberof RotateRecognizer
  11869. */
  11870. defaults: {
  11871. event: 'rotate',
  11872. threshold: 0,
  11873. pointers: 2
  11874. },
  11875. getTouchAction: function() {
  11876. return [TOUCH_ACTION_NONE];
  11877. },
  11878. attrTest: function(input) {
  11879. return this._super.attrTest.call(this, input) &&
  11880. (Math.abs(input.rotation) > this.options.threshold || this.state &
  11881. STATE_BEGAN);
  11882. }
  11883. });
  11884. /**
  11885. * Swipe
  11886. * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
  11887. * @constructor
  11888. * @extends AttrRecognizer
  11889. */
  11890. function SwipeRecognizer() {
  11891. AttrRecognizer.apply(this, arguments);
  11892. }
  11893. inherit(SwipeRecognizer, AttrRecognizer, {
  11894. /**
  11895. * @namespace
  11896. * @memberof SwipeRecognizer
  11897. */
  11898. defaults: {
  11899. event: 'swipe',
  11900. threshold: 10,
  11901. velocity: 0.65,
  11902. direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
  11903. pointers: 1
  11904. },
  11905. getTouchAction: function() {
  11906. return PanRecognizer.prototype.getTouchAction.call(this);
  11907. },
  11908. attrTest: function(input) {
  11909. var direction = this.options.direction;
  11910. var velocity;
  11911. if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
  11912. velocity = input.velocity;
  11913. } else if (direction & DIRECTION_HORIZONTAL) {
  11914. velocity = input.velocityX;
  11915. } else if (direction & DIRECTION_VERTICAL) {
  11916. velocity = input.velocityY;
  11917. }
  11918. return this._super.attrTest.call(this, input) &&
  11919. direction & input.direction &&
  11920. input.distance > this.options.threshold &&
  11921. abs(velocity) > this.options.velocity && input.eventType &
  11922. INPUT_END;
  11923. },
  11924. emit: function(input) {
  11925. var direction = directionStr(input.direction);
  11926. if (direction) {
  11927. this.manager.emit(this.options.event + direction, input);
  11928. }
  11929. this.manager.emit(this.options.event, input);
  11930. }
  11931. });
  11932. /**
  11933. * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
  11934. * between the given interval and position. The delay option can be used to recognize multi-taps without firing
  11935. * a single tap.
  11936. *
  11937. * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
  11938. * multi-taps being recognized.
  11939. * @constructor
  11940. * @extends Recognizer
  11941. */
  11942. function TapRecognizer() {
  11943. Recognizer.apply(this, arguments);
  11944. // previous time and center,
  11945. // used for tap counting
  11946. this.pTime = false;
  11947. this.pCenter = false;
  11948. this._timer = null;
  11949. this._input = null;
  11950. this.count = 0;
  11951. }
  11952. inherit(TapRecognizer, Recognizer, {
  11953. /**
  11954. * @namespace
  11955. * @memberof PinchRecognizer
  11956. */
  11957. defaults: {
  11958. event: 'tap',
  11959. pointers: 1,
  11960. taps: 1,
  11961. interval: 300, // max time between the multi-tap taps
  11962. time: 250, // max time of the pointer to be down (like finger on the screen)
  11963. threshold: 2, // a minimal movement is ok, but keep it low
  11964. posThreshold: 10 // a multi-tap can be a bit off the initial position
  11965. },
  11966. getTouchAction: function() {
  11967. return [TOUCH_ACTION_MANIPULATION];
  11968. },
  11969. process: function(input) {
  11970. var options = this.options;
  11971. var validPointers = input.pointers.length === options.pointers;
  11972. var validMovement = input.distance < options.threshold;
  11973. var validTouchTime = input.deltaTime < options.time;
  11974. this.reset();
  11975. if ((input.eventType & INPUT_START) && (this.count === 0)) {
  11976. return this.failTimeout();
  11977. }
  11978. // we only allow little movement
  11979. // and we've reached an end event, so a tap is possible
  11980. if (validMovement && validTouchTime && validPointers) {
  11981. if (input.eventType != INPUT_END) {
  11982. return this.failTimeout();
  11983. }
  11984. var validInterval = this.pTime ? (input.timeStamp - this.pTime <
  11985. options.interval) : true;
  11986. var validMultiTap = !this.pCenter || getDistance(this.pCenter,
  11987. input.center) < options.posThreshold;
  11988. this.pTime = input.timeStamp;
  11989. this.pCenter = input.center;
  11990. if (!validMultiTap || !validInterval) {
  11991. this.count = 1;
  11992. } else {
  11993. this.count += 1;
  11994. }
  11995. this._input = input;
  11996. // if tap count matches we have recognized it,
  11997. // else it has began recognizing...
  11998. var tapCount = this.count % options.taps;
  11999. if (tapCount === 0) {
  12000. // no failing requirements, immediately trigger the tap event
  12001. // or wait as long as the multitap interval to trigger
  12002. if (!this.hasRequireFailures()) {
  12003. return STATE_RECOGNIZED;
  12004. } else {
  12005. this._timer = setTimeoutContext(function() {
  12006. this.state = STATE_RECOGNIZED;
  12007. this.tryEmit();
  12008. }, options.interval, this);
  12009. return STATE_BEGAN;
  12010. }
  12011. }
  12012. }
  12013. return STATE_FAILED;
  12014. },
  12015. failTimeout: function() {
  12016. this._timer = setTimeoutContext(function() {
  12017. this.state = STATE_FAILED;
  12018. }, this.options.interval, this);
  12019. return STATE_FAILED;
  12020. },
  12021. reset: function() {
  12022. clearTimeout(this._timer);
  12023. },
  12024. emit: function() {
  12025. if (this.state == STATE_RECOGNIZED) {
  12026. this._input.tapCount = this.count;
  12027. this.manager.emit(this.options.event, this._input);
  12028. }
  12029. }
  12030. });
  12031. /**
  12032. * Simple way to create an manager with a default set of recognizers.
  12033. * @param {HTMLElement} element
  12034. * @param {Object} [options]
  12035. * @constructor
  12036. */
  12037. function Hammer(element, options) {
  12038. options = options || {};
  12039. options.recognizers = ifUndefined(options.recognizers, Hammer.defaults
  12040. .preset);
  12041. return new Manager(element, options);
  12042. }
  12043. /**
  12044. * @const {string}
  12045. */
  12046. Hammer.VERSION = '2.0.4';
  12047. /**
  12048. * default settings
  12049. * @namespace
  12050. */
  12051. Hammer.defaults = {
  12052. /**
  12053. * set if DOM events are being triggered.
  12054. * But this is slower and unused by simple implementations, so disabled by default.
  12055. * @type {Boolean}
  12056. * @default false
  12057. */
  12058. domEvents: false,
  12059. /**
  12060. * The value for the touchAction property/fallback.
  12061. * When set to `compute` it will magically set the correct value based on the added recognizers.
  12062. * @type {String}
  12063. * @default compute
  12064. */
  12065. touchAction: TOUCH_ACTION_COMPUTE,
  12066. /**
  12067. * @type {Boolean}
  12068. * @default true
  12069. */
  12070. enable: true,
  12071. /**
  12072. * EXPERIMENTAL FEATURE -- can be removed/changed
  12073. * Change the parent input target element.
  12074. * If Null, then it is being set the to main element.
  12075. * @type {Null|EventTarget}
  12076. * @default null
  12077. */
  12078. inputTarget: null,
  12079. /**
  12080. * force an input class
  12081. * @type {Null|Function}
  12082. * @default null
  12083. */
  12084. inputClass: null,
  12085. /**
  12086. * Default recognizer setup when calling `Hammer()`
  12087. * When creating a new Manager these will be skipped.
  12088. * @type {Array}
  12089. */
  12090. preset: [
  12091. // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
  12092. [RotateRecognizer, {
  12093. enable: false
  12094. }],
  12095. [PinchRecognizer, {
  12096. enable: false
  12097. },
  12098. ['rotate']
  12099. ],
  12100. [SwipeRecognizer, {
  12101. direction: DIRECTION_HORIZONTAL
  12102. }],
  12103. [PanRecognizer, {
  12104. direction: DIRECTION_HORIZONTAL
  12105. },
  12106. ['swipe']
  12107. ],
  12108. [TapRecognizer],
  12109. [TapRecognizer, {
  12110. event: 'doubletap',
  12111. taps: 2
  12112. },
  12113. ['tap']
  12114. ],
  12115. [PressRecognizer]
  12116. ],
  12117. /**
  12118. * Some CSS properties can be used to improve the working of Hammer.
  12119. * Add them to this method and they will be set when creating a new Manager.
  12120. * @namespace
  12121. */
  12122. cssProps: {
  12123. /**
  12124. * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
  12125. * @type {String}
  12126. * @default 'none'
  12127. */
  12128. userSelect: 'none',
  12129. /**
  12130. * Disable the Windows Phone grippers when pressing an element.
  12131. * @type {String}
  12132. * @default 'none'
  12133. */
  12134. touchSelect: 'none',
  12135. /**
  12136. * Disables the default callout shown when you touch and hold a touch target.
  12137. * On iOS, when you touch and hold a touch target such as a link, Safari displays
  12138. * a callout containing information about the link. This property allows you to disable that callout.
  12139. * @type {String}
  12140. * @default 'none'
  12141. */
  12142. touchCallout: 'none',
  12143. /**
  12144. * Specifies whether zooming is enabled. Used by IE10>
  12145. * @type {String}
  12146. * @default 'none'
  12147. */
  12148. contentZooming: 'none',
  12149. /**
  12150. * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
  12151. * @type {String}
  12152. * @default 'none'
  12153. */
  12154. userDrag: 'none',
  12155. /**
  12156. * Overrides the highlight color shown when the user taps a link or a JavaScript
  12157. * clickable element in iOS. This property obeys the alpha value, if specified.
  12158. * @type {String}
  12159. * @default 'rgba(0,0,0,0)'
  12160. */
  12161. tapHighlightColor: 'rgba(0,0,0,0)'
  12162. }
  12163. };
  12164. var STOP = 1;
  12165. var FORCED_STOP = 2;
  12166. /**
  12167. * Manager
  12168. * @param {HTMLElement} element
  12169. * @param {Object} [options]
  12170. * @constructor
  12171. */
  12172. function Manager(element, options) {
  12173. options = options || {};
  12174. this.options = merge(options, Hammer.defaults);
  12175. this.options.inputTarget = this.options.inputTarget || element;
  12176. this.handlers = {};
  12177. this.session = {};
  12178. this.recognizers = [];
  12179. this.element = element;
  12180. this.input = createInputInstance(this);
  12181. this.touchAction = new TouchAction(this, this.options.touchAction);
  12182. toggleCssProps(this, true);
  12183. each(options.recognizers, function(item) {
  12184. var recognizer = this.add(new(item[0])(item[1]));
  12185. item[2] && recognizer.recognizeWith(item[2]);
  12186. item[3] && recognizer.requireFailure(item[3]);
  12187. }, this);
  12188. }
  12189. Manager.prototype = {
  12190. /**
  12191. * set options
  12192. * @param {Object} options
  12193. * @returns {Manager}
  12194. */
  12195. set: function(options) {
  12196. extend(this.options, options);
  12197. // Options that need a little more setup
  12198. if (options.touchAction) {
  12199. this.touchAction.update();
  12200. }
  12201. if (options.inputTarget) {
  12202. // Clean up existing event listeners and reinitialize
  12203. this.input.destroy();
  12204. this.input.target = options.inputTarget;
  12205. this.input.init();
  12206. }
  12207. return this;
  12208. },
  12209. /**
  12210. * stop recognizing for this session.
  12211. * This session will be discarded, when a new [input]start event is fired.
  12212. * When forced, the recognizer cycle is stopped immediately.
  12213. * @param {Boolean} [force]
  12214. */
  12215. stop: function(force) {
  12216. this.session.stopped = force ? FORCED_STOP : STOP;
  12217. },
  12218. /**
  12219. * run the recognizers!
  12220. * called by the inputHandler function on every movement of the pointers (touches)
  12221. * it walks through all the recognizers and tries to detect the gesture that is being made
  12222. * @param {Object} inputData
  12223. */
  12224. recognize: function(inputData) {
  12225. var session = this.session;
  12226. if (session.stopped) {
  12227. return;
  12228. }
  12229. // run the touch-action polyfill
  12230. this.touchAction.preventDefaults(inputData);
  12231. var recognizer;
  12232. var recognizers = this.recognizers;
  12233. // this holds the recognizer that is being recognized.
  12234. // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
  12235. // if no recognizer is detecting a thing, it is set to `null`
  12236. var curRecognizer = session.curRecognizer;
  12237. // reset when the last recognizer is recognized
  12238. // or when we're in a new session
  12239. if (!curRecognizer || (curRecognizer && curRecognizer.state &
  12240. STATE_RECOGNIZED)) {
  12241. curRecognizer = session.curRecognizer = null;
  12242. }
  12243. var i = 0;
  12244. while (i < recognizers.length) {
  12245. recognizer = recognizers[i];
  12246. // find out if we are allowed try to recognize the input for this one.
  12247. // 1. allow if the session is NOT forced stopped (see the .stop() method)
  12248. // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
  12249. // that is being recognized.
  12250. // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
  12251. // this can be setup with the `recognizeWith()` method on the recognizer.
  12252. if (session.stopped !== FORCED_STOP && ( // 1
  12253. !curRecognizer || recognizer == curRecognizer || // 2
  12254. recognizer.canRecognizeWith(curRecognizer))) { // 3
  12255. recognizer.recognize(inputData);
  12256. } else {
  12257. recognizer.reset();
  12258. }
  12259. // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
  12260. // current active recognizer. but only if we don't already have an active recognizer
  12261. if (!curRecognizer && recognizer.state & (STATE_BEGAN |
  12262. STATE_CHANGED | STATE_ENDED)) {
  12263. curRecognizer = session.curRecognizer = recognizer;
  12264. }
  12265. i++;
  12266. }
  12267. },
  12268. /**
  12269. * get a recognizer by its event name.
  12270. * @param {Recognizer|String} recognizer
  12271. * @returns {Recognizer|Null}
  12272. */
  12273. get: function(recognizer) {
  12274. if (recognizer instanceof Recognizer) {
  12275. return recognizer;
  12276. }
  12277. var recognizers = this.recognizers;
  12278. for (var i = 0; i < recognizers.length; i++) {
  12279. if (recognizers[i].options.event == recognizer) {
  12280. return recognizers[i];
  12281. }
  12282. }
  12283. return null;
  12284. },
  12285. /**
  12286. * add a recognizer to the manager
  12287. * existing recognizers with the same event name will be removed
  12288. * @param {Recognizer} recognizer
  12289. * @returns {Recognizer|Manager}
  12290. */
  12291. add: function(recognizer) {
  12292. if (invokeArrayArg(recognizer, 'add', this)) {
  12293. return this;
  12294. }
  12295. // remove existing
  12296. var existing = this.get(recognizer.options.event);
  12297. if (existing) {
  12298. this.remove(existing);
  12299. }
  12300. this.recognizers.push(recognizer);
  12301. recognizer.manager = this;
  12302. this.touchAction.update();
  12303. return recognizer;
  12304. },
  12305. /**
  12306. * remove a recognizer by name or instance
  12307. * @param {Recognizer|String} recognizer
  12308. * @returns {Manager}
  12309. */
  12310. remove: function(recognizer) {
  12311. if (invokeArrayArg(recognizer, 'remove', this)) {
  12312. return this;
  12313. }
  12314. var recognizers = this.recognizers;
  12315. recognizer = this.get(recognizer);
  12316. recognizers.splice(inArray(recognizers, recognizer), 1);
  12317. this.touchAction.update();
  12318. return this;
  12319. },
  12320. /**
  12321. * bind event
  12322. * @param {String} events
  12323. * @param {Function} handler
  12324. * @returns {EventEmitter} this
  12325. */
  12326. on: function(events, handler) {
  12327. var handlers = this.handlers;
  12328. each(splitStr(events), function(event) {
  12329. handlers[event] = handlers[event] || [];
  12330. handlers[event].push(handler);
  12331. });
  12332. return this;
  12333. },
  12334. /**
  12335. * unbind event, leave emit blank to remove all handlers
  12336. * @param {String} events
  12337. * @param {Function} [handler]
  12338. * @returns {EventEmitter} this
  12339. */
  12340. off: function(events, handler) {
  12341. var handlers = this.handlers;
  12342. each(splitStr(events), function(event) {
  12343. if (!handler) {
  12344. delete handlers[event];
  12345. } else {
  12346. handlers[event].splice(inArray(handlers[event], handler),
  12347. 1);
  12348. }
  12349. });
  12350. return this;
  12351. },
  12352. /**
  12353. * emit event to the listeners
  12354. * @param {String} event
  12355. * @param {Object} data
  12356. */
  12357. emit: function(event, data) {
  12358. // we also want to trigger dom events
  12359. if (this.options.domEvents) {
  12360. triggerDomEvent(event, data);
  12361. }
  12362. // no handlers, so skip it all
  12363. var handlers = this.handlers[event] && this.handlers[event].slice();
  12364. if (!handlers || !handlers.length) {
  12365. return;
  12366. }
  12367. data.type = event;
  12368. data.preventDefault = function() {
  12369. data.srcEvent.preventDefault();
  12370. };
  12371. var i = 0;
  12372. while (i < handlers.length) {
  12373. handlers[i](data);
  12374. i++;
  12375. }
  12376. },
  12377. /**
  12378. * destroy the manager and unbinds all events
  12379. * it doesn't unbind dom events, that is the user own responsibility
  12380. */
  12381. destroy: function() {
  12382. this.element && toggleCssProps(this, false);
  12383. this.handlers = {};
  12384. this.session = {};
  12385. this.input.destroy();
  12386. this.element = null;
  12387. }
  12388. };
  12389. /**
  12390. * add/remove the css properties as defined in manager.options.cssProps
  12391. * @param {Manager} manager
  12392. * @param {Boolean} add
  12393. */
  12394. function toggleCssProps(manager, add) {
  12395. var element = manager.element;
  12396. each(manager.options.cssProps, function(value, name) {
  12397. element.style[prefixed(element.style, name)] = add ? value :
  12398. '';
  12399. });
  12400. }
  12401. /**
  12402. * trigger dom event
  12403. * @param {String} event
  12404. * @param {Object} data
  12405. */
  12406. function triggerDomEvent(event, data) {
  12407. var gestureEvent = document.createEvent('Event');
  12408. gestureEvent.initEvent(event, true, true);
  12409. gestureEvent.gesture = data;
  12410. data.target.dispatchEvent(gestureEvent);
  12411. }
  12412. extend(Hammer, {
  12413. INPUT_START: INPUT_START,
  12414. INPUT_MOVE: INPUT_MOVE,
  12415. INPUT_END: INPUT_END,
  12416. INPUT_CANCEL: INPUT_CANCEL,
  12417. STATE_POSSIBLE: STATE_POSSIBLE,
  12418. STATE_BEGAN: STATE_BEGAN,
  12419. STATE_CHANGED: STATE_CHANGED,
  12420. STATE_ENDED: STATE_ENDED,
  12421. STATE_RECOGNIZED: STATE_RECOGNIZED,
  12422. STATE_CANCELLED: STATE_CANCELLED,
  12423. STATE_FAILED: STATE_FAILED,
  12424. DIRECTION_NONE: DIRECTION_NONE,
  12425. DIRECTION_LEFT: DIRECTION_LEFT,
  12426. DIRECTION_RIGHT: DIRECTION_RIGHT,
  12427. DIRECTION_UP: DIRECTION_UP,
  12428. DIRECTION_DOWN: DIRECTION_DOWN,
  12429. DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
  12430. DIRECTION_VERTICAL: DIRECTION_VERTICAL,
  12431. DIRECTION_ALL: DIRECTION_ALL,
  12432. Manager: Manager,
  12433. Input: Input,
  12434. TouchAction: TouchAction,
  12435. TouchInput: TouchInput,
  12436. MouseInput: MouseInput,
  12437. PointerEventInput: PointerEventInput,
  12438. TouchMouseInput: TouchMouseInput,
  12439. SingleTouchInput: SingleTouchInput,
  12440. Recognizer: Recognizer,
  12441. AttrRecognizer: AttrRecognizer,
  12442. Tap: TapRecognizer,
  12443. Pan: PanRecognizer,
  12444. Swipe: SwipeRecognizer,
  12445. Pinch: PinchRecognizer,
  12446. Rotate: RotateRecognizer,
  12447. Press: PressRecognizer,
  12448. on: addEventListeners,
  12449. off: removeEventListeners,
  12450. each: each,
  12451. merge: merge,
  12452. extend: extend,
  12453. inherit: inherit,
  12454. bindFn: bindFn,
  12455. prefixed: prefixed
  12456. });
  12457. // jquery.hammer.js
  12458. // This jQuery plugin is just a small wrapper around the Hammer() class.
  12459. // It also extends the Manager.emit method by triggering jQuery events.
  12460. // $(element).hammer(options).bind("pan", myPanHandler);
  12461. // The Hammer instance is stored at $element.data("hammer").
  12462. // https://github.com/hammerjs/jquery.hammer.js
  12463. (function($, Hammer) {
  12464. function hammerify(el, options) {
  12465. var $el = $(el);
  12466. if (!$el.data('hammer')) {
  12467. $el.data('hammer', new Hammer($el[0], options));
  12468. }
  12469. }
  12470. $.fn.hammer = function(options) {
  12471. return this.each(function() {
  12472. hammerify(this, options);
  12473. });
  12474. };
  12475. // extend the emit method to also trigger jQuery events
  12476. Hammer.Manager.prototype.emit = (function(originalEmit) {
  12477. return function(type, data) {
  12478. originalEmit.call(this, type, data);
  12479. $(this.element).trigger({
  12480. type: type,
  12481. gesture: data
  12482. });
  12483. };
  12484. })(Hammer.Manager.prototype.emit);
  12485. })($, Hammer);
  12486. $.AMUI.Hammer = Hammer;
  12487. module.exports = Hammer;
  12488. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  12489. "undefined" ? self : typeof window !== "undefined" ? window : {})
  12490. }, {
  12491. "./core": 4
  12492. }
  12493. ],
  12494. 51: [
  12495. function(require, module, exports) {
  12496. (function(global) {
  12497. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  12498. "undefined" ? global.jQuery : null);
  12499. require('./core');
  12500. /**
  12501. * @ver 1.1.0
  12502. * @via https://github.com/aralejs/qrcode/blob/master/src/qrcode.js
  12503. * @license http://aralejs.org/
  12504. */
  12505. var qrcodeAlgObjCache = [];
  12506. /**
  12507. * 二维码构造函数,主要用于绘制
  12508. * @param {参数列表} opt 传递参数
  12509. * @return {}
  12510. */
  12511. var qrcode = function(opt) {
  12512. if (typeof opt === 'string') { // 只编码ASCII字符串
  12513. opt = {
  12514. text: opt
  12515. };
  12516. }
  12517. //设置默认参数
  12518. this.options = $.extend({}, {
  12519. text: "",
  12520. render: "",
  12521. width: 256,
  12522. height: 256,
  12523. correctLevel: 3,
  12524. background: "#ffffff",
  12525. foreground: "#000000"
  12526. }, opt);
  12527. //使用QRCodeAlg创建二维码结构
  12528. var qrCodeAlg = null;
  12529. for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) {
  12530. if (qrcodeAlgObjCache[i].text == this.options.text &&
  12531. qrcodeAlgObjCache[i].text.correctLevel == this.options.correctLevel
  12532. ) {
  12533. qrCodeAlg = qrcodeAlgObjCache[i].obj;
  12534. break;
  12535. }
  12536. }
  12537. if (i == l) {
  12538. qrCodeAlg = new QRCodeAlg(this.options.text, this.options.correctLevel);
  12539. qrcodeAlgObjCache.push({
  12540. text: this.options.text,
  12541. correctLevel: this.options.correctLevel,
  12542. obj: qrCodeAlg
  12543. });
  12544. }
  12545. if (this.options.render) {
  12546. switch (this.options.render) {
  12547. case "canvas":
  12548. return this.createCanvas(qrCodeAlg);
  12549. case "table":
  12550. return this.createTable(qrCodeAlg);
  12551. case "svg":
  12552. return this.createSVG(qrCodeAlg);
  12553. default:
  12554. return this.createDefault(qrCodeAlg);
  12555. }
  12556. }
  12557. return this.createDefault(qrCodeAlg);
  12558. };
  12559. /**
  12560. * 使用Canvas来画二维码
  12561. * @return {}
  12562. */
  12563. qrcode.prototype.createDefault = function(qrCodeAlg) {
  12564. var canvas = document.createElement('canvas');
  12565. if (canvas.getContext)
  12566. return this.createCanvas(qrCodeAlg);
  12567. if (!!document.createElementNS && !!document.createElementNS(
  12568. SVG_NS, 'svg').createSVGRect)
  12569. return this.createSVG(qrCodeAlg);
  12570. return this.createTable(qrCodeAlg);
  12571. };
  12572. qrcode.prototype.createCanvas = function(qrCodeAlg) {
  12573. //创建canvas节点
  12574. var canvas = document.createElement('canvas');
  12575. canvas.width = this.options.width;
  12576. canvas.height = this.options.height;
  12577. var ctx = canvas.getContext('2d');
  12578. //计算每个点的长宽
  12579. var tileW = (this.options.width / qrCodeAlg.getModuleCount()).toPrecision(
  12580. 4);
  12581. var tileH = this.options.height / qrCodeAlg.getModuleCount().toPrecision(
  12582. 4);
  12583. //绘制
  12584. for (var row = 0; row < qrCodeAlg.getModuleCount(); row++) {
  12585. for (var col = 0; col < qrCodeAlg.getModuleCount(); col++) {
  12586. ctx.fillStyle = qrCodeAlg.modules[row][col] ? this.options.foreground :
  12587. this.options.background;
  12588. var w = (Math.ceil((col + 1) * tileW) - Math.floor(col *
  12589. tileW));
  12590. var h = (Math.ceil((row + 1) * tileW) - Math.floor(row *
  12591. tileW));
  12592. ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH),
  12593. w, h);
  12594. }
  12595. }
  12596. //返回绘制的节点
  12597. return canvas;
  12598. };
  12599. /**
  12600. * 使用table来绘制二维码
  12601. * @return {}
  12602. */
  12603. qrcode.prototype.createTable = function(qrCodeAlg) {
  12604. //创建table节点
  12605. var s = [];
  12606. s.push(
  12607. '<table style="border:0px; margin:0px; padding:0px; border-collapse:collapse; background-color: ' +
  12608. this.options.background +
  12609. ';">');
  12610. // 计算每个节点的长宽;取整,防止点之间出现分离
  12611. var tileW = -1,
  12612. tileH = -1,
  12613. caculateW = -1,
  12614. caculateH = -1;
  12615. tileW = caculateW = Math.floor(this.options.width / qrCodeAlg.getModuleCount());
  12616. tileH = caculateH = Math.floor(this.options.height / qrCodeAlg.getModuleCount());
  12617. if (caculateW <= 0) {
  12618. if (qrCodeAlg.getModuleCount() < 80) {
  12619. tileW = 2;
  12620. } else {
  12621. tileW = 1;
  12622. }
  12623. }
  12624. if (caculateH <= 0) {
  12625. if (qrCodeAlg.getModuleCount() < 80) {
  12626. tileH = 2;
  12627. } else {
  12628. tileH = 1;
  12629. }
  12630. }
  12631. // 绘制二维码
  12632. foreTd = '<td style="border:0px; margin:0px; padding:0px; width:' +
  12633. tileW + 'px; background-color: ' + this.options.foreground +
  12634. '"></td>',
  12635. backTd = '<td style="border:0px; margin:0px; padding:0px; width:' +
  12636. tileW + 'px; background-color: ' + this.options.background +
  12637. '"></td>',
  12638. l = qrCodeAlg.getModuleCount();
  12639. for (var row = 0; row < l; row++) {
  12640. s.push(
  12641. '<tr style="border:0px; margin:0px; padding:0px; height: ' +
  12642. tileH + 'px">');
  12643. for (var col = 0; col < l; col++) {
  12644. s.push(qrCodeAlg.modules[row][col] ? foreTd : backTd);
  12645. }
  12646. s.push('</tr>');
  12647. }
  12648. s.push('</table>');
  12649. var span = document.createElement("span");
  12650. span.innerHTML = s.join('');
  12651. return span.firstChild;
  12652. };
  12653. /**
  12654. * 使用SVG开绘制二维码
  12655. * @return {}
  12656. */
  12657. qrcode.prototype.createSVG = function(qrCodeAlg) {
  12658. var x, dx, y, dy,
  12659. moduleCount = qrCodeAlg.getModuleCount(),
  12660. scale = this.options.height / this.options.width,
  12661. svg = '<svg xmlns="http://www.w3.org/2000/svg" ' + 'width="' +
  12662. this.options.width + 'px" height="' + this.options.height +
  12663. 'px" ' + 'viewbox="0 0 ' + moduleCount * 10 + ' ' + moduleCount *
  12664. 10 * scale + '">',
  12665. rectHead = '<path ',
  12666. foreRect = ' style="stroke-width:0.5;stroke:' + this.options.foreground +
  12667. ';fill:' + this.options.foreground + ';"></path>',
  12668. backRect = ' style="stroke-width:0.5;stroke:' + this.options.background +
  12669. ';fill:' + this.options.background + ';"></path>';
  12670. // draw in the svg
  12671. for (var row = 0; row < moduleCount; row++) {
  12672. for (var col = 0; col < moduleCount; col++) {
  12673. x = col * 10;
  12674. y = row * 10 * scale;
  12675. dx = (col + 1) * 10;
  12676. dy = (row + 1) * 10 * scale;
  12677. svg += rectHead + 'd="M ' + x + ',' + y + ' L ' + dx + ',' +
  12678. y + ' L ' + dx + ',' + dy + ' L ' + x + ',' + dy + ' Z"';
  12679. svg += qrCodeAlg.modules[row][col] ? foreRect : backRect;
  12680. }
  12681. }
  12682. svg += '</svg>';
  12683. // return just built svg
  12684. return $(svg)[0];
  12685. };
  12686. /**
  12687. * 获取单个字符的utf8编码
  12688. * unicode BMP平面约65535个字符
  12689. * @param {num} code
  12690. * return {array}
  12691. */
  12692. function unicodeFormat8(code) {
  12693. // 1 byte
  12694. if (code < 128) {
  12695. return [code];
  12696. // 2 bytes
  12697. } else if (code < 2048) {
  12698. c0 = 192 + (code >> 6);
  12699. c1 = 128 + (code & 63);
  12700. return [c0, c1];
  12701. // 3 bytes
  12702. } else {
  12703. c0 = 224 + (code >> 12);
  12704. c1 = 128 + (code >> 6 & 63);
  12705. c2 = 128 + (code & 63);
  12706. return [c0, c1, c2];
  12707. }
  12708. }
  12709. /**
  12710. * 获取字符串的utf8编码字节串
  12711. * @param {string} string
  12712. * @return {array}
  12713. */
  12714. function getUTF8Bytes(string) {
  12715. var utf8codes = [];
  12716. for (var i = 0; i < string.length; i++) {
  12717. var code = string.charCodeAt(i);
  12718. var utf8 = unicodeFormat8(code);
  12719. for (var j = 0; j < utf8.length; j++) {
  12720. utf8codes.push(utf8[j]);
  12721. }
  12722. }
  12723. return utf8codes;
  12724. }
  12725. /**
  12726. * 二维码算法实现
  12727. * @param {string} data 要编码的信息字符串
  12728. * @param {num} errorCorrectLevel 纠错等级
  12729. */
  12730. function QRCodeAlg(data, errorCorrectLevel) {
  12731. this.typeNumber = -1; //版本
  12732. this.errorCorrectLevel = errorCorrectLevel;
  12733. this.modules = null; //二维矩阵,存放最终结果
  12734. this.moduleCount = 0; //矩阵大小
  12735. this.dataCache = null; //数据缓存
  12736. this.rsBlocks = null; //版本数据信息
  12737. this.totalDataCount = -1; //可使用的数据量
  12738. this.data = data;
  12739. this.utf8bytes = getUTF8Bytes(data);
  12740. this.make();
  12741. }
  12742. QRCodeAlg.prototype = {
  12743. constructor: QRCodeAlg,
  12744. /**
  12745. * 获取二维码矩阵大小
  12746. * @return {num} 矩阵大小
  12747. */
  12748. getModuleCount: function() {
  12749. return this.moduleCount;
  12750. },
  12751. /**
  12752. * 编码
  12753. */
  12754. make: function() {
  12755. this.getRightType();
  12756. this.dataCache = this.createData();
  12757. this.createQrcode();
  12758. },
  12759. /**
  12760. * 设置二位矩阵功能图形
  12761. * @param {bool} test 表示是否在寻找最好掩膜阶段
  12762. * @param {num} maskPattern 掩膜的版本
  12763. */
  12764. makeImpl: function(maskPattern) {
  12765. this.moduleCount = this.typeNumber * 4 + 17;
  12766. this.modules = new Array(this.moduleCount);
  12767. for (var row = 0; row < this.moduleCount; row++) {
  12768. this.modules[row] = new Array(this.moduleCount);
  12769. }
  12770. this.setupPositionProbePattern(0, 0);
  12771. this.setupPositionProbePattern(this.moduleCount - 7, 0);
  12772. this.setupPositionProbePattern(0, this.moduleCount - 7);
  12773. this.setupPositionAdjustPattern();
  12774. this.setupTimingPattern();
  12775. this.setupTypeInfo(true, maskPattern);
  12776. if (this.typeNumber >= 7) {
  12777. this.setupTypeNumber(true);
  12778. }
  12779. this.mapData(this.dataCache, maskPattern);
  12780. },
  12781. /**
  12782. * 设置二维码的位置探测图形
  12783. * @param {num} row 探测图形的中心横坐标
  12784. * @param {num} col 探测图形的中心纵坐标
  12785. */
  12786. setupPositionProbePattern: function(row, col) {
  12787. for (var r = -1; r <= 7; r++) {
  12788. if (row + r <= -1 || this.moduleCount <= row + r) continue;
  12789. for (var c = -1; c <= 7; c++) {
  12790. if (col + c <= -1 || this.moduleCount <= col + c) continue;
  12791. if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c &&
  12792. c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <=
  12793. c && c <= 4)) {
  12794. this.modules[row + r][col + c] = true;
  12795. } else {
  12796. this.modules[row + r][col + c] = false;
  12797. }
  12798. }
  12799. }
  12800. },
  12801. /**
  12802. * 创建二维码
  12803. * @return {[type]} [description]
  12804. */
  12805. createQrcode: function() {
  12806. var minLostPoint = 0;
  12807. var pattern = 0;
  12808. var bestModules = null;
  12809. for (var i = 0; i < 8; i++) {
  12810. this.makeImpl(i);
  12811. var lostPoint = QRUtil.getLostPoint(this);
  12812. if (i == 0 || minLostPoint > lostPoint) {
  12813. minLostPoint = lostPoint;
  12814. pattern = i;
  12815. bestModules = this.modules;
  12816. }
  12817. }
  12818. this.modules = bestModules;
  12819. this.setupTypeInfo(false, pattern);
  12820. if (this.typeNumber >= 7) {
  12821. this.setupTypeNumber(false);
  12822. }
  12823. },
  12824. /**
  12825. * 设置定位图形
  12826. * @return {[type]} [description]
  12827. */
  12828. setupTimingPattern: function() {
  12829. for (var r = 8; r < this.moduleCount - 8; r++) {
  12830. if (this.modules[r][6] != null) {
  12831. continue;
  12832. }
  12833. this.modules[r][6] = (r % 2 == 0);
  12834. if (this.modules[6][r] != null) {
  12835. continue;
  12836. }
  12837. this.modules[6][r] = (r % 2 == 0);
  12838. }
  12839. },
  12840. /**
  12841. * 设置矫正图形
  12842. * @return {[type]} [description]
  12843. */
  12844. setupPositionAdjustPattern: function() {
  12845. var pos = QRUtil.getPatternPosition(this.typeNumber);
  12846. for (var i = 0; i < pos.length; i++) {
  12847. for (var j = 0; j < pos.length; j++) {
  12848. var row = pos[i];
  12849. var col = pos[j];
  12850. if (this.modules[row][col] != null) {
  12851. continue;
  12852. }
  12853. for (var r = -2; r <= 2; r++) {
  12854. for (var c = -2; c <= 2; c++) {
  12855. if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 &&
  12856. c == 0)) {
  12857. this.modules[row + r][col + c] = true;
  12858. } else {
  12859. this.modules[row + r][col + c] = false;
  12860. }
  12861. }
  12862. }
  12863. }
  12864. }
  12865. },
  12866. /**
  12867. * 设置版本信息(7以上版本才有)
  12868. * @param {bool} test 是否处于判断最佳掩膜阶段
  12869. * @return {[type]} [description]
  12870. */
  12871. setupTypeNumber: function(test) {
  12872. var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
  12873. for (var i = 0; i < 18; i++) {
  12874. var mod = (!test && ((bits >> i) & 1) == 1);
  12875. this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 -
  12876. 3
  12877. ] = mod;
  12878. this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i /
  12879. 3)] = mod;
  12880. }
  12881. },
  12882. /**
  12883. * 设置格式信息(纠错等级和掩膜版本)
  12884. * @param {bool} test
  12885. * @param {num} maskPattern 掩膜版本
  12886. * @return {}
  12887. */
  12888. setupTypeInfo: function(test, maskPattern) {
  12889. var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) |
  12890. maskPattern;
  12891. var bits = QRUtil.getBCHTypeInfo(data);
  12892. // vertical
  12893. for (var i = 0; i < 15; i++) {
  12894. var mod = (!test && ((bits >> i) & 1) == 1);
  12895. if (i < 6) {
  12896. this.modules[i][8] = mod;
  12897. } else if (i < 8) {
  12898. this.modules[i + 1][8] = mod;
  12899. } else {
  12900. this.modules[this.moduleCount - 15 + i][8] = mod;
  12901. }
  12902. // horizontal
  12903. var mod = (!test && ((bits >> i) & 1) == 1);
  12904. if (i < 8) {
  12905. this.modules[8][this.moduleCount - i - 1] = mod;
  12906. } else if (i < 9) {
  12907. this.modules[8][15 - i - 1 + 1] = mod;
  12908. } else {
  12909. this.modules[8][15 - i - 1] = mod;
  12910. }
  12911. }
  12912. // fixed module
  12913. this.modules[this.moduleCount - 8][8] = (!test);
  12914. },
  12915. /**
  12916. * 数据编码
  12917. * @return {[type]} [description]
  12918. */
  12919. createData: function() {
  12920. var buffer = new QRBitBuffer();
  12921. var lengthBits = this.typeNumber > 9 ? 16 : 8;
  12922. buffer.put(4, 4); //添加模式
  12923. buffer.put(this.utf8bytes.length, lengthBits);
  12924. for (var i = 0, l = this.utf8bytes.length; i < l; i++) {
  12925. buffer.put(this.utf8bytes[i], 8);
  12926. }
  12927. if (buffer.length + 4 <= this.totalDataCount * 8) {
  12928. buffer.put(0, 4);
  12929. }
  12930. // padding
  12931. while (buffer.length % 8 != 0) {
  12932. buffer.putBit(false);
  12933. }
  12934. // padding
  12935. while (true) {
  12936. if (buffer.length >= this.totalDataCount * 8) {
  12937. break;
  12938. }
  12939. buffer.put(QRCodeAlg.PAD0, 8);
  12940. if (buffer.length >= this.totalDataCount * 8) {
  12941. break;
  12942. }
  12943. buffer.put(QRCodeAlg.PAD1, 8);
  12944. }
  12945. return this.createBytes(buffer);
  12946. },
  12947. /**
  12948. * 纠错码编码
  12949. * @param {buffer} buffer 数据编码
  12950. * @return {[type]}
  12951. */
  12952. createBytes: function(buffer) {
  12953. var offset = 0;
  12954. var maxDcCount = 0;
  12955. var maxEcCount = 0;
  12956. var length = this.rsBlock.length / 3;
  12957. var rsBlocks = new Array();
  12958. for (var i = 0; i < length; i++) {
  12959. var count = this.rsBlock[i * 3 + 0];
  12960. var totalCount = this.rsBlock[i * 3 + 1];
  12961. var dataCount = this.rsBlock[i * 3 + 2];
  12962. for (var j = 0; j < count; j++) {
  12963. rsBlocks.push([dataCount, totalCount]);
  12964. }
  12965. }
  12966. var dcdata = new Array(rsBlocks.length);
  12967. var ecdata = new Array(rsBlocks.length);
  12968. for (var r = 0; r < rsBlocks.length; r++) {
  12969. var dcCount = rsBlocks[r][0];
  12970. var ecCount = rsBlocks[r][1] - dcCount;
  12971. maxDcCount = Math.max(maxDcCount, dcCount);
  12972. maxEcCount = Math.max(maxEcCount, ecCount);
  12973. dcdata[r] = new Array(dcCount);
  12974. for (var i = 0; i < dcdata[r].length; i++) {
  12975. dcdata[r][i] = 0xff & buffer.buffer[i + offset];
  12976. }
  12977. offset += dcCount;
  12978. var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  12979. var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() -
  12980. 1);
  12981. var modPoly = rawPoly.mod(rsPoly);
  12982. ecdata[r] = new Array(rsPoly.getLength() - 1);
  12983. for (var i = 0; i < ecdata[r].length; i++) {
  12984. var modIndex = i + modPoly.getLength() - ecdata[r].length;
  12985. ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
  12986. }
  12987. }
  12988. var data = new Array(this.totalDataCount);
  12989. var index = 0;
  12990. for (var i = 0; i < maxDcCount; i++) {
  12991. for (var r = 0; r < rsBlocks.length; r++) {
  12992. if (i < dcdata[r].length) {
  12993. data[index++] = dcdata[r][i];
  12994. }
  12995. }
  12996. }
  12997. for (var i = 0; i < maxEcCount; i++) {
  12998. for (var r = 0; r < rsBlocks.length; r++) {
  12999. if (i < ecdata[r].length) {
  13000. data[index++] = ecdata[r][i];
  13001. }
  13002. }
  13003. }
  13004. return data;
  13005. },
  13006. /**
  13007. * 布置模块,构建最终信息
  13008. * @param {} data
  13009. * @param {} maskPattern
  13010. * @return {}
  13011. */
  13012. mapData: function(data, maskPattern) {
  13013. var inc = -1;
  13014. var row = this.moduleCount - 1;
  13015. var bitIndex = 7;
  13016. var byteIndex = 0;
  13017. for (var col = this.moduleCount - 1; col > 0; col -= 2) {
  13018. if (col == 6) col--;
  13019. while (true) {
  13020. for (var c = 0; c < 2; c++) {
  13021. if (this.modules[row][col - c] == null) {
  13022. var dark = false;
  13023. if (byteIndex < data.length) {
  13024. dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
  13025. }
  13026. var mask = QRUtil.getMask(maskPattern, row, col - c);
  13027. if (mask) {
  13028. dark = !dark;
  13029. }
  13030. this.modules[row][col - c] = dark;
  13031. bitIndex--;
  13032. if (bitIndex == -1) {
  13033. byteIndex++;
  13034. bitIndex = 7;
  13035. }
  13036. }
  13037. }
  13038. row += inc;
  13039. if (row < 0 || this.moduleCount <= row) {
  13040. row -= inc;
  13041. inc = -inc;
  13042. break;
  13043. }
  13044. }
  13045. }
  13046. }
  13047. };
  13048. /**
  13049. * 填充字段
  13050. */
  13051. QRCodeAlg.PAD0 = 0xEC;
  13052. QRCodeAlg.PAD1 = 0x11;
  13053. //---------------------------------------------------------------------
  13054. // 纠错等级对应的编码
  13055. //---------------------------------------------------------------------
  13056. var QRErrorCorrectLevel = [1, 0, 3, 2];
  13057. //---------------------------------------------------------------------
  13058. // 掩膜版本
  13059. //---------------------------------------------------------------------
  13060. var QRMaskPattern = {
  13061. PATTERN000: 0,
  13062. PATTERN001: 1,
  13063. PATTERN010: 2,
  13064. PATTERN011: 3,
  13065. PATTERN100: 4,
  13066. PATTERN101: 5,
  13067. PATTERN110: 6,
  13068. PATTERN111: 7
  13069. };
  13070. //---------------------------------------------------------------------
  13071. // 工具类
  13072. //---------------------------------------------------------------------
  13073. var QRUtil = {
  13074. /*
  13075. 每个版本矫正图形的位置
  13076. */
  13077. PATTERN_POSITION_TABLE: [
  13078. [],
  13079. [6, 18],
  13080. [6, 22],
  13081. [6, 26],
  13082. [6, 30],
  13083. [6, 34],
  13084. [6, 22, 38],
  13085. [6, 24, 42],
  13086. [6, 26, 46],
  13087. [6, 28, 50],
  13088. [6, 30, 54],
  13089. [6, 32, 58],
  13090. [6, 34, 62],
  13091. [6, 26, 46, 66],
  13092. [6, 26, 48, 70],
  13093. [6, 26, 50, 74],
  13094. [6, 30, 54, 78],
  13095. [6, 30, 56, 82],
  13096. [6, 30, 58, 86],
  13097. [6, 34, 62, 90],
  13098. [6, 28, 50, 72, 94],
  13099. [6, 26, 50, 74, 98],
  13100. [6, 30, 54, 78, 102],
  13101. [6, 28, 54, 80, 106],
  13102. [6, 32, 58, 84, 110],
  13103. [6, 30, 58, 86, 114],
  13104. [6, 34, 62, 90, 118],
  13105. [6, 26, 50, 74, 98, 122],
  13106. [6, 30, 54, 78, 102, 126],
  13107. [6, 26, 52, 78, 104, 130],
  13108. [6, 30, 56, 82, 108, 134],
  13109. [6, 34, 60, 86, 112, 138],
  13110. [6, 30, 58, 86, 114, 142],
  13111. [6, 34, 62, 90, 118, 146],
  13112. [6, 30, 54, 78, 102, 126, 150],
  13113. [6, 24, 50, 76, 102, 128, 154],
  13114. [6, 28, 54, 80, 106, 132, 158],
  13115. [6, 32, 58, 84, 110, 136, 162],
  13116. [6, 26, 54, 82, 110, 138, 166],
  13117. [6, 30, 58, 86, 114, 142, 170]
  13118. ],
  13119. G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 <<
  13120. 1) | (1 << 0),
  13121. G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) |
  13122. (1 << 5) | (1 << 2) | (1 << 0),
  13123. G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 <<
  13124. 1),
  13125. /*
  13126. BCH编码格式信息
  13127. */
  13128. getBCHTypeInfo: function(data) {
  13129. var d = data << 10;
  13130. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >=
  13131. 0) {
  13132. d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(
  13133. QRUtil.G15)));
  13134. }
  13135. return ((data << 10) | d) ^ QRUtil.G15_MASK;
  13136. },
  13137. /*
  13138. BCH编码版本信息
  13139. */
  13140. getBCHTypeNumber: function(data) {
  13141. var d = data << 12;
  13142. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >=
  13143. 0) {
  13144. d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(
  13145. QRUtil.G18)));
  13146. }
  13147. return (data << 12) | d;
  13148. },
  13149. /*
  13150. 获取BCH位信息
  13151. */
  13152. getBCHDigit: function(data) {
  13153. var digit = 0;
  13154. while (data != 0) {
  13155. digit++;
  13156. data >>>= 1;
  13157. }
  13158. return digit;
  13159. },
  13160. /*
  13161. 获取版本对应的矫正图形位置
  13162. */
  13163. getPatternPosition: function(typeNumber) {
  13164. return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
  13165. },
  13166. /*
  13167. 掩膜算法
  13168. */
  13169. getMask: function(maskPattern, i, j) {
  13170. switch (maskPattern) {
  13171. case QRMaskPattern.PATTERN000:
  13172. return (i + j) % 2 == 0;
  13173. case QRMaskPattern.PATTERN001:
  13174. return i % 2 == 0;
  13175. case QRMaskPattern.PATTERN010:
  13176. return j % 3 == 0;
  13177. case QRMaskPattern.PATTERN011:
  13178. return (i + j) % 3 == 0;
  13179. case QRMaskPattern.PATTERN100:
  13180. return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
  13181. case QRMaskPattern.PATTERN101:
  13182. return (i * j) % 2 + (i * j) % 3 == 0;
  13183. case QRMaskPattern.PATTERN110:
  13184. return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
  13185. case QRMaskPattern.PATTERN111:
  13186. return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
  13187. default:
  13188. throw new Error("bad maskPattern:" + maskPattern);
  13189. }
  13190. },
  13191. /*
  13192. 获取RS的纠错多项式
  13193. */
  13194. getErrorCorrectPolynomial: function(errorCorrectLength) {
  13195. var a = new QRPolynomial([1], 0);
  13196. for (var i = 0; i < errorCorrectLength; i++) {
  13197. a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
  13198. }
  13199. return a;
  13200. },
  13201. /*
  13202. 获取评价
  13203. */
  13204. getLostPoint: function(qrCode) {
  13205. var moduleCount = qrCode.getModuleCount(),
  13206. lostPoint = 0,
  13207. darkCount = 0;
  13208. for (var row = 0; row < moduleCount; row++) {
  13209. var sameCount = 0;
  13210. var head = qrCode.modules[row][0];
  13211. for (var col = 0; col < moduleCount; col++) {
  13212. var current = qrCode.modules[row][col];
  13213. //level 3 评价
  13214. if (col < moduleCount - 6) {
  13215. if (current && !qrCode.modules[row][col + 1] && qrCode.modules[
  13216. row][col + 2] && qrCode.modules[row][col + 3] &&
  13217. qrCode.modules[row][col + 4] && !qrCode.modules[row][
  13218. col + 5
  13219. ] && qrCode.modules[row][col + 6]) {
  13220. if (col < moduleCount - 10) {
  13221. if (qrCode.modules[row][col + 7] && qrCode.modules[
  13222. row][col + 8] && qrCode.modules[row][col + 9] &&
  13223. qrCode.modules[row][col + 10]) {
  13224. lostPoint += 40;
  13225. }
  13226. } else if (col > 3) {
  13227. if (qrCode.modules[row][col - 1] && qrCode.modules[
  13228. row][col - 2] && qrCode.modules[row][col - 3] &&
  13229. qrCode.modules[row][col - 4]) {
  13230. lostPoint += 40;
  13231. }
  13232. }
  13233. }
  13234. }
  13235. //level 2 评价
  13236. if ((row < moduleCount - 1) && (col < moduleCount - 1)) {
  13237. var count = 0;
  13238. if (current) count++;
  13239. if (qrCode.modules[row + 1][col]) count++;
  13240. if (qrCode.modules[row][col + 1]) count++;
  13241. if (qrCode.modules[row + 1][col + 1]) count++;
  13242. if (count == 0 || count == 4) {
  13243. lostPoint += 3;
  13244. }
  13245. }
  13246. //level 1 评价
  13247. if (head ^ current) {
  13248. sameCount++;
  13249. } else {
  13250. head = current;
  13251. if (sameCount >= 5) {
  13252. lostPoint += (3 + sameCount - 5);
  13253. }
  13254. sameCount = 1;
  13255. }
  13256. //level 4 评价
  13257. if (current) {
  13258. darkCount++;
  13259. }
  13260. }
  13261. }
  13262. for (var col = 0; col < moduleCount; col++) {
  13263. var sameCount = 0;
  13264. var head = qrCode.modules[0][col];
  13265. for (var row = 0; row < moduleCount; row++) {
  13266. var current = qrCode.modules[row][col];
  13267. //level 3 评价
  13268. if (row < moduleCount - 6) {
  13269. if (current && !qrCode.modules[row + 1][col] && qrCode.modules[
  13270. row + 2][col] && qrCode.modules[row + 3][col] &&
  13271. qrCode.modules[row + 4][col] && !qrCode.modules[row +
  13272. 5][col] && qrCode.modules[row + 6][col]) {
  13273. if (row < moduleCount - 10) {
  13274. if (qrCode.modules[row + 7][col] && qrCode.modules[
  13275. row + 8][col] && qrCode.modules[row + 9][col] &&
  13276. qrCode.modules[row + 10][col]) {
  13277. lostPoint += 40;
  13278. }
  13279. } else if (row > 3) {
  13280. if (qrCode.modules[row - 1][col] && qrCode.modules[
  13281. row - 2][col] && qrCode.modules[row - 3][col] &&
  13282. qrCode.modules[row - 4][col]) {
  13283. lostPoint += 40;
  13284. }
  13285. }
  13286. }
  13287. }
  13288. //level 1 评价
  13289. if (head ^ current) {
  13290. sameCount++;
  13291. } else {
  13292. head = current;
  13293. if (sameCount >= 5) {
  13294. lostPoint += (3 + sameCount - 5);
  13295. }
  13296. sameCount = 1;
  13297. }
  13298. }
  13299. }
  13300. // LEVEL4
  13301. var ratio = Math.abs(100 * darkCount / moduleCount /
  13302. moduleCount - 50) / 5;
  13303. lostPoint += ratio * 10;
  13304. return lostPoint;
  13305. }
  13306. };
  13307. //---------------------------------------------------------------------
  13308. // QRMath使用的数学工具
  13309. //---------------------------------------------------------------------
  13310. var QRMath = {
  13311. /*
  13312. 将n转化为a^m
  13313. */
  13314. glog: function(n) {
  13315. if (n < 1) {
  13316. throw new Error("glog(" + n + ")");
  13317. }
  13318. return QRMath.LOG_TABLE[n];
  13319. },
  13320. /*
  13321. 将a^m转化为n
  13322. */
  13323. gexp: function(n) {
  13324. while (n < 0) {
  13325. n += 255;
  13326. }
  13327. while (n >= 256) {
  13328. n -= 255;
  13329. }
  13330. return QRMath.EXP_TABLE[n];
  13331. },
  13332. EXP_TABLE: new Array(256),
  13333. LOG_TABLE: new Array(256)
  13334. };
  13335. for (var i = 0; i < 8; i++) {
  13336. QRMath.EXP_TABLE[i] = 1 << i;
  13337. }
  13338. for (var i = 8; i < 256; i++) {
  13339. QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[
  13340. i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
  13341. }
  13342. for (var i = 0; i < 255; i++) {
  13343. QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
  13344. }
  13345. //---------------------------------------------------------------------
  13346. // QRPolynomial 多项式
  13347. //---------------------------------------------------------------------
  13348. /**
  13349. * 多项式类
  13350. * @param {Array} num 系数
  13351. * @param {num} shift a^shift
  13352. */
  13353. function QRPolynomial(num, shift) {
  13354. if (num.length == undefined) {
  13355. throw new Error(num.length + "/" + shift);
  13356. }
  13357. var offset = 0;
  13358. while (offset < num.length && num[offset] == 0) {
  13359. offset++;
  13360. }
  13361. this.num = new Array(num.length - offset + shift);
  13362. for (var i = 0; i < num.length - offset; i++) {
  13363. this.num[i] = num[i + offset];
  13364. }
  13365. }
  13366. QRPolynomial.prototype = {
  13367. get: function(index) {
  13368. return this.num[index];
  13369. },
  13370. getLength: function() {
  13371. return this.num.length;
  13372. },
  13373. /**
  13374. * 多项式乘法
  13375. * @param {QRPolynomial} e 被乘多项式
  13376. * @return {[type]} [description]
  13377. */
  13378. multiply: function(e) {
  13379. var num = new Array(this.getLength() + e.getLength() - 1);
  13380. for (var i = 0; i < this.getLength(); i++) {
  13381. for (var j = 0; j < e.getLength(); j++) {
  13382. num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath
  13383. .glog(e.get(j)));
  13384. }
  13385. }
  13386. return new QRPolynomial(num, 0);
  13387. },
  13388. /**
  13389. * 多项式模运算
  13390. * @param {QRPolynomial} e 模多项式
  13391. * @return {}
  13392. */
  13393. mod: function(e) {
  13394. var tl = this.getLength(),
  13395. el = e.getLength();
  13396. if (tl - el < 0) {
  13397. return this;
  13398. }
  13399. var num = new Array(tl);
  13400. for (var i = 0; i < tl; i++) {
  13401. num[i] = this.get(i);
  13402. }
  13403. while (num.length >= el) {
  13404. var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0));
  13405. for (var i = 0; i < e.getLength(); i++) {
  13406. num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
  13407. }
  13408. while (num[0] == 0) {
  13409. num.shift();
  13410. }
  13411. }
  13412. return new QRPolynomial(num, 0);
  13413. }
  13414. };
  13415. //---------------------------------------------------------------------
  13416. // RS_BLOCK_TABLE
  13417. //---------------------------------------------------------------------
  13418. /*
  13419. 二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数]
  13420. */
  13421. var RS_BLOCK_TABLE = [
  13422. // L
  13423. // M
  13424. // Q
  13425. // H
  13426. // 1
  13427. [1, 26, 19],
  13428. [1, 26, 16],
  13429. [1, 26, 13],
  13430. [1, 26, 9],
  13431. // 2
  13432. [1, 44, 34],
  13433. [1, 44, 28],
  13434. [1, 44, 22],
  13435. [1, 44, 16],
  13436. // 3
  13437. [1, 70, 55],
  13438. [1, 70, 44],
  13439. [2, 35, 17],
  13440. [2, 35, 13],
  13441. // 4
  13442. [1, 100, 80],
  13443. [2, 50, 32],
  13444. [2, 50, 24],
  13445. [4, 25, 9],
  13446. // 5
  13447. [1, 134, 108],
  13448. [2, 67, 43],
  13449. [2, 33, 15, 2, 34, 16],
  13450. [2, 33, 11, 2, 34, 12],
  13451. // 6
  13452. [2, 86, 68],
  13453. [4, 43, 27],
  13454. [4, 43, 19],
  13455. [4, 43, 15],
  13456. // 7
  13457. [2, 98, 78],
  13458. [4, 49, 31],
  13459. [2, 32, 14, 4, 33, 15],
  13460. [4, 39, 13, 1, 40, 14],
  13461. // 8
  13462. [2, 121, 97],
  13463. [2, 60, 38, 2, 61, 39],
  13464. [4, 40, 18, 2, 41, 19],
  13465. [4, 40, 14, 2, 41, 15],
  13466. // 9
  13467. [2, 146, 116],
  13468. [3, 58, 36, 2, 59, 37],
  13469. [4, 36, 16, 4, 37, 17],
  13470. [4, 36, 12, 4, 37, 13],
  13471. // 10
  13472. [2, 86, 68, 2, 87, 69],
  13473. [4, 69, 43, 1, 70, 44],
  13474. [6, 43, 19, 2, 44, 20],
  13475. [6, 43, 15, 2, 44, 16],
  13476. // 11
  13477. [4, 101, 81],
  13478. [1, 80, 50, 4, 81, 51],
  13479. [4, 50, 22, 4, 51, 23],
  13480. [3, 36, 12, 8, 37, 13],
  13481. // 12
  13482. [2, 116, 92, 2, 117, 93],
  13483. [6, 58, 36, 2, 59, 37],
  13484. [4, 46, 20, 6, 47, 21],
  13485. [7, 42, 14, 4, 43, 15],
  13486. // 13
  13487. [4, 133, 107],
  13488. [8, 59, 37, 1, 60, 38],
  13489. [8, 44, 20, 4, 45, 21],
  13490. [12, 33, 11, 4, 34, 12],
  13491. // 14
  13492. [3, 145, 115, 1, 146, 116],
  13493. [4, 64, 40, 5, 65, 41],
  13494. [11, 36, 16, 5, 37, 17],
  13495. [11, 36, 12, 5, 37, 13],
  13496. // 15
  13497. [5, 109, 87, 1, 110, 88],
  13498. [5, 65, 41, 5, 66, 42],
  13499. [5, 54, 24, 7, 55, 25],
  13500. [11, 36, 12],
  13501. // 16
  13502. [5, 122, 98, 1, 123, 99],
  13503. [7, 73, 45, 3, 74, 46],
  13504. [15, 43, 19, 2, 44, 20],
  13505. [3, 45, 15, 13, 46, 16],
  13506. // 17
  13507. [1, 135, 107, 5, 136, 108],
  13508. [10, 74, 46, 1, 75, 47],
  13509. [1, 50, 22, 15, 51, 23],
  13510. [2, 42, 14, 17, 43, 15],
  13511. // 18
  13512. [5, 150, 120, 1, 151, 121],
  13513. [9, 69, 43, 4, 70, 44],
  13514. [17, 50, 22, 1, 51, 23],
  13515. [2, 42, 14, 19, 43, 15],
  13516. // 19
  13517. [3, 141, 113, 4, 142, 114],
  13518. [3, 70, 44, 11, 71, 45],
  13519. [17, 47, 21, 4, 48, 22],
  13520. [9, 39, 13, 16, 40, 14],
  13521. // 20
  13522. [3, 135, 107, 5, 136, 108],
  13523. [3, 67, 41, 13, 68, 42],
  13524. [15, 54, 24, 5, 55, 25],
  13525. [15, 43, 15, 10, 44, 16],
  13526. // 21
  13527. [4, 144, 116, 4, 145, 117],
  13528. [17, 68, 42],
  13529. [17, 50, 22, 6, 51, 23],
  13530. [19, 46, 16, 6, 47, 17],
  13531. // 22
  13532. [2, 139, 111, 7, 140, 112],
  13533. [17, 74, 46],
  13534. [7, 54, 24, 16, 55, 25],
  13535. [34, 37, 13],
  13536. // 23
  13537. [4, 151, 121, 5, 152, 122],
  13538. [4, 75, 47, 14, 76, 48],
  13539. [11, 54, 24, 14, 55, 25],
  13540. [16, 45, 15, 14, 46, 16],
  13541. // 24
  13542. [6, 147, 117, 4, 148, 118],
  13543. [6, 73, 45, 14, 74, 46],
  13544. [11, 54, 24, 16, 55, 25],
  13545. [30, 46, 16, 2, 47, 17],
  13546. // 25
  13547. [8, 132, 106, 4, 133, 107],
  13548. [8, 75, 47, 13, 76, 48],
  13549. [7, 54, 24, 22, 55, 25],
  13550. [22, 45, 15, 13, 46, 16],
  13551. // 26
  13552. [10, 142, 114, 2, 143, 115],
  13553. [19, 74, 46, 4, 75, 47],
  13554. [28, 50, 22, 6, 51, 23],
  13555. [33, 46, 16, 4, 47, 17],
  13556. // 27
  13557. [8, 152, 122, 4, 153, 123],
  13558. [22, 73, 45, 3, 74, 46],
  13559. [8, 53, 23, 26, 54, 24],
  13560. [12, 45, 15, 28, 46, 16],
  13561. // 28
  13562. [3, 147, 117, 10, 148, 118],
  13563. [3, 73, 45, 23, 74, 46],
  13564. [4, 54, 24, 31, 55, 25],
  13565. [11, 45, 15, 31, 46, 16],
  13566. // 29
  13567. [7, 146, 116, 7, 147, 117],
  13568. [21, 73, 45, 7, 74, 46],
  13569. [1, 53, 23, 37, 54, 24],
  13570. [19, 45, 15, 26, 46, 16],
  13571. // 30
  13572. [5, 145, 115, 10, 146, 116],
  13573. [19, 75, 47, 10, 76, 48],
  13574. [15, 54, 24, 25, 55, 25],
  13575. [23, 45, 15, 25, 46, 16],
  13576. // 31
  13577. [13, 145, 115, 3, 146, 116],
  13578. [2, 74, 46, 29, 75, 47],
  13579. [42, 54, 24, 1, 55, 25],
  13580. [23, 45, 15, 28, 46, 16],
  13581. // 32
  13582. [17, 145, 115],
  13583. [10, 74, 46, 23, 75, 47],
  13584. [10, 54, 24, 35, 55, 25],
  13585. [19, 45, 15, 35, 46, 16],
  13586. // 33
  13587. [17, 145, 115, 1, 146, 116],
  13588. [14, 74, 46, 21, 75, 47],
  13589. [29, 54, 24, 19, 55, 25],
  13590. [11, 45, 15, 46, 46, 16],
  13591. // 34
  13592. [13, 145, 115, 6, 146, 116],
  13593. [14, 74, 46, 23, 75, 47],
  13594. [44, 54, 24, 7, 55, 25],
  13595. [59, 46, 16, 1, 47, 17],
  13596. // 35
  13597. [12, 151, 121, 7, 152, 122],
  13598. [12, 75, 47, 26, 76, 48],
  13599. [39, 54, 24, 14, 55, 25],
  13600. [22, 45, 15, 41, 46, 16],
  13601. // 36
  13602. [6, 151, 121, 14, 152, 122],
  13603. [6, 75, 47, 34, 76, 48],
  13604. [46, 54, 24, 10, 55, 25],
  13605. [2, 45, 15, 64, 46, 16],
  13606. // 37
  13607. [17, 152, 122, 4, 153, 123],
  13608. [29, 74, 46, 14, 75, 47],
  13609. [49, 54, 24, 10, 55, 25],
  13610. [24, 45, 15, 46, 46, 16],
  13611. // 38
  13612. [4, 152, 122, 18, 153, 123],
  13613. [13, 74, 46, 32, 75, 47],
  13614. [48, 54, 24, 14, 55, 25],
  13615. [42, 45, 15, 32, 46, 16],
  13616. // 39
  13617. [20, 147, 117, 4, 148, 118],
  13618. [40, 75, 47, 7, 76, 48],
  13619. [43, 54, 24, 22, 55, 25],
  13620. [10, 45, 15, 67, 46, 16],
  13621. // 40
  13622. [19, 148, 118, 6, 149, 119],
  13623. [18, 75, 47, 31, 76, 48],
  13624. [34, 54, 24, 34, 55, 25],
  13625. [20, 45, 15, 61, 46, 16]
  13626. ];
  13627. /**
  13628. * 根据数据获取对应版本
  13629. * @return {[type]} [description]
  13630. */
  13631. QRCodeAlg.prototype.getRightType = function() {
  13632. for (var typeNumber = 1; typeNumber < 41; typeNumber++) {
  13633. var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel];
  13634. if (rsBlock == undefined) {
  13635. throw new Error("bad rs block @ typeNumber:" + typeNumber +
  13636. "/errorCorrectLevel:" + this.errorCorrectLevel);
  13637. }
  13638. var length = rsBlock.length / 3;
  13639. var totalDataCount = 0;
  13640. for (var i = 0; i < length; i++) {
  13641. var count = rsBlock[i * 3 + 0];
  13642. var dataCount = rsBlock[i * 3 + 2];
  13643. totalDataCount += dataCount * count;
  13644. }
  13645. var lengthBytes = typeNumber > 9 ? 2 : 1;
  13646. if (this.utf8bytes.length + lengthBytes < totalDataCount ||
  13647. typeNumber == 40) {
  13648. this.typeNumber = typeNumber;
  13649. this.rsBlock = rsBlock;
  13650. this.totalDataCount = totalDataCount;
  13651. break;
  13652. }
  13653. }
  13654. };
  13655. //---------------------------------------------------------------------
  13656. // QRBitBuffer
  13657. //---------------------------------------------------------------------
  13658. function QRBitBuffer() {
  13659. this.buffer = new Array();
  13660. this.length = 0;
  13661. }
  13662. QRBitBuffer.prototype = {
  13663. get: function(index) {
  13664. var bufIndex = Math.floor(index / 8);
  13665. return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1);
  13666. },
  13667. put: function(num, length) {
  13668. for (var i = 0; i < length; i++) {
  13669. this.putBit(((num >>> (length - i - 1)) & 1));
  13670. }
  13671. },
  13672. putBit: function(bit) {
  13673. var bufIndex = Math.floor(this.length / 8);
  13674. if (this.buffer.length <= bufIndex) {
  13675. this.buffer.push(0);
  13676. }
  13677. if (bit) {
  13678. this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
  13679. }
  13680. this.length++;
  13681. }
  13682. };
  13683. /**
  13684. * 获取单个字符的utf8编码
  13685. * unicode BMP平面约65535个字符
  13686. * @param {num} code
  13687. * return {array}
  13688. */
  13689. function unicodeFormat8(code) {
  13690. // 1 byte
  13691. if (code < 128) {
  13692. return [code];
  13693. // 2 bytes
  13694. } else if (code < 2048) {
  13695. c0 = 192 + (code >> 6);
  13696. c1 = 128 + (code & 63);
  13697. return [c0, c1];
  13698. // 3 bytes
  13699. } else {
  13700. c0 = 224 + (code >> 12);
  13701. c1 = 128 + (code >> 6 & 63);
  13702. c2 = 128 + (code & 63);
  13703. return [c0, c1, c2];
  13704. }
  13705. }
  13706. /**
  13707. * 获取字符串的utf8编码字节串
  13708. * @param {string} string
  13709. * @return {array}
  13710. */
  13711. function getUTF8Bytes(string) {
  13712. var utf8codes = [];
  13713. for (var i = 0; i < string.length; i++) {
  13714. var code = string.charCodeAt(i);
  13715. var utf8 = unicodeFormat8(code);
  13716. for (var j = 0; j < utf8.length; j++) {
  13717. utf8codes.push(utf8[j]);
  13718. }
  13719. }
  13720. return utf8codes;
  13721. }
  13722. /**
  13723. * 二维码算法实现
  13724. * @param {string} data 要编码的信息字符串
  13725. * @param {num} errorCorrectLevel 纠错等级
  13726. */
  13727. function QRCodeAlg(data, errorCorrectLevel) {
  13728. this.typeNumber = -1; //版本
  13729. this.errorCorrectLevel = errorCorrectLevel;
  13730. this.modules = null; //二维矩阵,存放最终结果
  13731. this.moduleCount = 0; //矩阵大小
  13732. this.dataCache = null; //数据缓存
  13733. this.rsBlocks = null; //版本数据信息
  13734. this.totalDataCount = -1; //可使用的数据量
  13735. this.data = data;
  13736. this.utf8bytes = getUTF8Bytes(data);
  13737. this.make();
  13738. }
  13739. QRCodeAlg.prototype = {
  13740. constructor: QRCodeAlg,
  13741. /**
  13742. * 获取二维码矩阵大小
  13743. * @return {num} 矩阵大小
  13744. */
  13745. getModuleCount: function() {
  13746. return this.moduleCount;
  13747. },
  13748. /**
  13749. * 编码
  13750. */
  13751. make: function() {
  13752. this.getRightType();
  13753. this.dataCache = this.createData();
  13754. this.createQrcode();
  13755. },
  13756. /**
  13757. * 设置二位矩阵功能图形
  13758. * @param {bool} test 表示是否在寻找最好掩膜阶段
  13759. * @param {num} maskPattern 掩膜的版本
  13760. */
  13761. makeImpl: function(maskPattern) {
  13762. this.moduleCount = this.typeNumber * 4 + 17;
  13763. this.modules = new Array(this.moduleCount);
  13764. for (var row = 0; row < this.moduleCount; row++) {
  13765. this.modules[row] = new Array(this.moduleCount);
  13766. }
  13767. this.setupPositionProbePattern(0, 0);
  13768. this.setupPositionProbePattern(this.moduleCount - 7, 0);
  13769. this.setupPositionProbePattern(0, this.moduleCount - 7);
  13770. this.setupPositionAdjustPattern();
  13771. this.setupTimingPattern();
  13772. this.setupTypeInfo(true, maskPattern);
  13773. if (this.typeNumber >= 7) {
  13774. this.setupTypeNumber(true);
  13775. }
  13776. this.mapData(this.dataCache, maskPattern);
  13777. },
  13778. /**
  13779. * 设置二维码的位置探测图形
  13780. * @param {num} row 探测图形的中心横坐标
  13781. * @param {num} col 探测图形的中心纵坐标
  13782. */
  13783. setupPositionProbePattern: function(row, col) {
  13784. for (var r = -1; r <= 7; r++) {
  13785. if (row + r <= -1 || this.moduleCount <= row + r) continue;
  13786. for (var c = -1; c <= 7; c++) {
  13787. if (col + c <= -1 || this.moduleCount <= col + c) continue;
  13788. if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c &&
  13789. c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <=
  13790. c && c <= 4)) {
  13791. this.modules[row + r][col + c] = true;
  13792. } else {
  13793. this.modules[row + r][col + c] = false;
  13794. }
  13795. }
  13796. }
  13797. },
  13798. /**
  13799. * 创建二维码
  13800. * @return {[type]} [description]
  13801. */
  13802. createQrcode: function() {
  13803. var minLostPoint = 0;
  13804. var pattern = 0;
  13805. var bestModules = null;
  13806. for (var i = 0; i < 8; i++) {
  13807. this.makeImpl(i);
  13808. var lostPoint = QRUtil.getLostPoint(this);
  13809. if (i == 0 || minLostPoint > lostPoint) {
  13810. minLostPoint = lostPoint;
  13811. pattern = i;
  13812. bestModules = this.modules;
  13813. }
  13814. }
  13815. this.modules = bestModules;
  13816. this.setupTypeInfo(false, pattern);
  13817. if (this.typeNumber >= 7) {
  13818. this.setupTypeNumber(false);
  13819. }
  13820. },
  13821. /**
  13822. * 设置定位图形
  13823. * @return {[type]} [description]
  13824. */
  13825. setupTimingPattern: function() {
  13826. for (var r = 8; r < this.moduleCount - 8; r++) {
  13827. if (this.modules[r][6] != null) {
  13828. continue;
  13829. }
  13830. this.modules[r][6] = (r % 2 == 0);
  13831. if (this.modules[6][r] != null) {
  13832. continue;
  13833. }
  13834. this.modules[6][r] = (r % 2 == 0);
  13835. }
  13836. },
  13837. /**
  13838. * 设置矫正图形
  13839. * @return {[type]} [description]
  13840. */
  13841. setupPositionAdjustPattern: function() {
  13842. var pos = QRUtil.getPatternPosition(this.typeNumber);
  13843. for (var i = 0; i < pos.length; i++) {
  13844. for (var j = 0; j < pos.length; j++) {
  13845. var row = pos[i];
  13846. var col = pos[j];
  13847. if (this.modules[row][col] != null) {
  13848. continue;
  13849. }
  13850. for (var r = -2; r <= 2; r++) {
  13851. for (var c = -2; c <= 2; c++) {
  13852. if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 &&
  13853. c == 0)) {
  13854. this.modules[row + r][col + c] = true;
  13855. } else {
  13856. this.modules[row + r][col + c] = false;
  13857. }
  13858. }
  13859. }
  13860. }
  13861. }
  13862. },
  13863. /**
  13864. * 设置版本信息(7以上版本才有)
  13865. * @param {bool} test 是否处于判断最佳掩膜阶段
  13866. * @return {[type]} [description]
  13867. */
  13868. setupTypeNumber: function(test) {
  13869. var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
  13870. for (var i = 0; i < 18; i++) {
  13871. var mod = (!test && ((bits >> i) & 1) == 1);
  13872. this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 -
  13873. 3
  13874. ] = mod;
  13875. this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i /
  13876. 3)] = mod;
  13877. }
  13878. },
  13879. /**
  13880. * 设置格式信息(纠错等级和掩膜版本)
  13881. * @param {bool} test
  13882. * @param {num} maskPattern 掩膜版本
  13883. * @return {}
  13884. */
  13885. setupTypeInfo: function(test, maskPattern) {
  13886. var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) |
  13887. maskPattern;
  13888. var bits = QRUtil.getBCHTypeInfo(data);
  13889. // vertical
  13890. for (var i = 0; i < 15; i++) {
  13891. var mod = (!test && ((bits >> i) & 1) == 1);
  13892. if (i < 6) {
  13893. this.modules[i][8] = mod;
  13894. } else if (i < 8) {
  13895. this.modules[i + 1][8] = mod;
  13896. } else {
  13897. this.modules[this.moduleCount - 15 + i][8] = mod;
  13898. }
  13899. // horizontal
  13900. var mod = (!test && ((bits >> i) & 1) == 1);
  13901. if (i < 8) {
  13902. this.modules[8][this.moduleCount - i - 1] = mod;
  13903. } else if (i < 9) {
  13904. this.modules[8][15 - i - 1 + 1] = mod;
  13905. } else {
  13906. this.modules[8][15 - i - 1] = mod;
  13907. }
  13908. }
  13909. // fixed module
  13910. this.modules[this.moduleCount - 8][8] = (!test);
  13911. },
  13912. /**
  13913. * 数据编码
  13914. * @return {[type]} [description]
  13915. */
  13916. createData: function() {
  13917. var buffer = new QRBitBuffer();
  13918. var lengthBits = this.typeNumber > 9 ? 16 : 8;
  13919. buffer.put(4, 4); //添加模式
  13920. buffer.put(this.utf8bytes.length, lengthBits);
  13921. for (var i = 0, l = this.utf8bytes.length; i < l; i++) {
  13922. buffer.put(this.utf8bytes[i], 8);
  13923. }
  13924. if (buffer.length + 4 <= this.totalDataCount * 8) {
  13925. buffer.put(0, 4);
  13926. }
  13927. // padding
  13928. while (buffer.length % 8 != 0) {
  13929. buffer.putBit(false);
  13930. }
  13931. // padding
  13932. while (true) {
  13933. if (buffer.length >= this.totalDataCount * 8) {
  13934. break;
  13935. }
  13936. buffer.put(QRCodeAlg.PAD0, 8);
  13937. if (buffer.length >= this.totalDataCount * 8) {
  13938. break;
  13939. }
  13940. buffer.put(QRCodeAlg.PAD1, 8);
  13941. }
  13942. return this.createBytes(buffer);
  13943. },
  13944. /**
  13945. * 纠错码编码
  13946. * @param {buffer} buffer 数据编码
  13947. * @return {[type]}
  13948. */
  13949. createBytes: function(buffer) {
  13950. var offset = 0;
  13951. var maxDcCount = 0;
  13952. var maxEcCount = 0;
  13953. var length = this.rsBlock.length / 3;
  13954. var rsBlocks = new Array();
  13955. for (var i = 0; i < length; i++) {
  13956. var count = this.rsBlock[i * 3 + 0];
  13957. var totalCount = this.rsBlock[i * 3 + 1];
  13958. var dataCount = this.rsBlock[i * 3 + 2];
  13959. for (var j = 0; j < count; j++) {
  13960. rsBlocks.push([dataCount, totalCount]);
  13961. }
  13962. }
  13963. var dcdata = new Array(rsBlocks.length);
  13964. var ecdata = new Array(rsBlocks.length);
  13965. for (var r = 0; r < rsBlocks.length; r++) {
  13966. var dcCount = rsBlocks[r][0];
  13967. var ecCount = rsBlocks[r][1] - dcCount;
  13968. maxDcCount = Math.max(maxDcCount, dcCount);
  13969. maxEcCount = Math.max(maxEcCount, ecCount);
  13970. dcdata[r] = new Array(dcCount);
  13971. for (var i = 0; i < dcdata[r].length; i++) {
  13972. dcdata[r][i] = 0xff & buffer.buffer[i + offset];
  13973. }
  13974. offset += dcCount;
  13975. var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  13976. var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() -
  13977. 1);
  13978. var modPoly = rawPoly.mod(rsPoly);
  13979. ecdata[r] = new Array(rsPoly.getLength() - 1);
  13980. for (var i = 0; i < ecdata[r].length; i++) {
  13981. var modIndex = i + modPoly.getLength() - ecdata[r].length;
  13982. ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
  13983. }
  13984. }
  13985. var data = new Array(this.totalDataCount);
  13986. var index = 0;
  13987. for (var i = 0; i < maxDcCount; i++) {
  13988. for (var r = 0; r < rsBlocks.length; r++) {
  13989. if (i < dcdata[r].length) {
  13990. data[index++] = dcdata[r][i];
  13991. }
  13992. }
  13993. }
  13994. for (var i = 0; i < maxEcCount; i++) {
  13995. for (var r = 0; r < rsBlocks.length; r++) {
  13996. if (i < ecdata[r].length) {
  13997. data[index++] = ecdata[r][i];
  13998. }
  13999. }
  14000. }
  14001. return data;
  14002. },
  14003. /**
  14004. * 布置模块,构建最终信息
  14005. * @param {} data
  14006. * @param {} maskPattern
  14007. * @return {}
  14008. */
  14009. mapData: function(data, maskPattern) {
  14010. var inc = -1;
  14011. var row = this.moduleCount - 1;
  14012. var bitIndex = 7;
  14013. var byteIndex = 0;
  14014. for (var col = this.moduleCount - 1; col > 0; col -= 2) {
  14015. if (col == 6) col--;
  14016. while (true) {
  14017. for (var c = 0; c < 2; c++) {
  14018. if (this.modules[row][col - c] == null) {
  14019. var dark = false;
  14020. if (byteIndex < data.length) {
  14021. dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
  14022. }
  14023. var mask = QRUtil.getMask(maskPattern, row, col - c);
  14024. if (mask) {
  14025. dark = !dark;
  14026. }
  14027. this.modules[row][col - c] = dark;
  14028. bitIndex--;
  14029. if (bitIndex == -1) {
  14030. byteIndex++;
  14031. bitIndex = 7;
  14032. }
  14033. }
  14034. }
  14035. row += inc;
  14036. if (row < 0 || this.moduleCount <= row) {
  14037. row -= inc;
  14038. inc = -inc;
  14039. break;
  14040. }
  14041. }
  14042. }
  14043. }
  14044. };
  14045. /**
  14046. * 填充字段
  14047. */
  14048. QRCodeAlg.PAD0 = 0xEC;
  14049. QRCodeAlg.PAD1 = 0x11;
  14050. //---------------------------------------------------------------------
  14051. // 纠错等级对应的编码
  14052. //---------------------------------------------------------------------
  14053. var QRErrorCorrectLevel = [1, 0, 3, 2];
  14054. //---------------------------------------------------------------------
  14055. // 掩膜版本
  14056. //---------------------------------------------------------------------
  14057. var QRMaskPattern = {
  14058. PATTERN000: 0,
  14059. PATTERN001: 1,
  14060. PATTERN010: 2,
  14061. PATTERN011: 3,
  14062. PATTERN100: 4,
  14063. PATTERN101: 5,
  14064. PATTERN110: 6,
  14065. PATTERN111: 7
  14066. };
  14067. //---------------------------------------------------------------------
  14068. // 工具类
  14069. //---------------------------------------------------------------------
  14070. var QRUtil = {
  14071. /*
  14072. 每个版本矫正图形的位置
  14073. */
  14074. PATTERN_POSITION_TABLE: [
  14075. [],
  14076. [6, 18],
  14077. [6, 22],
  14078. [6, 26],
  14079. [6, 30],
  14080. [6, 34],
  14081. [6, 22, 38],
  14082. [6, 24, 42],
  14083. [6, 26, 46],
  14084. [6, 28, 50],
  14085. [6, 30, 54],
  14086. [6, 32, 58],
  14087. [6, 34, 62],
  14088. [6, 26, 46, 66],
  14089. [6, 26, 48, 70],
  14090. [6, 26, 50, 74],
  14091. [6, 30, 54, 78],
  14092. [6, 30, 56, 82],
  14093. [6, 30, 58, 86],
  14094. [6, 34, 62, 90],
  14095. [6, 28, 50, 72, 94],
  14096. [6, 26, 50, 74, 98],
  14097. [6, 30, 54, 78, 102],
  14098. [6, 28, 54, 80, 106],
  14099. [6, 32, 58, 84, 110],
  14100. [6, 30, 58, 86, 114],
  14101. [6, 34, 62, 90, 118],
  14102. [6, 26, 50, 74, 98, 122],
  14103. [6, 30, 54, 78, 102, 126],
  14104. [6, 26, 52, 78, 104, 130],
  14105. [6, 30, 56, 82, 108, 134],
  14106. [6, 34, 60, 86, 112, 138],
  14107. [6, 30, 58, 86, 114, 142],
  14108. [6, 34, 62, 90, 118, 146],
  14109. [6, 30, 54, 78, 102, 126, 150],
  14110. [6, 24, 50, 76, 102, 128, 154],
  14111. [6, 28, 54, 80, 106, 132, 158],
  14112. [6, 32, 58, 84, 110, 136, 162],
  14113. [6, 26, 54, 82, 110, 138, 166],
  14114. [6, 30, 58, 86, 114, 142, 170]
  14115. ],
  14116. G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 <<
  14117. 1) | (1 << 0),
  14118. G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) |
  14119. (1 << 5) | (1 << 2) | (1 << 0),
  14120. G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 <<
  14121. 1),
  14122. /*
  14123. BCH编码格式信息
  14124. */
  14125. getBCHTypeInfo: function(data) {
  14126. var d = data << 10;
  14127. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >=
  14128. 0) {
  14129. d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(
  14130. QRUtil.G15)));
  14131. }
  14132. return ((data << 10) | d) ^ QRUtil.G15_MASK;
  14133. },
  14134. /*
  14135. BCH编码版本信息
  14136. */
  14137. getBCHTypeNumber: function(data) {
  14138. var d = data << 12;
  14139. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >=
  14140. 0) {
  14141. d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(
  14142. QRUtil.G18)));
  14143. }
  14144. return (data << 12) | d;
  14145. },
  14146. /*
  14147. 获取BCH位信息
  14148. */
  14149. getBCHDigit: function(data) {
  14150. var digit = 0;
  14151. while (data != 0) {
  14152. digit++;
  14153. data >>>= 1;
  14154. }
  14155. return digit;
  14156. },
  14157. /*
  14158. 获取版本对应的矫正图形位置
  14159. */
  14160. getPatternPosition: function(typeNumber) {
  14161. return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
  14162. },
  14163. /*
  14164. 掩膜算法
  14165. */
  14166. getMask: function(maskPattern, i, j) {
  14167. switch (maskPattern) {
  14168. case QRMaskPattern.PATTERN000:
  14169. return (i + j) % 2 == 0;
  14170. case QRMaskPattern.PATTERN001:
  14171. return i % 2 == 0;
  14172. case QRMaskPattern.PATTERN010:
  14173. return j % 3 == 0;
  14174. case QRMaskPattern.PATTERN011:
  14175. return (i + j) % 3 == 0;
  14176. case QRMaskPattern.PATTERN100:
  14177. return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
  14178. case QRMaskPattern.PATTERN101:
  14179. return (i * j) % 2 + (i * j) % 3 == 0;
  14180. case QRMaskPattern.PATTERN110:
  14181. return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
  14182. case QRMaskPattern.PATTERN111:
  14183. return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
  14184. default:
  14185. throw new Error("bad maskPattern:" + maskPattern);
  14186. }
  14187. },
  14188. /*
  14189. 获取RS的纠错多项式
  14190. */
  14191. getErrorCorrectPolynomial: function(errorCorrectLength) {
  14192. var a = new QRPolynomial([1], 0);
  14193. for (var i = 0; i < errorCorrectLength; i++) {
  14194. a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
  14195. }
  14196. return a;
  14197. },
  14198. /*
  14199. 获取评价
  14200. */
  14201. getLostPoint: function(qrCode) {
  14202. var moduleCount = qrCode.getModuleCount(),
  14203. lostPoint = 0,
  14204. darkCount = 0;
  14205. for (var row = 0; row < moduleCount; row++) {
  14206. var sameCount = 0;
  14207. var head = qrCode.modules[row][0];
  14208. for (var col = 0; col < moduleCount; col++) {
  14209. var current = qrCode.modules[row][col];
  14210. //level 3 评价
  14211. if (col < moduleCount - 6) {
  14212. if (current && !qrCode.modules[row][col + 1] && qrCode.modules[
  14213. row][col + 2] && qrCode.modules[row][col + 3] &&
  14214. qrCode.modules[row][col + 4] && !qrCode.modules[row][
  14215. col + 5
  14216. ] && qrCode.modules[row][col + 6]) {
  14217. if (col < moduleCount - 10) {
  14218. if (qrCode.modules[row][col + 7] && qrCode.modules[
  14219. row][col + 8] && qrCode.modules[row][col + 9] &&
  14220. qrCode.modules[row][col + 10]) {
  14221. lostPoint += 40;
  14222. }
  14223. } else if (col > 3) {
  14224. if (qrCode.modules[row][col - 1] && qrCode.modules[
  14225. row][col - 2] && qrCode.modules[row][col - 3] &&
  14226. qrCode.modules[row][col - 4]) {
  14227. lostPoint += 40;
  14228. }
  14229. }
  14230. }
  14231. }
  14232. //level 2 评价
  14233. if ((row < moduleCount - 1) && (col < moduleCount - 1)) {
  14234. var count = 0;
  14235. if (current) count++;
  14236. if (qrCode.modules[row + 1][col]) count++;
  14237. if (qrCode.modules[row][col + 1]) count++;
  14238. if (qrCode.modules[row + 1][col + 1]) count++;
  14239. if (count == 0 || count == 4) {
  14240. lostPoint += 3;
  14241. }
  14242. }
  14243. //level 1 评价
  14244. if (head ^ current) {
  14245. sameCount++;
  14246. } else {
  14247. head = current;
  14248. if (sameCount >= 5) {
  14249. lostPoint += (3 + sameCount - 5);
  14250. }
  14251. sameCount = 1;
  14252. }
  14253. //level 4 评价
  14254. if (current) {
  14255. darkCount++;
  14256. }
  14257. }
  14258. }
  14259. for (var col = 0; col < moduleCount; col++) {
  14260. var sameCount = 0;
  14261. var head = qrCode.modules[0][col];
  14262. for (var row = 0; row < moduleCount; row++) {
  14263. var current = qrCode.modules[row][col];
  14264. //level 3 评价
  14265. if (row < moduleCount - 6) {
  14266. if (current && !qrCode.modules[row + 1][col] && qrCode.modules[
  14267. row + 2][col] && qrCode.modules[row + 3][col] &&
  14268. qrCode.modules[row + 4][col] && !qrCode.modules[row +
  14269. 5][col] && qrCode.modules[row + 6][col]) {
  14270. if (row < moduleCount - 10) {
  14271. if (qrCode.modules[row + 7][col] && qrCode.modules[
  14272. row + 8][col] && qrCode.modules[row + 9][col] &&
  14273. qrCode.modules[row + 10][col]) {
  14274. lostPoint += 40;
  14275. }
  14276. } else if (row > 3) {
  14277. if (qrCode.modules[row - 1][col] && qrCode.modules[
  14278. row - 2][col] && qrCode.modules[row - 3][col] &&
  14279. qrCode.modules[row - 4][col]) {
  14280. lostPoint += 40;
  14281. }
  14282. }
  14283. }
  14284. }
  14285. //level 1 评价
  14286. if (head ^ current) {
  14287. sameCount++;
  14288. } else {
  14289. head = current;
  14290. if (sameCount >= 5) {
  14291. lostPoint += (3 + sameCount - 5);
  14292. }
  14293. sameCount = 1;
  14294. }
  14295. }
  14296. }
  14297. // LEVEL4
  14298. var ratio = Math.abs(100 * darkCount / moduleCount /
  14299. moduleCount - 50) / 5;
  14300. lostPoint += ratio * 10;
  14301. return lostPoint;
  14302. }
  14303. };
  14304. //---------------------------------------------------------------------
  14305. // QRMath使用的数学工具
  14306. //---------------------------------------------------------------------
  14307. var QRMath = {
  14308. /*
  14309. 将n转化为a^m
  14310. */
  14311. glog: function(n) {
  14312. if (n < 1) {
  14313. throw new Error("glog(" + n + ")");
  14314. }
  14315. return QRMath.LOG_TABLE[n];
  14316. },
  14317. /*
  14318. 将a^m转化为n
  14319. */
  14320. gexp: function(n) {
  14321. while (n < 0) {
  14322. n += 255;
  14323. }
  14324. while (n >= 256) {
  14325. n -= 255;
  14326. }
  14327. return QRMath.EXP_TABLE[n];
  14328. },
  14329. EXP_TABLE: new Array(256),
  14330. LOG_TABLE: new Array(256)
  14331. };
  14332. for (var i = 0; i < 8; i++) {
  14333. QRMath.EXP_TABLE[i] = 1 << i;
  14334. }
  14335. for (var i = 8; i < 256; i++) {
  14336. QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[
  14337. i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
  14338. }
  14339. for (var i = 0; i < 255; i++) {
  14340. QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
  14341. }
  14342. //---------------------------------------------------------------------
  14343. // QRPolynomial 多项式
  14344. //---------------------------------------------------------------------
  14345. /**
  14346. * 多项式类
  14347. * @param {Array} num 系数
  14348. * @param {num} shift a^shift
  14349. */
  14350. function QRPolynomial(num, shift) {
  14351. if (num.length == undefined) {
  14352. throw new Error(num.length + "/" + shift);
  14353. }
  14354. var offset = 0;
  14355. while (offset < num.length && num[offset] == 0) {
  14356. offset++;
  14357. }
  14358. this.num = new Array(num.length - offset + shift);
  14359. for (var i = 0; i < num.length - offset; i++) {
  14360. this.num[i] = num[i + offset];
  14361. }
  14362. }
  14363. QRPolynomial.prototype = {
  14364. get: function(index) {
  14365. return this.num[index];
  14366. },
  14367. getLength: function() {
  14368. return this.num.length;
  14369. },
  14370. /**
  14371. * 多项式乘法
  14372. * @param {QRPolynomial} e 被乘多项式
  14373. * @return {[type]} [description]
  14374. */
  14375. multiply: function(e) {
  14376. var num = new Array(this.getLength() + e.getLength() - 1);
  14377. for (var i = 0; i < this.getLength(); i++) {
  14378. for (var j = 0; j < e.getLength(); j++) {
  14379. num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath
  14380. .glog(e.get(j)));
  14381. }
  14382. }
  14383. return new QRPolynomial(num, 0);
  14384. },
  14385. /**
  14386. * 多项式模运算
  14387. * @param {QRPolynomial} e 模多项式
  14388. * @return {}
  14389. */
  14390. mod: function(e) {
  14391. var tl = this.getLength(),
  14392. el = e.getLength();
  14393. if (tl - el < 0) {
  14394. return this;
  14395. }
  14396. var num = new Array(tl);
  14397. for (var i = 0; i < tl; i++) {
  14398. num[i] = this.get(i);
  14399. }
  14400. while (num.length >= el) {
  14401. var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0));
  14402. for (var i = 0; i < e.getLength(); i++) {
  14403. num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
  14404. }
  14405. while (num[0] == 0) {
  14406. num.shift();
  14407. }
  14408. }
  14409. return new QRPolynomial(num, 0);
  14410. }
  14411. };
  14412. //---------------------------------------------------------------------
  14413. // RS_BLOCK_TABLE
  14414. //---------------------------------------------------------------------
  14415. /*
  14416. 二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数]
  14417. */
  14418. RS_BLOCK_TABLE = [
  14419. // L
  14420. // M
  14421. // Q
  14422. // H
  14423. // 1
  14424. [1, 26, 19],
  14425. [1, 26, 16],
  14426. [1, 26, 13],
  14427. [1, 26, 9],
  14428. // 2
  14429. [1, 44, 34],
  14430. [1, 44, 28],
  14431. [1, 44, 22],
  14432. [1, 44, 16],
  14433. // 3
  14434. [1, 70, 55],
  14435. [1, 70, 44],
  14436. [2, 35, 17],
  14437. [2, 35, 13],
  14438. // 4
  14439. [1, 100, 80],
  14440. [2, 50, 32],
  14441. [2, 50, 24],
  14442. [4, 25, 9],
  14443. // 5
  14444. [1, 134, 108],
  14445. [2, 67, 43],
  14446. [2, 33, 15, 2, 34, 16],
  14447. [2, 33, 11, 2, 34, 12],
  14448. // 6
  14449. [2, 86, 68],
  14450. [4, 43, 27],
  14451. [4, 43, 19],
  14452. [4, 43, 15],
  14453. // 7
  14454. [2, 98, 78],
  14455. [4, 49, 31],
  14456. [2, 32, 14, 4, 33, 15],
  14457. [4, 39, 13, 1, 40, 14],
  14458. // 8
  14459. [2, 121, 97],
  14460. [2, 60, 38, 2, 61, 39],
  14461. [4, 40, 18, 2, 41, 19],
  14462. [4, 40, 14, 2, 41, 15],
  14463. // 9
  14464. [2, 146, 116],
  14465. [3, 58, 36, 2, 59, 37],
  14466. [4, 36, 16, 4, 37, 17],
  14467. [4, 36, 12, 4, 37, 13],
  14468. // 10
  14469. [2, 86, 68, 2, 87, 69],
  14470. [4, 69, 43, 1, 70, 44],
  14471. [6, 43, 19, 2, 44, 20],
  14472. [6, 43, 15, 2, 44, 16],
  14473. // 11
  14474. [4, 101, 81],
  14475. [1, 80, 50, 4, 81, 51],
  14476. [4, 50, 22, 4, 51, 23],
  14477. [3, 36, 12, 8, 37, 13],
  14478. // 12
  14479. [2, 116, 92, 2, 117, 93],
  14480. [6, 58, 36, 2, 59, 37],
  14481. [4, 46, 20, 6, 47, 21],
  14482. [7, 42, 14, 4, 43, 15],
  14483. // 13
  14484. [4, 133, 107],
  14485. [8, 59, 37, 1, 60, 38],
  14486. [8, 44, 20, 4, 45, 21],
  14487. [12, 33, 11, 4, 34, 12],
  14488. // 14
  14489. [3, 145, 115, 1, 146, 116],
  14490. [4, 64, 40, 5, 65, 41],
  14491. [11, 36, 16, 5, 37, 17],
  14492. [11, 36, 12, 5, 37, 13],
  14493. // 15
  14494. [5, 109, 87, 1, 110, 88],
  14495. [5, 65, 41, 5, 66, 42],
  14496. [5, 54, 24, 7, 55, 25],
  14497. [11, 36, 12],
  14498. // 16
  14499. [5, 122, 98, 1, 123, 99],
  14500. [7, 73, 45, 3, 74, 46],
  14501. [15, 43, 19, 2, 44, 20],
  14502. [3, 45, 15, 13, 46, 16],
  14503. // 17
  14504. [1, 135, 107, 5, 136, 108],
  14505. [10, 74, 46, 1, 75, 47],
  14506. [1, 50, 22, 15, 51, 23],
  14507. [2, 42, 14, 17, 43, 15],
  14508. // 18
  14509. [5, 150, 120, 1, 151, 121],
  14510. [9, 69, 43, 4, 70, 44],
  14511. [17, 50, 22, 1, 51, 23],
  14512. [2, 42, 14, 19, 43, 15],
  14513. // 19
  14514. [3, 141, 113, 4, 142, 114],
  14515. [3, 70, 44, 11, 71, 45],
  14516. [17, 47, 21, 4, 48, 22],
  14517. [9, 39, 13, 16, 40, 14],
  14518. // 20
  14519. [3, 135, 107, 5, 136, 108],
  14520. [3, 67, 41, 13, 68, 42],
  14521. [15, 54, 24, 5, 55, 25],
  14522. [15, 43, 15, 10, 44, 16],
  14523. // 21
  14524. [4, 144, 116, 4, 145, 117],
  14525. [17, 68, 42],
  14526. [17, 50, 22, 6, 51, 23],
  14527. [19, 46, 16, 6, 47, 17],
  14528. // 22
  14529. [2, 139, 111, 7, 140, 112],
  14530. [17, 74, 46],
  14531. [7, 54, 24, 16, 55, 25],
  14532. [34, 37, 13],
  14533. // 23
  14534. [4, 151, 121, 5, 152, 122],
  14535. [4, 75, 47, 14, 76, 48],
  14536. [11, 54, 24, 14, 55, 25],
  14537. [16, 45, 15, 14, 46, 16],
  14538. // 24
  14539. [6, 147, 117, 4, 148, 118],
  14540. [6, 73, 45, 14, 74, 46],
  14541. [11, 54, 24, 16, 55, 25],
  14542. [30, 46, 16, 2, 47, 17],
  14543. // 25
  14544. [8, 132, 106, 4, 133, 107],
  14545. [8, 75, 47, 13, 76, 48],
  14546. [7, 54, 24, 22, 55, 25],
  14547. [22, 45, 15, 13, 46, 16],
  14548. // 26
  14549. [10, 142, 114, 2, 143, 115],
  14550. [19, 74, 46, 4, 75, 47],
  14551. [28, 50, 22, 6, 51, 23],
  14552. [33, 46, 16, 4, 47, 17],
  14553. // 27
  14554. [8, 152, 122, 4, 153, 123],
  14555. [22, 73, 45, 3, 74, 46],
  14556. [8, 53, 23, 26, 54, 24],
  14557. [12, 45, 15, 28, 46, 16],
  14558. // 28
  14559. [3, 147, 117, 10, 148, 118],
  14560. [3, 73, 45, 23, 74, 46],
  14561. [4, 54, 24, 31, 55, 25],
  14562. [11, 45, 15, 31, 46, 16],
  14563. // 29
  14564. [7, 146, 116, 7, 147, 117],
  14565. [21, 73, 45, 7, 74, 46],
  14566. [1, 53, 23, 37, 54, 24],
  14567. [19, 45, 15, 26, 46, 16],
  14568. // 30
  14569. [5, 145, 115, 10, 146, 116],
  14570. [19, 75, 47, 10, 76, 48],
  14571. [15, 54, 24, 25, 55, 25],
  14572. [23, 45, 15, 25, 46, 16],
  14573. // 31
  14574. [13, 145, 115, 3, 146, 116],
  14575. [2, 74, 46, 29, 75, 47],
  14576. [42, 54, 24, 1, 55, 25],
  14577. [23, 45, 15, 28, 46, 16],
  14578. // 32
  14579. [17, 145, 115],
  14580. [10, 74, 46, 23, 75, 47],
  14581. [10, 54, 24, 35, 55, 25],
  14582. [19, 45, 15, 35, 46, 16],
  14583. // 33
  14584. [17, 145, 115, 1, 146, 116],
  14585. [14, 74, 46, 21, 75, 47],
  14586. [29, 54, 24, 19, 55, 25],
  14587. [11, 45, 15, 46, 46, 16],
  14588. // 34
  14589. [13, 145, 115, 6, 146, 116],
  14590. [14, 74, 46, 23, 75, 47],
  14591. [44, 54, 24, 7, 55, 25],
  14592. [59, 46, 16, 1, 47, 17],
  14593. // 35
  14594. [12, 151, 121, 7, 152, 122],
  14595. [12, 75, 47, 26, 76, 48],
  14596. [39, 54, 24, 14, 55, 25],
  14597. [22, 45, 15, 41, 46, 16],
  14598. // 36
  14599. [6, 151, 121, 14, 152, 122],
  14600. [6, 75, 47, 34, 76, 48],
  14601. [46, 54, 24, 10, 55, 25],
  14602. [2, 45, 15, 64, 46, 16],
  14603. // 37
  14604. [17, 152, 122, 4, 153, 123],
  14605. [29, 74, 46, 14, 75, 47],
  14606. [49, 54, 24, 10, 55, 25],
  14607. [24, 45, 15, 46, 46, 16],
  14608. // 38
  14609. [4, 152, 122, 18, 153, 123],
  14610. [13, 74, 46, 32, 75, 47],
  14611. [48, 54, 24, 14, 55, 25],
  14612. [42, 45, 15, 32, 46, 16],
  14613. // 39
  14614. [20, 147, 117, 4, 148, 118],
  14615. [40, 75, 47, 7, 76, 48],
  14616. [43, 54, 24, 22, 55, 25],
  14617. [10, 45, 15, 67, 46, 16],
  14618. // 40
  14619. [19, 148, 118, 6, 149, 119],
  14620. [18, 75, 47, 31, 76, 48],
  14621. [34, 54, 24, 34, 55, 25],
  14622. [20, 45, 15, 61, 46, 16]
  14623. ];
  14624. /**
  14625. * 根据数据获取对应版本
  14626. * @return {[type]} [description]
  14627. */
  14628. QRCodeAlg.prototype.getRightType = function() {
  14629. for (var typeNumber = 1; typeNumber < 41; typeNumber++) {
  14630. var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel];
  14631. if (rsBlock == undefined) {
  14632. throw new Error("bad rs block @ typeNumber:" + typeNumber +
  14633. "/errorCorrectLevel:" + this.errorCorrectLevel);
  14634. }
  14635. var length = rsBlock.length / 3;
  14636. var totalDataCount = 0;
  14637. for (var i = 0; i < length; i++) {
  14638. var count = rsBlock[i * 3 + 0];
  14639. var dataCount = rsBlock[i * 3 + 2];
  14640. totalDataCount += dataCount * count;
  14641. }
  14642. var lengthBytes = typeNumber > 9 ? 2 : 1;
  14643. if (this.utf8bytes.length + lengthBytes < totalDataCount ||
  14644. typeNumber == 40) {
  14645. this.typeNumber = typeNumber;
  14646. this.rsBlock = rsBlock;
  14647. this.totalDataCount = totalDataCount;
  14648. break;
  14649. }
  14650. }
  14651. };
  14652. //---------------------------------------------------------------------
  14653. // QRBitBuffer
  14654. //---------------------------------------------------------------------
  14655. function QRBitBuffer() {
  14656. this.buffer = new Array();
  14657. this.length = 0;
  14658. }
  14659. QRBitBuffer.prototype = {
  14660. get: function(index) {
  14661. var bufIndex = Math.floor(index / 8);
  14662. return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1);
  14663. },
  14664. put: function(num, length) {
  14665. for (var i = 0; i < length; i++) {
  14666. this.putBit(((num >>> (length - i - 1)) & 1));
  14667. }
  14668. },
  14669. putBit: function(bit) {
  14670. var bufIndex = Math.floor(this.length / 8);
  14671. if (this.buffer.length <= bufIndex) {
  14672. this.buffer.push(0);
  14673. }
  14674. if (bit) {
  14675. this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
  14676. }
  14677. this.length++;
  14678. }
  14679. };
  14680. $.AMUI.qrcode = qrcode;
  14681. module.exports = qrcode;
  14682. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  14683. "undefined" ? self : typeof window !== "undefined" ? window : {})
  14684. }, {
  14685. "./core": 4
  14686. }
  14687. ],
  14688. 52: [
  14689. function(require, module, exports) {
  14690. (function(global) {
  14691. 'use strict';
  14692. var $ = (typeof window !== "undefined" ? window.jQuery : typeof global !==
  14693. "undefined" ? global.jQuery : null);
  14694. require('./core');
  14695. /**
  14696. * store.js
  14697. * @via https://github.com/marcuswestin/store.js
  14698. * @license https://github.com/marcuswestin/store.js/blob/master/LICENSE
  14699. */
  14700. var store = {};
  14701. var win = window;
  14702. var localStorageName = 'localStorage';
  14703. var storage;
  14704. store.disabled = false;
  14705. store.version = '1.3.17';
  14706. store.set = function(key, value) {};
  14707. store.get = function(key, defaultVal) {};
  14708. store.has = function(key) {
  14709. return store.get(key) !== undefined;
  14710. };
  14711. store.remove = function(key) {};
  14712. store.clear = function() {};
  14713. store.transact = function(key, defaultVal, transactionFn) {
  14714. if (transactionFn == null) {
  14715. transactionFn = defaultVal;
  14716. defaultVal = null;
  14717. }
  14718. if (defaultVal == null) {
  14719. defaultVal = {};
  14720. }
  14721. var val = store.get(key, defaultVal);
  14722. transactionFn(val);
  14723. store.set(key, val);
  14724. };
  14725. store.getAll = function() {};
  14726. store.forEach = function() {};
  14727. store.serialize = function(value) {
  14728. return JSON.stringify(value);
  14729. };
  14730. store.deserialize = function(value) {
  14731. if (typeof value != 'string') {
  14732. return undefined;
  14733. }
  14734. try {
  14735. return JSON.parse(value);
  14736. } catch (e) {
  14737. return value || undefined;
  14738. }
  14739. };
  14740. // Functions to encapsulate questionable FireFox 3.6.13 behavior
  14741. // when about.config::dom.storage.enabled === false
  14742. // See https://github.com/marcuswestin/store.js/issues#issue/13
  14743. function isLocalStorageNameSupported() {
  14744. try {
  14745. return (localStorageName in win && win[localStorageName]);
  14746. } catch (err) {
  14747. return false;
  14748. }
  14749. }
  14750. if (isLocalStorageNameSupported()) {
  14751. storage = win[localStorageName];
  14752. store.set = function(key, val) {
  14753. if (val === undefined) {
  14754. return store.remove(key);
  14755. }
  14756. storage.setItem(key, store.serialize(val));
  14757. return val;
  14758. };
  14759. store.get = function(key, defaultVal) {
  14760. var val = store.deserialize(storage.getItem(key));
  14761. return (val === undefined ? defaultVal : val);
  14762. };
  14763. store.remove = function(key) {
  14764. storage.removeItem(key);
  14765. };
  14766. store.clear = function() {
  14767. storage.clear();
  14768. };
  14769. store.getAll = function() {
  14770. var ret = {};
  14771. store.forEach(function(key, val) {
  14772. ret[key] = val;
  14773. });
  14774. return ret;
  14775. };
  14776. store.forEach = function(callback) {
  14777. for (var i = 0; i < storage.length; i++) {
  14778. var key = storage.key(i);
  14779. callback(key, store.get(key));
  14780. }
  14781. };
  14782. }
  14783. try {
  14784. var testKey = '__storeJs__';
  14785. store.set(testKey, testKey);
  14786. if (store.get(testKey) != testKey) {
  14787. store.disabled = true;
  14788. }
  14789. store.remove(testKey);
  14790. } catch (e) {
  14791. store.disabled = true;
  14792. }
  14793. store.enabled = !store.disabled;
  14794. $.AMUI = $.AMUI || {};
  14795. $.AMUI.store = store;
  14796. module.exports = store;
  14797. }).call(this, typeof global !== "undefined" ? global : typeof self !==
  14798. "undefined" ? self : typeof window !== "undefined" ? window : {})
  14799. }, {
  14800. "./core": 4
  14801. }
  14802. ]
  14803. }, {}, [2]);