url_monitor.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; -*-
  2. // vim:set ft=javascript ts=2 sw=2 sts=2 cindent:
  3. var URLMonitor = (function($, window, undefined) {
  4. var URLMonitor = function(dispatcher) {
  5. var that = this;
  6. var reloadData = true;
  7. var changed = false;
  8. var newIntArgs = {};
  9. that.url_hash = new URLHash();
  10. // Thanks to:
  11. // http://kilianvalkhof.com/2010/javascript/the-case-of-the-disappearing-favicon/
  12. var setFavicon = function() {
  13. var link = $('link[type="image/x-icon"]').remove().attr("href");
  14. $('<link href="'+ link +'" rel="shortcut icon" type="image/x-icon" />').appendTo('head');
  15. }
  16. var updateURL = function() {
  17. var new_hash = that.url_hash.getHash();
  18. changed = false;
  19. window.location.hash = new_hash;
  20. setFavicon();
  21. dispatcher.post('hideForm');
  22. };
  23. var setArguments = function(args, force) {
  24. var oldArgs = that.url_hash.arguments;
  25. var argSplit = URLHash.splitArgs(args);
  26. if (!Util.isEqual(that.url_hash.extArguments, argSplit[1])) {
  27. changed = true;
  28. that.url_hash.setArguments(args);
  29. dispatcher.post('argsChanged', [args, oldArgs]);
  30. }
  31. if (changed) {
  32. // hashchange event will trigger
  33. newIntArgs = argSplit[0];
  34. updateURL();
  35. } else if (force || !Util.isEqual(that.url_hash.intArguments, argSplit[0])) {
  36. // hash is same, but internal arguments differ
  37. that.url_hash.setArguments(args);
  38. // hashchange event won't trigger, but internal args have
  39. // changed, so we have to do updateState's job
  40. dispatcher.post('hideForm');
  41. dispatcher.post('argsChanged', [args, oldArgs]);
  42. dispatcher.post('current', [that.url_hash.collection,
  43. that.url_hash.document, that.url_hash.arguments, reloadData]);
  44. reloadData = true;
  45. }
  46. };
  47. var setDocument = function(doc, args) {
  48. var oldDoc = that.url_hash.document;
  49. if (oldDoc !== doc) {
  50. changed = true;
  51. that.url_hash.setDocument(doc);
  52. dispatcher.post('docChanged', [doc, oldDoc]);
  53. }
  54. setArguments(args || null);
  55. dispatcher.post('getChangedOfDocument',[doc]);
  56. };
  57. var setCollection = function(coll, doc, args) {
  58. var oldColl = that.url_hash.collection;
  59. if (oldColl !== coll) {
  60. changed = true;
  61. that.url_hash.setCollection(coll);
  62. // keep "blind" down while loading new collection
  63. $('#waiter').dialog('open');
  64. dispatcher.post('ajax', [{
  65. action: 'getCollectionInformation',
  66. collection: coll
  67. }, 'collectionLoaded', {
  68. collection: coll,
  69. keep: true
  70. }]);
  71. dispatcher.post('collectionChanged', [coll, oldColl]);
  72. }
  73. setDocument(doc || '', args);
  74. }
  75. var updateState = function() {
  76. dispatcher.post('makeAjaxObsolete');
  77. if (!changed) {
  78. var new_url_hash = URLHash.parse(window.location.hash);
  79. setCollection(new_url_hash.collection, new_url_hash.document,
  80. $.extend(new_url_hash.arguments, newIntArgs));
  81. that.url_hash = new_url_hash;
  82. newIntArgs = {};
  83. }
  84. dispatcher.post('current', [that.url_hash.collection,
  85. that.url_hash.document, that.url_hash.arguments, reloadData]);
  86. reloadData = true;
  87. };
  88. var forceUpdate = function() {
  89. $(window).trigger('hashchange');
  90. };
  91. var preventReloadByURL = function() {
  92. reloadData = false;
  93. }
  94. var allowReloadByURL = function() {
  95. reloadData = true;
  96. }
  97. var init = function() {
  98. $(window).bind('hashchange', updateState);
  99. forceUpdate();
  100. }
  101. dispatcher.
  102. on('forceUpdate', forceUpdate).
  103. on('setArguments', setArguments).
  104. on('setDocument', setDocument).
  105. on('setCollection', setCollection).
  106. on('preventReloadByURL', preventReloadByURL).
  107. on('allowReloadByURL', allowReloadByURL).
  108. on('init', init);
  109. };
  110. return URLMonitor;
  111. })(jQuery, window);
  112. var URLHash = (function($, window, undefined) {
  113. var URLHash = function(collection, _document, _arguments) {
  114. var that = this;
  115. that.collection = collection;
  116. that.document = _document || '';
  117. that.arguments = _arguments || {};
  118. that.calcArgs();
  119. }
  120. URLHash.prototype = {
  121. calcArgs: function() {
  122. var args = URLHash.splitArgs(this.arguments);
  123. this.intArguments = args[0];
  124. this.extArguments = args[1];
  125. },
  126. setArgument: function(argument, value) {
  127. if (!this.arguments) {
  128. this.arguments = {};
  129. }
  130. this.arguments[argument] = value;
  131. this.calcArgs();
  132. return this;
  133. },
  134. setArguments: function(_arguments) {
  135. // the $.extend here basically takes a copy; raw assignment
  136. // would allow changes of the args to alter original, which
  137. // could be e.g. the "args" of search results
  138. this.arguments = $.extend({}, _arguments || {});
  139. this.calcArgs();
  140. return this;
  141. },
  142. setDocument: function(_document) {
  143. this.document = _document;
  144. return this;
  145. },
  146. setCollection: function(collection) {
  147. this.collection = collection;
  148. return this;
  149. },
  150. getHash: function() {
  151. var url_hash = this.collection + this.document;
  152. var url_args = Util.param(this.extArguments);
  153. if (url_args.length) {
  154. url_hash += '?' + url_args;
  155. }
  156. if (url_hash.length) {
  157. url_hash = '#' + url_hash;
  158. }
  159. return url_hash;
  160. },
  161. };
  162. // arguments that do not appear in the URL
  163. var INT_ARGS = ['match', 'matchfocus', 'edited'];
  164. URLHash.splitArgs = function(args) {
  165. var intArgs = {};
  166. var extArgs = $.extend({}, args);
  167. var intArgNameLen = INT_ARGS.length;
  168. for (var i = 0; i < intArgNameLen; i++) {
  169. intArgs[INT_ARGS[i]] = extArgs[INT_ARGS[i]];
  170. delete extArgs[INT_ARGS[i]];
  171. }
  172. return [intArgs, extArgs];
  173. };
  174. // TODO: Document and conform variables to the rest of the object
  175. URLHash.parse = function(hash) {
  176. if (hash.length) {
  177. // Remove the leading hash (#)
  178. hash = hash.substr(1);
  179. }
  180. hash = decodeURIComponent(hash);
  181. var pathAndArgs = hash.split('?');
  182. var path = pathAndArgs[0] || '';
  183. var argsStr = pathAndArgs[1] || '';
  184. var coll;
  185. var slashPos = path.lastIndexOf('/');
  186. if (slashPos === -1) {
  187. coll = '/';
  188. } else {
  189. coll = path.substr(0, slashPos + 1);
  190. if (coll[coll.length - 1] !== '/') {
  191. coll += '/';
  192. }
  193. if (coll[0] !== '/') {
  194. coll = '/' + coll;
  195. }
  196. }
  197. var doc = path.substr(slashPos + 1);
  198. var args = Util.deparam(argsStr);
  199. return new URLHash(coll, doc, args);
  200. };
  201. return URLHash;
  202. })(jQuery, window)