Move all code that executes after the switches to a new function

If any switches are async, the subsequent code will execute before
the switches are finished. This commit moves all that code to a new
function, and debounces the calls to onSwitch() so it only executes
once, after all the switches finish.

Fizes #72.
This commit is contained in:
Behind The Math
2018-01-20 22:06:03 -05:00
parent ca61c4a840
commit cb0a7cd850
3 changed files with 77 additions and 51 deletions

View File

@@ -14,6 +14,11 @@ var defaultSwitches = require("./lib/switches")
var Pjax = function(options) {
this.firstrun = true
this.state = {
numPendingSwitches: 0,
href: null,
options: null
}
var parseOptions = require("./lib/proto/parse-options.js");
parseOptions.apply(this,[options])
@@ -83,8 +88,12 @@ Pjax.prototype = {
},
onSwitch: function() {
this.parseDOM(document)
trigger(window, "resize scroll")
this.state.numPendingSwitches--
// debounce calls, so we only run this once after all switches are finished.
if (this.state.numPendingSwitches === 0) {
this.afterAllSwitches()
}
},
loadContent: function(html, options) {
@@ -125,22 +134,6 @@ Pjax.prototype = {
// try {
this.switchSelectors(this.options.selectors, tmpEl, document, options)
// FF bug: Wont 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 = Array.prototype.slice.call(document.querySelectorAll("[autofocus]")).pop()
if (autofocusEl && document.activeElement !== autofocusEl) {
autofocusEl.focus();
}
// execute scripts when DOM have been completely updated
this.options.selectors.forEach(function(selector) {
forEachEls(document.querySelectorAll(selector), function(el) {
executeScripts(el)
})
})
// }
// catch(e) {
// if (this.options.debug) {
@@ -181,6 +174,8 @@ Pjax.prototype = {
else if (request.getResponseHeader("X-XHR-Redirected-To")) {
href = request.getResponseHeader("X-XHR-Redirected-To")
}
this.state.href = href
this.state.options = options
try {
this.loadContent(html, options)
@@ -197,8 +192,30 @@ Pjax.prototype = {
throw e
}
}
}.bind(this))
},
if (options.history) {
afterAllSwitches: function() {
trigger(window, "resize scroll")
// FF bug: Wont 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 = Array.prototype.slice.call(document.querySelectorAll("[autofocus]")).pop()
if (autofocusEl && document.activeElement !== autofocusEl) {
autofocusEl.focus();
}
// execute scripts when DOM have been completely updated
this.options.selectors.forEach(function(selector) {
forEachEls(document.querySelectorAll(selector), function(el) {
executeScripts(el)
})
})
if (this.state.options.history) {
if (this.firstrun) {
this.lastUid = this.maxUid = newUid()
this.firstrun = false
@@ -213,12 +230,12 @@ Pjax.prototype = {
// Update browser history
this.lastUid = this.maxUid = newUid()
window.history.pushState({
url: href,
title: options.title,
url: this.state.href,
title: this.state.options.title,
uid: this.maxUid
},
options.title,
href)
this.state.options.title,
this.state.href)
}
this.forEachSelectors(function(el) {
@@ -226,20 +243,25 @@ Pjax.prototype = {
}, this)
// Fire Events
trigger(document,"pjax:complete pjax:success", options)
trigger(document,"pjax:complete pjax:success", this.state.options)
options.analytics()
this.state.options.analytics()
// Scroll page to top on new page load
if (options.scrollTo !== false) {
if (options.scrollTo.length > 1) {
window.scrollTo(options.scrollTo[0], options.scrollTo[1])
if (this.state.options.scrollTo !== false) {
if (this.state.options.scrollTo.length > 1) {
window.scrollTo(this.state.options.scrollTo[0], this.state.options.scrollTo[1])
}
else {
window.scrollTo(0, options.scrollTo)
window.scrollTo(0, this.state.options.scrollTo)
}
}
}.bind(this))
this.state = {
numPendingSwitches: 0,
href: null,
options: null
}
}
}

View File

@@ -24,6 +24,9 @@ module.exports = function(switches, switchesOptions, selectors, fromEl, toEl, op
if (this.log) {
this.log("newEl", newEl, "oldEl", oldEl)
}
this.state.numPendingSwitches++
if (switches[selector]) {
switches[selector].bind(this)(oldEl, newEl, options, switchesOptions[selector])
}

View File

@@ -9,7 +9,8 @@ tape("test switchesSelectors", function(t) {
var pjax = {
onSwitch: function() {
console.log("Switched")
}
},
state: {}
}
var tmpEl = document.implementation.createHTMLDocument()