fastman2 3.0.0-alpha.1 → 3.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/routerman.js CHANGED
@@ -1,1201 +1 @@
1
- (function webpackUniversalModuleDefinition(root, factory) {
2
- if(typeof exports === 'object' && typeof module === 'object')
3
- module.exports = factory();
4
- else if(typeof define === 'function' && define.amd)
5
- define([], factory);
6
- else if(typeof exports === 'object')
7
- exports["fastman"] = factory();
8
- else
9
- root["fastman"] = factory();
10
- })(this, function() {
11
- return webpackJsonpfastman([7],{
12
-
13
- /***/ 150:
14
- /***/ (function(module, exports, __webpack_require__) {
15
-
16
- "use strict";
17
-
18
-
19
- Object.defineProperty(exports, "__esModule", {
20
- value: true
21
- });
22
- /**
23
- * Created by dfzq on 2017/3/4.
24
- */
25
- /**
26
- * 获取 url 的 fragment(即 hash 中去掉 # 的剩余部分)
27
- *
28
- * 如果没有则返回空字符串
29
- * 如: http://example.com/path/?query=d#123 => 123
30
- *
31
- * @param {String} url url
32
- * @returns {String}
33
- */
34
- var getUrlFragment = exports.getUrlFragment = function getUrlFragment(url) {
35
- var hashIndex = url.indexOf('#');
36
- //return hashIndex === -1 ? '' : url.slice(hashIndex + 1);
37
- return hashIndex === -1 ? '/' : url.slice(hashIndex + 1);
38
- };
39
-
40
- /**
41
- * 获取一个链接相对于当前页面的绝对地址形式
42
- *
43
- * 假设当前页面是 http://a.com/b/c
44
- * 那么有以下情况:
45
- * d => http://a.com/b/d
46
- * /e => http://a.com/e
47
- * #1 => http://a.com/b/c#1
48
- * http://b.com/f => http://b.com/f
49
- *
50
- * @param {String} url url
51
- * @returns {String}
52
- */
53
- var getAbsoluteUrl = exports.getAbsoluteUrl = function getAbsoluteUrl(url) {
54
- var link = document.createElement('a');
55
- link.setAttribute('href', url);
56
- var absoluteUrl = link.href;
57
- link = null;
58
- return absoluteUrl;
59
- };
60
-
61
- /**
62
- * 获取一个 url 的基本部分,即不包括 hash
63
- *
64
- * @param {String} url url
65
- * @returns {String}
66
- */
67
- var getBaseUrl = exports.getBaseUrl = function getBaseUrl(url) {
68
- var hashIndex = url.indexOf('#');
69
- return hashIndex === -1 ? url.slice(0) : url.slice(0, hashIndex);
70
- };
71
-
72
- /**
73
- * 把一个字符串的 url 转为一个可获取其 base 和 fragment 等的对象
74
- *
75
- * @param {String} url url
76
- * @returns {UrlObject}
77
- */
78
- var toUrlObject = exports.toUrlObject = function toUrlObject(url) {
79
- var fullUrl = getAbsoluteUrl(url),
80
- baseUrl = getBaseUrl(fullUrl),
81
- fragment = getUrlFragment(url);
82
-
83
- return {
84
- base: baseUrl,
85
- full: fullUrl,
86
- original: url,
87
- fragment: fragment
88
- };
89
- };
90
-
91
- /**
92
- * 判断浏览器是否支持 sessionStorage,支持返回 true,否则返回 false
93
- * @returns {Boolean}
94
- */
95
- var supportStorage = exports.supportStorage = function supportStorage() {
96
- var mod = 'ob.router.storage.ability';
97
- try {
98
- sessionStorage.setItem(mod, mod);
99
- sessionStorage.removeItem(mod);
100
- return true;
101
- } catch (e) {
102
- return false;
103
- }
104
- };
105
-
106
- /***/ }),
107
-
108
- /***/ 235:
109
- /***/ (function(module, exports, __webpack_require__) {
110
-
111
- module.exports = __webpack_require__(52);
112
-
113
-
114
- /***/ }),
115
-
116
- /***/ 52:
117
- /***/ (function(module, exports, __webpack_require__) {
118
-
119
- "use strict";
120
-
121
-
122
- Object.defineProperty(exports, "__esModule", {
123
- value: true
124
- });
125
- /**
126
- * Created by dfzq on 2017/2/9.
127
- */
128
- var Util = __webpack_require__(150);
129
- var Version = __webpack_require__(58);
130
- // require("./native.history")
131
-
132
-
133
- if (!window.CustomEvent) {
134
- window.CustomEvent = function (type, config) {
135
- config = config || { bubbles: false, cancelable: false, detail: undefined };
136
- var e = document.createEvent('CustomEvent');
137
- e.initCustomEvent(type, config.bubbles, config.cancelable, config.detail);
138
- return e;
139
- };
140
-
141
- window.CustomEvent.prototype = window.Event.prototype;
142
- }
143
-
144
- var EVENTS = {
145
- pageLoadStart: 'pageLoadStart', // ajax 开始加载新页面前
146
- pageLoadCancel: 'pageLoadCancel', // 取消前一个 ajax 加载动作后
147
- pageLoadError: 'pageLoadError', // ajax 加载页面失败后
148
- pageLoadComplete: 'pageLoadComplete', // ajax 加载页面完成后(不论成功与否)
149
- pageAnimationStart: 'pageAnimationStart', // 动画切换 page 前
150
- pageAnimationEnd: 'pageAnimationEnd', // 动画切换 page 结束后
151
- beforePageRemove: 'beforePageRemove', // 移除旧 document 前(适用于非内联 page 切换)
152
- pageRemoved: 'pageRemoved', // 移除旧 document 后(适用于非内联 page 切换)
153
- beforePageSwitch: 'beforePageSwitch', // page 切换前,在 pageAnimationStart 前,beforePageSwitch 之后会做一些额外的处理才触发 pageAnimationStart
154
- pageInit: 'pageInitInternal' // 目前是定义为一个 page 加载完毕后(实际和 pageAnimationEnd 等同)
155
- };
156
-
157
- var routerConfig = {
158
- sectionGroupClass: 'page-group',
159
- // 表示是当前 page 的 class
160
- curPageClass: 'page-current',
161
- // 用来辅助切换时表示 page 是 visible 的,
162
- // 之所以不用 curPageClass,是因为 page-current 已被赋予了「当前 page」这一含义而不仅仅是 display: block
163
- // 并且,别的地方已经使用了,所以不方便做变更,故新增一个
164
- visiblePageClass: 'page-visible',
165
- // 表示是 page 的 class,注意,仅是标志 class,而不是所有的 class
166
- pageClass: 'page'
167
- };
168
-
169
- var DIRECTION = {
170
- leftToRight: 'from-left-to-right',
171
- rightToLeft: 'from-right-to-left'
172
- };
173
-
174
- var theHistory = $.device.hasNativeHistory ? window.history : History;
175
- /**
176
- * 判断对象是否为空(没有属性)
177
- * */
178
- var isObjectEmpty = function isObjectEmpty(obj) {
179
- for (var key in obj) {
180
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
181
- return false;
182
- }
183
- }
184
- return true;
185
- };
186
- var getHistoryState = function getHistoryState() {
187
- // 针对不同的 兼容性 获取 history 的state
188
- if ($.device.hasNativeHistory) {
189
- return theHistory.state; // 没有为 null
190
- }
191
- var state = theHistory.getState().data;
192
- // 兼容的 history 初始时 值为 {} 设置为null 与原来的 情况保持一致
193
- if (isObjectEmpty(state)) {
194
- return null;
195
- }
196
- return state;
197
- };
198
-
199
- /**
200
- * 路由构造函数
201
- * @constructor 构造器
202
- */
203
- var Router = function Router() {
204
- this.sessionNames = {
205
- currentState: 'application.router.currentState',
206
- maxStateId: 'application.router.maxStateId'
207
- };
208
-
209
- // 初始化history的state并做了一些缓存工作
210
- this._init();
211
- this.xhr = null;
212
- // Hash对应的VDom
213
- this.vdoms = {};
214
- // Hash对应的viewId
215
- this.hash2ViewId = {};
216
- // 路由是否由popstate引起
217
- this.popstateFlag = false;
218
-
219
- // 这块的声明已被移植到核心库的router模块中
220
- //window.addEventListener('popstate', this._onPopState.bind(this));
221
- };
222
-
223
- /**
224
- * 初始化
225
- *
226
- * - 把当前文档内容缓存起来
227
- * - 查找默认展示的块内容,查找顺序如下
228
- * 1. id 是 url 中的 fragment 的元素
229
- * 2. 有当前块 class 标识的第一个元素
230
- * 3. 第一个块
231
- * - 初始页面 state 处理
232
- *
233
- * @private
234
- */
235
- Router.prototype._init = function () {
236
-
237
- this.$view = $('body');
238
-
239
- // 用来保存 document 的 map
240
- this.cache = {};
241
- var $doc = $(document);
242
- var currentUrl = location.href;
243
- // 根据absoluteUrl将当前页面的document和page-group的dom缓存起来
244
- this._saveDocumentIntoCache($doc, currentUrl);
245
-
246
- var curPageId;
247
-
248
- var currentUrlObj = Util.toUrlObject(currentUrl);
249
- var $allSection = $doc.find('.' + routerConfig.pageClass);
250
- var $visibleSection = $doc.find('.' + routerConfig.curPageClass);
251
- var $curVisibleSection = $visibleSection.eq(0);
252
- var $hashSection;
253
-
254
- // if (currentUrlObj.fragment) {
255
- // $hashSection = $doc.find('#' + currentUrlObj.fragment);
256
- // }
257
- // if ($hashSection && $hashSection.length) {
258
- // $visibleSection = $hashSection.eq(0);
259
- // }
260
- // else if (!$visibleSection.length) {
261
- // $visibleSection = $allSection.eq(0);
262
- // }
263
- if (!$visibleSection.length) {
264
- $visibleSection = $allSection.eq(0);
265
- }
266
- // 如果当前page没有定义id,则随机产生id
267
- if (!$visibleSection.attr('id')) {
268
- $visibleSection.attr('id', getHistoryState() == null ? this._generateRandomId() : getHistoryState().pageId);
269
- }
270
-
271
- if ($curVisibleSection.length && $curVisibleSection.attr('id') !== $visibleSection.attr('id')) {
272
- // 在 router 到 inner page 的情况下,刷新(或者直接访问该链接)
273
- // 直接切换 class 会有「闪」的现象,或许可以采用 animateSection 来减缓一下
274
- $curVisibleSection.removeClass(routerConfig.curPageClass);
275
- $visibleSection.addClass(routerConfig.curPageClass);
276
- } else {
277
- $visibleSection.addClass(routerConfig.curPageClass);
278
- }
279
- curPageId = $visibleSection.attr('id');
280
-
281
- // 新进入一个使用 history.state 相关技术的页面时,如果第一个 state 不 push/replace,
282
- // 那么在后退回该页面时,将不触发 popState 事件
283
- if (getHistoryState() === null) {
284
- var curState = {
285
- id: this._getNextStateId(),
286
- url: Util.toUrlObject(currentUrl),
287
- pageId: curPageId
288
- };
289
- var hash = currentUrl;
290
- // 当在ie9 中使用historyjs 时 不能将 完整的url 给 replaceState 的第三个参数 会导致地址栏 以及跳转不正确
291
- // 使用 "/" 来代替
292
- if (!$.device.hasNativeHistory) {
293
- hash = curState.url.fragment;
294
- // hash = "?id=" + curState.id + "&pageId=" + curState.pageId;
295
- window.__isReplaceState = true;
296
- }
297
-
298
- // 如果是 historyjs 且 url中已经有 相应标识 认为是 原地刷新 不再执行replaceState
299
- if (!$.device.hasNativeHistory && /\?&_suid=.+$/.test(currentUrl)) {
300
- return;
301
- }
302
-
303
- theHistory.replaceState(curState, '', hash);
304
- this._saveAsCurrentState(curState);
305
- this._incMaxStateId();
306
- }
307
- };
308
-
309
- /**
310
- * 切换到 url 指定的块或文档
311
- *
312
- * 如果 url 指向的是当前页面,那么认为是切换块;
313
- * 否则是切换文档
314
- *
315
- * @param {String} router 核心层的router,内部包含match和path
316
- * @param {Boolean=} ignoreCache 是否强制请求不使用缓存,对 document 生效,默认是 false
317
- */
318
- Router.prototype.load = function (router, ignoreCache) {
319
- // if (ignoreCache === undefined) {
320
- // ignoreCache = false;
321
- // }
322
-
323
- // if (this._isTheSameDocument(location.href, url)) {
324
- // this._switchToSection(Util.getUrlFragment(url));
325
- // } else {
326
- // this._saveDocumentIntoCache($(document), location.href);
327
- // this._switchToDocument(url, ignoreCache);
328
- // }
329
-
330
- // // TODO 目前只支持内联,未来可扩展外联链接方式 ...
331
- // var hashId = Util.getUrlFragment(url)
332
- // core模块中进行v-tree操作
333
- // // 查找当前doms作用域中是否存在当前路由
334
- // if (!this.vdoms[hashId])
335
- // $.loadDocument(hashId)
336
- // 切换页面块
337
- this._switchToSection(router);
338
- };
339
-
340
- /**
341
- * 调用 history.forward()
342
- */
343
- Router.prototype.forward = function () {
344
- theHistory.forward();
345
- };
346
-
347
- /**
348
- * 调用 history.back()
349
- */
350
- Router.prototype.back = function () {
351
- theHistory.back();
352
- };
353
-
354
- //noinspection JSUnusedGlobalSymbols
355
- /**
356
- * @deprecated
357
- */
358
- Router.prototype.loadPage = Router.prototype.load;
359
-
360
- /**
361
- * 切换显示当前文档另一个块
362
- *
363
- * 把新块从右边切入展示,同时会把新的块的记录用 history.pushState 来保存起来
364
- *
365
- * 如果已经是当前显示的块,那么不做任何处理;
366
- * 如果没对应的块,那么忽略。
367
- *
368
- * @param {String} router 待切换router,内部包含match和path
369
- * @private
370
- */
371
- Router.prototype._switchToSection = function (router) {
372
- var hashId = router.path;
373
- var match = router.match;
374
- if (!hashId) {
375
- return;
376
- }
377
-
378
- var $curPage = this._getCurrentSection();
379
- // 根据路由规则,新页面将会是page-group的最后一个子节点
380
- //$newPage = $('#' + sectionId);
381
- var $newPage;
382
- if (!this.hash2ViewId[match]) {
383
- $newPage = this.$view.find('.' + routerConfig.pageClass).eq(-1);
384
- } else {
385
- $newPage = $('#' + this.hash2ViewId[match]);
386
- }
387
-
388
- // 如果已经是当前页,不做任何处理
389
- if ($curPage === $newPage) {
390
- return;
391
- }
392
-
393
- this._animateSection($curPage, $newPage, DIRECTION.rightToLeft);
394
- // 待切换的块未设置ID,自动生成一个随机值
395
- var sectionId;
396
- if (!$newPage.attr('id')) {
397
- sectionId = this._generateRandomId();
398
- $newPage.attr('id', sectionId);
399
- } else {
400
- sectionId = $newPage.attr('id');
401
- }
402
- this.hash2ViewId[match] = sectionId;
403
-
404
- this._pushNewState('#' + hashId, sectionId);
405
-
406
- // // 更新当前可见页面的node
407
- // $.setNode(this.vdoms[hashId])
408
- };
409
-
410
- /**
411
- * 载入显示一个新的文档
412
- *
413
- * - 如果有缓存,那么直接利用缓存来切换
414
- * - 否则,先把页面加载过来缓存,然后再切换
415
- * - 如果解析失败,那么用 location.href 的方式来跳转
416
- *
417
- * 注意:不能在这里以及其之后用 location.href 来 **读取** 切换前的页面的 url,
418
- * 因为如果是 popState 时的调用,那么此时 location 已经是 pop 出来的 state 的了
419
- *
420
- * @param {String} url 新的文档的 url
421
- * @param {Boolean=} ignoreCache 是否不使用缓存强制加载页面
422
- * @param {Boolean=} isPushState 是否需要 pushState
423
- * @param {String=} direction 新文档切入的方向
424
- * @private
425
- */
426
- Router.prototype._switchToDocument = function (url, ignoreCache, isPushState, direction) {
427
- var baseUrl = Util.toUrlObject(url).base;
428
-
429
- if (ignoreCache) {
430
- delete this.cache[baseUrl];
431
- }
432
-
433
- var cacheDocument = this.cache[baseUrl];
434
- var context = this;
435
-
436
- if (cacheDocument) {
437
- this._doSwitchDocument(url, isPushState, direction);
438
- } else {
439
- // TODO 改造成mobi中的http通讯模块 ...
440
- this._loadDocument(url, {
441
- success: function success($doc) {
442
- try {
443
- context._parseDocument(url, $doc);
444
- context._doSwitchDocument(url, isPushState, direction);
445
- } catch (e) {
446
- location.href = url;
447
- }
448
- },
449
- error: function error() {
450
- location.href = url;
451
- }
452
- });
453
- }
454
- };
455
-
456
- /**
457
- * 利用缓存来做具体的切换文档操作
458
- *
459
- * - 确定待切入的文档的默认展示 section
460
- * - 把新文档 append 到 view 中
461
- * - 动画切换文档
462
- * - 如果需要 pushState,那么把最新的状态 push 进去并把当前状态更新为该状态
463
- *
464
- * @param {String} url 待切换的文档的 url
465
- * @param {Boolean} isPushState 加载页面后是否需要 pushState,默认是 true
466
- * @param {String} direction 动画切换方向,默认是 DIRECTION.rightToLeft
467
- * @private
468
- */
469
- Router.prototype._doSwitchDocument = function (url, isPushState, direction) {
470
- if (typeof isPushState === 'undefined') {
471
- isPushState = true;
472
- }
473
-
474
- var urlObj = Util.toUrlObject(url);
475
- // 当前Document
476
- var $currentDoc = this.$view.find('.' + routerConfig.sectionGroupClass);
477
- // 将要animateTo的Document
478
- var $newDoc = $($('<div></div>').append(this.cache[urlObj.base].$content).html());
479
-
480
- // 确定一个 document 展示 section 的顺序
481
- // 1. 与 hash 关联的 element
482
- // 2. 默认的标识为 current 的 element
483
- // 3. 第一个 section
484
- var $allSection = $newDoc.find('.' + routerConfig.pageClass);
485
- var $visibleSection = $newDoc.find('.' + routerConfig.curPageClass);
486
- var $hashSection;
487
-
488
- if (urlObj.fragment) {
489
- $hashSection = $newDoc.find('#' + urlObj.fragment);
490
- }
491
- if ($hashSection && $hashSection.length) {
492
- $visibleSection = $hashSection.eq(0);
493
- } else if (!$visibleSection.length) {
494
- $visibleSection = $allSection.eq(0);
495
- }
496
- if (!$visibleSection.attr('id')) {
497
- $visibleSection.attr('id', this._generateRandomId());
498
- }
499
-
500
- var $currentSection = this._getCurrentSection();
501
- $currentSection.trigger(EVENTS.beforePageSwitch, [$currentSection.attr('id'), $currentSection]);
502
-
503
- $allSection.removeClass(routerConfig.curPageClass);
504
- $visibleSection.addClass(routerConfig.curPageClass);
505
-
506
- // prepend 而不 append 的目的是避免 append 进去新的 document 在后面,
507
- // 其里面的默认展示的(.page-current) 的页面直接就覆盖了原显示的页面(因为都是 absolute)
508
- this.$view.prepend($newDoc);
509
-
510
- this._animateDocument($currentDoc, $newDoc, $visibleSection, direction);
511
-
512
- if (isPushState) {
513
- this._pushNewState(url, $visibleSection.attr('id'));
514
- }
515
- };
516
-
517
- /**
518
- * 判断两个 url 指向的页面是否是同一个
519
- *
520
- * 判断方式: 如果两个 url 的 base 形式(不带 hash 的绝对形式)相同,那么认为是同一个页面
521
- *
522
- * @param {String} url
523
- * @param {String} anotherUrl
524
- * @returns {Boolean}
525
- * @private
526
- */
527
- Router.prototype._isTheSameDocument = function (url, anotherUrl) {
528
- return Util.toUrlObject(url).base === Util.toUrlObject(anotherUrl).base;
529
- };
530
-
531
- /**
532
- * ajax 加载 url 指定的页面内容
533
- *
534
- * 加载过程中会发出以下事件
535
- * pageLoadCancel: 如果前一个还没加载完,那么取消并发送该事件
536
- * pageLoadStart: 开始加载
537
- * pageLodComplete: ajax complete 完成
538
- * pageLoadError: ajax 发生 error
539
- *
540
- *
541
- * @param {String} url url
542
- * @param {Object=} callback 回调函数配置,可选,可以配置 success\error 和 complete
543
- * 所有回调函数的 this 都是 null,各自实参如下:
544
- * success: $doc, status, xhr
545
- * error: xhr, status, err
546
- * complete: xhr, status
547
- *
548
- * @private
549
- */
550
- Router.prototype._loadDocument = function (url, callback) {
551
- // 并发操作考虑
552
- if (this.xhr && this.xhr.readyState < 4) {
553
- this.xhr.onreadystatechange = function () {};
554
- this.xhr.abort();
555
- this.dispatch(EVENTS.pageLoadCancel);
556
- }
557
-
558
- this.dispatch(EVENTS.pageLoadStart);
559
-
560
- callback = callback || {};
561
- var self = this;
562
-
563
- this.xhr = $.ajax({
564
- url: url,
565
- success: $.proxy(function (data, status, xhr) {
566
- // 给包一层 <html/>,从而可以拿到完整的结构
567
- var $doc = $('<html></html>');
568
- $doc.append(data);
569
- callback.success && callback.success.call(null, $doc, status, xhr);
570
- }, this),
571
- error: function error(xhr, status, err) {
572
- callback.error && callback.error.call(null, xhr, status, err);
573
- // Ajax失败时的回调处理
574
- self.dispatch(EVENTS.pageLoadError);
575
- },
576
- complete: function complete(xhr, status) {
577
- callback.complete && callback.complete.call(null, xhr, status);
578
- self.dispatch(EVENTS.pageLoadComplete);
579
- }
580
- });
581
- };
582
-
583
- /**
584
- * 对于 ajax 加载进来的页面,把其缓存起来
585
- *
586
- * @param {String} url url
587
- * @param $doc ajax 载入的页面的 jq 对象,可以看做是该页面的 $(document)
588
- * @private
589
- */
590
- Router.prototype._parseDocument = function (url, $doc) {
591
- var $innerView = $doc.find('.' + routerConfig.sectionGroupClass);
592
-
593
- if (!$innerView.length) {
594
- throw new Error('missing router view mark: ' + routerConfig.sectionGroupClass);
595
- }
596
-
597
- this._saveDocumentIntoCache($doc, url);
598
- };
599
-
600
- /**
601
- * 把一个页面的相关信息保存到 this.cache 中
602
- *
603
- * 以页面的 baseUrl 为 key,而 value 则是一个 DocumentCache
604
- *
605
- * @param {*} doc doc
606
- * @param {String} url url
607
- * @private
608
- */
609
- Router.prototype._saveDocumentIntoCache = function (doc, url) {
610
- var urlAsKey = Util.toUrlObject(url).base;
611
- var $doc = $(doc);
612
-
613
- this.cache[urlAsKey] = {
614
- $doc: $doc,
615
- $content: $doc.find('.' + routerConfig.sectionGroupClass)
616
- };
617
- };
618
-
619
- /**
620
- * 从 sessionStorage 中获取保存下来的「当前状态」
621
- *
622
- * 如果解析失败,那么认为当前状态是 null
623
- *
624
- * @returns {State|null}
625
- * @private
626
- */
627
- Router.prototype._getLastState = function () {
628
- var currentState = sessionStorage.getItem(this.sessionNames.currentState);
629
- try {
630
- currentState = JSON.parse(currentState);
631
- } catch (e) {
632
- currentState = null;
633
- }
634
-
635
- return currentState;
636
- };
637
-
638
- /**
639
- * 把一个状态设为当前状态,保存仅 sessionStorage 中
640
- *
641
- * @param {State} state
642
- * @private
643
- */
644
- Router.prototype._saveAsCurrentState = function (state) {
645
- sessionStorage.setItem(this.sessionNames.currentState, JSON.stringify(state));
646
- };
647
-
648
- /**
649
- * 获取下一个 state 的 id
650
- *
651
- * 读取 sessionStorage 里的最后的状态的 id,然后 + 1;如果原没设置,那么返回 1
652
- *
653
- * @returns {number}
654
- * @private
655
- */
656
- Router.prototype._getNextStateId = function () {
657
- var maxStateId = sessionStorage.getItem(this.sessionNames.maxStateId);
658
- return maxStateId ? parseInt(maxStateId, 10) + 1 : 1;
659
- };
660
-
661
- /**
662
- * 把 sessionStorage 里的最后状态的 id 自加 1
663
- *
664
- * @private
665
- */
666
- Router.prototype._incMaxStateId = function () {
667
- sessionStorage.setItem(this.sessionNames.maxStateId, this._getNextStateId());
668
- };
669
-
670
- /**
671
- * 从一个文档切换为显示另一个文档
672
- *
673
- * @param $from 目前显示的文档
674
- * @param $to 待切换显示的新文档
675
- * @param $visibleSection 新文档中展示的 section 元素
676
- * @param direction 新文档切入方向
677
- * @private
678
- */
679
- Router.prototype._animateDocument = function ($from, $to, $visibleSection, direction) {
680
- var sectionId = $visibleSection.attr('id');
681
-
682
- var $visibleSectionInFrom = $from.find('.' + routerConfig.curPageClass);
683
- $visibleSectionInFrom.addClass(routerConfig.visiblePageClass).removeClass(routerConfig.curPageClass);
684
-
685
- $visibleSection.trigger(EVENTS.pageAnimationStart, [sectionId, $visibleSection]);
686
-
687
- this._animateElement($from, $to, direction);
688
-
689
- if ($.device.ie && Number($.device.ieVersion) <= 9) {
690
- $visibleSectionInFrom.removeClass(routerConfig.visiblePageClass);
691
- // 移除 document 前后,发送 beforePageRemove 和 pageRemoved 事件
692
- $(window).trigger(EVENTS.beforePageRemove, [$from]);
693
- $from.remove();
694
- $(window).trigger(EVENTS.pageRemoved);
695
-
696
- $visibleSection.trigger(EVENTS.pageAnimationEnd, [sectionId, $visibleSection]);
697
- // 外层(init.js)中会绑定 pageInitInternal 事件,然后对页面进行初始化
698
- $visibleSection.trigger(EVENTS.pageInit, [sectionId, $visibleSection]);
699
- } else {
700
- $from.animationEnd(function () {
701
- $visibleSectionInFrom.removeClass(routerConfig.visiblePageClass);
702
- // 移除 document 前后,发送 beforePageRemove 和 pageRemoved 事件
703
- $(window).trigger(EVENTS.beforePageRemove, [$from]);
704
- $from.remove();
705
- $(window).trigger(EVENTS.pageRemoved);
706
- });
707
-
708
- $to.animationEnd(function () {
709
- $visibleSection.trigger(EVENTS.pageAnimationEnd, [sectionId, $visibleSection]);
710
- // 外层(init.js)中会绑定 pageInitInternal 事件,然后对页面进行初始化
711
- $visibleSection.trigger(EVENTS.pageInit, [sectionId, $visibleSection]);
712
- });
713
- }
714
- };
715
-
716
- /**
717
- * 把当前文档的展示 section 从一个 section 切换到另一个 section
718
- *
719
- * @param $from
720
- * @param $to
721
- * @param direction
722
- * @private
723
- */
724
- Router.prototype._animateSection = function ($from, $to, direction) {
725
- var toId = $to.attr('id');
726
- $from.isBack = direction === DIRECTION.rightToLeft ? false : true;
727
- $from.trigger(EVENTS.beforePageSwitch, [$from.attr('id'), $from]);
728
-
729
- // $from.removeClass(routerConfig.curPageClass);
730
- $to.addClass(routerConfig.curPageClass).addClass("page-transiting");
731
- $to.isBack = direction === DIRECTION.rightToLeft ? false : true;
732
-
733
- // 给容器添加scroller自由滚动特性
734
- // 解决virtual-dom和js-scroller公用冲突的bug,全部使用原生scroller
735
- $('[data-toggle="scroller"]').not(".native-scroll").not(".javascript-scroll").scroller({
736
- type: 'native'
737
- });
738
-
739
- $to.trigger(EVENTS.pageAnimationStart, [toId, $to]);
740
- this._animateElement($from, $to, direction);
741
- // 判断是否PageInit
742
- var _isInit = true;
743
- for (var key in this.hash2ViewId) {
744
- if (this.hash2ViewId[key] === toId) {
745
- _isInit = false;
746
- break;
747
- }
748
- }
749
-
750
- // IE9 及以下不支持 动画事件
751
- if ($.device.ie && Number($.device.ieVersion) <= 9) {
752
- $from.removeClass(routerConfig.curPageClass);
753
- $to.removeClass("page-transiting");
754
- $to.trigger(EVENTS.pageAnimationEnd, [toId, $to]);
755
- // 外层(init.js)中会绑定 pageInitInternal 事件,然后对页面进行初始化
756
- if (_isInit) {
757
- $to.trigger(EVENTS.pageInit, [toId, $to]);
758
- }
759
- } else {
760
- $to.animationEnd(function () {
761
- $from.removeClass(routerConfig.curPageClass);
762
- $to.removeClass("page-transiting");
763
- $to.trigger(EVENTS.pageAnimationEnd, [toId, $to]);
764
- // 外层(init.js)中会绑定 pageInitInternal 事件,然后对页面进行初始化
765
- if (_isInit) {
766
- $to.trigger(EVENTS.pageInit, [toId, $to]);
767
- }
768
- });
769
- }
770
- };
771
-
772
- /**
773
- * 切换显示两个元素
774
- *
775
- * 切换是通过更新 class 来实现的,而具体的切换动画则是 class 关联的 css 来实现
776
- *
777
- * @param $from 当前显示的元素
778
- * @param $to 待显示的元素
779
- * @param direction 切换的方向
780
- * @private
781
- */
782
- Router.prototype._animateElement = function ($from, $to, direction) {
783
- // todo: 可考虑如果入参不指定,那么尝试读取 $to 的属性,再没有再使用默认的
784
- // 考虑读取点击的链接上指定的方向
785
- if (typeof direction === 'undefined') {
786
- direction = DIRECTION.rightToLeft;
787
- }
788
-
789
- var animPageClasses = ['page-from-center-to-left', 'page-from-center-to-right', 'page-from-right-to-center', 'page-from-right-to-center-compatible', 'page-from-left-to-center'].join(' ');
790
-
791
- var classForFrom, classForTo;
792
- switch (direction) {
793
- case DIRECTION.rightToLeft:
794
- classForFrom = 'page-from-center-to-left';
795
- //classForTo = $.device.ios ? 'page-from-right-to-center-compatible' : 'page-from-right-to-center';
796
- classForTo = $.device.ios && Version._compareVersion($.device.osVersion, '10.0.0') >= 0 && Version._compareVersion($.device.osVersion, '11.0.0') < 0 ? 'page-from-right-to-center-compatible' : 'page-from-right-to-center';
797
- break;
798
- case DIRECTION.leftToRight:
799
- classForFrom = 'page-from-center-to-right';
800
- classForTo = 'page-from-left-to-center';
801
- break;
802
- default:
803
- classForFrom = 'page-from-center-to-left';
804
- //classForTo = $.device.ios ? 'page-from-right-to-center-compatible' : 'page-from-right-to-center';
805
- classForTo = $.device.ios && Version._compareVersion($.device.osVersion, '10.0.0') >= 0 && Version._compareVersion($.device.osVersion, '11.0.0') < 0 ? 'page-from-right-to-center-compatible' : 'page-from-right-to-center';
806
- break;
807
- }
808
-
809
- $from.removeClass(animPageClasses).addClass(classForFrom);
810
- $to.removeClass(animPageClasses).addClass(classForTo);
811
-
812
- // ie 9及以下不支持动画事件
813
- if ($.device.ie && Number($.device.ieVersion) <= 9) {
814
- $from.removeClass(animPageClasses);
815
- $to.removeClass(animPageClasses);
816
- } else {
817
- $from.animationEnd(function () {
818
- $from.removeClass(animPageClasses);
819
- });
820
- $to.animationEnd(function () {
821
- $to.removeClass(animPageClasses);
822
- });
823
- }
824
- };
825
-
826
- /**
827
- * 获取当前显示的第一个 section
828
- *
829
- * @returns {*}
830
- * @private
831
- */
832
- Router.prototype._getCurrentSection = function () {
833
- return this.$view.find('.' + routerConfig.curPageClass).eq(0);
834
- };
835
-
836
- /**
837
- * popState 事件关联着的后退处理
838
- *
839
- * 判断两个 state 判断是否是属于同一个文档,然后做对应的 section 或文档切换;
840
- * 同时在切换后把新 state 设为当前 state
841
- *
842
- * @param {State} state 新 state
843
- * @param {State} fromState 旧 state
844
- * @private
845
- */
846
- Router.prototype._back = function (state, fromState) {
847
- // if (this._isTheSameDocument(state.url.full, fromState.url.full)) {
848
- // var $newPage = $('#' + state.pageId);
849
- // if ($newPage.length) {
850
- // var $currentPage = this._getCurrentSection();
851
- // this._animateSection($currentPage, $newPage, DIRECTION.leftToRight);
852
- // this._saveAsCurrentState(state);
853
- // } else {
854
- // // location.href = state.url.full;
855
- // location.href = state.url.base
856
- // }
857
- // } else {
858
- // this._saveDocumentIntoCache($(document), fromState.url.full);
859
- // this._switchToDocument(state.url.full, false, false, DIRECTION.leftToRight);
860
- // this._saveAsCurrentState(state);
861
- // }
862
- var $newPage = $('#' + state.pageId);
863
- if ($newPage.length) {
864
- var $currentPage = this._getCurrentSection();
865
- this._animateSection($currentPage, $newPage, DIRECTION.leftToRight);
866
- this._saveAsCurrentState(state);
867
- } else {
868
- location.href = state.url.full;
869
- //location.href = state.url.base
870
- }
871
- };
872
-
873
- /**
874
- * popState 事件关联着的前进处理,类似于 _back,不同的是切换方向
875
- *
876
- * @param {State} state 新 state
877
- * @param {State} fromState 旧 state
878
- * @private
879
- */
880
- Router.prototype._forward = function (state, fromState) {
881
- if (this._isTheSameDocument(state.url.full, fromState.url.full)) {
882
- var $newPage = $('#' + state.pageId);
883
- if ($newPage.length) {
884
- var $currentPage = this._getCurrentSection();
885
- this._animateSection($currentPage, $newPage, DIRECTION.rightToLeft);
886
- this._saveAsCurrentState(state);
887
- } else {
888
- // location.href = state.url.full;
889
- location.href = state.url.base;
890
- }
891
- } else {
892
- this._saveDocumentIntoCache($(document), fromState.url.full);
893
- this._switchToDocument(state.url.full, false, false, DIRECTION.rightToLeft);
894
- this._saveAsCurrentState(state);
895
- }
896
- };
897
-
898
- /**
899
- * popState 事件处理
900
- *
901
- * 根据 pop 出来的 state 和当前 state 来判断是前进还是后退
902
- *
903
- * @param event popstate事件对象
904
- * @param routerMatch 路由规则,支持通配符
905
- * @private
906
- */
907
- Router.prototype._onPopState = function (event, routerMatch) {
908
- var state = event.state;
909
- // if not a valid state, do nothing
910
- if (!state || !state.pageId) {
911
- return;
912
- }
913
-
914
- var lastState = this._getLastState();
915
-
916
- if (!lastState) {
917
- console.error && console.error('Missing last state when backward or forward');
918
- return;
919
- }
920
-
921
- if (state.id === lastState.id) {
922
- return;
923
- }
924
-
925
- if (state.id < lastState.id) {
926
- this._back(state, lastState);
927
- } else {
928
- this._forward(state, lastState);
929
- }
930
-
931
- // 前进后退都记录当前的hash对应的viewId,用于v-dom查找对应hash的node对象(已修复)
932
- this.hash2ViewId[routerMatch] = state.pageId;
933
-
934
- // 更新当前可见页面的node
935
- // $.setNode(this.vdoms[lastState.url.fragment])
936
- //$.setNode(this.vdoms[Util.getUrlFragment(location.href)])
937
- };
938
-
939
- /**
940
- * 页面进入到一个新状态
941
- *
942
- * 把新状态 push 进去,设置为当前的状态,然后把 maxState 的 id +1。
943
- *
944
- * @param {String} url 新状态的 url
945
- * @param {String} sectionId 新状态中显示的 section 元素的 id
946
- * @private
947
- */
948
- Router.prototype._pushNewState = function (url, sectionId) {
949
- var state = {
950
- id: this._getNextStateId(),
951
- pageId: sectionId,
952
- url: Util.toUrlObject(url)
953
- };
954
- // 存一个标识 让不兼容 history 的 stateChange方法 不会再 pushState 后执行
955
- window.__isPushState = true;
956
- // 不兼容history 的 url(也就是第三个参数) 中不能含有 原来的 # 字符
957
- url = $.device.hasNativeHistory ? url : url.slice(1);
958
- theHistory.pushState(state, '', url);
959
- this._saveAsCurrentState(state);
960
- this._incMaxStateId();
961
- };
962
-
963
- /**
964
- * 生成一个随机的 id
965
- *
966
- * @returns {string}
967
- * @private
968
- */
969
- Router.prototype._generateRandomId = function () {
970
- return "page-" + +new Date();
971
- };
972
-
973
- Router.prototype.dispatch = function (event) {
974
- var e = new CustomEvent(event, {
975
- bubbles: true,
976
- cancelable: true
977
- });
978
-
979
- //noinspection JSUnresolvedFunction
980
- window.dispatchEvent(e);
981
- };
982
-
983
- exports.Router = Router;
984
- exports.Util = Util;
985
- exports.routerConfig = routerConfig;
986
- exports.EVENTS = EVENTS;
987
-
988
- // /**
989
- // * 判断一个链接是否使用 router 来处理
990
- // *
991
- // * @param $link
992
- // * @returns {boolean}
993
- // */
994
- // function isInRouterBlackList($link) {
995
- // var classBlackList = [
996
- // 'external',
997
- // 'tab-link',
998
- // 'open-popup',
999
- // 'close-popup',
1000
- // 'open-panel',
1001
- // 'close-panel'
1002
- // ];
1003
- //
1004
- // for (var i = classBlackList.length -1 ; i >= 0; i--) {
1005
- // if ($link.hasClass(classBlackList[i])) {
1006
- // return true;
1007
- // }
1008
- // }
1009
- //
1010
- // var linkEle = $link.get(0);
1011
- // var linkHref = linkEle.getAttribute('href');
1012
- //
1013
- // var protoWhiteList = [
1014
- // 'http',
1015
- // 'https'
1016
- // ];
1017
- //
1018
- // //如果非noscheme形式的链接,且协议不是http(s),那么路由不会处理这类链接
1019
- // if (/^(\w+):/.test(linkHref) && protoWhiteList.indexOf(RegExp.$1) < 0) {
1020
- // return true;
1021
- // }
1022
- //
1023
- // //noinspection RedundantIfStatementJS
1024
- // if (linkEle.hasAttribute('external')) {
1025
- // return true;
1026
- // }
1027
- //
1028
- // return false;
1029
- // }
1030
-
1031
- // /**
1032
- // * 自定义是否执行路由功能的过滤器
1033
- // *
1034
- // * 可以在外部定义 $.config.routerFilter 函数,实参是点击链接的 Zepto 对象。
1035
- // *
1036
- // * @param $link 当前点击的链接的 Zepto 对象
1037
- // * @returns {boolean} 返回 true 表示执行路由功能,否则不做路由处理
1038
- // */
1039
- // function customClickFilter($link) {
1040
- // // 路由功能开关过滤器,返回 false 表示当前点击链接不使用路由
1041
- // var customRouterFilter = $link => {
1042
- // // 某个区域的 a 链接不想使用路由功能
1043
- // if ($link.is('.disable-router a')) {
1044
- // return false;
1045
- // }
1046
- //
1047
- // return true;
1048
- // };
1049
- // if ($.isFunction(customRouterFilter)) {
1050
- // var filterResult = customRouterFilter($link);
1051
- // if (typeof filterResult === 'boolean') {
1052
- // return filterResult;
1053
- // }
1054
- // }
1055
- //
1056
- // return true;
1057
- // }
1058
-
1059
- // $(function() {
1060
- // // 当前浏览器是否支持sessionStorage特性
1061
- // if (!Util.supportStorage()) {
1062
- // return;
1063
- // }
1064
- //
1065
- // // 页面元素需要定义.page,不然路由模块默认不会生效
1066
- // var $pages = $('.' + routerConfig.pageClass);
1067
- // if (!$pages.length) {
1068
- // var warnMsg = 'Disable router function because of no .page elements';
1069
- // if (window.console && window.console.warn) {
1070
- // console.warn(warnMsg);
1071
- // }
1072
- // return;
1073
- // }
1074
- //
1075
- // // 初始化路由:historyState
1076
- // var router = $.router = new Router();
1077
- //
1078
- // // 为page容器中的a标签注册点击事件
1079
- // $(document).on('click', 'a', function(e) {
1080
- // var $target = $(e.currentTarget);
1081
- //
1082
- // var filterResult = customClickFilter($target);
1083
- // if (!filterResult) {
1084
- // return;
1085
- // }
1086
- //
1087
- // if (isInRouterBlackList($target)) {
1088
- // return;
1089
- // }
1090
- //
1091
- // e.preventDefault();
1092
- //
1093
- // if ($target.hasClass('back')) {
1094
- // router.back();
1095
- // } else {
1096
- // var url = $target.attr('href');
1097
- // if (!url || url === '#') {
1098
- // return;
1099
- // }
1100
- //
1101
- // var ignoreCache = $target.attr('data-no-cache') === 'true';
1102
- //
1103
- // router.load(url, ignoreCache);
1104
- // }
1105
- // });
1106
- // });
1107
-
1108
- /***/ }),
1109
-
1110
- /***/ 58:
1111
- /***/ (function(module, exports, __webpack_require__) {
1112
-
1113
- "use strict";
1114
-
1115
-
1116
- Object.defineProperty(exports, "__esModule", {
1117
- value: true
1118
- });
1119
- /**
1120
- * Created by dfzq on 2017/7/31.
1121
- */
1122
-
1123
- /**
1124
- * 末尾补.0
1125
- * @param num 原始值
1126
- * @param n 位数最大的值
1127
- * @returns {*}
1128
- */
1129
- var padZero = function padZero(num, n) {
1130
- var len = num.split('.').length;
1131
- while (len < n) {
1132
- num = num + '.0';
1133
- len++;
1134
- }
1135
- return num;
1136
- };
1137
-
1138
- /**
1139
- * 获取APP版本号
1140
- * @param _
1141
- * @returns {*}
1142
- */
1143
- var getVersion = function getVersion(_) {
1144
- var groups = navigator.userAgent.toLowerCase().match(/DFYJ\/([\d.]+)/i);
1145
- if (!groups) {
1146
- return undefined;
1147
- } else {
1148
- return groups[1];
1149
- }
1150
- };
1151
-
1152
- /**
1153
- * 比较手机系统版本,arg1 > arg2, return 1; arg1 == arg2, return 0; arg1 < arg2, return -1
1154
- * @param compareVersion
1155
- * @returns {number}
1156
- */
1157
- var _compareVersion = function _compareVersion(a, b) {
1158
- // 补.0操作
1159
- var _as = a.split('.');
1160
- var _bs = b.split('.');
1161
- var max = Math.max(_as.length, _bs.length);
1162
- a = padZero(a, max);
1163
- b = padZero(b, max);
1164
-
1165
- var as = a.split('.');
1166
- var bs = b.split('.');
1167
- if (a === b) return 0;
1168
-
1169
- for (var i = 0; i < as.length; i++) {
1170
- var x = parseInt(as[i]);
1171
- if (!bs[i]) return 1;
1172
- var y = parseInt(bs[i]);
1173
- if (x < y) return -1;
1174
- if (x > y) return 1;
1175
- }
1176
- return -1;
1177
- };
1178
-
1179
- /**
1180
- * 比较APP版本,比compareVersion大则返回1,否则返回-1;相等返回0;
1181
- * @param compareVersion
1182
- * @returns {number}
1183
- */
1184
- var compareVersion = function compareVersion(_compareVersion2) {
1185
- // 获取当前版本号
1186
- var currentVersion = getVersion();
1187
- if (!currentVersion) {
1188
- return 1;
1189
- } else {
1190
- return _compareVersion(currentVersion, _compareVersion2);
1191
- }
1192
- };
1193
-
1194
- exports.getVersion = getVersion;
1195
- exports.compareVersion = compareVersion;
1196
- exports._compareVersion = _compareVersion;
1197
-
1198
- /***/ })
1199
-
1200
- },[235]);
1201
- });
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.fastman=t():e.fastman=t()}(this,function(){return webpackJsonpfastman([7],{150:function(e,t,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=t.getUrlFragment=function(e){var t=e.indexOf("#");return-1===t?"/":e.slice(t+1)},i=t.getAbsoluteUrl=function(e){var t=document.createElement("a");t.setAttribute("href",e);var a=t.href;return t=null,a},o=t.getBaseUrl=function(e){var t=e.indexOf("#");return-1===t?e.slice(0):e.slice(0,t)};t.toUrlObject=function(e){var t=i(e);return{base:o(t),full:t,original:e,fragment:r(e)}},t.supportStorage=function(){var e="ob.router.storage.ability";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(e){return!1}}},235:function(e,t,a){e.exports=a(52)},52:function(e,t,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=a(150),i=a(58);window.CustomEvent||(window.CustomEvent=function(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var a=document.createEvent("CustomEvent");return a.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),a},window.CustomEvent.prototype=window.Event.prototype);var o={pageLoadStart:"pageLoadStart",pageLoadCancel:"pageLoadCancel",pageLoadError:"pageLoadError",pageLoadComplete:"pageLoadComplete",pageAnimationStart:"pageAnimationStart",pageAnimationEnd:"pageAnimationEnd",beforePageRemove:"beforePageRemove",pageRemoved:"pageRemoved",beforePageSwitch:"beforePageSwitch",pageInit:"pageInitInternal"},n={sectionGroupClass:"page-group",curPageClass:"page-current",visiblePageClass:"page-visible",pageClass:"page"},s={leftToRight:"from-left-to-right",rightToLeft:"from-right-to-left"},c=$.device.hasNativeHistory?window.history:History,l=function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))return!1;return!0},u=function(){if($.device.hasNativeHistory)return c.state;var e=c.getState().data;return l(e)?null:e},g=function(){this.sessionNames={currentState:"application.router.currentState",maxStateId:"application.router.maxStateId"},this._init(),this.xhr=null,this.vdoms={},this.hash2ViewId={},this.popstateFlag=!1};g.prototype._init=function(){this.$view=$("body"),this.cache={};var e=$(document),t=location.href;this._saveDocumentIntoCache(e,t);var a,i=(r.toUrlObject(t),e.find("."+n.pageClass)),o=e.find("."+n.curPageClass),s=o.eq(0);if(o.length||(o=i.eq(0)),o.attr("id")||o.attr("id",null==u()?this._generateRandomId():u().pageId),s.length&&s.attr("id")!==o.attr("id")?(s.removeClass(n.curPageClass),o.addClass(n.curPageClass)):o.addClass(n.curPageClass),a=o.attr("id"),null===u()){var l={id:this._getNextStateId(),url:r.toUrlObject(t),pageId:a},g=t;if($.device.hasNativeHistory||(g=l.url.fragment,window.__isReplaceState=!0),!$.device.hasNativeHistory&&/\?&_suid=.+$/.test(t))return;c.replaceState(l,"",g),this._saveAsCurrentState(l),this._incMaxStateId()}},g.prototype.load=function(e,t){this._switchToSection(e)},g.prototype.forward=function(){c.forward()},g.prototype.back=function(){c.back()},g.prototype.loadPage=g.prototype.load,g.prototype._switchToSection=function(e){var t=e.path,a=e.match;if(t){var r,i=this._getCurrentSection();if(r=this.hash2ViewId[a]?$("#"+this.hash2ViewId[a]):this.$view.find("."+n.pageClass).eq(-1),i!==r){this._animateSection(i,r,s.rightToLeft);var o;r.attr("id")?o=r.attr("id"):(o=this._generateRandomId(),r.attr("id",o)),this.hash2ViewId[a]=o,this._pushNewState("#"+t,o)}}},g.prototype._switchToDocument=function(e,t,a,i){var o=r.toUrlObject(e).base;t&&delete this.cache[o];var n=this.cache[o],s=this;n?this._doSwitchDocument(e,a,i):this._loadDocument(e,{success:function(t){try{s._parseDocument(e,t),s._doSwitchDocument(e,a,i)}catch(t){location.href=e}},error:function(){location.href=e}})},g.prototype._doSwitchDocument=function(e,t,a){void 0===t&&(t=!0);var i,s=r.toUrlObject(e),c=this.$view.find("."+n.sectionGroupClass),l=$($("<div></div>").append(this.cache[s.base].$content).html()),u=l.find("."+n.pageClass),g=l.find("."+n.curPageClass);s.fragment&&(i=l.find("#"+s.fragment)),i&&i.length?g=i.eq(0):g.length||(g=u.eq(0)),g.attr("id")||g.attr("id",this._generateRandomId());var p=this._getCurrentSection();p.trigger(o.beforePageSwitch,[p.attr("id"),p]),u.removeClass(n.curPageClass),g.addClass(n.curPageClass),this.$view.prepend(l),this._animateDocument(c,l,g,a),t&&this._pushNewState(e,g.attr("id"))},g.prototype._isTheSameDocument=function(e,t){return r.toUrlObject(e).base===r.toUrlObject(t).base},g.prototype._loadDocument=function(e,t){this.xhr&&this.xhr.readyState<4&&(this.xhr.onreadystatechange=function(){},this.xhr.abort(),this.dispatch(o.pageLoadCancel)),this.dispatch(o.pageLoadStart),t=t||{};var a=this;this.xhr=$.ajax({url:e,success:$.proxy(function(e,a,r){var i=$("<html></html>");i.append(e),t.success&&t.success.call(null,i,a,r)},this),error:function(e,r,i){t.error&&t.error.call(null,e,r,i),a.dispatch(o.pageLoadError)},complete:function(e,r){t.complete&&t.complete.call(null,e,r),a.dispatch(o.pageLoadComplete)}})},g.prototype._parseDocument=function(e,t){if(!t.find("."+n.sectionGroupClass).length)throw new Error("missing router view mark: "+n.sectionGroupClass);this._saveDocumentIntoCache(t,e)},g.prototype._saveDocumentIntoCache=function(e,t){var a=r.toUrlObject(t).base,i=$(e);this.cache[a]={$doc:i,$content:i.find("."+n.sectionGroupClass)}},g.prototype._getLastState=function(){var e=sessionStorage.getItem(this.sessionNames.currentState);try{e=JSON.parse(e)}catch(t){e=null}return e},g.prototype._saveAsCurrentState=function(e){sessionStorage.setItem(this.sessionNames.currentState,JSON.stringify(e))},g.prototype._getNextStateId=function(){var e=sessionStorage.getItem(this.sessionNames.maxStateId);return e?parseInt(e,10)+1:1},g.prototype._incMaxStateId=function(){sessionStorage.setItem(this.sessionNames.maxStateId,this._getNextStateId())},g.prototype._animateDocument=function(e,t,a,r){var i=a.attr("id"),s=e.find("."+n.curPageClass);s.addClass(n.visiblePageClass).removeClass(n.curPageClass),a.trigger(o.pageAnimationStart,[i,a]),this._animateElement(e,t,r),$.device.ie&&Number($.device.ieVersion)<=9?(s.removeClass(n.visiblePageClass),$(window).trigger(o.beforePageRemove,[e]),e.remove(),$(window).trigger(o.pageRemoved),a.trigger(o.pageAnimationEnd,[i,a]),a.trigger(o.pageInit,[i,a])):(e.animationEnd(function(){s.removeClass(n.visiblePageClass),$(window).trigger(o.beforePageRemove,[e]),e.remove(),$(window).trigger(o.pageRemoved)}),t.animationEnd(function(){a.trigger(o.pageAnimationEnd,[i,a]),a.trigger(o.pageInit,[i,a])}))},g.prototype._animateSection=function(e,t,a){var r=t.attr("id");e.isBack=a!==s.rightToLeft,e.trigger(o.beforePageSwitch,[e.attr("id"),e]),t.addClass(n.curPageClass).addClass("page-transiting"),t.isBack=a!==s.rightToLeft,$('[data-toggle="scroller"]').not(".native-scroll").not(".javascript-scroll").scroller({type:"native"}),t.trigger(o.pageAnimationStart,[r,t]),this._animateElement(e,t,a);var i=!0;for(var c in this.hash2ViewId)if(this.hash2ViewId[c]===r){i=!1;break}$.device.ie&&Number($.device.ieVersion)<=9?(e.removeClass(n.curPageClass),t.removeClass("page-transiting"),t.trigger(o.pageAnimationEnd,[r,t]),i&&t.trigger(o.pageInit,[r,t])):t.animationEnd(function(){e.removeClass(n.curPageClass),t.removeClass("page-transiting"),t.trigger(o.pageAnimationEnd,[r,t]),i&&t.trigger(o.pageInit,[r,t])})},g.prototype._animateElement=function(e,t,a){void 0===a&&(a=s.rightToLeft);var r,o,n=["page-from-center-to-left","page-from-center-to-right","page-from-right-to-center","page-from-right-to-center-compatible","page-from-left-to-center"].join(" ");switch(a){case s.rightToLeft:r="page-from-center-to-left",o=$.device.ios&&i._compareVersion($.device.osVersion,"10.0.0")>=0&&i._compareVersion($.device.osVersion,"11.0.0")<0?"page-from-right-to-center-compatible":"page-from-right-to-center";break;case s.leftToRight:r="page-from-center-to-right",o="page-from-left-to-center";break;default:r="page-from-center-to-left",o=$.device.ios&&i._compareVersion($.device.osVersion,"10.0.0")>=0&&i._compareVersion($.device.osVersion,"11.0.0")<0?"page-from-right-to-center-compatible":"page-from-right-to-center"}e.removeClass(n).addClass(r),t.removeClass(n).addClass(o),$.device.ie&&Number($.device.ieVersion)<=9?(e.removeClass(n),t.removeClass(n)):(e.animationEnd(function(){e.removeClass(n)}),t.animationEnd(function(){t.removeClass(n)}))},g.prototype._getCurrentSection=function(){return this.$view.find("."+n.curPageClass).eq(0)},g.prototype._back=function(e,t){var a=$("#"+e.pageId);if(a.length){var r=this._getCurrentSection();this._animateSection(r,a,s.leftToRight),this._saveAsCurrentState(e)}else location.href=e.url.full},g.prototype._forward=function(e,t){if(this._isTheSameDocument(e.url.full,t.url.full)){var a=$("#"+e.pageId);if(a.length){var r=this._getCurrentSection();this._animateSection(r,a,s.rightToLeft),this._saveAsCurrentState(e)}else location.href=e.url.base}else this._saveDocumentIntoCache($(document),t.url.full),this._switchToDocument(e.url.full,!1,!1,s.rightToLeft),this._saveAsCurrentState(e)},g.prototype._onPopState=function(e,t){var a=e.state;if(a&&a.pageId){var r=this._getLastState();if(!r)return void console.error;a.id!==r.id&&(a.id<r.id?this._back(a,r):this._forward(a,r),this.hash2ViewId[t]=a.pageId)}},g.prototype._pushNewState=function(e,t){var a={id:this._getNextStateId(),pageId:t,url:r.toUrlObject(e)};window.__isPushState=!0,e=$.device.hasNativeHistory?e:e.slice(1),c.pushState(a,"",e),this._saveAsCurrentState(a),this._incMaxStateId()},g.prototype._generateRandomId=function(){return"page-"+ +new Date},g.prototype.dispatch=function(e){var t=new CustomEvent(e,{bubbles:!0,cancelable:!0});window.dispatchEvent(t)},t.Router=g,t.Util=r,t.routerConfig=n,t.EVENTS=o},58:function(e,t,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(e,t){for(var a=e.split(".").length;a<t;)e+=".0",a++;return e},i=function(e){var t=navigator.userAgent.toLowerCase().match(/DFYJ\/([\d.]+)/i);return t?t[1]:void 0},o=function(e,t){var a=e.split("."),i=t.split("."),o=Math.max(a.length,i.length);e=r(e,o),t=r(t,o);var n=e.split("."),s=t.split(".");if(e===t)return 0;for(var c=0;c<n.length;c++){var l=parseInt(n[c]);if(!s[c])return 1;var u=parseInt(s[c]);if(l<u)return-1;if(l>u)return 1}return-1},n=function(e){var t=i();return t?o(t,e):1};t.getVersion=i,t.compareVersion=n,t._compareVersion=o}},[235])});