6 lines
12 KiB
JavaScript
6 lines
12 KiB
JavaScript
/*!
|
|
* Copyright 2012, Chris Wanstrath
|
|
* Released under the MIT License
|
|
* https://github.com/defunkt/jquery-pjax
|
|
*/
|
|
!function($){function fnPjax(selector,container,options){return options=optionsFor(container,options),this.on("click.pjax",selector,(function(event){var opts=options;opts.container||((opts=$.extend({},options)).container=$(this).attr("data-pjax")),handleClick(event,opts)}))}function handleClick(event,container,options){options=optionsFor(container,options);var link=event.currentTarget,$link=$(link);if("A"!==link.tagName.toUpperCase())throw"$.fn.pjax or $.pjax.click requires an anchor element";if(!(event.which>1||event.metaKey||event.ctrlKey||event.shiftKey||event.altKey||location.protocol!==link.protocol||location.hostname!==link.hostname||link.href.indexOf("#")>-1&&stripHash(link)==stripHash(location)||event.isDefaultPrevented())){var defaults={url:link.href,container:$link.attr("data-pjax"),target:link},opts=$.extend({},defaults,options),clickEvent=$.Event("pjax:click");$link.trigger(clickEvent,[opts]),clickEvent.isDefaultPrevented()||(pjax(opts),event.preventDefault(),$link.trigger("pjax:clicked",[opts]))}}function handleSubmit(event,container,options){options=optionsFor(container,options);var form=event.currentTarget,$form=$(form);if("FORM"!==form.tagName.toUpperCase())throw"$.pjax.submit requires a form element";var defaults={type:($form.attr("method")||"GET").toUpperCase(),url:$form.attr("action"),container:$form.attr("data-pjax"),target:form};if("GET"!==defaults.type&&void 0!==window.FormData)defaults.data=new FormData(form),defaults.processData=!1,defaults.contentType=!1;else{if($form.find(":file").length)return;defaults.data=$form.serializeArray()}pjax($.extend({},defaults,options)),event.preventDefault()}function pjax(options){options=$.extend(!0,{},$.ajaxSettings,pjax.defaults,options),$.isFunction(options.url)&&(options.url=options.url());var hash=parseURL(options.url).hash,containerType=$.type(options.container);if("string"!==containerType)throw"expected string value for 'container' option; got "+containerType;var timeoutTimer,context=options.context=$(options.container);if(!context.length)throw"the container selector '"+options.container+"' did not match anything";function fire(type,args,props){props||(props={}),props.relatedTarget=options.target;var event=$.Event(type,props);return context.trigger(event,args),!event.isDefaultPrevented()}options.data||(options.data={}),$.isArray(options.data)?options.data.push({name:"_pjax",value:options.container}):options.data._pjax=options.container,options.beforeSend=function(xhr,settings){if("GET"!==settings.type&&(settings.timeout=0),xhr.setRequestHeader("X-PJAX","true"),xhr.setRequestHeader("X-PJAX-Container",options.container),!fire("pjax:beforeSend",[xhr,settings]))return!1;settings.timeout>0&&(timeoutTimer=setTimeout((function(){fire("pjax:timeout",[xhr,options])&&xhr.abort("timeout")}),settings.timeout),settings.timeout=0);var url=parseURL(settings.url);hash&&(url.hash=hash),options.requestUrl=stripInternalParams(url)},options.complete=function(xhr,textStatus){timeoutTimer&&clearTimeout(timeoutTimer),fire("pjax:complete",[xhr,textStatus,options]),fire("pjax:end",[xhr,options])},options.error=function(xhr,textStatus,errorThrown){var container=extractContainer("",xhr,options),allowed=fire("pjax:error",[xhr,textStatus,errorThrown,options]);"GET"==options.type&&"abort"!==textStatus&&allowed&&locationReplace(container.url)},options.success=function(data,status,xhr){var previousState=pjax.state,currentVersion="function"==typeof $.pjax.defaults.version?$.pjax.defaults.version():$.pjax.defaults.version,latestVersion=xhr.getResponseHeader("X-PJAX-Version"),container=extractContainer(data,xhr,options),url=parseURL(container.url);if(hash&&(url.hash=hash,container.url=url.href),currentVersion&&latestVersion&¤tVersion!==latestVersion)locationReplace(container.url);else if(container.contents){if(pjax.state={id:options.id||uniqueId(),url:container.url,title:container.title,container:options.container,fragment:options.fragment,timeout:options.timeout},(options.push||options.replace)&&window.history.replaceState(pjax.state,container.title,container.url),$.contains(context,document.activeElement))try{document.activeElement.blur()}catch(e){}container.title&&(document.title=container.title),fire("pjax:beforeReplace",[container.contents,options],{state:pjax.state,previousState:previousState}),context.html(container.contents);var autofocusEl=context.find("input[autofocus], textarea[autofocus]").last()[0];autofocusEl&&document.activeElement!==autofocusEl&&autofocusEl.focus(),function(scripts){if(!scripts)return;var existingScripts=$("script[src]");scripts.each((function(){var src=this.src;if(!existingScripts.filter((function(){return this.src===src})).length){var script=document.createElement("script"),type=$(this).attr("type");type&&(script.type=type),script.src=$(this).attr("src"),document.head.appendChild(script)}}))}(container.scripts);var scrollTo=options.scrollTo;if(hash){var name=decodeURIComponent(hash.slice(1)),target=document.getElementById(name)||document.getElementsByName(name)[0];target&&(scrollTo=$(target).offset().top)}"number"==typeof scrollTo&&$(window).scrollTop(scrollTo),fire("pjax:success",[data,status,xhr,options])}else locationReplace(container.url)},pjax.state||(pjax.state={id:uniqueId(),url:window.location.href,title:document.title,container:options.container,fragment:options.fragment,timeout:options.timeout},window.history.replaceState(pjax.state,document.title)),abortXHR(pjax.xhr),pjax.options=options;var id,value,xhr=pjax.xhr=$.ajax(options);return xhr.readyState>0&&(options.push&&!options.replace&&(id=pjax.state.id,value=[options.container,cloneContents(context)],cacheMapping[id]=value,cacheBackStack.push(id),trimCacheStack(cacheForwardStack,0),trimCacheStack(cacheBackStack,pjax.defaults.maxCacheLength),window.history.pushState(null,"",options.requestUrl)),fire("pjax:start",[xhr,options]),fire("pjax:send",[xhr,options])),pjax.xhr}function pjaxReload(container,options){var defaults={url:window.location.href,push:!1,replace:!0,scrollTo:!1};return pjax($.extend(defaults,optionsFor(container,options)))}function locationReplace(url){window.history.replaceState(null,"",pjax.state.url),window.location.replace(url)}var initialPop=!0,initialURL=window.location.href,initialState=window.history.state;function onPjaxPopstate(event){initialPop||abortXHR(pjax.xhr);var direction,previousState=pjax.state,state=event.state;if(state&&state.container){if(initialPop&&initialURL==state.url)return;if(previousState){if(previousState.id===state.id)return;direction=previousState.id<state.id?"forward":"back"}var cache=cacheMapping[state.id]||[],containerSelector=cache[0]||state.container,container=$(containerSelector),contents=cache[1];if(container.length){previousState&&function(direction,id,value){var pushStack,popStack;cacheMapping[id]=value,"forward"===direction?(pushStack=cacheBackStack,popStack=cacheForwardStack):(pushStack=cacheForwardStack,popStack=cacheBackStack);pushStack.push(id),(id=popStack.pop())&&delete cacheMapping[id];trimCacheStack(pushStack,pjax.defaults.maxCacheLength)}(direction,previousState.id,[containerSelector,cloneContents(container)]);var popstateEvent=$.Event("pjax:popstate",{state:state,direction:direction});container.trigger(popstateEvent);var options={id:state.id,url:state.url,container:containerSelector,push:!1,fragment:state.fragment,timeout:state.timeout,scrollTo:!1};if(contents){container.trigger("pjax:start",[null,options]),pjax.state=state,state.title&&(document.title=state.title);var beforeReplaceEvent=$.Event("pjax:beforeReplace",{state:state,previousState:previousState});container.trigger(beforeReplaceEvent,[contents,options]),container.html(contents),container.trigger("pjax:end",[null,options])}else pjax(options);container[0].offsetHeight}else locationReplace(location.href)}initialPop=!1}function fallbackPjax(options){var url=$.isFunction(options.url)?options.url():options.url,method=options.type?options.type.toUpperCase():"GET",form=$("<form>",{method:"GET"===method?"GET":"POST",action:url,style:"display:none"});"GET"!==method&&"POST"!==method&&form.append($("<input>",{type:"hidden",name:"_method",value:method.toLowerCase()}));var data=options.data;if("string"==typeof data)$.each(data.split("&"),(function(index,value){var pair=value.split("=");form.append($("<input>",{type:"hidden",name:pair[0],value:pair[1]}))}));else if($.isArray(data))$.each(data,(function(index,value){form.append($("<input>",{type:"hidden",name:value.name,value:value.value}))}));else if("object"==typeof data){var key;for(key in data)form.append($("<input>",{type:"hidden",name:key,value:data[key]}))}$(document.body).append(form),form.submit()}function abortXHR(xhr){xhr&&xhr.readyState<4&&(xhr.onreadystatechange=$.noop,xhr.abort())}function uniqueId(){return(new Date).getTime()}function cloneContents(container){var cloned=container.clone();return cloned.find("script").each((function(){this.src||$._data(this,"globalEval",!1)})),cloned.contents()}function stripInternalParams(url){return url.search=url.search.replace(/([?&])(_pjax|_)=[^&]*/g,"").replace(/^&/,""),url.href.replace(/\?($|#)/,"$1")}function parseURL(url){var a=document.createElement("a");return a.href=url,a}function stripHash(location){return location.href.replace(/#.*/,"")}function optionsFor(container,options){return container&&options?((options=$.extend({},options)).container=container,options):$.isPlainObject(container)?container:{container:container}}function findAll(elems,selector){return elems.filter(selector).add(elems.find(selector))}function parseHTML(html){return $.parseHTML(html,document,!0)}function extractContainer(data,xhr,options){var $head,$body,obj={},fullDocument=/<html/i.test(data),serverUrl=xhr.getResponseHeader("X-PJAX-URL");if(obj.url=serverUrl?stripInternalParams(parseURL(serverUrl)):options.requestUrl,fullDocument){$body=$(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]));var head=data.match(/<head[^>]*>([\s\S.]*)<\/head>/i);$head=null!=head?$(parseHTML(head[0])):$body}else $head=$body=$(parseHTML(data));if(0===$body.length)return obj;if(obj.title=findAll($head,"title").last().text(),options.fragment){var $fragment=$body;"body"!==options.fragment&&($fragment=findAll($fragment,options.fragment).first()),$fragment.length&&(obj.contents="body"===options.fragment?$fragment:$fragment.contents(),obj.title||(obj.title=$fragment.attr("title")||$fragment.data("title")))}else fullDocument||(obj.contents=$body);return obj.contents&&(obj.contents=obj.contents.not((function(){return $(this).is("title")})),obj.contents.find("title").remove(),obj.scripts=findAll(obj.contents,"script[src]").remove(),obj.contents=obj.contents.not(obj.scripts)),obj.title&&(obj.title=$.trim(obj.title)),obj}initialState&&initialState.container&&(pjax.state=initialState),"state"in window.history&&(initialPop=!1);var cacheMapping={},cacheForwardStack=[],cacheBackStack=[];function trimCacheStack(stack,length){for(;stack.length>length;)delete cacheMapping[stack.shift()]}function findVersion(){return $("meta").filter((function(){var name=$(this).attr("http-equiv");return name&&"X-PJAX-VERSION"===name.toUpperCase()})).attr("content")}function enable(){$.fn.pjax=fnPjax,$.pjax=pjax,$.pjax.enable=$.noop,$.pjax.disable=disable,$.pjax.click=handleClick,$.pjax.submit=handleSubmit,$.pjax.reload=pjaxReload,$.pjax.defaults={timeout:650,push:!0,replace:!1,type:"GET",dataType:"html",scrollTo:0,maxCacheLength:20,version:findVersion},$(window).on("popstate.pjax",onPjaxPopstate)}function disable(){$.fn.pjax=function(){return this},$.pjax=fallbackPjax,$.pjax.enable=enable,$.pjax.disable=$.noop,$.pjax.click=$.noop,$.pjax.submit=$.noop,$.pjax.reload=function(){window.location.reload()},$(window).off("popstate.pjax",onPjaxPopstate)}$.event.props&&$.inArray("state",$.event.props)<0?$.event.props.push("state"):"state"in $.Event.prototype||$.event.addProp("state"),$.support.pjax=window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/),$.support.pjax?enable():disable()}(jQuery); |