|
|
/*! Sea.js 2.2.3 | seajs.org/LICENSE.md */!function(a,b){function c(a){return function(b){return{}.toString.call(b)=="[object "+a+"]"}}function d(){return B++}function e(a){return a.match(E)[0]}function f(a){for(a=a.replace(F,"/");a.match(G);)a=a.replace(G,"/");return a=a.replace(H,"$1/")}function g(a){var b=a.length-1,c=a.charAt(b);return"#"===c?a.substring(0,b):".js"===a.substring(b-2)||a.indexOf("?")>0||".css"===a.substring(b-3)||"/"===c?a:a+".js"}function h(a){var b=v.alias;return b&&x(b[a])?b[a]:a}function i(a){var b=v.paths,c;return b&&(c=a.match(I))&&x(b[c[1]])&&(a=b[c[1]]+c[2]),a}function j(a){var b=v.vars;return b&&a.indexOf("{")>-1&&(a=a.replace(J,function(a,c){return x(b[c])?b[c]:a})),a}function k(a){var b=v.map,c=a;if(b)for(var d=0,e=b.length;e>d;d++){var f=b[d];if(c=z(f)?f(a)||a:a.replace(f[0],f[1]),c!==a)break}return c}function l(a,b){var c,d=a.charAt(0);if(K.test(a))c=a;else if("."===d)c=f((b?e(b):v.cwd)+a);else if("/"===d){var g=v.cwd.match(L);c=g?g[0]+a.substring(1):a}else c=v.base+a;return 0===c.indexOf("//")&&(c=location.protocol+c),c}function m(a,b){if(!a)return"";a=h(a),a=i(a),a=j(a),a=g(a);var c=l(a,b);return c=k(c)}function n(a){return a.hasAttribute?a.src:a.getAttribute("src",4)}function o(a,b,c,d){var e=T.test(a),f=M.createElement(e?"link":"script");c&&(f.charset=c),A(d)||f.setAttribute("crossorigin",d),p(f,b,e,a),e?(f.rel="stylesheet",f.href=a):(f.async=!0,f.src=a),U=f,S?R.insertBefore(f,S):R.appendChild(f),U=null}function p(a,c,d,e){function f(){a.onload=a.onerror=a.onreadystatechange=null,d||v.debug||R.removeChild(a),a=null,c()}var g="onload"in a;return!d||!W&&g?(g?(a.onload=f,a.onerror=function(){D("error",{uri:e,node:a}),f()}):a.onreadystatechange=function(){/loaded|complete/.test(a.readyState)&&f()},b):(setTimeout(function(){q(a,c)},1),b)}function q(a,b){var c=a.sheet,d;if(W)c&&(d=!0);else if(c)try{c.cssRules&&(d=!0)}catch(e){"NS_ERROR_DOM_SECURITY_ERR"===e.name&&(d=!0)}setTimeout(function(){d?b():q(a,b)},20)}function r(){if(U)return U;if(V&&"interactive"===V.readyState)return V;for(var a=R.getElementsByTagName("script"),b=a.length-1;b>=0;b--){var c=a[b];if("interactive"===c.readyState)return V=c}}function s(a){var b=[];return a.replace(Y,"").replace(X,function(a,c,d){d&&b.push(d)}),b}function t(a,b){this.uri=a,this.dependencies=b||[],this.exports=null,this.status=0,this._waitings={},this._remain=0}if(!a.seajs){var u=a.seajs={version:"2.2.3"},v=u.data={},w=c("Object"),x=c("String"),y=Array.isArray||c("Array"),z=c("Function"),A=c("Undefined"),B=0,C=v.events={};u.on=function(a,b){var c=C[a]||(C[a]=[]);return c.push(b),u},u.off=function(a,b){if(!a&&!b)return C=v.events={},u;var c=C[a];if(c)if(b)for(var d=c.length-1;d>=0;d--)c[d]===b&&c.splice(d,1);else delete C[a];return u};var D=u.emit=function(a,b){var c=C[a],d;if(c)for(c=c.slice();d=c.shift();)d(b);return u},E=/[^?#]*\//,F=/\/\.\//g,G=/\/[^/]+\/\.\.\//,H=/([^:/])\/\//g,I=/^([^/:]+)(\/.+)$/,J=/{([^{]+)}/g,K=/^\/\/.|:\//,L=/^.*?\/\/.*?\//,M=document,N=e(M.URL),O=M.scripts,P=M.getElementById("seajsnode")||O[O.length-1],Q=e(n(P)||N);u.resolve=m;var R=M.head||M.getElementsByTagName("head")[0]||M.documentElement,S=R.getElementsByTagName("base")[0],T=/\.css(?:\?|$)/i,U,V,W=+navigator.userAgent.replace(/.*(?:AppleWebKit|AndroidWebKit)\/(\d+).*/,"$1")<536;u.request=o;var X=/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g,Y=/\\\\/g,Z=u.cache={},$,_={},ab={},bb={},cb=t.STATUS={FETCHING:1,SAVED:2,LOADING:3,LOADED:4,EXECUTING:5,EXECUTED:6};t.prototype.resolve=function(){for(var a=this,b=a.dependencies,c=[],d=0,e=b.length;e>d;d++)c[d]=t.resolve(b[d],a.uri);return c},t.prototype.load=function(){var a=this;if(!(a.status>=cb.LOADING)){a.status=cb.LOADING;var c=a.resolve();D("load",c);for(var d=a._remain=c.length,e,f=0;d>f;f++)e=t.get(c[f]),e.status<cb.LOADED?e._waitings[a.uri]=(e._waitings[a.uri]||0)+1:a._remain--;if(0===a._remain)return a.onload(),b;var g={};for(f=0;d>f;f++)e=Z[c[f]],e.status<cb.FETCHING?e.fetch(g):e.status===cb.SAVED&&e.load();for(var h in g)g.hasOwnProperty(h)&&g[h]()}},t.protowindow.require = window.define = window.exports = window.module = undefined;
/*! * v2.0.1 * * Copyright 2012, Chris Wanstrath * Released under the MIT License * https://github.com/defunkt/jquery-pjax
*/
(function($){
// When called on a container with a selector, fetches the href with
// ajax into the container or with the data-pjax attribute on the link
// itself.
//
// Tries to make sure the back button and ctrl+click work the way
// you'd expect.
//
// Exported as $.fn.pjax
//
// Accepts a jQuery ajax options object that may include these
// pjax specific options:
//
//
// container - String selector for the element where to place the response body.
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// For convenience the second parameter can be either the container or
// the options object.
//
// Returns the jQuery object
function fnPjax(selector, container, options) { options = optionsFor(container, options); return this.on('click.pjax', selector, function(event) { var opts = options; if (!opts.container) { opts = $.extend({}, options); opts.container = $(this).attr('data-pjax') } handleClick(event, opts) })}
// Public: pjax on click handler
//
// Exported as $.pjax.click.
//
// event - "click" jQuery.Event
// options - pjax options
//
// Examples
//
// $(document).on('click', 'a', $.pjax.click)
// // is the same as
// $(document).pjax('a')
//
// Returns nothing.
function handleClick(event, container, options) { options = optionsFor(container, options);
var link = event.currentTarget; var $link = $(link);
if (link.tagName.toUpperCase() !== 'A') throw "$.fn.pjax or $.pjax.click requires an anchor element";
// Middle click, cmd click, and ctrl click should open
// links in a new tab as normal.
if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) return;
// Ignore cross origin links
if ( location.protocol !== link.protocol || location.hostname !== link.hostname ) return;
// Ignore case when a hash is being tacked on the current URL
if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) ) return;
// Ignore event with default prevented
if (event.isDefaultPrevented()) return;
var defaults = { url: link.href, container: $link.attr('data-pjax'), target: link };
var opts = $.extend({}, defaults, options); var clickEvent = $.Event('pjax:click'); $link.trigger(clickEvent, [opts]);
if (!clickEvent.isDefaultPrevented()) { pjax(opts); event.preventDefault(); $link.trigger('pjax:clicked', [opts]) }}
// Public: pjax on form submit handler
//
// Exported as $.pjax.submit
//
// event - "click" jQuery.Event
// options - pjax options
//
// Examples
//
// $(document).on('submit', 'form', function(event) {
// $.pjax.submit(event, '[data-pjax-container]')
// })
//
// Returns nothing.
function handleSubmit(event, container, options) { options = optionsFor(container, options);
var form = event.currentTarget; var $form = $(form);
if (form.tagName.toUpperCase() !== 'FORM') 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 (defaults.type !== 'GET' && window.FormData !== undefined) { defaults.data = new FormData(form); defaults.processData = false; defaults.contentType = false; } else { // Can't handle file uploads, exit
if ($form.find(':file').length) { return }
// Fallback to manually serializing the fields
defaults.data = $form.serializeArray() }
pjax($.extend({}, defaults, options));
event.preventDefault()}
// Loads a URL with ajax, puts the response body inside a container,
// then pushState()'s the loaded URL.
//
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
// container - String selector for where to stick the response body.
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
// var xhr = $.pjax({ url: this.href, container: '#main' })
// console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
function pjax(options) { options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options);
if ($.isFunction(options.url)) { options.url = options.url() }
var hash = parseURL(options.url).hash;
var containerType = $.type(options.container); if (containerType !== 'string') { throw "expected string value for 'container' option; got " + containerType } var context = options.context = $(options.container); if (!context.length) { throw "the container selector '" + options.container + "' did not match anything" }
// We want the browser to maintain two separate internal caches: one
// for pjax'd partial page loads and one for normal page loads.
// Without adding this secret parameter, some browsers will often
// confuse the two.
if (!options.data) options.data = {}; if ($.isArray(options.data)) { options.data.push({name: '_pjax', value: options.container}) } else { options.data._pjax = options.container }
function fire(type, args, props) { if (!props) props = {}; props.relatedTarget = options.target; var event = $.Event(type, props); context.trigger(event, args); return !event.isDefaultPrevented() }
var timeoutTimer;
options.beforeSend = function(xhr, settings) { // No timeout for non-GET requests
// Its not safe to request the resource again with a fallback method.
if (settings.type !== 'GET') { settings.timeout = 0 }
xhr.setRequestHeader('X-PJAX', 'true'); xhr.setRequestHeader('X-PJAX-Container', options.container);
if (!fire('pjax:beforeSend', [xhr, settings])) return false;
if (settings.timeout > 0) { timeoutTimer = setTimeout(function() { if (fire('pjax:timeout', [xhr, options])) xhr.abort('timeout') }, settings.timeout);
// Clear timeout setting so jquerys internal timeout isn't invoked
settings.timeout = 0 }
var url = parseURL(settings.url); if (hash) url.hash = hash; options.requestUrl = stripInternalParams(url) };
options.complete = function(xhr, textStatus) { if (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);
var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options]); if (options.type == 'GET' && textStatus !== 'abort' && allowed) { locationReplace(container.url) } };
options.success = function(data, status, xhr) { var previousState = pjax.state;
// If $.pjax.defaults.version is a function, invoke it first.
// Otherwise it can be a static string.
var currentVersion = typeof $.pjax.defaults.version === 'function' ? $.pjax.defaults.version() : $.pjax.defaults.version;
var latestVersion = xhr.getResponseHeader('X-PJAX-Version');
var container = extractContainer(data, xhr, options);
var url = parseURL(container.url); if (hash) { url.hash = hash; container.url = url.href }
// If there is a layout version mismatch, hard load the new url
if (currentVersion && latestVersion && currentVersion !== latestVersion) { locationReplace(container.url); return }
// If the new response is missing a body, hard load the page
if (!container.contents) { locationReplace(container.url); return }
pjax.state = { id: options.id || uniqueId(), url: container.url, title: container.title, container: options.container, fragment: options.fragment, timeout: options.timeout };
if (options.push || options.replace) { window.history.replaceState(pjax.state, container.title, container.url) }
// Only blur the focus if the focused element is within the container.
var blurFocus = $.contains(context, document.activeElement);
// Clear out any focused controls before inserting new page contents.
if (blurFocus) { try { document.activeElement.blur() } catch (e) { /* ignore */ } }
if (container.title) document.title = container.title;
fire('pjax:beforeReplace', [container.contents, options], { state: pjax.state, previousState: previousState }); context.html(container.contents);
// FF bug: Won't autofocus fields that are inserted via JS.
// This behavior is incorrect. So if theres no current focus, autofocus
// the last field.
//
// http://www.w3.org/html/wg/drafts/html/master/forms.html
var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]; if (autofocusEl && document.activeElement !== autofocusEl) { autofocusEl.focus() }
executeStyleTags(container.styles); executeScriptTags(container.scripts);
var scrollTo = options.scrollTo;
// Ensure browser scrolls to the element referenced by the URL anchor
if (hash) { var name = decodeURIComponent(hash.slice(1)); var target = document.getElementById(name) || document.getElementsByName(name)[0]; if (target) scrollTo = $(target).offset().top }
if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo);
fire('pjax:success', [data, status, xhr, options]) };
function executeScriptTags(scripts) { if (!scripts) return;
var urls = []; scripts.each(function() { urls.unshift($(this).attr('src')); }); loadAssets(urls, true); } function executeStyleTags(styles) { if (!styles) return;
var hrefs = []; styles.each(function() { hrefs.unshift($(this).attr('href')); }); loadAssets(hrefs); } // 按顺序加载静态资源
function loadAssets(urls, trigger) { if (urls.length < 1) { if (trigger) { fire('pjax:loaded'); } return; } seajs.use([urls.pop()], function () { loadAssets(urls, trigger); }); }
// Initialize pjax.state for the initial page load. Assume we're
// using the container and options of the link we're loading for the
// back button to the initial page. This ensures good back button
// behavior.
if (!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) }
// Cancel the current request if we're already pjaxing
abortXHR(pjax.xhr);
pjax.options = options; var xhr = pjax.xhr = $.ajax(options);
if (xhr.readyState > 0) { if (options.push && !options.replace) { // Cache current container element before replacing it
cachePush(pjax.state.id, [options.container, cloneContents(context)]);
window.history.pushState(null, "", options.requestUrl) }
fire('pjax:start', [xhr, options]); fire('pjax:send', [xhr, options]) }
return pjax.xhr}
// Public: Reload current page with pjax.
//
// Returns whatever $.pjax returns.
function pjaxReload(container, options) { var defaults = { url: window.location.href, push: false, replace: true, scrollTo: false };
return pjax($.extend(defaults, optionsFor(container, options)))}
// Internal: Hard replace current state with url.
//
// Work for around WebKit
// https://bugs.webkit.org/show_bug.cgi?id=93506
//
// Returns nothing.
function locationReplace(url) { window.history.replaceState(null, "", pjax.state.url); window.location.replace(url)}
var initialPop = true;var initialURL = window.location.href;var initialState = window.history.state;
// Initialize $.pjax.state if possible
// Happens when reloading a page and coming forward from a different
// session history.
if (initialState && initialState.container) { pjax.state = initialState}
// Non-webkit browsers don't fire an initial popstate event
if ('state' in window.history) { initialPop = false}
// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
function onPjaxPopstate(event) {
// Hitting back or forward should override any pending PJAX request.
if (!initialPop) { abortXHR(pjax.xhr) }
var previousState = pjax.state; var state = event.state; var direction;
if (state && state.container) { // When coming forward from a separate history session, will get an
// initial pop with a state we are already at. Skip reloading the current
// page.
if (initialPop && initialURL == state.url) return;
if (previousState) { // If popping back to the same state, just skip.
// Could be clicking back from hashchange rather than a pushState.
if (previousState.id === state.id) return;
// Since state IDs always increase, we can deduce the navigation direction
direction = previousState.id < state.id ? 'forward' : 'back' }
var cache = cacheMapping[state.id] || []; var containerSelector = cache[0] || state.container; var container = $(containerSelector), contents = cache[1];
if (container.length) { if (previousState) { // Cache current container before replacement and inform the
// cache which direction the history shifted.
cachePop(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: false, fragment: state.fragment, timeout: state.timeout, scrollTo: false };
if (contents) { container.trigger('pjax:start', [null, options]);
pjax.state = state; if (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) }
// Force reflow/relayout before the browser tries to restore the
// scroll position.
container[0].offsetHeight // eslint-disable-line no-unused-expressions
} else { locationReplace(location.href) } } initialPop = false}
// Fallback version of main pjax function for browsers that don't
// support pushState.
//
// Returns nothing since it retriggers a hard form submission.
function fallbackPjax(options) { var url = $.isFunction(options.url) ? options.url() : options.url, method = options.type ? options.type.toUpperCase() : 'GET';
var form = $('<form>', { method: method === 'GET' ? 'GET' : 'POST', action: url, style: 'display:none' });
if (method !== 'GET' && method !== 'POST') { form.append($('<input>', { type: 'hidden', name: '_method', value: method.toLowerCase() })) }
var data = options.data; if (typeof data === 'string') { $.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 (typeof data === 'object') { var key; for (key in data) form.append($('<input>', {type: 'hidden', name: key, value: data[key]})) }
$(document.body).append(form); form.submit()}
// Internal: Abort an XmlHttpRequest if it hasn't been completed,
// also removing its event handlers.
function abortXHR(xhr) { if ( xhr && xhr.readyState < 4) { xhr.onreadystatechange = $.noop; xhr.abort() }}
// Internal: Generate unique id for state object.
//
// Use a timestamp instead of a counter since ids should still be
// unique across page loads.
//
// Returns Number.
function uniqueId() { return (new Date).getTime()}
function cloneContents(container) { var cloned = container.clone(); // Unmark script tags as already being eval'd so they can get executed again
// when restored from cache. HAXX: Uses jQuery internal method.
cloned.find('script').each(function(){ if (!this.src) $._data(this, 'globalEval', false) }); return cloned.contents()}
// Internal: Strip internal query params from parsed URL.
//
// Returns sanitized url.href String.
function stripInternalParams(url) { url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '').replace(/^&/, ''); return url.href.replace(/\?($|#)/, '$1')}
// Internal: Parse URL components and returns a Locationish object.
//
// url - String URL
//
// Returns HTMLAnchorElement that acts like Location.
function parseURL(url) { var a = document.createElement('a'); a.href = url; return a}
// Internal: Return the `href` component of given URL object with the hash
// portion removed.
//
// location - Location or HTMLAnchorElement
//
// Returns String
function stripHash(location) { return location.href.replace(/#.*/, '')}
// Internal: Build options Object for arguments.
//
// For convenience the first parameter can be either the container or
// the options object.
//
// Examples
//
// optionsFor('#container')
// // => {container: '#container'}
//
// optionsFor('#container', {push: true})
// // => {container: '#container', push: true}
//
// optionsFor({container: '#container', push: true})
// // => {container: '#container', push: true}
//
// Returns options Object.
function optionsFor(container, options) { if (container && options) { options = $.extend({}, options); options.container = container; return options } else if ($.isPlainObject(container)) { return container } else { return {container: container} }}
// Internal: Filter and find all elements matching the selector.
//
// Where $.fn.find only matches descendants, findAll will test all the
// top level elements in the jQuery object as well.
//
// elems - jQuery object of Elements
// selector - String selector to match
//
// Returns a jQuery object.
function findAll(elems, selector) { return elems.filter(selector).add(elems.find(selector))}
function parseHTML(html) { return $.parseHTML(html, document, true)}
// Internal: Extracts container and metadata from response.
//
// 1. Extracts X-PJAX-URL header if set
// 2. Extracts inline <title> tags
// 3. Builds response Element and extracts fragment if set
//
// data - String response data
// xhr - XHR response
// options - pjax options Object
//
// Returns an Object with url, title, and contents keys.
function extractContainer(data, xhr, options) { var obj = {}, fullDocument = /<html/i.test(data);
// Prefer X-PJAX-URL header if it was set, otherwise fallback to
// using the original requested url.
var serverUrl = xhr.getResponseHeader('X-PJAX-URL'); obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl;
var $head, $body; // Attempt to parse response html into elements
if (fullDocument) { $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])); var head = data.match(/<head[^>]*>([\s\S.]*)<\/head>/i); $head = head != null ? $(parseHTML(head[0])) : $body } else { $head = $body = $(parseHTML(data)) }
// If response data is empty, return fast
if ($body.length === 0) return obj;
// If there's a <title> tag in the header, use it as
// the page's title.
obj.title = findAll($head, 'title').last().text();
if (options.fragment) { var $fragment = $body; // If they specified a fragment, look for it in the response
// and pull it out.
if (options.fragment !== 'body') { $fragment = findAll($fragment, options.fragment).first() }
if ($fragment.length) { obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents();
// If there's no title, look for data-title and title attributes
// on the fragment
if (!obj.title) obj.title = $fragment.attr('title') || $fragment.data('title') }
} else if (!fullDocument) { obj.contents = $body }
// Clean up any <title> tags
if (obj.contents) { // Remove any parent title elements
obj.contents = obj.contents.not(function() { return $(this).is('title') });
// Then scrub any titles from their descendants
obj.contents.find('title').remove();
// Gather all script[src] elements
obj.scripts = findAll(obj.contents, 'script[src]').remove(); obj.contents = obj.contents.not(obj.scripts);
// Collect all link[type="text/css"] elements
obj.styles = findAll(obj.contents, 'link[type="text/css"]').remove(); obj.contents = obj.contents.not(obj.styles); }
// Trim any whitespace off the title
if (obj.title) obj.title = $.trim(obj.title);
return obj}
// Internal: History DOM caching class.
var cacheMapping = {};var cacheForwardStack = [];var cacheBackStack = [];
// Push previous state id and container contents into the history
// cache. Should be called in conjunction with `pushState` to save the
// previous container contents.
//
// id - State ID Number
// value - DOM Element to cache
//
// Returns nothing.
function cachePush(id, value) { cacheMapping[id] = value; cacheBackStack.push(id);
// Remove all entries in forward history stack after pushing a new page.
trimCacheStack(cacheForwardStack, 0);
// Trim back history stack to max cache length.
trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)}
// Shifts cache from directional history cache. Should be
// called on `popstate` with the previous state id and container
// contents.
//
// direction - "forward" or "back" String
// id - State ID Number
// value - DOM Element to cache
//
// Returns nothing.
function cachePop(direction, id, value) { var pushStack, popStack; cacheMapping[id] = value;
if (direction === 'forward') { pushStack = cacheBackStack; popStack = cacheForwardStack } else { pushStack = cacheForwardStack; popStack = cacheBackStack }
pushStack.push(id); id = popStack.pop(); if (id) delete cacheMapping[id];
// Trim whichever stack we just pushed to to max cache length.
trimCacheStack(pushStack, pjax.defaults.maxCacheLength)}
// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
// longer than the specified length, deleting cached DOM elements as necessary.
//
// stack - Array of state IDs
// length - Maximum length to trim to
//
// Returns nothing.
function trimCacheStack(stack, length) { while (stack.length > length) delete cacheMapping[stack.shift()]}
// Public: Find version identifier for the initial page load.
//
// Returns String version or undefined.
function findVersion() { return $('meta').filter(function() { var name = $(this).attr('http-equiv'); return name && name.toUpperCase() === 'X-PJAX-VERSION' }).attr('content')}
// Install pjax functions on $.pjax to enable pushState behavior.
//
// Does nothing if already enabled.
//
// Examples
//
// $.pjax.enable()
//
// Returns nothing.
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: true, replace: false, type: 'GET', dataType: 'html', scrollTo: 0, maxCacheLength: 20, version: findVersion }; $(window).on('popstate.pjax', onPjaxPopstate)}
// Disable pushState behavior.
//
// This is the case when a browser doesn't support pushState. It is
// sometimes useful to disable pushState for debugging on a modern
// browser.
//
// Examples
//
// $.pjax.disable()
//
// Returns nothing.
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)}
// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
if ($.event.props && $.inArray('state', $.event.props) < 0) { $.event.props.push('state')} else if (!('state' in $.Event.prototype)) { $.event.addProp('state')}
// Is pjax supported by this browser?
$.support.pjax = window.history && window.history.pushState && window.history.replaceState && // pushState isn't reliable on iOS until 5.
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/);
if ($.support.pjax) { enable()} else { disable()}
})(jQuery);
|