Knockout Custom Binding for number values

by homer2

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css">
<script src="https://raw.github.com/SteveSanderson/knockout/master/build/output/knockout-latest.debug.js"></script>
value: <input type="text" data-bind="value: number" /><br/>
valueNumeric: <input type="text" data-bind="valueNumeric: number" /><br/>
valuePercent: <input type="text" data-bind="valuePercent: number" /><br/>
textPercent: <span data-bind="textPercent: number" ></span><br/>

text number extend Percent: <span data-bind="text: number.extend({ percent: 2 })" ></span><br/>
value number extend Percent: <input type="text" data-bind="value: number.extend({ percent: 2 })" /><br/>
text numberPercent: <span data-bind="text: number.extend({ percent: 4 })" ></span><br/>
value number extend Percent: <input type="text" data-bind="value: number.extend({ percent: 4 })" /><br/>
<button>val</button>

<div data-bind="text: ko.toJSON($root)"></div>

CSS

.header {
    font-size: 16px;
    font-family: sans-serif;
    font-weight: bold;
    margin-bottom: 20px;
}

JavaScript

ko.bindingHandlers.valueNumeric = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var underlyingObservable = valueAccessor();
        var interceptor = ko.computed({
            read: underlyingObservable,
            write: function (newValue) {
                var parsedValue = parseFloat(newValue.replace(/[^\d.]/g, ''));
                underlyingObservable(isNaN(parsedValue) ? newValue : parsedValue);
            }
        });
        ko.bindingHandlers.value.init(element, function () { return interceptor }, allBindingsAccessor);
    },
    update: ko.bindingHandlers.value.update
};

ko.bindingHandlers.valuePercent = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var underlyingObservable = valueAccessor();
        var interceptor = ko.computed({
            read: underlyingObservable,
            write: function (newValue) {
                var parsedValue = parseFloat(newValue.replace(/[^\d.]/g, '')) / 100;
                underlyingObservable(isNaN(parsedValue) ? newValue : parsedValue);
            }
        });
        ko.bindingHandlers.value.init(element, function () { return interceptor }, allBindingsAccessor);
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor();
        element.value=ko.utils.unwrapObservable(value)*100;
    }
};

ko.bindingHandlers.textPercent = {
    //init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    //    //init logic 
    //},
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var val = parseFloat(ko.utils.unwrapObservable(valueAccessor()));
        element.innerHTML = (val * 100).toFixed(2) + "%";
    }
}
    
ko.extenders.percent = function(target, precision) {
    //create a writeable computed observable to intercept writes to our observable
    var result = ko.computed({
        read: function(){ 
            //return...