Skip to content
Open
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
27 changes: 17 additions & 10 deletions src/htmx.js
Original file line number Diff line number Diff line change
Expand Up @@ -4053,7 +4053,10 @@ var htmx = (function() {
targetOverride: resolvedTarget,
swapOverride: context.swap,
select: context.select,
returnPromise: true
returnPromise: true,
push: context.push,
replace: context.replace,
selectOOB: context.selectOOB
})
}
} else {
Expand Down Expand Up @@ -4668,8 +4671,8 @@ var htmx = (function() {
const requestPath = responseInfo.pathInfo.finalRequestPath
const responsePath = responseInfo.pathInfo.responsePath

const pushUrl = getClosestAttributeValue(elt, 'hx-push-url')
const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url')
const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') || responseInfo.etc.push
const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') || responseInfo.etc.replace
const elementIsBoosted = getInternalData(elt).boosted

let saveType = null
Expand Down Expand Up @@ -4788,19 +4791,17 @@ var htmx = (function() {
}

if (hasHeader(xhr, /HX-Location:/i)) {
saveCurrentPageToHistory()
let redirectPath = xhr.getResponseHeader('HX-Location')
/** @type {HtmxAjaxHelperContext&{path:string}} */
var redirectSwapSpec
/** @type {HtmxAjaxHelperContext&{path?:string}} */
var redirectSwapSpec = {}
if (redirectPath.indexOf('{') === 0) {
redirectSwapSpec = parseJSON(redirectPath)
// what's the best way to throw an error if the user didn't include this
redirectPath = redirectSwapSpec.path
delete redirectSwapSpec.path
}
ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() {
pushUrlIntoHistory(redirectPath)
})
redirectSwapSpec.push = redirectSwapSpec.push || 'true'
ajaxHelper('get', redirectPath, redirectSwapSpec)
return
}

Expand Down Expand Up @@ -4899,7 +4900,7 @@ var htmx = (function() {
selectOverride = xhr.getResponseHeader('HX-Reselect')
}

const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob')
const selectOOB = etc.selectOOB || getClosestAttributeValue(elt, 'hx-select-oob')
const select = getClosestAttributeValue(elt, 'hx-select')

swap(target, serverResponse, swapSpec, {
Expand Down Expand Up @@ -5216,6 +5217,9 @@ var htmx = (function() {
* @property {Object|FormData} [values]
* @property {Record<string,string>} [headers]
* @property {string} [select]
* @property {string} [push]
* @property {string} [replace]
* @property {string} [selectOOB]
*/

/**
Expand Down Expand Up @@ -5262,6 +5266,9 @@ var htmx = (function() {
* @property {Object|FormData} [values]
* @property {boolean} [credentials]
* @property {number} [timeout]
* @property {string} [push]
* @property {string} [replace]
* @property {string} [selectOOB]
*/

/**
Expand Down
70 changes: 70 additions & 0 deletions test/core/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,16 @@ describe('Core htmx API test', function() {
div.innerHTML.should.equal('<div id="d2">bar</div>')
})

it('ajax api works with selectOOB', function() {
this.server.respondWith('GET', '/test', "<div id='oob'>OOB Content</div><div>Main Content</div>")
var target = make("<div id='target'></div>")
var oobDiv = make("<div id='oob'></div>")
htmx.ajax('GET', '/test', { target: '#target', selectOOB: '#oob:innerHTML' })
this.server.respond()
target.innerHTML.should.equal('<div>Main Content</div>')
oobDiv.innerHTML.should.equal('OOB Content')
})

it('ajax api works with Hx-Select overrides select', function() {
this.server.respondWith('GET', '/test', [200, { 'HX-Reselect': '#d2' }, "<div id='d1'>foo</div><div id='d2'>bar</div>"])
var div = make("<div id='target'></div>")
Expand Down Expand Up @@ -656,4 +666,64 @@ describe('Core htmx API test', function() {
var div = make('<div>textNode</div>')
htmx.process(div.firstChild)
})

it('ajax api push Url should push an element into the cache when true', function() {
this.server.respondWith('POST', '/test123', 'Clicked!')

var div = make("<div id='d1'></div>")
htmx.ajax('POST', '/test123', {
target: '#d1',
swap: 'innerHTML',
push: 'true'
})
this.server.respond()
div.innerHTML.should.equal('Clicked!')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/test123')
})

it('ajax api push Url should push an element into the cache when string', function() {
this.server.respondWith('POST', '/test', 'Clicked!')

var div = make("<div id='d1'></div>")
htmx.ajax('POST', '/test', {
target: '#d1',
swap: 'innerHTML',
push: '/abc123'
})
this.server.respond()
div.innerHTML.should.equal('Clicked!')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/abc123')
})

it('ajax api replace Url should replace an element into the cache when true', function() {
this.server.respondWith('POST', '/test123', 'Clicked!')

var div = make("<div id='d1'></div>")
htmx.ajax('POST', '/test123', {
target: '#d1',
swap: 'innerHTML',
replace: 'true'
})
this.server.respond()
div.innerHTML.should.equal('Clicked!')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/test123')
})

it('ajax api replace Url should replace an element into the cache when string', function() {
this.server.respondWith('POST', '/test', 'Clicked!')

var div = make("<div id='d1'></div>")
htmx.ajax('POST', '/test', {
target: '#d1',
swap: 'innerHTML',
replace: '/abc123'
})
this.server.respond()
div.innerHTML.should.equal('Clicked!')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/abc123')
})
})
50 changes: 50 additions & 0 deletions test/core/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,56 @@ describe('Core htmx AJAX headers', function() {
}, 30)
})

it('should push new Url on HX-Location', function(done) {
sessionStorage.removeItem('htmx-current-path-for-history')
this.server.respondWith('GET', '/test', [200, { 'HX-Location': '{"path":"/test2", "target":"#work-area"}' }, ''])
this.server.respondWith('GET', '/test2', [200, {}, '<div>Yay! Welcome</div>'])
var div = make('<div id="testdiv" hx-trigger="click" hx-get="/test"></div>')
div.click()
this.server.respond()
this.server.respond()
setTimeout(function() {
getWorkArea().innerHTML.should.equal('<div>Yay! Welcome</div>')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/test2')
done()
}, 30)
})

it('should not push new Url on HX-Location if push Url false', function(done) {
sessionStorage.setItem('htmx-current-path-for-history', '/old')
this.server.respondWith('GET', '/test', [200, { 'HX-Location': '{"push":"false", "path":"/test2", "target":"#work-area"}' }, ''])
this.server.respondWith('GET', '/test2', [200, {}, '<div>Yay! Welcome</div>'])
var div = make('<div id="testdiv" hx-trigger="click" hx-get="/test"></div>')
div.click()
this.server.respond()
this.server.respond()
setTimeout(function() {
getWorkArea().innerHTML.should.equal('<div>Yay! Welcome</div>')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/old')
done()
}, 30)
})

it('should push different Url on HX-Location if push Url is string', function(done) {
sessionStorage.removeItem('htmx-current-path-for-history')
var HTMX_HISTORY_CACHE_NAME = 'htmx-history-cache'
sessionStorage.removeItem(HTMX_HISTORY_CACHE_NAME)
this.server.respondWith('GET', '/test', [200, { 'HX-Location': '{"push":"/abc123", "path":"/test2", "target":"#work-area"}' }, ''])
this.server.respondWith('GET', '/test2', [200, {}, '<div>Yay! Welcome</div>'])
var div = make('<div id="testdiv" hx-trigger="click" hx-get="/test"></div>')
div.click()
this.server.respond()
this.server.respond()
setTimeout(function() {
getWorkArea().innerHTML.should.equal('<div>Yay! Welcome</div>')
var path = sessionStorage.getItem('htmx-current-path-for-history')
path.should.equal('/abc123')
done()
}, 30)
})

it('should refresh page on HX-Refresh', function() {
var refresh = false
htmx.location = { reload: function() { refresh = true } }
Expand Down
3 changes: 3 additions & 0 deletions www/content/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ or
* `values` - values to submit with the request
* `headers` - headers to submit with the request
* `select` - allows you to select the content you want swapped from a response
* `selectOOB` - allows you to select content for out-of-band swaps from a response
* `push` - can be `'true'` or a path to push a URL into browser location history
* `replace` - can be `'true'` or a path to replace the URL in the browser location history

##### Example

Expand Down
2 changes: 2 additions & 0 deletions www/content/headers/hx-location.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Path is required and is url to load the response from. The rest of the data mirr
* `values` - values to submit with the request
* `headers` - headers to submit with the request
* `select` - allows you to select the content you want swapped from a response
* `push` - set to `'false'` or a path string to prevent or override the URL pushed to browser location history
* `replace` - a path string to replace the URL in the browser location history

## Notes

Expand Down