Create a submit_buttons block in group edit profile template so that submit buttons can be customized. Replace submit_message usage with new notice block (still work in progress in Lookup User views). Add customized edit profile template for Sponsor with delete button (not used yet, upcoming commit). Add delete Sponsor request handler.
Patch by: Pawel Solyga
Review by: to-be-reviewed
/**
* $Id: editor_plugin_src.js 853 2008-05-27 08:05:35Z spocke $
*
* @author Moxiecode
* @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var each = tinymce.each;
tinymce.create('tinymce.plugins.TablePlugin', {
init : function(ed, url) {
var t = this;
t.editor = ed;
t.url = url;
// Register buttons
each([
['table', 'table.desc', 'mceInsertTable', true],
['delete_table', 'table.del', 'mceTableDelete'],
['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],
['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],
['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],
['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],
['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],
['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],
['row_props', 'table.row_desc', 'mceTableRowProps', true],
['cell_props', 'table.cell_desc', 'mceTableCellProps', true],
['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],
['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]
], function(c) {
ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
});
ed.onInit.add(function() {
if (ed && ed.plugins.contextmenu) {
ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
var sm, se = ed.selection, el = se.getNode() || ed.getBody();
if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th')) {
m.removeAll();
if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {
m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
m.addSeparator();
}
if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {
m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
m.addSeparator();
}
m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true, value : {action : 'insert'}});
m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable', ui : true});
m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete', ui : true});
m.addSeparator();
// Cell menu
sm = m.addMenu({title : 'table.cell'});
sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps', ui : true});
sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells', ui : true});
sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells', ui : true});
// Row menu
sm = m.addMenu({title : 'table.row'});
sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps', ui : true});
sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});
sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});
sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});
sm.addSeparator();
sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});
sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});
sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'});
sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'});
// Column menu
sm = m.addMenu({title : 'table.col'});
sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});
sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});
sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});
} else
m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true});
});
}
});
// Add undo level when new rows are created using the tab key
ed.onKeyDown.add(function(ed, e) {
if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE')) {
if (!tinymce.isGecko && !tinymce.isOpera) {
tinyMCE.execInstanceCommand(ed.editorId, "mceTableMoveToNextRow", true);
return tinymce.dom.Event.cancel(e);
}
ed.undoManager.add();
}
});
// Select whole table is a table border is clicked
if (!tinymce.isIE) {
if (ed.getParam('table_selection', true)) {
ed.onClick.add(function(ed, e) {
e = e.target;
if (e.nodeName === 'TABLE')
ed.selection.select(e);
});
}
}
ed.onNodeChange.add(function(ed, cm, n) {
var p = ed.dom.getParent(n, 'td,th,caption');
cm.setActive('table', n.nodeName === 'TABLE' || !!p);
if (p && p.nodeName === 'CAPTION')
p = null;
cm.setDisabled('delete_table', !p);
cm.setDisabled('delete_col', !p);
cm.setDisabled('delete_table', !p);
cm.setDisabled('delete_row', !p);
cm.setDisabled('col_after', !p);
cm.setDisabled('col_before', !p);
cm.setDisabled('row_after', !p);
cm.setDisabled('row_before', !p);
cm.setDisabled('row_props', !p);
cm.setDisabled('cell_props', !p);
cm.setDisabled('split_cells', !p || (parseInt(ed.dom.getAttrib(p, 'colspan', '1')) < 2 && parseInt(ed.dom.getAttrib(p, 'rowspan', '1')) < 2));
cm.setDisabled('merge_cells', !p);
});
// Padd empty table cells
if (!tinymce.isIE) {
ed.onBeforeSetContent.add(function(ed, o) {
if (o.initial)
o.content = o.content.replace(/<(td|th)([^>]+|)>\s*<\/(td|th)>/g, tinymce.isOpera ? '<$1$2> </$1>' : '<$1$2><br mce_bogus="1" /></$1>');
});
}
},
execCommand : function(cmd, ui, val) {
var ed = this.editor, b;
// Is table command
switch (cmd) {
case "mceTableMoveToNextRow":
case "mceInsertTable":
case "mceTableRowProps":
case "mceTableCellProps":
case "mceTableSplitCells":
case "mceTableMergeCells":
case "mceTableInsertRowBefore":
case "mceTableInsertRowAfter":
case "mceTableDeleteRow":
case "mceTableInsertColBefore":
case "mceTableInsertColAfter":
case "mceTableDeleteCol":
case "mceTableCutRow":
case "mceTableCopyRow":
case "mceTablePasteRowBefore":
case "mceTablePasteRowAfter":
case "mceTableDelete":
ed.execCommand('mceBeginUndoLevel');
this._doExecCommand(cmd, ui, val);
ed.execCommand('mceEndUndoLevel');
return true;
}
// Pass to next handler in chain
return false;
},
getInfo : function() {
return {
longname : 'Tables',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
},
// Private plugin internal methods
/**
* Executes the table commands.
*/
_doExecCommand : function(command, user_interface, value) {
var inst = this.editor, ed = inst, url = this.url;
var focusElm = inst.selection.getNode();
var trElm = inst.dom.getParent(focusElm, "tr");
var tdElm = inst.dom.getParent(focusElm, "td,th");
var tableElm = inst.dom.getParent(focusElm, "table");
var doc = inst.contentWindow.document;
var tableBorder = tableElm ? tableElm.getAttribute("border") : "";
// Get first TD if no TD found
if (trElm && tdElm == null)
tdElm = trElm.cells[0];
function inArray(ar, v) {
for (var i=0; i<ar.length; i++) {
// Is array
if (ar[i].length > 0 && inArray(ar[i], v))
return true;
// Found value
if (ar[i] == v)
return true;
}
return false;
}
function select(dx, dy) {
var td;
grid = getTableGrid(tableElm);
dx = dx || 0;
dy = dy || 0;
dx = Math.max(cpos.cellindex + dx, 0);
dy = Math.max(cpos.rowindex + dy, 0);
// Recalculate grid and select
inst.execCommand('mceRepaint');
td = getCell(grid, dy, dx);
if (td) {
inst.selection.select(td.firstChild || td);
inst.selection.collapse(1);
}
};
function makeTD() {
var newTD = doc.createElement("td");
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
}
function getColRowSpan(td) {
var colspan = inst.dom.getAttrib(td, "colspan");
var rowspan = inst.dom.getAttrib(td, "rowspan");
colspan = colspan == "" ? 1 : parseInt(colspan);
rowspan = rowspan == "" ? 1 : parseInt(rowspan);
return {colspan : colspan, rowspan : rowspan};
}
function getCellPos(grid, td) {
var x, y;
for (y=0; y<grid.length; y++) {
for (x=0; x<grid[y].length; x++) {
if (grid[y][x] == td)
return {cellindex : x, rowindex : y};
}
}
return null;
}
function getCell(grid, row, col) {
if (grid[row] && grid[row][col])
return grid[row][col];
return null;
}
function getNextCell(table, cell) {
var cells = [], x = 0, i, j, cell, nextCell;
for (i = 0; i < table.rows.length; i++)
for (j = 0; j < table.rows[i].cells.length; j++, x++)
cells[x] = table.rows[i].cells[j];
for (i = 0; i < cells.length; i++)
if (cells[i] == cell)
if (nextCell = cells[i+1])
return nextCell;
}
function getTableGrid(table) {
var grid = [], rows = table.rows, x, y, td, sd, xstart, x2, y2;
for (y=0; y<rows.length; y++) {
for (x=0; x<rows[y].cells.length; x++) {
td = rows[y].cells[x];
sd = getColRowSpan(td);
// All ready filled
for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ;
// Fill box
for (y2=y; y2<y+sd['rowspan']; y2++) {
if (!grid[y2])
grid[y2] = [];
for (x2=xstart; x2<xstart+sd['colspan']; x2++)
grid[y2][x2] = td;
}
}
}
return grid;
}
function trimRow(table, tr, td, new_tr) {
var grid = getTableGrid(table), cpos = getCellPos(grid, td);
var cells, lastElm;
// Time to crop away some
if (new_tr.cells.length != tr.childNodes.length) {
cells = tr.childNodes;
lastElm = null;
for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) {
var remove = true;
var sd = getColRowSpan(td);
// Remove due to rowspan
if (inArray(cells, td)) {
new_tr.childNodes[x]._delete = true;
} else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan
for (var i=x; i<x+td.colSpan; i++)
new_tr.childNodes[i]._delete = true;
}
if ((lastElm == null || td != lastElm) && sd.rowspan > 1)
td.rowSpan = sd.rowspan + 1;
lastElm = td;
}
deleteMarked(tableElm);
}
}
function prevElm(node, name) {
while ((node = node.previousSibling) != null) {
if (node.nodeName == name)
return node;
}
return null;
}
function nextElm(node, names) {
var namesAr = names.split(',');
while ((node = node.nextSibling) != null) {
for (var i=0; i<namesAr.length; i++) {
if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() )
return node;
}
}
return null;
}
function deleteMarked(tbl) {
if (tbl.rows == 0)
return;
var tr = tbl.rows[0];
do {
var next = nextElm(tr, "TR");
// Delete row
if (tr._delete) {
tr.parentNode.removeChild(tr);
continue;
}
// Delete cells
var td = tr.cells[0];
if (td.cells > 1) {
do {
var nexttd = nextElm(td, "TD,TH");
if (td._delete)
td.parentNode.removeChild(td);
} while ((td = nexttd) != null);
}
} while ((tr = next) != null);
}
function addRows(td_elm, tr_elm, rowspan) {
// Add rows
td_elm.rowSpan = 1;
var trNext = nextElm(tr_elm, "TR");
for (var i=1; i<rowspan && trNext; i++) {
var newTD = doc.createElement("td");
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
if (tinymce.isIE)
trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex));
else
trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]);
trNext = nextElm(trNext, "TR");
}
}
function copyRow(doc, table, tr) {
var grid = getTableGrid(table);
var newTR = tr.cloneNode(false);
var cpos = getCellPos(grid, tr.cells[0]);
var lastCell = null;
var tableBorder = inst.dom.getAttrib(table, "border");
var tdElm = null;
for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
var newTD = null;
if (lastCell != tdElm) {
for (var i=0; i<tr.cells.length; i++) {
if (tdElm == tr.cells[i]) {
newTD = tdElm.cloneNode(true);
break;
}
}
}
if (newTD == null) {
newTD = doc.createElement("td");
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
}
// Reset col/row span
newTD.colSpan = 1;
newTD.rowSpan = 1;
newTR.appendChild(newTD);
lastCell = tdElm;
}
return newTR;
}
// ---- Commands -----
// Handle commands
switch (command) {
case "mceTableMoveToNextRow":
var nextCell = getNextCell(tableElm, tdElm);
if (!nextCell) {
inst.execCommand("mceTableInsertRowAfter", tdElm);
nextCell = getNextCell(tableElm, tdElm);
}
inst.selection.select(nextCell);
inst.selection.collapse(true);
return true;
case "mceTableRowProps":
if (trElm == null)
return true;
if (user_interface) {
inst.windowManager.open({
url : url + '/row.htm',
width : 400 + parseInt(inst.getLang('table.rowprops_delta_width', 0)),
height : 295 + parseInt(inst.getLang('table.rowprops_delta_height', 0)),
inline : 1
}, {
plugin_url : url
});
}
return true;
case "mceTableCellProps":
if (tdElm == null)
return true;
if (user_interface) {
inst.windowManager.open({
url : url + '/cell.htm',
width : 400 + parseInt(inst.getLang('table.cellprops_delta_width', 0)),
height : 295 + parseInt(inst.getLang('table.cellprops_delta_height', 0)),
inline : 1
}, {
plugin_url : url
});
}
return true;
case "mceInsertTable":
if (user_interface) {
inst.windowManager.open({
url : url + '/table.htm',
width : 400 + parseInt(inst.getLang('table.table_delta_width', 0)),
height : 320 + parseInt(inst.getLang('table.table_delta_height', 0)),
inline : 1
}, {
plugin_url : url,
action : value ? value.action : 0
});
}
return true;
case "mceTableDelete":
var table = inst.dom.getParent(inst.selection.getNode(), "table");
if (table) {
table.parentNode.removeChild(table);
inst.execCommand('mceRepaint');
}
return true;
case "mceTableSplitCells":
case "mceTableMergeCells":
case "mceTableInsertRowBefore":
case "mceTableInsertRowAfter":
case "mceTableDeleteRow":
case "mceTableInsertColBefore":
case "mceTableInsertColAfter":
case "mceTableDeleteCol":
case "mceTableCutRow":
case "mceTableCopyRow":
case "mceTablePasteRowBefore":
case "mceTablePasteRowAfter":
// No table just return (invalid command)
if (!tableElm)
return true;
// Table has a tbody use that reference
// Changed logic by ApTest 2005.07.12 (www.aptest.com)
// Now lookk at the focused element and take its parentNode. That will be a tbody or a table.
if (trElm && tableElm != trElm.parentNode)
tableElm = trElm.parentNode;
if (tableElm && trElm) {
switch (command) {
case "mceTableCutRow":
if (!trElm || !tdElm)
return true;
inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
inst.execCommand("mceTableDeleteRow");
break;
case "mceTableCopyRow":
if (!trElm || !tdElm)
return true;
inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
break;
case "mceTablePasteRowBefore":
if (!trElm || !tdElm)
return true;
var newTR = inst.tableRowClipboard.cloneNode(true);
var prevTR = prevElm(trElm, "TR");
if (prevTR != null)
trimRow(tableElm, prevTR, prevTR.cells[0], newTR);
trElm.parentNode.insertBefore(newTR, trElm);
break;
case "mceTablePasteRowAfter":
if (!trElm || !tdElm)
return true;
var nextTR = nextElm(trElm, "TR");
var newTR = inst.tableRowClipboard.cloneNode(true);
trimRow(tableElm, trElm, tdElm, newTR);
if (nextTR == null)
trElm.parentNode.appendChild(newTR);
else
nextTR.parentNode.insertBefore(newTR, nextTR);
break;
case "mceTableInsertRowBefore":
if (!trElm || !tdElm)
return true;
var grid = getTableGrid(tableElm);
var cpos = getCellPos(grid, tdElm);
var newTR = doc.createElement("tr");
var lastTDElm = null;
cpos.rowindex--;
if (cpos.rowindex < 0)
cpos.rowindex = 0;
// Create cells
for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
if (tdElm != lastTDElm) {
var sd = getColRowSpan(tdElm);
if (sd['rowspan'] == 1) {
var newTD = doc.createElement("td");
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
newTD.colSpan = tdElm.colSpan;
newTR.appendChild(newTD);
} else
tdElm.rowSpan = sd['rowspan'] + 1;
lastTDElm = tdElm;
}
}
trElm.parentNode.insertBefore(newTR, trElm);
select(0, 1);
break;
case "mceTableInsertRowAfter":
if (!trElm || !tdElm)
return true;
var grid = getTableGrid(tableElm);
var cpos = getCellPos(grid, tdElm);
var newTR = doc.createElement("tr");
var lastTDElm = null;
// Create cells
for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
if (tdElm != lastTDElm) {
var sd = getColRowSpan(tdElm);
if (sd['rowspan'] == 1) {
var newTD = doc.createElement("td");
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
newTD.colSpan = tdElm.colSpan;
newTR.appendChild(newTD);
} else
tdElm.rowSpan = sd['rowspan'] + 1;
lastTDElm = tdElm;
}
}
if (newTR.hasChildNodes()) {
var nextTR = nextElm(trElm, "TR");
if (nextTR)
nextTR.parentNode.insertBefore(newTR, nextTR);
else
tableElm.appendChild(newTR);
}
select(0, 1);
break;
case "mceTableDeleteRow":
if (!trElm || !tdElm)
return true;
var grid = getTableGrid(tableElm);
var cpos = getCellPos(grid, tdElm);
// Only one row, remove whole table
if (grid.length == 1 && tableElm.nodeName == 'TBODY') {
inst.dom.remove(inst.dom.getParent(tableElm, "table"));
return true;
}
// Move down row spanned cells
var cells = trElm.cells;
var nextTR = nextElm(trElm, "TR");
for (var x=0; x<cells.length; x++) {
if (cells[x].rowSpan > 1) {
var newTD = cells[x].cloneNode(true);
var sd = getColRowSpan(cells[x]);
newTD.rowSpan = sd.rowspan - 1;
var nextTD = nextTR.cells[x];
if (nextTD == null)
nextTR.appendChild(newTD);
else
nextTR.insertBefore(newTD, nextTD);
}
}
// Delete cells
var lastTDElm = null;
for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
if (tdElm != lastTDElm) {
var sd = getColRowSpan(tdElm);
if (sd.rowspan > 1) {
tdElm.rowSpan = sd.rowspan - 1;
} else {
trElm = tdElm.parentNode;
if (trElm.parentNode)
trElm._delete = true;
}
lastTDElm = tdElm;
}
}
deleteMarked(tableElm);
select(0, -1);
break;
case "mceTableInsertColBefore":
if (!trElm || !tdElm)
return true;
var grid = getTableGrid(tableElm);
var cpos = getCellPos(grid, tdElm);
var lastTDElm = null;
for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
if (tdElm != lastTDElm) {
var sd = getColRowSpan(tdElm);
if (sd['colspan'] == 1) {
var newTD = doc.createElement(tdElm.nodeName);
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
newTD.rowSpan = tdElm.rowSpan;
tdElm.parentNode.insertBefore(newTD, tdElm);
} else
tdElm.colSpan++;
lastTDElm = tdElm;
}
}
select();
break;
case "mceTableInsertColAfter":
if (!trElm || !tdElm)
return true;
var grid = getTableGrid(tableElm);
var cpos = getCellPos(grid, tdElm);
var lastTDElm = null;
for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
if (tdElm != lastTDElm) {
var sd = getColRowSpan(tdElm);
if (sd['colspan'] == 1) {
var newTD = doc.createElement(tdElm.nodeName);
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
newTD.rowSpan = tdElm.rowSpan;
var nextTD = nextElm(tdElm, "TD,TH");
if (nextTD == null)
tdElm.parentNode.appendChild(newTD);
else
nextTD.parentNode.insertBefore(newTD, nextTD);
} else
tdElm.colSpan++;
lastTDElm = tdElm;
}
}
select(1);
break;
case "mceTableDeleteCol":
if (!trElm || !tdElm)
return true;
var grid = getTableGrid(tableElm);
var cpos = getCellPos(grid, tdElm);
var lastTDElm = null;
// Only one col, remove whole table
if ((grid.length > 1 && grid[0].length <= 1) && tableElm.nodeName == 'TBODY') {
inst.dom.remove(inst.dom.getParent(tableElm, "table"));
return true;
}
// Delete cells
for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
if (tdElm != lastTDElm) {
var sd = getColRowSpan(tdElm);
if (sd['colspan'] > 1)
tdElm.colSpan = sd['colspan'] - 1;
else {
if (tdElm.parentNode)
tdElm.parentNode.removeChild(tdElm);
}
lastTDElm = tdElm;
}
}
select(-1);
break;
case "mceTableSplitCells":
if (!trElm || !tdElm)
return true;
var spandata = getColRowSpan(tdElm);
var colspan = spandata["colspan"];
var rowspan = spandata["rowspan"];
// Needs splitting
if (colspan > 1 || rowspan > 1) {
// Generate cols
tdElm.colSpan = 1;
for (var i=1; i<colspan; i++) {
var newTD = doc.createElement("td");
if (!tinymce.isIE)
newTD.innerHTML = '<br mce_bogus="1"/>';
trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH"));
if (rowspan > 1)
addRows(newTD, trElm, rowspan);
}
addRows(tdElm, trElm, rowspan);
}
// Apply visual aids
tableElm = inst.dom.getParent(inst.selection.getNode(), "table");
break;
case "mceTableMergeCells":
var rows = [];
var sel = inst.selection.getSel();
var grid = getTableGrid(tableElm);
if (tinymce.isIE || sel.rangeCount == 1) {
if (user_interface) {
// Setup template
var sp = getColRowSpan(tdElm);
inst.windowManager.open({
url : url + '/merge_cells.htm',
width : 240 + parseInt(inst.getLang('table.merge_cells_delta_width', 0)),
height : 110 + parseInt(inst.getLang('table.merge_cells_delta_height', 0)),
inline : 1
}, {
action : "update",
numcols : sp.colspan,
numrows : sp.rowspan,
plugin_url : url
});
return true;
} else {
var numRows = parseInt(value['numrows']);
var numCols = parseInt(value['numcols']);
var cpos = getCellPos(grid, tdElm);
if (("" + numRows) == "NaN")
numRows = 1;
if (("" + numCols) == "NaN")
numCols = 1;
// Get rows and cells
var tRows = tableElm.rows;
for (var y=cpos.rowindex; y<grid.length; y++) {
var rowCells = [];
for (var x=cpos.cellindex; x<grid[y].length; x++) {
var td = getCell(grid, y, x);
if (td && !inArray(rows, td) && !inArray(rowCells, td)) {
var cp = getCellPos(grid, td);
// Within range
if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows)
rowCells[rowCells.length] = td;
}
}
if (rowCells.length > 0)
rows[rows.length] = rowCells;
var td = getCell(grid, cpos.rowindex, cpos.cellindex);
each(ed.dom.select('br', td), function(e, i) {
if (i > 0 && ed.dom.getAttrib('mce_bogus'))
ed.dom.remove(e);
});
}
//return true;
}
} else {
var cells = [];
var sel = inst.selection.getSel();
var lastTR = null;
var curRow = null;
var x1 = -1, y1 = -1, x2, y2;
// Only one cell selected, whats the point?
if (sel.rangeCount < 2)
return true;
// Get all selected cells
for (var i=0; i<sel.rangeCount; i++) {
var rng = sel.getRangeAt(i);
var tdElm = rng.startContainer.childNodes[rng.startOffset];
if (!tdElm)
break;
if (tdElm.nodeName == "TD" || tdElm.nodeName == "TH")
cells[cells.length] = tdElm;
}
// Get rows and cells
var tRows = tableElm.rows;
for (var y=0; y<tRows.length; y++) {
var rowCells = [];
for (var x=0; x<tRows[y].cells.length; x++) {
var td = tRows[y].cells[x];
for (var i=0; i<cells.length; i++) {
if (td == cells[i]) {
rowCells[rowCells.length] = td;
}
}
}
if (rowCells.length > 0)
rows[rows.length] = rowCells;
}
// Find selected cells in grid and box
var curRow = [];
var lastTR = null;
for (var y=0; y<grid.length; y++) {
for (var x=0; x<grid[y].length; x++) {
grid[y][x]._selected = false;
for (var i=0; i<cells.length; i++) {
if (grid[y][x] == cells[i]) {
// Get start pos
if (x1 == -1) {
x1 = x;
y1 = y;
}
// Get end pos
x2 = x;
y2 = y;
grid[y][x]._selected = true;
}
}
}
}
// Is there gaps, if so deny
for (var y=y1; y<=y2; y++) {
for (var x=x1; x<=x2; x++) {
if (!grid[y][x]._selected) {
alert("Invalid selection for merge.");
return true;
}
}
}
}
// Validate selection and get total rowspan and colspan
var rowSpan = 1, colSpan = 1;
// Validate horizontal and get total colspan
var lastRowSpan = -1;
for (var y=0; y<rows.length; y++) {
var rowColSpan = 0;
for (var x=0; x<rows[y].length; x++) {
var sd = getColRowSpan(rows[y][x]);
rowColSpan += sd['colspan'];
if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) {
alert("Invalid selection for merge.");
return true;
}
lastRowSpan = sd['rowspan'];
}
if (rowColSpan > colSpan)
colSpan = rowColSpan;
lastRowSpan = -1;
}
// Validate vertical and get total rowspan
var lastColSpan = -1;
for (var x=0; x<rows[0].length; x++) {
var colRowSpan = 0;
for (var y=0; y<rows.length; y++) {
var sd = getColRowSpan(rows[y][x]);
colRowSpan += sd['rowspan'];
if (lastColSpan != -1 && sd['colspan'] != lastColSpan) {
alert("Invalid selection for merge.");
return true;
}
lastColSpan = sd['colspan'];
}
if (colRowSpan > rowSpan)
rowSpan = colRowSpan;
lastColSpan = -1;
}
// Setup td
tdElm = rows[0][0];
tdElm.rowSpan = rowSpan;
tdElm.colSpan = colSpan;
// Merge cells
for (var y=0; y<rows.length; y++) {
for (var x=0; x<rows[y].length; x++) {
var html = rows[y][x].innerHTML;
var chk = html.replace(/[ \t\r\n]/g, "");
if (chk != "<br/>" && chk != "<br>" && chk != '<br mce_bogus="1"/>' && (x+y > 0))
tdElm.innerHTML += html;
// Not current cell
if (rows[y][x] != tdElm && !rows[y][x]._deleted) {
var cpos = getCellPos(grid, rows[y][x]);
var tr = rows[y][x].parentNode;
tr.removeChild(rows[y][x]);
rows[y][x]._deleted = true;
// Empty TR, remove it
if (!tr.hasChildNodes()) {
tr.parentNode.removeChild(tr);
var lastCell = null;
for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) {
if (cellElm != lastCell && cellElm.rowSpan > 1)
cellElm.rowSpan--;
lastCell = cellElm;
}
if (tdElm.rowSpan > 1)
tdElm.rowSpan--;
}
}
}
}
// Remove all but one bogus br
each(ed.dom.select('br', tdElm), function(e, i) {
if (i > 0 && ed.dom.getAttrib(e, 'mce_bogus'))
ed.dom.remove(e);
});
break;
}
tableElm = inst.dom.getParent(inst.selection.getNode(), "table");
inst.addVisual(tableElm);
inst.nodeChanged();
}
return true;
}
// Pass to next handler in chain
return false;
}
});
// Register plugin
tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
})();