Twitter bootstrap ko checkedButtons

by cuhuak

HTML

<script src="http://twitter.github.com/bootstrap/assets/js/bootstrap-button.js?"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<div class="btn-group">
    <button data-value="0" data-bind="checkedButtons: radioValue" class="btn btn-small">radio 0</button>
    <button data-value="1" data-bind="checkedButtons: radioValue" class="btn btn-small">radio 1</button>
</div>
<br>
<div class="btn-group">
    <button data-value="true" data-toggle="checkbox" data-bind="checkedButtons: checkboxValue" class="btn btn-small">true/false</button>
</div>
<br>
<div class="btn-group">
    <button data-value="a" data-toggle="checkbox" data-bind="checkedButtons: checkboxArray" class="btn btn-small">select a</button>
    <button data-value="b" data-toggle="checkbox" data-bind="checkedButtons: checkboxArray" class="btn btn-small">select b</button>
</div>
<br>
<pre data-bind="text: ko.toJSON($root, null, 3)"></pre>

CSS

body { margin: 10px;}

JavaScript

ko.bindingHandlers['checkedButtons'] = {
    'init': function (element, valueAccessor, allBindingsAccessor) {
        var type = element.getAttribute('data-toggle') || 'radio';
        var updateHandler = function () {
            var valueToWrite;
            var isActive = !!~element.className.indexOf('active');
            var dataValue = element.getAttribute('data-value');
            if (type == "checkbox") {
                valueToWrite = !isActive;
            } else if (type == "radio" && !isActive) {
                valueToWrite = dataValue;
            } else {
                return; // "checkedButtons" binding only responds to checkbox and radio data-toggle attribute
            }

            var modelValue = valueAccessor();
            if ((type == "checkbox") && (ko.utils.unwrapObservable(modelValue) instanceof Array)) {
                // For checkboxes bound to an array, we add/remove the checkbox value to that array
                // This works for both observable and non-observable arrays
                var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.unwrapObservable(modelValue), dataValue);
                if (!isActive && (existingEntryIndex < 0))
                    modelValue.push(dataValue);
                else if (isActive && (existingEntryIndex >= 0))
                    modelValue.splice(existingEntryIndex, 1);
            } else {
                if (modelValue() !== valueToWrite) {
                    modelValue(valueToWrite);
                }
            }
        };
        
        ko.utils.registerEventHandler(element, "click", updateHandler);
    },
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var type = element.getAttribute('data-toggle') || 'radio';

        if (type == "checkbox") {
            if (value instanceof Array) {
                // When bound to an array, the checkbox being checked represents its value being present in that...