Fun with highlighting

https://groups.google.com/d/topic/knockoutjs/iO_rMnwES8Y/discussion

by gurkavcu

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-latest.debug.js"></script>
Highlight: <input data-bind="value: match, valueUpdate: 'afterkeydown'" /> <select data-bind="options: styleChoices, value: style"></select>

<p>Enter a new search term or try selecting text below with your mouse</p>
<hr />
<div data-bind="highlightedText: { text: text, highlight: match, css: style }, selectedText: match"></div>

CSS

.yellow { background-color: yellow; }
.red { background-color: red; color: #ccc; }
.black { background-color: #000; color: #fff; }
.big { font-size: 1.5em; font-weight: bold; }
input { margin: 5px; width: 150px; }
p { color: #666; }

JavaScript

ko.bindingHandlers.highlightedText = {
    update: function(element, valueAccessor) {
        var options = valueAccessor();
        var value = ko.utils.unwrapObservable(options.text);
        var search = ko.utils.unwrapObservable(options.highlight);
        var css = ko.utils.unwrapObservable(options.css); //could be an observable
        if (options.sanitize) {
            value = $('<div/>').text(value).html(); //could do this or something similar to escape HTML before replacement, if there is a risk of HTML injection in this value
        }
        var replacement = '<span class="' + css + '">' + search + '</span>';
        element.innerHTML = value.replace(new RegExp(search, 'g'), replacement);
    }
};

//set a value based on the text that a user selects
ko.bindingHandlers.selectedText = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor();
        ko.utils.registerEventHandler(element, 'mouseup', function() {
            var modelValue = valueAccessor();
            //get the selected text
            var selectedText = '';
            if (window.getSelection) {
                selectedText = window.getSelection();
            } else if (document.getSelection) {
                selectedText = document.getSelection();
            } else if (document.selection) {
                selectedText = document.selection.createRange().text;
            }
            //only change if something was selected
            if (selectedText.toString()) {
                if (ko.isWriteableObservable(modelValue)) {
                    modelValue(selectedText.toString());
                }
                else { //handle non-observables
                    var allBindings = allBindingsAccessor();
                    if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['selectedText']) allBindings['_ko_property_writers']['selectedText'](selectedText);
                }
            }
        });
   ...