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
34 changes: 34 additions & 0 deletions src/ws/test/ext/ws.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,40 @@ describe('web-sockets extension', function() {
byId('d2').innerHTML.should.equal('div2')
})


it('handles message from the server with template wrapping', function() {
var div = make('<div hx-ext="ws" ws-connect="ws://localhost:8080"><div id="d1">div1</div><div id="d2">div2</div><table><tr id="r3"><td>table</td></tr></Table></div>')
this.tickMock()

this.socketServer.emit('message', '<div id="d1">replaced</div><template><tr id="r3"><td>replaced</td></tr></template>')

this.tickMock()
byId('d1').innerHTML.should.equal('replaced')
byId('d2').innerHTML.should.equal('div2')
byId('r3').innerHTML.should.equal('<td>replaced</td>')
})

it('handles replacing template with id', function() {
var div = make('<div hx-ext="ws" ws-connect="ws://localhost:8080"><template id="t1">Template</template></div>')
this.tickMock()

this.socketServer.emit('message', '<template id="t1">replaced</template>')

this.tickMock()
byId('t1').innerHTML.should.equal('replaced')
})

it('handles replacing template with hx-swap-oob attribute', function() {
var div = make('<div hx-ext="ws" ws-connect="ws://localhost:8080"><template id="t1">Template</template></div>')
this.tickMock()

this.socketServer.emit('message', '<template hx-swap-oob="outerHTML:#t1">replaced</template>')

this.tickMock()

div.firstChild.innerHTML.should.equal('replaced')
})

it('raises lifecycle events (connecting, open, close) in correct order', function() {
var handledEventTypes = []
var handler = function(evt) { handledEventTypes.push(evt.detail.event.type) }
Expand Down
24 changes: 18 additions & 6 deletions src/ws/ws.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,23 @@ This extension adds support for WebSockets to htmx. See /www/extensions/ws.md f
}
}

/**
* perform oobSwap on all fragment children and process children wrapped in empty template tags
* @param {HTMLCollection} children
* @param {Object} settleInfo
* @returns
*/
function oobSwapChildren(children, settleInfo) {
for (const child of Array.from(children)) {
const hxSwapOob = api.getAttributeValue(child, 'hx-swap-oob')
if(child.tagName !== 'TEMPLATE' || hxSwapOob || child.id) {
api.oobSwap(hxSwapOob || 'true', child, settleInfo)
} else {
oobSwapChildren(child.content.children, settleInfo)
}
}
}

/**
* ensureWebSocket creates a new WebSocket on the designated element, using
* the element's "ws-connect" attribute.
Expand Down Expand Up @@ -137,12 +154,7 @@ This extension adds support for WebSockets to htmx. See /www/extensions/ws.md f
var settleInfo = api.makeSettleInfo(socketElt)
var fragment = api.makeFragment(response)

if (fragment.children.length) {
var children = Array.from(fragment.children)
for (var i = 0; i < children.length; i++) {
api.oobSwap(api.getAttributeValue(children[i], 'hx-swap-oob') || 'true', children[i], settleInfo)
}
}
oobSwapChildren(fragment.children, settleInfo)

api.settleImmediately(settleInfo.tasks)
api.triggerEvent(socketElt, 'htmx:wsAfterMessage', { message: response, socketWrapper: socketWrapper.publicInterface })
Expand Down