// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 //============================================ // Wayback Common JS Library //============================================ var WB_wombat_replayServer; var WB_wombat_replayPrefix; var WB_wombat_replayDatePrefix; var WB_wombat_captureDatePart; var WB_wombat_origHost; //Location objects var WB_wombat_self_location; var WB_wombat_top_location; var WB_wombat_opener_location; // Domain var WB_wombat_document_domain; //function to allow jquery expando requests (http://stackoverflow.com/questions/7200722/jquery-expando-properties), //which return a function that has its name defined in a parameter of the request, to be executed. we rewrite the function call elsewhere (see //ArchiveUrlReplay.xml) and then define it here to ensure it exists. expando function include current timestamp so we can never replay them without //overriding default expando behavior function jQueryREWRITTEN_BY_WAYBACK() { o=arguments; } function WB_Get_Domain(href) { var a = document.createElement('a'); a.href = href; return a.protocol + "//" + a.hostname; } function WB_StripPort(str) { var hostWithPort = str.match(/^http:\/\/[\w\d@.-]+:\d+/); if (hostWithPort) { var hostName = hostWithPort[0].substr(0, hostWithPort[0].lastIndexOf(':')); return hostName + str.substr(hostWithPort[0].length); } return str; } function WB_IsHostUrl(str) { // Good guess that's its a hostname if (str.indexOf("www.") == 0) { return true; } // hostname:port (port required) var matches = str.match(/^[\w-]+(\.[\w-_]+)+(:\d+)(\/|$)/); if (matches && (matches[0].length < 64)) { return true; } // ip:port matches = str.match(/^\d+\.\d+\.\d+\.\d+(:\d+)?(\/|$)/); if (matches && (matches[0].length < 64)) { return true; } return false; } function WB_RewriteUrl(url) { var httpPrefix = "http://"; var httpsPrefix = "https://"; if (!url) { return url; } // If not dealing with a string, get string version and try to convert it if ((typeof url) != "string") { url = url.toString(); } // If starts with prefix, no rewriting needed // Only check replay prefix (no date) as date may be different for each capture if (url.indexOf(WB_wombat_replayServer) == 0) { return url; } // If server relative url, add prefix and original host if (WB_IsRelativeUrl(url)) { // Already a relative url, don't make any changes! if (url.indexOf(WB_wombat_captureDatePart) >= 0) { return url; } return WB_wombat_replayDatePrefix + WB_wombat_origHost + url; } // If full url starting with http:// add http prefix if (url.indexOf(httpPrefix) == 0) { return WB_wombat_replayDatePrefix.replace("https://", "http://") + url; } // If full url starting with https:// add https prefix if (url.indexOf(httpsPrefix) == 0) { return WB_wombat_replayDatePrefix.replace("http://", "https://") + url; } // May or may not be a hostname, call function to determine // If it is, add the prefix and make sure port is removed if (WB_IsHostUrl(url)) { return WB_wombat_replayDatePrefix + httpPrefix + url; } return url; } //determine if url is server or path relative or not function WB_IsRelativeUrl(url) { if (url) { var urlType = (typeof url); if (urlType == "string") { return (url.charAt(0) == "/" || url.charAt(0) == "."); } else if (urlType == "object") { return (url.href && (url.href.charAt(0) == "/" || url.charAt(0) == ".")); } } return false; } //http://wayback.archive-it.org/1000000016/20140801164720/http://www.w3.org/2000/svg -> http://www.w3.org/2000/svg - for https://webarchive.jira.com/browse/ARI-3906 function WB_UnRewriteUrl(url) { return WB_ExtractOrig(url); } function WB_CopyObjectFields(obj) { var newObj = {}; for (prop in obj) { if ((typeof obj[prop]) != "function") { newObj[prop] = obj[prop]; } } return newObj; } function WB_ExtractOrigNoProtocol(href) { var lHref = WB_ExtractOrig(href); if (lHref.slice(0, 5) == "http:") { return lHref.slice(5); } else if (lHref.slice(0, 6) == "https:") { return lHref.slice(6); } return lHref; } function WB_ExtractOrig(href) { if (!href) { return ""; } href = href.toString(); var index = href.indexOf("/http", 1); if (index > 0) { return href.substr(index + 1); } else { return href; } } //solution from http://stackoverflow.com/questions/4497531/javascript-get-url-path function WB_GetPath(href) { var a = document.createElement('a'); a.href = href; return a.pathname; } //solution from http://stackoverflow.com/questions/4497531/javascript-get-url-path //specifically, user stecb's answer function WB_ExtractOrigPathname(href) { var origHref = WB_ExtractOrig(href); return WB_GetPath(origHref); } function WB_ExtractOrigPathnameAndQueryString(href) { var origHref = WB_ExtractOrig(href); var a = document.createElement('a'); a.href = origHref; if (WB_EndsWith(origHref, "?")) { return a.pathname + "?"; } return a.pathname + a.search; } function WB_EndsWith(str, endingStr) { return str.indexOf(endingStr, str.length - endingStr.length) !== -1; } //solution from http://stackoverflow.com/questions/4497531/javascript-get-url-path function WB_ExtractOrigSearch(href) { var origHref = WB_ExtractOrig(href); var a = document.createElement('a'); a.href = origHref; return a.search; } // rewrite orig href to https if it is http and the page is being loaded as https // this is to deal with Firefox mixed content security which restricts loading http urls from a page // loaded over https function WB_fixProtocol(href) { if (!href) { return ""; } if (location.protocol == "https:") { if (href.slice(0, 5) == "http:") { href = "https:" + href.slice(5); } } return href; } function WB_CopyLocationObj(loc) { var newLoc = WB_CopyObjectFields(loc); newLoc._origLoc = loc; newLoc._origHref = loc.href; // Rewrite replace and assign functions newLoc.replace = function(url) { this._origLoc.replace(WB_RewriteUrl(url)); }; newLoc.assign = function(url) { this._origLoc.assign(WB_RewriteUrl(url)); }; newLoc.reload = function() { this._origLoc.reload(); }; newLoc.href = WB_fixProtocol(WB_ExtractOrig(newLoc._origHref)); newLoc.pathname = WB_ExtractOrigPathname(newLoc._origHref); newLoc.search = WB_ExtractOrigSearch(newLoc._origHref); newLoc.toString = function() { return this.href; }; newLoc.hash = loc.hash; newLoc.lasthash = loc.hash; newLoc.lastSearch = newLoc.search return newLoc; } //override createElementNS JS function in order to ensure namespace is correct - for https://webarchive.jira.com/browse/ARI-3906 function WB_CreateElementNS(namespace, elementName) { namespace = WB_UnRewriteUrl(namespace); return document.createElementNS(namespace, elementName); } function WB_wombat_updateLoc(reqHref, origHref, loc, wbSearchLoc) { if (reqHref) { if (WB_IsRelativeUrl(reqHref)) { //for relative paths, just compare the paths + query string, not full urls if (WB_ExtractOrigPathnameAndQueryString(origHref) != reqHref) { loc.href = WB_RewriteUrl(reqHref); return true; } } else { //for full urls, compare everything but leading protocol (http or https) if (WB_ExtractOrigNoProtocol(origHref) != WB_ExtractOrigNoProtocol(reqHref)) { loc.href = WB_RewriteUrl(reqHref); return true; } } } if (wbSearchLoc) { if (loc.search != wbSearchLoc) { console.log('replacing browser location.search with %s', wbSearchLoc); loc.search = wbSearchLoc; } } return false; } function WB_wombat_checkLocationChange(wbLoc, isTop) { var has_updated = null; var locType = (typeof wbLoc); var location = (isTop ? window.top.location : window.location); // String has been assigned to location, so assign it if (locType == "string") { has_updated = WB_wombat_updateLoc(wbLoc, location.href, location); } else if (locType == "object") { var search = wbLoc.search != wbLoc.lastSearch ? wbLoc.search : null; has_updated = WB_wombat_updateLoc(wbLoc.href, wbLoc._origHref, location, search); } if (WB_wombat_self_location.hash != WB_wombat_self_location.lasthash) { //if wombat hash has been updated, make sure it's in sync with window.location hash window.location.hash = WB_wombat_self_location.hash; } else if (window.location.hash != WB_wombat_self_location.hash) { //if window.location.hash has been updated before wombat hash, handle this here WB_wombat_self_location.hash = window.location.hash; } WB_wombat_self_location.lasthash = WB_wombat_self_location.hash; return has_updated; } var wombat_updating = false; function WB_wombat_checkLocations() { if (wombat_updating) { return false; } wombat_updating = true; var updated_self = WB_wombat_checkLocationChange(document.WB_wombat_self_location, false); if (!updated_self) { updated_self = WB_wombat_checkLocationChange(WB_wombat_self_location, false); } var updated_top = null; if (document.WB_wombat_self_location != WB_wombat_top_location) { updated_top = WB_wombat_checkLocationChange(WB_wombat_top_location, true); if (!updated_top) { if (WB_wombat_self_location != WB_wombat_top_location) { updated_top = WB_wombat_checkLocationChange(WB_wombat_top_location, true); } } } //for https://webarchive.jira.com/browse/ARI-3955 if (updated_self || updated_top) { return false; } wombat_updating = false; } //copied from https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage function WB_wombat_Override_LocalStorage() { Object.defineProperty(window, "localStorage", new (function () { var aKeys = [], oStorage = {}; Object.defineProperty(oStorage, "getItem", { value: function (sKey) { return sKey ? (this[sKey] ? this[sKey] : null) : null; }, writable: false, configurable: false, enumerable: false }); Object.defineProperty(oStorage, "key", { value: function (nKeyId) { return aKeys[nKeyId]; }, writable: false, configurable: false, enumerable: false }); Object.defineProperty(oStorage, "setItem", { value: function (sKey, sValue) { if(!sKey) { return; } document.cookie = escape(sKey) + "=" + escape(sValue) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/"; }, writable: false, configurable: false, enumerable: false }); Object.defineProperty(oStorage, "length", { get: function () { return aKeys.length; }, configurable: false, enumerable: false }); Object.defineProperty(oStorage, "removeItem", { value: function (sKey) { if(!sKey) { return; } document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"; }, writable: false, configurable: false, enumerable: false }); this.get = function () { var iThisIndx; for (var sKey in oStorage) { iThisIndx = aKeys.indexOf(sKey); if (iThisIndx === -1) { oStorage.setItem(sKey, oStorage[sKey]); } else { aKeys.splice(iThisIndx, 1); } delete oStorage[sKey]; } for (aKeys; aKeys.length > 0; aKeys.splice(0, 1)) { oStorage.removeItem(aKeys[0]); } for (var aCouple, iKey, nIdx = 0, aCouples = document.cookie.split(/\s*;\s*/); nIdx < aCouples.length; nIdx++) { aCouple = aCouples[nIdx].split(/\s*=\s*/); if (aCouple.length > 1) { oStorage[iKey = unescape(aCouple[0])] = unescape(aCouple[1]); aKeys.push(iKey); } } return oStorage; }; this.configurable = false; this.enumerable = true; })()); } function WB_wombat_Init(replayPrefix, captureDate, origHost) { WB_wombat_replayServer = location.protocol + "//" + location.host; try { var collectionId = /https?:\/\/wayback\..*archive-it\.org\/([\d]+(?:-test)?)/.exec(replayPrefix)[1]; WB_wombat_replayPrefix = WB_wombat_replayServer + "/" + collectionId + "/"; } catch (exc) { WB_wombat_replayPrefix = replayPrefix; } WB_wombat_replayDatePrefix = WB_wombat_replayPrefix + captureDate + "/"; WB_wombat_captureDatePart = "/" + captureDate + "/"; WB_wombat_origHost = "http://" + origHost; WB_wombat_self_location = WB_CopyLocationObj(window.self.location); WB_wombat_top_location = ((window.self.location != window.top.location) ? WB_CopyLocationObj(window.top.location) : WB_wombat_self_location); WB_wombat_opener_location = null; //try catch for https://webarchive.jira.com/browse/ARI-3715 try { WB_wombat_opener_location = (window.opener ? WB_CopyLocationObj(window.opener.location) : null); } catch (err) { console.log(err); } //WB_wombat_document_domain = document.domain; WB_wombat_document_domain = origHost; // For https://webarchive.jira.com/browse/ARI-3985 document.WB_wombat_self_location = WB_wombat_self_location; //override window.open function so that a new window will have WB_wombat_self_location as a member since wombat //rewriting may change window.location to window.WB_wombat_self_location //for https://webarchive.jira.com/browse/ARI-4006 var originalOpenFunction = window.open; window.open = function (url, windowName, windowFeatures) { var newWindow = originalOpenFunction(url, windowName, windowFeatures); newWindow.WB_wombat_self_location = newWindow.self.location; return newWindow; }; var originalHistoryPushStateFunction = history.pushState; //override pushState and replaceState history functions so we can retain the correct archival format //livesiteurl in the browsers location bar //if the site is using these methods. for https://webarchive.jira.com/browse/ARI-4068 history.pushState = function (stateObject, title, url) { var rewrittenUrl = null; if (url) { rewrittenUrl = WB_GetPath(WB_RewriteUrl(WB_GetPath(url))) + WB_ExtractOrigSearch(url); } if (stateObject) { if (stateObject.path) { stateObject.path = WB_GetPath(WB_RewriteUrl(WB_GetPath(stateObject.path))) + WB_ExtractOrigSearch(stateObject.path); } } originalHistoryPushStateFunction.call(history, stateObject, title, rewrittenUrl); }; var originalHistoryReplaceStateFunction = history.replaceState; history.replaceState = function (stateObject, title, url) { var rewrittenUrl = null; if (url) { rewrittenUrl = WB_GetPath(WB_RewriteUrl(WB_GetPath(url))) + WB_ExtractOrigSearch(url); } if (stateObject) { if (stateObject.path) { stateObject.path = WB_GetPath(WB_RewriteUrl(WB_GetPath(stateObject.path))) + WB_ExtractOrigSearch(stateObject.path); } } originalHistoryReplaceStateFunction.call(history, stateObject, title, rewrittenUrl); }; window.originalPostMessageFunction = window.postMessage; window.WB_PostMessage_Fixup = function(target, message, targetOrigin, transfer) { target.originalPostMessageFunction.call(target, message, targetOrigin, transfer); } window.WB_PostMessage = function(callingWindow, message, targetOrigin, transfer) { var rewrittenTargetOrigin; if (targetOrigin) { rewrittenTargetOrigin = WB_Get_Domain(WB_RewriteUrl(targetOrigin)); } //detect condition of window containing current function not //being the window from which the function was called if (window !== callingWindow) { //make sure to call postMessage from the same window the live site would call from //this may not occur as each window (iframes included) has an overidden WB_PostMessage callingWindow.WB_PostMessage_Fixup(window, message, rewrittenTargetOrigin, transfer); } else { window.originalPostMessageFunction.call(window, message, rewrittenTargetOrigin, transfer); } } document.WB_wombat_self_location = WB_wombat_self_location; //from http://stackoverflow.com/questions/2638292/after-travelling-back-in-firefox-history-javascript-wont-run - for https://webarchive.jira.com/browse/ARI-4118 window.onunload = function(){}; WB_Wombat_SetCookies(WB_wombat_self_location._origHref, location.protocol + "//" + origHost, replayPrefix.split("/")[3], captureDate); //for https://webarchive.jira.com/browse/ARI-4161 - error in Scott Reed's Firefox: NS_ERROR_DOM_QUOTA_REACHED Persistent storage maximum size reached try { WB_wombat_Override_LocalStorage(); } catch (e) { console.log("WB_wombat_Override_LocalStorage error: " + e); } var proxied = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function() { //only set withCredentials == true if request is to wayback and ready state is correct for withCredentials //otherwise withCredentials == true will block requests to analytics site. if ((this.readyState == 0 || this.readyState == 1) && (arguments[1].indexOf(WB_wombat_replayPrefix) == 0 || arguments[1].indexOf("/") == 0)) { this.withCredentials=true; } return proxied.apply(this, [].slice.call(arguments)); }; } // determine if current page executing javascript is an embedded page or not function WB_Wombat_IsEmbedded() { return window.self !== window.top; } function WB_Wombat_SetCookies(origHref, origHost, collectionId, captureDate) { //only set wayback.initiatingpage cookie for "top-level" pages, otherwise, Wayback QA could mark down missing //urls under the wrong containing page since wayback.initiatingpage cookie is used to determine //the containing page if (!WB_Wombat_IsEmbedded()) { document.cookie="wayback.initiatingpage=" + encodeURIComponent(origHref) + "; path=/"; } document.cookie="wayback.archivalhost=" + encodeURIComponent(origHost) + "; path=/"; document.cookie="wayback.collectionid=" + collectionId + "; path=/"; document.cookie="wayback.timestamp=" + captureDate + "; path=/"; } //copied from http://stackoverflow.com/questions/1833588/javascript-clone-a-function Function.prototype.clone = function() { var cloneObj = this; if(this.__isClone) { cloneObj = this.__clonedFrom; } var temp = function() { return cloneObj.apply(this, arguments); }; for(var key in this) { temp[key] = this[key]; } temp.__isClone = true; temp.__clonedFrom = cloneObj; return temp; }; // Check quickly after page load setTimeout(WB_wombat_checkLocations, 100); //setTimeout(WB_wombat_checkLocations, 1000); // Check periodically every few seconds setInterval(WB_wombat_checkLocations, 500); // @license-end