MDL-44758 editor-atto: prevent table-in-table creation

Prevent new table creation, displaying table context menu instead when cursor is within caption, when multiple cells are selected, when selection contains both nodes within and outside of the table, and when selection contains nodes from multiple tables.
This commit is contained in:
Jetha Chan 2014-04-15 11:34:21 +08:00
parent ca4554402d
commit f0ddce4df1
4 changed files with 156 additions and 51 deletions

View file

@ -179,30 +179,27 @@ Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.Edi
* @private * @private
*/ */
_displayTableEditor: function(e) { _displayTableEditor: function(e) {
var selection = this.get('host').getSelectionParentNode(), var cell = this._getSuitableTableCell();
cell;
if (!selection) {
// We don't have a current selection at all, so show the standard dialogue.
return this._displayDialogue(e);
}
// Check all of the table cells found in the selection.
Y.one(selection).ancestors('th, td', true).each(function(node) {
if (this.editor.contains(node)) {
cell = node;
}
}, this);
if (cell) { if (cell) {
// Add the cell to the EventFacade to save duplication in when showing the menu. // Add the cell to the EventFacade to save duplication in when showing the menu.
e.tableCell = cell; e.tableCell = cell;
return this._showTableMenu(e); return this._showTableMenu(e);
} }
return this._displayDialogue(e); return this._displayDialogue(e);
}, },
/**
* Returns whether or not the parameter node exists within the editor.
*
* @method _stopAtContentEditableFilter
* @param {Node} node
* @private
* @return {boolean} whether or not the parameter node exists within the editor.
*/
_stopAtContentEditableFilter: function(node) {
this.editor.contains(node);
},
/** /**
* Return the edit table dialogue content, attaching any required * Return the edit table dialogue content, attaching any required
* events. * events.
@ -247,6 +244,44 @@ Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return this._content; return this._content;
}, },
/**
* Given the current selection, return a table cell suitable for table editing
* purposes, i.e. the first table cell selected, or the first cell in the table
* that the selection exists in, or null if not within a table.
*
* @method _getSuitableTableCell
* @private
* @return {Node} suitable target cell, or null if not within a table
*/
_getSuitableTableCell: function() {
var targetcell = null,
host = this.get('host');
host.getSelectedNodes().some(function (node) {
if (node.ancestor('td, th, caption', true, this._stopAtContentEditableFilter)) {
targetcell = node;
var caption = node.ancestor('caption', true, this._stopAtContentEditableFilter);
if (caption) {
var table = caption.get('parentNode');
if (table) {
targetcell = table.one('td, th');
}
}
// Once we've found a cell to target, we shouldn't need to keep looking.
return true;
}
});
if (targetcell) {
var selection = host.getSelectionFromNode(targetcell);
host.setSelection(selection);
}
return targetcell;
},
/** /**
* Change a node from one type to another, copying all attributes and children. * Change a node from one type to another, copying all attributes and children.
* *

File diff suppressed because one or more lines are too long

View file

@ -179,30 +179,27 @@ Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.Edi
* @private * @private
*/ */
_displayTableEditor: function(e) { _displayTableEditor: function(e) {
var selection = this.get('host').getSelectionParentNode(), var cell = this._getSuitableTableCell();
cell;
if (!selection) {
// We don't have a current selection at all, so show the standard dialogue.
return this._displayDialogue(e);
}
// Check all of the table cells found in the selection.
Y.one(selection).ancestors('th, td', true).each(function(node) {
if (this.editor.contains(node)) {
cell = node;
}
}, this);
if (cell) { if (cell) {
// Add the cell to the EventFacade to save duplication in when showing the menu. // Add the cell to the EventFacade to save duplication in when showing the menu.
e.tableCell = cell; e.tableCell = cell;
return this._showTableMenu(e); return this._showTableMenu(e);
} }
return this._displayDialogue(e); return this._displayDialogue(e);
}, },
/**
* Returns whether or not the parameter node exists within the editor.
*
* @method _stopAtContentEditableFilter
* @param {Node} node
* @private
* @return {boolean} whether or not the parameter node exists within the editor.
*/
_stopAtContentEditableFilter: function(node) {
this.editor.contains(node);
},
/** /**
* Return the edit table dialogue content, attaching any required * Return the edit table dialogue content, attaching any required
* events. * events.
@ -247,6 +244,44 @@ Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return this._content; return this._content;
}, },
/**
* Given the current selection, return a table cell suitable for table editing
* purposes, i.e. the first table cell selected, or the first cell in the table
* that the selection exists in, or null if not within a table.
*
* @method _getSuitableTableCell
* @private
* @return {Node} suitable target cell, or null if not within a table
*/
_getSuitableTableCell: function() {
var targetcell = null,
host = this.get('host');
host.getSelectedNodes().some(function (node) {
if (node.ancestor('td, th, caption', true, this._stopAtContentEditableFilter)) {
targetcell = node;
var caption = node.ancestor('caption', true, this._stopAtContentEditableFilter);
if (caption) {
var table = caption.get('parentNode');
if (table) {
targetcell = table.one('td, th');
}
}
// Once we've found a cell to target, we shouldn't need to keep looking.
return true;
}
});
if (targetcell) {
var selection = host.getSelectionFromNode(targetcell);
host.setSelection(selection);
}
return targetcell;
},
/** /**
* Change a node from one type to another, copying all attributes and children. * Change a node from one type to another, copying all attributes and children.
* *

View file

@ -177,30 +177,27 @@ Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.Edi
* @private * @private
*/ */
_displayTableEditor: function(e) { _displayTableEditor: function(e) {
var selection = this.get('host').getSelectionParentNode(), var cell = this._getSuitableTableCell();
cell;
if (!selection) {
// We don't have a current selection at all, so show the standard dialogue.
return this._displayDialogue(e);
}
// Check all of the table cells found in the selection.
Y.one(selection).ancestors('th, td', true).each(function(node) {
if (this.editor.contains(node)) {
cell = node;
}
}, this);
if (cell) { if (cell) {
// Add the cell to the EventFacade to save duplication in when showing the menu. // Add the cell to the EventFacade to save duplication in when showing the menu.
e.tableCell = cell; e.tableCell = cell;
return this._showTableMenu(e); return this._showTableMenu(e);
} }
return this._displayDialogue(e); return this._displayDialogue(e);
}, },
/**
* Returns whether or not the parameter node exists within the editor.
*
* @method _stopAtContentEditableFilter
* @param {Node} node
* @private
* @return {boolean} whether or not the parameter node exists within the editor.
*/
_stopAtContentEditableFilter: function(node) {
this.editor.contains(node);
},
/** /**
* Return the edit table dialogue content, attaching any required * Return the edit table dialogue content, attaching any required
* events. * events.
@ -245,6 +242,44 @@ Y.namespace('M.atto_table').Button = Y.Base.create('button', Y.M.editor_atto.Edi
return this._content; return this._content;
}, },
/**
* Given the current selection, return a table cell suitable for table editing
* purposes, i.e. the first table cell selected, or the first cell in the table
* that the selection exists in, or null if not within a table.
*
* @method _getSuitableTableCell
* @private
* @return {Node} suitable target cell, or null if not within a table
*/
_getSuitableTableCell: function() {
var targetcell = null,
host = this.get('host');
host.getSelectedNodes().some(function (node) {
if (node.ancestor('td, th, caption', true, this._stopAtContentEditableFilter)) {
targetcell = node;
var caption = node.ancestor('caption', true, this._stopAtContentEditableFilter);
if (caption) {
var table = caption.get('parentNode');
if (table) {
targetcell = table.one('td, th');
}
}
// Once we've found a cell to target, we shouldn't need to keep looking.
return true;
}
});
if (targetcell) {
var selection = host.getSelectionFromNode(targetcell);
host.setSelection(selection);
}
return targetcell;
},
/** /**
* Change a node from one type to another, copying all attributes and children. * Change a node from one type to another, copying all attributes and children.
* *