ViewModel Test

by bombo

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-1.2.1.debug.js"></script>
<ul id="header" data-bind="template: { name: 'AddressHeaderEntry', foreach: Addresses }">
    <li id="add" class="unselected" data-bind="click: Add">+</li>
</ul>

<div id="container" data-bind="template: {name: 'AddressEntry', foreach: Addresses }"></div>


<!-- Templates -->

<script id="AddressHeaderEntry" type="text/html">
    <li class="headerEntry unselected" data-bind="click: GetFocus, css: { selected: Selected(), unselected: !Selected() }"><input data-bind="value: Name, enable: checkEnable" disabled="disabled" /></li>
</script>

<script id="AddressEntry" type="text/html">
    <div class="entry" data-bind="visible: Selected">
        <div class="field">
            <label for="firstname">First name: </label>
            <input type="text" id="firstname" data-bind="value: Firstname, enable: checkEnable" disabled="disabled" />
        </div>
        <div class="field">
            <label for="lastname">Last name: </label>
            <input type="text" id="lastname" data-bind="value: Lastname, enable: checkEnable" disabled="disabled" />
        </div>
        <div class="field">
            <label for="street">Street: </label>
            <input type="text" id="street" data-bind="value: Street, enable: checkEnable" disabled="disabled" />
        </div>
        <div class="toolbox">
            <button data-bind="click: editEntry, text: buttonText"></button>
        </div>
    </div>
</script>

CSS

ul#header li {
    float: left;
    padding: 2px 6px;
    border-left: 1px dotted #aaa;
    border-top: 1px dotted #aaa;
    border-right: 1px dotted #aaa;
}

.unselected, .unselected input {
    cursor: pointer;
    background: #eee;
}

.unselected, .unselected input[disabled] {
    background: #eee;
}

#header li input {
    width: 80px;
}

.unselected:hover {
    color: #39b;
}

#container {
    clear: both;
    position: relative;
    top: -1px;
    border: 1px dotted #aaa;
    z-index: 10;
    -moz-box-shadow: 2px 2px 0px #888888; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: 2px 2px 0px #888888; /* Safari and Chrome */
    box-shadow: 2px 2px 0px #888888;
}

.field {
    margin: 5px;
}

.field label {
    display: inline-block;
    width: 150px;
    text-align: right;
}

input[disabled] {
    background: white;
    border: none;
    margin: 2px;
}

input {
    border-color: #ccc;
}

.selected {
    position: relative;
    z-index: 100;
    border-bottom: 1px solid white;
    background: white;
    cursor: auto;
    -moz-box-shadow: 2px 0px 0px #888888; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: 2px 0px 0px #888888; /* Safari and Chrome */
    box-shadow: 2px 0px 0px #888888;
}

.selected input {
    font-weight: bold;
}

.toolbox {
    text-align: right;
}

button {
    background: #ccc;
    border: none;
    cursor: pointer;
    padding: 4px 8px;
}

button:hover {
    background: #eee;
}

JavaScript

//////////////////////////////////
// Constructors                 //
//////////////////////////////////

function VMKey(user, selectedEmployeeId, guid) {
    this.User = user;
    this.SelectedEmployeeId = selectedEmployeeId;
    this.GUID = guid;
}

function VMHeader(modelID, name, description, action, key) {
    this.ModelID = modelID;
    this.ModelName = name;
    this.Description = description;
    this.Action = action;
    this.Key = key;
}

function AddressesField(name, lastname, firstname, street) {
    this.Name = ko.observable(name);
    this.Lastname = ko.observable(lastname);
    this.Firstname = ko.observable(firstname);
    this.Street = ko.observable(street);
    this.Selected = ko.observable(false);

    this.buttonText = ko.observable('edit');
    this.checkEnable = ko.dependentObservable(function () {
        return this.buttonText() === 'accept';
    }, this);
    
    this.editEntry = function (event) {
        if (this.buttonText() === 'edit') {
            this.buttonText('accept');
        } else {
            this.buttonText('edit');
        }
    }.bind(this);
    this.GetFocus = function (event) {
        if (viewModel.focussedElement) {
            viewModel.focussedElement.Selected(false);
            viewModel.focussedElement.buttonText('edit');
        }
        viewModel.focussedElement = this;
        this.Selected(true);
    }.bind(this);
}

//////////////////////////////////
// ViewModel                    //
//////////////////////////////////

var viewModel = {
    Header: new VMHeader(
        '',
        'AddressModel',
        'This Model retrieves all information regarding Address Handling',
        'GetCustomizing',
        new VMKey()
    ),
    Addresses: ko.observableArray([
        new AddressesField('Current', 'Twartzen', 'Bruce', 'Now Street'),
        new AddressesField('Future', 'Twartzen', 'Bruce', 'Future Blvd.')
    ]),
    Add: function () {
        this.Addresses.push(new AddressesField('New'));
    },
   ...