diff --git a/README.md b/README.md
index 6d0f92d..38efdb5 100644
--- a/README.md
+++ b/README.md
@@ -124,9 +124,13 @@ To see if Pjax is actually supported by your browser, use `Pjax.isSupported()`.
## 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
new Pjax({
@@ -153,12 +157,24 @@ Pjax.prototype.getElements = function() {
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]"`)
@@ -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.
-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,
+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,
and set `preventDefault` to true, to prevent Pjax from receiving the event.
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
-is the same as the current page's URL will not work, due to the query string
+(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
appended to force a cache bust).
##### `timeout` (Integer, default: `0`)
diff --git a/example/example.js b/example/example.js
index 594b3a5..9880439 100644
--- a/example/example.js
+++ b/example/example.js
@@ -1,4 +1,31 @@
/* 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)
document.addEventListener("pjax:send", function() {
@@ -15,14 +42,20 @@ document.addEventListener("pjax:error", function() {
document.addEventListener("pjax:success", function() {
console.log("Event: pjax:success", arguments)
+
+ // Init page content
+ initButtons()
})
document.addEventListener("DOMContentLoaded", function() {
- var pjax = new Pjax({
+ // Init Pjax instance
+ pjax = new Pjax({
elements: [".js-Pjax"],
selectors: [".body", "title"],
- cacheBust: true,
- // currentUrlFullReload: true,
+ cacheBust: true
})
console.log("Pjax initialized.", pjax)
+
+ // Init page content
+ initButtons()
})
diff --git a/example/index.html b/example/index.html
index 2245d5b..39cd261 100644
--- a/example/index.html
+++ b/example/index.html
@@ -13,6 +13,13 @@
Go to Page 2 or Page 3 and view your console to see Pjax events.
Clicking on this page will just reload the page entirely.
+
Manual URL loading
+
+ You can use Pjax's loadUrl method to manually load a URL. Click the buttons below to try it out!
+
+
+
+
Forms
You can submit GET or POST forms with Pjax! Go to the form examples to try it out.
diff --git a/index.js b/index.js
index 493ecd9..b8d34db 100644
--- a/index.js
+++ b/index.js
@@ -1,13 +1,15 @@
-var clone = require("./lib/clone.js")
var executeScripts = require("./lib/execute-scripts.js")
var forEachEls = require("./lib/foreach-els.js")
+var parseOptions = require("./lib/parse-options.js")
var switches = require("./lib/switches")
var newUid = require("./lib/uniqueid.js")
var on = require("./lib/events/on.js")
var trigger = require("./lib/events/trigger.js")
+var clone = require("./lib/util/clone.js")
var contains = require("./lib/util/contains.js")
+var extend = require("./lib/util/extend.js")
var noop = require("./lib/util/noop")
var Pjax = function(options) {
@@ -17,8 +19,8 @@ var Pjax = function(options) {
options: null
}
- var parseOptions = require("./lib/proto/parse-options.js")
- parseOptions.call(this,options)
+
+ this.options = parseOptions(options)
this.log("Pjax options", this.options)
if (this.options.scrollRestoration && "scrollRestoration" in history) {
@@ -35,7 +37,6 @@ var Pjax = function(options) {
opt.url = st.state.url
opt.title = st.state.title
opt.history = false
- opt.requestOptions = {}
opt.scrollPos = st.state.scrollPos
if (st.state.uid < this.lastUid) {
opt.backward = true
@@ -142,6 +143,10 @@ Pjax.prototype = {
doRequest: require("./lib/send-request.js"),
loadUrl: function(href, options) {
+ options = typeof options === "object" ?
+ extend({}, this.options, options) :
+ clone(this.options)
+
this.log("load href", href, options)
// Abort any previous request
@@ -150,8 +155,7 @@ Pjax.prototype = {
trigger(document, "pjax:send", options)
// Do the request
- options.requestOptions.timeout = this.options.timeout
- this.request = this.doRequest(href, options.requestOptions, function(html, request) {
+ this.request = this.doRequest(href, options, function(html, request) {
// Fail if unable to load HTML via AJAX
if (html === false) {
trigger(document, "pjax:complete pjax:error", options)
diff --git a/lib/proto/parse-options.js b/lib/parse-options.js
similarity index 95%
rename from lib/proto/parse-options.js
rename to lib/parse-options.js
index 8118d50..a3f5239 100644
--- a/lib/proto/parse-options.js
+++ b/lib/parse-options.js
@@ -1,6 +1,6 @@
/* global _gaq: true, ga: true */
-var defaultSwitches = require("../switches")
+var defaultSwitches = require("./switches")
module.exports = function(options) {
options = options || {}
@@ -36,5 +36,5 @@ module.exports = function(options) {
options.switches.body = defaultSwitches.switchElementsAlt
}
- this.options = options
+ return options
}
diff --git a/lib/proto/attach-form.js b/lib/proto/attach-form.js
index 3ca881b..9ad4c77 100644
--- a/lib/proto/attach-form.js
+++ b/lib/proto/attach-form.js
@@ -1,5 +1,5 @@
var on = require("../events/on")
-var clone = require("../clone")
+var clone = require("../util/clone")
var attrClick = "data-pjax-click-state"
diff --git a/lib/proto/attach-link.js b/lib/proto/attach-link.js
index f7009e5..7de3317 100644
--- a/lib/proto/attach-link.js
+++ b/lib/proto/attach-link.js
@@ -1,5 +1,5 @@
var on = require("../events/on")
-var clone = require("../clone")
+var clone = require("../util/clone")
var attrClick = "data-pjax-click-state"
var attrKey = "data-pjax-keyup-state"
@@ -9,9 +9,6 @@ var linkAction = function(el, event) {
// clone it so the changes don't persist
var options = clone(this.options)
- // Initialize requestOptions since loadUrl expects it to be an object
- options.requestOptions = {}
-
// Don’t break browser special behavior on links (like page in new window)
if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
el.setAttribute(attrClick, "modifier")
diff --git a/lib/send-request.js b/lib/send-request.js
index f2817b5..9e203aa 100644
--- a/lib/send-request.js
+++ b/lib/send-request.js
@@ -3,10 +3,12 @@ var updateQueryString = require("./util/update-query-string");
module.exports = function(location, options, callback) {
options = options || {}
var queryString
- var requestMethod = (options.requestMethod || "GET").toUpperCase()
- var requestParams = options.requestParams || null
+ var requestOptions = options.requestOptions || {}
+ var requestMethod = (requestOptions.requestMethod || "GET").toUpperCase()
+ var requestParams = requestOptions.requestParams || null
var requestPayload = null
var request = new XMLHttpRequest()
+ var timeout = options.timeout || 0
request.onreadystatechange = function() {
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
- if (this.options.cacheBust) {
+ if (options.cacheBust) {
location = updateQueryString(location, "t", Date.now())
}
request.open(requestMethod, location, true)
- request.timeout = options.timeout
+ request.timeout = timeout
request.setRequestHeader("X-Requested-With", "XMLHttpRequest")
request.setRequestHeader("X-PJAX", "true")
diff --git a/lib/clone.js b/lib/util/clone.js
similarity index 100%
rename from lib/clone.js
rename to lib/util/clone.js
diff --git a/lib/util/extend.js b/lib/util/extend.js
new file mode 100644
index 0000000..07efde9
--- /dev/null
+++ b/lib/util/extend.js
@@ -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
+}
diff --git a/tests/lib/clone.js b/tests/lib/clone.js
deleted file mode 100644
index 9997943..0000000
--- a/tests/lib/clone.js
+++ /dev/null
@@ -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()
-})
diff --git a/tests/lib/proto/parse-options.js b/tests/lib/parse-options.js
similarity index 87%
rename from tests/lib/proto/parse-options.js
rename to tests/lib/parse-options.js
index 4665bcb..9c7785a 100644
--- a/tests/lib/proto/parse-options.js
+++ b/tests/lib/parse-options.js
@@ -1,10 +1,10 @@
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) {
t.test("- default options", function(t) {
var pjax = {}
- parseOptions.call(pjax, {})
+ pjax.options = parseOptions({})
t.equal(pjax.options.elements, "a[href], form[action]")
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
t.test("- analytics is a function", function(t) {
var pjax = {}
- parseOptions.call(pjax, {analytics: "some string"})
+ pjax.options = parseOptions({analytics: "some string"})
t.deepEqual(typeof pjax.options.analytics, "function")
t.end()
@@ -39,7 +39,7 @@ tape("test parse initalization options function", function(t) {
// verify that the value false for scrollTo is not squashed
t.test("- scrollTo remains false", function(t) {
var pjax = {}
- parseOptions.call(pjax, {scrollTo: false})
+ pjax.options = parseOptions({scrollTo: false})
t.deepEqual(pjax.options.scrollTo, false)
t.end()
diff --git a/tests/lib/send-request.js b/tests/lib/send-request.js
index 9ecaf56..0c95b30 100644
--- a/tests/lib/send-request.js
+++ b/tests/lib/send-request.js
@@ -18,12 +18,7 @@ tape("test xhr request", function(t) {
var url = "https://httpbin.org/get"
t.test("- request is made, gets a result, and is cache-busted", function(t) {
- var requestCacheBust = sendRequest.bind({
- options: {
- cacheBust: true
- }
- })
- var r = requestCacheBust(url, {}, function(result) {
+ var r = sendRequest(url, {cacheBust: true}, function(result) {
t.equal(r.responseURL.indexOf("?"), url.length, "XHR URL is cache-busted when configured to be")
try {
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) {
- var requestNoCacheBust = sendRequest.bind({
- options: {
- cacheBust: false
- }
- })
- var r = requestNoCacheBust(url, {}, function() {
+ var r = sendRequest(url, {}, function() {
t.equal(r.responseURL, url, "XHR URL is left untouched")
t.end()
})
diff --git a/tests/lib/util/clone.js b/tests/lib/util/clone.js
new file mode 100644
index 0000000..e79a4cd
--- /dev/null
+++ b/tests/lib/util/clone.js
@@ -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()
+})
diff --git a/tests/lib/util/extend.js b/tests/lib/util/extend.js
new file mode 100644
index 0000000..0319797
--- /dev/null
+++ b/tests/lib/util/extend.js
@@ -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()
+})