Knockout - MVVM basics - function

HTML

<script src="http://www.rabblesoft.com/sites/haroon/gridster/src/jquery.gridster.js"></script>
<link rel="stylesheet" href="http://www.rabblesoft.com/sites/haroon/gridster/dist/jquery.gridster.css">
<script src="http://www.rabblesoft.com/sites/haroon/gridster/dist/jquery.gridster.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
<div class="gridster">
    <ul data-bind="foreach: myData">
        <li data-bind="attr:{
          
          'data-row':datarow,
          'data-col':datacol,
          'data-sizex':datasizex,
          'data-sizey':datasizey

    },text:text, doubleClick: $parent.AddOne"></li>
    </ul>
</div>

CSS

/*! gridster.js - v0.1.0 - 2012-10-20
* http://gridster.net/
* Copyright (c) 2012 ducksboard; Licensed MIT */
 body {
    background-color: #011529;
}
li {
    background-color: #FFFFFF;
    list-style: none;
}
widget {
    background-color: #bcddfe;
}
.gridster {
    position:relative;
}
.gridster > * {
    margin: 0 auto;
    -webkit-transition: height .4s;
    -moz-transition: height .4s;
    -o-transition: height .4s;
    -ms-transition: height .4s;
    transition: height .4s;
}
.gridster .gs_w {
    z-index: 2;
    position: absolute;
}
.ready .gs_w:not(.preview-holder) {
    -webkit-transition: opacity .3s, left .3s, top .3s;
    -moz-transition: opacity .3s, left .3s, top .3s;
    -o-transition: opacity .3s, left .3s, top .3s;
    transition: opacity .3s, left .3s, top .3s;
}
.ready .gs_w:not(.preview-holder) {
    -webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
    -moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
    -o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
    transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
}
.gridster .preview-holder {
    z-index: 1;
    position: absolute;
    background-color: #fff;
    border-color: #fff;
    opacity: 0.3;
}
.gridster .player-revert {
    z-index: 10!important;
    -webkit-transition: left .3s, top .3s!important;
    -moz-transition: left .3s, top .3s!important;
    -o-transition: left .3s, top .3s!important;
    transition: left .3s, top .3s!important;
}
.gridster .dragging {
    z-index: 10!important;
    -webkit-transition: all 0s !important;
    -moz-transition: all 0s !important;
    -o-transition: all 0s !important;
    transition: all 0s !important;
}
.gridster {
}
.demo {
    margin: 1em 0;
    padding: 3.0em 0 3.0em;
    background: #004756;
}
.additional_element {
    margin: 5px;
    padding: 5px;
    color: white;
    cursor: pointer;
}
.grid_elements {
    width: 50px;
    float: left;
}
.grid_elements...

JavaScript

//This is some widget data to start the process
var gridData = [ {text:'Widget #1', datarow:1, datacol:1, datasizex:1, datasizey:1},
    {text:'Widget #2', datarow:2, datacol:1, datasizex:1, datasizey:1},
    {text:'Widget #3', datarow:1, datacol:2, datasizex:1, datasizey:1},
    {text:'Widget #4', datarow:2, datacol:2, datasizex:1, datasizey:1}];

//Add a double click handler to the knockout binding handlers
ko.bindingHandlers.doubleClick = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var handler = valueAccessor(),
            delay = 200,
            clickTimeout = false;

        $(element).click(function () {
            if (clickTimeout !== false) {
                handler.call(viewModel);
                clickTimeout = false;
            } else {
                clickTimeout = setTimeout(function () {
                    clickTimeout = false;
                }, delay);
            }
        });
    }
};

// The viewmodel contains an observable array of widget data to be 
//    displayed on the gridster
var viewmodel = function () {

    var self = this;
    self.myData = ko.observableArray(gridData);
    //AddOne adds an element to the observable array (called at runtime from doubleClick events)
    self.AddOne = function () {
        var self = this;
        myViewModel.myData.push({
            text: 'Widget Added After!',
            datarow: 1,
            datacol: 1,
            datasizex: 1,
            datasizey: 1
        });
    };

};


var myViewModel = new viewmodel();
ko.applyBindings(myViewModel);

$(".gridster ul").gridster({
    widget_margins: [5, 5],
    widget_base_dimensions: [140, 140]
});