mirror of https://github.com/vtrois/kratos
feat: 更新 pjax.js
parent
b381bedd07
commit
9f0f64036b
|
@ -6,62 +6,58 @@
|
||||||
|
|
||||||
(function($){
|
(function($){
|
||||||
|
|
||||||
// When called on a container with a selector, fetches the href with
|
// 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
|
// ajax into the container or with the data-pjax attribute on the link
|
||||||
// itself.
|
// itself.
|
||||||
//
|
//
|
||||||
// Tries to make sure the back button and ctrl+click work the way
|
// Tries to make sure the back button and ctrl+click work the way
|
||||||
// you'd expect.
|
// you'd expect.
|
||||||
//
|
//
|
||||||
// Exported as $.fn.pjax
|
// Exported as $.fn.pjax
|
||||||
//
|
//
|
||||||
// Accepts a jQuery ajax options object that may include these
|
// Accepts a jQuery ajax options object that may include these
|
||||||
// pjax specific options:
|
// pjax specific options:
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// container - Where to stick the response body. Usually a String selector.
|
// container - String selector for the element where to place the response body.
|
||||||
// $(container).html(xhr.responseBody)
|
// push - Whether to pushState the URL. Defaults to true (of course).
|
||||||
// (default: current jquery context)
|
// replace - Want to use replaceState instead? That's cool.
|
||||||
// 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.
|
||||||
// For convenience the second parameter can be either the container or
|
//
|
||||||
// the options object.
|
// Returns the jQuery object
|
||||||
//
|
|
||||||
// Returns the jQuery object
|
|
||||||
function fnPjax(selector, container, options) {
|
function fnPjax(selector, container, options) {
|
||||||
var context = this
|
options = optionsFor(container, options)
|
||||||
return this.on('click.pjax', selector, function(event) {
|
return this.on('click.pjax', selector, function(event) {
|
||||||
var opts = $.extend({}, optionsFor(container, options))
|
var opts = options
|
||||||
if (!opts.container)
|
if (!opts.container) {
|
||||||
opts.container = $(this).attr('data-pjax') || context
|
opts = $.extend({}, options)
|
||||||
|
opts.container = $(this).attr('data-pjax')
|
||||||
|
}
|
||||||
handleClick(event, opts)
|
handleClick(event, opts)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public: pjax on click handler
|
// Public: pjax on click handler
|
||||||
//
|
//
|
||||||
// Exported as $.pjax.click.
|
// Exported as $.pjax.click.
|
||||||
//
|
//
|
||||||
// event - "click" jQuery.Event
|
// event - "click" jQuery.Event
|
||||||
// options - pjax options
|
// options - pjax options
|
||||||
//
|
//
|
||||||
// Examples
|
// Examples
|
||||||
//
|
//
|
||||||
// $(document).on('click', 'a', $.pjax.click)
|
// $(document).on('click', 'a', $.pjax.click)
|
||||||
// // is the same as
|
// // is the same as
|
||||||
// $(document).pjax('a')
|
// $(document).pjax('a')
|
||||||
//
|
//
|
||||||
// $(document).on('click', 'a', function(event) {
|
// Returns nothing.
|
||||||
// var container = $(this).closest('[data-pjax-container]')
|
|
||||||
// $.pjax.click(event, container)
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// Returns nothing.
|
|
||||||
function handleClick(event, container, options) {
|
function handleClick(event, container, options) {
|
||||||
options = optionsFor(container, options)
|
options = optionsFor(container, options)
|
||||||
|
|
||||||
var link = event.currentTarget
|
var link = event.currentTarget
|
||||||
|
var $link = $(link)
|
||||||
|
|
||||||
if (link.tagName.toUpperCase() !== 'A')
|
if (link.tagName.toUpperCase() !== 'A')
|
||||||
throw "$.fn.pjax or $.pjax.click requires an anchor element"
|
throw "$.fn.pjax or $.pjax.click requires an anchor element"
|
||||||
|
@ -85,36 +81,35 @@
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
url: link.href,
|
url: link.href,
|
||||||
container: $(link).attr('data-pjax'),
|
container: $link.attr('data-pjax'),
|
||||||
target: link
|
target: link
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts = $.extend({}, defaults, options)
|
var opts = $.extend({}, defaults, options)
|
||||||
var clickEvent = $.Event('pjax:click')
|
var clickEvent = $.Event('pjax:click')
|
||||||
$(link).trigger(clickEvent, [opts])
|
$link.trigger(clickEvent, [opts])
|
||||||
|
|
||||||
if (!clickEvent.isDefaultPrevented()) {
|
if (!clickEvent.isDefaultPrevented()) {
|
||||||
pjax(opts)
|
pjax(opts)
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
$(link).trigger('pjax:clicked', [opts])
|
$link.trigger('pjax:clicked', [opts])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public: pjax on form submit handler
|
// Public: pjax on form submit handler
|
||||||
//
|
//
|
||||||
// Exported as $.pjax.submit
|
// Exported as $.pjax.submit
|
||||||
//
|
//
|
||||||
// event - "click" jQuery.Event
|
// event - "click" jQuery.Event
|
||||||
// options - pjax options
|
// options - pjax options
|
||||||
//
|
//
|
||||||
// Examples
|
// Examples
|
||||||
//
|
//
|
||||||
// $(document).on('submit', 'form', function(event) {
|
// $(document).on('submit', 'form', function(event) {
|
||||||
// var container = $(this).closest('[data-pjax-container]')
|
// $.pjax.submit(event, '[data-pjax-container]')
|
||||||
// $.pjax.submit(event, container)
|
// })
|
||||||
// })
|
//
|
||||||
//
|
// Returns nothing.
|
||||||
// Returns nothing.
|
|
||||||
function handleSubmit(event, container, options) {
|
function handleSubmit(event, container, options) {
|
||||||
options = optionsFor(container, options)
|
options = optionsFor(container, options)
|
||||||
|
|
||||||
|
@ -132,17 +127,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaults.type !== 'GET' && window.FormData !== undefined) {
|
if (defaults.type !== 'GET' && window.FormData !== undefined) {
|
||||||
defaults.data = new FormData(form);
|
defaults.data = new FormData(form)
|
||||||
defaults.processData = false;
|
defaults.processData = false
|
||||||
defaults.contentType = false;
|
defaults.contentType = false
|
||||||
} else {
|
} else {
|
||||||
// Can't handle file uploads, exit
|
// Can't handle file uploads, exit
|
||||||
if ($(form).find(':file').length) {
|
if ($form.find(':file').length) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to manually serializing the fields
|
// Fallback to manually serializing the fields
|
||||||
defaults.data = $(form).serializeArray();
|
defaults.data = $form.serializeArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
pjax($.extend({}, defaults, options))
|
pjax($.extend({}, defaults, options))
|
||||||
|
@ -150,25 +145,24 @@
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads a URL with ajax, puts the response body inside a container,
|
// Loads a URL with ajax, puts the response body inside a container,
|
||||||
// then pushState()'s the loaded URL.
|
// then pushState()'s the loaded URL.
|
||||||
//
|
//
|
||||||
// Works just like $.ajax in that it accepts a jQuery ajax
|
// Works just like $.ajax in that it accepts a jQuery ajax
|
||||||
// settings object (with keys like url, type, data, etc).
|
// settings object (with keys like url, type, data, etc).
|
||||||
//
|
//
|
||||||
// Accepts these extra keys:
|
// Accepts these extra keys:
|
||||||
//
|
//
|
||||||
// container - Where to stick the response body.
|
// container - String selector for where to stick the response body.
|
||||||
// $(container).html(xhr.responseBody)
|
// push - Whether to pushState the URL. Defaults to true (of course).
|
||||||
// push - Whether to pushState the URL. Defaults to true (of course).
|
// replace - Want to use replaceState instead? That's cool.
|
||||||
// replace - Want to use replaceState instead? That's cool.
|
//
|
||||||
//
|
// Use it just like $.ajax:
|
||||||
// Use it just like $.ajax:
|
//
|
||||||
//
|
// var xhr = $.pjax({ url: this.href, container: '#main' })
|
||||||
// var xhr = $.pjax({ url: this.href, container: '#main' })
|
// console.log( xhr.readyState )
|
||||||
// console.log( xhr.readyState )
|
//
|
||||||
//
|
// Returns whatever $.ajax returns.
|
||||||
// Returns whatever $.ajax returns.
|
|
||||||
function pjax(options) {
|
function pjax(options) {
|
||||||
options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
|
options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
|
||||||
|
|
||||||
|
@ -176,11 +170,16 @@
|
||||||
options.url = options.url()
|
options.url = options.url()
|
||||||
}
|
}
|
||||||
|
|
||||||
var target = options.target
|
|
||||||
|
|
||||||
var hash = parseURL(options.url).hash
|
var hash = parseURL(options.url).hash
|
||||||
|
|
||||||
var context = options.context = findContainerFor(options.container)
|
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
|
// We want the browser to maintain two separate internal caches: one
|
||||||
// for pjax'd partial page loads and one for normal page loads.
|
// for pjax'd partial page loads and one for normal page loads.
|
||||||
|
@ -188,14 +187,14 @@
|
||||||
// confuse the two.
|
// confuse the two.
|
||||||
if (!options.data) options.data = {}
|
if (!options.data) options.data = {}
|
||||||
if ($.isArray(options.data)) {
|
if ($.isArray(options.data)) {
|
||||||
options.data.push({ name: '_pjax', value: context.selector })
|
options.data.push({name: '_pjax', value: options.container})
|
||||||
} else {
|
} else {
|
||||||
options.data._pjax = context.selector
|
options.data._pjax = options.container
|
||||||
}
|
}
|
||||||
//
|
|
||||||
function fire(type, args, props) {
|
function fire(type, args, props) {
|
||||||
if (!props) props = {}
|
if (!props) props = {}
|
||||||
props.relatedTarget = target
|
props.relatedTarget = options.target
|
||||||
var event = $.Event(type, props)
|
var event = $.Event(type, props)
|
||||||
context.trigger(event, args)
|
context.trigger(event, args)
|
||||||
return !event.isDefaultPrevented()
|
return !event.isDefaultPrevented()
|
||||||
|
@ -211,7 +210,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.setRequestHeader('X-PJAX', 'true')
|
xhr.setRequestHeader('X-PJAX', 'true')
|
||||||
xhr.setRequestHeader('X-PJAX-Container', context.selector)
|
xhr.setRequestHeader('X-PJAX-Container', options.container)
|
||||||
|
|
||||||
if (!fire('pjax:beforeSend', [xhr, settings]))
|
if (!fire('pjax:beforeSend', [xhr, settings]))
|
||||||
return false
|
return false
|
||||||
|
@ -250,13 +249,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
options.success = function(data, status, xhr) {
|
options.success = function(data, status, xhr) {
|
||||||
var previousState = pjax.state;
|
var previousState = pjax.state
|
||||||
|
|
||||||
// If $.pjax.defaults.version is a function, invoke it first.
|
// If $.pjax.defaults.version is a function, invoke it first.
|
||||||
// Otherwise it can be a static string.
|
// Otherwise it can be a static string.
|
||||||
var currentVersion = (typeof $.pjax.defaults.version === 'function') ?
|
var currentVersion = typeof $.pjax.defaults.version === 'function' ?
|
||||||
$.pjax.defaults.version() :
|
$.pjax.defaults.version() :
|
||||||
$.pjax.defaults.version
|
$.pjax.defaults.version
|
||||||
|
|
||||||
var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
|
var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
|
||||||
|
|
||||||
|
@ -284,7 +283,7 @@
|
||||||
id: options.id || uniqueId(),
|
id: options.id || uniqueId(),
|
||||||
url: container.url,
|
url: container.url,
|
||||||
title: container.title,
|
title: container.title,
|
||||||
container: context.selector,
|
container: options.container,
|
||||||
fragment: options.fragment,
|
fragment: options.fragment,
|
||||||
timeout: options.timeout
|
timeout: options.timeout
|
||||||
}
|
}
|
||||||
|
@ -294,13 +293,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only blur the focus if the focused element is within the container.
|
// Only blur the focus if the focused element is within the container.
|
||||||
var blurFocus = $.contains(options.container, document.activeElement)
|
var blurFocus = $.contains(context, document.activeElement)
|
||||||
|
|
||||||
// Clear out any focused controls before inserting new page contents.
|
// Clear out any focused controls before inserting new page contents.
|
||||||
if (blurFocus) {
|
if (blurFocus) {
|
||||||
try {
|
try {
|
||||||
document.activeElement.blur()
|
document.activeElement.blur()
|
||||||
} catch (e) { }
|
} catch (e) { /* ignore */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container.title) document.title = container.title
|
if (container.title) document.title = container.title
|
||||||
|
@ -318,7 +317,7 @@
|
||||||
// http://www.w3.org/html/wg/drafts/html/master/forms.html
|
// http://www.w3.org/html/wg/drafts/html/master/forms.html
|
||||||
var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
|
var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
|
||||||
if (autofocusEl && document.activeElement !== autofocusEl) {
|
if (autofocusEl && document.activeElement !== autofocusEl) {
|
||||||
autofocusEl.focus();
|
autofocusEl.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
executeScriptTags(container.scripts)
|
executeScriptTags(container.scripts)
|
||||||
|
@ -347,7 +346,7 @@
|
||||||
id: uniqueId(),
|
id: uniqueId(),
|
||||||
url: window.location.href,
|
url: window.location.href,
|
||||||
title: document.title,
|
title: document.title,
|
||||||
container: context.selector,
|
container: options.container,
|
||||||
fragment: options.fragment,
|
fragment: options.fragment,
|
||||||
timeout: options.timeout
|
timeout: options.timeout
|
||||||
}
|
}
|
||||||
|
@ -363,7 +362,7 @@
|
||||||
if (xhr.readyState > 0) {
|
if (xhr.readyState > 0) {
|
||||||
if (options.push && !options.replace) {
|
if (options.push && !options.replace) {
|
||||||
// Cache current container element before replacing it
|
// Cache current container element before replacing it
|
||||||
cachePush(pjax.state.id, cloneContents(context))
|
cachePush(pjax.state.id, [options.container, cloneContents(context)])
|
||||||
|
|
||||||
window.history.pushState(null, "", options.requestUrl)
|
window.history.pushState(null, "", options.requestUrl)
|
||||||
}
|
}
|
||||||
|
@ -375,9 +374,9 @@
|
||||||
return pjax.xhr
|
return pjax.xhr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public: Reload current page with pjax.
|
// Public: Reload current page with pjax.
|
||||||
//
|
//
|
||||||
// Returns whatever $.pjax returns.
|
// Returns whatever $.pjax returns.
|
||||||
function pjaxReload(container, options) {
|
function pjaxReload(container, options) {
|
||||||
var defaults = {
|
var defaults = {
|
||||||
url: window.location.href,
|
url: window.location.href,
|
||||||
|
@ -389,12 +388,12 @@
|
||||||
return pjax($.extend(defaults, optionsFor(container, options)))
|
return pjax($.extend(defaults, optionsFor(container, options)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Hard replace current state with url.
|
// Internal: Hard replace current state with url.
|
||||||
//
|
//
|
||||||
// Work for around WebKit
|
// Work for around WebKit
|
||||||
// https://bugs.webkit.org/show_bug.cgi?id=93506
|
// https://bugs.webkit.org/show_bug.cgi?id=93506
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function locationReplace(url) {
|
function locationReplace(url) {
|
||||||
window.history.replaceState(null, "", pjax.state.url)
|
window.history.replaceState(null, "", pjax.state.url)
|
||||||
window.location.replace(url)
|
window.location.replace(url)
|
||||||
|
@ -405,25 +404,26 @@
|
||||||
var initialURL = window.location.href
|
var initialURL = window.location.href
|
||||||
var initialState = window.history.state
|
var initialState = window.history.state
|
||||||
|
|
||||||
// Initialize $.pjax.state if possible
|
// Initialize $.pjax.state if possible
|
||||||
// Happens when reloading a page and coming forward from a different
|
// Happens when reloading a page and coming forward from a different
|
||||||
// session history.
|
// session history.
|
||||||
if (initialState && initialState.container) {
|
if (initialState && initialState.container) {
|
||||||
pjax.state = initialState
|
pjax.state = initialState
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-webkit browsers don't fire an initial popstate event
|
// Non-webkit browsers don't fire an initial popstate event
|
||||||
if ('state' in window.history) {
|
if ('state' in window.history) {
|
||||||
initialPop = false
|
initialPop = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// popstate handler takes care of the back and forward buttons
|
// popstate handler takes care of the back and forward buttons
|
||||||
//
|
//
|
||||||
// You probably shouldn't use pjax on pages with other pushState
|
// You probably shouldn't use pjax on pages with other pushState
|
||||||
// stuff yet.
|
// stuff yet.
|
||||||
function onPjaxPopstate(event) {
|
function onPjaxPopstate(event) {
|
||||||
// Hitting back or forward should override any pending PJAX request.
|
|
||||||
if (!initialPop) {
|
// Hitting back or forward should override any pending PJAX request.
|
||||||
|
if (!initialPop) {
|
||||||
abortXHR(pjax.xhr)
|
abortXHR(pjax.xhr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,16 +445,16 @@
|
||||||
// Since state IDs always increase, we can deduce the navigation direction
|
// Since state IDs always increase, we can deduce the navigation direction
|
||||||
direction = previousState.id < state.id ? 'forward' : 'back'
|
direction = previousState.id < state.id ? 'forward' : 'back'
|
||||||
}
|
}
|
||||||
//changed by jackchain cancel cache;
|
|
||||||
var cache = cacheMapping[state.id] || []
|
var cache = cacheMapping[state.id] || []
|
||||||
//console.log(cache);
|
var containerSelector = cache[0] || state.container
|
||||||
var container = $(cache[0] || state.container), contents = cache[1]
|
var container = $(containerSelector), contents = cache[1]
|
||||||
//console.log(container);
|
|
||||||
if (container.length) {
|
if (container.length) {
|
||||||
if (previousState) {
|
if (previousState) {
|
||||||
// Cache current container before replacement and inform the
|
// Cache current container before replacement and inform the
|
||||||
// cache which direction the history shifted.
|
// cache which direction the history shifted.
|
||||||
cachePop(direction, previousState.id, cloneContents(container))
|
cachePop(direction, previousState.id, [containerSelector, cloneContents(container)])
|
||||||
}
|
}
|
||||||
|
|
||||||
var popstateEvent = $.Event('pjax:popstate', {
|
var popstateEvent = $.Event('pjax:popstate', {
|
||||||
|
@ -466,7 +466,7 @@
|
||||||
var options = {
|
var options = {
|
||||||
id: state.id,
|
id: state.id,
|
||||||
url: state.url,
|
url: state.url,
|
||||||
container: container,
|
container: containerSelector,
|
||||||
push: false,
|
push: false,
|
||||||
fragment: state.fragment,
|
fragment: state.fragment,
|
||||||
timeout: state.timeout,
|
timeout: state.timeout,
|
||||||
|
@ -492,18 +492,18 @@
|
||||||
|
|
||||||
// Force reflow/relayout before the browser tries to restore the
|
// Force reflow/relayout before the browser tries to restore the
|
||||||
// scroll position.
|
// scroll position.
|
||||||
container[0].offsetHeight
|
container[0].offsetHeight // eslint-disable-line no-unused-expressions
|
||||||
} else {
|
} else {
|
||||||
locationReplace(location.href)
|
locationReplace(location.href)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initialPop = false
|
initialPop = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback version of main pjax function for browsers that don't
|
// Fallback version of main pjax function for browsers that don't
|
||||||
// support pushState.
|
// support pushState.
|
||||||
//
|
//
|
||||||
// Returns nothing since it retriggers a hard form submission.
|
// Returns nothing since it retriggers a hard form submission.
|
||||||
function fallbackPjax(options) {
|
function fallbackPjax(options) {
|
||||||
var url = $.isFunction(options.url) ? options.url() : options.url,
|
var url = $.isFunction(options.url) ? options.url() : options.url,
|
||||||
method = options.type ? options.type.toUpperCase() : 'GET'
|
method = options.type ? options.type.toUpperCase() : 'GET'
|
||||||
|
@ -542,8 +542,8 @@
|
||||||
form.submit()
|
form.submit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Abort an XmlHttpRequest if it hasn't been completed,
|
// Internal: Abort an XmlHttpRequest if it hasn't been completed,
|
||||||
// also removing its event handlers.
|
// also removing its event handlers.
|
||||||
function abortXHR(xhr) {
|
function abortXHR(xhr) {
|
||||||
if ( xhr && xhr.readyState < 4) {
|
if ( xhr && xhr.readyState < 4) {
|
||||||
xhr.onreadystatechange = $.noop
|
xhr.onreadystatechange = $.noop
|
||||||
|
@ -551,12 +551,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Generate unique id for state object.
|
// Internal: Generate unique id for state object.
|
||||||
//
|
//
|
||||||
// Use a timestamp instead of a counter since ids should still be
|
// Use a timestamp instead of a counter since ids should still be
|
||||||
// unique across page loads.
|
// unique across page loads.
|
||||||
//
|
//
|
||||||
// Returns Number.
|
// Returns Number.
|
||||||
function uniqueId() {
|
function uniqueId() {
|
||||||
return (new Date).getTime()
|
return (new Date).getTime()
|
||||||
}
|
}
|
||||||
|
@ -566,127 +566,97 @@
|
||||||
// Unmark script tags as already being eval'd so they can get executed again
|
// Unmark script tags as already being eval'd so they can get executed again
|
||||||
// when restored from cache. HAXX: Uses jQuery internal method.
|
// when restored from cache. HAXX: Uses jQuery internal method.
|
||||||
cloned.find('script').each(function(){
|
cloned.find('script').each(function(){
|
||||||
if (!this.src) jQuery._data(this, 'globalEval', false)
|
if (!this.src) $._data(this, 'globalEval', false)
|
||||||
})
|
})
|
||||||
return [container.selector, cloned.contents()]
|
return cloned.contents()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Strip internal query params from parsed URL.
|
// Internal: Strip internal query params from parsed URL.
|
||||||
//
|
//
|
||||||
// Returns sanitized url.href String.
|
// Returns sanitized url.href String.
|
||||||
function stripInternalParams(url) {
|
function stripInternalParams(url) {
|
||||||
url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '')
|
url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '').replace(/^&/, '')
|
||||||
return url.href.replace(/\?($|#)/, '$1')
|
return url.href.replace(/\?($|#)/, '$1')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Parse URL components and returns a Locationish object.
|
// Internal: Parse URL components and returns a Locationish object.
|
||||||
//
|
//
|
||||||
// url - String URL
|
// url - String URL
|
||||||
//
|
//
|
||||||
// Returns HTMLAnchorElement that acts like Location.
|
// Returns HTMLAnchorElement that acts like Location.
|
||||||
function parseURL(url) {
|
function parseURL(url) {
|
||||||
var a = document.createElement('a')
|
var a = document.createElement('a')
|
||||||
a.href = url
|
a.href = url
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Return the `href` component of given URL object with the hash
|
// Internal: Return the `href` component of given URL object with the hash
|
||||||
// portion removed.
|
// portion removed.
|
||||||
//
|
//
|
||||||
// location - Location or HTMLAnchorElement
|
// location - Location or HTMLAnchorElement
|
||||||
//
|
//
|
||||||
// Returns String
|
// Returns String
|
||||||
function stripHash(location) {
|
function stripHash(location) {
|
||||||
return location.href.replace(/#.*/, '')
|
return location.href.replace(/#.*/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Build options Object for arguments.
|
// Internal: Build options Object for arguments.
|
||||||
//
|
//
|
||||||
// For convenience the first parameter can be either the container or
|
// For convenience the first parameter can be either the container or
|
||||||
// the options object.
|
// the options object.
|
||||||
//
|
//
|
||||||
// Examples
|
// Examples
|
||||||
//
|
//
|
||||||
// optionsFor('#container')
|
// optionsFor('#container')
|
||||||
// // => {container: '#container'}
|
// // => {container: '#container'}
|
||||||
//
|
//
|
||||||
// optionsFor('#container', {push: true})
|
// optionsFor('#container', {push: true})
|
||||||
// // => {container: '#container', push: true}
|
// // => {container: '#container', push: true}
|
||||||
//
|
//
|
||||||
// optionsFor({container: '#container', push: true})
|
// optionsFor({container: '#container', push: true})
|
||||||
// // => {container: '#container', push: true}
|
// // => {container: '#container', push: true}
|
||||||
//
|
//
|
||||||
// Returns options Object.
|
// Returns options Object.
|
||||||
function optionsFor(container, options) {
|
function optionsFor(container, options) {
|
||||||
// Both container and options
|
if (container && options) {
|
||||||
if ( container && options )
|
options = $.extend({}, options)
|
||||||
options.container = container
|
options.container = container
|
||||||
|
return options
|
||||||
// First argument is options Object
|
} else if ($.isPlainObject(container)) {
|
||||||
else if ( $.isPlainObject(container) )
|
|
||||||
options = container
|
|
||||||
|
|
||||||
// Only container
|
|
||||||
else
|
|
||||||
options = {container: container}
|
|
||||||
|
|
||||||
// Find and validate container
|
|
||||||
if (options.container)
|
|
||||||
options.container = findContainerFor(options.container)
|
|
||||||
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal: Find container element for a variety of inputs.
|
|
||||||
//
|
|
||||||
// Because we can't persist elements using the history API, we must be
|
|
||||||
// able to find a String selector that will consistently find the Element.
|
|
||||||
//
|
|
||||||
// container - A selector String, jQuery object, or DOM Element.
|
|
||||||
//
|
|
||||||
// Returns a jQuery object whose context is `document` and has a selector.
|
|
||||||
function findContainerFor(container) {
|
|
||||||
container = $(container)
|
|
||||||
|
|
||||||
if ( !container.length ) {
|
|
||||||
throw "no pjax container for " + container.selector
|
|
||||||
} else if ( container.selector !== '' && container.context === document ) {
|
|
||||||
return container
|
return container
|
||||||
} else if ( container.attr('id') ) {
|
|
||||||
return $('#' + container.attr('id'))
|
|
||||||
} else {
|
} else {
|
||||||
throw "cant get selector for pjax container!"
|
return {container: container}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Filter and find all elements matching the selector.
|
// Internal: Filter and find all elements matching the selector.
|
||||||
//
|
//
|
||||||
// Where $.fn.find only matches descendants, findAll will test all the
|
// Where $.fn.find only matches descendants, findAll will test all the
|
||||||
// top level elements in the jQuery object as well.
|
// top level elements in the jQuery object as well.
|
||||||
//
|
//
|
||||||
// elems - jQuery object of Elements
|
// elems - jQuery object of Elements
|
||||||
// selector - String selector to match
|
// selector - String selector to match
|
||||||
//
|
//
|
||||||
// Returns a jQuery object.
|
// Returns a jQuery object.
|
||||||
function findAll(elems, selector) {
|
function findAll(elems, selector) {
|
||||||
return elems.filter(selector).add(elems.find(selector));
|
return elems.filter(selector).add(elems.find(selector))
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseHTML(html) {
|
function parseHTML(html) {
|
||||||
return $.parseHTML(html, document, true)
|
return $.parseHTML(html, document, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: Extracts container and metadata from response.
|
// Internal: Extracts container and metadata from response.
|
||||||
//
|
//
|
||||||
// 1. Extracts X-PJAX-URL header if set
|
// 1. Extracts X-PJAX-URL header if set
|
||||||
// 2. Extracts inline <title> tags
|
// 2. Extracts inline <title> tags
|
||||||
// 3. Builds response Element and extracts fragment if set
|
// 3. Builds response Element and extracts fragment if set
|
||||||
//
|
//
|
||||||
// data - String response data
|
// data - String response data
|
||||||
// xhr - XHR response
|
// xhr - XHR response
|
||||||
// options - pjax options Object
|
// options - pjax options Object
|
||||||
//
|
//
|
||||||
// Returns an Object with url, title, and contents keys.
|
// Returns an Object with url, title, and contents keys.
|
||||||
function extractContainer(data, xhr, options) {
|
function extractContainer(data, xhr, options) {
|
||||||
var obj = {}, fullDocument = /<html/i.test(data)
|
var obj = {}, fullDocument = /<html/i.test(data)
|
||||||
|
|
||||||
|
@ -695,12 +665,14 @@
|
||||||
var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
|
var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
|
||||||
obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl
|
obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl
|
||||||
|
|
||||||
|
var $head, $body
|
||||||
// Attempt to parse response html into elements
|
// Attempt to parse response html into elements
|
||||||
if (fullDocument) {
|
if (fullDocument) {
|
||||||
var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]))
|
$body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
|
||||||
var $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 {
|
} else {
|
||||||
var $head = $body = $(parseHTML(data))
|
$head = $body = $(parseHTML(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If response data is empty, return fast
|
// If response data is empty, return fast
|
||||||
|
@ -712,12 +684,11 @@
|
||||||
obj.title = findAll($head, 'title').last().text()
|
obj.title = findAll($head, 'title').last().text()
|
||||||
|
|
||||||
if (options.fragment) {
|
if (options.fragment) {
|
||||||
|
var $fragment = $body
|
||||||
// If they specified a fragment, look for it in the response
|
// If they specified a fragment, look for it in the response
|
||||||
// and pull it out.
|
// and pull it out.
|
||||||
if (options.fragment === 'body') {
|
if (options.fragment !== 'body') {
|
||||||
var $fragment = $body
|
$fragment = findAll($fragment, options.fragment).first()
|
||||||
} else {
|
|
||||||
var $fragment = findAll($body, options.fragment).first()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($fragment.length) {
|
if ($fragment.length) {
|
||||||
|
@ -741,13 +712,9 @@
|
||||||
// Then scrub any titles from their descendants
|
// Then scrub any titles from their descendants
|
||||||
obj.contents.find('title').remove()
|
obj.contents.find('title').remove()
|
||||||
|
|
||||||
// Gather all script[src] elements
|
// Gather all script[src] elements
|
||||||
//console.log(obj.contents);
|
obj.scripts = findAll(obj.contents, 'script[src]').remove()
|
||||||
//obj.scripts = findAll(obj.contents, 'script[src]').remove()
|
obj.contents = obj.contents.not(obj.scripts)
|
||||||
//console.log(obj.contents);
|
|
||||||
//console.log(obj.scripts);
|
|
||||||
//obj.contents = obj.contents.not(obj.scripts)
|
|
||||||
//console.log(obj.contents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim any whitespace off the title
|
// Trim any whitespace off the title
|
||||||
|
@ -756,20 +723,21 @@
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load an execute scripts using standard script request.
|
// Load an execute scripts using standard script request.
|
||||||
//
|
//
|
||||||
// Avoids jQuery's traditional $.getScript which does a XHR request and
|
// Avoids jQuery's traditional $.getScript which does a XHR request and
|
||||||
// globalEval.
|
// globalEval.
|
||||||
//
|
//
|
||||||
// scripts - jQuery object of script Elements
|
// scripts - jQuery object of script Elements
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function executeScriptTags(scripts) {
|
function executeScriptTags(scripts) {
|
||||||
if (!scripts) return
|
if (!scripts) return
|
||||||
|
|
||||||
var existingScripts = $('script[src]')
|
var existingScripts = $('script[src]')
|
||||||
|
|
||||||
scripts.each(function() {
|
scripts.each(function() {
|
||||||
var src = this.src;
|
var src = this.src
|
||||||
var matchedScripts = existingScripts.filter(function() {
|
var matchedScripts = existingScripts.filter(function() {
|
||||||
return this.src === src
|
return this.src === src
|
||||||
})
|
})
|
||||||
|
@ -783,19 +751,19 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal: History DOM caching class.
|
// Internal: History DOM caching class.
|
||||||
var cacheMapping = {}
|
var cacheMapping = {}
|
||||||
var cacheForwardStack = []
|
var cacheForwardStack = []
|
||||||
var cacheBackStack = []
|
var cacheBackStack = []
|
||||||
|
|
||||||
// Push previous state id and container contents into the history
|
// Push previous state id and container contents into the history
|
||||||
// cache. Should be called in conjunction with `pushState` to save the
|
// cache. Should be called in conjunction with `pushState` to save the
|
||||||
// previous container contents.
|
// previous container contents.
|
||||||
//
|
//
|
||||||
// id - State ID Number
|
// id - State ID Number
|
||||||
// value - DOM Element to cache
|
// value - DOM Element to cache
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function cachePush(id, value) {
|
function cachePush(id, value) {
|
||||||
cacheMapping[id] = value
|
cacheMapping[id] = value
|
||||||
cacheBackStack.push(id)
|
cacheBackStack.push(id)
|
||||||
|
@ -807,15 +775,15 @@
|
||||||
trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
|
trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shifts cache from directional history cache. Should be
|
// Shifts cache from directional history cache. Should be
|
||||||
// called on `popstate` with the previous state id and container
|
// called on `popstate` with the previous state id and container
|
||||||
// contents.
|
// contents.
|
||||||
//
|
//
|
||||||
// direction - "forward" or "back" String
|
// direction - "forward" or "back" String
|
||||||
// id - State ID Number
|
// id - State ID Number
|
||||||
// value - DOM Element to cache
|
// value - DOM Element to cache
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function cachePop(direction, id, value) {
|
function cachePop(direction, id, value) {
|
||||||
var pushStack, popStack
|
var pushStack, popStack
|
||||||
cacheMapping[id] = value
|
cacheMapping[id] = value
|
||||||
|
@ -829,28 +797,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
pushStack.push(id)
|
pushStack.push(id)
|
||||||
if (id = popStack.pop())
|
id = popStack.pop()
|
||||||
delete cacheMapping[id]
|
if (id) delete cacheMapping[id]
|
||||||
|
|
||||||
// Trim whichever stack we just pushed to to max cache length.
|
// Trim whichever stack we just pushed to to max cache length.
|
||||||
trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
|
trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
|
// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
|
||||||
// longer than the specified length, deleting cached DOM elements as necessary.
|
// longer than the specified length, deleting cached DOM elements as necessary.
|
||||||
//
|
//
|
||||||
// stack - Array of state IDs
|
// stack - Array of state IDs
|
||||||
// length - Maximum length to trim to
|
// length - Maximum length to trim to
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function trimCacheStack(stack, length) {
|
function trimCacheStack(stack, length) {
|
||||||
while (stack.length > length)
|
while (stack.length > length)
|
||||||
delete cacheMapping[stack.shift()]
|
delete cacheMapping[stack.shift()]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public: Find version identifier for the initial page load.
|
// Public: Find version identifier for the initial page load.
|
||||||
//
|
//
|
||||||
// Returns String version or undefined.
|
// Returns String version or undefined.
|
||||||
function findVersion() {
|
function findVersion() {
|
||||||
return $('meta').filter(function() {
|
return $('meta').filter(function() {
|
||||||
var name = $(this).attr('http-equiv')
|
var name = $(this).attr('http-equiv')
|
||||||
|
@ -858,15 +826,15 @@
|
||||||
}).attr('content')
|
}).attr('content')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install pjax functions on $.pjax to enable pushState behavior.
|
// Install pjax functions on $.pjax to enable pushState behavior.
|
||||||
//
|
//
|
||||||
// Does nothing if already enabled.
|
// Does nothing if already enabled.
|
||||||
//
|
//
|
||||||
// Examples
|
// Examples
|
||||||
//
|
//
|
||||||
// $.pjax.enable()
|
// $.pjax.enable()
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function enable() {
|
function enable() {
|
||||||
$.fn.pjax = fnPjax
|
$.fn.pjax = fnPjax
|
||||||
$.pjax = pjax
|
$.pjax = pjax
|
||||||
|
@ -882,24 +850,23 @@
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
dataType: 'html',
|
dataType: 'html',
|
||||||
scrollTo: 0,
|
scrollTo: 0,
|
||||||
maxCacheLength: 0,
|
maxCacheLength: 20,
|
||||||
//cache:false,//changed by jackchain fire IE cache bug
|
|
||||||
version: findVersion
|
version: findVersion
|
||||||
}
|
}
|
||||||
$(window).on('popstate.pjax', onPjaxPopstate)
|
$(window).on('popstate.pjax', onPjaxPopstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable pushState behavior.
|
// Disable pushState behavior.
|
||||||
//
|
//
|
||||||
// This is the case when a browser doesn't support pushState. It is
|
// This is the case when a browser doesn't support pushState. It is
|
||||||
// sometimes useful to disable pushState for debugging on a modern
|
// sometimes useful to disable pushState for debugging on a modern
|
||||||
// browser.
|
// browser.
|
||||||
//
|
//
|
||||||
// Examples
|
// Examples
|
||||||
//
|
//
|
||||||
// $.pjax.disable()
|
// $.pjax.disable()
|
||||||
//
|
//
|
||||||
// Returns nothing.
|
// Returns nothing.
|
||||||
function disable() {
|
function disable() {
|
||||||
$.fn.pjax = function() { return this }
|
$.fn.pjax = function() { return this }
|
||||||
$.pjax = fallbackPjax
|
$.pjax = fallbackPjax
|
||||||
|
@ -913,17 +880,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Add the state property to jQuery's event object so we can use it in
|
// Add the state property to jQuery's event object so we can use it in
|
||||||
// $(window).bind('popstate')
|
// $(window).bind('popstate')
|
||||||
if ( $.inArray('state', $.event.props) < 0 )
|
if ($.event.props && $.inArray('state', $.event.props) < 0) {
|
||||||
$.event.props.push('state')
|
$.event.props.push('state')
|
||||||
|
} else if (!('state' in $.Event.prototype)) {
|
||||||
|
$.event.addProp('state')
|
||||||
|
}
|
||||||
|
|
||||||
// Is pjax supported by this browser?
|
// Is pjax supported by this browser?
|
||||||
$.support.pjax =
|
$.support.pjax =
|
||||||
window.history && window.history.pushState && window.history.replaceState &&
|
window.history && window.history.pushState && window.history.replaceState &&
|
||||||
// pushState isn't reliable on iOS until 5.
|
// pushState isn't reliable on iOS until 5.
|
||||||
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
|
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
|
||||||
|
|
||||||
$.support.pjax ? enable() : disable()
|
if ($.support.pjax) {
|
||||||
|
enable()
|
||||||
|
} else {
|
||||||
|
disable()
|
||||||
|
}
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery)
|
Loading…
Reference in New Issue