@@ -9,7 +9,7 @@ we can't currently get rid off.
99@class up.browser
1010###
1111up.browser = (->
12-12+1313u = up.util
14141515loadPage = (url, options = {}) ->
@@ -47,7 +47,23 @@ up.browser = (->
4747window.console.groupEnd ||= noop
48484949canPushState = u.memoize ->
50-u.isDefined(history.pushState)
50+# We cannot use pushState if the initial request method is a POST for two reasons:
51+#
52+# 1. Up.js replaces the initial state so it can handle the pop event when the
53+# user goes back to the initial URL later. If the initial request was a POST,
54+# Up.js will wrongly assumed that it can restore the state by reloading with GET.
55+#
56+# 2. Some browsers have a bug where the initial request method is used for all
57+# subsequently pushed states. That means if the user reloads the page on a later
58+# GET state, the browser will wrongly attempt a POST request.
59+# Modern Firefoxes, Chromes and IE10+ don't seem to be affected by this,
60+# but we saw this behavior with Safari 8 and IE9 (IE9 can't do pushState anyway).
61+#
62+# The way that we work around this is that we don't support pushState if the
63+# initial request method was anything other than GET (but allow the rest of the
64+# Up.js framework to work). This way Up.js will fall back to full page loads until
65+# the framework was booted from a GET request.
66+u.isDefined(history.pushState) && initialRequestMethod == 'get'
51675268canCssAnimation = u.memoize ->
5369'transition' of document.documentElement.style
@@ -62,7 +78,20 @@ up.browser = (->
6278minor = parseInt(parts[1])
6379compatible = major >= 2 || (major == 1 && minor >= 9)
6480 compatible or u.error("jQuery %o found, but Up.js requires 1.9+", version)
65-81+82+# Returns and deletes a cookie with the given name
83+# Inspired by Turbolinks: https://github.com/rails/turbolinks/blob/83d4b3d2c52a681f07900c28adb28bc8da604733/lib/assets/javascripts/turbolinks.coffee#L292
84+popCookie = (name) ->
85+value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1]
86+if u.isPresent(value)
87+document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'
88+ value
89+90+# Server-side companion libraries like upjs-rails set this cookie so we
91+# have a way to detect the request method of the initial page load.
92+# There is no Javascript API for this.
93+initialRequestMethod = (popCookie('_up_request_method') || 'get').toLowerCase()
94+6695isSupported = u.memoize ->
6796# This is the most concise way to exclude IE8 and lower
6897# while keeping all relevant desktop and mobile browsers.
@@ -76,6 +105,5 @@ up.browser = (->
76105canInputEvent: canInputEvent
77106isSupported: isSupported
78107ensureRecentJquery: ensureRecentJquery
79-80-)()
81108109+)()