Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/htmx.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,11 @@ var htmx = (function() {
* @returns {string}
*/
function normalizePath(path) {
// use dummy base URL to allow normalize on path only
const url = new URL(path, 'http://x')
if (url) {
try {
const url = new URL(path, window.location.href)
path = url.pathname + url.search
} catch (e) {
// fallback for malformed URLs
}
// remove trailing slash, unless index page
if (path != '/') {
Expand Down
59 changes: 49 additions & 10 deletions test/attributes/hx-push-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ describe('hx-push-url attribute', function() {
const chai = window.chai
var HTMX_HISTORY_CACHE_NAME = 'htmx-history-cache'

// Helper to normalize paths like htmx does
function normalizePath(path) {
const url = new URL(path, window.location.href)
return url.pathname
}

beforeEach(function() {
this.server = makeServer()
clearWorkArea()
Expand All @@ -23,7 +29,7 @@ describe('hx-push-url attribute', function() {
this.server.respond()
getWorkArea().textContent.should.equal('second')
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache[cache.length - 1].url.should.equal('/test')
cache[cache.length - 1].url.should.equal(normalizePath('/test'))
})

it('navigation should not push an element into the cache when false', function() {
Expand All @@ -50,7 +56,7 @@ describe('hx-push-url attribute', function() {
getWorkArea().textContent.should.equal('second')
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(2)
cache[1].url.should.equal('/abc123')
cache[1].url.should.equal(normalizePath('abc123'))
})

it('restore should return old value', function() {
Expand Down Expand Up @@ -197,9 +203,9 @@ describe('hx-push-url attribute', function() {
htmx._('saveToHistoryCache')('url1', make('<div>'))
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(3)
cache[0].url.should.equal('/url3')
cache[1].url.should.equal('/url2')
cache[2].url.should.equal('/url1')
cache[0].url.should.equal(normalizePath('url3'))
cache[1].url.should.equal(normalizePath('url2'))
cache[2].url.should.equal(normalizePath('url1'))
})

it('htmx:afterSettle is called when replacing outerHTML', function() {
Expand Down Expand Up @@ -273,21 +279,21 @@ describe('hx-push-url attribute', function() {
})
}

it.skip('normalizePath falls back to no normalization if path not valid URL', function() {
// path normalization has a bug breaking it right now preventing this test
it('normalizePath falls back to no normalization if path not valid URL', function() {
// path normalization bug is now fixed
htmx._('saveToHistoryCache')('http://', make('<div>'))
htmx._('saveToHistoryCache')('http//', make('<div>'))
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(2)
cache[0].url.should.equal('http://') // no normalization as invalid
cache[1].url.should.equal('/http') // can normalize this one
cache[0].url.should.equal('http:') // trailing slash removed after normalization
cache[1].url.should.equal(normalizePath('http')) // can normalize this one
})

it('history cache clears out disabled attribute', function() {
htmx._('saveToHistoryCache')('/url1', make('<div><div data-disabled-by-htmx disabled></div></div>'))
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(1)
cache[0].url.should.equal('/url1')
cache[0].url.should.equal(normalizePath('/url1'))
cache[0].content.should.equal('<div data-disabled-by-htmx=""></div>')
})

Expand Down Expand Up @@ -375,6 +381,39 @@ describe('hx-push-url attribute', function() {
htmx.off('htmx:pushedIntoHistory', handler)
})

it('normalizes relative paths correctly', function() {
// Get current path to build expected normalized paths
var currentPath = window.location.pathname
var basePath = currentPath.substring(0, currentPath.lastIndexOf('/') + 1)

htmx._('saveToHistoryCache')('relative/path', make('<div>'))
htmx._('saveToHistoryCache')('./another/path', make('<div>'))
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(2)
// Both should be normalized to absolute paths based on current location
cache[0].url.should.equal(basePath + 'relative/path')
cache[1].url.should.equal(basePath + 'another/path')
})

it('normalizes paths with query strings correctly', function() {
var currentPath = window.location.pathname
var basePath = currentPath.substring(0, currentPath.lastIndexOf('/') + 1)

htmx._('saveToHistoryCache')('path?foo=bar', make('<div>'))
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(1)
cache[0].url.should.equal(basePath + 'path?foo=bar')
})

it('normalizes paths with trailing slashes', function() {
htmx._('saveToHistoryCache')('/path/', make('<div>'))
htmx._('saveToHistoryCache')('/path/to/page/', make('<div>'))
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache.length.should.equal(2)
cache[0].url.should.equal(normalizePath('/path'))
cache[1].url.should.equal(normalizePath('/path/to/page'))
})

it('pushing url without anchor will retain the page anchor tag', function() {
var handler = htmx.on('htmx:configRequest', function(evt) {
evt.detail.path = evt.detail.path + '#test'
Expand Down
8 changes: 7 additions & 1 deletion test/attributes/hx-replace-url.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
describe('hx-replace-url attribute', function() {
var HTMX_HISTORY_CACHE_NAME = 'htmx-history-cache'

// Helper to normalize paths like htmx does
function normalizePath(path) {
const url = new URL(path, window.location.href)
return url.pathname
}

beforeEach(function() {
this.server = makeServer()
clearWorkArea()
Expand All @@ -22,7 +28,7 @@ describe('hx-replace-url attribute', function() {
this.server.respond()
getWorkArea().textContent.should.equal('second')
var cache = JSON.parse(sessionStorage.getItem(HTMX_HISTORY_CACHE_NAME))
cache[cache.length - 1].url.should.equal('/test')
cache[cache.length - 1].url.should.equal(normalizePath('/test'))
})

it('should handle HX-Replace-Url response header', function() {
Expand Down