mui.view.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /**
  2. * <div id="app" class="mui-views">
  3. <div class="mui-view">
  4. <div class="mui-navbar">
  5. </div>
  6. <div class="mui-pages">
  7. </div>
  8. </div>
  9. </div>
  10. * @param {Object} $
  11. * @param {Object} window
  12. */
  13. (function($, window) {
  14. var CLASS_LEFT = $.className('left');
  15. var CLASS_CENTER = $.className('center');
  16. var CLASS_RIGHT = $.className('right');
  17. var CLASS_PAGE = $.className('page');
  18. var CLASS_PAGE_LEFT = $.className('page-left');
  19. var CLASS_PAGE_CENTER = $.className('page-center');
  20. var CLASS_NAVBAR_LEFT = $.className('navbar-left');
  21. var CLASS_NAVBAR_CENTER = $.className('navbar-center');
  22. var CLASS_PAGE_SHADOW = $.className('page-shadow');
  23. var CLASS_TRANSITIONING = $.className('transitioning');
  24. var SELECTOR_LEFT = '.' + CLASS_LEFT;
  25. var SELECTOR_CENTER = '.' + CLASS_CENTER;
  26. var SELECTOR_RIGHT = '.' + CLASS_RIGHT;
  27. var SELECTOR_ICON = $.classSelector('.icon');
  28. var SELECTOR_NAVBAR = $.classSelector('.navbar');
  29. var SELECTOR_NAVBAR_INNER = $.classSelector('.navbar-inner');
  30. var SELECTOR_PAGES = $.classSelector('.pages');
  31. var SELECTOR_BTN_NAV = $.classSelector('.btn-nav');
  32. var SELECTOR_PAGE_LEFT = '.' + CLASS_PAGE_LEFT;
  33. var SELECTOR_PAGE_CENTER = '.' + CLASS_PAGE_CENTER;
  34. var SELECTOR_NAVBAR_LEFT = '.' + CLASS_NAVBAR_LEFT;
  35. var SELECTOR_NAVBAR_CENTER = '.' + CLASS_NAVBAR_CENTER;
  36. var View = $.Class.extend({
  37. init: function(element, options) {
  38. this.view = this.element = element;
  39. this.options = $.extend({
  40. animateNavbar: 'ios', //ios
  41. swipeBackPageActiveArea: 30,
  42. hardwareAccelerated: true
  43. }, options);
  44. this.navbars = this.view.querySelector(SELECTOR_NAVBAR);
  45. this.pages = this.view.querySelector(SELECTOR_PAGES);
  46. this.history = []; //history
  47. this.maxScrollX = this.view.offsetWidth;
  48. this.x = this.y = 0;
  49. this.translateZ = this.options.hardwareAccelerated ? ' translateZ(0)' : '';
  50. this.ratio = 0;
  51. this.isBack = true;
  52. this.moved = this.dragging = false;
  53. this.activeNavbar = this.previousNavbar = null;
  54. this.activePage = this.previousPage = null;
  55. this._initPageEventMethod();
  56. this._initDefaultPage();
  57. this.navbars && this._initNavBar();
  58. this.initEvent();
  59. },
  60. _initPageEventMethod: function() {
  61. var self = this;
  62. $.each(['onPageBeforeShow', 'onPageShow', 'onPageBeforeBack', 'onPageBack'], function(index, event) {
  63. self[event + 'Callbacks'] = {};
  64. self[event] = function(page, callback) {
  65. var eventCallbacks = event + 'Callbacks';
  66. if (!self[eventCallbacks].hasOwnProperty(page)) {
  67. self[eventCallbacks][page] = [callback];
  68. } else {
  69. self[eventCallbacks][page].push(callback);
  70. }
  71. };
  72. });
  73. },
  74. _initDefaultPage: function() {
  75. var defaultPage = document.querySelector(this.options.defaultPage);
  76. if (defaultPage) {
  77. this._appendPage(defaultPage);
  78. } else {
  79. throw new Error('defaultPage[' + this.options.defaultPage + '] does not exist');
  80. }
  81. },
  82. initEvent: function() {
  83. this.view.addEventListener('click', this);
  84. this.view.addEventListener('tap', this);
  85. this.pages.addEventListener('drag', this);
  86. this.pages.addEventListener('dragend', this);
  87. this.pages.addEventListener('webkitTransitionEnd', this);
  88. },
  89. handleEvent: function(event) {
  90. switch (event.type) {
  91. case 'click':
  92. this._click(event);
  93. break;
  94. case 'tap':
  95. this._tap(event);
  96. break;
  97. case 'drag':
  98. this._drag(event);
  99. break;
  100. case 'dragend':
  101. this._dragend(event);
  102. break;
  103. case 'webkitTransitionEnd':
  104. this._webkitTransitionEnd(event);
  105. break;
  106. }
  107. },
  108. shadow: function() {
  109. var shadow = document.createElement('div');
  110. shadow.className = CLASS_PAGE_SHADOW;
  111. return shadow;
  112. }(),
  113. _removePage: function(page, navbar) {
  114. navbar && this._removeNavbar(page, navbar);
  115. document.body.appendChild(page);
  116. this._cleanPageClass(page);
  117. },
  118. _prependPage: function(page) {
  119. var navbar = page.querySelector(SELECTOR_NAVBAR_INNER);
  120. navbar && this._prependNavbar(navbar);
  121. page.classList.add(CLASS_PAGE_LEFT);
  122. this.pages.insertBefore(page, this.pages.firstElementChild);
  123. },
  124. _appendPage: function(page) {
  125. var navbar = page.querySelector(SELECTOR_NAVBAR_INNER);
  126. navbar && this._appendNavbar(navbar);
  127. page.classList.add(CLASS_PAGE_CENTER);
  128. this.pages.appendChild(page);
  129. },
  130. _removeNavbar: function(page, navbar) {
  131. page.insertBefore(navbar, page.firstElementChild);
  132. this._cleanNavbarClass(navbar);
  133. },
  134. _prependNavbar: function(navbar) {
  135. navbar.classList.add(CLASS_NAVBAR_LEFT);
  136. this.navbars.insertBefore(navbar, this.navbars.firstElementChild);
  137. },
  138. _appendNavbar: function(navbar) {
  139. navbar.classList.add(CLASS_NAVBAR_CENTER);
  140. this.navbars.appendChild(navbar);
  141. },
  142. _cleanPageClass: function(page) {
  143. page.classList.remove(CLASS_PAGE_CENTER);
  144. page.classList.remove(CLASS_PAGE_LEFT);
  145. },
  146. _cleanNavbarClass: function(navbar) {
  147. navbar.classList.remove(CLASS_NAVBAR_CENTER);
  148. navbar.classList.remove(CLASS_NAVBAR_LEFT);
  149. },
  150. _tap: function(event) {
  151. var target = event.target;
  152. for (; target && target !== document; target = target.parentNode) {
  153. if (target.tagName === 'A' && target.hash) {
  154. var page = document.getElementById(target.hash.replace('#', ''));
  155. if (page && page.classList.contains(CLASS_PAGE)) {
  156. event.stopPropagation();
  157. event.detail.gesture.preventDefault();
  158. this.go(target.hash);
  159. break;
  160. }
  161. }
  162. }
  163. },
  164. _click: function(event) {
  165. var target = event.target;
  166. for (; target && target !== document; target = target.parentNode) {
  167. if (target.tagName === 'A' && target.hash) {
  168. var page = document.getElementById(target.hash.replace('#', ''));
  169. if (page && page.classList.contains(CLASS_PAGE)) {
  170. event.preventDefault();
  171. break;
  172. }
  173. }
  174. }
  175. },
  176. _cleanStyle: function(el) {
  177. if (el) {
  178. el.style.webkitTransform = '';
  179. el.style.opacity = '';
  180. }
  181. },
  182. _isAnimateNavbarIOS: function() {
  183. return !$.os.android && this.options.animateNavbar === 'ios';
  184. },
  185. _webkitTransitionEnd: function(event) {
  186. this.dragging = this.moved = false;
  187. if (this.activePage !== event.target) {
  188. return;
  189. }
  190. this.isInTransition = false;
  191. this.shadow.parentNode === this.activePage && this.activePage.removeChild(this.shadow);
  192. this.previousPageClassList.remove(CLASS_TRANSITIONING);
  193. this.activePageClassList.remove(CLASS_TRANSITIONING);
  194. var self = this;
  195. if (this._isAnimateNavbarIOS() && this.previousNavElements && this.activeNavElements) {
  196. var isBack = this.isBack;
  197. $.each(this.previousNavElements, function(i, el) {
  198. el.classList.remove(CLASS_TRANSITIONING);
  199. isBack && self._cleanStyle(el);
  200. });
  201. $.each(this.activeNavElements, function(i, el) {
  202. el.classList.remove(CLASS_TRANSITIONING);
  203. self._cleanStyle(el);
  204. });
  205. if (this.previousNavBackIcon) {
  206. this.previousNavBackIcon.classList.remove(CLASS_TRANSITIONING);
  207. isBack && this._cleanStyle(this.previousNavBackIcon);
  208. }
  209. if (this.activeNavBackIcon) {
  210. this.activeNavBackIcon.classList.remove(CLASS_TRANSITIONING);
  211. this._cleanStyle(this.activeNavBackIcon);
  212. }
  213. } else {
  214. this.previousNavbar && this.previousNavbar.classList.remove(CLASS_TRANSITIONING);
  215. this.activeNavbar && this.activeNavbar.classList.remove(CLASS_TRANSITIONING);
  216. this._cleanStyle(this.previousNavbar);
  217. this._cleanStyle(this.activeNavbar);
  218. }
  219. this._cleanStyle(this.previousPage);
  220. this._cleanStyle(this.activePage);
  221. if (this.ratio <= 0.5) {
  222. return;
  223. }
  224. if (this.isBack) {
  225. this._removePage(this.activePage, this.activeNavbar);
  226. this.previousPageClassList.remove(CLASS_PAGE_LEFT);
  227. this.previousPageClassList.add(CLASS_PAGE_CENTER);
  228. if (this.previousNavbar) {
  229. this.previousNavbar.classList.remove(CLASS_NAVBAR_LEFT);
  230. this.previousNavbar.classList.add(CLASS_NAVBAR_CENTER);
  231. }
  232. if (this.history.length > 0) {
  233. this._prependPage(this.history.pop());
  234. }
  235. this.navbars && this._initNavBar();
  236. this._trigger('pageBack', this.activePage);
  237. this._trigger('pageShow', this.previousPage);
  238. } else {
  239. this.previousPageClassList.add(CLASS_PAGE_LEFT);
  240. this.activePageClassList.add(CLASS_PAGE_CENTER);
  241. this._trigger('pageShow', this.activePage);
  242. }
  243. },
  244. _trigger: function(eventType, page) {
  245. var eventCallbacks = 'on' + eventType.charAt(0).toUpperCase() + eventType.slice(1) + 'Callbacks';
  246. if (this[eventCallbacks].hasOwnProperty(page.id)) {
  247. var callbacks = this[eventCallbacks][page.id];
  248. var event = new CustomEvent(eventType, {
  249. detail: {
  250. page: page
  251. },
  252. bubbles: true,
  253. cancelable: true
  254. });
  255. for (var len = callbacks.length; len--;) {
  256. callbacks[len].call(this, event);
  257. }
  258. }
  259. $.trigger(this.view, eventType, {
  260. page: page
  261. });
  262. },
  263. _initPageTransform: function() {
  264. this.previousPage = this.pages.querySelector(SELECTOR_PAGE_LEFT);
  265. this.activePage = this.pages.querySelector(SELECTOR_PAGE_CENTER);
  266. if (this.previousPage && this.activePage) {
  267. this.activePage.appendChild(this.shadow);
  268. this.previousPageClassList = this.previousPage.classList;
  269. this.activePageClassList = this.activePage.classList;
  270. this.previousPageStyle = this.previousPage.style;
  271. this.activePageStyle = this.activePage.style;
  272. this.previousPageClassList.remove(CLASS_TRANSITIONING);
  273. this.activePageClassList.remove(CLASS_TRANSITIONING);
  274. if (this.navbars) {
  275. this.previousNavbar = this.navbars.querySelector(SELECTOR_NAVBAR_LEFT);
  276. this.activeNavbar = this.navbars.querySelector(SELECTOR_NAVBAR_CENTER);
  277. if (this._isAnimateNavbarIOS() && this.previousNavbar && this.activeNavbar) {
  278. this.previousNavElements = this.previousNavbar.querySelectorAll(SELECTOR_LEFT + ',' + SELECTOR_CENTER + ',' + SELECTOR_RIGHT);
  279. this.activeNavElements = this.activeNavbar.querySelectorAll(SELECTOR_LEFT + ',' + SELECTOR_CENTER + ',' + SELECTOR_RIGHT);
  280. this.previousNavBackIcon = this.previousNavbar.querySelector(SELECTOR_LEFT + SELECTOR_BTN_NAV + ' ' + SELECTOR_ICON);
  281. this.activeNavBackIcon = this.activeNavbar.querySelector(SELECTOR_LEFT + SELECTOR_BTN_NAV + ' ' + SELECTOR_ICON);
  282. }
  283. }
  284. this.x = 0;
  285. this.dragging = true;
  286. return true;
  287. }
  288. return false;
  289. },
  290. _initNavBar: function() {
  291. if (this._isAnimateNavbarIOS() && this.navbars) {
  292. var inners = this.navbars.querySelectorAll(SELECTOR_NAVBAR_INNER);
  293. var inner, left, right, center, leftWidth, rightWidth, centerWidth, noLeft, onRight, currLeft, diff, navbarWidth;
  294. for (var i = 0, len = inners.length; i < len; i++) {
  295. inner = inners[i];
  296. left = inner.querySelector(SELECTOR_LEFT);
  297. right = inner.querySelector(SELECTOR_RIGHT);
  298. center = inner.querySelector(SELECTOR_CENTER);
  299. noLeft = !left;
  300. noRight = !right;
  301. leftWidth = noLeft ? 0 : left.offsetWidth;
  302. rightWidth = noRight ? 0 : right.offsetWidth;
  303. centerWidth = center ? center.offsetWidth : 0;
  304. navbarWidth = this.maxScrollX;
  305. onLeft = inner.classList.contains('navbar-left');
  306. if (noRight) {
  307. currLeft = navbarWidth - centerWidth;
  308. }
  309. if (noLeft) {
  310. currLeft = 0;
  311. }
  312. if (!noLeft && !noRight) {
  313. currLeft = (navbarWidth - rightWidth - centerWidth + leftWidth) / 2;
  314. }
  315. var requiredLeft = (navbarWidth - centerWidth) / 2;
  316. if (navbarWidth - leftWidth - rightWidth > centerWidth) {
  317. if (requiredLeft < leftWidth) {
  318. requiredLeft = leftWidth;
  319. }
  320. if (requiredLeft + centerWidth > navbarWidth - rightWidth) {
  321. requiredLeft = navbarWidth - rightWidth - centerWidth;
  322. }
  323. diff = requiredLeft - currLeft;
  324. } else {
  325. diff = 0;
  326. }
  327. var centerLeft = diff;
  328. if (center) {
  329. center.style.marginLeft = -leftWidth + 'px';
  330. center.mNavbarLeftOffset = -(currLeft + diff) + 30; //这个30是测出来的。后续要实际计算一下
  331. center.mNavbarRightOffset = navbarWidth - currLeft - diff - centerWidth;
  332. }
  333. if (onLeft) center.style.webkitTransform = ('translate3d(' + center.mNavbarLeftOffset + 'px, 0, 0)');
  334. if (!noLeft) {
  335. left.mNavbarLeftOffset = -leftWidth;
  336. left.mNavbarRightOffset = (navbarWidth - leftWidth) / 2;
  337. if (onLeft) left.style.webkitTransform = ('translate3d(' + left[0].mNavbarLeftOffset + 'px, 0, 0)');
  338. }
  339. if (!noRight) {
  340. right.mNavbarLeftOffset = -(navbarWidth - rightWidth) / 2;
  341. right.mNavbarRightOffset = rightWidth;
  342. if (onLeft) right.style.webkitTransform = ('translate3d(' + right[0].mNavbarLeftOffset + 'px, 0, 0)');
  343. }
  344. }
  345. }
  346. },
  347. _drag: function(event) {
  348. if (this.isInTransition) {
  349. return;
  350. }
  351. var detail = event.detail;
  352. if (!this.dragging) {
  353. if (($.gestures.session.firstTouch.center.x - this.view.offsetLeft) < this.options.swipeBackPageActiveArea) {
  354. this.isBack = true;
  355. this._initPageTransform();
  356. }
  357. }
  358. if (this.dragging) {
  359. var deltaX = 0;
  360. if (!this.moved) { //start
  361. deltaX = detail.deltaX;
  362. $.gestures.session.lockDirection = true; //锁定方向
  363. $.gestures.session.startDirection = detail.direction;
  364. } else { //move
  365. deltaX = detail.deltaX - ($.gestures.session.prevTouch && $.gestures.session.prevTouch.deltaX || 0);
  366. }
  367. var newX = this.x + deltaX;
  368. if (newX < 0 || newX > this.maxScrollX) {
  369. newX = newX < 0 ? 0 : this.maxScrollX;
  370. }
  371. event.stopPropagation();
  372. detail.gesture.preventDefault();
  373. if (!this.requestAnimationFrame) {
  374. this._updateTranslate();
  375. }
  376. this.moved = true;
  377. this.x = newX;
  378. this.y = 0;
  379. }
  380. },
  381. _dragend: function(event) {
  382. if (!this.moved) {
  383. return;
  384. }
  385. event.stopPropagation();
  386. var detail = event.detail;
  387. this._clearRequestAnimationFrame();
  388. this._prepareTransition();
  389. this.ratio = this.x / this.maxScrollX;
  390. if (this.ratio === 1 || this.ratio === 0) {
  391. $.trigger(this.activePage, 'webkitTransitionEnd');
  392. return;
  393. }
  394. if (this.ratio > 0.5) {
  395. this.setTranslate(this.maxScrollX, 0);
  396. } else {
  397. this._cleanStyle(this.previousPage);
  398. this._cleanStyle(this.activePage);
  399. }
  400. },
  401. _prepareTransition: function() {
  402. this.isInTransition = true;
  403. this.previousPageClassList.add(CLASS_TRANSITIONING);
  404. this.activePageClassList.add(CLASS_TRANSITIONING);
  405. var self = this;
  406. if (this.previousNavbar && this.activeNavbar) {
  407. this.previousNavbar.classList.add(CLASS_TRANSITIONING);
  408. this.activeNavbar.classList.add(CLASS_TRANSITIONING);
  409. if (this._isAnimateNavbarIOS() && this.previousNavElements && this.activeNavElements) {
  410. $.each(this.previousNavElements, function(i, el) {
  411. el.classList.add(CLASS_TRANSITIONING);
  412. self._cleanStyle(el);
  413. });
  414. $.each(this.activeNavElements, function(i, el) {
  415. el.classList.add(CLASS_TRANSITIONING);
  416. self._cleanStyle(el);
  417. });
  418. if (this.previousNavBackIcon) {
  419. this._cleanStyle(this.previousNavBackIcon);
  420. this.previousNavBackIcon.classList.add(CLASS_TRANSITIONING);
  421. }
  422. if (this.activeNavBackIcon) {
  423. this._cleanStyle(this.activeNavBackIcon);
  424. this.activeNavBackIcon.classList.add(CLASS_TRANSITIONING);
  425. }
  426. }
  427. }
  428. },
  429. _clearRequestAnimationFrame: function() {
  430. if (this.requestAnimationFrame) {
  431. cancelAnimationFrame(this.requestAnimationFrame);
  432. this.requestAnimationFrame = null;
  433. }
  434. },
  435. _getTranslateStr: function(x, y) {
  436. if (this.options.hardwareAccelerated) {
  437. return 'translate3d(' + x + 'px,' + y + 'px,0px) ' + this.translateZ;
  438. }
  439. return 'translate(' + x + 'px,' + y + 'px) ';
  440. },
  441. _updateTranslate: function() {
  442. var self = this;
  443. if (self.x !== self.lastX || self.y !== self.lastY) {
  444. self.setTranslate(self.x, self.y);
  445. }
  446. self.requestAnimationFrame = requestAnimationFrame(function() {
  447. self._updateTranslate();
  448. });
  449. },
  450. _setNavbarTranslate: function(x, y) {
  451. var percentage = x / this.maxScrollX;
  452. //only for ios
  453. if (this._isAnimateNavbarIOS()) {
  454. if (this.previousNavElements && this.activeNavElements) {
  455. this.animateNavbarByIOS(percentage);
  456. }
  457. } else { //pop-in
  458. this.activeNavbar.style.opacity = 1 - percentage * 1.3;
  459. this.previousNavbar.style.opacity = percentage * 1.3 - 0.3;
  460. }
  461. },
  462. animateNavbarByIOS: function(percentage) {
  463. var i, len, style, el;
  464. for (i = 0, len = this.activeNavElements.length; i < len; i++) {
  465. el = this.activeNavElements[i];
  466. style = el.style;
  467. style.opacity = (1 - percentage * (el.classList.contains(CLASS_LEFT) ? 3.5 : 1.3));
  468. if (!el.classList.contains(CLASS_RIGHT)) {
  469. var activeNavTranslate = percentage * el.mNavbarRightOffset;
  470. el.style.webkitTransform = ('translate3d(' + activeNavTranslate + 'px,0,0)');
  471. if (el.classList.contains(CLASS_LEFT) && this.activeNavBackIcon) {
  472. this.activeNavBackIcon.style.webkitTransform = ('translate3d(' + -activeNavTranslate + 'px,0,0)');
  473. }
  474. }
  475. }
  476. for (i = 0, len = this.previousNavElements.length; i < len; i++) {
  477. el = this.previousNavElements[i];
  478. style = el.style;
  479. style.opacity = percentage * 1.3 - 0.3;
  480. if (!el.classList.contains(CLASS_RIGHT)) {
  481. var previousNavTranslate = el.mNavbarLeftOffset * (1 - percentage);
  482. el.style.webkitTransform = ('translate3d(' + previousNavTranslate + 'px,0,0)');
  483. if (el.classList.contains(CLASS_LEFT) && this.previousNavBackIcon) {
  484. this.previousNavBackIcon.style.webkitTransform = ('translate3d(' + -previousNavTranslate + 'px,0,0)');
  485. }
  486. }
  487. }
  488. },
  489. setTranslate: function(x, y) {
  490. this.x = x;
  491. this.y = y;
  492. this.previousPage.style.opacity = 0.9 + 0.1 * x / this.maxScrollX;
  493. this.previousPage.style['webkitTransform'] = this._getTranslateStr((x / 6 - this.maxScrollX / 6), y);
  494. this.activePage.style['webkitTransform'] = this._getTranslateStr(x, y);
  495. this.navbars && this._setNavbarTranslate(x, y);
  496. this.lastX = this.x;
  497. this.lastY = this.y;
  498. },
  499. canBack: function() {
  500. return this.pages.querySelector(SELECTOR_PAGE_LEFT);
  501. },
  502. back: function() {
  503. if (this.isInTransition) {
  504. return;
  505. }
  506. this.isBack = true;
  507. this.ratio = 1;
  508. if (this._initPageTransform()) {
  509. this._trigger('pageBeforeBack', this.activePage);
  510. this._trigger('pageBeforeShow', this.previousPage);
  511. this._prepareTransition();
  512. this.previousPage.offsetHeight;
  513. this.activePage.offsetHeight;
  514. this.setTranslate(this.maxScrollX, 0);
  515. }
  516. },
  517. go: function(pageSelector) {
  518. if (this.isInTransition) {
  519. return;
  520. }
  521. var nextPage = document.querySelector(pageSelector);
  522. if (nextPage) {
  523. var previousPage = this.pages.querySelector(SELECTOR_PAGE_LEFT);
  524. var activePage = this.pages.querySelector(SELECTOR_PAGE_CENTER);
  525. var previousNavbar;
  526. var activeNavbar;
  527. if (this.navbars) {
  528. previousNavbar = this.navbars.querySelector(SELECTOR_NAVBAR_LEFT);
  529. activeNavbar = this.navbars.querySelector(SELECTOR_NAVBAR_CENTER);
  530. }
  531. if (activeNavbar) {
  532. activeNavbar.classList.remove(CLASS_NAVBAR_CENTER);
  533. activeNavbar.classList.add(CLASS_NAVBAR_LEFT);
  534. }
  535. if (previousPage) {
  536. this._removePage(previousPage, previousNavbar);
  537. this.history.push(previousPage); //add to history
  538. }
  539. if (activePage) {
  540. activePage.classList.remove(CLASS_PAGE_CENTER);
  541. activePage.style.webkitTransform = 'translate3d(0,0,0)';
  542. activePage.classList.add(CLASS_PAGE_LEFT);
  543. }
  544. nextPage.style.webkitTransform = 'translate3d(100%,0,0)';
  545. this._appendPage(nextPage);
  546. nextPage.appendChild(this.shadow); //shadow
  547. nextPage.offsetHeight; //force
  548. this.isBack = false;
  549. this.ratio = 1;
  550. this._initPageTransform();
  551. this.navbars && this._initNavBar();
  552. this.navbars && this._setNavbarTranslate(this.maxScrollX, 0);
  553. //force
  554. this.previousPage.offsetHeight;
  555. this.activePage.offsetHeight;
  556. if (this.navbars) {
  557. this.previousNavbar.offsetHeight;
  558. this.activeNavbar.offsetHeight;
  559. }
  560. this._trigger('pageBeforeShow', this.activePage);
  561. this._prepareTransition();
  562. this.setTranslate(0, 0);
  563. }
  564. }
  565. });
  566. $.fn.view = function(options) {
  567. var self = this[0];
  568. var viewApi = null;
  569. var id = self.getAttribute('data-view');
  570. if (!id) {
  571. id = ++$.uuid;
  572. $.data[id] = viewApi = new View(self, options);
  573. self.setAttribute('data-view', id);
  574. } else {
  575. viewApi = $.data[id];
  576. }
  577. return viewApi;
  578. }
  579. })(mui, window);