/**
* SimpleTableModel.js
*
* Released under LGPL License.
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*/
define(
'tinymce.core.selection.SimpleTableModel',
[
'ephox.katamari.api.Arr',
'ephox.katamari.api.Option',
'ephox.katamari.api.Struct',
'ephox.sugar.api.dom.Compare',
'ephox.sugar.api.dom.Insert',
'ephox.sugar.api.dom.InsertAll',
'ephox.sugar.api.dom.Replication',
'ephox.sugar.api.node.Element',
'ephox.sugar.api.properties.Attr',
'ephox.sugar.api.search.SelectorFilter'
],
function (Arr, Option, Struct, Compare, Insert, InsertAll, Replication, Element, Attr, SelectorFilter) {
var tableModel = Struct.immutable('element', 'width', 'rows');
var tableRow = Struct.immutable('element', 'cells');
var cellPosition = Struct.immutable('x', 'y');
var getSpan = function (td, key) {
var value = parseInt(Attr.get(td, key), 10);
return isNaN(value) ? 1 : value;
};
var fillout = function (table, x, y, tr, td) {
var rowspan = getSpan(td, 'rowspan');
var colspan = getSpan(td, 'colspan');
var rows = table.rows();
for (var y2 = y; y2 < y + rowspan; y2++) {
if (!rows[y2]) {
rows[y2] = tableRow(Replication.deep(tr), []);
}
for (var x2 = x; x2 < x + colspan; x2++) {
var cells = rows[y2].cells();
// not filler td:s are purposely not cloned so that we can
// find cells in the model by element object references
cells[x2] = y2 == y && x2 == x ? td : Replication.shallow(td);
}
}
};
var cellExists = function (table, x, y) {
var rows = table.rows();
var cells = rows[y] ? rows[y].cells() : [];
return !!cells[x];
};
var skipCellsX = function (table, x, y) {
while (cellExists(table, x, y)) {
x++;
}
return x;
};
var getWidth = function (rows) {
return Arr.foldl(rows, function (acc, row) {
return row.cells().length > acc ? row.cells().length : acc;
}, 0);
};
var findElementPos = function (table, element) {
var rows = table.rows();
for (var y = 0; y < rows.length; y++) {
var cells = rows[y].cells();
for (var x = 0; x < cells.length; x++) {
if (Compare.eq(cells[x], element)) {
return Option.some(cellPosition(x, y));
}
}
}
return Option.none();
};
var extractRows = function (table, sx, sy, ex, ey) {
var newRows = [];
var rows = table.rows();
for (var y = sy; y <= ey; y++) {
var cells = rows[y].cells();
var slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
newRows.push(tableRow(rows[y].element(), slice));
}
return newRows;
};
var subTable = function (table, startPos, endPos) {
var sx = startPos.x(), sy = startPos.y();
var ex = endPos.x(), ey = endPos.y();
var newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
return tableModel(table.element(), getWidth(newRows), newRows);
};
var createDomTable = function (table, rows) {
var tableElement = Replication.shallow(table.element());
var tableBody = Element.fromTag('tbody');
InsertAll.append(tableBody, rows);
Insert.append(tableElement, tableBody);
return tableElement;
};
var modelRowsToDomRows = function (table) {
return Arr.map(table.rows(), function (row) {
var cells = Arr.map(row.cells(), function (cell) {
var td = Replication.deep(cell);
Attr.remove(td, 'colspan');
Attr.remove(td, 'rowspan');
return td;
});
var tr = Replication.shallow(row.element());
InsertAll.append(tr, cells);
return tr;
});
};
var fromDom = function (tableElm) {
var table = tableModel(Replication.shallow(tableElm), 0, []);
Arr.each(SelectorFilter.descendants(tableElm, 'tr'), function (tr, y) {
Arr.each(SelectorFilter.descendants(tr, 'td,th'), function (td, x) {
fillout(table, skipCellsX(table, x, y), y, tr, td);
});
});
return tableModel(table.element(), getWidth(table.rows()), table.rows());
};
var toDom = function (table) {
return createDomTable(table, modelRowsToDomRows(table));
};
var subsection = function (table, startElement, endElement) {
return findElementPos(table, startElement).bind(function (startPos) {
return findElementPos(table, endElement).map(function (endPos) {
return subTable(table, startPos, endPos);
});
});
};
return {
fromDom: fromDom,
toDom: toDom,
subsection: subsection
};
}
);
|