summaryrefslogtreecommitdiffstats
path: root/editor/libeditor/HTMLInlineTableEditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/libeditor/HTMLInlineTableEditor.cpp')
-rw-r--r--editor/libeditor/HTMLInlineTableEditor.cpp283
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