diff options
Diffstat (limited to 'editor/libeditor/HTMLInlineTableEditor.cpp')
-rw-r--r-- | editor/libeditor/HTMLInlineTableEditor.cpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/editor/libeditor/HTMLInlineTableEditor.cpp b/editor/libeditor/HTMLInlineTableEditor.cpp new file mode 100644 index 000000000..3da1876ec --- /dev/null +++ b/editor/libeditor/HTMLInlineTableEditor.cpp @@ -0,0 +1,283 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/HTMLEditor.h" + +#include "HTMLEditUtils.h" +#include "mozilla/dom/Element.h" +#include "nsAString.h" +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsError.h" +#include "nsIContent.h" +#include "nsIDOMElement.h" +#include "nsIDOMEventTarget.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMNode.h" +#include "nsIHTMLObjectResizer.h" +#include "nsIPresShell.h" +#include "nsLiteralString.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nscore.h" + +namespace mozilla { + +// Uncomment the following line if you want to disable +// table deletion when the only column/row is removed +// #define DISABLE_TABLE_DELETION 1 + +NS_IMETHODIMP +HTMLEditor::SetInlineTableEditingEnabled(bool aIsEnabled) +{ + mIsInlineTableEditingEnabled = aIsEnabled; + return NS_OK; +} + +NS_IMETHODIMP +HTMLEditor::GetInlineTableEditingEnabled(bool* aIsEnabled) +{ + *aIsEnabled = mIsInlineTableEditingEnabled; + return NS_OK; +} + +NS_IMETHODIMP +HTMLEditor::ShowInlineTableEditingUI(nsIDOMElement* aCell) +{ + NS_ENSURE_ARG_POINTER(aCell); + + // do nothing if aCell is not a table cell... + nsCOMPtr<Element> cell = do_QueryInterface(aCell); + if (!cell || !HTMLEditUtils::IsTableCell(cell)) { + return NS_OK; + } + + if (NS_WARN_IF(!IsDescendantOfEditorRoot(cell))) { + return NS_ERROR_UNEXPECTED; + } + + if (mInlineEditedCell) { + NS_ERROR("call HideInlineTableEditingUI first"); + return NS_ERROR_UNEXPECTED; + } + + // the resizers and the shadow will be anonymous children of the body + nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot()); + NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER); + + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement, + NS_LITERAL_STRING("mozTableAddColumnBefore"), + false, getter_AddRefs(mAddColumnBeforeButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement, + NS_LITERAL_STRING("mozTableRemoveColumn"), + false, getter_AddRefs(mRemoveColumnButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement, + NS_LITERAL_STRING("mozTableAddColumnAfter"), + false, getter_AddRefs(mAddColumnAfterButton)); + + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement, + NS_LITERAL_STRING("mozTableAddRowBefore"), + false, getter_AddRefs(mAddRowBeforeButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement, + NS_LITERAL_STRING("mozTableRemoveRow"), + false, getter_AddRefs(mRemoveRowButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement, + NS_LITERAL_STRING("mozTableAddRowAfter"), + false, getter_AddRefs(mAddRowAfterButton)); + + AddMouseClickListener(mAddColumnBeforeButton); + AddMouseClickListener(mRemoveColumnButton); + AddMouseClickListener(mAddColumnAfterButton); + AddMouseClickListener(mAddRowBeforeButton); + AddMouseClickListener(mRemoveRowButton); + AddMouseClickListener(mAddRowAfterButton); + + mInlineEditedCell = aCell; + return RefreshInlineTableEditingUI(); +} + +NS_IMETHODIMP +HTMLEditor::HideInlineTableEditingUI() +{ + mInlineEditedCell = nullptr; + + RemoveMouseClickListener(mAddColumnBeforeButton); + RemoveMouseClickListener(mRemoveColumnButton); + RemoveMouseClickListener(mAddColumnAfterButton); + RemoveMouseClickListener(mAddRowBeforeButton); + RemoveMouseClickListener(mRemoveRowButton); + RemoveMouseClickListener(mAddRowAfterButton); + + // get the presshell's document observer interface. + nsCOMPtr<nsIPresShell> ps = GetPresShell(); + // We allow the pres shell to be null; when it is, we presume there + // are no document observers to notify, but we still want to + // UnbindFromTree. + + // get the root content node. + nsCOMPtr<nsIContent> bodyContent = GetRoot(); + + DeleteRefToAnonymousNode(mAddColumnBeforeButton, bodyContent, ps); + mAddColumnBeforeButton = nullptr; + DeleteRefToAnonymousNode(mRemoveColumnButton, bodyContent, ps); + mRemoveColumnButton = nullptr; + DeleteRefToAnonymousNode(mAddColumnAfterButton, bodyContent, ps); + mAddColumnAfterButton = nullptr; + DeleteRefToAnonymousNode(mAddRowBeforeButton, bodyContent, ps); + mAddRowBeforeButton = nullptr; + DeleteRefToAnonymousNode(mRemoveRowButton, bodyContent, ps); + mRemoveRowButton = nullptr; + DeleteRefToAnonymousNode(mAddRowAfterButton, bodyContent, ps); + mAddRowAfterButton = nullptr; + + return NS_OK; +} + +NS_IMETHODIMP +HTMLEditor::DoInlineTableEditingAction(nsIDOMElement* aElement) +{ + NS_ENSURE_ARG_POINTER(aElement); + bool anonElement = false; + if (aElement && + NS_SUCCEEDED(aElement->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement)) && + anonElement) { + nsAutoString anonclass; + nsresult rv = + aElement->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass); + NS_ENSURE_SUCCESS(rv, rv); + + if (!StringBeginsWith(anonclass, NS_LITERAL_STRING("mozTable"))) + return NS_OK; + + nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(mInlineEditedCell); + nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode); + int32_t rowCount, colCount; + rv = GetTableSize(tableElement, &rowCount, &colCount); + NS_ENSURE_SUCCESS(rv, rv); + + bool hideUI = false; + bool hideResizersWithInlineTableUI = (GetAsDOMNode(mResizedObject) == tableElement); + + if (anonclass.EqualsLiteral("mozTableAddColumnBefore")) + InsertTableColumn(1, false); + else if (anonclass.EqualsLiteral("mozTableAddColumnAfter")) + InsertTableColumn(1, true); + else if (anonclass.EqualsLiteral("mozTableAddRowBefore")) + InsertTableRow(1, false); + else if (anonclass.EqualsLiteral("mozTableAddRowAfter")) + InsertTableRow(1, true); + else if (anonclass.EqualsLiteral("mozTableRemoveColumn")) { + DeleteTableColumn(1); +#ifndef DISABLE_TABLE_DELETION + hideUI = (colCount == 1); +#endif + } + else if (anonclass.EqualsLiteral("mozTableRemoveRow")) { + DeleteTableRow(1); +#ifndef DISABLE_TABLE_DELETION + hideUI = (rowCount == 1); +#endif + } + else + return NS_OK; + + if (hideUI) { + HideInlineTableEditingUI(); + if (hideResizersWithInlineTableUI) + HideResizers(); + } + } + + return NS_OK; +} + +void +HTMLEditor::AddMouseClickListener(nsIDOMElement* aElement) +{ + nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement)); + if (evtTarget) { + evtTarget->AddEventListener(NS_LITERAL_STRING("click"), + mEventListener, true); + } +} + +void +HTMLEditor::RemoveMouseClickListener(nsIDOMElement* aElement) +{ + nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement)); + if (evtTarget) { + evtTarget->RemoveEventListener(NS_LITERAL_STRING("click"), + mEventListener, true); + } +} + +NS_IMETHODIMP +HTMLEditor::RefreshInlineTableEditingUI() +{ + nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mInlineEditedCell); + if (!htmlElement) { + return NS_ERROR_NULL_POINTER; + } + + int32_t xCell, yCell, wCell, hCell; + GetElementOrigin(mInlineEditedCell, xCell, yCell); + + nsresult rv = htmlElement->GetOffsetWidth(&wCell); + NS_ENSURE_SUCCESS(rv, rv); + rv = htmlElement->GetOffsetHeight(&hCell); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t xHoriz = xCell + wCell/2; + int32_t yVert = yCell + hCell/2; + + nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(mInlineEditedCell); + nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode); + int32_t rowCount, colCount; + rv = GetTableSize(tableElement, &rowCount, &colCount); + NS_ENSURE_SUCCESS(rv, rv); + + SetAnonymousElementPosition(xHoriz-10, yCell-7, mAddColumnBeforeButton); +#ifdef DISABLE_TABLE_DELETION + NS_NAMED_LITERAL_STRING(classStr, "class"); + + if (colCount== 1) { + mRemoveColumnButton->SetAttribute(classStr, + NS_LITERAL_STRING("hidden")); + } + else { + bool hasClass = false; + rv = mRemoveColumnButton->HasAttribute(classStr, &hasClass); + if (NS_SUCCEEDED(rv) && hasClass) { + mRemoveColumnButton->RemoveAttribute(classStr); + } +#endif + SetAnonymousElementPosition(xHoriz-4, yCell-7, mRemoveColumnButton); +#ifdef DISABLE_TABLE_DELETION + } +#endif + SetAnonymousElementPosition(xHoriz+6, yCell-7, mAddColumnAfterButton); + + SetAnonymousElementPosition(xCell-7, yVert-10, mAddRowBeforeButton); +#ifdef DISABLE_TABLE_DELETION + if (rowCount== 1) { + mRemoveRowButton->SetAttribute(classStr, + NS_LITERAL_STRING("hidden")); + } + else { + bool hasClass = false; + rv = mRemoveRowButton->HasAttribute(classStr, &hasClass); + if (NS_SUCCEEDED(rv) && hasClass) { + mRemoveRowButton->RemoveAttribute(classStr); + } +#endif + SetAnonymousElementPosition(xCell-7, yVert-4, mRemoveRowButton); +#ifdef DISABLE_TABLE_DELETION + } +#endif + SetAnonymousElementPosition(xCell-7, yVert+6, mAddRowAfterButton); + + return NS_OK; +} + +} // namespace mozilla |