PageRenderTime 61ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/src/SPA/nav/nav.js

https://bitbucket.org/mdavid/aspnetwebstack
JavaScript | 317 lines | 284 code | 30 blank | 3 comment | 83 complexity | d8384fb5e5e752449e5eb89001f0b98f MD5 | raw file
  1. (function() {
  2. /*!
  3. nav.js v0.1 - (c) Microsoft Corporation
  4. */
  5. var readWriteValue;
  6. var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty;
  7. readWriteValue = function(initialValue) {
  8. var currentValue;
  9. currentValue = initialValue;
  10. return function() {
  11. if (arguments.length > 0) currentValue = arguments[0];
  12. return currentValue;
  13. };
  14. };
  15. window.NavHistory = (function() {
  16. function NavHistory(opts) {
  17. this.navigateAll = __bind(this.navigateAll, this);
  18. this.navigate = __bind(this.navigate, this);
  19. this._entriesArray = __bind(this._entriesArray, this);
  20. this.forward = __bind(this.forward, this);
  21. this.back = __bind(this.back, this);
  22. this.loadedData = __bind(this.loadedData, this);
  23. this.params = __bind(this.params, this);
  24. this.current = __bind(this.current, this);
  25. this.relative = __bind(this.relative, this);
  26. this.length = __bind(this.length, this);
  27. var useKo;
  28. this.options = opts || {};
  29. this.options.params = this._extend({}, this.options.params, this._asString);
  30. this.isLinkedToUrl = false;
  31. useKo = 'ko' in this.options ? this.options.ko : (typeof ko !== "undefined" && ko !== null ? ko.observable : void 0) != null;
  32. this.position = useKo ? ko.observable(-1) : readWriteValue(-1);
  33. this.entries = useKo ? ko.observableArray([]) : [];
  34. }
  35. NavHistory.prototype.length = function() {
  36. return this._entriesArray().length;
  37. };
  38. NavHistory.prototype.relative = function(offset) {
  39. return this._entriesArray()[this.position() + offset] || {};
  40. };
  41. NavHistory.prototype.current = function() {
  42. return this.relative(0);
  43. };
  44. NavHistory.prototype.params = function() {
  45. return this.current().params || {};
  46. };
  47. NavHistory.prototype.loadedData = function() {
  48. return this.current().loadedData;
  49. };
  50. NavHistory.prototype.back = function() {
  51. if (this.position() > 0) return this.navigateAll(this.relative(-1).params);
  52. };
  53. NavHistory.prototype.forward = function() {
  54. if (this.position() < this.length() - 1) {
  55. return this.navigateAll(this.relative(1).params);
  56. }
  57. };
  58. NavHistory.prototype._entriesArray = function() {
  59. if (typeof this.entries === 'function') {
  60. return this.entries();
  61. } else {
  62. return this.entries;
  63. }
  64. };
  65. NavHistory.prototype.initialize = function(opts) {
  66. if (opts != null ? opts.linkToUrl : void 0) {
  67. this._linkToUrl();
  68. } else {
  69. this.navigateAll((opts != null ? opts.params : void 0) || {});
  70. }
  71. return this;
  72. };
  73. NavHistory.prototype.navigate = function(newParams, opts) {
  74. var newParamsPlusCurrent;
  75. newParamsPlusCurrent = this._extend(this._extend({}, this.params()), newParams);
  76. return this.navigateAll(newParamsPlusCurrent, opts);
  77. };
  78. NavHistory.prototype.navigateAll = function(newParams, opts) {
  79. var beforeNavigateCallback, isBack, isForward, isNoChange, navEntry, navInfo, threadLoadToken, transition, _ref, _ref2;
  80. var _this = this;
  81. newParams = this._normalizeParams(newParams);
  82. isBack = false;
  83. isForward = false;
  84. isNoChange = false;
  85. transition = opts != null ? opts.transition : void 0;
  86. navEntry = null;
  87. if (this.length() && this._propsAreEqual(newParams, this.params())) {
  88. if (opts != null ? opts.force : void 0) {
  89. isNoChange = true;
  90. navEntry = this.current();
  91. } else {
  92. return;
  93. }
  94. } else if (this._propsAreEqual(newParams, (_ref = this.relative(-1)) != null ? _ref.params : void 0)) {
  95. isBack = true;
  96. transition = transition || this.current().savedTransition;
  97. navEntry = this.relative(-1);
  98. } else if (this._propsAreEqual(newParams, (_ref2 = this.relative(1)) != null ? _ref2.params : void 0)) {
  99. isForward = true;
  100. navEntry = this.relative(1);
  101. transition = transition || this.current().savedTransition;
  102. } else {
  103. navEntry = {
  104. params: newParams,
  105. navEntryId: "navEntry_" + this._getUniqueSequenceValue()
  106. };
  107. }
  108. navInfo = {
  109. isFirst: this.length() === 0,
  110. isBack: isBack,
  111. isForward: isForward,
  112. transition: transition
  113. };
  114. beforeNavigateCallback = function() {
  115. var deleteCount, updatedQueryString;
  116. if (isBack) {
  117. _this.position(_this.position() - 1);
  118. } else if (isForward) {
  119. _this.position(_this.position() + 1);
  120. } else if (!isNoChange) {
  121. deleteCount = _this.length() - _this.position() - 1;
  122. _this.entries().splice(_this.position() + 1, deleteCount, navEntry);
  123. if (_this.options.maxEntries && _this.length() > _this.options.maxEntries) {
  124. _this.entries.shift();
  125. } else {
  126. _this.position(_this.position() + 1);
  127. if (typeof _this.entries.valueHasMutated === 'function') {
  128. _this.entries.valueHasMutated();
  129. }
  130. }
  131. }
  132. if (!isBack && navInfo.transition) {
  133. _this.current().savedTransition = navInfo.transition;
  134. }
  135. if (_this.isLinkedToUrl && ((opts != null ? opts.updateUrl : void 0) !== false) && !isNoChange) {
  136. updatedQueryString = _this._getUpdatedQueryString(_this.params());
  137. window.NavHistory.historyProvider.pushState({
  138. url: updatedQueryString
  139. });
  140. }
  141. if (_this.options.onNavigate) {
  142. return _this.options.onNavigate.call(_this, _this.current(), navInfo);
  143. }
  144. };
  145. if (!this.options.beforeNavigate) {
  146. beforeNavigateCallback();
  147. } else {
  148. threadLoadToken = this.objectLoadToken = {};
  149. this.options.beforeNavigate.call(this, navEntry, navInfo, (function(loadedData) {
  150. if (threadLoadToken === _this.objectLoadToken) {
  151. if (loadedData !== void 0) navEntry.loadedData = loadedData;
  152. return beforeNavigateCallback();
  153. }
  154. }));
  155. }
  156. return this;
  157. };
  158. NavHistory.prototype._asString = function(val) {
  159. if (val === null || val === void 0) {
  160. return "";
  161. } else {
  162. return val.toString();
  163. }
  164. };
  165. NavHistory.prototype._extend = function(target, source, mapFunction) {
  166. var key, value;
  167. for (key in source) {
  168. if (!__hasProp.call(source, key)) continue;
  169. value = source[key];
  170. target[key] = mapFunction ? mapFunction(value) : value;
  171. }
  172. return target;
  173. };
  174. NavHistory.prototype._normalizeParams = function(params) {
  175. var defaults;
  176. defaults = this.options.params || {};
  177. return this._extend(this._extend({}, defaults), params || {}, this._asString);
  178. };
  179. NavHistory.prototype._propsAreEqual = function(obj1, obj2) {
  180. var obj1key, obj1value, obj2key, obj2value;
  181. if (!(obj1 && obj2)) return obj1 === obj2;
  182. for (obj1key in obj1) {
  183. if (!__hasProp.call(obj1, obj1key)) continue;
  184. obj1value = obj1[obj1key];
  185. if (obj2[obj1key] !== obj1value) return false;
  186. }
  187. for (obj2key in obj2) {
  188. if (!__hasProp.call(obj2, obj2key)) continue;
  189. obj2value = obj2[obj2key];
  190. if (obj1[obj2key] !== obj2value) return false;
  191. }
  192. return true;
  193. };
  194. NavHistory.prototype._parseQueryString = function(url) {
  195. var pair, query, result, tokens, _i, _len, _ref;
  196. if (url.indexOf('?') < 0) return {};
  197. query = url.substring(url.lastIndexOf('?') + 1);
  198. result = {};
  199. _ref = query.split("&");
  200. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  201. pair = _ref[_i];
  202. tokens = pair.split("=");
  203. if (tokens.length === 2) result[tokens[0]] = decodeURIComponent(tokens[1]);
  204. }
  205. return result;
  206. };
  207. NavHistory.prototype._formatQueryString = function(params) {
  208. var formattedUrl, key, value;
  209. formattedUrl = '?';
  210. for (key in params) {
  211. if (!__hasProp.call(params, key)) continue;
  212. value = params[key];
  213. if (formattedUrl !== '?') formattedUrl += '&';
  214. formattedUrl += key + '=' + encodeURIComponent(value);
  215. }
  216. return formattedUrl;
  217. };
  218. NavHistory.prototype._getUpdatedQueryString = function(params) {
  219. var allUrlParams, defaultValue, key, suppliedValue, _ref;
  220. allUrlParams = this._parseQueryString(window.NavHistory.historyProvider.getState().url);
  221. _ref = this.options.params;
  222. for (key in _ref) {
  223. if (!__hasProp.call(_ref, key)) continue;
  224. defaultValue = _ref[key];
  225. suppliedValue = params[key];
  226. if (suppliedValue === defaultValue) {
  227. delete allUrlParams[key];
  228. } else {
  229. allUrlParams[key] = suppliedValue;
  230. }
  231. }
  232. return this._formatQueryString(allUrlParams);
  233. };
  234. NavHistory.prototype._getUniqueSequenceValue = function() {
  235. NavHistory._sequence = NavHistory._sequence || 0;
  236. return (NavHistory._sequence++).toString();
  237. };
  238. NavHistory.prototype._linkToUrl = function() {
  239. var onStateChange;
  240. var _this = this;
  241. this.isLinkedToUrl = true;
  242. onStateChange = function() {
  243. var allUrlParams, applicableParams, defaults, key, value;
  244. applicableParams = {};
  245. allUrlParams = _this._parseQueryString(window.NavHistory.historyProvider.getState().url);
  246. defaults = _this.options.params || {};
  247. for (key in allUrlParams) {
  248. if (!__hasProp.call(allUrlParams, key)) continue;
  249. value = allUrlParams[key];
  250. if (defaults.hasOwnProperty(key)) applicableParams[key] = value;
  251. }
  252. return _this.navigateAll(applicableParams, {
  253. updateUrl: false
  254. });
  255. };
  256. onStateChange();
  257. return window.NavHistory.historyProvider.onStateChange(onStateChange);
  258. };
  259. return NavHistory;
  260. })();
  261. window.NavHistory.historyProvider = {
  262. onStateChange: function(handler) {
  263. return History.Adapter.bind(window, 'statechange', handler);
  264. },
  265. pushState: function(data) {
  266. return History.pushState(null, null, data.url);
  267. },
  268. getState: function() {
  269. return History.getState();
  270. },
  271. back: function() {
  272. return History.back();
  273. }
  274. };
  275. window.NavHistory.showPane = function(elementId, navInfo) {
  276. var elemToShow, sibling, _i, _len, _ref;
  277. elemToShow = document.getElementById(elementId);
  278. if (elemToShow) {
  279. _ref = elemToShow.parentNode.childNodes;
  280. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  281. sibling = _ref[_i];
  282. if (sibling.nodeType === 1) sibling.style.display = 'none';
  283. }
  284. return elemToShow.style.display = 'block';
  285. }
  286. };
  287. }).call(this);