jQuery UI dialog basic

by rniemeyer

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-1.3pre.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/base/jquery-ui.css">
<ul id="items" data-bind="foreach: items">
    <li>
        <a class="item" href="#" data-bind="text: name"></a>
    </li>
</ul>

<div style="display: none" data-bind="showModal: selectedItem">
    <div data-bind="with: selectedItem">
        <div>
            <input data-bind="value: name" />
        </div>
        <button data-bind="jqButton: {}, click: $root.accept">Accept</button>
        <button data-bind="jqButton: {}, click: $root.cancel">Cancel</button>
    </div>
</div>

CSS

div { padding: 5px; }

JavaScript

//custom binding to initialize a jQuery UI button
ko.bindingHandlers.jqButton = {
    init: function(element, valueAccessor) {
        var options = ko.utils.unwrapObservable(valueAccessor()) || {};
        
        //handle disposal
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).button("destroy");
        }); 
        
        $(element).button(options);  
    }    
};

ko.bindingHandlers.showModal = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        $(element).dialog({
            close: function() {
                if (ko.isWriteableObservable(value)) {
                   value(null);   
                }
            }
        }); 
        
        //handle disposal
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).dialog("destroy");
        }); 
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).dialog(value ? "open" : "close");   
    }
};

//wrapper to an observable that requires accept/cancel
ko.protectedObservable = function(initialValue) {
    //private variables
    var _actualValue = ko.observable(initialValue);
    var _tempValue = initialValue;
    
    //dependentObservable that we will return
    var result = ko.dependentObservable({
        //always return the actual value
        read: function() {
           return _actualValue(); 
        },
        //stored in a temporary spot until commit
        write: function(newValue) {
             _tempValue = newValue; 
        }
    }); 
    
    //if different, commit temp value
    result.commit = function() {
        if (_tempValue !== _actualValue()) {
             _actualValue(_tempValue); 
        }  
    };
    
    //force subscribers to take original
    result.reset = function() {
        _actualValue.valueHasMutated();
        _tempValue =...