📄 browser.js
字号:
/* Copyright (c) 2004-2006, The Dojo Foundation All Rights Reserved. Licensed under the Academic Free License version 2.1 or above OR the modified BSD license. For more information on Dojo licensing, see: http://dojotoolkit.org/community/licensing.shtml*/dojo.provide("dojo.undo.browser");dojo.require("dojo.io.common");try{ if((!djConfig["preventBackButtonFix"])&&(!dojo.hostenv.post_load_)){ document.write("<iframe style='border: 0px; width: 1px; height: 1px; position: absolute; bottom: 0px; right: 0px; visibility: visible;' name='djhistory' id='djhistory' src='"+(dojo.hostenv.getBaseScriptUri()+'iframe_history.html')+"'></iframe>"); }}catch(e){/* squelch */}if(dojo.render.html.opera){ dojo.debug("Opera is not supported with dojo.undo.browser, so back/forward detection will not work.");}dojo.undo.browser = { initialHref: (!dj_undef("window")) ? window.location.href : "", initialHash: (!dj_undef("window")) ? window.location.hash : "", moveForward: false, historyStack: [], forwardStack: [], historyIframe: null, bookmarkAnchor: null, locationTimer: null, /** * */ setInitialState: function(/*Object*/args){ //summary: Sets the state object and back callback for the very first page that is loaded. //description: It is recommended that you call this method as part of an event listener that is registered via //dojo.addOnLoad(). //args: Object // See the addToHistory() function for the list of valid args properties. this.initialState = this._createState(this.initialHref, args, this.initialHash); }, //FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things. //FIXME: is there a slight race condition in moz using change URL with the timer check and when // the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent. addToHistory: function(args){ //summary: adds a state object (args) to the history list. You must set //djConfig.preventBackButtonFix = false to use dojo.undo.browser. //args: Object // args can have the following properties: // To support getting back button notifications, the object argument should implement a // function called either "back", "backButton", or "handle". The string "back" will be // passed as the first and only argument to this callback. // - To support getting forward button notifications, the object argument should implement a // function called either "forward", "forwardButton", or "handle". The string "forward" will be // passed as the first and only argument to this callback. // - If you want the browser location string to change, define "changeUrl" on the object. If the // value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment // identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does // not evaluate to false, that value will be used as the fragment identifier. For example, // if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1 // Full example: // dojo.undo.browser.addToHistory({ // back: function() { alert('back pressed'); }, // forward: function() { alert('forward pressed'); }, // changeUrl: true // }); // // BROWSER NOTES: // Safari 1.2: // back button "works" fine, however it's not possible to actually // DETECT that you've moved backwards by inspecting window.location. // Unless there is some other means of locating. // FIXME: perhaps we can poll on history.length? // Safari 2.0.3+ (and probably 1.3.2+): // works fine, except when changeUrl is used. When changeUrl is used, // Safari jumps all the way back to whatever page was shown before // the page that uses dojo.undo.browser support. // IE 5.5 SP2: // back button behavior is macro. It does not move back to the // previous hash value, but to the last full page load. This suggests // that the iframe is the correct way to capture the back button in // these cases. // Don't test this page using local disk for MSIE. MSIE will not create // a history list for iframe_history.html if served from a file: URL. // The XML served back from the XHR tests will also not be properly // created if served from local disk. Serve the test pages from a web // server to test in that browser. // IE 6.0: // same behavior as IE 5.5 SP2 // Firefox 1.0+: // the back button will return us to the previous hash on the same // page, thereby not requiring an iframe hack, although we do then // need to run a timer to detect inter-page movement. //If addToHistory is called, then that means we prune the //forward stack -- the user went back, then wanted to //start a new forward path. this.forwardStack = []; var hash = null; var url = null; if(!this.historyIframe){ this.historyIframe = window.frames["djhistory"]; } if(!this.bookmarkAnchor){ this.bookmarkAnchor = document.createElement("a"); dojo.body().appendChild(this.bookmarkAnchor); this.bookmarkAnchor.style.display = "none"; } if(args["changeUrl"]){ hash = "#"+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime()); //If the current hash matches the new one, just replace the history object with //this new one. It doesn't make sense to track different state objects for the same //logical URL. This matches the browser behavior of only putting in one history //item no matter how many times you click on the same #hash link, at least in Firefox //and Safari, and there is no reliable way in those browsers to know if a #hash link //has been clicked on multiple times. So making this the standard behavior in all browsers //so that dojo.undo.browser's behavior is the same in all browsers. if(this.historyStack.length == 0 && this.initialState.urlHash == hash){ this.initialState = this._createState(url, args, hash); return; }else if(this.historyStack.length > 0 && this.historyStack[this.historyStack.length - 1].urlHash == hash){ this.historyStack[this.historyStack.length - 1] = this._createState(url, args, hash); return; } this.changingUrl = true; setTimeout("window.location.href = '"+hash+"'; dojo.undo.browser.changingUrl = false;", 1); this.bookmarkAnchor.href = hash; if(dojo.render.html.ie){ url = this._loadIframeHistory(); var oldCB = args["back"]||args["backButton"]||args["handle"]; //The function takes handleName as a parameter, in case the //callback we are overriding was "handle". In that case, //we will need to pass the handle name to handle. var tcb = function(handleName){ if(window.location.hash != ""){ setTimeout("window.location.href = '"+hash+"';", 1); } //Use apply to set "this" to args, and to try to avoid memory leaks. oldCB.apply(this, [handleName]); } //Set interceptor function in the right place. if(args["back"]){ args.back = tcb; }else if(args["backButton"]){ args.backButton = tcb; }else if(args["handle"]){ args.handle = tcb; } var oldFW = args["forward"]||args["forwardButton"]||args["handle"]; //The function takes handleName as a parameter, in case the //callback we are overriding was "handle". In that case, //we will need to pass the handle name to handle. var tfw = function(handleName){ if(window.location.hash != ""){ window.location.href = hash; } if(oldFW){ // we might not actually have one //Use apply to set "this" to args, and to try to avoid memory leaks. oldFW.apply(this, [handleName]); } } //Set interceptor function in the right place. if(args["forward"]){ args.forward = tfw; }else if(args["forwardButton"]){ args.forwardButton = tfw; }else if(args["handle"]){ args.handle = tfw; } }else if(dojo.render.html.moz){ // start the timer if(!this.locationTimer){ this.locationTimer = setInterval("dojo.undo.browser.checkLocation();", 200); } } }else{ url = this._loadIframeHistory(); } this.historyStack.push(this._createState(url, args, hash)); }, checkLocation: function(){ //summary: private method. Do not call this directly. if (!this.changingUrl){ var hsl = this.historyStack.length; if((window.location.hash == this.initialHash||window.location.href == this.initialHref)&&(hsl == 1)){ // 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); this.handleBackButton(); return; } // first check to see if we could have gone forward. We always halt on // a no-hash item. if(this.forwardStack.length > 0){ if(this.forwardStack[this.forwardStack.length-1].urlHash == window.location.hash){ this.handleForwardButton(); return; } } // ok, that didn't work, try someplace back in the history stack if((hsl >= 2)&&(this.historyStack[hsl-2])){ if(this.historyStack[hsl-2].urlHash==window.location.hash){ this.handleBackButton(); return; } } } }, iframeLoaded: function(evt, ifrLoc){ //summary: private method. Do not call this directly. if(!dojo.render.html.opera){ var query = this._getUrlQuery(ifrLoc.href); if(query == null){ // alert("iframeLoaded"); // we hit the end of the history, so we should go back if(this.historyStack.length == 1){ this.handleBackButton(); } return; } if(this.moveForward){ // we were expecting it, so it's not either a forward or backward movement this.moveForward = false; return; } //Check the back stack first, since it is more likely. //Note that only one step back or forward is supported. if(this.historyStack.length >= 2 && query == this._getUrlQuery(this.historyStack[this.historyStack.length-2].url)){ this.handleBackButton(); } else if(this.forwardStack.length > 0 && query == this._getUrlQuery(this.forwardStack[this.forwardStack.length-1].url)){ this.handleForwardButton(); } } }, handleBackButton: function(){ //summary: private method. Do not call this directly. //The "current" page is always at the top of the history stack. var current = this.historyStack.pop(); if(!current){ return; } var last = this.historyStack[this.historyStack.length-1]; if(!last && this.historyStack.length == 0){ last = this.initialState; } if (last){ if(last.kwArgs["back"]){ last.kwArgs["back"](); }else if(last.kwArgs["backButton"]){ last.kwArgs["backButton"](); }else if(last.kwArgs["handle"]){ last.kwArgs.handle("back"); } } this.forwardStack.push(current); }, handleForwardButton: function(){ //summary: private method. Do not call this directly. var last = this.forwardStack.pop(); if(!last){ return; } if(last.kwArgs["forward"]){ last.kwArgs.forward(); }else if(last.kwArgs["forwardButton"]){ last.kwArgs.forwardButton(); }else if(last.kwArgs["handle"]){ last.kwArgs.handle("forward"); } this.historyStack.push(last); }, _createState: function(url, args, hash){ //summary: private method. Do not call this directly. return {"url": url, "kwArgs": args, "urlHash": hash}; //Object }, _getUrlQuery: function(url){ //summary: private method. Do not call this directly. var segments = url.split("?"); if (segments.length < 2){ return null; //null } else{ return segments[1]; //String } }, _loadIframeHistory: function(){ //summary: private method. Do not call this directly. var url = dojo.hostenv.getBaseScriptUri()+"iframe_history.html?"+(new Date()).getTime(); this.moveForward = true; dojo.io.setIFrameSrc(this.historyIframe, url, false); return url; //String }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -