spreadsheet cell-like table

Features ・selectable ・drag and pastable ・direction key support

by Seungrae Lee

HTML

<table id="example1" cellspacing="0" cellpadding="3">
    <tr>
        <td></td>
        <td>kia</td>
        <td>toyota</td>
        <td>GM</td>
        <td><span id="E1">rating</span>
        </td>
    </tr>
    <tr>
        <td>2011</td>
        <td>10</td>
        <td>11</td>
        <td tabindex="1">12</td>
        <td>
            <input type="text" name="E2" id="E2" value="8" size="5" />
        </td>
    </tr>
    <tr>
        <td>2012</td>
        <td>11</td>
        <td>12</td>
        <td>13</td>
        <td>
            <input type="text" name="E3" id="E3" value="9" size="5" />
        </td>
    </tr>
    <tr>
        <td>2013</td>
        <td>12</td>
        <td>13</td>
        <td>14</td>
        <td>
            <input type="text" name="E4" id="E4" value="10" size="5" />
        </td>
    </tr>
    <tr>
        <td>2014</td>
        <td>13</td>
        <td>14</td>
        <td>15</td>
        <td>
            <input type="text" name="E4" id="E4" value="9" size="5" />
        </td>
    </tr>
</table>
<div id="console"></div>

CSS

table#example1 td {
    border: 1px solid #ccc;
    text-align: center;
}
table#example1 input {
    text-align: left;
    font-size: 11pt;
    padding: 2px;
    margin: 0px;
    border: 0px;
}
.ui-cell-borders {
    position: absolute;
}
.wtBorders, .wtAnchor {
    display: block;
    position: absolute;
}
.wtBorders {
    width: 2px;
    height: 2px;
}
.wtAnchor {
    width: 5px;
    height: 5px;
    cursor: crosshair;
}

JavaScript

(function ($, undefined) {
    $.ui = $.ui || {};
    $.extend($.ui, {
        keyCode: {
            LEFT: 37,
            UP: 38,
            RIGHT: 39,
            DOWN: 40
        }
    });
    $.extend($.fn, {
        version: "0.3.1",
        iTable: function (options) {
            return this.each(function () {
                return new $.iTable(options, this);
            });
        }
    });
    // constructor
    $.iTable = function (options, target) {
        // merge options
        this.o = $.extend(true, {}, $.iTable.defaults, options);
        this.target = target;
        this.init();
    };

    // define cell object
    var Cell = function (colIndex, rowIndex, element) {
        var obj = this,
            _create = function () {
                obj.col = colIndex;
                obj.row = rowIndex;
                obj.reference = colIndex + "" + rowIndex;
                obj.target = element;
                obj.top = element.offset().top;
                obj.left = element.offset().left;
                obj.width = element.prop("offsetWidth");
                obj.height = element.prop("offsetHeight");
                obj.value = _getValue();
            },
            _getValue = function () {
                var node = _deepestNode(element);
                var val;
                switch (node[0].nodeName.toLowerCase()) {
                    case "input":
                        if (/text/i.test(node[0].type)) {
                            val = node.val();
                        } //if~else
                        break;
                    default:
                        val = node.text();
                        break;
                } //switch
                return val;
            },
            _deepestNode = function (node) {
                var target = node;
                var next = node.children();
                while (next.length > 0) {
                    target = next;
                    next = next.children();
    ...