Skip to content

Commit 41c55c9

Browse files
committed
prep 2.0.8 release
1 parent 49d6aa3 commit 41c55c9

File tree

9 files changed

+439
-224
lines changed

9 files changed

+439
-224
lines changed

www/static/node_modules/mocha/mocha.js

Lines changed: 204 additions & 193 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

www/static/src/htmx.js

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ var htmx = (function() {
280280
*/
281281
historyRestoreAsHxRequest: true,
282282
/**
283-
* Weather to report input validation errors to the end user and update focus to the first input that fails validation.
283+
* Whether to report input validation errors to the end user and update focus to the first input that fails validation.
284284
* This should always be enabled as this matches default browser form submit behaviour
285285
* @type boolean
286286
* @default false
@@ -296,7 +296,7 @@ var htmx = (function() {
296296
location,
297297
/** @type {typeof internalEval} */
298298
_: null,
299-
version: '2.0.7'
299+
version: '2.0.8'
300300
}
301301
// Tsc madness part 2
302302
htmx.onLoad = onLoadHelper
@@ -525,6 +525,9 @@ var htmx = (function() {
525525
* @returns {Document}
526526
*/
527527
function parseHTML(resp) {
528+
if ('parseHTMLUnsafe' in Document) {
529+
return Document.parseHTMLUnsafe(resp)
530+
}
528531
const parser = new DOMParser()
529532
return parser.parseFromString(resp, 'text/html')
530533
}
@@ -3126,7 +3129,7 @@ var htmx = (function() {
31263129
//= ===================================================================
31273130
// History Support
31283131
//= ===================================================================
3129-
let currentPathForHistory = location.pathname + location.search
3132+
let currentPathForHistory
31303133

31313134
/**
31323135
* @param {string} path
@@ -3138,6 +3141,8 @@ var htmx = (function() {
31383141
}
31393142
}
31403143

3144+
setCurrentPathForHistory(location.pathname + location.search)
3145+
31413146
/**
31423147
* @returns {Element}
31433148
*/
@@ -4073,7 +4078,10 @@ var htmx = (function() {
40734078
targetOverride: resolvedTarget,
40744079
swapOverride: context.swap,
40754080
select: context.select,
4076-
returnPromise: true
4081+
returnPromise: true,
4082+
push: context.push,
4083+
replace: context.replace,
4084+
selectOOB: context.selectOOB
40774085
})
40784086
}
40794087
} else {
@@ -4688,8 +4696,8 @@ var htmx = (function() {
46884696
const requestPath = responseInfo.pathInfo.finalRequestPath
46894697
const responsePath = responseInfo.pathInfo.responsePath
46904698

4691-
const pushUrl = getClosestAttributeValue(elt, 'hx-push-url')
4692-
const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url')
4699+
const pushUrl = responseInfo.etc.push || getClosestAttributeValue(elt, 'hx-push-url')
4700+
const replaceUrl = responseInfo.etc.replace || getClosestAttributeValue(elt, 'hx-replace-url')
46934701
const elementIsBoosted = getInternalData(elt).boosted
46944702

46954703
let saveType = null
@@ -4808,19 +4816,17 @@ var htmx = (function() {
48084816
}
48094817

48104818
if (hasHeader(xhr, /HX-Location:/i)) {
4811-
saveCurrentPageToHistory()
48124819
let redirectPath = xhr.getResponseHeader('HX-Location')
4813-
/** @type {HtmxAjaxHelperContext&{path:string}} */
4814-
var redirectSwapSpec
4820+
/** @type {HtmxAjaxHelperContext&{path?:string}} */
4821+
var redirectSwapSpec = {}
48154822
if (redirectPath.indexOf('{') === 0) {
48164823
redirectSwapSpec = parseJSON(redirectPath)
48174824
// what's the best way to throw an error if the user didn't include this
48184825
redirectPath = redirectSwapSpec.path
48194826
delete redirectSwapSpec.path
48204827
}
4821-
ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() {
4822-
pushUrlIntoHistory(redirectPath)
4823-
})
4828+
redirectSwapSpec.push = redirectSwapSpec.push || 'true'
4829+
ajaxHelper('get', redirectPath, redirectSwapSpec)
48244830
return
48254831
}
48264832

@@ -4919,7 +4925,7 @@ var htmx = (function() {
49194925
selectOverride = xhr.getResponseHeader('HX-Reselect')
49204926
}
49214927

4922-
const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob')
4928+
const selectOOB = etc.selectOOB || getClosestAttributeValue(elt, 'hx-select-oob')
49234929
const select = getClosestAttributeValue(elt, 'hx-select')
49244930

49254931
swap(target, serverResponse, swapSpec, {
@@ -5118,7 +5124,7 @@ var htmx = (function() {
51185124
"[hx-trigger='restored'],[data-hx-trigger='restored']"
51195125
)
51205126
body.addEventListener('htmx:abort', function(evt) {
5121-
const target = evt.target
5127+
const target = (/** @type {CustomEvent} */(evt)).detail.elt || evt.target
51225128
const internalData = getInternalData(target)
51235129
if (internalData && internalData.xhr) {
51245130
internalData.xhr.abort()
@@ -5238,6 +5244,9 @@ var htmx = (function() {
52385244
* @property {Object|FormData} [values]
52395245
* @property {Record<string,string>} [headers]
52405246
* @property {string} [select]
5247+
* @property {string} [push]
5248+
* @property {string} [replace]
5249+
* @property {string} [selectOOB]
52415250
*/
52425251

52435252
/**
@@ -5284,6 +5293,9 @@ var htmx = (function() {
52845293
* @property {Object|FormData} [values]
52855294
* @property {boolean} [credentials]
52865295
* @property {number} [timeout]
5296+
* @property {string} [push]
5297+
* @property {string} [replace]
5298+
* @property {string} [selectOOB]
52875299
*/
52885300

52895301
/**

www/static/test/attributes/hx-boost.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ describe('hx-boost attribute', function() {
206206
div.innerHTML.should.equal('Boosted!')
207207
})
208208

209-
if (window.__playwright__binding__ && /chrome/i.test(navigator.userAgent)) {
209+
if (/headlesschrome/i.test(navigator.userAgent)) {
210210
it('ctrlKey mouse click does not boost', function() {
211211
// Test only works well in playwright with chome for code coverage as otherwise it opens a new tab breaking things
212212
this.server.respondWith('GET', '/test', 'Boosted')

www/static/test/attributes/hx-trigger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ describe('hx-trigger attribute', function() {
10381038
}, 250)
10391039
})
10401040

1041-
if (window.__playwright__binding__) {
1041+
if (/headlesschrome/i.test(navigator.userAgent)) {
10421042
it('scrolling triggers intersect event', function(done) {
10431043
// test only works reliably with playwright
10441044
this.server.respondWith('GET', '/test', 'test')

www/static/test/core/api.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,16 @@ describe('Core htmx API test', function() {
321321
div.innerHTML.should.equal('<div id="d2">bar</div>')
322322
})
323323

324+
it('ajax api works with selectOOB', function() {
325+
this.server.respondWith('GET', '/test', "<div id='oob'>OOB Content</div><div>Main Content</div>")
326+
var target = make("<div id='target'></div>")
327+
var oobDiv = make("<div id='oob'></div>")
328+
htmx.ajax('GET', '/test', { target: '#target', selectOOB: '#oob:innerHTML' })
329+
this.server.respond()
330+
target.innerHTML.should.equal('<div>Main Content</div>')
331+
oobDiv.innerHTML.should.equal('OOB Content')
332+
})
333+
324334
it('ajax api works with Hx-Select overrides select', function() {
325335
this.server.respondWith('GET', '/test', [200, { 'HX-Reselect': '#d2' }, "<div id='d1'>foo</div><div id='d2'>bar</div>"])
326336
var div = make("<div id='target'></div>")
@@ -658,4 +668,64 @@ describe('Core htmx API test', function() {
658668
var div = make('<div>textNode</div>')
659669
htmx.process(div.firstChild)
660670
})
671+
672+
it('ajax api push Url should push an element into the cache when true', function() {
673+
this.server.respondWith('POST', '/test123', 'Clicked!')
674+
675+
var div = make("<div id='d1'></div>")
676+
htmx.ajax('POST', '/test123', {
677+
target: '#d1',
678+
swap: 'innerHTML',
679+
push: 'true'
680+
})
681+
this.server.respond()
682+
div.innerHTML.should.equal('Clicked!')
683+
var path = sessionStorage.getItem('htmx-current-path-for-history')
684+
path.should.equal('/test123')
685+
})
686+
687+
it('ajax api push Url should push an element into the cache when string', function() {
688+
this.server.respondWith('POST', '/test', 'Clicked!')
689+
690+
var div = make("<div id='d1'></div>")
691+
htmx.ajax('POST', '/test', {
692+
target: '#d1',
693+
swap: 'innerHTML',
694+
push: '/abc123'
695+
})
696+
this.server.respond()
697+
div.innerHTML.should.equal('Clicked!')
698+
var path = sessionStorage.getItem('htmx-current-path-for-history')
699+
path.should.equal('/abc123')
700+
})
701+
702+
it('ajax api replace Url should replace an element into the cache when true', function() {
703+
this.server.respondWith('POST', '/test123', 'Clicked!')
704+
705+
var div = make("<div id='d1'></div>")
706+
htmx.ajax('POST', '/test123', {
707+
target: '#d1',
708+
swap: 'innerHTML',
709+
replace: 'true'
710+
})
711+
this.server.respond()
712+
div.innerHTML.should.equal('Clicked!')
713+
var path = sessionStorage.getItem('htmx-current-path-for-history')
714+
path.should.equal('/test123')
715+
})
716+
717+
it('ajax api replace Url should replace an element into the cache when string', function() {
718+
this.server.respondWith('POST', '/test', 'Clicked!')
719+
720+
var div = make("<div id='d1'></div>")
721+
htmx.ajax('POST', '/test', {
722+
target: '#d1',
723+
swap: 'innerHTML',
724+
replace: '/abc123'
725+
})
726+
this.server.respond()
727+
div.innerHTML.should.equal('Clicked!')
728+
var path = sessionStorage.getItem('htmx-current-path-for-history')
729+
path.should.equal('/abc123')
730+
})
661731
})

www/static/test/core/headers.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,56 @@ describe('Core htmx AJAX headers', function() {
410410
}, 30)
411411
})
412412

413+
it('should push new Url on HX-Location', function(done) {
414+
sessionStorage.removeItem('htmx-current-path-for-history')
415+
this.server.respondWith('GET', '/test', [200, { 'HX-Location': '{"path":"/test2", "target":"#work-area"}' }, ''])
416+
this.server.respondWith('GET', '/test2', [200, {}, '<div>Yay! Welcome</div>'])
417+
var div = make('<div id="testdiv" hx-trigger="click" hx-get="/test"></div>')
418+
div.click()
419+
this.server.respond()
420+
this.server.respond()
421+
setTimeout(function() {
422+
getWorkArea().innerHTML.should.equal('<div>Yay! Welcome</div>')
423+
var path = sessionStorage.getItem('htmx-current-path-for-history')
424+
path.should.equal('/test2')
425+
done()
426+
}, 30)
427+
})
428+
429+
it('should not push new Url on HX-Location if push Url false', function(done) {
430+
sessionStorage.setItem('htmx-current-path-for-history', '/old')
431+
this.server.respondWith('GET', '/test', [200, { 'HX-Location': '{"push":"false", "path":"/test2", "target":"#work-area"}' }, ''])
432+
this.server.respondWith('GET', '/test2', [200, {}, '<div>Yay! Welcome</div>'])
433+
var div = make('<div id="testdiv" hx-trigger="click" hx-get="/test"></div>')
434+
div.click()
435+
this.server.respond()
436+
this.server.respond()
437+
setTimeout(function() {
438+
getWorkArea().innerHTML.should.equal('<div>Yay! Welcome</div>')
439+
var path = sessionStorage.getItem('htmx-current-path-for-history')
440+
path.should.equal('/old')
441+
done()
442+
}, 30)
443+
})
444+
445+
it('should push different Url on HX-Location if push Url is string', function(done) {
446+
sessionStorage.removeItem('htmx-current-path-for-history')
447+
var HTMX_HISTORY_CACHE_NAME = 'htmx-history-cache'
448+
sessionStorage.removeItem(HTMX_HISTORY_CACHE_NAME)
449+
this.server.respondWith('GET', '/test', [200, { 'HX-Location': '{"push":"/abc123", "path":"/test2", "target":"#work-area"}' }, ''])
450+
this.server.respondWith('GET', '/test2', [200, {}, '<div>Yay! Welcome</div>'])
451+
var div = make('<div id="testdiv" hx-trigger="click" hx-get="/test"></div>')
452+
div.click()
453+
this.server.respond()
454+
this.server.respond()
455+
setTimeout(function() {
456+
getWorkArea().innerHTML.should.equal('<div>Yay! Welcome</div>')
457+
var path = sessionStorage.getItem('htmx-current-path-for-history')
458+
path.should.equal('/abc123')
459+
done()
460+
}, 30)
461+
})
462+
413463
it('should refresh page on HX-Refresh', function() {
414464
var refresh = false
415465
htmx.location = { reload: function() { refresh = true } }

www/static/test/core/shadowdom.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,4 +1341,64 @@ describe('Core htmx Shadow DOM Tests', function() {
13411341
getWorkArea().innerHTML.should.equal('Clicked!')
13421342
chai.expect(getWorkArea().shadowRoot).to.be.a('null')
13431343
})
1344+
1345+
it('hx-sync works properly in shadow DOM', function() {
1346+
var count = 0
1347+
this.server.respondWith('GET', '/test', function(xhr) {
1348+
xhr.respond(200, {}, 'Click ' + count++)
1349+
})
1350+
make('<div hx-sync="this:drop"><button id="b1" hx-get="/test">Initial</button>' +
1351+
' <button id="b2" hx-get="/test">Initial</button></div>')
1352+
var b1 = byId('b1')
1353+
var b2 = byId('b2')
1354+
b1.click()
1355+
b2.click()
1356+
this.server.respond()
1357+
this.server.respond()
1358+
b1.innerHTML.should.equal('Click 0')
1359+
b2.innerHTML.should.equal('Initial')
1360+
})
1361+
1362+
it('can abort a request programmatically in shadow DOM', function() {
1363+
var count = 0
1364+
var abortedCount = 0
1365+
this.server.respondWith('GET', '/test', function(xhr) {
1366+
xhr.respond(200, {}, 'Click ' + count++)
1367+
})
1368+
make('<div><button id="b1" hx-get="/test">Initial</button>' +
1369+
' <button id="b2" hx-get="/test">Initial</button></div>')
1370+
var b1 = byId('b1')
1371+
var b2 = byId('b2')
1372+
1373+
// Listen for abort events to verify they're working
1374+
htmx.on(b1, 'htmx:abort', function() { abortedCount++ })
1375+
1376+
b1.click()
1377+
b2.click()
1378+
1379+
htmx.trigger(b1, 'htmx:abort')
1380+
1381+
this.server.respond()
1382+
this.server.respond()
1383+
b1.innerHTML.should.equal('Initial')
1384+
b2.innerHTML.should.equal('Click 0')
1385+
abortedCount.should.equal(1)
1386+
})
1387+
1388+
it('hx-sync abort strategy works in shadow DOM', function() {
1389+
var count = 0
1390+
this.server.respondWith('GET', '/test', function(xhr) {
1391+
xhr.respond(200, {}, 'Click ' + count++)
1392+
})
1393+
make('<div hx-sync="this"><button hx-sync="closest div:abort" id="b1" hx-get="/test">Initial</button>' +
1394+
' <button id="b2" hx-get="/test">Initial</button></div>')
1395+
var b1 = byId('b1')
1396+
var b2 = byId('b2')
1397+
b1.click()
1398+
b2.click()
1399+
this.server.respond()
1400+
this.server.respond()
1401+
b1.innerHTML.should.equal('Initial')
1402+
b2.innerHTML.should.equal('Click 0')
1403+
})
13441404
})

www/static/test/manual/hxboost_relative_resources/nested/page2.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
<body style="padding:20px;font-family: sans-serif" hx-boost="true">
88
<a href="../index.html">Back To Page 1</a>
99
<p>Image should be displayed below</p>
10-
<img src="img.png" alt="Image" />
10+
<img src="img.png" />
1111
</body>
1212
</html>

0 commit comments

Comments
 (0)