📄 history.js
字号:
this._ignoreHistoryCallback = true; // need to quote special chars because we're document writing this id into the the iframe var escapedId = !this.isA.String(id) ? id : id.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") .replace(/\t/g, "\\t").replace(/\r/g, "\\r") .replace(/\n/g, "\\n"); var html = "<HTML><HEAD><TITLE>"+ (title != null ? title : this.historyTitle != null ? this.historyTitle : id)+ "</TITLE></HEAD><BODY><SCRIPT>top.isc.History.historyCallback(window,\""+escapedId+"\");</SCRIPT></BODY></HTML>"; var win = this._historyFrame.contentWindow; win.document.open(); win.document.write(html); win.document.close();},// in IE, this method will always return false before pageLoad because historyState is not// available until then. In Moz/FF, this method will return accurate data before pageLoad.haveHistoryState : function () { if (isc.Browser.isIE && !isc.SA_Page.isLoaded()) { this.logWarn("haveHistoryState() called before pageLoad - this always returns false" +" in IE because state information is not available before pageLoad"); } return this.historyState && this.historyState.stack[0] != null;},_getIsomorphicDir : function () { return window.isomorphicDir ? window.isomorphicDir : "../isomorphic/";},// this method is called before pageLoad at the end of this file_init : function () { this.logInfo("History initializing"); if (this._trackingHistory) return; this._trackingHistory = true; // in safari we only support chaning the top-level URL to something bookmarkable, but // history support is non-existant at present if (isc.Browser.isSafari) return; // write out a form that will store serialized data associated with each history id. We'll // use this to support cross-page transition history in IE. Also, this allows the user to // associate arbitrary data with an id, which will be available in his callback. // // This allows the pattern of registering a callback that simply does eval(data) where // that's appropriate. // // Note: setting visibility:hidden on the form breaks body styling in IE. Setting // display:none on the form breaks page rendering completely in IE. But setting // display:none on the textarea works around that problem. // var formHTML = "<form style='position:absolute;top:-1000px' id='isc_historyForm'>" + "<textarea id='isc_historyField' style='display:none'></textarea></form>"; document.write(formHTML); if (isc.Browser.isIE) { var frameHTML = "<iframe id='isc_historyFrame' src='" + this.getBlankFrameURL() + "' style='position:absolute;visibility:hidden;top:-1000px'></iframe>"; document.write(frameHTML); this._historyFrame = document.getElementById('isc_historyFrame'); // make sure the frame isn't the last thing in the BODY tag - see comments in // createAbsoluteElement() for notes on this. document.write("<span id='isc_history_buffer_marker' style='display:none'></span>"); } // init() calls _completeInit() in Moz, but in IE we must wait for page load before we can // get the form auto-fill data out. if (isc.Browser.isIE) { isc.SA_Page.onLoad(function () { this._completeInit() }, this); } else if (isc.Browser.isMoz || isc.Browser.isOpera) { // in Moz, the form auto-fill values are available synchronously right after // document.write(), but in IE the values are not present until page load. this._completeInit(); }},// getBlankFrameURL(): When we write out the history frame, we need to give it an explicit src URL// to avoid warnings about secure/non-secure items in IE6 / httpsgetBlankFrameURL : function () { if (isc.Page) return isc.Page.getBlankFrameURL(); if (isc.Browser.isIE && ("https:" == window.location.protocol || document.domain != location.hostname )) { // the special directories handling hasn't been set up yet so figure out the URL explicitly var path = window.location.href; if (path.charAt(path.length-1) != "/") { path = path.substring(0, path.lastIndexOf("/") + 1); } path += (window.isomorphicDir || "../isomorphic/"); path += "system/helpers/empty.html"; return path; } return "about:blank"; },_getFormValue : function () { var field = document.getElementById("isc_historyField"); return field ? field.value : null;},_setFormValue : function (value) { var field = document.getElementById("isc_historyField"); if (field) field.value = value;},// this method is called at the end of this file - after pageLoad in IE and synchronously after// init() in Moz/FF_completeInit : function () { // grab the serialized historyState from form auto-fill var historyState = this._getFormValue(); if (historyState) { historyState = new Function("return "+historyState)(); } // historyState = { // stack: [id1, id2, id3 ... idN], // data: { // id1: data, // id2: data // ... // idN: data // } // } // if we had no persisted historyState, init a skeleton if (!historyState) historyState = { stack: [], data: [] }; this.historyState = historyState; this.logInfo("History init complete"); // in Moz, the only way to detect history changes is to watch the URL of the top-level page // for a delta. In IE, we don't need this because we get an onload event from the iframe, // but we still need to watch the top-level URL because the user may use a bookmark to // navigate to a different history entry, or click on a series of links in another page // that points to history ids on this page and since, in that case, there is no navigation // of the iframe, we won't get a history navigation event. // // FIXME: We currently use the Moz workaround for Opera as well, but Opera has the // mindnumbing feature of suspending timeouts whenever the chrome back/forward buttons are // pressed and only resuming them when the mouse moves over the page. So if you're just // hitting back/forward in the chrome, you're out of luck - until you mouse over the page. // Using z/x keyboard shortcuts works and so does the page context menu. This sucks and // is completely stupid because it's not like that's what you'd ever want. This // problem would affect sites that set up timers to do things on the page (like rotate ads) // and also use anchors on the page. User hits an anchor, hits back, and all animations // stop. Nice one guys. this._lastURL = location.href; this._historyTimer = window.setInterval("isc.History._statHistory()", this._historyStatInterval); // In IE, similar logic is triggered by IFRAME load event if (isc.Browser.isMoz || isc.Browser.isOpera) { isc.SA_Page.onLoad(this._fireInitialHistoryCallback, this); }},_fireInitialHistoryCallback : function () { // only fire once if (this._firedInitialHistoryCallback) return; // fire the initial history callback once we a) have a callback registered and b) pageLoad // has occurred. if (this._historyCallback && isc.SA_Page.isLoaded()) { this._firedInitialHistoryCallback = true; // if we have history state, then it's a history transition for the initial load. var id = this._getHistory(location.href); if (this.haveHistoryState()) this._fireHistoryCallback(id); }},// helper methods to get and add history to URLs. Anchor values are automatically// encoded/decoded by these._addHistory : function (url, id) { var match = url.match(/([^#]*).*/); return match[1]+"#"+encodeURIComponent(id);},_getHistory : function (url) { var match = location.href.match(/([^#]*)#(.*)/); return match ? decodeURIComponent(match[2]) : null;},_addFrameHistory : function (url, id) { // see notes in _restoreNextId() for why we're adding this second param return url+"?ba="+encodeURIComponent(id);},_getFrameHistory : function (url) { var match = url.match(/.*\?ba=(.*)/); return match ? decodeURIComponent(match[1]) : null;},// How often do we poll to see if the URL has changed? _historyStatInterval: 100,_saveHistoryState : function() { if (isc.Comm) { this._setFormValue(isc.Comm.serialize(this.historyState)); } },// Moz, Opera_statHistory : function () { if (location.href != this._lastURL) { var id = this._getHistory(location.href); this._fireHistoryCallback(id); } this._lastURL = location.href;},// IE only - called by callback.htmlhistoryCallback : function (win, currentFrameHistoryId) { if (currentFrameHistoryId == null) currentFrameHistoryId = this._getFrameHistory(win.location.href); var newURL = this._addHistory(location.href, currentFrameHistoryId); // navigation has occurred, update the top-level URL to reflect the current id if (isc.SA_Page.isLoaded()) { location.href = newURL; // update _lastURL so that _statHistory() doesn't double-fire this callback this._lastURL = newURL; } else { // update _lastURL so that _statHistory() doesn't double-fire this callback isc.SA_Page.onLoad(function () { location.href = this._addHistory(location.href, currentFrameHistoryId); this._lastURL = newURL; }, this); } // if this callback is the result of the creation of a new synthetic history entry, don't // fire the callback if (this._ignoreHistoryCallback) { this._ignoreHistoryCallback = false; return; } if (isc.SA_Page.isLoaded()) { this._fireHistoryCallback(currentFrameHistoryId); } else { isc.SA_Page.onLoad(function () { this._fireHistoryCallback(currentFrameHistoryId) }, this); }},_fireHistoryCallback : function (id) { // store for getLastHistoryId() this._lastHistoryId = id; if (!this._historyCallback) { this.logWarn("ready to fire history callback, but no callback registered." +"Please call isc.History.registerCallback() before pageLoad." +" If you can't register your callback before pageLoad, you" +" can call isc.History.getCurrentHistoryId() to get the ID" +" when you're ready."); return; } // we must actually have historyState in order to fire a callback. If there's no state, // there are no synthetic history entries as far as this page load is concerned. if (!this.haveHistoryState()) return; if (id == "init") id = null; var callback = this._historyCallback; this.logDebug("history callback: " + id); if (isc.Class && this.isA.String(callback)) { isc.Class.fireCallback(callback, ["id", "data"], [id, this.historyState.data[id]]); } else { callback = isc.addProperties({}, callback); callback.args = [id, this.historyState.data[id]]; this.fireSimpleCallback(callback); }}}); // end History class// mandatory pre-page load initisc.History._init();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -