grid emulation test

by joshjs

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.debug.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<script src="http://borismoore.github.com/jsrender/jsrender.js"></script>
<div id="pageGrid" class="pageGrid" data-bind="blocks: Blocks, selectedBlockIds: selectedBlockIds, style: { width: gridWidth, height: gridHeight }"></div>
<table id="blockDetails" data-bind="with: editingBlock">
    <tr>
        <td>Id:</td>
        <td><span data-bind="text: Id" /></td>
    </tr>
    <tr>
        <td>Code:</td>
        <td><input data-bind="value: Code" /></td>
    </tr>
    <tr>
        <td>Notes:</td>
        <td><input data-bind="value: Notes" /></td>
    </tr>
</table>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
    <script id="gridBlockTemplate" type="text/x-jsrender">
        {{for #data}}
            <a id="block-{{:Id}}" data-id="{{:Id}}" class="gridBlock" style="top: {{:Top}}px; left: {{:Left}}px; height: {{:Height-1}}px; width: {{:Width-1}}px;"></a>
        {{/for}}
    </script>

CSS

.ui-selecting {
  background: #feca40; }

.ui-selected {
  background: #f39814;
  color: white; }

.pageGrid
{
    position: relative;
    border: 1px solid #666;
    border-top:0;
    border-left:0;
    overflow: hidden;
    background: #CEEEEE;
}

.gridBlock
{
    position: absolute;
    border: 1px solid #666;
    border-bottom: 0;
    border-right:0;
    overflow: hidden;
}

JavaScript

var gridData = {
    "GridHeight": 50,
    "GridWidth": 150,
    "Blocks": [{
        Id: 1,
        Code: 'A01',
        Width: 50,
        Height: 50,
        Top: 0,
        Left: 0,
        Notes: 'foo'},
    {
        Id: 2,
        Code: 'A02',
        Width: 50,
        Height: 50,
        Top: 0,
        Left: 50,
        Notes: 'bar'},
    {
        Id: 3,
        Code: 'A03',
        Width: 50,
        Height: 50,
        Top: 0,
        Left: 100,
        Notes: ''}]
};

if (Array.prototype.remove == undefined) {
    Array.prototype.remove = function() {
        var what, a = arguments, L = a.length, ax;
        while (L && this.length) {
            what = a[--L];
            while ((ax = this.indexOf(what)) != -1) {
                this.splice(ax, 1);
            }
        }
        return this;
    };
}

/*!
 *  jQuery gridView plugin
 */

;(function ($, window, document, undefined) {
    $.widget("ui.gridView", {
        options: {
            blockClass: 'gridBlock',
            blockTemplate: 'gridBlockTemplate'
        },
        _create: function () {
            var self = this,
                o = this.options;

            self._blockData = [];
            self._selectedBlockIds = [];

            self.element.selectable({
                filter: '.'+self.options.blockClass,
                selected: function (e, ui) {
                    var id = $(ui.selected).data('id');
                    if (self._selectedBlockIds.indexOf(id) == -1) {
                        self._selectedBlockIds.push(id);
                    }
                },
                selecting: function (e, ui) {
                    if (!e.ctrlKey) {
                        self._selectedBlockIds = [];
                    }
                },
                stop: function (e, ui) {
                    self.element.trigger("selectedBlockIdsChanged", [self.getSelectedBlockIds()]);
                },
                unselected: function (e, ui) {
                    var id =...