a zip code crypto-currency system good for red ONLY

deep-linker.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. import { DIRECTION_BACK, convertToViews, isNav, isTab, isTabs } from './nav-util';
  2. import { isArray, isPresent } from '../util/util';
  3. import { formatUrlPart } from './url-serializer';
  4. import { ViewController } from './view-controller';
  5. /**
  6. * @hidden
  7. */
  8. var DeepLinker = (function () {
  9. function DeepLinker(_app, _serializer, _location, _moduleLoader, _baseCfr) {
  10. this._app = _app;
  11. this._serializer = _serializer;
  12. this._location = _location;
  13. this._moduleLoader = _moduleLoader;
  14. this._baseCfr = _baseCfr;
  15. /** @internal */
  16. this._history = [];
  17. }
  18. /**
  19. * @internal
  20. */
  21. DeepLinker.prototype.init = function () {
  22. var _this = this;
  23. // scenario 1: Initial load of all navs from the initial browser URL
  24. var browserUrl = normalizeUrl(this._location.path());
  25. (void 0) /* console.debug */;
  26. // remember this URL in our internal history stack
  27. this._historyPush(browserUrl);
  28. // listen for browser URL changes
  29. this._location.subscribe(function (locationChg) {
  30. _this._urlChange(normalizeUrl(locationChg.url));
  31. });
  32. };
  33. /**
  34. * The browser's location has been updated somehow.
  35. * @internal
  36. */
  37. DeepLinker.prototype._urlChange = function (browserUrl) {
  38. var _this = this;
  39. // do nothing if this url is the same as the current one
  40. if (!this._isCurrentUrl(browserUrl)) {
  41. var isGoingBack = true;
  42. if (this._isBackUrl(browserUrl)) {
  43. // scenario 2: user clicked the browser back button
  44. // scenario 4: user changed the browser URL to what was the back url was
  45. // scenario 5: user clicked a link href that was the back url
  46. (void 0) /* console.debug */;
  47. this._historyPop();
  48. }
  49. else {
  50. // scenario 3: user click forward button
  51. // scenario 4: user changed browser URL that wasn't the back url
  52. // scenario 5: user clicked a link href that wasn't the back url
  53. isGoingBack = false;
  54. (void 0) /* console.debug */;
  55. this._historyPush(browserUrl);
  56. }
  57. // get the app's root nav container
  58. var activeNavContainers_1 = this._app.getActiveNavContainers();
  59. if (activeNavContainers_1 && activeNavContainers_1.length) {
  60. if (browserUrl === '/') {
  61. // a url change to the index url
  62. if (isPresent(this._indexAliasUrl)) {
  63. // we already know the indexAliasUrl
  64. // update the url to use the know alias
  65. browserUrl = this._indexAliasUrl;
  66. }
  67. else {
  68. // the url change is to the root but we don't
  69. // already know the url used. So let's just
  70. // reset the root nav to its root page
  71. activeNavContainers_1.forEach(function (navContainer) {
  72. navContainer.goToRoot({
  73. updateUrl: false,
  74. isNavRoot: true
  75. });
  76. });
  77. return;
  78. }
  79. }
  80. // normal url
  81. var segments = this.getCurrentSegments(browserUrl);
  82. segments
  83. .map(function (segment) {
  84. // find the matching nav container
  85. for (var _i = 0, activeNavContainers_2 = activeNavContainers_1; _i < activeNavContainers_2.length; _i++) {
  86. var navContainer = activeNavContainers_2[_i];
  87. var nav = getNavFromTree(navContainer, segment.navId);
  88. if (nav) {
  89. return {
  90. segment: segment,
  91. navContainer: nav
  92. };
  93. }
  94. }
  95. })
  96. .filter(function (pair) { return !!pair; })
  97. .forEach(function (pair) {
  98. _this._loadViewForSegment(pair.navContainer, pair.segment, function () { });
  99. });
  100. }
  101. }
  102. };
  103. DeepLinker.prototype.getCurrentSegments = function (browserUrl) {
  104. if (!browserUrl) {
  105. browserUrl = normalizeUrl(this._location.path());
  106. }
  107. return this._serializer.parse(browserUrl);
  108. };
  109. /**
  110. * Update the deep linker using the NavController's current active view.
  111. * @internal
  112. */
  113. DeepLinker.prototype.navChange = function (direction) {
  114. if (direction) {
  115. var activeNavContainers = this._app.getActiveNavContainers();
  116. // the only time you'll ever get a TABS here is when loading directly from a URL
  117. // this method will be called again when the TAB is loaded
  118. // so just don't worry about the TABS for now
  119. // if you encounter a TABS, just return
  120. for (var _i = 0, activeNavContainers_3 = activeNavContainers; _i < activeNavContainers_3.length; _i++) {
  121. var activeNavContainer = activeNavContainers_3[_i];
  122. if (isTabs(activeNavContainer) || activeNavContainer.isTransitioning()) {
  123. return;
  124. }
  125. }
  126. // okay, get the root navs and build the segments up
  127. var segments = [];
  128. var navContainers = this._app.getRootNavs();
  129. for (var _a = 0, navContainers_1 = navContainers; _a < navContainers_1.length; _a++) {
  130. var navContainer = navContainers_1[_a];
  131. var segmentsForNav = this.getSegmentsFromNav(navContainer);
  132. segments = segments.concat(segmentsForNav);
  133. }
  134. segments = segments.filter(function (segment) { return !!segment; });
  135. if (segments.length) {
  136. var browserUrl = this._serializer.serialize(segments);
  137. this._updateLocation(browserUrl, direction);
  138. }
  139. }
  140. };
  141. DeepLinker.prototype.getSegmentsFromNav = function (nav) {
  142. var _this = this;
  143. var segments = [];
  144. if (isNav(nav)) {
  145. segments.push(this.getSegmentFromNav(nav));
  146. }
  147. else if (isTab(nav)) {
  148. segments.push(this.getSegmentFromTab(nav));
  149. }
  150. nav.getActiveChildNavs().forEach(function (child) {
  151. segments = segments.concat(_this.getSegmentsFromNav(child));
  152. });
  153. return segments;
  154. };
  155. DeepLinker.prototype.getSegmentFromNav = function (nav, component, data) {
  156. if (!component) {
  157. var viewController = nav.getActive(true);
  158. if (viewController) {
  159. component = viewController.component;
  160. data = viewController.data;
  161. }
  162. }
  163. return this._serializer.serializeComponent(nav, component, data);
  164. };
  165. DeepLinker.prototype.getSegmentFromTab = function (navContainer, component, data) {
  166. if (navContainer && navContainer.parent) {
  167. var tabsNavContainer = navContainer.parent;
  168. var activeChildNavs = tabsNavContainer.getActiveChildNavs();
  169. if (activeChildNavs && activeChildNavs.length) {
  170. var activeChildNav = activeChildNavs[0];
  171. var viewController = activeChildNav.getActive(true);
  172. if (viewController) {
  173. component = viewController.component;
  174. data = viewController.data;
  175. }
  176. return this._serializer.serializeComponent(tabsNavContainer, component, data);
  177. }
  178. }
  179. };
  180. /**
  181. * @internal
  182. */
  183. DeepLinker.prototype._updateLocation = function (browserUrl, direction) {
  184. if (this._indexAliasUrl === browserUrl) {
  185. browserUrl = '/';
  186. }
  187. if (direction === DIRECTION_BACK && this._isBackUrl(browserUrl)) {
  188. // this URL is exactly the same as the back URL
  189. // it's safe to use the browser's location.back()
  190. (void 0) /* console.debug */;
  191. this._historyPop();
  192. this._location.back();
  193. }
  194. else if (!this._isCurrentUrl(browserUrl)) {
  195. // probably navigating forward
  196. (void 0) /* console.debug */;
  197. this._historyPush(browserUrl);
  198. this._location.go(browserUrl);
  199. }
  200. };
  201. DeepLinker.prototype.getComponentFromName = function (componentName) {
  202. var link = this._serializer.getLinkFromName(componentName);
  203. if (link) {
  204. // cool, we found the right link for this component name
  205. return this.getNavLinkComponent(link);
  206. }
  207. // umm, idk
  208. return Promise.reject("invalid link: " + componentName);
  209. };
  210. DeepLinker.prototype.getNavLinkComponent = function (link) {
  211. if (link.component) {
  212. // sweet, we're already got a component loaded for this link
  213. return Promise.resolve(link.component);
  214. }
  215. if (link.loadChildren) {
  216. // awesome, looks like we'll lazy load this component
  217. // using loadChildren as the URL to request
  218. return this._moduleLoader.load(link.loadChildren).then(function (response) {
  219. link.component = response.component;
  220. return response.component;
  221. });
  222. }
  223. return Promise.reject("invalid link component: " + link.name);
  224. };
  225. /**
  226. * @internal
  227. */
  228. DeepLinker.prototype.resolveComponent = function (component) {
  229. var cfr = this._moduleLoader.getComponentFactoryResolver(component);
  230. if (!cfr) {
  231. cfr = this._baseCfr;
  232. }
  233. return cfr.resolveComponentFactory(component);
  234. };
  235. /**
  236. * @internal
  237. */
  238. DeepLinker.prototype.createUrl = function (navContainer, nameOrComponent, _data, prepareExternalUrl) {
  239. if (prepareExternalUrl === void 0) { prepareExternalUrl = true; }
  240. // create a segment out of just the passed in name
  241. var segment = this._serializer.createSegmentFromName(navContainer, nameOrComponent);
  242. var allSegments = this.getCurrentSegments();
  243. if (segment) {
  244. for (var i = 0; i < allSegments.length; i++) {
  245. if (allSegments[i].navId === navContainer.name || allSegments[i].navId === navContainer.id) {
  246. allSegments[i] = segment;
  247. var url = this._serializer.serialize(allSegments);
  248. return prepareExternalUrl ? this._location.prepareExternalUrl(url) : url;
  249. }
  250. }
  251. }
  252. return '';
  253. };
  254. /**
  255. * Each NavController will call this method when it initializes for
  256. * the first time. This allows each NavController to figure out
  257. * where it lives in the path and load up the correct component.
  258. * @internal
  259. */
  260. DeepLinker.prototype.getSegmentByNavIdOrName = function (navId, name) {
  261. var browserUrl = normalizeUrl(this._location.path());
  262. var segments = this._serializer.parse(browserUrl);
  263. for (var _i = 0, segments_1 = segments; _i < segments_1.length; _i++) {
  264. var segment = segments_1[_i];
  265. if (segment.navId === navId || segment.navId === name) {
  266. return segment;
  267. }
  268. }
  269. return null;
  270. };
  271. /**
  272. * @internal
  273. */
  274. DeepLinker.prototype.initViews = function (segment) {
  275. var _this = this;
  276. var link = this._serializer.getLinkFromName(segment.name);
  277. return this.getNavLinkComponent(link).then(function (component) {
  278. segment.component = component;
  279. var view = new ViewController(component, segment.data);
  280. view.id = segment.id;
  281. if (isArray(segment.defaultHistory)) {
  282. return convertToViews(_this, segment.defaultHistory).then(function (views) {
  283. views.push(view);
  284. return views;
  285. });
  286. }
  287. return [view];
  288. });
  289. };
  290. /**
  291. * @internal
  292. */
  293. DeepLinker.prototype._isBackUrl = function (browserUrl) {
  294. return (browserUrl === this._history[this._history.length - 2]);
  295. };
  296. /**
  297. * @internal
  298. */
  299. DeepLinker.prototype._isCurrentUrl = function (browserUrl) {
  300. return (browserUrl === this._history[this._history.length - 1]);
  301. };
  302. /**
  303. * @internal
  304. */
  305. DeepLinker.prototype._historyPush = function (browserUrl) {
  306. if (!this._isCurrentUrl(browserUrl)) {
  307. this._history.push(browserUrl);
  308. if (this._history.length > 30) {
  309. this._history.shift();
  310. }
  311. }
  312. };
  313. /**
  314. * @internal
  315. */
  316. DeepLinker.prototype._historyPop = function () {
  317. this._history.pop();
  318. if (!this._history.length) {
  319. this._historyPush(this._location.path());
  320. }
  321. };
  322. /**
  323. * @internal
  324. */
  325. DeepLinker.prototype._getTabSelector = function (tab) {
  326. if (isPresent(tab.tabUrlPath)) {
  327. return tab.tabUrlPath;
  328. }
  329. if (isPresent(tab.tabTitle)) {
  330. return formatUrlPart(tab.tabTitle);
  331. }
  332. return "tab-" + tab.index;
  333. };
  334. /**
  335. * Using the known Path of Segments, walk down all descendents
  336. * from the root NavController and load each NavController according
  337. * to each Segment. This is usually called after a browser URL and
  338. * Path changes and needs to update all NavControllers to match
  339. * the new browser URL. Because the URL is already known, it will
  340. * not update the browser's URL when transitions have completed.
  341. *
  342. * @internal
  343. */
  344. DeepLinker.prototype._loadViewForSegment = function (navContainer, segment, done) {
  345. if (!segment) {
  346. return done(false, false);
  347. }
  348. if (isTabs(navContainer) || (isTab(navContainer) && navContainer.parent)) {
  349. var tabs = (isTabs(navContainer) ? navContainer : navContainer.parent);
  350. var selectedIndex = tabs._getSelectedTabIndex(segment.secondaryId);
  351. var tab = tabs.getByIndex(selectedIndex);
  352. tab._segment = segment;
  353. tabs.select(tab, {
  354. updateUrl: false,
  355. animate: false
  356. }, true);
  357. return done(false, false);
  358. }
  359. var navController = navContainer;
  360. var numViews = navController.length() - 1;
  361. // walk backwards to see if the exact view we want to show here
  362. // is already in the stack that we can just pop back to
  363. for (var i = numViews; i >= 0; i--) {
  364. var viewController = navController.getByIndex(i);
  365. if (viewController && (viewController.id === segment.id || viewController.id === segment.name)) {
  366. // hooray! we've already got a view loaded in the stack
  367. // matching the view they wanted to show
  368. if (i === numViews) {
  369. // this is the last view in the stack and it's the same
  370. // as the segment so there's no change needed
  371. return done(false, false);
  372. }
  373. else {
  374. // it's not the exact view as the end
  375. // let's have this nav go back to this exact view
  376. return navController.popTo(viewController, {
  377. animate: false,
  378. updateUrl: false,
  379. }, done);
  380. }
  381. }
  382. }
  383. // ok, so we don't know about a view that they're navigating to
  384. // so we might as well just call setRoot and make tthe view the first view
  385. // this seems like the least bad option
  386. return navController.setRoot(segment.component || segment.name, segment.data, {
  387. id: segment.id, animate: false, updateUrl: false
  388. }, done);
  389. };
  390. return DeepLinker;
  391. }());
  392. export { DeepLinker };
  393. export function setupDeepLinker(app, serializer, location, moduleLoader, cfr) {
  394. var deepLinker = new DeepLinker(app, serializer, location, moduleLoader, cfr);
  395. deepLinker.init();
  396. return deepLinker;
  397. }
  398. export function normalizeUrl(browserUrl) {
  399. browserUrl = browserUrl.trim();
  400. if (browserUrl.charAt(0) !== '/') {
  401. // ensure first char is a /
  402. browserUrl = '/' + browserUrl;
  403. }
  404. if (browserUrl.length > 1 && browserUrl.charAt(browserUrl.length - 1) === '/') {
  405. // ensure last char is not a /
  406. browserUrl = browserUrl.substr(0, browserUrl.length - 1);
  407. }
  408. return browserUrl;
  409. }
  410. export function getNavFromTree(nav, id) {
  411. while (nav) {
  412. if (nav.id === id || nav.name === id) {
  413. return nav;
  414. }
  415. nav = nav.parent;
  416. }
  417. return null;
  418. }
  419. //# sourceMappingURL=deep-linker.js.map