Knockout For Fun

Just for fun / experimentation. Color Palette: http://paletton.com/#uid=33h0k0kllll6y++b-C3v68kHq00

by David Kyle

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<script src="http://code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css">
<div id="primary">
    <div class="liner">
        <nav data-bind="attr: {class: Navigation.WrapperClass}">
            <ul data-bind="foreach: Navigation.Items">
                <li><a data-bind="text: Name, attr: {href: Link, target: Target, title: Title}"></a>

                </li>
            </ul>
        </nav>
        <section class="container user-data-wrapper" data-bind="with: UserData">
             <h2>User Detail</h2>

             <h2><a class="reset" href="javascript:void(0);" title="Clear">Clear</a></h2>

            <form name="sample-form" method="post" action=""> <span class="form-item-wrapper">
               <label for="firstName">First Name:</label>
                    <input type="text" name="firstName" id="firstName" data-bind="value: FirstName" />
                </span>
 <span class="form-item-wrapper">
                    <label for="gender">Gender:</label>
                    <select name="gender" id="gender" data-bind="value: Gender">
                        <option>--Select--</option>
                        <option>Male</option>
                        <option>Female</option>
                        <option>Time Lord</option>
                    </select>
                </span>
                <span class="form-item-wrapper">
                    <label for="birthDate">Birth Date</label>
                    <input type="text" name="birthDate" id="birthDate" data-bind="value: BirthDate" />
                </span>
                <span class="form-item-wrapper">
                    Current Age: <span class="age-output" data-bind="text: Age"></span>
                </span>
           ...

CSS

BODY {
    font-family: Verdana, Arial, Sans-Serif;
    font-size: small;
}
BODY, DIV, nav UL, nav UL LI, SECTION, A {
    border: 0;
    margin: 0;
    padding: 0;
    text-indent: 0px;
    border-collapse: collapse;
}
#primary {
    margin: 0px auto;
    width: 99%;
}
.liner {
    padding: 1px 3px;
}
A {
    text-decoration: none;
}
nav {
    display: block;
    width: 100%;
    margin-top: 10px;
}
nav UL {
    list-style-type: none;
    display: inline-block;
    margin: 1px;
    width: 100%;
    background: rgb(240, 249, 255);
    background: url(data:image/svg+xml;
    base64, PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2YwZjlmZiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNhZmUzZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
    background: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(240, 249, 255, .6)), to(rgba(175, 227, 255, .6)));
    background: -webkit-linear-gradient(rgba(240, 249, 255, .6) 0%, rgba(175, 227, 255, .6) 100%);
    background: -moz-linear-gradient(rgba(240, 249, 255, .6) 0%, rgba(175, 227, 255, 1) 100%);
    background: -o-linear-gradient(rgba(240, 249, 255, .6) 0%, rgba(175, 227, 255, .6) 100%);
    background: linear-gradient(rgba(240, 249, 255, .6) 0%, rgba(175, 227, 255, .6) 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f0f9ff', endColorstr='#afe3ff', GradientType=0);
    border-radius: 0px 5px 0px 5px;
    border: outset 1px rgba(240, 249, 255, .6);
}
nav UL LI {
    display: inline-block;
    min-width: 80px;
   ...

JavaScript

$(function () {
    $(document).on("click", "a", function (e) {
        if ($(this).prop("class").indexOf("reset") > -1) {
            //Bypass the reset
        } else {
            model.History.Log({
                Type: "Mouse",
                Target: $(this)
            });
        } // end if/else
        return false;
    });
    $("#birthDate").datepicker({
        changeMonth: true,
        changeYear: true
    });
    $(document).bind("clear-history", function (e) {
        model.History.Clear();
    });
    $(document).bind("clear-form", function (e) {
        model.UserData.Clear();
    });
    $(".history-wrapper .reset").click(function (e) {
        $(document).trigger("clear-history");
    });
    $(".user-data-wrapper .reset").click(function (e) {
        $(document).trigger("clear-form");
    });
    $(document).on("blur", "input[type='text']", function (e) {
        model.History.Log({
            Type: "Keyboard",
            Target: $(this)
        });
    });
    $(document).on("change", "select", function (e) {
        model.History.Log({
            Type: "Mouse",
            Target: $(this)
        });
    });
});

//Root view model bound to the primary node
var AdminViewModel = function () {
    var self = this;
    //Create sub-view models as part of the main page ViewModel
    self.Navigation = new NavigationViewModel();
    self.History = new HistoryViewModel();
    self.UserData = new UserDataViewModel();
};

//ViewModel that contains observables for populating navigation
var NavigationViewModel = function () {
    var self = this;
    self.WrapperClass = ko.observable("");
    self.Items = ko.observableArray();
    self.AddItem = function (rawItem) {
        var newItem = new NavigationItemViewModel();
        newItem.Name(rawItem.Name);
        newItem.Link(rawItem.Link);
        newItem.Title(rawItem.Title);
        self.Items.push(newItem);
    };
};

var HistoryViewModel = function () {
    var self = this;
    self.Items =...