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 =...