Editable on Steroids

by Herst

HTML

<link rel="stylesheet" href="http://mottie.github.io/tablesorter/dist/css/theme.default.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://rawgit.com/Mottie/tablesorter/master/js/jquery.tablesorter.js"></script>
<script src="https://rawgit.com/Mottie/tablesorter/master/js/widgets/widget-editable.js"></script>
<div class="container-fluid">
    <table id="table" class="table table-bordered">
        <thead>
            <tr>http://jsfiddle.net/Herst/3ckksgbh/#fork
                <th>Name (One-Line)</th>
                <th>Descr. (Multi-Line)</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td class="cell-name">foo</td>
                <td class="cell-descr">bar</td>
            </tr>
        </tbody>
    </table>Results:
    <textarea id="results"></textarea>
</div>

CSS

#table div.form-control {
    height: 100% !important;
}

JavaScript

function appendToLineArr(arr, texts) {
    if (arr.length) arr[arr.length - 1] += texts.splice(0, 1); // take first element and append to last line

    $.merge(arr, texts);
}

function getLinesFromHTML($el) {
    var $contents = $el.contents(),
        lines = [];

    if (!$contents.length) return '';

    $contents.each(function (i, subEl) {

        if (subEl.nodeType === 3) // text node
        appendToLineArr(lines, subEl.data.split(/\n/g));
        else if (subEl.nodeType === 1) { // element node

            // alt idea: use .css('display')
            switch (subEl.tagName.toLowerCase()) { // or .nodeName?
                // common block elements
                case 'blockquote':
                case 'div':
                case 'p':

                    $.merge(lines, getLinesFromHTML($(subEl))); // TODO trim?

                    break;

                case 'br':
                    lines.push('');

                    break;

                default:
                    // assume inline elements for the rest, assume no block element inside (standard-compliant)

                    appendToLineArr(lines, $(subEl).text().split(/\n/g));
            }
        }
    });

    return lines;
}

function trimArray(arr) {

    if (!arr.length) return [];

    var firstNonEmpty = -1,
        lastNonEmpty = -1;

    for (var i = 0; i < arr.length; ++i)
    if (arr[i]) {
        firstNonEmpty = i
        break;
    }

    if (firstNonEmpty < 0) return [];

    for (var j = arr.length - 1; j >= 0; --j)
    if (arr[j]) {
        lastNonEmpty = j;
        break;
    }

    return arr.slice(firstNonEmpty, lastNonEmpty + 1);
}

function getTextFromHTML($el, withNewLines) {
    if (!withNewLines) return $.trim($el.text()); // .trim necessary? JQuery doc unclear

    return $.trim($.map($el.contents(), function (el) {
        if (el.nodeType === 3 && el.data) // text node
        return el.data;
        else if (el.nodeType === 1 && el.tagName.toLowerCase() == 'br')...