/Rover/html-template/history/history.js

http://vanished-games.googlecode.com/ · JavaScript · 669 lines · 505 code · 78 blank · 86 comment · 194 complexity · 53fff2b96bbc90225512a59a28c87ece MD5 · raw file

  1. BrowserHistoryUtils = {
  2. addEvent: function(elm, evType, fn, useCapture) {
  3. useCapture = useCapture || false;
  4. if (elm.addEventListener) {
  5. elm.addEventListener(evType, fn, useCapture);
  6. return true;
  7. }
  8. else if (elm.attachEvent) {
  9. var r = elm.attachEvent('on' + evType, fn);
  10. return r;
  11. }
  12. else {
  13. elm['on' + evType] = fn;
  14. }
  15. }
  16. }
  17. BrowserHistory = (function() {
  18. // type of browser
  19. var browser = {
  20. ie: false,
  21. firefox: false,
  22. safari: false,
  23. opera: false,
  24. version: -1
  25. };
  26. // if setDefaultURL has been called, our first clue
  27. // that the SWF is ready and listening
  28. //var swfReady = false;
  29. // the URL we'll send to the SWF once it is ready
  30. //var pendingURL = '';
  31. // Default app state URL to use when no fragment ID present
  32. var defaultHash = '';
  33. // Last-known app state URL
  34. var currentHref = document.location.href;
  35. // Initial URL (used only by IE)
  36. var initialHref = document.location.href;
  37. // Initial URL (used only by IE)
  38. var initialHash = document.location.hash;
  39. // History frame source URL prefix (used only by IE)
  40. var historyFrameSourcePrefix = 'history/historyFrame.html?';
  41. // History maintenance (used only by Safari)
  42. var currentHistoryLength = -1;
  43. var historyHash = [];
  44. var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash);
  45. var backStack = [];
  46. var forwardStack = [];
  47. var currentObjectId = null;
  48. //UserAgent detection
  49. var useragent = navigator.userAgent.toLowerCase();
  50. if (useragent.indexOf("opera") != -1) {
  51. browser.opera = true;
  52. } else if (useragent.indexOf("msie") != -1) {
  53. browser.ie = true;
  54. browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4));
  55. } else if (useragent.indexOf("safari") != -1) {
  56. browser.safari = true;
  57. browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7));
  58. } else if (useragent.indexOf("gecko") != -1) {
  59. browser.firefox = true;
  60. }
  61. if (browser.ie == true && browser.version == 7) {
  62. window["_ie_firstload"] = false;
  63. }
  64. // Accessor functions for obtaining specific elements of the page.
  65. function getHistoryFrame()
  66. {
  67. return document.getElementById('ie_historyFrame');
  68. }
  69. function getAnchorElement()
  70. {
  71. return document.getElementById('firefox_anchorDiv');
  72. }
  73. function getFormElement()
  74. {
  75. return document.getElementById('safari_formDiv');
  76. }
  77. function getRememberElement()
  78. {
  79. return document.getElementById("safari_remember_field");
  80. }
  81. // Get the Flash player object for performing ExternalInterface callbacks.
  82. // Updated for changes to SWFObject2.
  83. function getPlayer(id) {
  84. if (id && document.getElementById(id)) {
  85. var r = document.getElementById(id);
  86. if (typeof r.SetVariable != "undefined") {
  87. return r;
  88. }
  89. else {
  90. var o = r.getElementsByTagName("object");
  91. var e = r.getElementsByTagName("embed");
  92. if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
  93. return o[0];
  94. }
  95. else if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
  96. return e[0];
  97. }
  98. }
  99. }
  100. else {
  101. var o = document.getElementsByTagName("object");
  102. var e = document.getElementsByTagName("embed");
  103. if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
  104. return e[0];
  105. }
  106. else if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
  107. return o[0];
  108. }
  109. else if (o.length > 1 && typeof o[1].SetVariable != "undefined") {
  110. return o[1];
  111. }
  112. }
  113. return undefined;
  114. }
  115. function getPlayers() {
  116. var players = [];
  117. if (players.length == 0) {
  118. var tmp = document.getElementsByTagName('object');
  119. players = tmp;
  120. }
  121. if (players.length == 0 || players[0].object == null) {
  122. var tmp = document.getElementsByTagName('embed');
  123. players = tmp;
  124. }
  125. return players;
  126. }
  127. function getIframeHash() {
  128. var doc = getHistoryFrame().contentWindow.document;
  129. var hash = String(doc.location.search);
  130. if (hash.length == 1 && hash.charAt(0) == "?") {
  131. hash = "";
  132. }
  133. else if (hash.length >= 2 && hash.charAt(0) == "?") {
  134. hash = hash.substring(1);
  135. }
  136. return hash;
  137. }
  138. /* Get the current location hash excluding the '#' symbol. */
  139. function getHash() {
  140. // It would be nice if we could use document.location.hash here,
  141. // but it's faulty sometimes.
  142. var idx = document.location.href.indexOf('#');
  143. return (idx >= 0) ? document.location.href.substr(idx+1) : '';
  144. }
  145. /* Get the current location hash excluding the '#' symbol. */
  146. function setHash(hash) {
  147. // It would be nice if we could use document.location.hash here,
  148. // but it's faulty sometimes.
  149. if (hash == '') hash = '#'
  150. document.location.hash = hash;
  151. }
  152. function createState(baseUrl, newUrl, flexAppUrl) {
  153. return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null };
  154. }
  155. /* Add a history entry to the browser.
  156. * baseUrl: the portion of the location prior to the '#'
  157. * newUrl: the entire new URL, including '#' and following fragment
  158. * flexAppUrl: the portion of the location following the '#' only
  159. */
  160. function addHistoryEntry(baseUrl, newUrl, flexAppUrl) {
  161. //delete all the history entries
  162. forwardStack = [];
  163. if (browser.ie) {
  164. //Check to see if we are being asked to do a navigate for the first
  165. //history entry, and if so ignore, because it's coming from the creation
  166. //of the history iframe
  167. if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) {
  168. currentHref = initialHref;
  169. return;
  170. }
  171. if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) {
  172. newUrl = baseUrl + '#' + defaultHash;
  173. flexAppUrl = defaultHash;
  174. } else {
  175. // for IE, tell the history frame to go somewhere without a '#'
  176. // in order to get this entry into the browser history.
  177. getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl;
  178. }
  179. setHash(flexAppUrl);
  180. } else {
  181. //ADR
  182. if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) {
  183. initialState = createState(baseUrl, newUrl, flexAppUrl);
  184. } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) {
  185. backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl);
  186. }
  187. if (browser.safari) {
  188. // for Safari, submit a form whose action points to the desired URL
  189. if (browser.version <= 419.3) {
  190. var file = window.location.pathname.toString();
  191. file = file.substring(file.lastIndexOf("/")+1);
  192. getFormElement().innerHTML = '<form name="historyForm" action="'+file+'#' + flexAppUrl + '" method="GET"></form>';
  193. //get the current elements and add them to the form
  194. var qs = window.location.search.substring(1);
  195. var qs_arr = qs.split("&");
  196. for (var i = 0; i < qs_arr.length; i++) {
  197. var tmp = qs_arr[i].split("=");
  198. var elem = document.createElement("input");
  199. elem.type = "hidden";
  200. elem.name = tmp[0];
  201. elem.value = tmp[1];
  202. document.forms.historyForm.appendChild(elem);
  203. }
  204. document.forms.historyForm.submit();
  205. } else {
  206. top.location.hash = flexAppUrl;
  207. }
  208. // We also have to maintain the history by hand for Safari
  209. historyHash[history.length] = flexAppUrl;
  210. _storeStates();
  211. } else {
  212. // Otherwise, write an anchor into the page and tell the browser to go there
  213. addAnchor(flexAppUrl);
  214. setHash(flexAppUrl);
  215. }
  216. }
  217. backStack.push(createState(baseUrl, newUrl, flexAppUrl));
  218. }
  219. function _storeStates() {
  220. if (browser.safari) {
  221. getRememberElement().value = historyHash.join(",");
  222. }
  223. }
  224. function handleBackButton() {
  225. //The "current" page is always at the top of the history stack.
  226. var current = backStack.pop();
  227. if (!current) { return; }
  228. var last = backStack[backStack.length - 1];
  229. if (!last && backStack.length == 0){
  230. last = initialState;
  231. }
  232. forwardStack.push(current);
  233. }
  234. function handleForwardButton() {
  235. //summary: private method. Do not call this directly.
  236. var last = forwardStack.pop();
  237. if (!last) { return; }
  238. backStack.push(last);
  239. }
  240. function handleArbitraryUrl() {
  241. //delete all the history entries
  242. forwardStack = [];
  243. }
  244. /* Called periodically to poll to see if we need to detect navigation that has occurred */
  245. function checkForUrlChange() {
  246. if (browser.ie) {
  247. if (currentHref != document.location.href && currentHref + '#' != document.location.href) {
  248. //This occurs when the user has navigated to a specific URL
  249. //within the app, and didn't use browser back/forward
  250. //IE seems to have a bug where it stops updating the URL it
  251. //shows the end-user at this point, but programatically it
  252. //appears to be correct. Do a full app reload to get around
  253. //this issue.
  254. if (browser.version < 7) {
  255. currentHref = document.location.href;
  256. document.location.reload();
  257. } else {
  258. if (getHash() != getIframeHash()) {
  259. // this.iframe.src = this.blankURL + hash;
  260. var sourceToSet = historyFrameSourcePrefix + getHash();
  261. getHistoryFrame().src = sourceToSet;
  262. }
  263. }
  264. }
  265. }
  266. if (browser.safari) {
  267. // For Safari, we have to check to see if history.length changed.
  268. if (currentHistoryLength >= 0 && history.length != currentHistoryLength) {
  269. //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|"));
  270. var flexAppUrl = getHash();
  271. if (browser.version < 528.16 /* Anything earlier than Safari 4.0 */)
  272. {
  273. // If it did change and we're running Safari 3.x or earlier,
  274. // then we have to look the old state up in our hand-maintained
  275. // array since document.location.hash won't have changed,
  276. // then call back into BrowserManager.
  277. currentHistoryLength = history.length;
  278. flexAppUrl = historyHash[currentHistoryLength];
  279. }
  280. //ADR: to fix multiple
  281. if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
  282. var pl = getPlayers();
  283. for (var i = 0; i < pl.length; i++) {
  284. pl[i].browserURLChange(flexAppUrl);
  285. }
  286. } else {
  287. getPlayer().browserURLChange(flexAppUrl);
  288. }
  289. _storeStates();
  290. }
  291. }
  292. if (browser.firefox) {
  293. if (currentHref != document.location.href) {
  294. var bsl = backStack.length;
  295. var urlActions = {
  296. back: false,
  297. forward: false,
  298. set: false
  299. }
  300. if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) {
  301. urlActions.back = true;
  302. // FIXME: could this ever be a forward button?
  303. // we can't clear it because we still need to check for forwards. Ugg.
  304. // clearInterval(this.locationTimer);
  305. handleBackButton();
  306. }
  307. // first check to see if we could have gone forward. We always halt on
  308. // a no-hash item.
  309. if (forwardStack.length > 0) {
  310. if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) {
  311. urlActions.forward = true;
  312. handleForwardButton();
  313. }
  314. }
  315. // ok, that didn't work, try someplace back in the history stack
  316. if ((bsl >= 2) && (backStack[bsl - 2])) {
  317. if (backStack[bsl - 2].flexAppUrl == getHash()) {
  318. urlActions.back = true;
  319. handleBackButton();
  320. }
  321. }
  322. if (!urlActions.back && !urlActions.forward) {
  323. var foundInStacks = {
  324. back: -1,
  325. forward: -1
  326. }
  327. for (var i = 0; i < backStack.length; i++) {
  328. if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
  329. arbitraryUrl = true;
  330. foundInStacks.back = i;
  331. }
  332. }
  333. for (var i = 0; i < forwardStack.length; i++) {
  334. if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
  335. arbitraryUrl = true;
  336. foundInStacks.forward = i;
  337. }
  338. }
  339. handleArbitraryUrl();
  340. }
  341. // Firefox changed; do a callback into BrowserManager to tell it.
  342. currentHref = document.location.href;
  343. var flexAppUrl = getHash();
  344. if (flexAppUrl == '') {
  345. //flexAppUrl = defaultHash;
  346. }
  347. //ADR: to fix multiple
  348. if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
  349. var pl = getPlayers();
  350. for (var i = 0; i < pl.length; i++) {
  351. pl[i].browserURLChange(flexAppUrl);
  352. }
  353. } else {
  354. getPlayer().browserURLChange(flexAppUrl);
  355. }
  356. }
  357. }
  358. //setTimeout(checkForUrlChange, 50);
  359. }
  360. /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */
  361. function addAnchor(flexAppUrl)
  362. {
  363. if (document.getElementsByName(flexAppUrl).length == 0) {
  364. getAnchorElement().innerHTML += "<a name='" + flexAppUrl + "'>" + flexAppUrl + "</a>";
  365. }
  366. }
  367. var _initialize = function () {
  368. if (browser.ie)
  369. {
  370. var scripts = document.getElementsByTagName('script');
  371. for (var i = 0, s; s = scripts[i]; i++) {
  372. if (s.src.indexOf("history.js") > -1) {
  373. var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html");
  374. }
  375. }
  376. historyFrameSourcePrefix = iframe_location + "?";
  377. var src = historyFrameSourcePrefix;
  378. var iframe = document.createElement("iframe");
  379. iframe.id = 'ie_historyFrame';
  380. iframe.name = 'ie_historyFrame';
  381. //iframe.src = historyFrameSourcePrefix;
  382. try {
  383. document.body.appendChild(iframe);
  384. } catch(e) {
  385. setTimeout(function() {
  386. document.body.appendChild(iframe);
  387. }, 0);
  388. }
  389. }
  390. if (browser.safari)
  391. {
  392. var rememberDiv = document.createElement("div");
  393. rememberDiv.id = 'safari_rememberDiv';
  394. document.body.appendChild(rememberDiv);
  395. rememberDiv.innerHTML = '<input type="text" id="safari_remember_field" style="width: 500px;">';
  396. var formDiv = document.createElement("div");
  397. formDiv.id = 'safari_formDiv';
  398. document.body.appendChild(formDiv);
  399. var reloader_content = document.createElement('div');
  400. reloader_content.id = 'safarireloader';
  401. var scripts = document.getElementsByTagName('script');
  402. for (var i = 0, s; s = scripts[i]; i++) {
  403. if (s.src.indexOf("history.js") > -1) {
  404. html = (new String(s.src)).replace(".js", ".html");
  405. }
  406. }
  407. reloader_content.innerHTML = '<iframe id="safarireloader-iframe" src="about:blank" frameborder="no" scrolling="no"></iframe>';
  408. document.body.appendChild(reloader_content);
  409. reloader_content.style.position = 'absolute';
  410. reloader_content.style.left = reloader_content.style.top = '-9999px';
  411. iframe = reloader_content.getElementsByTagName('iframe')[0];
  412. if (document.getElementById("safari_remember_field").value != "" ) {
  413. historyHash = document.getElementById("safari_remember_field").value.split(",");
  414. }
  415. }
  416. if (browser.firefox)
  417. {
  418. var anchorDiv = document.createElement("div");
  419. anchorDiv.id = 'firefox_anchorDiv';
  420. document.body.appendChild(anchorDiv);
  421. }
  422. //setTimeout(checkForUrlChange, 50);
  423. }
  424. return {
  425. historyHash: historyHash,
  426. backStack: function() { return backStack; },
  427. forwardStack: function() { return forwardStack },
  428. getPlayer: getPlayer,
  429. initialize: function(src) {
  430. _initialize(src);
  431. },
  432. setURL: function(url) {
  433. document.location.href = url;
  434. },
  435. getURL: function() {
  436. return document.location.href;
  437. },
  438. getTitle: function() {
  439. return document.title;
  440. },
  441. setTitle: function(title) {
  442. try {
  443. backStack[backStack.length - 1].title = title;
  444. } catch(e) { }
  445. //if on safari, set the title to be the empty string.
  446. if (browser.safari) {
  447. if (title == "") {
  448. try {
  449. var tmp = window.location.href.toString();
  450. title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#"));
  451. } catch(e) {
  452. title = "";
  453. }
  454. }
  455. }
  456. document.title = title;
  457. },
  458. setDefaultURL: function(def)
  459. {
  460. defaultHash = def;
  461. def = getHash();
  462. //trailing ? is important else an extra frame gets added to the history
  463. //when navigating back to the first page. Alternatively could check
  464. //in history frame navigation to compare # and ?.
  465. if (browser.ie)
  466. {
  467. window['_ie_firstload'] = true;
  468. var sourceToSet = historyFrameSourcePrefix + def;
  469. var func = function() {
  470. getHistoryFrame().src = sourceToSet;
  471. window.location.replace("#" + def);
  472. setInterval(checkForUrlChange, 50);
  473. }
  474. try {
  475. func();
  476. } catch(e) {
  477. window.setTimeout(function() { func(); }, 0);
  478. }
  479. }
  480. if (browser.safari)
  481. {
  482. currentHistoryLength = history.length;
  483. if (historyHash.length == 0) {
  484. historyHash[currentHistoryLength] = def;
  485. var newloc = "#" + def;
  486. window.location.replace(newloc);
  487. } else {
  488. //alert(historyHash[historyHash.length-1]);
  489. }
  490. //setHash(def);
  491. setInterval(checkForUrlChange, 50);
  492. }
  493. if (browser.firefox || browser.opera)
  494. {
  495. var reg = new RegExp("#" + def + "$");
  496. if (window.location.toString().match(reg)) {
  497. } else {
  498. var newloc ="#" + def;
  499. window.location.replace(newloc);
  500. }
  501. setInterval(checkForUrlChange, 50);
  502. //setHash(def);
  503. }
  504. },
  505. /* Set the current browser URL; called from inside BrowserManager to propagate
  506. * the application state out to the container.
  507. */
  508. setBrowserURL: function(flexAppUrl, objectId) {
  509. if (browser.ie && typeof objectId != "undefined") {
  510. currentObjectId = objectId;
  511. }
  512. //fromIframe = fromIframe || false;
  513. //fromFlex = fromFlex || false;
  514. //alert("setBrowserURL: " + flexAppUrl);
  515. //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ;
  516. var pos = document.location.href.indexOf('#');
  517. var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href;
  518. var newUrl = baseUrl + '#' + flexAppUrl;
  519. if (document.location.href != newUrl && document.location.href + '#' != newUrl) {
  520. currentHref = newUrl;
  521. addHistoryEntry(baseUrl, newUrl, flexAppUrl);
  522. currentHistoryLength = history.length;
  523. }
  524. },
  525. browserURLChange: function(flexAppUrl) {
  526. var objectId = null;
  527. if (browser.ie && currentObjectId != null) {
  528. objectId = currentObjectId;
  529. }
  530. pendingURL = '';
  531. if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
  532. var pl = getPlayers();
  533. for (var i = 0; i < pl.length; i++) {
  534. try {
  535. pl[i].browserURLChange(flexAppUrl);
  536. } catch(e) { }
  537. }
  538. } else {
  539. try {
  540. getPlayer(objectId).browserURLChange(flexAppUrl);
  541. } catch(e) { }
  542. }
  543. currentObjectId = null;
  544. },
  545. getUserAgent: function() {
  546. return navigator.userAgent;
  547. },
  548. getPlatform: function() {
  549. return navigator.platform;
  550. }
  551. }
  552. })();
  553. // Initialization
  554. // Automated unit testing and other diagnostics
  555. function setURL(url)
  556. {
  557. document.location.href = url;
  558. }
  559. function backButton()
  560. {
  561. history.back();
  562. }
  563. function forwardButton()
  564. {
  565. history.forward();
  566. }
  567. function goForwardOrBackInHistory(step)
  568. {
  569. history.go(step);
  570. }
  571. //BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); });
  572. (function(i) {
  573. var u =navigator.userAgent;var e=/*@cc_on!@*/false;
  574. var st = setTimeout;
  575. if(/webkit/i.test(u)){
  576. st(function(){
  577. var dr=document.readyState;
  578. if(dr=="loaded"||dr=="complete"){i()}
  579. else{st(arguments.callee,10);}},10);
  580. } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
  581. document.addEventListener("DOMContentLoaded",i,false);
  582. } else if(e){
  583. (function(){
  584. var t=document.createElement('doc:rdy');
  585. try{t.doScroll('left');
  586. i();t=null;
  587. }catch(e){st(arguments.callee,0);}})();
  588. } else{
  589. window.onload=i;
  590. }
  591. })( function() {BrowserHistory.initialize();} );