Skip to content

Commit d3e5570

Browse files
committed
Merge branch 'scroll-fixes'
Closes #474
2 parents a958cd6 + 3dde9e9 commit d3e5570

File tree

6 files changed

+106
-62
lines changed

6 files changed

+106
-62
lines changed

jquery.pjax.js

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ function pjax(options) {
225225
settings.timeout = 0
226226
}
227227

228-
options.requestUrl = stripInternalParams(parseURL(settings.url).href)
228+
var url = parseURL(settings.url)
229+
url.hash = hash
230+
options.requestUrl = stripInternalParams(url.href)
229231
}
230232

231233
options.complete = function(xhr, textStatus) {
@@ -259,6 +261,12 @@ function pjax(options) {
259261

260262
var container = extractContainer(data, xhr, options)
261263

264+
var url = parseURL(container.url)
265+
if (hash) {
266+
url.hash = hash
267+
container.url = url.href
268+
}
269+
262270
// If there is a layout version mismatch, hard load the new url
263271
if (currentVersion && latestVersion && currentVersion !== latestVersion) {
264272
locationReplace(container.url)
@@ -309,28 +317,17 @@ function pjax(options) {
309317

310318
executeScriptTags(container.scripts)
311319

312-
// Scroll to top by default
313-
if (typeof options.scrollTo === 'number')
314-
$(window).scrollTop(options.scrollTo)
315-
316-
// If the URL has a hash in it, make sure the browser
317-
// knows to navigate to the hash.
318-
if ( hash !== '' ) {
319-
// Avoid using simple hash set here. Will add another history
320-
// entry. Replace the url with replaceState and scroll to target
321-
// by hand.
322-
//
323-
// window.location.hash = hash
324-
var url = parseURL(container.url)
325-
url.hash = hash
326-
327-
pjax.state.url = url.href
328-
window.history.replaceState(pjax.state, container.title, url.href)
320+
var scrollTo = options.scrollTo
329321

330-
var target = document.getElementById(url.hash.slice(1))
331-
if (target) $(window).scrollTop($(target).offset().top)
322+
// Ensure browser scrolls to the element referenced by the URL anchor
323+
if (hash) {
324+
var name = decodeURIComponent(hash.slice(1))
325+
var target = document.getElementById(name) || document.getElementsByName(name)[0]
326+
if (target) scrollTo = $(target).offset().top
332327
}
333328

329+
if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo)
330+
334331
fire('pjax:success', [data, status, xhr, options])
335332
}
336333

@@ -566,8 +563,8 @@ function cloneContents(container) {
566563
// Returns String.
567564
function stripParam(url, name) {
568565
return url
569-
.replace(new RegExp('[?&]' + name + '=[^&]*'), '')
570-
.replace(/[?&]$/, '')
566+
.replace(new RegExp('[?&]' + name + '=[^&#]*'), '')
567+
.replace(/[?&]($|#)/, '\1')
571568
.replace(/[?&]/, '?')
572569
}
573570

test/app.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def title(str)
2121

2222
after do
2323
if pjax?
24-
response.headers['X-PJAX-URL'] = request.url
24+
response.headers['X-PJAX-URL'] ||= request.url
2525
response.headers['X-PJAX-Version'] = 'v1'
2626
end
2727
end
@@ -48,7 +48,17 @@ def title(str)
4848
end
4949

5050
get '/redirect.html' do
51-
redirect "/hello.html"
51+
if params[:anchor]
52+
path = "/hello.html##{params[:anchor]}"
53+
if pjax?
54+
response.headers['X-PJAX-URL'] = uri(path)
55+
status 200
56+
else
57+
redirect path
58+
end
59+
else
60+
redirect "/hello.html"
61+
end
5262
end
5363

5464
get '/timeout.html' do

test/unit/fn_pjax.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -230,21 +230,6 @@ if ($.support.pjax) {
230230
frame.$("a[href='/dinosaurs.html']").click()
231231
})
232232

233-
234-
asyncTest("scrolls to anchor after load", function() {
235-
var frame = this.frame
236-
237-
frame.$("#main").pjax("a").on("pjax:end", function() {
238-
equal(frame.location.pathname, "/dinosaurs.html")
239-
equal(frame.location.hash, "#main")
240-
start()
241-
})
242-
243-
var link = frame.$("a[href='/dinosaurs.html']")
244-
link.attr('href', "/dinosaurs.html#main")
245-
link.click()
246-
})
247-
248233
asyncTest("triggers pjax:click event from link", function() {
249234
var frame = this.frame
250235

test/unit/pjax.js

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,24 +1192,10 @@ if ($.support.pjax) {
11921192
})
11931193
})
11941194

1195-
asyncTest("follows redirect with X-PJAX-URL header", function() {
1196-
var frame = this.frame
1197-
1198-
frame.$('#main').on("pjax:success", function() {
1199-
equal(frame.location.pathname, "/hello.html")
1200-
equal(frame.$("#main > p").html().trim(), "Hello!")
1201-
start()
1202-
})
1203-
frame.$.pjax({
1204-
url: "redirect.html",
1205-
container: "#main"
1206-
})
1207-
})
1208-
12091195
asyncTest("lazily sets initial $.pjax.state", function() {
12101196
var frame = this.frame
12111197

1212-
ok(!frame.$.pjax.state)
1198+
equal(frame.$.pjax.state, null)
12131199

12141200
frame.$('#main').on("pjax:success", function() {
12151201
start()
@@ -1219,24 +1205,28 @@ if ($.support.pjax) {
12191205
container: "#main"
12201206
})
12211207

1222-
ok(frame.$.pjax.state.id)
1223-
ok(frame.$.pjax.state.url.match("/home.html"))
1224-
equal(frame.$.pjax.state.container, "#main")
1208+
var initialState = frame.$.pjax.state
1209+
ok(initialState.id)
1210+
equal(initialState.url, "http://" + frame.location.host + "/home.html")
1211+
equal(initialState.container, "#main")
12251212
})
12261213

12271214
asyncTest("updates $.pjax.state to new page", function() {
12281215
var frame = this.frame
12291216

12301217
frame.$('#main').on("pjax:success", function() {
1231-
ok(frame.$.pjax.state.id)
1232-
ok(frame.$.pjax.state.url.match("/hello.html"))
1233-
equal(frame.$.pjax.state.container, "#main")
1218+
var state = frame.$.pjax.state
1219+
ok(state.id)
1220+
equal(state.url, "http://" + frame.location.host + "/hello.html#new")
1221+
equal(state.container, "#main")
12341222
start()
12351223
})
12361224
frame.$.pjax({
1237-
url: "hello.html",
1225+
url: "hello.html#new",
12381226
container: "#main"
12391227
})
1228+
1229+
var initialState = frame.$.pjax.state
12401230
})
12411231

12421232
asyncTest("new id is generated for new pages", function() {

test/unit/pjax_fallback.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ $.each([true, false], function() {
55
var disabled = this == false
66
var s = disabled ? " (disabled)" : ""
77

8+
var ua = navigator.userAgent
9+
var safari = ua.match("Safari") && !ua.match("Chrome") && !ua.match("Edge")
10+
var chrome = ua.match("Chrome") && !ua.match("Edge")
11+
812
module("$.pjax fallback"+s, {
913
setup: function() {
1014
var self = this
@@ -123,6 +127,8 @@ asyncTest("scrolls to anchor at top page"+s, function() {
123127

124128
this.loaded = function(frame) {
125129
setTimeout(function() {
130+
equal(frame.location.pathname, "/anchor.html")
131+
equal(frame.location.hash, "#top")
126132
equal(frame.window.scrollY, 8)
127133
start()
128134
}, 100)
@@ -132,6 +138,14 @@ asyncTest("scrolls to anchor at top page"+s, function() {
132138
url: "/anchor.html#top",
133139
container: "#main"
134140
})
141+
142+
if (disabled) {
143+
equal(frame.location.pathname, "/home.html")
144+
equal(frame.location.hash, "")
145+
} else {
146+
equal(frame.location.pathname, "/anchor.html")
147+
equal(frame.location.hash, "#top")
148+
}
135149
})
136150

137151
asyncTest("empty anchor doesn't scroll page"+s, function() {
@@ -170,7 +184,23 @@ asyncTest("scrolls to anchor at bottom page"+s, function() {
170184
})
171185
})
172186

187+
asyncTest("scrolls to named encoded anchor"+s, function() {
188+
var frame = this.frame
173189

190+
equal(frame.window.scrollY, 0)
191+
192+
this.loaded = function(frame) {
193+
setTimeout(function() {
194+
equal(frame.window.scrollY, 10008)
195+
start()
196+
}, 10)
197+
}
198+
199+
frame.$.pjax({
200+
url: "/anchor.html#%62%6F%74%74%6F%6D",
201+
container: "#main"
202+
})
203+
})
174204

175205
asyncTest("sets GET method"+s, function() {
176206
var frame = this.frame
@@ -396,4 +426,36 @@ asyncTest("handle form submit"+s, function() {
396426
frame.$("form").submit()
397427
})
398428

429+
asyncTest("browser URL is correct after redirect"+s, function() {
430+
var frame = this.frame
431+
432+
this.loaded = function() {
433+
equal(frame.location.pathname, "/hello.html")
434+
var expectedHash = safari && disabled ? "" : "#new"
435+
equal(frame.location.hash, expectedHash)
436+
start()
437+
}
438+
439+
frame.$.pjax({
440+
url: "redirect.html#new",
441+
container: "#main"
442+
})
443+
})
444+
445+
asyncTest("server can't affect anchor after redirect"+s, function() {
446+
var frame = this.frame
447+
448+
this.loaded = function() {
449+
equal(frame.location.pathname, "/hello.html")
450+
var expectedHash = safari && disabled ? "" : "#new"
451+
equal(frame.location.hash, expectedHash)
452+
start()
453+
}
454+
455+
frame.$.pjax({
456+
url: "redirect.html?anchor=server#new",
457+
container: "#main"
458+
})
459+
})
460+
399461
})

test/views/anchor.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<%= title 'Anchor' %>
22
<div id="top" style="width:500px;height:10000px;"></div>
3-
<div id="bottom" style="width:500px;height:10000px;"></div>
3+
<a name="bottom" style="width:500px;height:10000px;display:block;"></a>
44
<script type="text/javascript">window.parent.iframeLoad(window)</script>

0 commit comments

Comments
 (0)