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