diff options
author | p.b <1430300+pbt@users.noreply.github.com> | 2024-02-29 11:11:46 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-29 11:11:46 -0500 |
commit | d1fc7895f65b9235a2f5daa63060a94b6d2252c4 (patch) | |
tree | 2935a058dd2808decf1eee7f6605519e5fe4c5b5 | |
parent | f004978bbbf68befb49bfef7f17a2ec25ce35ae0 (diff) | |
download | htmx-d1fc7895f65b9235a2f5daa63060a94b6d2252c4.tar.gz htmx-d1fc7895f65b9235a2f5daa63060a94b6d2252c4.zip |
Add textContent swap style (#2356)
* feat: add textContent swap style
* add documentation
---------
Co-authored-by: pbt <pb.to@icloud.com>
-rw-r--r-- | src/htmx.js | 75 | ||||
-rw-r--r-- | test/attributes/hx-swap.js | 47 | ||||
-rw-r--r-- | www/content/attributes/hx-swap.md | 1 |
3 files changed, 88 insertions, 35 deletions
diff --git a/src/htmx.js b/src/htmx.js index 9935979f..19c66629 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1805,46 +1805,51 @@ var htmx = (function() { } const settleInfo = makeSettleInfo(target) - let fragment = makeFragment(content) - - settleInfo.title = fragment.title - - // select-oob swaps - if (swapOptions.selectOOB) { - const oobSelectValues = swapOptions.selectOOB.split(',') - for (let i = 0; i < oobSelectValues.length; i++) { - const oobSelectValue = oobSelectValues[i].split(':', 2) - let id = oobSelectValue[0].trim() - if (id.indexOf('#') === 0) { - id = id.substring(1) - } - const oobValue = oobSelectValue[1] || 'true' - const oobElement = fragment.querySelector('#' + id) - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo) + if (swapSpec.swapStyle === 'textContent') { + // parse only as text; don't process OOB swaps + target.textContent = content + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } } } - } - // oob swaps - findAndSwapOobElements(fragment, settleInfo) - forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { - findAndSwapOobElements(template.content, settleInfo) - if (template.content.childElementCount === 0) { + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap - template.remove() - } - }) - - // normal swap - if (swapOptions.select) { - const newFragment = getDocument().createDocumentFragment() - forEach(fragment.querySelectorAll(swapOptions.select), function(node) { - newFragment.appendChild(node) + template.remove() + } }) - fragment = newFragment + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) } - handlePreservedElements(fragment) - swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) // apply saved focus and selection information to swapped content if (selectionInfo.elt && diff --git a/test/attributes/hx-swap.js b/test/attributes/hx-swap.js index ac405d75..d3e9099b 100644 --- a/test/attributes/hx-swap.js +++ b/test/attributes/hx-swap.js @@ -22,6 +22,53 @@ describe('hx-swap attribute', function() { a.innerHTML.should.equal('Clicked!') }) + it('swap textContent properly with HTML tags', function() { + this.server.respondWith('GET', '/test', '<a id="a1" hx-get="/test2">Click Me</a>') + + var d1 = make('<div id="d1" hx-get="/test" hx-swap="textContent"></div>') + d1.click() + should.equal(byId('d1'), d1) + this.server.respond() + d1.textContent.should.equal('<a id="a1" hx-get="/test2">Click Me</a>') + should.equal(byId('a1'), null) + }) + + it('swap textContent properly with HTML tags and text', function() { + this.server.respondWith('GET', '/test', 'text content <a id="a1" hx-get="/test2">Click Me</a>') + + var d1 = make('<div id="d1" hx-get="/test" hx-swap="textContent"></div>') + d1.click() + should.equal(byId('d1'), d1) + this.server.respond() + d1.textContent.should.equal('text content <a id="a1" hx-get="/test2">Click Me</a>') + should.equal(byId('a1'), null) + }) + + it('swap textContent ignores OOB swaps', function() { + this.server.respondWith('GET', '/test', '<span id="d2" hx-swap-oob="true">hi</span> <a id="a1" hx-get="/test2">Click Me</a>') + + var d1 = make('<div id="d1" hx-get="/test" hx-swap="textContent"></div>') + var d2 = make('<div id="d2">some text</div>') + d1.click() + should.equal(byId('d1'), d1) + should.equal(byId('d2'), d2) + this.server.respond() + d1.textContent.should.equal('<span id="d2" hx-swap-oob="true">hi</span> <a id="a1" hx-get="/test2">Click Me</a>') + d2.outerHTML.should.equal('<div id="d2">some text</div>') + should.equal(byId('a1'), null) + }) + + it('swap textContent properly with text', function() { + this.server.respondWith('GET', '/test', 'plain text') + + var div = make('<div id="d1" hx-get="/test" hx-swap="textContent"></div>') + div.click() + should.equal(byId('d1'), div) + this.server.respond() + div.textContent.should.equal('plain text') + should.equal(byId('a1'), null) + }) + it('swap outerHTML properly', function() { this.server.respondWith('GET', '/test', '<a id="a1" hx-get="/test2">Click Me</a>') this.server.respondWith('GET', '/test2', 'Clicked!') diff --git a/www/content/attributes/hx-swap.md b/www/content/attributes/hx-swap.md index f4ef401a..d7593985 100644 --- a/www/content/attributes/hx-swap.md +++ b/www/content/attributes/hx-swap.md @@ -10,6 +10,7 @@ The possible values of this attribute are: * `innerHTML` - Replace the inner html of the target element * `outerHTML` - Replace the entire target element with the response +* `textContent` - Replace the text content of the target element, without parsing the response as HTML * `beforebegin` - Insert the response before the target element * `afterbegin` - Insert the response before the first child of the target element * `beforeend` - Insert the response after the last child of the target element |