From 2c2aa96ada964a056c7d3c98ed0defce26a4946f Mon Sep 17 00:00:00 2001 From: Ophir Lifshitz Date: Tue, 1 Sep 2020 06:11:13 -0400 Subject: [PATCH] Let replace functions return DocumentFragments --- readme.md | 2 +- src/findAndReplaceDOMText.js | 8 +++++ test/test.js | 59 ++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1c82391..a79c2b2 100644 --- a/readme.md +++ b/readme.md @@ -119,7 +119,7 @@ A portion object has the following properties: #### The `replace` Function -If you pass a function to the `replace` option your function will be called on every portion of every match and is expected to return a DOM Node (a Text or Element node). Your function will be passed both the portion and the encapsulating match of that portion. +If you pass a function to the `replace` option your function will be called on every portion of every match and is expected to return a DOM Node (a Text, Element, or DocumentFragment node). Your function will be passed both the portion and the encapsulating match of that portion. E.g. diff --git a/src/findAndReplaceDOMText.js b/src/findAndReplaceDOMText.js index f4c4cb9..f40c473 100644 --- a/src/findAndReplaceDOMText.js +++ b/src/findAndReplaceDOMText.js @@ -548,6 +548,7 @@ endPortion, match ); + var newNodeLastChild = newNode.lastChild; node.parentNode.insertBefore(newNode, node); @@ -569,6 +570,9 @@ newNode.parentNode.replaceChild(node, newNode); }); + if (newNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + return newNodeLastChild; + } return newNode; } else { @@ -609,6 +613,7 @@ endPortion, match ); + var lastNodeLastChild = lastNode.lastChild; matchStartNode.parentNode.insertBefore(precedingTextNode, matchStartNode); matchStartNode.parentNode.insertBefore(firstNode, matchStartNode); @@ -625,6 +630,9 @@ lastNode.parentNode.replaceChild(matchEndNode, lastNode); }); + if (lastNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + return lastNodeLastChild; + } return lastNode; } } diff --git a/test/test.js b/test/test.js index 0562d2f..cd21d52 100644 --- a/test/test.js +++ b/test/test.js @@ -532,3 +532,62 @@ test('>Two portions', function() { }); htmlEqual(d.innerHTML, '___0234'); }); + +module('Document fragments'); + +test('Custom replacement function returns Element', function() { + var d = document.createElement('div'); + d.innerHTML = '11 22'; + findAndReplaceDOMText(d, { + find: /\d+/g, + replace: function(portion) { + var fragment = document.createElement('fragment'); + var m = document.createElement('m'); + + m.appendChild(document.createTextNode(portion.text)) + fragment.appendChild(document.createTextNode('x')); + fragment.appendChild(m); + fragment.appendChild(document.createTextNode('y')); + return fragment; + } + }); + htmlEqual(d.innerHTML, 'x11y x22y'); +}); + +test('Custom replacement function returns actual DocumentFragment', function() { + var d = document.createElement('div'); + d.innerHTML = '11 22'; + findAndReplaceDOMText(d, { + find: /\d+/g, + replace: function(portion) { + var fragment = document.createDocumentFragment(); + var m = document.createElement('m'); + + m.appendChild(document.createTextNode(portion.text)) + fragment.appendChild(document.createTextNode('x')); + fragment.appendChild(m); + fragment.appendChild(document.createTextNode('y')); + return fragment; + } + }); + htmlEqual(d.innerHTML, 'x11y x22y'); +}); + +test('Custom replacement function returns actual DocumentFragment - more complex', function() { + var d = document.createElement('div'); + d.innerHTML = '11 22 33 44 55 66666'; + findAndReplaceDOMText(d, { + find: /\d+/g, + replace: function(portion) { + var fragment = document.createDocumentFragment(); + var m = document.createElement('m'); + + m.appendChild(document.createTextNode(portion.text)) + fragment.appendChild(document.createTextNode('x')); + fragment.appendChild(m); + fragment.appendChild(document.createTextNode('y')); + return fragment; + } + }); + htmlEqual(d.innerHTML, 'x11y x22y x3yx3y x44y x5yx5y x6yx6yx6yx6yx6y'); +});