loadUrl enhancements (#134)

`loadUrl` enhancements

- Make `options` parameter optional
- Allow partial overriding of instance options when calling `loadUrl` directly
- Make `requestOptions` optional
- Document `loadUrl` usage and provide examples
This commit was merged in pull request #134.
This commit is contained in:
Robin North
2018-03-06 10:06:38 +00:00
committed by GitHub
parent f98f2dd63b
commit 05fa833169
15 changed files with 148 additions and 62 deletions

View File

@@ -124,9 +124,13 @@ To see if Pjax is actually supported by your browser, use `Pjax.isSupported()`.
## Usage ## Usage
### `new Pjax()` ### Methods
Let's talk more about the most basic way to get started: #### `new Pjax()`
Let's talk more about the most basic way to get started.
When instantiating `Pjax`, you can pass options in to the constructor as an object:
```js ```js
new Pjax({ new Pjax({
@@ -153,12 +157,24 @@ Pjax.prototype.getElements = function() {
return document.getElementsByClassName(".js-Pjax") return document.getElementsByClassName(".js-Pjax")
} }
new Pjax({}) new Pjax()
``` ```
When instantiating a `Pjax` object, you need to pass all options as an object: #### `loadUrl(href, [options])`
#### Options With this method, you can manually trigger loading of a URL:
```js
var pjax = new Pjax()
// use case 1 (without options override)
pjax.loadUrl("/your-url")
// use case 2 (with options override)
pjax.loadUrl("/your-other-url", {timeout: 10})
```
### Options
##### `elements` (String, default: `"a[href], form[action]"`) ##### `elements` (String, default: `"a[href], form[action]"`)
@@ -398,8 +414,8 @@ Enables verbose mode. Useful to debug page layout differences.
When set to true, clicking on a link that points to the current URL will trigger a full page reload. When set to true, clicking on a link that points to the current URL will trigger a full page reload.
The default is `false`, so clicking on such a link will do nothing. The default is `false`, so clicking on such a link will do nothing.
If you want to add some custom behavior, add a click listener to the link, If you want to add some custom behavior, add a click listener to the link,
and set `preventDefault` to true, to prevent Pjax from receiving the event. and set `preventDefault` to true, to prevent Pjax from receiving the event.
Here is some sample code: Here is some sample code:
@@ -420,8 +436,8 @@ Here is some sample code:
} }
``` ```
(Note that if `cacheBust` is set to true, the code that checks if the href (Note that if `cacheBust` is set to true, the code that checks if the href
is the same as the current page's URL will not work, due to the query string is the same as the current page's URL will not work, due to the query string
appended to force a cache bust). appended to force a cache bust).
##### `timeout` (Integer, default: `0`) ##### `timeout` (Integer, default: `0`)

View File

@@ -1,4 +1,31 @@
/* global Pjax */ /* global Pjax */
var pjax;
var initButtons = function() {
var buttons = document.querySelectorAll("button[data-manual-trigger]")
if (!buttons) {
return
}
// jshint -W083
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", function(e) {
var el = e.currentTarget
if (el.getAttribute("data-manual-trigger-override") === "true") {
// Manually load URL with overridden Pjax instance options
pjax.loadUrl("/example/page2.html", {cacheBust: false})
}
else
{
// Manually load URL with current Pjax instance options
pjax.loadUrl("/example/page2.html")
}
})
}
// jshint +W083
}
console.log("Document initialized:", window.location.href) console.log("Document initialized:", window.location.href)
document.addEventListener("pjax:send", function() { document.addEventListener("pjax:send", function() {
@@ -15,14 +42,20 @@ document.addEventListener("pjax:error", function() {
document.addEventListener("pjax:success", function() { document.addEventListener("pjax:success", function() {
console.log("Event: pjax:success", arguments) console.log("Event: pjax:success", arguments)
// Init page content
initButtons()
}) })
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
var pjax = new Pjax({ // Init Pjax instance
pjax = new Pjax({
elements: [".js-Pjax"], elements: [".js-Pjax"],
selectors: [".body", "title"], selectors: [".body", "title"],
cacheBust: true, cacheBust: true
// currentUrlFullReload: true,
}) })
console.log("Pjax initialized.", pjax) console.log("Pjax initialized.", pjax)
// Init page content
initButtons()
}) })

View File

@@ -13,6 +13,13 @@
Go to <a href="page2.html" class="js-Pjax">Page 2</a> or <a href="page3.html" class="js-Pjax">Page 3</a> and view your console to see Pjax events. Go to <a href="page2.html" class="js-Pjax">Page 2</a> or <a href="page3.html" class="js-Pjax">Page 3</a> and view your console to see Pjax events.
Clicking on <a href="index.html">this page</a> will just reload the page entirely. Clicking on <a href="index.html">this page</a> will just reload the page entirely.
<h2>Manual URL loading</h2>
You can use Pjax's <i>loadUrl</i> method to manually load a URL. Click the buttons below to try it out!<br /><br />
<button data-manual-trigger>loadUrl with current options</button><br /><br />
<button data-manual-trigger data-manual-trigger-override="true">loadUrl with overridden options (no cache busting)</button>
<h2>Forms</h2> <h2>Forms</h2>
You can submit GET or POST forms with Pjax! Go to the <a href="forms.html">form examples</a> to try it out. You can submit GET or POST forms with Pjax! Go to the <a href="forms.html">form examples</a> to try it out.

View File

@@ -1,13 +1,15 @@
var clone = require("./lib/clone.js")
var executeScripts = require("./lib/execute-scripts.js") var executeScripts = require("./lib/execute-scripts.js")
var forEachEls = require("./lib/foreach-els.js") var forEachEls = require("./lib/foreach-els.js")
var parseOptions = require("./lib/parse-options.js")
var switches = require("./lib/switches") var switches = require("./lib/switches")
var newUid = require("./lib/uniqueid.js") var newUid = require("./lib/uniqueid.js")
var on = require("./lib/events/on.js") var on = require("./lib/events/on.js")
var trigger = require("./lib/events/trigger.js") var trigger = require("./lib/events/trigger.js")
var clone = require("./lib/util/clone.js")
var contains = require("./lib/util/contains.js") var contains = require("./lib/util/contains.js")
var extend = require("./lib/util/extend.js")
var noop = require("./lib/util/noop") var noop = require("./lib/util/noop")
var Pjax = function(options) { var Pjax = function(options) {
@@ -17,8 +19,8 @@ var Pjax = function(options) {
options: null options: null
} }
var parseOptions = require("./lib/proto/parse-options.js")
parseOptions.call(this,options) this.options = parseOptions(options)
this.log("Pjax options", this.options) this.log("Pjax options", this.options)
if (this.options.scrollRestoration && "scrollRestoration" in history) { if (this.options.scrollRestoration && "scrollRestoration" in history) {
@@ -35,7 +37,6 @@ var Pjax = function(options) {
opt.url = st.state.url opt.url = st.state.url
opt.title = st.state.title opt.title = st.state.title
opt.history = false opt.history = false
opt.requestOptions = {}
opt.scrollPos = st.state.scrollPos opt.scrollPos = st.state.scrollPos
if (st.state.uid < this.lastUid) { if (st.state.uid < this.lastUid) {
opt.backward = true opt.backward = true
@@ -142,6 +143,10 @@ Pjax.prototype = {
doRequest: require("./lib/send-request.js"), doRequest: require("./lib/send-request.js"),
loadUrl: function(href, options) { loadUrl: function(href, options) {
options = typeof options === "object" ?
extend({}, this.options, options) :
clone(this.options)
this.log("load href", href, options) this.log("load href", href, options)
// Abort any previous request // Abort any previous request
@@ -150,8 +155,7 @@ Pjax.prototype = {
trigger(document, "pjax:send", options) trigger(document, "pjax:send", options)
// Do the request // Do the request
options.requestOptions.timeout = this.options.timeout this.request = this.doRequest(href, options, function(html, request) {
this.request = this.doRequest(href, options.requestOptions, function(html, request) {
// Fail if unable to load HTML via AJAX // Fail if unable to load HTML via AJAX
if (html === false) { if (html === false) {
trigger(document, "pjax:complete pjax:error", options) trigger(document, "pjax:complete pjax:error", options)

View File

@@ -1,6 +1,6 @@
/* global _gaq: true, ga: true */ /* global _gaq: true, ga: true */
var defaultSwitches = require("../switches") var defaultSwitches = require("./switches")
module.exports = function(options) { module.exports = function(options) {
options = options || {} options = options || {}
@@ -36,5 +36,5 @@ module.exports = function(options) {
options.switches.body = defaultSwitches.switchElementsAlt options.switches.body = defaultSwitches.switchElementsAlt
} }
this.options = options return options
} }

View File

@@ -1,5 +1,5 @@
var on = require("../events/on") var on = require("../events/on")
var clone = require("../clone") var clone = require("../util/clone")
var attrClick = "data-pjax-click-state" var attrClick = "data-pjax-click-state"

View File

@@ -1,5 +1,5 @@
var on = require("../events/on") var on = require("../events/on")
var clone = require("../clone") var clone = require("../util/clone")
var attrClick = "data-pjax-click-state" var attrClick = "data-pjax-click-state"
var attrKey = "data-pjax-keyup-state" var attrKey = "data-pjax-keyup-state"
@@ -9,9 +9,6 @@ var linkAction = function(el, event) {
// clone it so the changes don't persist // clone it so the changes don't persist
var options = clone(this.options) var options = clone(this.options)
// Initialize requestOptions since loadUrl expects it to be an object
options.requestOptions = {}
// Dont break browser special behavior on links (like page in new window) // Dont break browser special behavior on links (like page in new window)
if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) { if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
el.setAttribute(attrClick, "modifier") el.setAttribute(attrClick, "modifier")

View File

@@ -3,10 +3,12 @@ var updateQueryString = require("./util/update-query-string");
module.exports = function(location, options, callback) { module.exports = function(location, options, callback) {
options = options || {} options = options || {}
var queryString var queryString
var requestMethod = (options.requestMethod || "GET").toUpperCase() var requestOptions = options.requestOptions || {}
var requestParams = options.requestParams || null var requestMethod = (requestOptions.requestMethod || "GET").toUpperCase()
var requestParams = requestOptions.requestParams || null
var requestPayload = null var requestPayload = null
var request = new XMLHttpRequest() var request = new XMLHttpRequest()
var timeout = options.timeout || 0
request.onreadystatechange = function() { request.onreadystatechange = function() {
if (request.readyState === 4) { if (request.readyState === 4) {
@@ -51,12 +53,12 @@ module.exports = function(location, options, callback) {
} }
// Add a timestamp as part of the query string if cache busting is enabled // Add a timestamp as part of the query string if cache busting is enabled
if (this.options.cacheBust) { if (options.cacheBust) {
location = updateQueryString(location, "t", Date.now()) location = updateQueryString(location, "t", Date.now())
} }
request.open(requestMethod, location, true) request.open(requestMethod, location, true)
request.timeout = options.timeout request.timeout = timeout
request.setRequestHeader("X-Requested-With", "XMLHttpRequest") request.setRequestHeader("X-Requested-With", "XMLHttpRequest")
request.setRequestHeader("X-PJAX", "true") request.setRequestHeader("X-PJAX", "true")

21
lib/util/extend.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = function(target) {
if (target == null) {
return target
}
var to = Object(target)
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i]
if (source != null) {
for (var key in source) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(source, key)) {
to[key] = source[key]
}
}
}
}
return to
}

View File

@@ -1,17 +0,0 @@
var tape = require("tape")
var clone = require("../../lib/clone")
tape("test clone method", function(t) {
var obj = {one: 1, two: 2}
var cloned = clone(obj)
t.notEqual(obj, cloned, "cloned object isn't the object")
t.same(obj, cloned, "cloned object have the same values than object")
cloned.tree = 3
t.notSame(obj, cloned, "modified cloned object haven't the same values than object")
t.end()
})

View File

@@ -1,10 +1,10 @@
var tape = require("tape") var tape = require("tape")
var parseOptions = require("../../../lib/proto/parse-options.js") var parseOptions = require("../../lib/parse-options.js")
tape("test parse initalization options function", function(t) { tape("test parse initalization options function", function(t) {
t.test("- default options", function(t) { t.test("- default options", function(t) {
var pjax = {} var pjax = {}
parseOptions.call(pjax, {}) pjax.options = parseOptions({})
t.equal(pjax.options.elements, "a[href], form[action]") t.equal(pjax.options.elements, "a[href], form[action]")
t.equal(pjax.options.selectors.length, 2, "selectors length") t.equal(pjax.options.selectors.length, 2, "selectors length")
@@ -30,7 +30,7 @@ tape("test parse initalization options function", function(t) {
// verify analytics always ends up as a function even when passed not a function // verify analytics always ends up as a function even when passed not a function
t.test("- analytics is a function", function(t) { t.test("- analytics is a function", function(t) {
var pjax = {} var pjax = {}
parseOptions.call(pjax, {analytics: "some string"}) pjax.options = parseOptions({analytics: "some string"})
t.deepEqual(typeof pjax.options.analytics, "function") t.deepEqual(typeof pjax.options.analytics, "function")
t.end() t.end()
@@ -39,7 +39,7 @@ tape("test parse initalization options function", function(t) {
// verify that the value false for scrollTo is not squashed // verify that the value false for scrollTo is not squashed
t.test("- scrollTo remains false", function(t) { t.test("- scrollTo remains false", function(t) {
var pjax = {} var pjax = {}
parseOptions.call(pjax, {scrollTo: false}) pjax.options = parseOptions({scrollTo: false})
t.deepEqual(pjax.options.scrollTo, false) t.deepEqual(pjax.options.scrollTo, false)
t.end() t.end()

View File

@@ -18,12 +18,7 @@ tape("test xhr request", function(t) {
var url = "https://httpbin.org/get" var url = "https://httpbin.org/get"
t.test("- request is made, gets a result, and is cache-busted", function(t) { t.test("- request is made, gets a result, and is cache-busted", function(t) {
var requestCacheBust = sendRequest.bind({ var r = sendRequest(url, {cacheBust: true}, function(result) {
options: {
cacheBust: true
}
})
var r = requestCacheBust(url, {}, function(result) {
t.equal(r.responseURL.indexOf("?"), url.length, "XHR URL is cache-busted when configured to be") t.equal(r.responseURL.indexOf("?"), url.length, "XHR URL is cache-busted when configured to be")
try { try {
result = JSON.parse(result) result = JSON.parse(result)
@@ -36,12 +31,7 @@ tape("test xhr request", function(t) {
}) })
}) })
t.test("- request is not cache-busted when configured not to be", function(t) { t.test("- request is not cache-busted when configured not to be", function(t) {
var requestNoCacheBust = sendRequest.bind({ var r = sendRequest(url, {}, function() {
options: {
cacheBust: false
}
})
var r = requestNoCacheBust(url, {}, function() {
t.equal(r.responseURL, url, "XHR URL is left untouched") t.equal(r.responseURL, url, "XHR URL is left untouched")
t.end() t.end()
}) })

17
tests/lib/util/clone.js Normal file
View File

@@ -0,0 +1,17 @@
var tape = require("tape")
var clone = require("../../../lib/util/clone")
tape("test clone method", function(t) {
var obj = {one: 1, two: 2}
var cloned = clone(obj)
t.notEqual(obj, cloned, "cloned object isn't the original object")
t.same(obj, cloned, "cloned object has the same values as original object")
cloned.three = 3
t.notSame(obj, cloned, "modified cloned object doesn't have the same values as original object")
t.end()
})

16
tests/lib/util/extend.js Normal file
View File

@@ -0,0 +1,16 @@
var tape = require("tape")
var extend = require("../../../lib/util/extend")
tape("test extend method", function(t) {
var obj = {one: 1, two: 2}
var extended = extend({}, obj, {two: "two", three: 3})
t.notEqual(obj, extended, "extended object isn't the original object")
t.notSame(obj, extended, "extended object doesn't have the same values as original object")
t.notSame(obj.two, extended.two, "extended object value overwrites value from original object")
t.end()
})