Fix async switches #110
125
index.js
125
index.js
@@ -14,6 +14,11 @@ var defaultSwitches = require("./lib/switches")
|
|||||||
|
|
||||||
var Pjax = function(options) {
|
var Pjax = function(options) {
|
||||||
this.firstrun = true
|
this.firstrun = true
|
||||||
|
this.state = {
|
||||||
|
numPendingSwitches: 0,
|
||||||
|
href: null,
|
||||||
|
options: null
|
||||||
|
}
|
||||||
|
|
||||||
var parseOptions = require("./lib/proto/parse-options.js");
|
var parseOptions = require("./lib/proto/parse-options.js");
|
||||||
parseOptions.apply(this,[options])
|
parseOptions.apply(this,[options])
|
||||||
@@ -83,8 +88,12 @@ Pjax.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onSwitch: function() {
|
onSwitch: function() {
|
||||||
this.parseDOM(document)
|
this.state.numPendingSwitches--
|
||||||
trigger(window, "resize scroll")
|
|
||||||
|
// debounce calls, so we only run this once after all switches are finished.
|
||||||
|
if (this.state.numPendingSwitches === 0) {
|
||||||
|
this.afterAllSwitches()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
loadContent: function(html, options) {
|
loadContent: function(html, options) {
|
||||||
@@ -125,22 +134,6 @@ Pjax.prototype = {
|
|||||||
// try {
|
// try {
|
||||||
this.switchSelectors(this.options.selectors, tmpEl, document, options)
|
this.switchSelectors(this.options.selectors, tmpEl, document, options)
|
||||||
|
|
||||||
// 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 = 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) {
|
// catch(e) {
|
||||||
// if (this.options.debug) {
|
// if (this.options.debug) {
|
||||||
@@ -181,6 +174,8 @@ Pjax.prototype = {
|
|||||||
else if (request.getResponseHeader("X-XHR-Redirected-To")) {
|
else if (request.getResponseHeader("X-XHR-Redirected-To")) {
|
||||||
href = request.getResponseHeader("X-XHR-Redirected-To")
|
href = request.getResponseHeader("X-XHR-Redirected-To")
|
||||||
}
|
}
|
||||||
|
this.state.href = href
|
||||||
|
this.state.options = clone(options)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.loadContent(html, options)
|
this.loadContent(html, options)
|
||||||
@@ -197,49 +192,79 @@ Pjax.prototype = {
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}.bind(this))
|
||||||
|
},
|
||||||
|
|
||||||
if (options.history) {
|
afterAllSwitches: function() {
|
||||||
if (this.firstrun) {
|
trigger(window, "resize scroll")
|
||||||
this.lastUid = this.maxUid = newUid()
|
|
||||||
this.firstrun = false
|
// FF bug: Won’t autofocus fields that are inserted via JS.
|
||||||
window.history.replaceState({
|
// 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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var state = this.state
|
||||||
|
|
||||||
|
if (state.options.history) {
|
||||||
|
if (this.firstrun) {
|
||||||
|
this.lastUid = this.maxUid = newUid()
|
||||||
|
this.firstrun = false
|
||||||
|
window.history.replaceState({
|
||||||
url: window.location.href,
|
url: window.location.href,
|
||||||
title: document.title,
|
title: document.title,
|
||||||
uid: this.maxUid
|
uid: this.maxUid
|
||||||
},
|
},
|
||||||
document.title)
|
document.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update browser history
|
// Update browser history
|
||||||
this.lastUid = this.maxUid = newUid()
|
this.lastUid = this.maxUid = newUid()
|
||||||
window.history.pushState({
|
|
||||||
url: href,
|
window.history.pushState({
|
||||||
title: options.title,
|
url: state.href,
|
||||||
|
title: state.options.title,
|
||||||
uid: this.maxUid
|
uid: this.maxUid
|
||||||
},
|
},
|
||||||
options.title,
|
state.options.title,
|
||||||
href)
|
state.href)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.forEachSelectors(function(el) {
|
||||||
|
this.parseDOM(el)
|
||||||
|
}, this)
|
||||||
|
|
||||||
|
// Fire Events
|
||||||
|
trigger(document,"pjax:complete pjax:success", state.options)
|
||||||
|
|
||||||
|
state.options.analytics()
|
||||||
|
|
||||||
|
// Scroll page to top on new page load
|
||||||
|
if (state.options.scrollTo !== false) {
|
||||||
|
if (state.options.scrollTo.length > 1) {
|
||||||
|
window.scrollTo(state.options.scrollTo[0], state.options.scrollTo[1])
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
this.forEachSelectors(function(el) {
|
window.scrollTo(0, state.options.scrollTo)
|
||||||
this.parseDOM(el)
|
|
||||||
}, this)
|
|
||||||
|
|
||||||
// Fire Events
|
|
||||||
trigger(document,"pjax:complete pjax:success", options)
|
|
||||||
|
|
||||||
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])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window.scrollTo(0, options.scrollTo)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
numPendingSwitches: 0,
|
||||||
|
href: null,
|
||||||
|
options: null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ var forEachEls = require("./foreach-els")
|
|||||||
var defaultSwitches = require("./switches")
|
var defaultSwitches = require("./switches")
|
||||||
|
|
||||||
module.exports = function(switches, switchesOptions, selectors, fromEl, toEl, options) {
|
module.exports = function(switches, switchesOptions, selectors, fromEl, toEl, options) {
|
||||||
|
var switchesQueue = [];
|
||||||
|
|
||||||
selectors.forEach(function(selector) {
|
selectors.forEach(function(selector) {
|
||||||
var newEls = fromEl.querySelectorAll(selector)
|
var newEls = fromEl.querySelectorAll(selector)
|
||||||
var oldEls = toEl.querySelectorAll(selector)
|
var oldEls = toEl.querySelectorAll(selector)
|
||||||
@@ -24,12 +26,18 @@ module.exports = function(switches, switchesOptions, selectors, fromEl, toEl, op
|
|||||||
if (this.log) {
|
if (this.log) {
|
||||||
this.log("newEl", newEl, "oldEl", oldEl)
|
this.log("newEl", newEl, "oldEl", oldEl)
|
||||||
}
|
}
|
||||||
if (switches[selector]) {
|
|
||||||
switches[selector].bind(this)(oldEl, newEl, options, switchesOptions[selector])
|
var callback = (switches[selector]) ?
|
||||||
}
|
switches[selector].bind(this, oldEl, newEl, options, switchesOptions[selector]) :
|
||||||
else {
|
defaultSwitches.outerHTML.bind(this, oldEl, newEl, options)
|
||||||
defaultSwitches.outerHTML.bind(this)(oldEl, newEl, options)
|
|
||||||
}
|
switchesQueue.push(callback)
|
||||||
}, this)
|
}, this)
|
||||||
}, this)
|
}, this)
|
||||||
|
|
||||||
|
this.state.numPendingSwitches = switchesQueue.length
|
||||||
|
|
||||||
|
switchesQueue.forEach(function(queuedSwitch) {
|
||||||
|
queuedSwitch()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"lint": "jscs . && jshint . --exclude-path .gitignore",
|
"lint": "jscs . && jshint . --exclude-path .gitignore",
|
||||||
"standalone": "browserify index.js --standalone Pjax > pjax.js",
|
"standalone": "browserify index.js --standalone Pjax > pjax.js",
|
||||||
"build-debug": "browserify index.js --debug --standalone Pjax > pjax.js",
|
"build-debug": "browserify index.js --debug --standalone Pjax > pjax.js",
|
||||||
"tests": "tape -r ./tests/index.js ./tests/**/*.js",
|
"tests": "tape -r ./tests/setup.js ./tests/**/*.js",
|
||||||
"test": "npm run lint && npm run tests | tap-spec",
|
"test": "npm run lint && npm run tests | tap-spec",
|
||||||
"coverage-tests": "npm run tests | tap-nyc",
|
"coverage-tests": "npm run tests | tap-nyc",
|
||||||
"coverage": "nyc -x \"tests/**\" npm run coverage-tests",
|
"coverage": "nyc -x \"tests/**\" npm run coverage-tests",
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ tape("test switchesSelectors", function(t) {
|
|||||||
var pjax = {
|
var pjax = {
|
||||||
onSwitch: function() {
|
onSwitch: function() {
|
||||||
console.log("Switched")
|
console.log("Switched")
|
||||||
}
|
},
|
||||||
|
state: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tmpEl = document.implementation.createHTMLDocument()
|
var tmpEl = document.implementation.createHTMLDocument()
|
||||||
|
|||||||
Reference in New Issue
Block a user