JSFiddle - React, Tailwind, and code Playground
by mcannon
HTML
<div class="box">
<label for="pattern">Pattern</label>
<input id="pattern" data-bind="value:regexPattern, valueUpdate:'afterkeydown'" name="regexPattern" placeholder="Enter your regex here.">
<div class="options">
<p>Options: <span data-bind="text:regexOptions"></span></p>
<input type="checkbox" id="opt-global" data-bind="checked:optionGlobal">
<label for="opt-global">g</label>
<input type="checkbox" id="opt-case" data-bind="checked:optionCase">
<label for="opt-case">i</label>
<input type="checkbox" id="opt-lines" data-bind="checked:optionLines">
<label for="opt-case">m</label>
</div>
</br>
<label for="stringToTest">String To Test</label>
<textarea id="stringToTest" data-bind="value:stringToTest, valueUpdate:'afterkeydown'" name="stringToTest" placeholder="Enter your test string here."></textarea>
<!--output-->
<p>Matches (highlighted - hover for index)</p>
<div class="box output-box">
<div data-bind="highlightedText: { text:stringToTest, matches: regexExecResult(), css: 'highlight'}"></div>
<p data-bind="html:errorMsg" id="error-message"></p>
</div>
</div>
CSS
body { font-family: helvetica, arial; font-size: 1em; }
#pattern, textarea { display:block; font-family: inherit; font-size: inherit; width: 300px; margin-bottom:25px;}
textarea { height: 100px }
label { display:block; font-weight:bold;}
.options label { display:inline; font-size:.75em; margin-right:5px;}
p { font-weight:bold; margin-bottom:0px;}
.highlight0 { color:#060; background-color:#C5F7C5; }
.highlight1 { color:#060; background-color:#C5C5F7; }
.box { background-color:#EEE; min-height:2em; padding:10px; display:inline-block; margin: auto; margin-bottom:25px; border: solid 1px #CCC; }
.output-box { background-color:#fff; width:300px;}
.regex { margin-top:0px; font-weight:normal; text-decoration:none}
#error-message { color:#F00 }
JavaScript
ko.bindingHandlers.highlightedText= {
update: function(element, valueAccessor) {
var options = valueAccessor();
var originalText = ko.utils.unwrapObservable(options.text);
var matches = ko.utils.unwrapObservable(options.matches);
var css = ko.utils.unwrapObservable(options.css);
// if (options.sanitize) {
// value = $('<div/>').text(originalText).html(); //could do this or something similar to escape HTML before replacement, if there is a risk of HTML injection in this value
// }
if (matches && matches.length==0){
element.innerHTML = originalText; //return?
}
else
{
var highlightedString="", startPos=0, replacement="";
for (var i=0; i < matches.length; i++){
//translate the original text into a new string with the highlighted markup
//figure out where the last loop iteration left off
startPos = matches[i-1] ? matches[i-1].index + matches[i-1].matchedText.length: 0;
//build the highlight
replacement = '<span class="' + css + i%2 + '" title="Index: ' + matches[i].index + '">' + matches[i].matchedText + '</span>';
var myString = originalText.substring(startPos, matches[i].index) +
replacement;
highlightedString += myString;
}
startPos = matches[matches.length-1].index + matches[matches.length-1].matchedText.length;
highlightedString += originalText.substring(startPos, originalText.length);
element.innerHTML =...