Multi-cell HTML table select, copy, and paste
This combines methods culled from several stack overflow answers to create a Flash-free multicell cut and paste, using native browser features. This solution is structured as a jQuery extension.
The SO answers used include:
http://stackoverflow.com/questions/17527870/how-does-trello-access-the-users-clipboard
http://jsfiddle.net/AGEf7/
http://stackoverflow.com/questions/12066870/how-to-check-if-an-element-is-overlapping-other-elements
http://stackoverflow.com/questions/8884803/jquery-drag-and-draw
HTML
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<div id="container">
<div id="bucket0" class="flexRow"></div>
<div class="flexCol">
<h3>Source content</h3>
<p>Click and drag to select one or more table cells.</p>
</div>
<div id="bucket1" class="flexRow">
<div class="flexCol">
<div id="myDiv" class="inlineFlex">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Fixed</th>
</tr>
</thead>
<tbody>
<tr>
<td>#1</td>
</tr>
<tr>
<td>#2</td>
</tr>
</tbody>
</table>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Lorem</th>
<th>Ipsum</th>
<th>Dolor</th>
</tr>
</thead>
<tbody>
<tr>
<td> <strong>1</strong>
</td>
<td> <a href="#" onclick="alert('I\'ve been clicked')">2</a>
</td>
<td>2.5</td>
</tr>
<tr>
<td><img src="http://i.stack.imgur.com/xkF9Q.jpg"/></td>
<td> <strong>4</strong>.5</td>
<td>
<input type="text" value="5" class="form-control" />
</td>
...
CSS
.selectionbox {
position: absolute;
background: transparent;
border: 1px dotted #000;
}
.container {
display: flex;
flex-flow: column;
}
.flexRow {
display: flex;
flex-flow: row;
height: 50%;
}
.flexCol {
display: flex;
flex-flow: column
}
.inlineFlex {
display: inline-flex;
}
input.form-control {
width: 4em;
}
tr { height: 4em; }
JavaScript
$.fn.selectable = function (options) {
// Internal methods
var defaults = {
highlightClass: 'selected',
selectionBoxClass: 'selectionbox'
};
options = $.extend(defaults, options);
var getOverlappingElements = function (overlay, rootElement) {
return $(rootElement)
.find('*')
.filter(function () {
var rect1 = this.getBoundingClientRect(),
rect2 = overlay.getBoundingClientRect();
var overlap = !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom);
return overlap;
});
}
var getSelections = function (rootElement) {
// Build delimited array from selections for paste
var $elements = $(rootElement).find('td.' + options.highlightClass),
selections = '';
if (!$elements || !$elements.length) {
return selections;
}
var firstRow = $elements[0].closest('tr').rowIndex,
rowArray = [];
for (var i = 0; i < $elements.length; i++) {
var thisRowIndex = $elements[i].closest('tr').rowIndex - firstRow;
if (!rowArray[thisRowIndex]) {
rowArray[thisRowIndex] = [];
}
var $visibleInputs = $($elements[i]).find('input:visible');
var hasInput = $visibleInputs.length > 0;
if (!hasInput) {
rowArray[thisRowIndex].push($elements[i].innerText);
} else {
rowArray[thisRowIndex].push($visibleInputs[0].value);
}
}
// Build delimited string from array
for (var i = 0; i < rowArray.length; i++) {
for (var j = 0; j < rowArray[i].length; j++) {
selections += rowArray[i][j];
if (j < rowArray[i].length - 1) {
selections += '\t';
}
}
if (i < rowArray.length - 1) {
...