Best Python code snippet using Kiwi_python
history.js
Source:history.js
1/**2 * History.js Core3 * @author Benjamin Arthur Lupton <contact@balupton.com>4 * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>5 * @license New BSD License <http://creativecommons.org/licenses/BSD/>6 */7(function(window,undefined){8 "use strict";9 // ========================================================================10 // Initialise11 // Localise Globals12 var13 console = window.console||undefined, // Prevent a JSLint complain14 document = window.document, // Make sure we are using the correct document15 navigator = window.navigator, // Make sure we are using the correct navigator16 sessionStorage = window.sessionStorage||false, // sessionStorage17 setTimeout = window.setTimeout,18 clearTimeout = window.clearTimeout,19 setInterval = window.setInterval,20 clearInterval = window.clearInterval,21 JSON = window.JSON,22 alert = window.alert,23 History = window.History = window.History||{}, // Public History Object24 history = window.history; // Old History Object25 // MooTools Compatibility26 JSON.stringify = JSON.stringify||JSON.encode;27 JSON.parse = JSON.parse||JSON.decode;28 // Check Existence29 if ( typeof History.init !== 'undefined' ) {30 throw new Error('History.js Core has already been loaded...');31 }32 // Initialise History33 History.init = function(){34 // Check Load Status of Adapter35 if ( typeof History.Adapter === 'undefined' ) {36 return false;37 }38 // Check Load Status of Core39 if ( typeof History.initCore !== 'undefined' ) {40 History.initCore();41 }42 // Check Load Status of HTML4 Support43 if ( typeof History.initHtml4 !== 'undefined' ) {44 History.initHtml4();45 }46 // Return true47 return true;48 };49 // ========================================================================50 // Initialise Core51 // Initialise Core52 History.initCore = function(){53 // Initialise54 if ( typeof History.initCore.initialized !== 'undefined' ) {55 // Already Loaded56 return false;57 }58 else {59 History.initCore.initialized = true;60 }61 // ====================================================================62 // Options63 /**64 * History.options65 * Configurable options66 */67 History.options = History.options||{};68 /**69 * History.options.hashChangeInterval70 * How long should the interval be before hashchange checks71 */72 History.options.hashChangeInterval = History.options.hashChangeInterval || 100;73 /**74 * History.options.safariPollInterval75 * How long should the interval be before safari poll checks76 */77 History.options.safariPollInterval = History.options.safariPollInterval || 500;78 /**79 * History.options.doubleCheckInterval80 * How long should the interval be before we perform a double check81 */82 History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;83 /**84 * History.options.storeInterval85 * How long should we wait between store calls86 */87 History.options.storeInterval = History.options.storeInterval || 1000;88 /**89 * History.options.busyDelay90 * How long should we wait between busy events91 */92 History.options.busyDelay = History.options.busyDelay || 250;93 /**94 * History.options.debug95 * If true will enable debug messages to be logged96 */97 History.options.debug = History.options.debug || false;98 /**99 * History.options.initialTitle100 * What is the title of the initial state101 */102 History.options.initialTitle = History.options.initialTitle || document.title;103 // ====================================================================104 // Interval record105 /**106 * History.intervalList107 * List of intervals set, to be cleared when document is unloaded.108 */109 History.intervalList = [];110 /**111 * History.clearAllIntervals112 * Clears all setInterval instances.113 */114 History.clearAllIntervals = function(){115 var i, il = History.intervalList;116 if (typeof il !== "undefined" && il !== null) {117 for (i = 0; i < il.length; i++) {118 clearInterval(il[i]);119 }120 History.intervalList = null;121 }122 };123 // ====================================================================124 // Debug125 /**126 * History.debug(message,...)127 * Logs the passed arguments if debug enabled128 */129 History.debug = function(){130 if ( (History.options.debug||false) ) {131 History.log.apply(History,arguments);132 }133 };134 /**135 * History.log(message,...)136 * Logs the passed arguments137 */138 History.log = function(){139 // Prepare140 var141 consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'),142 textarea = document.getElementById('log'),143 message,144 i,n,145 args,arg146 ;147 // Write to Console148 if ( consoleExists ) {149 args = Array.prototype.slice.call(arguments);150 message = args.shift();151 if ( typeof console.debug !== 'undefined' ) {152 console.debug.apply(console,[message,args]);153 }154 else {155 console.log.apply(console,[message,args]);156 }157 }158 else {159 message = ("\n"+arguments[0]+"\n");160 }161 // Write to log162 for ( i=1,n=arguments.length; i<n; ++i ) {163 arg = arguments[i];164 if ( typeof arg === 'object' && typeof JSON !== 'undefined' ) {165 try {166 arg = JSON.stringify(arg);167 }168 catch ( Exception ) {169 // Recursive Object170 }171 }172 message += "\n"+arg+"\n";173 }174 // Textarea175 if ( textarea ) {176 textarea.value += message+"\n-----\n";177 textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;178 }179 // No Textarea, No Console180 else if ( !consoleExists ) {181 alert(message);182 }183 // Return true184 return true;185 };186 // ====================================================================187 // Emulated Status188 /**189 * History.getInternetExplorerMajorVersion()190 * Get's the major version of Internet Explorer191 * @return {integer}192 * @license Public Domain193 * @author Benjamin Arthur Lupton <contact@balupton.com>194 * @author James Padolsey <https://gist.github.com/527683>195 */196 History.getInternetExplorerMajorVersion = function(){197 var result = History.getInternetExplorerMajorVersion.cached =198 (typeof History.getInternetExplorerMajorVersion.cached !== 'undefined')199 ? History.getInternetExplorerMajorVersion.cached200 : (function(){201 var v = 3,202 div = document.createElement('div'),203 all = div.getElementsByTagName('i');204 while ( (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0] ) {}205 return (v > 4) ? v : false;206 })()207 ;208 return result;209 };210 /**211 * History.isInternetExplorer()212 * Are we using Internet Explorer?213 * @return {boolean}214 * @license Public Domain215 * @author Benjamin Arthur Lupton <contact@balupton.com>216 */217 History.isInternetExplorer = function(){218 var result =219 History.isInternetExplorer.cached =220 (typeof History.isInternetExplorer.cached !== 'undefined')221 ? History.isInternetExplorer.cached222 : Boolean(History.getInternetExplorerMajorVersion())223 ;224 return result;225 };226 /**227 * History.emulated228 * Which features require emulating?229 */230 History.emulated = {231 pushState: !Boolean(232 window.history && window.history.pushState && window.history.replaceState233 && !(234 (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */235 || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */236 )237 ),238 hashChange: Boolean(239 !(('onhashchange' in window) || ('onhashchange' in document))240 ||241 (History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)242 )243 };244 /**245 * History.enabled246 * Is History enabled?247 */248 History.enabled = !History.emulated.pushState;249 /**250 * History.bugs251 * Which bugs are present252 */253 History.bugs = {254 /**255 * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call256 * https://bugs.webkit.org/show_bug.cgi?id=56249257 */258 setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),259 /**260 * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions261 * https://bugs.webkit.org/show_bug.cgi?id=42940262 */263 safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),264 /**265 * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)266 */267 ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8),268 /**269 * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event270 */271 hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7)272 };273 /**274 * History.isEmptyObject(obj)275 * Checks to see if the Object is Empty276 * @param {Object} obj277 * @return {boolean}278 */279 History.isEmptyObject = function(obj) {280 for ( var name in obj ) {281 return false;282 }283 return true;284 };285 /**286 * History.cloneObject(obj)287 * Clones a object and eliminate all references to the original contexts288 * @param {Object} obj289 * @return {Object}290 */291 History.cloneObject = function(obj) {292 var hash,newObj;293 if ( obj ) {294 hash = JSON.stringify(obj);295 newObj = JSON.parse(hash);296 }297 else {298 newObj = {};299 }300 return newObj;301 };302 // ====================================================================303 // URL Helpers304 /**305 * History.getRootUrl()306 * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"307 * @return {String} rootUrl308 */309 History.getRootUrl = function(){310 // Create311 var rootUrl = document.location.protocol+'//'+(document.location.hostname||document.location.host);312 if ( document.location.port||false ) {313 rootUrl += ':'+document.location.port;314 }315 rootUrl += '/';316 // Return317 return rootUrl;318 };319 /**320 * History.getBaseHref()321 * Fetches the `href` attribute of the `<base href="...">` element if it exists322 * @return {String} baseHref323 */324 History.getBaseHref = function(){325 // Create326 var327 baseElements = document.getElementsByTagName('base'),328 baseElement = null,329 baseHref = '';330 // Test for Base Element331 if ( baseElements.length === 1 ) {332 // Prepare for Base Element333 baseElement = baseElements[0];334 baseHref = baseElement.href.replace(/[^\/]+$/,'');335 }336 // Adjust trailing slash337 baseHref = baseHref.replace(/\/+$/,'');338 if ( baseHref ) baseHref += '/';339 // Return340 return baseHref;341 };342 /**343 * History.getBaseUrl()344 * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)345 * @return {String} baseUrl346 */347 History.getBaseUrl = function(){348 // Create349 var baseUrl = History.getBaseHref()||History.getBasePageUrl()||History.getRootUrl();350 // Return351 return baseUrl;352 };353 /**354 * History.getPageUrl()355 * Fetches the URL of the current page356 * @return {String} pageUrl357 */358 History.getPageUrl = function(){359 // Fetch360 var361 State = History.getState(false,false),362 stateUrl = (State||{}).url||document.location.href,363 pageUrl;364 // Create365 pageUrl = stateUrl.replace(/\/+$/,'').replace(/[^\/]+$/,function(part,index,string){366 return (/\./).test(part) ? part : part+'/';367 });368 // Return369 return pageUrl;370 };371 /**372 * History.getBasePageUrl()373 * Fetches the Url of the directory of the current page374 * @return {String} basePageUrl375 */376 History.getBasePageUrl = function(){377 // Create378 var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){379 return (/[^\/]$/).test(part) ? '' : part;380 }).replace(/\/+$/,'')+'/';381 // Return382 return basePageUrl;383 };384 /**385 * History.getFullUrl(url)386 * Ensures that we have an absolute URL and not a relative URL387 * @param {string} url388 * @param {Boolean} allowBaseHref389 * @return {string} fullUrl390 */391 History.getFullUrl = function(url,allowBaseHref){392 // Prepare393 var fullUrl = url, firstChar = url.substring(0,1);394 allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref;395 // Check396 if ( /[a-z]+\:\/\//.test(url) ) {397 // Full URL398 }399 else if ( firstChar === '/' ) {400 // Root URL401 fullUrl = History.getRootUrl()+url.replace(/^\/+/,'');402 }403 else if ( firstChar === '#' ) {404 // Anchor URL405 fullUrl = History.getPageUrl().replace(/#.*/,'')+url;406 }407 else if ( firstChar === '?' ) {408 // Query URL409 fullUrl = History.getPageUrl().replace(/[\?#].*/,'')+url;410 }411 else {412 // Relative URL413 if ( allowBaseHref ) {414 fullUrl = History.getBaseUrl()+url.replace(/^(\.\/)+/,'');415 } else {416 fullUrl = History.getBasePageUrl()+url.replace(/^(\.\/)+/,'');417 }418 // We have an if condition above as we do not want hashes419 // which are relative to the baseHref in our URLs420 // as if the baseHref changes, then all our bookmarks421 // would now point to different locations422 // whereas the basePageUrl will always stay the same423 }424 // Return425 return fullUrl.replace(/\#$/,'');426 };427 /**428 * History.getShortUrl(url)429 * Ensures that we have a relative URL and not a absolute URL430 * @param {string} url431 * @return {string} url432 */433 History.getShortUrl = function(url){434 // Prepare435 var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl();436 // Trim baseUrl437 if ( History.emulated.pushState ) {438 // We are in a if statement as when pushState is not emulated439 // The actual url these short urls are relative to can change440 // So within the same session, we the url may end up somewhere different441 shortUrl = shortUrl.replace(baseUrl,'');442 }443 // Trim rootUrl444 shortUrl = shortUrl.replace(rootUrl,'/');445 // Ensure we can still detect it as a state446 if ( History.isTraditionalAnchor(shortUrl) ) {447 shortUrl = './'+shortUrl;448 }449 // Clean It450 shortUrl = shortUrl.replace(/^(\.\/)+/g,'./').replace(/\#$/,'');451 // Return452 return shortUrl;453 };454 // ====================================================================455 // State Storage456 /**457 * History.store458 * The store for all session specific data459 */460 History.store = {};461 /**462 * History.idToState463 * 1-1: State ID to State Object464 */465 History.idToState = History.idToState||{};466 /**467 * History.stateToId468 * 1-1: State String to State ID469 */470 History.stateToId = History.stateToId||{};471 /**472 * History.urlToId473 * 1-1: State URL to State ID474 */475 History.urlToId = History.urlToId||{};476 /**477 * History.storedStates478 * Store the states in an array479 */480 History.storedStates = History.storedStates||[];481 /**482 * History.savedStates483 * Saved the states in an array484 */485 History.savedStates = History.savedStates||[];486 /**487 * History.noramlizeStore()488 * Noramlize the store by adding necessary values489 */490 History.normalizeStore = function(){491 History.store.idToState = History.store.idToState||{};492 History.store.urlToId = History.store.urlToId||{};493 History.store.stateToId = History.store.stateToId||{};494 };495 /**496 * History.getState()497 * Get an object containing the data, title and url of the current state498 * @param {Boolean} friendly499 * @param {Boolean} create500 * @return {Object} State501 */502 History.getState = function(friendly,create){503 // Prepare504 if ( typeof friendly === 'undefined' ) { friendly = true; }505 if ( typeof create === 'undefined' ) { create = true; }506 // Fetch507 var State = History.getLastSavedState();508 // Create509 if ( !State && create ) {510 State = History.createStateObject();511 }512 // Adjust513 if ( friendly ) {514 State = History.cloneObject(State);515 State.url = State.cleanUrl||State.url;516 }517 // Return518 return State;519 };520 /**521 * History.getIdByState(State)522 * Gets a ID for a State523 * @param {State} newState524 * @return {String} id525 */526 History.getIdByState = function(newState){527 // Fetch ID528 var id = History.extractId(newState.url),529 str;530 531 if ( !id ) {532 // Find ID via State String533 str = History.getStateString(newState);534 if ( typeof History.stateToId[str] !== 'undefined' ) {535 id = History.stateToId[str];536 }537 else if ( typeof History.store.stateToId[str] !== 'undefined' ) {538 id = History.store.stateToId[str];539 }540 else {541 // Generate a new ID542 while ( true ) {543 id = (new Date()).getTime() + String(Math.random()).replace(/\D/g,'');544 if ( typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined' ) {545 break;546 }547 }548 // Apply the new State to the ID549 History.stateToId[str] = id;550 History.idToState[id] = newState;551 }552 }553 // Return ID554 return id;555 };556 /**557 * History.normalizeState(State)558 * Expands a State Object559 * @param {object} State560 * @return {object}561 */562 History.normalizeState = function(oldState){563 // Variables564 var newState, dataNotEmpty;565 // Prepare566 if ( !oldState || (typeof oldState !== 'object') ) {567 oldState = {};568 }569 // Check570 if ( typeof oldState.normalized !== 'undefined' ) {571 return oldState;572 }573 // Adjust574 if ( !oldState.data || (typeof oldState.data !== 'object') ) {575 oldState.data = {};576 }577 // ----------------------------------------------------------------578 // Create579 newState = {};580 newState.normalized = true;581 newState.title = oldState.title||'';582 newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));583 newState.hash = History.getShortUrl(newState.url);584 newState.data = History.cloneObject(oldState.data);585 // Fetch ID586 newState.id = History.getIdByState(newState);587 // ----------------------------------------------------------------588 // Clean the URL589 newState.cleanUrl = newState.url.replace(/\??\&_suid.*/,'');590 newState.url = newState.cleanUrl;591 // Check to see if we have more than just a url592 dataNotEmpty = !History.isEmptyObject(newState.data);593 // Apply594 if ( newState.title || dataNotEmpty ) {595 // Add ID to Hash596 newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/,'');597 if ( !/\?/.test(newState.hash) ) {598 newState.hash += '?';599 }600 newState.hash += '&_suid='+newState.id;601 }602 // Create the Hashed URL603 newState.hashedUrl = History.getFullUrl(newState.hash);604 // ----------------------------------------------------------------605 // Update the URL if we have a duplicate606 if ( (History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState) ) {607 newState.url = newState.hashedUrl;608 }609 // ----------------------------------------------------------------610 // Return611 return newState;612 };613 /**614 * History.createStateObject(data,title,url)615 * Creates a object based on the data, title and url state params616 * @param {object} data617 * @param {string} title618 * @param {string} url619 * @return {object}620 */621 History.createStateObject = function(data,title,url){622 // Hashify623 var State = {624 'data': data,625 'title': title,626 'url': url627 };628 // Expand the State629 State = History.normalizeState(State);630 // Return object631 return State;632 };633 /**634 * History.getStateById(id)635 * Get a state by it's UID636 * @param {String} id637 */638 History.getStateById = function(id){639 // Prepare640 id = String(id);641 // Retrieve642 var State = History.idToState[id] || History.store.idToState[id] || undefined;643 // Return State644 return State;645 };646 /**647 * Get a State's String648 * @param {State} passedState649 */650 History.getStateString = function(passedState){651 // Prepare652 var State, cleanedState, str;653 // Fetch654 State = History.normalizeState(passedState);655 // Clean656 cleanedState = {657 data: State.data,658 title: passedState.title,659 url: passedState.url660 };661 // Fetch662 str = JSON.stringify(cleanedState);663 // Return664 return str;665 };666 /**667 * Get a State's ID668 * @param {State} passedState669 * @return {String} id670 */671 History.getStateId = function(passedState){672 // Prepare673 var State, id;674 675 // Fetch676 State = History.normalizeState(passedState);677 // Fetch678 id = State.id;679 // Return680 return id;681 };682 /**683 * History.getHashByState(State)684 * Creates a Hash for the State Object685 * @param {State} passedState686 * @return {String} hash687 */688 History.getHashByState = function(passedState){689 // Prepare690 var State, hash;691 692 // Fetch693 State = History.normalizeState(passedState);694 // Hash695 hash = State.hash;696 // Return697 return hash;698 };699 /**700 * History.extractId(url_or_hash)701 * Get a State ID by it's URL or Hash702 * @param {string} url_or_hash703 * @return {string} id704 */705 History.extractId = function ( url_or_hash ) {706 // Prepare707 var id,parts,url;708 // Extract709 parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);710 url = parts ? (parts[1]||url_or_hash) : url_or_hash;711 id = parts ? String(parts[2]||'') : '';712 // Return713 return id||false;714 };715 /**716 * History.isTraditionalAnchor717 * Checks to see if the url is a traditional anchor or not718 * @param {String} url_or_hash719 * @return {Boolean}720 */721 History.isTraditionalAnchor = function(url_or_hash){722 // Check723 var isTraditional = !(/[\/\?\.]/.test(url_or_hash));724 // Return725 return isTraditional;726 };727 /**728 * History.extractState729 * Get a State by it's URL or Hash730 * @param {String} url_or_hash731 * @return {State|null}732 */733 History.extractState = function(url_or_hash,create){734 // Prepare735 var State = null, id, url;736 create = create||false;737 // Fetch SUID738 id = History.extractId(url_or_hash);739 if ( id ) {740 State = History.getStateById(id);741 }742 // Fetch SUID returned no State743 if ( !State ) {744 // Fetch URL745 url = History.getFullUrl(url_or_hash);746 // Check URL747 id = History.getIdByUrl(url)||false;748 if ( id ) {749 State = History.getStateById(id);750 }751 // Create State752 if ( !State && create && !History.isTraditionalAnchor(url_or_hash) ) {753 State = History.createStateObject(null,null,url);754 }755 }756 // Return757 return State;758 };759 /**760 * History.getIdByUrl()761 * Get a State ID by a State URL762 */763 History.getIdByUrl = function(url){764 // Fetch765 var id = History.urlToId[url] || History.store.urlToId[url] || undefined;766 // Return767 return id;768 };769 /**770 * History.getLastSavedState()771 * Get an object containing the data, title and url of the current state772 * @return {Object} State773 */774 History.getLastSavedState = function(){775 return History.savedStates[History.savedStates.length-1]||undefined;776 };777 /**778 * History.getLastStoredState()779 * Get an object containing the data, title and url of the current state780 * @return {Object} State781 */782 History.getLastStoredState = function(){783 return History.storedStates[History.storedStates.length-1]||undefined;784 };785 /**786 * History.hasUrlDuplicate787 * Checks if a Url will have a url conflict788 * @param {Object} newState789 * @return {Boolean} hasDuplicate790 */791 History.hasUrlDuplicate = function(newState) {792 // Prepare793 var hasDuplicate = false,794 oldState;795 // Fetch796 oldState = History.extractState(newState.url);797 // Check798 hasDuplicate = oldState && oldState.id !== newState.id;799 // Return800 return hasDuplicate;801 };802 /**803 * History.storeState804 * Store a State805 * @param {Object} newState806 * @return {Object} newState807 */808 History.storeState = function(newState){809 // Store the State810 History.urlToId[newState.url] = newState.id;811 // Push the State812 History.storedStates.push(History.cloneObject(newState));813 // Return newState814 return newState;815 };816 /**817 * History.isLastSavedState(newState)818 * Tests to see if the state is the last state819 * @param {Object} newState820 * @return {boolean} isLast821 */822 History.isLastSavedState = function(newState){823 // Prepare824 var isLast = false,825 newId, oldState, oldId;826 // Check827 if ( History.savedStates.length ) {828 newId = newState.id;829 oldState = History.getLastSavedState();830 oldId = oldState.id;831 // Check832 isLast = (newId === oldId);833 }834 // Return835 return isLast;836 };837 /**838 * History.saveState839 * Push a State840 * @param {Object} newState841 * @return {boolean} changed842 */843 History.saveState = function(newState){844 // Check Hash845 if ( History.isLastSavedState(newState) ) {846 return false;847 }848 // Push the State849 History.savedStates.push(History.cloneObject(newState));850 // Return true851 return true;852 };853 /**854 * History.getStateByIndex()855 * Gets a state by the index856 * @param {integer} index857 * @return {Object}858 */859 History.getStateByIndex = function(index){860 // Prepare861 var State = null;862 // Handle863 if ( typeof index === 'undefined' ) {864 // Get the last inserted865 State = History.savedStates[History.savedStates.length-1];866 }867 else if ( index < 0 ) {868 // Get from the end869 State = History.savedStates[History.savedStates.length+index];870 }871 else {872 // Get from the beginning873 State = History.savedStates[index];874 }875 // Return State876 return State;877 };878 // ====================================================================879 // Hash Helpers880 /**881 * History.getHash()882 * Gets the current document hash883 * @return {string}884 */885 History.getHash = function(){886 var hash = History.unescapeHash(document.location.hash);887 return hash;888 };889 /**890 * History.unescapeString()891 * Unescape a string892 * @param {String} str893 * @return {string}894 */895 History.unescapeString = function(str){896 // Prepare897 var result = str,898 tmp;899 // Unescape hash900 while ( true ) {901 tmp = window.unescape(result);902 if ( tmp === result ) {903 break;904 }905 result = tmp;906 }907 // Return result908 return result;909 };910 /**911 * History.unescapeHash()912 * normalize and Unescape a Hash913 * @param {String} hash914 * @return {string}915 */916 History.unescapeHash = function(hash){917 // Prepare918 var result = History.normalizeHash(hash);919 // Unescape hash920 result = History.unescapeString(result);921 // Return result922 return result;923 };924 /**925 * History.normalizeHash()926 * normalize a hash across browsers927 * @return {string}928 */929 History.normalizeHash = function(hash){930 // Prepare931 var result = hash.replace(/[^#]*#/,'').replace(/#.*/, '');932 // Return result933 return result;934 };935 /**936 * History.setHash(hash)937 * Sets the document hash938 * @param {string} hash939 * @return {History}940 */941 History.setHash = function(hash,queue){942 // Prepare943 var adjustedHash, State, pageUrl;944 // Handle Queueing945 if ( queue !== false && History.busy() ) {946 // Wait + Push to Queue947 //History.debug('History.setHash: we must wait', arguments);948 History.pushQueue({949 scope: History,950 callback: History.setHash,951 args: arguments,952 queue: queue953 });954 return false;955 }956 // Log957 //History.debug('History.setHash: called',hash);958 // Prepare959 adjustedHash = History.escapeHash(hash);960 // Make Busy + Continue961 History.busy(true);962 // Check if hash is a state963 State = History.extractState(hash,true);964 if ( State && !History.emulated.pushState ) {965 // Hash is a state so skip the setHash966 //History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);967 // PushState968 History.pushState(State.data,State.title,State.url,false);969 }970 else if ( document.location.hash !== adjustedHash ) {971 // Hash is a proper hash, so apply it972 // Handle browser bugs973 if ( History.bugs.setHash ) {974 // Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249975 // Fetch the base page976 pageUrl = History.getPageUrl();977 // Safari hash apply978 History.pushState(null,null,pageUrl+'#'+adjustedHash,false);979 }980 else {981 // Normal hash apply982 document.location.hash = adjustedHash;983 }984 }985 // Chain986 return History;987 };988 /**989 * History.escape()990 * normalize and Escape a Hash991 * @return {string}992 */993 History.escapeHash = function(hash){994 // Prepare995 var result = History.normalizeHash(hash);996 // Escape hash997 result = window.escape(result);998 // IE6 Escape Bug999 if ( !History.bugs.hashEscape ) {1000 // Restore common parts1001 result = result1002 .replace(/\%21/g,'!')1003 .replace(/\%26/g,'&')1004 .replace(/\%3D/g,'=')1005 .replace(/\%3F/g,'?');1006 }1007 // Return result1008 return result;1009 };1010 /**1011 * History.getHashByUrl(url)1012 * Extracts the Hash from a URL1013 * @param {string} url1014 * @return {string} url1015 */1016 History.getHashByUrl = function(url){1017 // Extract the hash1018 var hash = String(url)1019 .replace(/([^#]*)#?([^#]*)#?(.*)/, '$2')1020 ;1021 // Unescape hash1022 hash = History.unescapeHash(hash);1023 // Return hash1024 return hash;1025 };1026 /**1027 * History.setTitle(title)1028 * Applies the title to the document1029 * @param {State} newState1030 * @return {Boolean}1031 */1032 History.setTitle = function(newState){1033 // Prepare1034 var title = newState.title,1035 firstState;1036 // Initial1037 if ( !title ) {1038 firstState = History.getStateByIndex(0);1039 if ( firstState && firstState.url === newState.url ) {1040 title = firstState.title||History.options.initialTitle;1041 }1042 }1043 // Apply1044 try {1045 document.getElementsByTagName('title')[0].innerHTML = title.replace('<','<').replace('>','>').replace(' & ',' & ');1046 }1047 catch ( Exception ) { }1048 document.title = title;1049 // Chain1050 return History;1051 };1052 // ====================================================================1053 // Queueing1054 /**1055 * History.queues1056 * The list of queues to use1057 * First In, First Out1058 */1059 History.queues = [];1060 /**1061 * History.busy(value)1062 * @param {boolean} value [optional]1063 * @return {boolean} busy1064 */1065 History.busy = function(value){1066 // Apply1067 if ( typeof value !== 'undefined' ) {1068 //History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);1069 History.busy.flag = value;1070 }1071 // Default1072 else if ( typeof History.busy.flag === 'undefined' ) {1073 History.busy.flag = false;1074 }1075 // Queue1076 if ( !History.busy.flag ) {1077 // Execute the next item in the queue1078 clearTimeout(History.busy.timeout);1079 var fireNext = function(){1080 var i, queue, item;1081 if ( History.busy.flag ) return;1082 for ( i=History.queues.length-1; i >= 0; --i ) {1083 queue = History.queues[i];1084 if ( queue.length === 0 ) continue;1085 item = queue.shift();1086 History.fireQueueItem(item);1087 History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);1088 }1089 };1090 History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);1091 }1092 // Return1093 return History.busy.flag;1094 };1095 /**1096 * History.busy.flag1097 */1098 History.busy.flag = false;1099 /**1100 * History.fireQueueItem(item)1101 * Fire a Queue Item1102 * @param {Object} item1103 * @return {Mixed} result1104 */1105 History.fireQueueItem = function(item){1106 return item.callback.apply(item.scope||History,item.args||[]);1107 };1108 /**1109 * History.pushQueue(callback,args)1110 * Add an item to the queue1111 * @param {Object} item [scope,callback,args,queue]1112 */1113 History.pushQueue = function(item){1114 // Prepare the queue1115 History.queues[item.queue||0] = History.queues[item.queue||0]||[];1116 // Add to the queue1117 History.queues[item.queue||0].push(item);1118 // Chain1119 return History;1120 };1121 /**1122 * History.queue (item,queue), (func,queue), (func), (item)1123 * Either firs the item now if not busy, or adds it to the queue1124 */1125 History.queue = function(item,queue){1126 // Prepare1127 if ( typeof item === 'function' ) {1128 item = {1129 callback: item1130 };1131 }1132 if ( typeof queue !== 'undefined' ) {1133 item.queue = queue;1134 }1135 // Handle1136 if ( History.busy() ) {1137 History.pushQueue(item);1138 } else {1139 History.fireQueueItem(item);1140 }1141 // Chain1142 return History;1143 };1144 /**1145 * History.clearQueue()1146 * Clears the Queue1147 */1148 History.clearQueue = function(){1149 History.busy.flag = false;1150 History.queues = [];1151 return History;1152 };1153 // ====================================================================1154 // IE Bug Fix1155 /**1156 * History.stateChanged1157 * States whether or not the state has changed since the last double check was initialised1158 */1159 History.stateChanged = false;1160 /**1161 * History.doubleChecker1162 * Contains the timeout used for the double checks1163 */1164 History.doubleChecker = false;1165 /**1166 * History.doubleCheckComplete()1167 * Complete a double check1168 * @return {History}1169 */1170 History.doubleCheckComplete = function(){1171 // Update1172 History.stateChanged = true;1173 // Clear1174 History.doubleCheckClear();1175 // Chain1176 return History;1177 };1178 /**1179 * History.doubleCheckClear()1180 * Clear a double check1181 * @return {History}1182 */1183 History.doubleCheckClear = function(){1184 // Clear1185 if ( History.doubleChecker ) {1186 clearTimeout(History.doubleChecker);1187 History.doubleChecker = false;1188 }1189 // Chain1190 return History;1191 };1192 /**1193 * History.doubleCheck()1194 * Create a double check1195 * @return {History}1196 */1197 History.doubleCheck = function(tryAgain){1198 // Reset1199 History.stateChanged = false;1200 History.doubleCheckClear();1201 // Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)1202 // Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=429401203 if ( History.bugs.ieDoubleCheck ) {1204 // Apply Check1205 History.doubleChecker = setTimeout(1206 function(){1207 History.doubleCheckClear();1208 if ( !History.stateChanged ) {1209 //History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);1210 // Re-Attempt1211 tryAgain();1212 }1213 return true;1214 },1215 History.options.doubleCheckInterval1216 );1217 }1218 // Chain1219 return History;1220 };1221 // ====================================================================1222 // Safari Bug Fix1223 /**1224 * History.safariStatePoll()1225 * Poll the current state1226 * @return {History}1227 */1228 History.safariStatePoll = function(){1229 // Poll the URL1230 // Get the Last State which has the new URL1231 var1232 urlState = History.extractState(document.location.href),1233 newState;1234 // Check for a difference1235 if ( !History.isLastSavedState(urlState) ) {1236 newState = urlState;1237 }1238 else {1239 return;1240 }1241 // Check if we have a state with that url1242 // If not create it1243 if ( !newState ) {1244 //History.debug('History.safariStatePoll: new');1245 newState = History.createStateObject();1246 }1247 // Apply the New State1248 //History.debug('History.safariStatePoll: trigger');1249 History.Adapter.trigger(window,'popstate');1250 // Chain1251 return History;1252 };1253 // ====================================================================1254 // State Aliases1255 /**1256 * History.back(queue)1257 * Send the browser history back one item1258 * @param {Integer} queue [optional]1259 */1260 History.back = function(queue){1261 //History.debug('History.back: called', arguments);1262 // Handle Queueing1263 if ( queue !== false && History.busy() ) {1264 // Wait + Push to Queue1265 //History.debug('History.back: we must wait', arguments);1266 History.pushQueue({1267 scope: History,1268 callback: History.back,1269 args: arguments,1270 queue: queue1271 });1272 return false;1273 }1274 // Make Busy + Continue1275 History.busy(true);1276 // Fix certain browser bugs that prevent the state from changing1277 History.doubleCheck(function(){1278 History.back(false);1279 });1280 // Go back1281 history.go(-1);1282 // End back closure1283 return true;1284 };1285 /**1286 * History.forward(queue)1287 * Send the browser history forward one item1288 * @param {Integer} queue [optional]1289 */1290 History.forward = function(queue){1291 //History.debug('History.forward: called', arguments);1292 // Handle Queueing1293 if ( queue !== false && History.busy() ) {1294 // Wait + Push to Queue1295 //History.debug('History.forward: we must wait', arguments);1296 History.pushQueue({1297 scope: History,1298 callback: History.forward,1299 args: arguments,1300 queue: queue1301 });1302 return false;1303 }1304 // Make Busy + Continue1305 History.busy(true);1306 // Fix certain browser bugs that prevent the state from changing1307 History.doubleCheck(function(){1308 History.forward(false);1309 });1310 // Go forward1311 history.go(1);1312 // End forward closure1313 return true;1314 };1315 /**1316 * History.go(index,queue)1317 * Send the browser history back or forward index times1318 * @param {Integer} queue [optional]1319 */1320 History.go = function(index,queue){1321 //History.debug('History.go: called', arguments);1322 // Prepare1323 var i;1324 // Handle1325 if ( index > 0 ) {1326 // Forward1327 for ( i=1; i<=index; ++i ) {1328 History.forward(queue);1329 }1330 }1331 else if ( index < 0 ) {1332 // Backward1333 for ( i=-1; i>=index; --i ) {1334 History.back(queue);1335 }1336 }1337 else {1338 throw new Error('History.go: History.go requires a positive or negative integer passed.');1339 }1340 // Chain1341 return History;1342 };1343 // ====================================================================1344 // HTML5 State Support1345 // Non-Native pushState Implementation1346 if ( History.emulated.pushState ) {1347 /*1348 * Provide Skeleton for HTML4 Browsers1349 */1350 // Prepare1351 var emptyFunction = function(){};1352 History.pushState = History.pushState||emptyFunction;1353 History.replaceState = History.replaceState||emptyFunction;1354 } // History.emulated.pushState1355 // Native pushState Implementation1356 else {1357 /*1358 * Use native HTML5 History API Implementation1359 */1360 /**1361 * History.onPopState(event,extra)1362 * Refresh the Current State1363 */1364 History.onPopState = function(event,extra){1365 // Prepare1366 var stateId = false, newState = false, currentHash, currentState;1367 // Reset the double check1368 History.doubleCheckComplete();1369 // Check for a Hash, and handle apporiatly1370 currentHash = History.getHash();1371 if ( currentHash ) {1372 // Expand Hash1373 currentState = History.extractState(currentHash||document.location.href,true);1374 if ( currentState ) {1375 // We were able to parse it, it must be a State!1376 // Let's forward to replaceState1377 //History.debug('History.onPopState: state anchor', currentHash, currentState);1378 History.replaceState(currentState.data, currentState.title, currentState.url, false);1379 }1380 else {1381 // Traditional Anchor1382 //History.debug('History.onPopState: traditional anchor', currentHash);1383 History.Adapter.trigger(window,'anchorchange');1384 History.busy(false);1385 }1386 // We don't care for hashes1387 History.expectedStateId = false;1388 return false;1389 }1390 // Ensure1391 stateId = History.Adapter.extractEventData('state',event,extra) || false;1392 // Fetch State1393 if ( stateId ) {1394 // Vanilla: Back/forward button was used1395 newState = History.getStateById(stateId);1396 }1397 else if ( History.expectedStateId ) {1398 // Vanilla: A new state was pushed, and popstate was called manually1399 newState = History.getStateById(History.expectedStateId);1400 }1401 else {1402 // Initial State1403 newState = History.extractState(document.location.href);1404 }1405 // The State did not exist in our store1406 if ( !newState ) {1407 // Regenerate the State1408 newState = History.createStateObject(null,null,document.location.href);1409 }1410 // Clean1411 History.expectedStateId = false;1412 // Check if we are the same state1413 if ( History.isLastSavedState(newState) ) {1414 // There has been no change (just the page's hash has finally propagated)1415 //History.debug('History.onPopState: no change', newState, History.savedStates);1416 History.busy(false);1417 return false;1418 }1419 // Store the State1420 History.storeState(newState);1421 History.saveState(newState);1422 // Force update of the title1423 History.setTitle(newState);1424 // Fire Our Event1425 History.Adapter.trigger(window,'statechange');1426 History.busy(false);1427 // Return true1428 return true;1429 };1430 History.Adapter.bind(window,'popstate',History.onPopState);1431 /**1432 * History.pushState(data,title,url)1433 * Add a new State to the history object, become it, and trigger onpopstate1434 * We have to trigger for HTML4 compatibility1435 * @param {object} data1436 * @param {string} title1437 * @param {string} url1438 * @return {true}1439 */1440 History.pushState = function(data,title,url,queue){1441 //History.debug('History.pushState: called', arguments);1442 // Check the State1443 if ( History.getHashByUrl(url) && History.emulated.pushState ) {1444 throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');1445 }1446 // Handle Queueing1447 if ( queue !== false && History.busy() ) {1448 // Wait + Push to Queue1449 //History.debug('History.pushState: we must wait', arguments);1450 History.pushQueue({1451 scope: History,1452 callback: History.pushState,1453 args: arguments,1454 queue: queue1455 });1456 return false;1457 }1458 // Make Busy + Continue1459 History.busy(true);1460 // Create the newState1461 var newState = History.createStateObject(data,title,url);1462 // Check it1463 if ( History.isLastSavedState(newState) ) {1464 // Won't be a change1465 History.busy(false);1466 }1467 else {1468 // Store the newState1469 History.storeState(newState);1470 History.expectedStateId = newState.id;1471 // Push the newState1472 history.pushState(newState.id,newState.title,newState.url);1473 // Fire HTML5 Event1474 History.Adapter.trigger(window,'popstate');1475 }1476 // End pushState closure1477 return true;1478 };1479 /**1480 * History.replaceState(data,title,url)1481 * Replace the State and trigger onpopstate1482 * We have to trigger for HTML4 compatibility1483 * @param {object} data1484 * @param {string} title1485 * @param {string} url1486 * @return {true}1487 */1488 History.replaceState = function(data,title,url,queue){1489 //History.debug('History.replaceState: called', arguments);1490 // Check the State1491 if ( History.getHashByUrl(url) && History.emulated.pushState ) {1492 throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');1493 }1494 // Handle Queueing1495 if ( queue !== false && History.busy() ) {1496 // Wait + Push to Queue1497 //History.debug('History.replaceState: we must wait', arguments);1498 History.pushQueue({1499 scope: History,1500 callback: History.replaceState,1501 args: arguments,1502 queue: queue1503 });1504 return false;1505 }1506 // Make Busy + Continue1507 History.busy(true);1508 // Create the newState1509 var newState = History.createStateObject(data,title,url);1510 // Check it1511 if ( History.isLastSavedState(newState) ) {1512 // Won't be a change1513 History.busy(false);1514 }1515 else {1516 // Store the newState1517 History.storeState(newState);1518 History.expectedStateId = newState.id;1519 // Push the newState1520 history.replaceState(newState.id,newState.title,newState.url);1521 // Fire HTML5 Event1522 History.Adapter.trigger(window,'popstate');1523 }1524 // End replaceState closure1525 return true;1526 };1527 } // !History.emulated.pushState1528 // ====================================================================1529 // Initialise1530 /**1531 * Load the Store1532 */1533 if ( sessionStorage ) {1534 // Fetch1535 try {1536 History.store = JSON.parse(sessionStorage.getItem('History.store'))||{};1537 }1538 catch ( err ) {1539 History.store = {};1540 }1541 // Normalize1542 History.normalizeStore();1543 }1544 else {1545 // Default Load1546 History.store = {};1547 History.normalizeStore();1548 }1549 /**1550 * Clear Intervals on exit to prevent memory leaks1551 */1552 History.Adapter.bind(window,"beforeunload",History.clearAllIntervals);1553 History.Adapter.bind(window,"unload",History.clearAllIntervals);1554 /**1555 * Create the initial State1556 */1557 History.saveState(History.storeState(History.extractState(document.location.href,true)));1558 /**1559 * Bind for Saving Store1560 */1561 if ( sessionStorage ) {1562 // When the page is closed1563 History.onUnload = function(){1564 // Prepare1565 var currentStore, item;1566 // Fetch1567 try {1568 currentStore = JSON.parse(sessionStorage.getItem('History.store'))||{};1569 }1570 catch ( err ) {1571 currentStore = {};1572 }1573 // Ensure1574 currentStore.idToState = currentStore.idToState || {};1575 currentStore.urlToId = currentStore.urlToId || {};1576 currentStore.stateToId = currentStore.stateToId || {};1577 // Sync1578 for ( item in History.idToState ) {1579 if ( !History.idToState.hasOwnProperty(item) ) {1580 continue;1581 }1582 currentStore.idToState[item] = History.idToState[item];1583 }1584 for ( item in History.urlToId ) {1585 if ( !History.urlToId.hasOwnProperty(item) ) {1586 continue;1587 }1588 currentStore.urlToId[item] = History.urlToId[item];1589 }1590 for ( item in History.stateToId ) {1591 if ( !History.stateToId.hasOwnProperty(item) ) {1592 continue;1593 }1594 currentStore.stateToId[item] = History.stateToId[item];1595 }1596 // Update1597 History.store = currentStore;1598 History.normalizeStore();1599 // Store1600 sessionStorage.setItem('History.store',JSON.stringify(currentStore));1601 };1602 // For Internet Explorer1603 History.intervalList.push(setInterval(History.onUnload,History.options.storeInterval));1604 1605 // For Other Browsers1606 History.Adapter.bind(window,'beforeunload',History.onUnload);1607 History.Adapter.bind(window,'unload',History.onUnload);1608 1609 // Both are enabled for consistency1610 }1611 // Non-Native pushState Implementation1612 if ( !History.emulated.pushState ) {1613 // Be aware, the following is only for native pushState implementations1614 // If you are wanting to include something for all browsers1615 // Then include it above this if block1616 /**1617 * Setup Safari Fix1618 */1619 if ( History.bugs.safariPoll ) {1620 History.intervalList.push(setInterval(History.safariStatePoll, History.options.safariPollInterval));1621 }1622 /**1623 * Ensure Cross Browser Compatibility1624 */1625 if ( navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName||'') === 'Mozilla' ) {1626 /**1627 * Fix Safari HashChange Issue1628 */1629 // Setup Alias1630 History.Adapter.bind(window,'hashchange',function(){1631 History.Adapter.trigger(window,'popstate');1632 });1633 // Initialise Alias1634 if ( History.getHash() ) {1635 History.Adapter.onDomLoad(function(){1636 History.Adapter.trigger(window,'hashchange');1637 });1638 }1639 }1640 } // !History.emulated.pushState1641 }; // History.initCore1642 // Try and Initialise History1643 History.init();...
history.html4.js
Source:history.html4.js
1/**2 * History.js HTML4 Support3 * Depends on the HTML5 Support4 * @author Benjamin Arthur Lupton <contact@balupton.com>5 * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>6 * @license New BSD License <http://creativecommons.org/licenses/BSD/>7 */8(function(window,undefined){9 "use strict";10 // ========================================================================11 // Initialise12 // Localise Globals13 var14 document = window.document, // Make sure we are using the correct document15 setTimeout = window.setTimeout||setTimeout,16 clearTimeout = window.clearTimeout||clearTimeout,17 setInterval = window.setInterval||setInterval,18 History = window.History = window.History||{}; // Public History Object19 // Check Existence20 if ( typeof History.initHtml4 !== 'undefined' ) {21 throw new Error('History.js HTML4 Support has already been loaded...');22 }23 // ========================================================================24 // Initialise HTML4 Support25 // Initialise HTML4 Support26 History.initHtml4 = function(){27 // Initialise28 if ( typeof History.initHtml4.initialized !== 'undefined' ) {29 // Already Loaded30 return false;31 }32 else {33 History.initHtml4.initialized = true;34 }35 // ====================================================================36 // Properties37 /**38 * History.enabled39 * Is History enabled?40 */41 History.enabled = true;42 // ====================================================================43 // Hash Storage44 /**45 * History.savedHashes46 * Store the hashes in an array47 */48 History.savedHashes = [];49 /**50 * History.isLastHash(newHash)51 * Checks if the hash is the last hash52 * @param {string} newHash53 * @return {boolean} true54 */55 History.isLastHash = function(newHash){56 // Prepare57 var oldHash = History.getHashByIndex(),58 isLast;59 // Check60 isLast = newHash === oldHash;61 // Return isLast62 return isLast;63 };64 /**65 * History.saveHash(newHash)66 * Push a Hash67 * @param {string} newHash68 * @return {boolean} true69 */70 History.saveHash = function(newHash){71 // Check Hash72 if ( History.isLastHash(newHash) ) {73 return false;74 }75 // Push the Hash76 History.savedHashes.push(newHash);77 // Return true78 return true;79 };80 /**81 * History.getHashByIndex()82 * Gets a hash by the index83 * @param {integer} index84 * @return {string}85 */86 History.getHashByIndex = function(index){87 // Prepare88 var hash = null;89 // Handle90 if ( typeof index === 'undefined' ) {91 // Get the last inserted92 hash = History.savedHashes[History.savedHashes.length-1];93 }94 else if ( index < 0 ) {95 // Get from the end96 hash = History.savedHashes[History.savedHashes.length+index];97 }98 else {99 // Get from the beginning100 hash = History.savedHashes[index];101 }102 // Return hash103 return hash;104 };105 // ====================================================================106 // Discarded States107 /**108 * History.discardedHashes109 * A hashed array of discarded hashes110 */111 History.discardedHashes = {};112 /**113 * History.discardedStates114 * A hashed array of discarded states115 */116 History.discardedStates = {};117 /**118 * History.discardState(State)119 * Discards the state by ignoring it through History120 * @param {object} State121 * @return {true}122 */123 History.discardState = function(discardedState,forwardState,backState){124 //History.debug('History.discardState', arguments);125 // Prepare126 var discardedStateHash = History.getHashByState(discardedState),127 discardObject;128 // Create Discard Object129 discardObject = {130 'discardedState': discardedState,131 'backState': backState,132 'forwardState': forwardState133 };134 // Add to DiscardedStates135 History.discardedStates[discardedStateHash] = discardObject;136 // Return true137 return true;138 };139 /**140 * History.discardHash(hash)141 * Discards the hash by ignoring it through History142 * @param {string} hash143 * @return {true}144 */145 History.discardHash = function(discardedHash,forwardState,backState){146 //History.debug('History.discardState', arguments);147 // Create Discard Object148 var discardObject = {149 'discardedHash': discardedHash,150 'backState': backState,151 'forwardState': forwardState152 };153 // Add to discardedHash154 History.discardedHashes[discardedHash] = discardObject;155 // Return true156 return true;157 };158 /**159 * History.discardState(State)160 * Checks to see if the state is discarded161 * @param {object} State162 * @return {bool}163 */164 History.discardedState = function(State){165 // Prepare166 var StateHash = History.getHashByState(State),167 discarded;168 // Check169 discarded = History.discardedStates[StateHash]||false;170 // Return true171 return discarded;172 };173 /**174 * History.discardedHash(hash)175 * Checks to see if the state is discarded176 * @param {string} State177 * @return {bool}178 */179 History.discardedHash = function(hash){180 // Check181 var discarded = History.discardedHashes[hash]||false;182 // Return true183 return discarded;184 };185 /**186 * History.recycleState(State)187 * Allows a discarded state to be used again188 * @param {object} data189 * @param {string} title190 * @param {string} url191 * @return {true}192 */193 History.recycleState = function(State){194 //History.debug('History.recycleState', arguments);195 // Prepare196 var StateHash = History.getHashByState(State);197 // Remove from DiscardedStates198 if ( History.discardedState(State) ) {199 delete History.discardedStates[StateHash];200 }201 // Return true202 return true;203 };204 // ====================================================================205 // HTML4 HashChange Support206 if ( History.emulated.hashChange ) {207 /*208 * We must emulate the HTML4 HashChange Support by manually checking for hash changes209 */210 /**211 * History.hashChangeInit()212 * Init the HashChange Emulation213 */214 History.hashChangeInit = function(){215 // Define our Checker Function216 History.checkerFunction = null;217 // Define some variables that will help in our checker function218 var lastDocumentHash = '',219 iframeId, iframe,220 lastIframeHash, checkerRunning;221 // Handle depending on the browser222 if ( History.isInternetExplorer() ) {223 // IE6 and IE7224 // We need to use an iframe to emulate the back and forward buttons225 // Create iFrame226 iframeId = 'historyjs-iframe';227 iframe = document.createElement('iframe');228 // Adjust iFarme229 iframe.setAttribute('id', iframeId);230 iframe.style.display = 'none';231 // Append iFrame232 document.body.appendChild(iframe);233 // Create initial history entry234 iframe.contentWindow.document.open();235 iframe.contentWindow.document.close();236 // Define some variables that will help in our checker function237 lastIframeHash = '';238 checkerRunning = false;239 // Define the checker function240 History.checkerFunction = function(){241 // Check Running242 if ( checkerRunning ) {243 return false;244 }245 // Update Running246 checkerRunning = true;247 // Fetch248 var documentHash = History.getHash()||'',249 iframeHash = History.unescapeHash(iframe.contentWindow.document.location.hash)||'';250 // The Document Hash has changed (application caused)251 if ( documentHash !== lastDocumentHash ) {252 // Equalise253 lastDocumentHash = documentHash;254 // Create a history entry in the iframe255 if ( iframeHash !== documentHash ) {256 //History.debug('hashchange.checker: iframe hash change', 'documentHash (new):', documentHash, 'iframeHash (old):', iframeHash);257 // Equalise258 lastIframeHash = iframeHash = documentHash;259 // Create History Entry260 iframe.contentWindow.document.open();261 iframe.contentWindow.document.close();262 // Update the iframe's hash263 iframe.contentWindow.document.location.hash = History.escapeHash(documentHash);264 }265 // Trigger Hashchange Event266 History.Adapter.trigger(window,'hashchange');267 }268 // The iFrame Hash has changed (back button caused)269 else if ( iframeHash !== lastIframeHash ) {270 //History.debug('hashchange.checker: iframe hash out of sync', 'iframeHash (new):', iframeHash, 'documentHash (old):', documentHash);271 // Equalise272 lastIframeHash = iframeHash;273 // Update the Hash274 History.setHash(iframeHash,false);275 }276 // Reset Running277 checkerRunning = false;278 // Return true279 return true;280 };281 }282 else {283 // We are not IE284 // Firefox 1 or 2, Opera285 // Define the checker function286 History.checkerFunction = function(){287 // Prepare288 var documentHash = History.getHash();289 // The Document Hash has changed (application caused)290 if ( documentHash !== lastDocumentHash ) {291 // Equalise292 lastDocumentHash = documentHash;293 // Trigger Hashchange Event294 History.Adapter.trigger(window,'hashchange');295 }296 // Return true297 return true;298 };299 }300 // Apply the checker function301 History.intervalList.push(setInterval(History.checkerFunction, History.options.hashChangeInterval));302 // Done303 return true;304 }; // History.hashChangeInit305 // Bind hashChangeInit306 History.Adapter.onDomLoad(History.hashChangeInit);307 } // History.emulated.hashChange308 // ====================================================================309 // HTML5 State Support310 // Non-Native pushState Implementation311 if ( History.emulated.pushState ) {312 /*313 * We must emulate the HTML5 State Management by using HTML4 HashChange314 */315 /**316 * History.onHashChange(event)317 * Trigger HTML5's window.onpopstate via HTML4 HashChange Support318 */319 History.onHashChange = function(event){320 //History.debug('History.onHashChange', arguments);321 // Prepare322 var currentUrl = ((event && event.newURL) || document.location.href),323 currentHash = History.getHashByUrl(currentUrl),324 currentState = null,325 currentStateHash = null,326 currentStateHashExits = null,327 discardObject;328 // Check if we are the same state329 if ( History.isLastHash(currentHash) ) {330 // There has been no change (just the page's hash has finally propagated)331 //History.debug('History.onHashChange: no change');332 History.busy(false);333 return false;334 }335 // Reset the double check336 History.doubleCheckComplete();337 // Store our location for use in detecting back/forward direction338 History.saveHash(currentHash);339 // Expand Hash340 if ( currentHash && History.isTraditionalAnchor(currentHash) ) {341 //History.debug('History.onHashChange: traditional anchor', currentHash);342 // Traditional Anchor Hash343 History.Adapter.trigger(window,'anchorchange');344 History.busy(false);345 return false;346 }347 // Create State348 currentState = History.extractState(History.getFullUrl(currentHash||document.location.href,false),true);349 // Check if we are the same state350 if ( History.isLastSavedState(currentState) ) {351 //History.debug('History.onHashChange: no change');352 // There has been no change (just the page's hash has finally propagated)353 History.busy(false);354 return false;355 }356 // Create the state Hash357 currentStateHash = History.getHashByState(currentState);358 // Check if we are DiscardedState359 discardObject = History.discardedState(currentState);360 if ( discardObject ) {361 // Ignore this state as it has been discarded and go back to the state before it362 if ( History.getHashByIndex(-2) === History.getHashByState(discardObject.forwardState) ) {363 // We are going backwards364 //History.debug('History.onHashChange: go backwards');365 History.back(false);366 } else {367 // We are going forwards368 //History.debug('History.onHashChange: go forwards');369 History.forward(false);370 }371 return false;372 }373 // Push the new HTML5 State374 //History.debug('History.onHashChange: success hashchange');375 History.pushState(currentState.data,currentState.title,currentState.url,false);376 // End onHashChange closure377 return true;378 };379 History.Adapter.bind(window,'hashchange',History.onHashChange);380 /**381 * History.pushState(data,title,url)382 * Add a new State to the history object, become it, and trigger onpopstate383 * We have to trigger for HTML4 compatibility384 * @param {object} data385 * @param {string} title386 * @param {string} url387 * @return {true}388 */389 History.pushState = function(data,title,url,queue){390 //History.debug('History.pushState: called', arguments);391 // Check the State392 if ( History.getHashByUrl(url) ) {393 throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');394 }395 // Handle Queueing396 if ( queue !== false && History.busy() ) {397 // Wait + Push to Queue398 //History.debug('History.pushState: we must wait', arguments);399 History.pushQueue({400 scope: History,401 callback: History.pushState,402 args: arguments,403 queue: queue404 });405 return false;406 }407 // Make Busy408 History.busy(true);409 // Fetch the State Object410 var newState = History.createStateObject(data,title,url),411 newStateHash = History.getHashByState(newState),412 oldState = History.getState(false),413 oldStateHash = History.getHashByState(oldState),414 html4Hash = History.getHash();415 // Store the newState416 History.storeState(newState);417 History.expectedStateId = newState.id;418 // Recycle the State419 History.recycleState(newState);420 // Force update of the title421 History.setTitle(newState);422 // Check if we are the same State423 if ( newStateHash === oldStateHash ) {424 //History.debug('History.pushState: no change', newStateHash);425 History.busy(false);426 return false;427 }428 // Update HTML4 Hash429 if ( newStateHash !== html4Hash && newStateHash !== History.getShortUrl(document.location.href) ) {430 //History.debug('History.pushState: update hash', newStateHash, html4Hash);431 History.setHash(newStateHash,false);432 return false;433 }434 // Update HTML5 State435 History.saveState(newState);436 // Fire HTML5 Event437 //History.debug('History.pushState: trigger popstate');438 History.Adapter.trigger(window,'statechange');439 History.busy(false);440 // End pushState closure441 return true;442 };443 /**444 * History.replaceState(data,title,url)445 * Replace the State and trigger onpopstate446 * We have to trigger for HTML4 compatibility447 * @param {object} data448 * @param {string} title449 * @param {string} url450 * @return {true}451 */452 History.replaceState = function(data,title,url,queue){453 //History.debug('History.replaceState: called', arguments);454 // Check the State455 if ( History.getHashByUrl(url) ) {456 throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');457 }458 // Handle Queueing459 if ( queue !== false && History.busy() ) {460 // Wait + Push to Queue461 //History.debug('History.replaceState: we must wait', arguments);462 History.pushQueue({463 scope: History,464 callback: History.replaceState,465 args: arguments,466 queue: queue467 });468 return false;469 }470 // Make Busy471 History.busy(true);472 // Fetch the State Objects473 var newState = History.createStateObject(data,title,url),474 oldState = History.getState(false),475 previousState = History.getStateByIndex(-2);476 // Discard Old State477 History.discardState(oldState,newState,previousState);478 // Alias to PushState479 History.pushState(newState.data,newState.title,newState.url,false);480 // End replaceState closure481 return true;482 };483 } // History.emulated.pushState484 // ====================================================================485 // Initialise486 // Non-Native pushState Implementation487 if ( History.emulated.pushState ) {488 /**489 * Ensure initial state is handled correctly490 */491 if ( History.getHash() && !History.emulated.hashChange ) {492 History.Adapter.onDomLoad(function(){493 History.Adapter.trigger(window,'hashchange');494 });495 }496 } // History.emulated.pushState497 }; // History.initHtml4498 // Try and Initialise History499 if ( typeof History.init !== 'undefined' ) {500 History.init();501 }...
history-html5-coverage.js
Source:history-html5-coverage.js
1/*2YUI 3.7.3 (build 5687)3Copyright 2012 Yahoo! Inc. All rights reserved.4Licensed under the BSD License.5http://yuilibrary.com/license/6*/7if (typeof _yuitest_coverage == "undefined"){8 _yuitest_coverage = {};9 _yuitest_coverline = function(src, line){10 var coverage = _yuitest_coverage[src];11 if (!coverage.lines[line]){12 coverage.calledLines++;13 }14 coverage.lines[line]++;15 };16 _yuitest_coverfunc = function(src, name, line){17 var coverage = _yuitest_coverage[src],18 funcId = name + ":" + line;19 if (!coverage.functions[funcId]){20 coverage.calledFunctions++;21 }22 coverage.functions[funcId]++;23 };24}25_yuitest_coverage["build/history-html5/history-html5.js"] = {26 lines: {},27 functions: {},28 coveredLines: 0,29 calledLines: 0,30 coveredFunctions: 0,31 calledFunctions: 0,32 path: "build/history-html5/history-html5.js",33 code: []34};35_yuitest_coverage["build/history-html5/history-html5.js"].code=["YUI.add('history-html5', function (Y, NAME) {","","/**"," * Provides browser history management using the HTML5 history API."," *"," * @module history"," * @submodule history-html5"," * @since 3.2.0"," */","","/**"," * <p>"," * Provides browser history management using the HTML5 history API."," * </p>"," *"," * <p>"," * When calling the <code>add()</code>, <code>addValue()</code>,"," * <code>replace()</code>, or <code>replaceValue()</code> methods on"," * <code>HistoryHTML5</code>, the following additional options are supported:"," * </p>"," *"," * <dl>"," * <dt><strong>title (String)</strong></dt>"," * <dd>"," * Title to use for the new history entry. Browsers will typically display"," * this title to the user in the detailed history window or in a dropdown"," * menu attached to the back/forward buttons. If not specified, the title"," * of the current document will be used."," * </dd>"," *"," * <dt><strong>url (String)</strong></dt>"," * <dd>"," * URL to display to the user for the new history entry. This URL will be"," * visible in the browser's address bar and will be the bookmarked URL if"," * the user bookmarks the page. It may be a relative path (\"foo/bar\"), an"," * absolute path (\"/foo/bar\"), or a full URL (\"http://example.com/foo/bar\")."," * If you specify a full URL, the origin <i>must</i> be the same as the"," * origin of the current page, or an error will occur. If no URL is"," * specified, the current URL will not be changed."," * </dd>"," * </dl>"," *"," * @class HistoryHTML5"," * @extends HistoryBase"," * @constructor"," * @param {Object} config (optional) Configuration object."," */","","var HistoryBase = Y.HistoryBase,"," Lang = Y.Lang,"," win = Y.config.win,"," useHistoryHTML5 = Y.config.useHistoryHTML5,",""," SRC_POPSTATE = 'popstate',"," SRC_REPLACE = HistoryBase.SRC_REPLACE;","","function HistoryHTML5() {"," HistoryHTML5.superclass.constructor.apply(this, arguments);","}","","Y.extend(HistoryHTML5, HistoryBase, {"," // -- Initialization -------------------------------------------------------"," _init: function (config) {"," var bookmarkedState = win.history.state;",""," // Treat empty state objects as `null` so they're not processed further."," if (Y.Object.isEmpty(bookmarkedState)) {"," bookmarkedState = null;"," }",""," config || (config = {});",""," // If both the initial state and the bookmarked state are objects, merge"," // them (bookmarked state wins)."," if (config.initialState"," && Lang.type(config.initialState) === 'object'"," && Lang.type(bookmarkedState) === 'object') {",""," this._initialState = Y.merge(config.initialState, bookmarkedState);"," } else {"," // Otherwise, the bookmarked state always wins if there is one. If"," // there isn't a bookmarked state, history-base will take care of"," // falling back to config.initialState or null."," this._initialState = bookmarkedState;"," }",""," Y.on('popstate', this._onPopState, win, this);",""," HistoryHTML5.superclass._init.apply(this, arguments);"," },",""," // -- Protected Methods ----------------------------------------------------",""," /**"," * Overrides HistoryBase's <code>_storeState()</code> and pushes or replaces"," * a history entry using the HTML5 history API when necessary."," *"," * @method _storeState"," * @param {String} src Source of the changes."," * @param {Object} newState New state to store."," * @param {Object} options Zero or more options."," * @protected"," */"," _storeState: function (src, newState, options) {"," if (src !== SRC_POPSTATE) {"," win.history[src === SRC_REPLACE ? 'replaceState' : 'pushState']("," newState,"," options.title || Y.config.doc.title || '',"," options.url || null"," );"," }",""," HistoryHTML5.superclass._storeState.apply(this, arguments);"," },",""," // -- Protected Event Handlers ---------------------------------------------",""," /**"," * Handler for popstate events."," *"," * @method _onPopState"," * @param {Event} e"," * @protected"," */"," _onPopState: function (e) {"," this._resolveChanges(SRC_POPSTATE, e._event.state || null);"," }","}, {"," // -- Public Static Properties ---------------------------------------------"," NAME: 'historyhtml5',",""," /**"," * Constant used to identify state changes originating from"," * <code>popstate</code> events."," *"," * @property SRC_POPSTATE"," * @type String"," * @static"," * @final"," */"," SRC_POPSTATE: SRC_POPSTATE","});","","if (!Y.Node.DOM_EVENTS.popstate) {"," Y.Node.DOM_EVENTS.popstate = 1;","}","","Y.HistoryHTML5 = HistoryHTML5;","","/**"," * <p>"," * If <code>true</code>, the <code>Y.History</code> alias will always point to"," * <code>Y.HistoryHTML5</code> when the history-html5 module is loaded, even if"," * the current browser doesn't support HTML5 history."," * </p>"," *"," * <p>"," * If <code>false</code>, the <code>Y.History</code> alias will always point to"," * <code>Y.HistoryHash</code> when the history-hash module is loaded, even if"," * the current browser supports HTML5 history."," * </p>"," *"," * <p>"," * If neither <code>true</code> nor <code>false</code>, the"," * <code>Y.History</code> alias will point to the best available history adapter"," * that the browser supports. This is the default behavior."," * </p>"," *"," * @property useHistoryHTML5"," * @type boolean"," * @for config"," * @since 3.2.0"," */","","// HistoryHTML5 will always win over HistoryHash unless useHistoryHTML5 is false","// or HTML5 history is not supported.","if (useHistoryHTML5 === true || (useHistoryHTML5 !== false &&"," HistoryBase.html5)) {"," Y.History = HistoryHTML5;","}","","","}, '3.7.3', {\"optional\": [\"json\"], \"requires\": [\"event-base\", \"history-base\", \"node-base\"]});"];36_yuitest_coverage["build/history-html5/history-html5.js"].lines = {"1":0,"49":0,"57":0,"58":0,"61":0,"64":0,"67":0,"68":0,"71":0,"75":0,"79":0,"84":0,"87":0,"89":0,"105":0,"106":0,"113":0,"126":0,"144":0,"145":0,"148":0,"177":0,"179":0};37_yuitest_coverage["build/history-html5/history-html5.js"].functions = {"HistoryHTML5:57":0,"_init:63":0,"_storeState:104":0,"_onPopState:125":0,"(anonymous 1):1":0};38_yuitest_coverage["build/history-html5/history-html5.js"].coveredLines = 23;39_yuitest_coverage["build/history-html5/history-html5.js"].coveredFunctions = 5;40_yuitest_coverline("build/history-html5/history-html5.js", 1);41YUI.add('history-html5', function (Y, NAME) {42/**43 * Provides browser history management using the HTML5 history API.44 *45 * @module history46 * @submodule history-html547 * @since 3.2.048 */49/**50 * <p>51 * Provides browser history management using the HTML5 history API.52 * </p>53 *54 * <p>55 * When calling the <code>add()</code>, <code>addValue()</code>,56 * <code>replace()</code>, or <code>replaceValue()</code> methods on57 * <code>HistoryHTML5</code>, the following additional options are supported:58 * </p>59 *60 * <dl>61 * <dt><strong>title (String)</strong></dt>62 * <dd>63 * Title to use for the new history entry. Browsers will typically display64 * this title to the user in the detailed history window or in a dropdown65 * menu attached to the back/forward buttons. If not specified, the title66 * of the current document will be used.67 * </dd>68 *69 * <dt><strong>url (String)</strong></dt>70 * <dd>71 * URL to display to the user for the new history entry. This URL will be72 * visible in the browser's address bar and will be the bookmarked URL if73 * the user bookmarks the page. It may be a relative path ("foo/bar"), an74 * absolute path ("/foo/bar"), or a full URL ("http://example.com/foo/bar").75 * If you specify a full URL, the origin <i>must</i> be the same as the76 * origin of the current page, or an error will occur. If no URL is77 * specified, the current URL will not be changed.78 * </dd>79 * </dl>80 *81 * @class HistoryHTML582 * @extends HistoryBase83 * @constructor84 * @param {Object} config (optional) Configuration object.85 */86_yuitest_coverfunc("build/history-html5/history-html5.js", "(anonymous 1)", 1);87_yuitest_coverline("build/history-html5/history-html5.js", 49);88var HistoryBase = Y.HistoryBase,89 Lang = Y.Lang,90 win = Y.config.win,91 useHistoryHTML5 = Y.config.useHistoryHTML5,92 SRC_POPSTATE = 'popstate',93 SRC_REPLACE = HistoryBase.SRC_REPLACE;94_yuitest_coverline("build/history-html5/history-html5.js", 57);95function HistoryHTML5() {96 _yuitest_coverfunc("build/history-html5/history-html5.js", "HistoryHTML5", 57);97_yuitest_coverline("build/history-html5/history-html5.js", 58);98HistoryHTML5.superclass.constructor.apply(this, arguments);99}100_yuitest_coverline("build/history-html5/history-html5.js", 61);101Y.extend(HistoryHTML5, HistoryBase, {102 // -- Initialization -------------------------------------------------------103 _init: function (config) {104 _yuitest_coverfunc("build/history-html5/history-html5.js", "_init", 63);105_yuitest_coverline("build/history-html5/history-html5.js", 64);106var bookmarkedState = win.history.state;107 // Treat empty state objects as `null` so they're not processed further.108 _yuitest_coverline("build/history-html5/history-html5.js", 67);109if (Y.Object.isEmpty(bookmarkedState)) {110 _yuitest_coverline("build/history-html5/history-html5.js", 68);111bookmarkedState = null;112 }113 _yuitest_coverline("build/history-html5/history-html5.js", 71);114config || (config = {});115 // If both the initial state and the bookmarked state are objects, merge116 // them (bookmarked state wins).117 _yuitest_coverline("build/history-html5/history-html5.js", 75);118if (config.initialState119 && Lang.type(config.initialState) === 'object'120 && Lang.type(bookmarkedState) === 'object') {121 _yuitest_coverline("build/history-html5/history-html5.js", 79);122this._initialState = Y.merge(config.initialState, bookmarkedState);123 } else {124 // Otherwise, the bookmarked state always wins if there is one. If125 // there isn't a bookmarked state, history-base will take care of126 // falling back to config.initialState or null.127 _yuitest_coverline("build/history-html5/history-html5.js", 84);128this._initialState = bookmarkedState;129 }130 _yuitest_coverline("build/history-html5/history-html5.js", 87);131Y.on('popstate', this._onPopState, win, this);132 _yuitest_coverline("build/history-html5/history-html5.js", 89);133HistoryHTML5.superclass._init.apply(this, arguments);134 },135 // -- Protected Methods ----------------------------------------------------136 /**137 * Overrides HistoryBase's <code>_storeState()</code> and pushes or replaces138 * a history entry using the HTML5 history API when necessary.139 *140 * @method _storeState141 * @param {String} src Source of the changes.142 * @param {Object} newState New state to store.143 * @param {Object} options Zero or more options.144 * @protected145 */146 _storeState: function (src, newState, options) {147 _yuitest_coverfunc("build/history-html5/history-html5.js", "_storeState", 104);148_yuitest_coverline("build/history-html5/history-html5.js", 105);149if (src !== SRC_POPSTATE) {150 _yuitest_coverline("build/history-html5/history-html5.js", 106);151win.history[src === SRC_REPLACE ? 'replaceState' : 'pushState'](152 newState,153 options.title || Y.config.doc.title || '',154 options.url || null155 );156 }157 _yuitest_coverline("build/history-html5/history-html5.js", 113);158HistoryHTML5.superclass._storeState.apply(this, arguments);159 },160 // -- Protected Event Handlers ---------------------------------------------161 /**162 * Handler for popstate events.163 *164 * @method _onPopState165 * @param {Event} e166 * @protected167 */168 _onPopState: function (e) {169 _yuitest_coverfunc("build/history-html5/history-html5.js", "_onPopState", 125);170_yuitest_coverline("build/history-html5/history-html5.js", 126);171this._resolveChanges(SRC_POPSTATE, e._event.state || null);172 }173}, {174 // -- Public Static Properties ---------------------------------------------175 NAME: 'historyhtml5',176 /**177 * Constant used to identify state changes originating from178 * <code>popstate</code> events.179 *180 * @property SRC_POPSTATE181 * @type String182 * @static183 * @final184 */185 SRC_POPSTATE: SRC_POPSTATE186});187_yuitest_coverline("build/history-html5/history-html5.js", 144);188if (!Y.Node.DOM_EVENTS.popstate) {189 _yuitest_coverline("build/history-html5/history-html5.js", 145);190Y.Node.DOM_EVENTS.popstate = 1;191}192_yuitest_coverline("build/history-html5/history-html5.js", 148);193Y.HistoryHTML5 = HistoryHTML5;194/**195 * <p>196 * If <code>true</code>, the <code>Y.History</code> alias will always point to197 * <code>Y.HistoryHTML5</code> when the history-html5 module is loaded, even if198 * the current browser doesn't support HTML5 history.199 * </p>200 *201 * <p>202 * If <code>false</code>, the <code>Y.History</code> alias will always point to203 * <code>Y.HistoryHash</code> when the history-hash module is loaded, even if204 * the current browser supports HTML5 history.205 * </p>206 *207 * <p>208 * If neither <code>true</code> nor <code>false</code>, the209 * <code>Y.History</code> alias will point to the best available history adapter210 * that the browser supports. This is the default behavior.211 * </p>212 *213 * @property useHistoryHTML5214 * @type boolean215 * @for config216 * @since 3.2.0217 */218// HistoryHTML5 will always win over HistoryHash unless useHistoryHTML5 is false219// or HTML5 history is not supported.220_yuitest_coverline("build/history-html5/history-html5.js", 177);221if (useHistoryHTML5 === true || (useHistoryHTML5 !== false &&222 HistoryBase.html5)) {223 _yuitest_coverline("build/history-html5/history-html5.js", 179);224Y.History = HistoryHTML5;225}...
history.py
Source:history.py
...52 53 history_length=property(get_history_length,set_history_length)54 history_cursor=property(get_history_cursor,set_history_cursor)5556 def clear_history(self):57 '''Clear readline history.'''58 self.history[:] = []59 self.history_cursor = 06061 def read_history_file(self, filename=None): 62 '''Load a readline history file.'''63 if filename is None:64 filename=self.history_filename65 try:66 for line in open(filename, 'r'):67 self.add_history(lineobj.ReadLineTextBuffer(line.rstrip()))68 except IOError:69 self.history = []70 self.history_cursor = 07172 def write_history_file(self, filename=None): 73 '''Save a readline history file.'''74 if filename is None:75 filename=self.history_filename76 fp = open(filename, 'wb')77 for line in self.history[-self.history_length:]:78 fp.write(line.get_line_text())79 fp.write('\n')80 fp.close()818283 def add_history(self, line):84 '''Append a line to the history buffer, as if it was the last line typed.'''85 if not line.get_line_text():86 pass87 elif len(self.history) > 0 and self.history[-1].get_line_text() == line.get_line_text():88 pass89 else:90 self.history.append(line)91 self.history_cursor = len(self.history)9293 def previous_history(self,current): # (C-p)94 '''Move back through the history list, fetching the previous command. '''95 if self.history_cursor==len(self.history):96 self.history.append(current.copy()) #do not use add_history since we do not want to increment cursor97 98 if self.history_cursor > 0:99 self.history_cursor -= 1100 current.set_line(self.history[self.history_cursor].get_line_text())101 current.point=lineobj.EndOfLine102103 def next_history(self,current): # (C-n)104 '''Move forward through the history list, fetching the next command. '''105 if self.history_cursor < len(self.history)-1:106 self.history_cursor += 1107 current.set_line(self.history[self.history_cursor].get_line_text())108109 def beginning_of_history(self): # (M-<)110 '''Move to the first line in the history.'''111 self.history_cursor = 0112 if len(self.history) > 0:113 self.l_buffer = self.history[0]114115 def end_of_history(self,current): # (M->)116 '''Move to the end of the input history, i.e., the line currently117 being entered.'''118 self.history_cursor=len(self.history)119 current.set_line(self.history[-1].get_line_text())120121 def reverse_search_history(self,searchfor,startpos=None):122 if startpos is None:123 startpos=self.history_cursor124 res=[(idx,line) for idx,line in enumerate(self.history[startpos:0:-1]) if line.startswith(searchfor)]125 if res:126 self.history_cursor-=res[0][0]127 return res[0][1].get_line_text()128 return ""129 130 def forward_search_history(self,searchfor,startpos=None):131 if startpos is None:132 startpos=self.history_cursor133 res=[(idx,line) for idx,line in enumerate(self.history[startpos:]) if line.startswith(searchfor)]134 if res:135 self.history_cursor+=res[0][0]136 return res[0][1].get_line_text()137 return ""138139 def _non_i_search(self, direction, current):140 c = pyreadline.rl.console141 line = current.get_line_text()142 query = ''143 while 1:144 c.pos(*pyreadline.rl.prompt_end_pos)145 scroll = c.write_scrolling(":%s" % query)146 pyreadline.rl._update_prompt_pos(scroll)147 pyreadline.rl._clear_after()148149 event = c.getkeypress()150 log_sock(str(event),"history")151 152 if event.keyinfo.keyname == 'backspace':153 if len(query) > 0:154 query = query[:-1]155 else:156 break157 elif event.char in string.letters + string.digits + string.punctuation + ' ':158 query += event.char159 elif event.keyinfo.keyname == 'return':160 break161 else:162 pyreadline.rl._bell()163 log_sock(query,"history")164 res=""165 if query:166 if direction==-1:167 res=self.reverse_search_history(query)168 169 else:170 res=self.forward_search_history(query)171 log_sock(res,"history")172 return lineobj.ReadLineTextBuffer(res,point=0)173 174 def non_incremental_reverse_search_history(self,current): # (M-p)175 '''Search backward starting at the current line and moving up176 through the history as necessary using a non-incremental search for177 a string supplied by the user.'''178 return self._non_i_search(-1,current)179180 def non_incremental_forward_search_history(self,current): # (M-n)181 '''Search forward starting at the current line and moving down182 through the the history as necessary using a non-incremental search183 for a string supplied by the user.'''184 return self._non_i_search(1,current)185186 def _search(self, direction, partial):187 try:188 if (self.lastcommand != self.history_search_forward and189 self.lastcommand != self.history_search_backward):190 self.query = ''.join(partial[0:partial.point].get_line_text())191 hcstart=max(self.history_cursor,0) 192 log_sock("hcstart %s"%hcstart,"history")193 hc = self.history_cursor + direction194 while (direction < 0 and hc >= 0) or (direction > 0 and hc < len(self.history)):195 h = self.history[hc]196 if not self.query:197 self.history_cursor = hc198 result=lineobj.ReadLineTextBuffer(h,point=len(h.get_line_text()))199 return result200 elif h.get_line_text().startswith(self.query) and h != partial.get_line_text():201 self.history_cursor = hc202 result=lineobj.ReadLineTextBuffer(h,point=partial.point)203 return result204 hc += direction205 else:206 if len(self.history)==0:207 pass 208 elif hc>=len(self.history) and not self.query:209 self.history_cursor=len(self.history)210 return lineobj.ReadLineTextBuffer("",point=0)211 elif self.history[max(min(hcstart,len(self.history)-1),0)].get_line_text().startswith(self.query) and self.query:212 return lineobj.ReadLineTextBuffer(self.history[max(min(hcstart,len(self.history)-1),0)],point=partial.point)213 else: 214 return lineobj.ReadLineTextBuffer(partial,point=partial.point)215 return lineobj.ReadLineTextBuffer(self.query,point=min(len(self.query),partial.point))216 except IndexError:217 log_sock("hcstart:%s %s"%(hcstart,len(self.history)),"history")218 raise219220 def history_search_forward(self,partial): # ()221 '''Search forward through the history for the string of characters222 between the start of the current line and the point. This is a223 non-incremental search. By default, this command is unbound.'''224 q= self._search(1,partial)225 return q226227 def history_search_backward(self,partial): # ()228 '''Search backward through the history for the string of characters229 between the start of the current line and the point. This is a230 non-incremental search. By default, this command is unbound.'''231 232 q= self._search(-1,partial)233 return q234235236 237if __name__=="__main__":238 q=LineHistory()239 RL=lineobj.ReadLineTextBuffer240 q.add_history(RL("aaaa"))241 q.add_history(RL("aaba"))242 q.add_history(RL("aaca"))243 q.add_history(RL("akca"))244 q.add_history(RL("bbb"))
...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!