Mypal/editor/libeditor/HTMLInlineTableEditor.cpp

284 lines
9.0 KiB
C++

/* 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