Finished implementation of menu-driven table selection. Implemented detection of row or column selection. r=mjudge

This commit is contained in:
cmanske%netscape.com 2000-03-21 06:05:24 +00:00
Родитель 89f6311468
Коммит e3ef5768c7
22 изменённых файлов: 1055 добавлений и 351 удалений

Просмотреть файл

@ -1857,7 +1857,6 @@ nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
{ {
nsCOMPtr<nsIDOMAttr> resultAttribute; nsCOMPtr<nsIDOMAttr> resultAttribute;
destElement->RemoveAttributeNode(destAttribute, getter_AddRefs(resultAttribute)); destElement->RemoveAttributeNode(destAttribute, getter_AddRefs(resultAttribute));
// Is the resultAttribute deleted automagically?
} }
} }
} }
@ -1881,7 +1880,7 @@ nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
// Do we ever get here? // Do we ever get here?
destElement->RemoveAttribute(sourceAttrName); destElement->RemoveAttribute(sourceAttrName);
#if DEBUG_cmanske #if DEBUG_cmanske
printf("Attribute in NamedNodeMap has empty value in nsEditor::CloneAttributes()\n"); printf("Attribute in sourceAttribute has empty value in nsEditor::CloneAttributes()\n");
#endif #endif
} }
} }
@ -5014,19 +5013,11 @@ nsEditor::GetFirstNodeInRange(nsIDOMRange *aRange, nsIDOMNode **aNode)
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!startParent) return NS_ERROR_FAILURE; if (!startParent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> startNode;
PRInt32 offset; PRInt32 offset;
res = aRange->GetStartOffset(&offset); res = aRange->GetStartOffset(&offset);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNodeList> nodeList; nsCOMPtr<nsIDOMNode> child = GetChildAt(startParent, offset);
res = startParent->GetChildNodes(getter_AddRefs(nodeList));
if (NS_FAILED(res)) return res;
if (!nodeList) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> child;
res = nodeList->Item(offset,getter_AddRefs(child));
if (NS_FAILED(res)) return res;
if (!child) return NS_ERROR_FAILURE; if (!child) return NS_ERROR_FAILURE;
*aNode = child.get(); *aNode = child.get();

Просмотреть файл

@ -2847,6 +2847,59 @@ nsEditorShell::GetSelectedElement(const PRUnichar *aInTagName, nsIDOMElement **a
return result; return result;
} }
NS_IMETHODIMP
nsEditorShell::GetFirstSelectedCell(nsIDOMElement **aOutElement)
{
if (!aOutElement)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE;
switch (mEditorType)
{
case eHTMLTextEditorType:
{
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
if (tableEditor)
result = tableEditor->GetFirstSelectedCell(aOutElement);
break;
}
case ePlainTextEditorType:
default:
result = NS_ERROR_NOT_IMPLEMENTED;
}
return result;
}
NS_IMETHODIMP
nsEditorShell::GetNextSelectedCell(nsIDOMElement **aOutElement)
{
if (!aOutElement)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE;
switch (mEditorType)
{
case eHTMLTextEditorType:
{
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
if (tableEditor)
result = tableEditor->GetNextSelectedCell(aOutElement);
break;
}
case ePlainTextEditorType:
default:
result = NS_ERROR_NOT_IMPLEMENTED;
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditorShell::GetElementOrParentByTagName(const PRUnichar *aInTagName, nsIDOMNode *node, nsIDOMElement **aOutElement) nsEditorShell::GetElementOrParentByTagName(const PRUnichar *aInTagName, nsIDOMNode *node, nsIDOMElement **aOutElement)
{ {
@ -3537,9 +3590,9 @@ nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRBool *aIsSelected, nsIDOMElement **_retval) nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRInt32 *aSelectedCount, nsIDOMElement **_retval)
{ {
if (!_retval || !aTagName || !aIsSelected) if (!_retval || !aTagName || !aSelectedCount)
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE; nsresult result = NS_NOINTERFACE;
@ -3550,7 +3603,7 @@ nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRBool *aIs
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
nsAutoString TagName(*aTagName); nsAutoString TagName(*aTagName);
if (tableEditor) if (tableEditor)
result = tableEditor->GetSelectedOrParentTableElement(*_retval, TagName, *aIsSelected); result = tableEditor->GetSelectedOrParentTableElement(*_retval, TagName, *aSelectedCount);
*aTagName = TagName.ToNewUnicode(); *aTagName = TagName.ToNewUnicode();
} }
break; break;
@ -3560,6 +3613,28 @@ nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRBool *aIs
return result; return result;
} }
NS_IMETHODIMP
nsEditorShell::GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 *_retval)
{
if (!_retval)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE;
switch (mEditorType)
{
case eHTMLTextEditorType:
{
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
if (tableEditor)
result = tableEditor->GetSelectedCellsType(aElement, *_retval);
}
break;
default:
result = NS_ERROR_NOT_IMPLEMENTED;
}
return result;
}
/* end of table editing */ /* end of table editing */
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -224,7 +224,22 @@ nsHTMLEditUtils::IsListItem(nsIDOMNode *node)
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// IsTableCell: true if node an html td or th // IsTable: true if node an html table
//
PRBool
nsHTMLEditUtils::IsTable(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditor::IsTable");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
if (tag == "table")
return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsTableRow: true if node an html tr
// //
PRBool PRBool
nsHTMLEditUtils::IsTableRow(nsIDOMNode *node) nsHTMLEditUtils::IsTableRow(nsIDOMNode *node)

Просмотреть файл

@ -44,6 +44,7 @@ public:
static PRBool IsHeader(nsIDOMNode *aNode); static PRBool IsHeader(nsIDOMNode *aNode);
static PRBool IsParagraph(nsIDOMNode *aNode); static PRBool IsParagraph(nsIDOMNode *aNode);
static PRBool IsListItem(nsIDOMNode *aNode); static PRBool IsListItem(nsIDOMNode *aNode);
static PRBool IsTable(nsIDOMNode *aNode);
static PRBool IsTableRow(nsIDOMNode *aNode); static PRBool IsTableRow(nsIDOMNode *aNode);
static PRBool IsTableCell(nsIDOMNode *aNode); static PRBool IsTableCell(nsIDOMNode *aNode);
static PRBool IsList(nsIDOMNode *aNode); static PRBool IsList(nsIDOMNode *aNode);

Просмотреть файл

@ -40,8 +40,8 @@
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIDOMHTMLAnchorElement.h" #include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMHTMLImageElement.h" #include "nsIDOMHTMLImageElement.h"
#include "nsISelectionController.h" #include "nsISelectionController.h"
#include "nsIFrameSelection.h" // For TABLESELECTION_ defines
#include "nsICSSLoader.h" #include "nsICSSLoader.h"
#include "nsICSSStyleSheet.h" #include "nsICSSStyleSheet.h"
@ -196,11 +196,10 @@ static PRBool IsCellNode(nsIDOMNode *aNode)
nsAutoString tagName; nsAutoString tagName;
if (NS_SUCCEEDED(element->GetTagName(tagName))) if (NS_SUCCEEDED(element->GetTagName(tagName)))
{ {
tagName.ToLowerCase(); // With only 2 tests, it doesn't
// With only 3 tests, it doesn't
// seem worth using nsAtoms // seem worth using nsAtoms
if (tagName.Equals("td") || if (tagName.EqualsIgnoreCase("td") ||
tagName.Equals("th")) tagName.EqualsIgnoreCase("th"))
{ {
return PR_TRUE; return PR_TRUE;
} }
@ -217,7 +216,7 @@ nsHTMLEditor::nsHTMLEditor()
, mRules(nsnull) , mRules(nsnull)
, mIsComposing(PR_FALSE) , mIsComposing(PR_FALSE)
, mMaxTextLength(-1) , mMaxTextLength(-1)
, mSelectingTableCells(PR_FALSE) , mSelectedCellIndex(0)
{ {
// Done in nsEditor // Done in nsEditor
// NS_INIT_REFCNT(); // NS_INIT_REFCNT();
@ -2620,11 +2619,10 @@ nsHTMLEditor::GetElementOrParentByTagName(const nsString &aTagName, nsIDOMNode *
res = selection->GetAnchorOffset(&offset); res = selection->GetAnchorOffset(&offset);
if(NS_FAILED(res)) return res; if(NS_FAILED(res)) return res;
currentNode = nsEditor::GetChildAt(anchorNode, offset); currentNode = nsEditor::GetChildAt(anchorNode, offset);
if (!currentNode) return NS_ERROR_FAILURE;
} else {
// anchor node is probably a text node - just use that
currentNode = anchorNode;
} }
// anchor node is probably a text node - just use that
if (!currentNode)
currentNode = anchorNode;
} }
nsAutoString TagName = aTagName; nsAutoString TagName = aTagName;
@ -3053,14 +3051,30 @@ nsHTMLEditor::SetBackgroundColor(const nsString& aColor)
NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document"); NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document");
// Find a selected or enclosing table element to set background on // Find a selected or enclosing table element to set background on
// TODO: Handle case of > 1 table cell or row selected
nsCOMPtr<nsIDOMElement> element; nsCOMPtr<nsIDOMElement> element;
PRBool isSelected; PRInt32 selectedCount;
nsAutoString tagName; nsAutoString tagName;
nsresult res = GetSelectedOrParentTableElement(*getter_AddRefs(element), tagName, isSelected); nsresult res = GetSelectedOrParentTableElement(*getter_AddRefs(element), tagName, selectedCount);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!element) if (element)
{ {
if (selectedCount > 0)
{
// Traverse all selected cells
nsCOMPtr<nsIDOMElement> cell;
res = GetFirstSelectedCell(getter_AddRefs(cell));
if (NS_SUCCEEDED(res) && cell)
{
while(cell)
{
SetAttribute(cell, "bgcolor", aColor);
GetNextSelectedCell(getter_AddRefs(cell));
};
return NS_OK;
}
}
// If we failed to find a cell, fall through to use originally-found element
} else {
// No table element -- set the background color on the body tag // No table element -- set the background color on the body tag
res = nsEditor::GetBodyElement(getter_AddRefs(element)); res = nsEditor::GetBodyElement(getter_AddRefs(element));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
@ -5826,7 +5840,7 @@ nsHTMLEditor::IsTableCell(nsIDOMNode *node)
NS_PRECONDITION(node, "null node passed to nsHTMLEditor::IsTableCell"); NS_PRECONDITION(node, "null node passed to nsHTMLEditor::IsTableCell");
nsAutoString tag; nsAutoString tag;
nsEditor::GetTagString(node,tag); nsEditor::GetTagString(node,tag);
if (tag == "td") if (tag == "td" || tag == "th")
{ {
return PR_TRUE; return PR_TRUE;
} }
@ -7844,4 +7858,3 @@ nsHTMLEditor::InsertContainerAbove(nsIDOMNode *inNode,
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -203,7 +203,15 @@ public:
NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow);
NS_IMETHOD GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); NS_IMETHOD GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow);
NS_IMETHOD SetCaretAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol, PRInt32 aDirection); NS_IMETHOD SetCaretAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol, PRInt32 aDirection);
NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRBool &aIsSelected); NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount);
NS_IMETHOD GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 &aSelectionType);
// Finds the first selected cell in first range of selection
// This is in the *order of selection*, not order in the table
// (i.e., each cell added to selection is added in another range
// in the selection's rangelist, independent of location in table)
NS_IMETHOD GetFirstSelectedCell(nsIDOMElement **aCell);
// Get next cell until no more are found. Always use GetFirstSelected cell first
NS_IMETHOD GetNextSelectedCell(nsIDOMElement **aCell);
// Selection and navigation // Selection and navigation
@ -348,6 +356,9 @@ protected:
// Needed to do appropriate deleting when last cell or row is about to be deleted // Needed to do appropriate deleting when last cell or row is about to be deleted
// This doesn't count cells that don't start in the given row (are spanning from row above) // This doesn't count cells that don't start in the given row (are spanning from row above)
PRInt32 GetNumberOfCellsInRow(nsIDOMElement* aTable, PRInt32 rowIndex); PRInt32 GetNumberOfCellsInRow(nsIDOMElement* aTable, PRInt32 rowIndex);
// Test if all cells in row or column at given index are selected
PRBool AllCellsInRowSelected(nsIDOMElement *aTable, PRInt32 aRowIndex, PRInt32 aNumberOfColumns);
PRBool AllCellsInColumnSelected(nsIDOMElement *aTable, PRInt32 aColIndex, PRInt32 aNumberOfRows);
// Most insert methods need to get the same basic context data // Most insert methods need to get the same basic context data
NS_IMETHOD GetCellContext(nsCOMPtr<nsIDOMSelection> &aSelection, NS_IMETHOD GetCellContext(nsCOMPtr<nsIDOMSelection> &aSelection,
@ -355,17 +366,13 @@ protected:
nsCOMPtr<nsIDOMNode> &aCellParent, PRInt32& aCellOffset, nsCOMPtr<nsIDOMNode> &aCellParent, PRInt32& aCellOffset,
PRInt32& aRow, PRInt32& aCol); PRInt32& aRow, PRInt32& aCol);
// Finds the first selected cell in first range of selection
// This is in the *order of selection*, not order in the table
// (i.e., each cell added to selection is added in another range
// in the selection's rangelist, independent of location in table)
NS_IMETHOD GetFirstSelectedCell(nsIDOMElement **aCell);
// Fallback method: Call this after using ClearSelection() and you // Fallback method: Call this after using ClearSelection() and you
// failed to set selection to some other content in the document // failed to set selection to some other content in the document
NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection); NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection);
// end of table editing utilities
// End of Table Editing utilities
NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode, NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode,
nsString &aParentTag, nsString &aParentTag,
@ -607,13 +614,8 @@ protected:
PRBool mCachedUnderlineStyle; PRBool mCachedUnderlineStyle;
nsString mCachedFontName; nsString mCachedFontName;
// True when selection consists of table cell(s) // Used by GetFirstSelectedCell and GetNextSelectedCell
PRBool mSelectingTableCells; PRInt32 mSelectedCellIndex;
// Used to monitor block of cells selected
// by dragging mouse across the table
nsCOMPtr<nsIDOMElement> mStartSelectedCell;
nsCOMPtr<nsIDOMElement> mCurrentSelectedCell;
public: public:
static nsIAtom *gTypingTxnName; static nsIAtom *gTypingTxnName;

Просмотреть файл

@ -40,6 +40,8 @@
#include "nsITableCellLayout.h" // For efficient access to table cell #include "nsITableCellLayout.h" // For efficient access to table cell
#include "nsITableLayout.h" // data owned by the table and cell frames #include "nsITableLayout.h" // data owned by the table and cell frames
#include "nsHTMLEditor.h" #include "nsHTMLEditor.h"
#include "nsIFrameSelection.h" // For TABLESELECTION_ defines
#include "nsVoidArray.h"
#include "nsEditorUtils.h" #include "nsEditorUtils.h"
@ -799,7 +801,7 @@ nsHTMLEditor::DeleteTableColumn(PRInt32 aNumber)
if (curCell) if (curCell)
{ {
// This must always be >= 1 // This must always be >= 1
NS_ASSERTION((actualRowSpan > 0),"Effective ROWSPAN = 0 in DeleteTableColumn"); NS_ASSERTION((actualRowSpan > 0),"Actual ROWSPAN = 0 in DeleteTableColumn");
// Find cells that don't start in column we are deleting // Find cells that don't start in column we are deleting
if (curStartColIndex < startColIndex || colSpan > 1 || colSpan == 0) if (curStartColIndex < startColIndex || colSpan > 1 || colSpan == 0)
@ -1643,13 +1645,9 @@ nsHTMLEditor::GetCellContext(nsCOMPtr<nsIDOMSelection> &aSelection,
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!aSelection) return NS_ERROR_FAILURE; if (!aSelection) return NS_ERROR_FAILURE;
// Find the first selected cell
// res = GetFirstSelectedCell(getter_AddRefs(aCell));
if (!aCell) if (!aCell)
{ {
//If a cell wasn't selected, then assume the selection is INSIDE // Get cell if it's the child of selection anchor node,
// and use anchor node to search up to the containing cell
// Test if selected node (from anchor node) is a cell
// or get the enclosing by a cell // or get the enclosing by a cell
res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(aCell)); res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(aCell));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
@ -1683,78 +1681,109 @@ nsHTMLEditor::GetFirstSelectedCell(nsIDOMElement **aCell)
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_FAILURE; if (!selection) return NS_ERROR_FAILURE;
//TODO: Replace this with code below new "table cell mode" flag is implemented
nsCOMPtr<nsIEnumerator> enumerator;
res = selection->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_FAILURE;
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if ((NS_SUCCEEDED(res)) && currentItem)
{
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
if (!iter) return NS_ERROR_FAILURE;
iter->Init(range);
// loop through the content iterator for each content node
nsCOMPtr<nsIContent> content;
while (NS_ENUMERATOR_FALSE == iter->IsDone())
{
res = iter->CurrentNode(getter_AddRefs(content));
// Not likely!
if (NS_FAILED(res)) return NS_ERROR_FAILURE;
nsCOMPtr<nsIAtom> atom;
content->GetTag(*getter_AddRefs(atom));
if (atom.get() == nsIEditProperty::td ||
atom.get() == nsIEditProperty::th )
{
// We found a cell
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(content);
if (cellElement)
{
*aCell = cellElement.get();
NS_ADDREF(*aCell);
}
return NS_OK;
}
iter->Next();
}
}
return NS_EDITOR_ELEMENT_NOT_FOUND;
#if 0
//TODO: Do this only after checking the new "table cell mode" flag
// The first cell is the starting node in the first selection range
nsCOMPtr<nsIDOMRange> firstRange; nsCOMPtr<nsIDOMRange> firstRange;
res = selection->GetRangeAt(0, getter_AddRefs(firstRange)); res = selection->GetRangeAt(0, getter_AddRefs(firstRange));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!firstRange) return NS_ERROR_FAILURE; if (!firstRange) return NS_ERROR_FAILURE;
#ifdef DEBUG_cmanske
{
nsCOMPtr<nsIDOMNode> anchorNode;
PRInt32 anchorOffset = -1;
selection->GetAnchorNode(getter_AddRefs(anchorNode));
selection->GetAnchorOffset(&anchorOffset);
nsCOMPtr<nsIDOMNode> focusNode;
res = selection->GetFocusNode(getter_AddRefs(focusNode));
if (NS_FAILED(res)) return res;
PRInt32 focusOffset = -1;
selection->GetFocusOffset(&focusOffset);
nsAutoString name;
anchorNode->GetNodeName(name);
printf("GetFirstSelectedCell: Anchor node of selection: ");
wprintf(name.GetUnicode());
printf(" Offset: %d\n", anchorOffset);
focusNode->GetNodeName(name);
printf("Focus node of selection: ");
wprintf(name.GetUnicode());
printf(" Offset: %x\n", focusOffset);
PRInt32 rangeCount;
res = selection->GetRangeCount(&rangeCount);
printf(" RangeCount: %d\n", rangeCount);
printf(" Range pointer = %d\n", firstRange);
}
#endif
// This is failing -- range doesn't match that set when selecting cell!
nsCOMPtr<nsIDOMNode> cellNode; nsCOMPtr<nsIDOMNode> cellNode;
res = GetFirstNodeInRange(firstRange, getter_AddRefs(cellNode)); res = GetFirstNodeInRange(firstRange, getter_AddRefs(cellNode));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!cellNode) return NS_ERROR_FAILURE; if (!cellNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(cellNode);
if (cellElement) if (IsTableCell(cellNode))
{ {
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(cellNode);
*aCell = cellElement.get(); *aCell = cellElement.get();
NS_ADDREF(*aCell); NS_ADDREF(*aCell);
} }
else res = NS_EDITOR_ELEMENT_NOT_FOUND; else
res = NS_EDITOR_ELEMENT_NOT_FOUND;
mSelectedCellIndex = 1;
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetNextSelectedCell(nsIDOMElement **aCell)
{
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
nsCOMPtr<nsIDOMSelection> selection;
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_FAILURE;
PRInt32 rangeCount;
res = selection->GetRangeCount(&rangeCount);
if (NS_FAILED(res)) return res;
// Don't even try if index exceeds range count
if (mSelectedCellIndex >= rangeCount)
{
// Should we reset index?
// Maybe better to force recalling GetFirstSelectedCell()
//mSelectedCellIndex = 0;
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
// Get first node in first range of selection - test if it's a cell
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(mSelectedCellIndex, getter_AddRefs(range));
if (NS_FAILED(res)) return res;
if (!range) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> cellNode;
res = nsEditor::GetFirstNodeInRange(range, getter_AddRefs(cellNode));
if (NS_FAILED(res)) return res;
if (!cellNode) return NS_ERROR_FAILURE;
if (IsTableCell(cellNode))
{
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(cellNode);
*aCell = cellElement.get();
NS_ADDREF(*aCell);
}
else
res = NS_EDITOR_ELEMENT_NOT_FOUND;
// Setup for next cell
mSelectedCellIndex++;
return res; return res;
#endif
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1842,11 +1871,11 @@ nsHTMLEditor::SetCaretAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt3
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRBool &aIsSelected) nsHTMLEditor::GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount)
{ {
aTableElement = nsnull; aTableElement = nsnull;
aTagName = ""; aTagName = "";
aIsSelected = PR_FALSE; aSelectedCount = 0;
nsCOMPtr<nsIDOMSelection> selection; nsCOMPtr<nsIDOMSelection> selection;
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection)); nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
@ -1858,52 +1887,218 @@ nsHTMLEditor::GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsS
nsAutoString tdName("td"); nsAutoString tdName("td");
nsCOMPtr<nsIDOMNode> anchorNode; nsCOMPtr<nsIDOMNode> anchorNode;
// Find the first selected cell
// TODO: Handle multiple cells selected!
nsCOMPtr<nsIDOMElement> firstCell;
nsCOMPtr<nsIDOMElement> tableElement;
res = GetFirstSelectedCell(getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res;
if (tableElement)
{
aTagName = tdName;
aIsSelected = PR_TRUE;
goto SET_RETURN_ELEMENT;
}
// See if table or row is selected
res = GetSelectedElement(tableName, getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res;
if (tableElement)
{
aTagName = tableName;
aIsSelected = PR_TRUE;
goto SET_RETURN_ELEMENT;
}
res = GetSelectedElement(trName, getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res;
if (tableElement)
{
aTagName = trName;
aIsSelected = PR_TRUE;
goto SET_RETURN_ELEMENT;
}
// Look for a table cell parent
res = selection->GetAnchorNode(getter_AddRefs(anchorNode)); res = selection->GetAnchorNode(getter_AddRefs(anchorNode));
if (NS_FAILED(res)) return res; if(NS_FAILED(res)) return res;
if (!anchorNode) return NS_ERROR_FAILURE; if (!anchorNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> tableElement;
nsCOMPtr<nsIDOMNode> selectedNode;
// Get child of anchor node, if exists
PRBool hasChildren;
anchorNode->HasChildNodes(&hasChildren);
if (hasChildren)
{
PRInt32 anchorOffset;
res = selection->GetAnchorOffset(&anchorOffset);
if (NS_FAILED(res)) return res;
selectedNode = nsEditor::GetChildAt(anchorNode, anchorOffset);
if (!selectedNode)
selectedNode = anchorNode;
nsAutoString tag;
nsEditor::GetTagString(selectedNode,tag);
if (tag == tdName)
{
tableElement = do_QueryInterface(anchorNode);
aTagName = tdName;
// Each cell is in its own selection range,
// so count signals multiple-cell selection
res = selection->GetRangeCount(&aSelectedCount);
if (NS_FAILED(res)) return res;
}
else if(tag == tableName)
{
tableElement = do_QueryInterface(anchorNode);
aTagName = tableName;
aSelectedCount = 1;
}
else if(tag == trName)
{
tableElement = do_QueryInterface(anchorNode);
aTagName = trName;
aSelectedCount = 1;
}
}
if (!tableElement)
{
// Didn't find a table element -- find a cell parent
res = GetElementOrParentByTagName(tdName, anchorNode, getter_AddRefs(tableElement)); res = GetElementOrParentByTagName(tdName, anchorNode, getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res; if(NS_FAILED(res)) return res;
if (tableElement) if (tableElement)
{
aTagName = tdName; aTagName = tdName;
SET_RETURN_ELEMENT: }
if (tableElement)
{
aTableElement = tableElement.get(); aTableElement = tableElement.get();
NS_ADDREF(aTableElement); NS_ADDREF(aTableElement);
} }
return res; return res;
} }
static PRBool IndexNotTested(nsVoidArray *aArray, PRInt32 aIndex)
{
if (aArray)
{
PRInt32 count = aArray->Count();
for (PRInt32 i = 0; i < count; i++)
{
if(aIndex == (PRInt32)(aArray->ElementAt(i)))
return PR_FALSE;
}
}
return PR_TRUE;
}
NS_IMETHODIMP
nsHTMLEditor::GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 &aSelectionType)
{
aSelectionType = 0;
// Be sure we have a table element
// (if aElement is null, this uses selection's anchor node)
nsCOMPtr<nsIDOMElement> table;
nsresult res = GetElementOrParentByTagName("table", aElement, getter_AddRefs(table));
if (NS_FAILED(res)) return res;
PRInt32 rowCount, colCount;
res = GetTableSize(table, rowCount, colCount);
if (NS_FAILED(res)) return res;
// Traverse all selected cells
// (Failure here may indicate that aCellElement wasn't really a cell)
nsCOMPtr<nsIDOMElement> selectedCell;
res = GetFirstSelectedCell(getter_AddRefs(selectedCell));
if (NS_FAILED(res)) return res;
// We have at least one selected cell, so set return value
aSelectionType = TABLESELECTION_CELL;
// Store indexes of each row/col to avoid duplication of searches
nsVoidArray indexArray;
PRBool allCellsInRowAreSelected = PR_TRUE;
PRBool allCellsInColAreSelected = PR_FALSE;
while (NS_SUCCEEDED(res) && selectedCell)
{
// Get the cell's location in the cellmap
PRInt32 startRowIndex, startColIndex;
res = GetCellIndexes(selectedCell, startRowIndex, startColIndex);
if(NS_FAILED(res)) return res;
if (IndexNotTested(&indexArray, startColIndex))
{
indexArray.AppendElement((void*)startColIndex);
allCellsInRowAreSelected = AllCellsInRowSelected(table, startRowIndex, colCount);
// We're done as soon as we fail for any row
if (!allCellsInRowAreSelected) break;
}
res = GetNextSelectedCell(getter_AddRefs(selectedCell));
}
if (allCellsInRowAreSelected)
{
aSelectionType = TABLESELECTION_ROW;
return NS_OK;
}
// Test for columns
// Empty the indexArray
indexArray.Clear();
// Start at first cell again
res = GetFirstSelectedCell(getter_AddRefs(selectedCell));
while (NS_SUCCEEDED(res) && selectedCell)
{
// Get the cell's location in the cellmap
PRInt32 startRowIndex, startColIndex;
res = GetCellIndexes(selectedCell, startRowIndex, startColIndex);
if(NS_FAILED(res)) return res;
if (IndexNotTested(&indexArray, startRowIndex))
{
indexArray.AppendElement((void*)startColIndex);
allCellsInColAreSelected = AllCellsInColumnSelected(table, startColIndex, colCount);
// We're done as soon as we fail for any column
if (!allCellsInRowAreSelected) break;
}
res = GetNextSelectedCell(getter_AddRefs(selectedCell));
}
if (allCellsInColAreSelected)
aSelectionType = TABLESELECTION_COLUMN;
return NS_OK;
}
PRBool
nsHTMLEditor::AllCellsInRowSelected(nsIDOMElement *aTable, PRInt32 aRowIndex, PRInt32 aNumberOfColumns)
{
if (!aTable) return PR_FALSE;
PRInt32 curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
PRBool isSelected;
for( PRInt32 col = 0; col < aNumberOfColumns; col += actualColSpan)
{
nsCOMPtr<nsIDOMElement> cell;
nsresult res = GetCellDataAt(aTable, aRowIndex, col, *getter_AddRefs(cell),
curStartRowIndex, curStartColIndex, rowSpan, colSpan,
actualRowSpan, actualColSpan, isSelected);
if (NS_FAILED(res)) return PR_FALSE;
// Skip cell spanning into this location from a row above
if (curStartRowIndex == aRowIndex)
{
// If no cell, we may have a "ragged" right edge,
// so return TRUE only if we already found a cell in the row
if (!cell) return (col > 0) ? PR_TRUE : PR_FALSE;
// Return as soon as a non-selected cell is found
if (!isSelected) return PR_FALSE;
}
NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in AllCellsInRowSelected");
}
return PR_TRUE;
}
PRBool
nsHTMLEditor::AllCellsInColumnSelected(nsIDOMElement *aTable, PRInt32 aColIndex, PRInt32 aNumberOfRows)
{
if (!aTable) return PR_FALSE;
PRInt32 curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
PRBool isSelected;
for( PRInt32 row = 0; row < aNumberOfRows; row += actualRowSpan)
{
nsCOMPtr<nsIDOMElement> cell;
nsresult res = GetCellDataAt(aTable, row, aColIndex, *getter_AddRefs(cell),
curStartRowIndex, curStartColIndex, rowSpan, colSpan,
actualRowSpan, actualColSpan, isSelected);
if (NS_FAILED(res)) return PR_FALSE;
// Skip cell spanning into this location from a column to the left
if (curStartColIndex == aColIndex)
{
// If no cell, we must have a "ragged" right edge on the last column
// so return TRUE only if we already found a cell in the row
if (!cell) return (row > 0) ? PR_TRUE : PR_FALSE;
// Return as soon as a non-selected cell is found
if (!isSelected) return PR_FALSE;
}
NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in AllCellsInColumnSelected");
}
return PR_TRUE;
}

Просмотреть файл

@ -2847,6 +2847,59 @@ nsEditorShell::GetSelectedElement(const PRUnichar *aInTagName, nsIDOMElement **a
return result; return result;
} }
NS_IMETHODIMP
nsEditorShell::GetFirstSelectedCell(nsIDOMElement **aOutElement)
{
if (!aOutElement)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE;
switch (mEditorType)
{
case eHTMLTextEditorType:
{
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
if (tableEditor)
result = tableEditor->GetFirstSelectedCell(aOutElement);
break;
}
case ePlainTextEditorType:
default:
result = NS_ERROR_NOT_IMPLEMENTED;
}
return result;
}
NS_IMETHODIMP
nsEditorShell::GetNextSelectedCell(nsIDOMElement **aOutElement)
{
if (!aOutElement)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE;
switch (mEditorType)
{
case eHTMLTextEditorType:
{
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
if (tableEditor)
result = tableEditor->GetNextSelectedCell(aOutElement);
break;
}
case ePlainTextEditorType:
default:
result = NS_ERROR_NOT_IMPLEMENTED;
}
return result;
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditorShell::GetElementOrParentByTagName(const PRUnichar *aInTagName, nsIDOMNode *node, nsIDOMElement **aOutElement) nsEditorShell::GetElementOrParentByTagName(const PRUnichar *aInTagName, nsIDOMNode *node, nsIDOMElement **aOutElement)
{ {
@ -3537,9 +3590,9 @@ nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRBool *aIsSelected, nsIDOMElement **_retval) nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRInt32 *aSelectedCount, nsIDOMElement **_retval)
{ {
if (!_retval || !aTagName || !aIsSelected) if (!_retval || !aTagName || !aSelectedCount)
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE; nsresult result = NS_NOINTERFACE;
@ -3550,7 +3603,7 @@ nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRBool *aIs
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
nsAutoString TagName(*aTagName); nsAutoString TagName(*aTagName);
if (tableEditor) if (tableEditor)
result = tableEditor->GetSelectedOrParentTableElement(*_retval, TagName, *aIsSelected); result = tableEditor->GetSelectedOrParentTableElement(*_retval, TagName, *aSelectedCount);
*aTagName = TagName.ToNewUnicode(); *aTagName = TagName.ToNewUnicode();
} }
break; break;
@ -3560,6 +3613,28 @@ nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRBool *aIs
return result; return result;
} }
NS_IMETHODIMP
nsEditorShell::GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 *_retval)
{
if (!_retval)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_NOINTERFACE;
switch (mEditorType)
{
case eHTMLTextEditorType:
{
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
if (tableEditor)
result = tableEditor->GetSelectedCellsType(aElement, *_retval);
}
break;
default:
result = NS_ERROR_NOT_IMPLEMENTED;
}
return result;
}
/* end of table editing */ /* end of table editing */
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -60,14 +60,6 @@ interface nsIEditorShell : nsISupports
eDisplayModeEdit, eDisplayModeEdit,
eDisplayModeBrowserPreview eDisplayModeBrowserPreview
}; };
enum {
eTable,
eTableRow,
eTableColumn,
eTableCell,
eTableCaption
};
%} %}
readonly attribute boolean documentModified; readonly attribute boolean documentModified;
readonly attribute boolean documentIsEmpty; readonly attribute boolean documentIsEmpty;
@ -201,6 +193,22 @@ interface nsIEditorShell : nsISupports
*/ */
nsIDOMElement GetSelectedElement(in wstring tagName); nsIDOMElement GetSelectedElement(in wstring tagName);
/** Get first selected node from first selection range.
* Assumes cell-selection model where each cell
* is in a separate range (selection parent node is table row)
* Returns null if ranges don't contain cell selections
*/
nsIDOMElement GetFirstSelectedCell();
/** Get next selected cell element from first selection range.
* Assumes cell-selection model where each cell
* is in a separate range (selection parent node is table row)
* Always call GetFirstSelectedCell() to initialize stored index of "next" cell
* Returns null if after last cell or
* ranges don't contain cell selections
*/
nsIDOMElement GetNextSelectedCell();
/** Return the input node or a parent matching the given aTagName, /** Return the input node or a parent matching the given aTagName,
* starting the search at the supplied node. * starting the search at the supplied node.
* An example of use is for testing if a node is in a table cell * An example of use is for testing if a node is in a table cell
@ -368,12 +376,34 @@ interface nsIEditorShell : nsISupports
* *
* Returns: * Returns:
* The table element (table, row, or cell) found * The table element (table, row, or cell) found
* If multiple table cells are selected, this is the "focus" cell (last cell selected)
*
* tagName The tagname of returned element * tagName The tagname of returned element
* Note that "td" will be returned if name is actually "th" * Note that "td" will be returned if name is actually "th"
* isSelected Tells if element returned is a selected element * selectedCount How many table elements were selected
* (false if element is a parent cell of selection) * This tells us if we have multiple cells selected
* (0 if element is a parent cell of selection)
*/ */
nsIDOMElement GetSelectedOrParentTableElement(out wstring tagName, out boolean isSelected); nsIDOMElement GetSelectedOrParentTableElement(out wstring tagName, out PRInt32 selectedCount);
/** Generally used after GetSelectedOrParentTableElement
* to test if selected cells are complete rows or columns
*
* cellElement Any table, cell, or element inside a table
* Used to get enclosing table.
* If null, selection's focusNode is used
*
* Returns: (defines are from nsIFrameSelection.h)
* 0 cellElement was not a cell
* 1 (TABLESELECTION_CELL) There are 1 or more cells selected
* but complete rows or columns are not selected
* 2 (TABLESELECTION_ROW) All cells are in 1 or more rows
* and in each row, all cells selected
* Note: This is the value if all rows (thus all cells) are selected
* 3 (TABLESELECTION_COLUMN) All cells are in 1 or more columns
* and in each column, all cells are selected
*/
PRUint32 GetSelectedCellsType(in nsIDOMElement element);
/**** end of table editing *****/ /**** end of table editing *****/

Просмотреть файл

@ -1857,7 +1857,6 @@ nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
{ {
nsCOMPtr<nsIDOMAttr> resultAttribute; nsCOMPtr<nsIDOMAttr> resultAttribute;
destElement->RemoveAttributeNode(destAttribute, getter_AddRefs(resultAttribute)); destElement->RemoveAttributeNode(destAttribute, getter_AddRefs(resultAttribute));
// Is the resultAttribute deleted automagically?
} }
} }
} }
@ -1881,7 +1880,7 @@ nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
// Do we ever get here? // Do we ever get here?
destElement->RemoveAttribute(sourceAttrName); destElement->RemoveAttribute(sourceAttrName);
#if DEBUG_cmanske #if DEBUG_cmanske
printf("Attribute in NamedNodeMap has empty value in nsEditor::CloneAttributes()\n"); printf("Attribute in sourceAttribute has empty value in nsEditor::CloneAttributes()\n");
#endif #endif
} }
} }
@ -5014,19 +5013,11 @@ nsEditor::GetFirstNodeInRange(nsIDOMRange *aRange, nsIDOMNode **aNode)
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!startParent) return NS_ERROR_FAILURE; if (!startParent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> startNode;
PRInt32 offset; PRInt32 offset;
res = aRange->GetStartOffset(&offset); res = aRange->GetStartOffset(&offset);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNodeList> nodeList; nsCOMPtr<nsIDOMNode> child = GetChildAt(startParent, offset);
res = startParent->GetChildNodes(getter_AddRefs(nodeList));
if (NS_FAILED(res)) return res;
if (!nodeList) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> child;
res = nodeList->Item(offset,getter_AddRefs(child));
if (NS_FAILED(res)) return res;
if (!child) return NS_ERROR_FAILURE; if (!child) return NS_ERROR_FAILURE;
*aNode = child.get(); *aNode = child.get();

Просмотреть файл

@ -224,7 +224,22 @@ nsHTMLEditUtils::IsListItem(nsIDOMNode *node)
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// IsTableCell: true if node an html td or th // IsTable: true if node an html table
//
PRBool
nsHTMLEditUtils::IsTable(nsIDOMNode *node)
{
NS_PRECONDITION(node, "null node passed to nsHTMLEditor::IsTable");
nsAutoString tag;
nsEditor::GetTagString(node,tag);
if (tag == "table")
return PR_TRUE;
return PR_FALSE;
}
///////////////////////////////////////////////////////////////////////////
// IsTableRow: true if node an html tr
// //
PRBool PRBool
nsHTMLEditUtils::IsTableRow(nsIDOMNode *node) nsHTMLEditUtils::IsTableRow(nsIDOMNode *node)

Просмотреть файл

@ -44,6 +44,7 @@ public:
static PRBool IsHeader(nsIDOMNode *aNode); static PRBool IsHeader(nsIDOMNode *aNode);
static PRBool IsParagraph(nsIDOMNode *aNode); static PRBool IsParagraph(nsIDOMNode *aNode);
static PRBool IsListItem(nsIDOMNode *aNode); static PRBool IsListItem(nsIDOMNode *aNode);
static PRBool IsTable(nsIDOMNode *aNode);
static PRBool IsTableRow(nsIDOMNode *aNode); static PRBool IsTableRow(nsIDOMNode *aNode);
static PRBool IsTableCell(nsIDOMNode *aNode); static PRBool IsTableCell(nsIDOMNode *aNode);
static PRBool IsList(nsIDOMNode *aNode); static PRBool IsList(nsIDOMNode *aNode);

Просмотреть файл

@ -40,8 +40,8 @@
#include "nsIDOMSelection.h" #include "nsIDOMSelection.h"
#include "nsIDOMHTMLAnchorElement.h" #include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMHTMLImageElement.h" #include "nsIDOMHTMLImageElement.h"
#include "nsISelectionController.h" #include "nsISelectionController.h"
#include "nsIFrameSelection.h" // For TABLESELECTION_ defines
#include "nsICSSLoader.h" #include "nsICSSLoader.h"
#include "nsICSSStyleSheet.h" #include "nsICSSStyleSheet.h"
@ -196,11 +196,10 @@ static PRBool IsCellNode(nsIDOMNode *aNode)
nsAutoString tagName; nsAutoString tagName;
if (NS_SUCCEEDED(element->GetTagName(tagName))) if (NS_SUCCEEDED(element->GetTagName(tagName)))
{ {
tagName.ToLowerCase(); // With only 2 tests, it doesn't
// With only 3 tests, it doesn't
// seem worth using nsAtoms // seem worth using nsAtoms
if (tagName.Equals("td") || if (tagName.EqualsIgnoreCase("td") ||
tagName.Equals("th")) tagName.EqualsIgnoreCase("th"))
{ {
return PR_TRUE; return PR_TRUE;
} }
@ -217,7 +216,7 @@ nsHTMLEditor::nsHTMLEditor()
, mRules(nsnull) , mRules(nsnull)
, mIsComposing(PR_FALSE) , mIsComposing(PR_FALSE)
, mMaxTextLength(-1) , mMaxTextLength(-1)
, mSelectingTableCells(PR_FALSE) , mSelectedCellIndex(0)
{ {
// Done in nsEditor // Done in nsEditor
// NS_INIT_REFCNT(); // NS_INIT_REFCNT();
@ -2620,11 +2619,10 @@ nsHTMLEditor::GetElementOrParentByTagName(const nsString &aTagName, nsIDOMNode *
res = selection->GetAnchorOffset(&offset); res = selection->GetAnchorOffset(&offset);
if(NS_FAILED(res)) return res; if(NS_FAILED(res)) return res;
currentNode = nsEditor::GetChildAt(anchorNode, offset); currentNode = nsEditor::GetChildAt(anchorNode, offset);
if (!currentNode) return NS_ERROR_FAILURE;
} else {
// anchor node is probably a text node - just use that
currentNode = anchorNode;
} }
// anchor node is probably a text node - just use that
if (!currentNode)
currentNode = anchorNode;
} }
nsAutoString TagName = aTagName; nsAutoString TagName = aTagName;
@ -3053,14 +3051,30 @@ nsHTMLEditor::SetBackgroundColor(const nsString& aColor)
NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document"); NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document");
// Find a selected or enclosing table element to set background on // Find a selected or enclosing table element to set background on
// TODO: Handle case of > 1 table cell or row selected
nsCOMPtr<nsIDOMElement> element; nsCOMPtr<nsIDOMElement> element;
PRBool isSelected; PRInt32 selectedCount;
nsAutoString tagName; nsAutoString tagName;
nsresult res = GetSelectedOrParentTableElement(*getter_AddRefs(element), tagName, isSelected); nsresult res = GetSelectedOrParentTableElement(*getter_AddRefs(element), tagName, selectedCount);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!element) if (element)
{ {
if (selectedCount > 0)
{
// Traverse all selected cells
nsCOMPtr<nsIDOMElement> cell;
res = GetFirstSelectedCell(getter_AddRefs(cell));
if (NS_SUCCEEDED(res) && cell)
{
while(cell)
{
SetAttribute(cell, "bgcolor", aColor);
GetNextSelectedCell(getter_AddRefs(cell));
};
return NS_OK;
}
}
// If we failed to find a cell, fall through to use originally-found element
} else {
// No table element -- set the background color on the body tag // No table element -- set the background color on the body tag
res = nsEditor::GetBodyElement(getter_AddRefs(element)); res = nsEditor::GetBodyElement(getter_AddRefs(element));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
@ -5826,7 +5840,7 @@ nsHTMLEditor::IsTableCell(nsIDOMNode *node)
NS_PRECONDITION(node, "null node passed to nsHTMLEditor::IsTableCell"); NS_PRECONDITION(node, "null node passed to nsHTMLEditor::IsTableCell");
nsAutoString tag; nsAutoString tag;
nsEditor::GetTagString(node,tag); nsEditor::GetTagString(node,tag);
if (tag == "td") if (tag == "td" || tag == "th")
{ {
return PR_TRUE; return PR_TRUE;
} }
@ -7844,4 +7858,3 @@ nsHTMLEditor::InsertContainerAbove(nsIDOMNode *inNode,
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -203,7 +203,15 @@ public:
NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow);
NS_IMETHOD GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); NS_IMETHOD GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow);
NS_IMETHOD SetCaretAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol, PRInt32 aDirection); NS_IMETHOD SetCaretAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol, PRInt32 aDirection);
NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRBool &aIsSelected); NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount);
NS_IMETHOD GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 &aSelectionType);
// Finds the first selected cell in first range of selection
// This is in the *order of selection*, not order in the table
// (i.e., each cell added to selection is added in another range
// in the selection's rangelist, independent of location in table)
NS_IMETHOD GetFirstSelectedCell(nsIDOMElement **aCell);
// Get next cell until no more are found. Always use GetFirstSelected cell first
NS_IMETHOD GetNextSelectedCell(nsIDOMElement **aCell);
// Selection and navigation // Selection and navigation
@ -348,6 +356,9 @@ protected:
// Needed to do appropriate deleting when last cell or row is about to be deleted // Needed to do appropriate deleting when last cell or row is about to be deleted
// This doesn't count cells that don't start in the given row (are spanning from row above) // This doesn't count cells that don't start in the given row (are spanning from row above)
PRInt32 GetNumberOfCellsInRow(nsIDOMElement* aTable, PRInt32 rowIndex); PRInt32 GetNumberOfCellsInRow(nsIDOMElement* aTable, PRInt32 rowIndex);
// Test if all cells in row or column at given index are selected
PRBool AllCellsInRowSelected(nsIDOMElement *aTable, PRInt32 aRowIndex, PRInt32 aNumberOfColumns);
PRBool AllCellsInColumnSelected(nsIDOMElement *aTable, PRInt32 aColIndex, PRInt32 aNumberOfRows);
// Most insert methods need to get the same basic context data // Most insert methods need to get the same basic context data
NS_IMETHOD GetCellContext(nsCOMPtr<nsIDOMSelection> &aSelection, NS_IMETHOD GetCellContext(nsCOMPtr<nsIDOMSelection> &aSelection,
@ -355,17 +366,13 @@ protected:
nsCOMPtr<nsIDOMNode> &aCellParent, PRInt32& aCellOffset, nsCOMPtr<nsIDOMNode> &aCellParent, PRInt32& aCellOffset,
PRInt32& aRow, PRInt32& aCol); PRInt32& aRow, PRInt32& aCol);
// Finds the first selected cell in first range of selection
// This is in the *order of selection*, not order in the table
// (i.e., each cell added to selection is added in another range
// in the selection's rangelist, independent of location in table)
NS_IMETHOD GetFirstSelectedCell(nsIDOMElement **aCell);
// Fallback method: Call this after using ClearSelection() and you // Fallback method: Call this after using ClearSelection() and you
// failed to set selection to some other content in the document // failed to set selection to some other content in the document
NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection); NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection);
// end of table editing utilities
// End of Table Editing utilities
NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode, NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode,
nsString &aParentTag, nsString &aParentTag,
@ -607,13 +614,8 @@ protected:
PRBool mCachedUnderlineStyle; PRBool mCachedUnderlineStyle;
nsString mCachedFontName; nsString mCachedFontName;
// True when selection consists of table cell(s) // Used by GetFirstSelectedCell and GetNextSelectedCell
PRBool mSelectingTableCells; PRInt32 mSelectedCellIndex;
// Used to monitor block of cells selected
// by dragging mouse across the table
nsCOMPtr<nsIDOMElement> mStartSelectedCell;
nsCOMPtr<nsIDOMElement> mCurrentSelectedCell;
public: public:
static nsIAtom *gTypingTxnName; static nsIAtom *gTypingTxnName;

Просмотреть файл

@ -40,6 +40,8 @@
#include "nsITableCellLayout.h" // For efficient access to table cell #include "nsITableCellLayout.h" // For efficient access to table cell
#include "nsITableLayout.h" // data owned by the table and cell frames #include "nsITableLayout.h" // data owned by the table and cell frames
#include "nsHTMLEditor.h" #include "nsHTMLEditor.h"
#include "nsIFrameSelection.h" // For TABLESELECTION_ defines
#include "nsVoidArray.h"
#include "nsEditorUtils.h" #include "nsEditorUtils.h"
@ -799,7 +801,7 @@ nsHTMLEditor::DeleteTableColumn(PRInt32 aNumber)
if (curCell) if (curCell)
{ {
// This must always be >= 1 // This must always be >= 1
NS_ASSERTION((actualRowSpan > 0),"Effective ROWSPAN = 0 in DeleteTableColumn"); NS_ASSERTION((actualRowSpan > 0),"Actual ROWSPAN = 0 in DeleteTableColumn");
// Find cells that don't start in column we are deleting // Find cells that don't start in column we are deleting
if (curStartColIndex < startColIndex || colSpan > 1 || colSpan == 0) if (curStartColIndex < startColIndex || colSpan > 1 || colSpan == 0)
@ -1643,13 +1645,9 @@ nsHTMLEditor::GetCellContext(nsCOMPtr<nsIDOMSelection> &aSelection,
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!aSelection) return NS_ERROR_FAILURE; if (!aSelection) return NS_ERROR_FAILURE;
// Find the first selected cell
// res = GetFirstSelectedCell(getter_AddRefs(aCell));
if (!aCell) if (!aCell)
{ {
//If a cell wasn't selected, then assume the selection is INSIDE // Get cell if it's the child of selection anchor node,
// and use anchor node to search up to the containing cell
// Test if selected node (from anchor node) is a cell
// or get the enclosing by a cell // or get the enclosing by a cell
res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(aCell)); res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(aCell));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
@ -1683,78 +1681,109 @@ nsHTMLEditor::GetFirstSelectedCell(nsIDOMElement **aCell)
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_FAILURE; if (!selection) return NS_ERROR_FAILURE;
//TODO: Replace this with code below new "table cell mode" flag is implemented
nsCOMPtr<nsIEnumerator> enumerator;
res = selection->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_FAILURE;
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if ((NS_SUCCEEDED(res)) && currentItem)
{
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
if (!iter) return NS_ERROR_FAILURE;
iter->Init(range);
// loop through the content iterator for each content node
nsCOMPtr<nsIContent> content;
while (NS_ENUMERATOR_FALSE == iter->IsDone())
{
res = iter->CurrentNode(getter_AddRefs(content));
// Not likely!
if (NS_FAILED(res)) return NS_ERROR_FAILURE;
nsCOMPtr<nsIAtom> atom;
content->GetTag(*getter_AddRefs(atom));
if (atom.get() == nsIEditProperty::td ||
atom.get() == nsIEditProperty::th )
{
// We found a cell
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(content);
if (cellElement)
{
*aCell = cellElement.get();
NS_ADDREF(*aCell);
}
return NS_OK;
}
iter->Next();
}
}
return NS_EDITOR_ELEMENT_NOT_FOUND;
#if 0
//TODO: Do this only after checking the new "table cell mode" flag
// The first cell is the starting node in the first selection range
nsCOMPtr<nsIDOMRange> firstRange; nsCOMPtr<nsIDOMRange> firstRange;
res = selection->GetRangeAt(0, getter_AddRefs(firstRange)); res = selection->GetRangeAt(0, getter_AddRefs(firstRange));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!firstRange) return NS_ERROR_FAILURE; if (!firstRange) return NS_ERROR_FAILURE;
#ifdef DEBUG_cmanske
{
nsCOMPtr<nsIDOMNode> anchorNode;
PRInt32 anchorOffset = -1;
selection->GetAnchorNode(getter_AddRefs(anchorNode));
selection->GetAnchorOffset(&anchorOffset);
nsCOMPtr<nsIDOMNode> focusNode;
res = selection->GetFocusNode(getter_AddRefs(focusNode));
if (NS_FAILED(res)) return res;
PRInt32 focusOffset = -1;
selection->GetFocusOffset(&focusOffset);
nsAutoString name;
anchorNode->GetNodeName(name);
printf("GetFirstSelectedCell: Anchor node of selection: ");
wprintf(name.GetUnicode());
printf(" Offset: %d\n", anchorOffset);
focusNode->GetNodeName(name);
printf("Focus node of selection: ");
wprintf(name.GetUnicode());
printf(" Offset: %x\n", focusOffset);
PRInt32 rangeCount;
res = selection->GetRangeCount(&rangeCount);
printf(" RangeCount: %d\n", rangeCount);
printf(" Range pointer = %d\n", firstRange);
}
#endif
// This is failing -- range doesn't match that set when selecting cell!
nsCOMPtr<nsIDOMNode> cellNode; nsCOMPtr<nsIDOMNode> cellNode;
res = GetFirstNodeInRange(firstRange, getter_AddRefs(cellNode)); res = GetFirstNodeInRange(firstRange, getter_AddRefs(cellNode));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!cellNode) return NS_ERROR_FAILURE; if (!cellNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(cellNode);
if (cellElement) if (IsTableCell(cellNode))
{ {
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(cellNode);
*aCell = cellElement.get(); *aCell = cellElement.get();
NS_ADDREF(*aCell); NS_ADDREF(*aCell);
} }
else res = NS_EDITOR_ELEMENT_NOT_FOUND; else
res = NS_EDITOR_ELEMENT_NOT_FOUND;
mSelectedCellIndex = 1;
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetNextSelectedCell(nsIDOMElement **aCell)
{
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
nsCOMPtr<nsIDOMSelection> selection;
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_FAILURE;
PRInt32 rangeCount;
res = selection->GetRangeCount(&rangeCount);
if (NS_FAILED(res)) return res;
// Don't even try if index exceeds range count
if (mSelectedCellIndex >= rangeCount)
{
// Should we reset index?
// Maybe better to force recalling GetFirstSelectedCell()
//mSelectedCellIndex = 0;
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
// Get first node in first range of selection - test if it's a cell
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(mSelectedCellIndex, getter_AddRefs(range));
if (NS_FAILED(res)) return res;
if (!range) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> cellNode;
res = nsEditor::GetFirstNodeInRange(range, getter_AddRefs(cellNode));
if (NS_FAILED(res)) return res;
if (!cellNode) return NS_ERROR_FAILURE;
if (IsTableCell(cellNode))
{
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(cellNode);
*aCell = cellElement.get();
NS_ADDREF(*aCell);
}
else
res = NS_EDITOR_ELEMENT_NOT_FOUND;
// Setup for next cell
mSelectedCellIndex++;
return res; return res;
#endif
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1842,11 +1871,11 @@ nsHTMLEditor::SetCaretAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt3
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLEditor::GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRBool &aIsSelected) nsHTMLEditor::GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount)
{ {
aTableElement = nsnull; aTableElement = nsnull;
aTagName = ""; aTagName = "";
aIsSelected = PR_FALSE; aSelectedCount = 0;
nsCOMPtr<nsIDOMSelection> selection; nsCOMPtr<nsIDOMSelection> selection;
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection)); nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
@ -1858,52 +1887,218 @@ nsHTMLEditor::GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsS
nsAutoString tdName("td"); nsAutoString tdName("td");
nsCOMPtr<nsIDOMNode> anchorNode; nsCOMPtr<nsIDOMNode> anchorNode;
// Find the first selected cell
// TODO: Handle multiple cells selected!
nsCOMPtr<nsIDOMElement> firstCell;
nsCOMPtr<nsIDOMElement> tableElement;
res = GetFirstSelectedCell(getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res;
if (tableElement)
{
aTagName = tdName;
aIsSelected = PR_TRUE;
goto SET_RETURN_ELEMENT;
}
// See if table or row is selected
res = GetSelectedElement(tableName, getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res;
if (tableElement)
{
aTagName = tableName;
aIsSelected = PR_TRUE;
goto SET_RETURN_ELEMENT;
}
res = GetSelectedElement(trName, getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res;
if (tableElement)
{
aTagName = trName;
aIsSelected = PR_TRUE;
goto SET_RETURN_ELEMENT;
}
// Look for a table cell parent
res = selection->GetAnchorNode(getter_AddRefs(anchorNode)); res = selection->GetAnchorNode(getter_AddRefs(anchorNode));
if (NS_FAILED(res)) return res; if(NS_FAILED(res)) return res;
if (!anchorNode) return NS_ERROR_FAILURE; if (!anchorNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> tableElement;
nsCOMPtr<nsIDOMNode> selectedNode;
// Get child of anchor node, if exists
PRBool hasChildren;
anchorNode->HasChildNodes(&hasChildren);
if (hasChildren)
{
PRInt32 anchorOffset;
res = selection->GetAnchorOffset(&anchorOffset);
if (NS_FAILED(res)) return res;
selectedNode = nsEditor::GetChildAt(anchorNode, anchorOffset);
if (!selectedNode)
selectedNode = anchorNode;
nsAutoString tag;
nsEditor::GetTagString(selectedNode,tag);
if (tag == tdName)
{
tableElement = do_QueryInterface(anchorNode);
aTagName = tdName;
// Each cell is in its own selection range,
// so count signals multiple-cell selection
res = selection->GetRangeCount(&aSelectedCount);
if (NS_FAILED(res)) return res;
}
else if(tag == tableName)
{
tableElement = do_QueryInterface(anchorNode);
aTagName = tableName;
aSelectedCount = 1;
}
else if(tag == trName)
{
tableElement = do_QueryInterface(anchorNode);
aTagName = trName;
aSelectedCount = 1;
}
}
if (!tableElement)
{
// Didn't find a table element -- find a cell parent
res = GetElementOrParentByTagName(tdName, anchorNode, getter_AddRefs(tableElement)); res = GetElementOrParentByTagName(tdName, anchorNode, getter_AddRefs(tableElement));
if(NS_FAILED(res)) return res; if(NS_FAILED(res)) return res;
if (tableElement) if (tableElement)
{
aTagName = tdName; aTagName = tdName;
SET_RETURN_ELEMENT: }
if (tableElement)
{
aTableElement = tableElement.get(); aTableElement = tableElement.get();
NS_ADDREF(aTableElement); NS_ADDREF(aTableElement);
} }
return res; return res;
} }
static PRBool IndexNotTested(nsVoidArray *aArray, PRInt32 aIndex)
{
if (aArray)
{
PRInt32 count = aArray->Count();
for (PRInt32 i = 0; i < count; i++)
{
if(aIndex == (PRInt32)(aArray->ElementAt(i)))
return PR_FALSE;
}
}
return PR_TRUE;
}
NS_IMETHODIMP
nsHTMLEditor::GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 &aSelectionType)
{
aSelectionType = 0;
// Be sure we have a table element
// (if aElement is null, this uses selection's anchor node)
nsCOMPtr<nsIDOMElement> table;
nsresult res = GetElementOrParentByTagName("table", aElement, getter_AddRefs(table));
if (NS_FAILED(res)) return res;
PRInt32 rowCount, colCount;
res = GetTableSize(table, rowCount, colCount);
if (NS_FAILED(res)) return res;
// Traverse all selected cells
// (Failure here may indicate that aCellElement wasn't really a cell)
nsCOMPtr<nsIDOMElement> selectedCell;
res = GetFirstSelectedCell(getter_AddRefs(selectedCell));
if (NS_FAILED(res)) return res;
// We have at least one selected cell, so set return value
aSelectionType = TABLESELECTION_CELL;
// Store indexes of each row/col to avoid duplication of searches
nsVoidArray indexArray;
PRBool allCellsInRowAreSelected = PR_TRUE;
PRBool allCellsInColAreSelected = PR_FALSE;
while (NS_SUCCEEDED(res) && selectedCell)
{
// Get the cell's location in the cellmap
PRInt32 startRowIndex, startColIndex;
res = GetCellIndexes(selectedCell, startRowIndex, startColIndex);
if(NS_FAILED(res)) return res;
if (IndexNotTested(&indexArray, startColIndex))
{
indexArray.AppendElement((void*)startColIndex);
allCellsInRowAreSelected = AllCellsInRowSelected(table, startRowIndex, colCount);
// We're done as soon as we fail for any row
if (!allCellsInRowAreSelected) break;
}
res = GetNextSelectedCell(getter_AddRefs(selectedCell));
}
if (allCellsInRowAreSelected)
{
aSelectionType = TABLESELECTION_ROW;
return NS_OK;
}
// Test for columns
// Empty the indexArray
indexArray.Clear();
// Start at first cell again
res = GetFirstSelectedCell(getter_AddRefs(selectedCell));
while (NS_SUCCEEDED(res) && selectedCell)
{
// Get the cell's location in the cellmap
PRInt32 startRowIndex, startColIndex;
res = GetCellIndexes(selectedCell, startRowIndex, startColIndex);
if(NS_FAILED(res)) return res;
if (IndexNotTested(&indexArray, startRowIndex))
{
indexArray.AppendElement((void*)startColIndex);
allCellsInColAreSelected = AllCellsInColumnSelected(table, startColIndex, colCount);
// We're done as soon as we fail for any column
if (!allCellsInRowAreSelected) break;
}
res = GetNextSelectedCell(getter_AddRefs(selectedCell));
}
if (allCellsInColAreSelected)
aSelectionType = TABLESELECTION_COLUMN;
return NS_OK;
}
PRBool
nsHTMLEditor::AllCellsInRowSelected(nsIDOMElement *aTable, PRInt32 aRowIndex, PRInt32 aNumberOfColumns)
{
if (!aTable) return PR_FALSE;
PRInt32 curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
PRBool isSelected;
for( PRInt32 col = 0; col < aNumberOfColumns; col += actualColSpan)
{
nsCOMPtr<nsIDOMElement> cell;
nsresult res = GetCellDataAt(aTable, aRowIndex, col, *getter_AddRefs(cell),
curStartRowIndex, curStartColIndex, rowSpan, colSpan,
actualRowSpan, actualColSpan, isSelected);
if (NS_FAILED(res)) return PR_FALSE;
// Skip cell spanning into this location from a row above
if (curStartRowIndex == aRowIndex)
{
// If no cell, we may have a "ragged" right edge,
// so return TRUE only if we already found a cell in the row
if (!cell) return (col > 0) ? PR_TRUE : PR_FALSE;
// Return as soon as a non-selected cell is found
if (!isSelected) return PR_FALSE;
}
NS_ASSERTION((actualColSpan > 0),"ActualColSpan = 0 in AllCellsInRowSelected");
}
return PR_TRUE;
}
PRBool
nsHTMLEditor::AllCellsInColumnSelected(nsIDOMElement *aTable, PRInt32 aColIndex, PRInt32 aNumberOfRows)
{
if (!aTable) return PR_FALSE;
PRInt32 curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
PRBool isSelected;
for( PRInt32 row = 0; row < aNumberOfRows; row += actualRowSpan)
{
nsCOMPtr<nsIDOMElement> cell;
nsresult res = GetCellDataAt(aTable, row, aColIndex, *getter_AddRefs(cell),
curStartRowIndex, curStartColIndex, rowSpan, colSpan,
actualRowSpan, actualColSpan, isSelected);
if (NS_FAILED(res)) return PR_FALSE;
// Skip cell spanning into this location from a column to the left
if (curStartColIndex == aColIndex)
{
// If no cell, we must have a "ragged" right edge on the last column
// so return TRUE only if we already found a cell in the row
if (!cell) return (row > 0) ? PR_TRUE : PR_FALSE;
// Return as soon as a non-selected cell is found
if (!isSelected) return PR_FALSE;
}
NS_ASSERTION((actualRowSpan > 0),"ActualRowSpan = 0 in AllCellsInColumnSelected");
}
return PR_TRUE;
}

Просмотреть файл

@ -237,13 +237,48 @@ public:
* @param aTableElement The table element (table, row, or cell) returned * @param aTableElement The table element (table, row, or cell) returned
* @param aTagName The tagname of returned element * @param aTagName The tagname of returned element
* Note that "td" will be returned if name is actually "th" * Note that "td" will be returned if name is actually "th"
* @param aIsSelected Tells if element returned is a selected element * @param aSelectedCount How many table elements were selected
* (false if element is a parent cell of selection) * This tells us if we have multiple cells selected
* (0 if element is a parent cell of selection)
*
* Returns NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found (passes NS_SUCCEEDED macro) * Returns NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found (passes NS_SUCCEEDED macro)
*/ */
NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRBool &aIsSelected)=0; NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount)=0;
/** Generally used after GetSelectedOrParentTableElement
* to test if selected cells are complete rows or columns
*
* @param aElement Any table or cell element or any element inside a table
* Used to get enclosing table.
* If null, selection's anchorNode is used
*
* @param aSelectionType Returns:
* 0 aCellElement was not a cell (returned result = NS_ERROR_FAILURE)
* TABLESELECTION_CELL There are 1 or more cells selected
* but complete rows or columns are not selected
* TABLESELECTION_ROW All cells are in 1 or more rows
* and in each row, all cells selected
* Note: This is the value if all rows (thus all cells) are selected
* TABLESELECTION_COLUMN All cells are in 1 or more columns
* and in each column, all cells are selected
*/
NS_IMETHOD GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 &aSelectionType)=0;
/** Get first selected element from first selection range.
* Assumes cell-selection model where each cell
* is in a separate range (selection parent node is table row)
* @param aCell Selected cell or null if ranges don't contain cell selections
*/
NS_IMETHOD GetFirstSelectedCell(nsIDOMElement **aCell)=0;
/** Get next selected cell element from first selection range.
* Assumes cell-selection model where each cell
* is in a separate range (selection parent node is table row)
* Always call GetFirstSelectedCell() to initialize stored index of "next" cell
* @param aCell Selected cell or null if no more selected cells
* or ranges don't contain cell selections
*/
NS_IMETHOD GetNextSelectedCell(nsIDOMElement **aCell)=0;
}; };
#endif // nsITableEditor_h__ #endif // nsITableEditor_h__

Просмотреть файл

@ -1153,9 +1153,9 @@ function SetBackColorString(xulElementID)
if (xulElement) if (xulElement)
{ {
var textVal; var textVal;
var isSelectedObj = new Object(); var selectedCountObj = new Object();
var tagNameObj = new Object(); var tagNameObj = new Object();
var element = editorShell.GetSelectedOrParentTableElement(tagNameObj, isSelectedObj); var element = editorShell.GetSelectedOrParentTableElement(tagNameObj, selectedCountObj);
if (tagNameObj.value == "table") if (tagNameObj.value == "table")
textVal = editorShell.GetString("TableBackColor"); textVal = editorShell.GetString("TableBackColor");
@ -1564,6 +1564,7 @@ function EditorInsertOrEditTable(insertAllowed)
function EditorTableCellProperties() function EditorTableCellProperties()
{ {
dump("*** EditorTableCellProperties\n");
var cell = editorShell.GetElementOrParentByTagName("td", null); var cell = editorShell.GetElementOrParentByTagName("td", null);
if (cell) { if (cell) {
// Start Table Properties dialog on the "Cell" panel // Start Table Properties dialog on the "Cell" panel

Просмотреть файл

@ -107,6 +107,18 @@ function EditorTestSelection()
function EditorTestTableLayout() function EditorTestTableLayout()
{ {
dump("\n\n\n************ Dump Selection Ranges ************\n");
var selection = editorShell.editorSelection;
for (i = 0; i < selection.rangeCount; i++)
{
var range = selection.getRangeAt(i);
if (range)
{
dump("Range "+i+": StartParent="+range.startParent+", offset="+range.startOffset+"\n");
}
}
dump("\n\n");
var table = editorShell.GetElementOrParentByTagName("table", null); var table = editorShell.GetElementOrParentByTagName("table", null);
if (!table) { if (!table) {
dump("Enclosing Table not found: Place caret in a table cell to do this test\n\n"); dump("Enclosing Table not found: Place caret in a table cell to do this test\n\n");

Просмотреть файл

@ -50,6 +50,8 @@
<html:script language="JavaScript" src="chrome://editor/content/EditorCommands.js"/> <html:script language="JavaScript" src="chrome://editor/content/EditorCommands.js"/>
<html:script language="JavaScript" src="chrome://editor/content/EditorCommandsDebug.js"/> <html:script language="JavaScript" src="chrome://editor/content/EditorCommandsDebug.js"/>
<html:script language="JavaScript" src="chrome://editor/content/EditorCommandsDebug.js"/>
<html:script language="javascript" src="chrome://global/content/strres.js"/>
<commands id="commands"> <commands id="commands">
<commandset id="globalEditMenuItems"/> <commandset id="globalEditMenuItems"/>

Просмотреть файл

@ -50,6 +50,7 @@ var bgcolor = "bgcolor";
var CellIsHeader = false; var CellIsHeader = false;
var rowCount = 1; var rowCount = 1;
var colCount = 1; var colCount = 1;
var selectedCellCount = 0;
var error = 0; var error = 0;
// dialog initialization code // dialog initialization code
@ -81,7 +82,11 @@ function Startup()
// dialog.TableLeaveLocCheck = document.getElementById("TableLeaveLocCheck"); // dialog.TableLeaveLocCheck = document.getElementById("TableLeaveLocCheck");
// Cell Panel // Cell Panel
dialog.SelectionSelect = document.getElementById("SelectionSelect"); dialog.SelectionList = document.getElementById("SelectionList");
dialog.SelectCellItem = document.getElementById("SelectCellItem");
dialog.SelectRowItem = document.getElementById("SelectRowItem");
dialog.SelectColumnItem = document.getElementById("SelectColumnItem");
dialog.CellHeightInput = document.getElementById("CellHeightInput"); dialog.CellHeightInput = document.getElementById("CellHeightInput");
dialog.CellHeightUnits = document.getElementById("CellHeightUnits"); dialog.CellHeightUnits = document.getElementById("CellHeightUnits");
dialog.CellWidthInput = document.getElementById("CellWidthInput"); dialog.CellWidthInput = document.getElementById("CellWidthInput");
@ -98,14 +103,28 @@ function Startup()
// dialog.CellLeaveLocCheck = document.getElementById("CellLeaveLocCheck"); // dialog.CellLeaveLocCheck = document.getElementById("CellLeaveLocCheck");
TableElement = editorShell.GetElementOrParentByTagName("table", null); TableElement = editorShell.GetElementOrParentByTagName("table", null);
CellElement = editorShell.GetElementOrParentByTagName("td", null); var tagNameObj = new Object;
var countObj = new Object;
var element = editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
var tagName = tagNameObj.value;
if (tagNameObj.value == "td")
{
dump("*** Found cell around selection\n");
CellElement = element;
}
selectedCellCount = countObj.value;
// If the count is 0, then we are inside the cell, so select it
if (selectedCellCount == 0)
editorShell.SelectCell();
// We allow a missing cell -- see below
if(!TableElement) if(!TableElement)
{ {
dump("Failed to get selected element or create a new one!\n"); dump("Failed to get selected element or create a new one!\n");
window.close(); window.close();
} }
// We allow a missing cell -- see below
TabPanel = document.getElementById("TabPanel"); TabPanel = document.getElementById("TabPanel");
var TableTab = document.getElementById("TableTab"); var TableTab = document.getElementById("TableTab");
@ -123,6 +142,7 @@ function Startup()
// Activate the Cell Panel if requested // Activate the Cell Panel if requested
if (currentPanel == CellPanel) if (currentPanel == CellPanel)
{ {
dump("*** Requested CellPanel for Table Properties dialog.\n");
// We must have a cell element to start in this panel // We must have a cell element to start in this panel
if(!CellElement) if(!CellElement)
{ {
@ -156,11 +176,17 @@ function Startup()
doSetOKCancel(onOK, null); doSetOKCancel(onOK, null);
// Note: we must use TableElement, not globalTableElement for these,
// thus we should not put this in InitDialog.
// Instead, monitor desired counts with separate globals
rowCount = editorShell.GetTableRowCount(TableElement);
colCount = editorShell.GetTableColumnCount(TableElement);
// This uses values set on global Elements; // This uses values set on global Elements;
InitDialog(); InitDialog();
// Should be dialog.TableRowsInput, or // Should be dialog.TableRowsInput, or
// SelectionSelect in cel panenl, // SelectionList in cel panenl,
// but this is disabled for Beta1disabled for Beta1 // but this is disabled for Beta1disabled for Beta1
if (currentPanel == CellPanel) if (currentPanel == CellPanel)
dialog.CellHeightInput.focus(); dialog.CellHeightInput.focus();
@ -172,19 +198,8 @@ function Startup()
function InitDialog() function InitDialog()
{ {
// Get Table attributes // Get Table attributes
try {
// For some strange reason, we are failing to the "layoutObject" for the table!
rowCount = editorShell.GetTableRowCount(globalTableElement);
dialog.TableRowsInput.value = rowCount; dialog.TableRowsInput.value = rowCount;
colCount = editorShell.GetTableColumnCount(tableGlobatlElement);
dialog.TableColumnsInput.value = colCount; dialog.TableColumnsInput.value = colCount;
}
catch (ex) {
dump("Failed to get table rows and/or columns count\n");
dialog.TableRowsInput.value = "";
dialog.TableColumnsInput.value = "";
}
dialog.TableHeightInput.value = InitPixelOrPercentCombobox(globalTableElement, "height", "TableHeightUnits"); dialog.TableHeightInput.value = InitPixelOrPercentCombobox(globalTableElement, "height", "TableHeightUnits");
dialog.TableWidthInput.value = InitPixelOrPercentCombobox(globalTableElement, "width", "TableWidthUnits"); dialog.TableWidthInput.value = InitPixelOrPercentCombobox(globalTableElement, "width", "TableWidthUnits");
dialog.BorderWidthInput.value = globalTableElement.border; dialog.BorderWidthInput.value = globalTableElement.border;
@ -220,12 +235,25 @@ dump("Caption Element = "+captionElement+"\n");
// Get cell attributes // Get cell attributes
if (globalCellElement) if (globalCellElement)
{ {
//TODO: Test if all cells in selection are in a row or column, // Test if entire rows or columns are selected and set menu appropriately
// and set dialog.SelectionSelect.selectedIndex appropriately var SelectionType = editorShell.GetSelectedCellsType(TableElement);
dump("SelectionList.selectedIndex = "+dialog.SelectionList.selectedIndex+"\n");
switch (SelectionType)
{
case 2:
dialog.SelectionList.selectedItem = dialog.SelectRowItem;
break;
case 3:
dialog.SelectionList.selectedItem = dialog.SelectColumnItem;
break;
default:
dialog.SelectionList.selectedItem = dialog.SelectCellItem;
break;
}
dialog.CellHeightInput.value = InitPixelOrPercentCombobox(globalCellElement, "height", "CellHeightUnits"); dialog.CellHeightInput.value = InitPixelOrPercentCombobox(globalCellElement, "height", "CellHeightUnits");
dialog.CellWidthInput.value = InitPixelOrPercentCombobox(globalCellElement, "width", "CellWidthUnits"); dialog.CellWidthInput.value = InitPixelOrPercentCombobox(globalCellElement, "width", "CellWidthUnits");
//BUG: We don't suppor "rowSpan" or "colSpan" JS attributes? //BUG: We don't support "rowSpan" or "colSpan" JS attributes?
dump("RowSpan="+globalCellElement.rowSpan+" ColSpan="+globalCellElement.colSpan+"\n"); dump("RowSpan="+globalCellElement.rowSpan+" ColSpan="+globalCellElement.colSpan+"\n");
dialog.RowSpanInput.value = globalCellElement.getAttribute("rowspan"); dialog.RowSpanInput.value = globalCellElement.getAttribute("rowspan");
@ -584,12 +612,22 @@ function onOK()
{ {
if (ValidateData()) if (ValidateData())
{ {
editorShell.BeginBatchChanges();
editorShell.CloneAttributes(TableElement, globalTableElement); editorShell.CloneAttributes(TableElement, globalTableElement);
editorShell.CloneAttributes(CellElement, globalCellElement); // Apply changes to all selected cells
var selectedCell = editorShell.GetFirstSelectedCell();
while (selectedCell)
{
// TODO: We need to change this to set only particular attributes
// Set an "ignore" attribute on the attribute node?
editorShell.CloneAttributes(selectedCell,globalCellElement);
selectedCell = editorShell.GetNextSelectedCell();
}
//TODO: DOM manipulation to add/remove table rows/columns, //TODO: DOM manipulation to add/remove table rows/columns,
// Switch cell type to TH -- involves removing TD and replacing with TD // Switch cell type to TH -- involves removing TD and replacing with TD
// Creating and moving CAPTION element // Creating and moving CAPTION element
editorShell.EndBatchChanges();
return true; return true;
} }
return false; return false;

Просмотреть файл

@ -172,11 +172,13 @@
<titledbox class="NoTopMargin NoTopPadding NoBottomPad" autostretch="never" valign="middle"> <titledbox class="NoTopMargin NoTopPadding NoBottomPad" autostretch="never" valign="middle">
<title><text align="left" value="&cellSelection.label;"/></title> <title><text align="left" value="&cellSelection.label;"/></title>
<spring class="spacer"/> <spring class="spacer"/>
<html:select class="MinWidth50" id="SelectionSelect" disabled="true"> <menulist class="MinWidth50" id="SelectionList">
<html:option>&cellSelectionCell.label;</html:option> <menupopup>
<html:option>&cellSelectionRow.label;</html:option> <menuitem data="1" id="SelectCellItem" value="&cellSelectionCell.label;"/>
<html:option>&cellSelectionColumn.label;</html:option> <menuitem data="2" id="SelectRowItem" value="&cellSelectionRow.label;"/>
</html:select> <menuitem data="3" id="SelectColumnItem" value="&cellSelectionColumn.label;"/>
</menupopup>
</menulist>
<spring class="bigspacer"/> <spring class="bigspacer"/>
<titledbutton class="push MinWidth50" value="&cellSelectionPrevious.label;" onclick="SelectPrevious()" disabled="true"/> <titledbutton class="push MinWidth50" value="&cellSelectionPrevious.label;" onclick="SelectPrevious()" disabled="true"/>
<spring class="bigspacer"/> <spring class="bigspacer"/>

Просмотреть файл

@ -45,8 +45,8 @@ tr {
input { input {
height: 1em; height: 1em;
max-height: 1em; max-height: 1em;
padding-top: 5px; padding-top: 2px;
padding-bottom: 5px; padding-bottom: 2px;
margin: 0px; margin: 0px;
} }