| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| BrowserHistoryUtils = { |
| addEvent: function(elm, evType, fn, useCapture) { |
| useCapture = useCapture || false; |
| if (elm.addEventListener) { |
| elm.addEventListener(evType, fn, useCapture); |
| return true; |
| } |
| else if (elm.attachEvent) { |
| var r = elm.attachEvent('on' + evType, fn); |
| return r; |
| } |
| else { |
| elm['on' + evType] = fn; |
| } |
| } |
| } |
| |
| BrowserHistory = (function() { |
| // type of browser |
| var browser = { |
| ie: false, |
| ie8: false, |
| firefox: false, |
| safari: false, |
| opera: false, |
| version: -1 |
| }; |
| |
| // Default app state URL to use when no fragment ID present |
| var defaultHash = ''; |
| |
| // Last-known app state URL |
| var currentHref = document.location.href; |
| |
| // Initial URL (used only by IE) |
| var initialHref = document.location.href; |
| |
| // Initial URL (used only by IE) |
| var initialHash = document.location.hash; |
| |
| // History frame source URL prefix (used only by IE) |
| var historyFrameSourcePrefix = 'history/historyFrame.html?'; |
| |
| // History maintenance (used only by Safari) |
| var currentHistoryLength = -1; |
| |
| // Flag to denote the existence of onhashchange |
| var browserHasHashChange = false; |
| |
| var historyHash = []; |
| |
| var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); |
| |
| var backStack = []; |
| var forwardStack = []; |
| |
| var currentObjectId = null; |
| |
| //UserAgent detection |
| var useragent = navigator.userAgent.toLowerCase(); |
| |
| if (useragent.indexOf("opera") != -1) { |
| browser.opera = true; |
| } else if (useragent.indexOf("msie") != -1) { |
| browser.ie = true; |
| browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); |
| if (browser.version == 8) |
| { |
| browser.ie = false; |
| browser.ie8 = true; |
| } |
| } else if (useragent.indexOf("safari") != -1) { |
| browser.safari = true; |
| browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); |
| } else if (useragent.indexOf("gecko") != -1) { |
| browser.firefox = true; |
| } |
| |
| if (browser.ie == true && browser.version == 7) { |
| window["_ie_firstload"] = false; |
| } |
| |
| function hashChangeHandler() |
| { |
| currentHref = document.location.href; |
| var flexAppUrl = getHash(); |
| //ADR: to fix multiple |
| if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { |
| var pl = getPlayers(); |
| for (var i = 0; i < pl.length; i++) { |
| pl[i].browserURLChange(flexAppUrl); |
| } |
| } else { |
| getPlayer().browserURLChange(flexAppUrl); |
| } |
| } |
| |
| // Accessor functions for obtaining specific elements of the page. |
| function getHistoryFrame() |
| { |
| return document.getElementById('ie_historyFrame'); |
| } |
| |
| function getFormElement() |
| { |
| return document.getElementById('safari_formDiv'); |
| } |
| |
| function getRememberElement() |
| { |
| return document.getElementById("safari_remember_field"); |
| } |
| |
| // Get the Flash player object for performing ExternalInterface callbacks. |
| // Updated for changes to SWFObject2. |
| function getPlayer(id) { |
| var i; |
| |
| if (id && document.getElementById(id)) { |
| var r = document.getElementById(id); |
| if (typeof r.SetVariable != "undefined") { |
| return r; |
| } |
| else { |
| var o = r.getElementsByTagName("object"); |
| var e = r.getElementsByTagName("embed"); |
| for (i = 0; i < o.length; i++) { |
| if (typeof o[i].browserURLChange != "undefined") |
| return o[i]; |
| } |
| for (i = 0; i < e.length; i++) { |
| if (typeof e[i].browserURLChange != "undefined") |
| return e[i]; |
| } |
| } |
| } |
| else { |
| var o = document.getElementsByTagName("object"); |
| var e = document.getElementsByTagName("embed"); |
| for (i = 0; i < e.length; i++) { |
| if (typeof e[i].browserURLChange != "undefined") |
| { |
| return e[i]; |
| } |
| } |
| for (i = 0; i < o.length; i++) { |
| if (typeof o[i].browserURLChange != "undefined") |
| { |
| return o[i]; |
| } |
| } |
| } |
| return undefined; |
| } |
| |
| function getPlayers() { |
| var i; |
| var players = []; |
| if (players.length == 0) { |
| var tmp = document.getElementsByTagName('object'); |
| for (i = 0; i < tmp.length; i++) |
| { |
| if (typeof tmp[i].browserURLChange != "undefined") |
| players.push(tmp[i]); |
| } |
| } |
| if (players.length == 0 || players[0].object == null) { |
| var tmp = document.getElementsByTagName('embed'); |
| for (i = 0; i < tmp.length; i++) |
| { |
| if (typeof tmp[i].browserURLChange != "undefined") |
| players.push(tmp[i]); |
| } |
| } |
| return players; |
| } |
| |
| function getIframeHash() { |
| var doc = getHistoryFrame().contentWindow.document; |
| var hash = String(doc.location.search); |
| if (hash.length == 1 && hash.charAt(0) == "?") { |
| hash = ""; |
| } |
| else if (hash.length >= 2 && hash.charAt(0) == "?") { |
| hash = hash.substring(1); |
| } |
| return hash; |
| } |
| |
| /* Get the current location hash excluding the '#' symbol. */ |
| function getHash() { |
| // It would be nice if we could use document.location.hash here, |
| // but it's faulty sometimes. |
| var idx = document.location.href.indexOf('#'); |
| return (idx >= 0) ? document.location.href.substr(idx+1) : ''; |
| } |
| |
| /* Get the current location hash excluding the '#' symbol. */ |
| function setHash(hash) { |
| // It would be nice if we could use document.location.hash here, |
| // but it's faulty sometimes. |
| if (hash == '') hash = '#' |
| document.location.hash = hash; |
| } |
| |
| function createState(baseUrl, newUrl, flexAppUrl) { |
| return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; |
| } |
| |
| /* Add a history entry to the browser. |
| * baseUrl: the portion of the location prior to the '#' |
| * newUrl: the entire new URL, including '#' and following fragment |
| * flexAppUrl: the portion of the location following the '#' only |
| */ |
| function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { |
| |
| //delete all the history entries |
| forwardStack = []; |
| |
| if (browser.ie) { |
| //Check to see if we are being asked to do a navigate for the first |
| //history entry, and if so ignore, because it's coming from the creation |
| //of the history iframe |
| if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { |
| currentHref = initialHref; |
| return; |
| } |
| if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { |
| newUrl = baseUrl + '#' + defaultHash; |
| flexAppUrl = defaultHash; |
| } else { |
| // for IE, tell the history frame to go somewhere without a '#' |
| // in order to get this entry into the browser history. |
| getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; |
| } |
| setHash(flexAppUrl); |
| } else { |
| |
| //ADR |
| if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { |
| initialState = createState(baseUrl, newUrl, flexAppUrl); |
| } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { |
| backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); |
| } |
| |
| if (browser.safari && !browserHasHashChange) { |
| // for Safari, submit a form whose action points to the desired URL |
| if (browser.version <= 419.3) { |
| var file = window.location.pathname.toString(); |
| file = file.substring(file.lastIndexOf("/")+1); |
| getFormElement().innerHTML = '<form name="historyForm" action="'+file+'#' + flexAppUrl + '" method="GET"></form>'; |
| //get the current elements and add them to the form |
| var qs = window.location.search.substring(1); |
| var qs_arr = qs.split("&"); |
| for (var i = 0; i < qs_arr.length; i++) { |
| var tmp = qs_arr[i].split("="); |
| var elem = document.createElement("input"); |
| elem.type = "hidden"; |
| elem.name = tmp[0]; |
| elem.value = tmp[1]; |
| document.forms.historyForm.appendChild(elem); |
| } |
| document.forms.historyForm.submit(); |
| } else { |
| top.location.hash = flexAppUrl; |
| } |
| // We also have to maintain the history by hand for Safari |
| historyHash[history.length] = flexAppUrl; |
| _storeStates(); |
| } else { |
| // Otherwise, just tell the browser to go there |
| setHash(flexAppUrl); |
| } |
| } |
| backStack.push(createState(baseUrl, newUrl, flexAppUrl)); |
| } |
| |
| function _storeStates() { |
| if (browser.safari) { |
| getRememberElement().value = historyHash.join(","); |
| } |
| } |
| |
| function handleBackButton() { |
| //The "current" page is always at the top of the history stack. |
| var current = backStack.pop(); |
| if (!current) { return; } |
| var last = backStack[backStack.length - 1]; |
| if (!last && backStack.length == 0){ |
| last = initialState; |
| } |
| forwardStack.push(current); |
| } |
| |
| function handleForwardButton() { |
| //summary: private method. Do not call this directly. |
| |
| var last = forwardStack.pop(); |
| if (!last) { return; } |
| backStack.push(last); |
| } |
| |
| function handleArbitraryUrl() { |
| //delete all the history entries |
| forwardStack = []; |
| } |
| |
| /* Called periodically to poll to see if we need to detect navigation that has occurred */ |
| function checkForUrlChange() { |
| |
| if (browser.ie) { |
| if (currentHref != document.location.href && currentHref + '#' != document.location.href) { |
| //This occurs when the user has navigated to a specific URL |
| //within the app, and didn't use browser back/forward |
| //IE seems to have a bug where it stops updating the URL it |
| //shows the end-user at this point, but programatically it |
| //appears to be correct. Do a full app reload to get around |
| //this issue. |
| if (browser.version < 7) { |
| currentHref = document.location.href; |
| document.location.reload(); |
| } else { |
| if (getHash() != getIframeHash()) { |
| // this.iframe.src = this.blankURL + hash; |
| var sourceToSet = historyFrameSourcePrefix + getHash(); |
| getHistoryFrame().src = sourceToSet; |
| currentHref = document.location.href; |
| } |
| } |
| } |
| } |
| |
| if (browser.safari && !browserHasHashChange) { |
| // For Safari, we have to check to see if history.length changed. |
| if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { |
| //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); |
| var flexAppUrl = getHash(); |
| if (browser.version < 528.16 /* Anything earlier than Safari 4.0 */) |
| { |
| // If it did change and we're running Safari 3.x or earlier, |
| // then we have to look the old state up in our hand-maintained |
| // array since document.location.hash won't have changed, |
| // then call back into BrowserManager. |
| currentHistoryLength = history.length; |
| flexAppUrl = historyHash[currentHistoryLength]; |
| } |
| |
| //ADR: to fix multiple |
| if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { |
| var pl = getPlayers(); |
| for (var i = 0; i < pl.length; i++) { |
| pl[i].browserURLChange(flexAppUrl); |
| } |
| } else { |
| getPlayer().browserURLChange(flexAppUrl); |
| } |
| _storeStates(); |
| } |
| } |
| if (browser.firefox && !browserHasHashChange) { |
| if (currentHref != document.location.href) { |
| var bsl = backStack.length; |
| |
| var urlActions = { |
| back: false, |
| forward: false, |
| set: false |
| } |
| |
| if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { |
| urlActions.back = true; |
| // FIXME: could this ever be a forward button? |
| // we can't clear it because we still need to check for forwards. Ugg. |
| // clearInterval(this.locationTimer); |
| handleBackButton(); |
| } |
| |
| // first check to see if we could have gone forward. We always halt on |
| // a no-hash item. |
| if (forwardStack.length > 0) { |
| if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { |
| urlActions.forward = true; |
| handleForwardButton(); |
| } |
| } |
| |
| // ok, that didn't work, try someplace back in the history stack |
| if ((bsl >= 2) && (backStack[bsl - 2])) { |
| if (backStack[bsl - 2].flexAppUrl == getHash()) { |
| urlActions.back = true; |
| handleBackButton(); |
| } |
| } |
| |
| if (!urlActions.back && !urlActions.forward) { |
| var foundInStacks = { |
| back: -1, |
| forward: -1 |
| } |
| |
| for (var i = 0; i < backStack.length; i++) { |
| if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { |
| arbitraryUrl = true; |
| foundInStacks.back = i; |
| } |
| } |
| for (var i = 0; i < forwardStack.length; i++) { |
| if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { |
| arbitraryUrl = true; |
| foundInStacks.forward = i; |
| } |
| } |
| handleArbitraryUrl(); |
| } |
| |
| // Firefox changed; do a callback into BrowserManager to tell it. |
| currentHref = document.location.href; |
| var flexAppUrl = getHash(); |
| //ADR: to fix multiple |
| if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { |
| var pl = getPlayers(); |
| for (var i = 0; i < pl.length; i++) { |
| pl[i].browserURLChange(flexAppUrl); |
| } |
| } else { |
| getPlayer().browserURLChange(flexAppUrl); |
| } |
| } |
| } |
| } |
| |
| var _initialize = function () { |
| |
| browserHasHashChange = ("onhashchange" in document.body); |
| |
| if (browser.ie) |
| { |
| var scripts = document.getElementsByTagName('script'); |
| for (var i = 0, s; s = scripts[i]; i++) { |
| if (s.src.indexOf("history.js") > -1) { |
| var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); |
| } |
| } |
| historyFrameSourcePrefix = iframe_location + "?"; |
| var src = historyFrameSourcePrefix; |
| |
| var iframe = document.createElement("iframe"); |
| iframe.id = 'ie_historyFrame'; |
| iframe.name = 'ie_historyFrame'; |
| iframe.src = 'javascript:false;'; |
| |
| try { |
| document.body.appendChild(iframe); |
| } catch(e) { |
| setTimeout(function() { |
| document.body.appendChild(iframe); |
| }, 0); |
| } |
| } |
| |
| if (browser.safari && !browserHasHashChange) |
| { |
| var rememberDiv = document.createElement("div"); |
| rememberDiv.id = 'safari_rememberDiv'; |
| document.body.appendChild(rememberDiv); |
| rememberDiv.innerHTML = '<input type="text" id="safari_remember_field" style="width: 500px;">'; |
| |
| var formDiv = document.createElement("div"); |
| formDiv.id = 'safari_formDiv'; |
| document.body.appendChild(formDiv); |
| |
| var reloader_content = document.createElement('div'); |
| reloader_content.id = 'safarireloader'; |
| var scripts = document.getElementsByTagName('script'); |
| for (var i = 0, s; s = scripts[i]; i++) { |
| if (s.src.indexOf("history.js") > -1) { |
| html = (new String(s.src)).replace(".js", ".html"); |
| } |
| } |
| reloader_content.innerHTML = '<iframe id="safarireloader-iframe" src="about:blank" frameborder="no" scrolling="no"></iframe>'; |
| document.body.appendChild(reloader_content); |
| reloader_content.style.position = 'absolute'; |
| reloader_content.style.left = reloader_content.style.top = '-9999px'; |
| iframe = reloader_content.getElementsByTagName('iframe')[0]; |
| |
| if (document.getElementById("safari_remember_field").value != "" ) { |
| historyHash = document.getElementById("safari_remember_field").value.split(","); |
| } |
| } |
| |
| if (browserHasHashChange) |
| document.body.onhashchange = hashChangeHandler; |
| } |
| |
| return { |
| historyHash: historyHash, |
| backStack: function() { return backStack; }, |
| forwardStack: function() { return forwardStack }, |
| getPlayer: getPlayer, |
| initialize: function(src) { |
| _initialize(src); |
| }, |
| setURL: function(url) { |
| document.location.href = url; |
| }, |
| getURL: function() { |
| return document.location.href; |
| }, |
| getTitle: function() { |
| return document.title; |
| }, |
| setTitle: function(title) { |
| try { |
| backStack[backStack.length - 1].title = title; |
| } catch(e) { } |
| //if on safari, set the title to be the empty string. |
| if (browser.safari) { |
| if (title == "") { |
| try { |
| var tmp = window.location.href.toString(); |
| title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); |
| } catch(e) { |
| title = ""; |
| } |
| } |
| } |
| document.title = title; |
| }, |
| setDefaultURL: function(def) |
| { |
| defaultHash = def; |
| def = getHash(); |
| //trailing ? is important else an extra frame gets added to the history |
| //when navigating back to the first page. Alternatively could check |
| //in history frame navigation to compare # and ?. |
| if (browser.ie) |
| { |
| window['_ie_firstload'] = true; |
| var sourceToSet = historyFrameSourcePrefix + def; |
| var func = function() { |
| getHistoryFrame().src = sourceToSet; |
| window.location.replace("#" + def); |
| setInterval(checkForUrlChange, 50); |
| } |
| try { |
| func(); |
| } catch(e) { |
| window.setTimeout(function() { func(); }, 0); |
| } |
| } |
| |
| if (browser.safari) |
| { |
| currentHistoryLength = history.length; |
| if (historyHash.length == 0) { |
| historyHash[currentHistoryLength] = def; |
| var newloc = "#" + def; |
| window.location.replace(newloc); |
| } else { |
| //alert(historyHash[historyHash.length-1]); |
| } |
| setInterval(checkForUrlChange, 50); |
| } |
| |
| |
| if (browser.firefox || browser.opera) |
| { |
| var reg = new RegExp("#" + def + "$"); |
| if (window.location.toString().match(reg)) { |
| } else { |
| var newloc ="#" + def; |
| window.location.replace(newloc); |
| } |
| setInterval(checkForUrlChange, 50); |
| } |
| |
| }, |
| |
| /* Set the current browser URL; called from inside BrowserManager to propagate |
| * the application state out to the container. |
| */ |
| setBrowserURL: function(flexAppUrl, objectId) { |
| if (browser.ie && typeof objectId != "undefined") { |
| currentObjectId = objectId; |
| } |
| //fromIframe = fromIframe || false; |
| //fromFlex = fromFlex || false; |
| //alert("setBrowserURL: " + flexAppUrl); |
| //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; |
| |
| var pos = document.location.href.indexOf('#'); |
| var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; |
| var newUrl = baseUrl + '#' + flexAppUrl; |
| |
| if (document.location.href != newUrl && document.location.href + '#' != newUrl) { |
| currentHref = newUrl; |
| addHistoryEntry(baseUrl, newUrl, flexAppUrl); |
| currentHistoryLength = history.length; |
| } |
| }, |
| |
| browserURLChange: function(flexAppUrl) { |
| var objectId = null; |
| if (browser.ie && currentObjectId != null) { |
| objectId = currentObjectId; |
| } |
| |
| if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { |
| var pl = getPlayers(); |
| for (var i = 0; i < pl.length; i++) { |
| try { |
| pl[i].browserURLChange(flexAppUrl); |
| } catch(e) { } |
| } |
| } else { |
| try { |
| getPlayer(objectId).browserURLChange(flexAppUrl); |
| } catch(e) { } |
| } |
| |
| currentObjectId = null; |
| }, |
| getUserAgent: function() { |
| return navigator.userAgent; |
| }, |
| getPlatform: function() { |
| return navigator.platform; |
| } |
| |
| } |
| |
| })(); |
| |
| // Initialization |
| |
| // Automated unit testing and other diagnostics |
| |
| function setURL(url) |
| { |
| document.location.href = url; |
| } |
| |
| function backButton() |
| { |
| history.back(); |
| } |
| |
| function forwardButton() |
| { |
| history.forward(); |
| } |
| |
| function goForwardOrBackInHistory(step) |
| { |
| history.go(step); |
| } |
| |
| //BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); |
| (function(i) { |
| var u =navigator.userAgent;var e=/*@cc_on!@*/false; |
| var st = setTimeout; |
| if(/webkit/i.test(u)){ |
| st(function(){ |
| var dr=document.readyState; |
| if(dr=="loaded"||dr=="complete"){i()} |
| else{st(arguments.callee,10);}},10); |
| } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ |
| document.addEventListener("DOMContentLoaded",i,false); |
| } else if(e){ |
| (function(){ |
| var t=document.createElement('doc:rdy'); |
| try{t.doScroll('left'); |
| i();t=null; |
| }catch(e){st(arguments.callee,0);}})(); |
| } else{ |
| window.onload=i; |
| } |
| })( function() {BrowserHistory.initialize();} ); |