mirror of
https://github.com/humhub/humhub.git
synced 2025-02-24 19:23:21 +01:00
Merge pull request #3020 from githubjeka/patch-1
Fix compatible PJAX with jQuery 3
This commit is contained in:
commit
cdf3764f28
@ -5,28 +5,28 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This modified version removed pjaxs asynchronous script loading mechanism.
|
||||
* Now the script management is handled by yii.js which assures scripts beeing loades synchronously.
|
||||
*
|
||||
*
|
||||
* This was required since the humhub:ready event is was triggered before scripts of pjax results were loaded.
|
||||
* Since those scripts possibly contain widgets or additions required in the page.
|
||||
*
|
||||
*
|
||||
* Therefore we removed the:
|
||||
*
|
||||
*
|
||||
* executeScriptTags(container.scripts, context) call
|
||||
*
|
||||
*
|
||||
* and
|
||||
*
|
||||
*
|
||||
* obj.scripts = findAll(obj.contents, 'script').remove()
|
||||
* obj.contents = obj.contents.not(obj.scripts)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* see:
|
||||
*
|
||||
*
|
||||
* https://github.com/defunkt/jquery-pjax/issues/331
|
||||
* https://github.com/defunkt/jquery-pjax/pull/479
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
(function($){
|
||||
@ -64,11 +64,13 @@
|
||||
//
|
||||
// Returns the jQuery object
|
||||
function fnPjax(selector, container, options) {
|
||||
var context = this
|
||||
options = optionsFor(container, options)
|
||||
return this.on('click.pjax', selector, function(event) {
|
||||
var opts = $.extend({history: true}, optionsFor(container, options))
|
||||
if (!opts.container)
|
||||
opts.container = $(this).attr('data-pjax') || context
|
||||
var opts = options
|
||||
if (!opts.container) {
|
||||
opts = $.extend({}, options)
|
||||
opts.container = $(this).attr('data-pjax')
|
||||
}
|
||||
handleClick(event, opts)
|
||||
})
|
||||
}
|
||||
@ -98,9 +100,9 @@ function handleClick(event, container, options) {
|
||||
options = optionsFor(container, options)
|
||||
|
||||
var link = event.currentTarget
|
||||
|
||||
var $link = $(link)
|
||||
// Ignore links with data-pjax="0"
|
||||
if ($(link).data('pjax') == 0) {
|
||||
if ($link.data('pjax') == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -126,18 +128,18 @@ function handleClick(event, container, options) {
|
||||
|
||||
var defaults = {
|
||||
url: link.href,
|
||||
container: $(link).attr('data-pjax'),
|
||||
container: $link.attr('data-pjax'),
|
||||
target: link
|
||||
}
|
||||
|
||||
var opts = $.extend({}, defaults, options)
|
||||
var clickEvent = $.Event('pjax:click')
|
||||
$(link).trigger(clickEvent, [opts])
|
||||
$link.trigger(clickEvent, [opts])
|
||||
|
||||
if (!clickEvent.isDefaultPrevented()) {
|
||||
pjax(opts)
|
||||
event.preventDefault()
|
||||
$(link).trigger('pjax:clicked', [opts])
|
||||
$link.trigger('pjax:clicked', [opts])
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,8 +153,7 @@ function handleClick(event, container, options) {
|
||||
// Examples
|
||||
//
|
||||
// $(document).on('submit', 'form', function(event) {
|
||||
// var container = $(this).closest('[data-pjax-container]')
|
||||
// $.pjax.submit(event, container)
|
||||
// $.pjax.submit(event, '[data-pjax-container]')
|
||||
// })
|
||||
//
|
||||
// Returns nothing.
|
||||
@ -173,17 +174,17 @@ function handleSubmit(event, container, options) {
|
||||
}
|
||||
|
||||
if (defaults.type !== 'GET' && window.FormData !== undefined) {
|
||||
defaults.data = new FormData(form);
|
||||
defaults.processData = false;
|
||||
defaults.contentType = false;
|
||||
defaults.data = new FormData(form)
|
||||
defaults.processData = false
|
||||
defaults.contentType = false
|
||||
} else {
|
||||
// Can't handle file uploads, exit
|
||||
if ($(form).find(':file').length) {
|
||||
return;
|
||||
if ($form.find(':file').length) {
|
||||
return
|
||||
}
|
||||
|
||||
// Fallback to manually serializing the fields
|
||||
defaults.data = $(form).serializeArray();
|
||||
defaults.data = $form.serializeArray()
|
||||
}
|
||||
|
||||
pjax($.extend({}, defaults, options))
|
||||
@ -199,8 +200,7 @@ function handleSubmit(event, container, options) {
|
||||
//
|
||||
// Accepts these extra keys:
|
||||
//
|
||||
// container - Where to stick the response body.
|
||||
// $(container).html(xhr.responseBody)
|
||||
// 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.
|
||||
//
|
||||
@ -217,11 +217,16 @@ function pjax(options) {
|
||||
options.url = options.url()
|
||||
}
|
||||
|
||||
var target = options.target
|
||||
|
||||
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
|
||||
// for pjax'd partial page loads and one for normal page loads.
|
||||
@ -229,15 +234,14 @@ function pjax(options) {
|
||||
// confuse the two.
|
||||
if (!options.data) options.data = {}
|
||||
if ($.isArray(options.data)) {
|
||||
options.data = $.grep(options.data, function(obj) { return '_pjax' !== obj.name })
|
||||
options.data.push({name: '_pjax', value: context.selector})
|
||||
options.data.push({name: '_pjax', value: options.container})
|
||||
} else {
|
||||
options.data._pjax = context.selector
|
||||
options.data._pjax = options.container
|
||||
}
|
||||
|
||||
function fire(type, args, props) {
|
||||
if (!props) props = {}
|
||||
props.relatedTarget = target
|
||||
props.relatedTarget = options.target
|
||||
var event = $.Event(type, props)
|
||||
context.trigger(event, args)
|
||||
return !event.isDefaultPrevented()
|
||||
@ -253,14 +257,7 @@ function pjax(options) {
|
||||
}
|
||||
|
||||
xhr.setRequestHeader('X-PJAX', 'true')
|
||||
xhr.setRequestHeader('X-PJAX-Container', context.selector)
|
||||
|
||||
if (settings.ieRedirectCompatibility) {
|
||||
var ua = window.navigator.userAgent
|
||||
if (ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0) {
|
||||
xhr.setRequestHeader('X-Ie-Redirect-Compatibility', 'true')
|
||||
}
|
||||
}
|
||||
xhr.setRequestHeader('X-PJAX-Container', options.container)
|
||||
|
||||
if (!fire('pjax:beforeSend', [xhr, settings]))
|
||||
return false
|
||||
@ -291,22 +288,15 @@ function pjax(options) {
|
||||
|
||||
options.error = function(xhr, textStatus, errorThrown) {
|
||||
var container = extractContainer("", xhr, options)
|
||||
// Check redirect status code
|
||||
var redirect = (xhr.status >= 301 && xhr.status <= 303)
|
||||
// Do not fire pjax::error in case of redirect
|
||||
var allowed = redirect || fire('pjax:error', [xhr, textStatus, errorThrown, options])
|
||||
if (redirect || options.type == 'GET' && textStatus !== 'abort' && allowed) {
|
||||
if (options.replaceRedirect) {
|
||||
locationReplace(container.url)
|
||||
} else if (options.pushRedirect) {
|
||||
window.history.pushState(null, "", container.url)
|
||||
window.location.replace(container.url)
|
||||
}
|
||||
|
||||
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;
|
||||
var previousState = pjax.state
|
||||
|
||||
// If $.pjax.defaults.version is a function, invoke it first.
|
||||
// Otherwise it can be a static string.
|
||||
@ -340,13 +330,12 @@ function pjax(options) {
|
||||
id: options.id || uniqueId(),
|
||||
url: container.url,
|
||||
title: container.title,
|
||||
container: context.selector,
|
||||
container: options.container,
|
||||
fragment: options.fragment,
|
||||
timeout: options.timeout,
|
||||
cache: options.cache
|
||||
timeout: options.timeout
|
||||
}
|
||||
|
||||
if (options.history && (options.push || options.replace)) {
|
||||
if (options.push || options.replace) {
|
||||
window.history.replaceState(pjax.state, container.title, container.url)
|
||||
}
|
||||
|
||||
@ -375,9 +364,9 @@ function pjax(options) {
|
||||
// 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();
|
||||
autofocusEl.focus()
|
||||
}
|
||||
|
||||
|
||||
// removed @see headline doc
|
||||
//executeScriptTags(container.scripts, context)
|
||||
|
||||
@ -405,10 +394,9 @@ function pjax(options) {
|
||||
id: uniqueId(),
|
||||
url: window.location.href,
|
||||
title: document.title,
|
||||
container: context.selector,
|
||||
container: options.container,
|
||||
fragment: options.fragment,
|
||||
timeout: options.timeout,
|
||||
cache: options.cache
|
||||
timeout: options.timeout
|
||||
}
|
||||
window.history.replaceState(pjax.state, document.title)
|
||||
}
|
||||
@ -424,9 +412,9 @@ function pjax(options) {
|
||||
var xhr = pjax.xhr = $.ajax(options)
|
||||
|
||||
if (xhr.readyState > 0) {
|
||||
if (options.history && (options.push && !options.replace)) {
|
||||
if (options.push && !options.replace) {
|
||||
// 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)
|
||||
}
|
||||
@ -459,7 +447,6 @@ function pjaxReload(container, options) {
|
||||
//
|
||||
// Returns nothing.
|
||||
function locationReplace(url) {
|
||||
if (!pjax.options.history) return;
|
||||
window.history.replaceState(null, "", pjax.state.url)
|
||||
window.location.replace(url)
|
||||
}
|
||||
@ -486,6 +473,7 @@ if ('state' in window.history) {
|
||||
// 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)
|
||||
@ -510,28 +498,18 @@ function onPjaxPopstate(event) {
|
||||
direction = previousState.id < state.id ? 'forward' : 'back'
|
||||
}
|
||||
|
||||
var cache = cacheMapping[state.id] || [];
|
||||
var container = $(cache[0] || state.container);
|
||||
|
||||
var cache = cacheMapping[state.id] || []
|
||||
var containerSelector = cache[0] || state.container
|
||||
var container = $(containerSelector), contents = cache[1]
|
||||
|
||||
// HUMHUB PATCH, cached content was used even when cache is deactivated.
|
||||
var contents = (state.cache) ? cache[1] : undefined;
|
||||
|
||||
if (container.length) {
|
||||
var options = {
|
||||
id: state.id,
|
||||
url: state.url,
|
||||
container: container,
|
||||
push: false,
|
||||
fragment: state.fragment,
|
||||
timeout: state.timeout,
|
||||
cache: state.cache,
|
||||
scrollTo: false
|
||||
}
|
||||
|
||||
if (previousState && options.cache) {
|
||||
if (previousState) {
|
||||
// Cache current container before replacement and inform the
|
||||
// cache which direction the history shifted.
|
||||
cachePop(direction, previousState.id, cloneContents(container))
|
||||
cachePop(direction, previousState.id, [containerSelector, cloneContents(container)])
|
||||
}
|
||||
|
||||
var popstateEvent = $.Event('pjax:popstate', {
|
||||
@ -540,6 +518,16 @@ function onPjaxPopstate(event) {
|
||||
})
|
||||
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])
|
||||
|
||||
@ -635,7 +623,7 @@ function cloneContents(container) {
|
||||
cloned.find('script').each(function(){
|
||||
if (!this.src) jQuery._data(this, 'globalEval', false)
|
||||
})
|
||||
return [container.selector, cloned.contents()]
|
||||
return cloned.contents()
|
||||
}
|
||||
|
||||
// Internal: Strip internal query params from parsed URL.
|
||||
@ -685,44 +673,14 @@ function stripHash(location) {
|
||||
//
|
||||
// Returns options Object.
|
||||
function optionsFor(container, options) {
|
||||
// Both container and options
|
||||
if ( container && options )
|
||||
if (container && options) {
|
||||
options = $.extend({}, options)
|
||||
options.container = container
|
||||
|
||||
// First argument is options Object
|
||||
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 options
|
||||
} else if ($.isPlainObject(container)) {
|
||||
return container
|
||||
} else if ( container.attr('id') ) {
|
||||
return $('#' + container.attr('id'))
|
||||
} else {
|
||||
throw "cant get selector for pjax container!"
|
||||
return {container: container}
|
||||
}
|
||||
}
|
||||
|
||||
@ -736,7 +694,7 @@ function findContainerFor(container) {
|
||||
//
|
||||
// Returns a jQuery object.
|
||||
function findAll(elems, selector) {
|
||||
return elems.filter(selector).add(elems.find(selector));
|
||||
return elems.filter(selector).add(elems.find(selector))
|
||||
}
|
||||
|
||||
function parseHTML(html) {
|
||||
@ -811,8 +769,8 @@ function extractContainer(data, xhr, options) {
|
||||
// Gather all script elements
|
||||
/*
|
||||
* Removed @see headline documentation.
|
||||
*
|
||||
* obj.scripts = findAll(obj.contents, 'script').remove()
|
||||
*
|
||||
* obj.scripts = findAll(obj.contents, 'script[src]').remove()
|
||||
* obj.contents = obj.contents.not(obj.scripts)
|
||||
*/
|
||||
}
|
||||
@ -829,44 +787,26 @@ function extractContainer(data, xhr, options) {
|
||||
// globalEval.
|
||||
//
|
||||
// scripts - jQuery object of script Elements
|
||||
// context - jQuery object whose context is `document` and has a selector
|
||||
//
|
||||
// Returns nothing.
|
||||
function executeScriptTags(scripts, context) {
|
||||
function executeScriptTags(scripts) {
|
||||
if (!scripts) return
|
||||
|
||||
var existingScripts = $('script[src]')
|
||||
|
||||
var cb = function (next) {
|
||||
scripts.each(function() {
|
||||
var src = this.src
|
||||
var matchedScripts = existingScripts.filter(function () {
|
||||
var matchedScripts = existingScripts.filter(function() {
|
||||
return this.src === src
|
||||
})
|
||||
if (matchedScripts.length) return
|
||||
|
||||
if (matchedScripts.length) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
if (src) {
|
||||
$.getScript(src).done(next).fail(next)
|
||||
document.head.appendChild(this)
|
||||
} else {
|
||||
context.append(this)
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var next = function () {
|
||||
if (i >= scripts.length) {
|
||||
return
|
||||
}
|
||||
var script = scripts[i]
|
||||
i++
|
||||
cb.call(script, next)
|
||||
}
|
||||
next()
|
||||
var script = document.createElement('script')
|
||||
var type = $(this).attr('type')
|
||||
if (type) script.type = type
|
||||
script.src = $(this).attr('src')
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
// Internal: History DOM caching class.
|
||||
@ -883,9 +823,6 @@ var cacheBackStack = []
|
||||
//
|
||||
// Returns nothing.
|
||||
function cachePush(id, value) {
|
||||
if (!pjax.options.cache) {
|
||||
return;
|
||||
}
|
||||
cacheMapping[id] = value
|
||||
cacheBackStack.push(id)
|
||||
|
||||
@ -965,8 +902,6 @@ function enable() {
|
||||
$.pjax.submit = handleSubmit
|
||||
$.pjax.reload = pjaxReload
|
||||
$.pjax.defaults = {
|
||||
history: true,
|
||||
cache: true,
|
||||
timeout: 650,
|
||||
push: true,
|
||||
replace: false,
|
||||
@ -974,11 +909,7 @@ function enable() {
|
||||
dataType: 'html',
|
||||
scrollTo: 0,
|
||||
maxCacheLength: 20,
|
||||
version: findVersion,
|
||||
pushRedirect: false,
|
||||
replaceRedirect: true,
|
||||
skipOuterContainers: false,
|
||||
ieRedirectCompatibility: true
|
||||
version: findVersion
|
||||
}
|
||||
$(window).on('popstate.pjax', onPjaxPopstate)
|
||||
}
|
||||
@ -1009,8 +940,11 @@ function disable() {
|
||||
|
||||
// Add the state property to jQuery's event object so we can use it in
|
||||
// $(window).bind('popstate')
|
||||
if ( $.inArray('state', $.event.props) < 0 )
|
||||
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 =
|
||||
@ -1020,5 +954,4 @@ $.support.pjax =
|
||||
|
||||
$.support.pjax ? enable() : disable()
|
||||
|
||||
})(jQuery);
|
||||
|
||||
})(jQuery)
|
||||
|
Loading…
x
Reference in New Issue
Block a user