diff --git a/mozilla/editor/composer/src/Makefile.in b/mozilla/editor/composer/src/Makefile.in index 6b27dbcd307..f18c586b87c 100644 --- a/mozilla/editor/composer/src/Makefile.in +++ b/mozilla/editor/composer/src/Makefile.in @@ -83,6 +83,25 @@ EXTRA_DSO_LDOPTS += \ _FILES = \ $(srcdir)/res/EditorOverride.css \ + $(srcdir)/res/grabber.gif \ + $(srcdir)/res/table-add-column-after-active.gif \ + $(srcdir)/res/table-add-column-after-hover.gif \ + $(srcdir)/res/table-add-column-after.gif \ + $(srcdir)/res/table-add-column-before-active.gif \ + $(srcdir)/res/table-add-column-before-hover.gif \ + $(srcdir)/res/table-add-column-before.gif \ + $(srcdir)/res/table-add-row-after-active.gif \ + $(srcdir)/res/table-add-row-after-hover.gif \ + $(srcdir)/res/table-add-row-after.gif \ + $(srcdir)/res/table-add-row-before-active.gif \ + $(srcdir)/res/table-add-row-before-hover.gif \ + $(srcdir)/res/table-add-row-before.gif \ + $(srcdir)/res/table-remove-column-active.gif \ + $(srcdir)/res/table-remove-column-hover.gif \ + $(srcdir)/res/table-remove-column.gif \ + $(srcdir)/res/table-remove-row-active.gif \ + $(srcdir)/res/table-remove-row-hover.gif \ + $(srcdir)/res/table-remove-row.gif \ $(NULL) libs:: diff --git a/mozilla/editor/composer/src/nsComposerCommands.cpp b/mozilla/editor/composer/src/nsComposerCommands.cpp index eb3d4dc5b27..5edb67cc30f 100644 --- a/mozilla/editor/composer/src/nsComposerCommands.cpp +++ b/mozilla/editor/composer/src/nsComposerCommands.cpp @@ -45,6 +45,8 @@ #include "nsIHTMLEditor.h" #include "nsIEditingSession.h" +#include "nsIHTMLAbsPosEditor.h" + #include "nsIDOMElement.h" #include "nsIClipboard.h" @@ -1090,6 +1092,203 @@ nsAlignCommand::SetState(nsIEditor *aEditor, nsString& newState) #pragma mark - #endif + +nsAbsolutePositioningCommand::nsAbsolutePositioningCommand() +: nsBaseStateUpdatingCommand("") +{ +} + +NS_IMETHODIMP +nsAbsolutePositioningCommand::IsCommandEnabled(const char * aCommandName, + nsISupports *aCommandRefCon, + PRBool *_retval) +{ + NS_ASSERTION(aCommandRefCon, "Need an editor here"); + + nsCOMPtr htmlEditor = do_QueryInterface(aCommandRefCon); + if (!htmlEditor) return NS_ERROR_FAILURE; + + htmlEditor->GetAbsolutePositioningEnabled(_retval); + return NS_OK; +} + +nsresult +nsAbsolutePositioningCommand::GetCurrentState(nsIEditor *aEditor, const char* aTagName, nsICommandParams *aParams) +{ + NS_ASSERTION(aEditor, "Need an editor here"); + + nsCOMPtr htmlEditor = do_QueryInterface(aEditor); + if (!htmlEditor) return NS_ERROR_FAILURE; + + PRBool isEnabled; + htmlEditor->GetAbsolutePositioningEnabled(&isEnabled); + if (!isEnabled) { + aParams->SetBooleanValue(STATE_MIXED,PR_FALSE); + aParams->SetCStringValue(STATE_ATTRIBUTE, ""); + return NS_OK; + } + + nsCOMPtr elt; + nsresult rv = htmlEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); + if (NS_FAILED(rv)) + return rv; + + nsAutoString outStateString; + if (elt) + outStateString.Assign(NS_LITERAL_STRING("absolute")); + + aParams->SetBooleanValue(STATE_MIXED,PR_FALSE); + aParams->SetCStringValue(STATE_ATTRIBUTE, NS_ConvertUCS2toUTF8(outStateString).get()); + return NS_OK; +} + +nsresult +nsAbsolutePositioningCommand::ToggleState(nsIEditor *aEditor, const char* aTagName) +{ + NS_ASSERTION(aEditor, "Need an editor here"); + + nsCOMPtr htmlEditor = do_QueryInterface(aEditor); + if (!htmlEditor) return NS_ERROR_FAILURE; + + nsCOMPtr elt; + nsresult rv = htmlEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); + if (NS_FAILED(rv)) return rv; + + if (elt) { + // we have to remove positioning on an element + rv = htmlEditor->AbsolutePositionSelection(PR_FALSE); + } + else { + rv = htmlEditor->AbsolutePositionSelection(PR_TRUE); + } + return rv; +} + + +#ifdef XP_MAC +#pragma mark - +#endif + +NS_IMETHODIMP +nsDecreaseZIndexCommand::IsCommandEnabled(const char * aCommandName, + nsISupports *refCon, + PRBool *outCmdEnabled) +{ + nsCOMPtr htmlEditor = do_QueryInterface(refCon); + if (!htmlEditor) return NS_ERROR_FAILURE; + + PRBool isEnabled; + htmlEditor->GetAbsolutePositioningEnabled(outCmdEnabled); + if (!(*outCmdEnabled)) + return NS_OK; + + nsCOMPtr positionedElement; + htmlEditor->GetPositionedElement(getter_AddRefs(positionedElement)); + *outCmdEnabled = PR_FALSE; + if (positionedElement) { + PRInt32 z; + nsresult res = htmlEditor->GetElementZIndex(positionedElement, &z); + if (NS_FAILED(res)) return res; + *outCmdEnabled = (z > 0); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDecreaseZIndexCommand::DoCommand(const char *aCommandName, + nsISupports *refCon) +{ + nsCOMPtr htmlEditor = do_QueryInterface(refCon); + if (!htmlEditor) + return NS_ERROR_NOT_IMPLEMENTED; + + return htmlEditor->RelativeChangeZIndex(-1); +} + +NS_IMETHODIMP +nsDecreaseZIndexCommand::DoCommandParams(const char *aCommandName, + nsICommandParams *aParams, + nsISupports *refCon) +{ + return DoCommand(aCommandName, refCon); +} + +NS_IMETHODIMP +nsDecreaseZIndexCommand::GetCommandStateParams(const char *aCommandName, + nsICommandParams *aParams, + nsISupports *refCon) +{ + NS_ENSURE_ARG_POINTER(aParams); + + PRBool enabled = PR_FALSE; + nsresult rv = IsCommandEnabled(aCommandName, refCon, &enabled); + NS_ENSURE_SUCCESS(rv, rv); + + return aParams->SetBooleanValue(STATE_ENABLED, enabled); +} + +#ifdef XP_MAC +#pragma mark - +#endif + +NS_IMETHODIMP +nsIncreaseZIndexCommand::IsCommandEnabled(const char * aCommandName, + nsISupports *refCon, + PRBool *outCmdEnabled) +{ + nsCOMPtr htmlEditor = do_QueryInterface(refCon); + if (!htmlEditor) return NS_ERROR_FAILURE; + + PRBool isEnabled; + htmlEditor->GetAbsolutePositioningEnabled(outCmdEnabled); + if (!(*outCmdEnabled)) + return NS_OK; + + nsCOMPtr positionedElement; + htmlEditor->GetPositionedElement(getter_AddRefs(positionedElement)); + *outCmdEnabled = (nsnull != positionedElement); + return NS_OK; +} + +NS_IMETHODIMP +nsIncreaseZIndexCommand::DoCommand(const char *aCommandName, + nsISupports *refCon) +{ + nsCOMPtr htmlEditor = do_QueryInterface(refCon); + if (!htmlEditor) + return NS_ERROR_NOT_IMPLEMENTED; + + return htmlEditor->RelativeChangeZIndex(1); +} + +NS_IMETHODIMP +nsIncreaseZIndexCommand::DoCommandParams(const char *aCommandName, + nsICommandParams *aParams, + nsISupports *refCon) +{ + return DoCommand(aCommandName, refCon); +} + +NS_IMETHODIMP +nsIncreaseZIndexCommand::GetCommandStateParams(const char *aCommandName, + nsICommandParams *aParams, + nsISupports *refCon) +{ + NS_ENSURE_ARG_POINTER(aParams); + + PRBool enabled = PR_FALSE; + nsresult rv = IsCommandEnabled(aCommandName, refCon, &enabled); + NS_ENSURE_SUCCESS(rv, rv); + + return aParams->SetBooleanValue(STATE_ENABLED, enabled); +} + +#ifdef XP_MAC +#pragma mark - +#endif + + NS_IMETHODIMP nsRemoveStylesCommand::IsCommandEnabled(const char * aCommandName, nsISupports *refCon, diff --git a/mozilla/editor/composer/src/nsComposerCommands.h b/mozilla/editor/composer/src/nsComposerCommands.h index cd2d53079b2..c81547d923f 100644 --- a/mozilla/editor/composer/src/nsComposerCommands.h +++ b/mozilla/editor/composer/src/nsComposerCommands.h @@ -271,7 +271,17 @@ protected: virtual nsresult SetState(nsIEditor *aEditor, nsString& newState); }; +class nsAbsolutePositioningCommand : public nsBaseStateUpdatingCommand +{ +public: + nsAbsolutePositioningCommand(); +protected: + + NS_IMETHOD IsCommandEnabled(const char *aCommandName, nsISupports *aCommandRefCon, PRBool *_retval); + virtual nsresult GetCurrentState(nsIEditor *aEditor, const char* aTagName, nsICommandParams *aParams); + virtual nsresult ToggleState(nsIEditor *aEditor, const char* aTagName); +}; // composer commands @@ -281,6 +291,9 @@ NS_DECL_COMPOSER_COMMAND(nsSetDocumentStateCommand) NS_DECL_COMPOSER_COMMAND(nsSetDocumentOptionsCommand) //NS_DECL_COMPOSER_COMMAND(nsPrintingCommands) +NS_DECL_COMPOSER_COMMAND(nsDecreaseZIndexCommand) +NS_DECL_COMPOSER_COMMAND(nsIncreaseZIndexCommand) + // Generic commands // File menu diff --git a/mozilla/editor/composer/src/nsComposerController.cpp b/mozilla/editor/composer/src/nsComposerController.cpp index a3e9070ce4c..d5af827c058 100644 --- a/mozilla/editor/composer/src/nsComposerController.cpp +++ b/mozilla/editor/composer/src/nsComposerController.cpp @@ -171,5 +171,9 @@ nsComposerController::RegisterHTMLEditorCommands( NS_REGISTER_TAG_COMMAND(nsInsertTagCommand, "cmd_insertImageNoUI", "img"); NS_REGISTER_TAG_COMMAND(nsInsertTagCommand, "cmd_insertHR", "hr"); + NS_REGISTER_ONE_COMMAND(nsAbsolutePositioningCommand, "cmd_absPos"); + NS_REGISTER_ONE_COMMAND(nsDecreaseZIndexCommand, "cmd_decreaseZIndex"); + NS_REGISTER_ONE_COMMAND(nsIncreaseZIndexCommand, "cmd_increaseZIndex"); + return NS_OK; } diff --git a/mozilla/editor/composer/src/res/EditorOverride.css b/mozilla/editor/composer/src/res/EditorOverride.css index 00b99649a23..9ea9f2f5e5a 100644 --- a/mozilla/editor/composer/src/res/EditorOverride.css +++ b/mozilla/editor/composer/src/res/EditorOverride.css @@ -105,26 +105,35 @@ option { #mozToc.readonly { -moz-user-select: all !important; - -moz-user-input: none ! important; + -moz-user-input: none !important; } /* the following rules are for Image Resizing */ span[\_moz_anonclass="mozResizer"] { - width: 4px; - height: 4px; + width: 5px; + height: 5px; position: absolute; - display: block; border: 1px black solid; - background-color: black; + background-color: white; -moz-user-select: none; + z-index: 2147483646; /* max value -1 for this property */ +} + +/* we can't use :active below */ +span[\_moz_anonclass="mozResizer"][\_moz_activated], +span[\_moz_anonclass="mozResizer"]:hover { + background-color: black; } span[\_moz_anonclass="mozResizer"].hidden, span[\_moz_anonclass="mozResizingShadow"].hidden, img[\_moz_anonclass="mozResizingShadow"].hidden, -span[\_moz_anonclass="mozResizingInfo"].hidden { - display: none ! important; +span[\_moz_anonclass="mozGrabber"].hidden, +span[\_moz_anonclass="mozResizingInfo"].hidden, +a[\_moz_anonclass="mozTableRemoveRow"].hidden, +a[\_moz_anonclass="mozTableRemoveColumn"].hidden { + display: none !important; } span[\_moz_anonclass="mozResizer"][anonlocation="nw"] { @@ -153,12 +162,12 @@ span[\_moz_anonclass="mozResizer"][anonlocation="se"] { } span[\_moz_anonclass="mozResizingShadow"], -img[\_moz_anonclass="mozResizingShadow"]{ - border: thin dashed black; +img[\_moz_anonclass="mozResizingShadow"] { + -moz-outline: thin dashed black; -moz-user-select: none; - display: block; -moz-opacity: 0.5; position: absolute; + z-index: 2147483647; /* max value for this property */ } span[\_moz_anonclass="mozResizingInfo"] { @@ -169,5 +178,167 @@ span[\_moz_anonclass="mozResizingInfo"] { border: ridge 2px #d0d0d0; padding: 2px; position: absolute; - display: block; + z-index: 2147483647; /* max value for this property */ +} + +img[\_moz_resizing] { + -moz-outline: thin solid black; +} + +*[\_moz_abspos] { + -moz-outline: silver ridge 2px; + z-index: 2147483645 !important; /* max value -2 for this property */ +} +*[\_moz_abspos="white"] { + background-color: white !important; +} +*[\_moz_abspos="black"] { + background-color: black !important; +} + +span[\_moz_anonclass="mozGrabber"] { + -moz-outline: ridge 2px silver; + padding: 2px; + position: absolute; + width: 12px; + height: 12px; + background-image: url("resource:/res/grabber.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none; + cursor: move; +} + +/* INLINE TABLE EDITING */ + +a[\_moz_anonclass="mozTableAddColumnBefore"] { + position: absolute; + z-index: 2147483647; /* max value for this property */ + text-decoration: none !important; + border: none 0px !important; + width: 4px; + height: 8px; + background-image: url("resource:/res/table-add-column-before.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none !important; + -moz-user-focus: none !important; +} + +a[\_moz_anonclass="mozTableAddColumnBefore"]:hover { + background-image: url("resource:/res/table-add-column-before-hover.gif"); +} + +a[\_moz_anonclass="mozTableAddColumnBefore"]:active { + background-image: url("resource:/res/table-add-column-before-active.gif"); +} + +a[\_moz_anonclass="mozTableAddColumnAfter"] { + position: absolute; + z-index: 2147483647; /* max value for this property */ + text-decoration: none !important; + border: none 0px !important; + width: 4px; + height: 8px; + background-image: url("resource:/res/table-add-column-after.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none !important; + -moz-user-focus: none !important; +} + +a[\_moz_anonclass="mozTableAddColumnAfter"]:hover { + background-image: url("resource:/res/table-add-column-after-hover.gif"); +} + +a[\_moz_anonclass="mozTableAddColumnAfter"]:active { + background-image: url("resource:/res/table-add-column-after-active.gif"); +} + +a[\_moz_anonclass="mozTableRemoveColumn"] { + position: absolute; + z-index: 2147483647; /* max value for this property */ + text-decoration: none !important; + border: none 0px !important; + width: 8px; + height: 8px; + background-image: url("resource:/res/table-remove-column.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none !important; + -moz-user-focus: none !important; +} + +a[\_moz_anonclass="mozTableRemoveColumn"]:hover { + background-image: url("resource:/res/table-remove-column-hover.gif"); +} + +a[\_moz_anonclass="mozTableRemoveColumn"]:active { + background-image: url("resource:/res/table-remove-column-active.gif"); +} + +a[\_moz_anonclass="mozTableAddRowBefore"] { + position: absolute; + z-index: 2147483647; /* max value for this property */ + text-decoration: none !important; + border: none 0px !important; + width: 8px; + height: 4px; + background-image: url("resource:/res/table-add-row-before.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none !important; + -moz-user-focus: none !important; +} + +a[\_moz_anonclass="mozTableAddRowBefore"]:hover { + background-image: url("resource:/res/table-add-row-before-hover.gif"); +} + +a[\_moz_anonclass="mozTableAddRowBefore"]:active { + background-image: url("resource:/res/table-add-row-before-active.gif"); +} + +a[\_moz_anonclass="mozTableAddRowAfter"] { + position: absolute; + z-index: 2147483647; /* max value for this property */ + text-decoration: none !important; + border: none 0px !important; + width: 8px; + height: 4px; + background-image: url("resource:/res/table-add-row-after.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none !important; + -moz-user-focus: none !important; +} + +a[\_moz_anonclass="mozTableAddRowAfter"]:hover { + background-image: url("resource:/res/table-add-row-after-hover.gif"); +} + +a[\_moz_anonclass="mozTableAddRowAfter"]:active { + background-image: url("resource:/res/table-add-row-after-active.gif"); +} + +a[\_moz_anonclass="mozTableRemoveRow"] { + position: absolute; + z-index: 2147483647; /* max value for this property */ + text-decoration: none !important; + border: none 0px !important; + width: 8px; + height: 8px; + background-image: url("resource:/res/table-remove-row.gif"); + background-repeat: no-repeat; + background-position: center center; + -moz-user-select: none !important; + -moz-user-focus: none !important; +} + +a[\_moz_anonclass="mozTableRemoveRow"]:hover { + background-image: url("resource:/res/table-remove-row-hover.gif"); +} + +a[\_moz_anonclass="mozTableRemoveRow"]:active { + background-image: url("resource:/res/table-remove-row-active.gif"); } diff --git a/mozilla/editor/composer/src/res/grabber.gif b/mozilla/editor/composer/src/res/grabber.gif new file mode 100644 index 00000000000..06749a64fca Binary files /dev/null and b/mozilla/editor/composer/src/res/grabber.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-column-after-active.gif b/mozilla/editor/composer/src/res/table-add-column-after-active.gif new file mode 100644 index 00000000000..ffa6ed9d808 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-column-after-active.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-column-after-hover.gif b/mozilla/editor/composer/src/res/table-add-column-after-hover.gif new file mode 100644 index 00000000000..29679f9812a Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-column-after-hover.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-column-after.gif b/mozilla/editor/composer/src/res/table-add-column-after.gif new file mode 100644 index 00000000000..8891be969c5 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-column-after.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-column-before-active.gif b/mozilla/editor/composer/src/res/table-add-column-before-active.gif new file mode 100644 index 00000000000..81f27eac203 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-column-before-active.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-column-before-hover.gif b/mozilla/editor/composer/src/res/table-add-column-before-hover.gif new file mode 100644 index 00000000000..7b54537e404 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-column-before-hover.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-column-before.gif b/mozilla/editor/composer/src/res/table-add-column-before.gif new file mode 100644 index 00000000000..d4a3ffe5e95 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-column-before.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-row-after-active.gif b/mozilla/editor/composer/src/res/table-add-row-after-active.gif new file mode 100644 index 00000000000..ff2475dccb3 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-row-after-active.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-row-after-hover.gif b/mozilla/editor/composer/src/res/table-add-row-after-hover.gif new file mode 100644 index 00000000000..a829351b64d Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-row-after-hover.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-row-after.gif b/mozilla/editor/composer/src/res/table-add-row-after.gif new file mode 100644 index 00000000000..3f1a39d9815 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-row-after.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-row-before-active.gif b/mozilla/editor/composer/src/res/table-add-row-before-active.gif new file mode 100644 index 00000000000..148c45fb046 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-row-before-active.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-row-before-hover.gif b/mozilla/editor/composer/src/res/table-add-row-before-hover.gif new file mode 100644 index 00000000000..e8f1d10b0c9 Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-row-before-hover.gif differ diff --git a/mozilla/editor/composer/src/res/table-add-row-before.gif b/mozilla/editor/composer/src/res/table-add-row-before.gif new file mode 100644 index 00000000000..1682170cb3a Binary files /dev/null and b/mozilla/editor/composer/src/res/table-add-row-before.gif differ diff --git a/mozilla/editor/composer/src/res/table-remove-column-active.gif b/mozilla/editor/composer/src/res/table-remove-column-active.gif new file mode 100644 index 00000000000..4dfbde4ce2c Binary files /dev/null and b/mozilla/editor/composer/src/res/table-remove-column-active.gif differ diff --git a/mozilla/editor/composer/src/res/table-remove-column-hover.gif b/mozilla/editor/composer/src/res/table-remove-column-hover.gif new file mode 100644 index 00000000000..fd11bb52c3d Binary files /dev/null and b/mozilla/editor/composer/src/res/table-remove-column-hover.gif differ diff --git a/mozilla/editor/composer/src/res/table-remove-column.gif b/mozilla/editor/composer/src/res/table-remove-column.gif new file mode 100644 index 00000000000..d8071da0a9e Binary files /dev/null and b/mozilla/editor/composer/src/res/table-remove-column.gif differ diff --git a/mozilla/editor/composer/src/res/table-remove-row-active.gif b/mozilla/editor/composer/src/res/table-remove-row-active.gif new file mode 100644 index 00000000000..4dfbde4ce2c Binary files /dev/null and b/mozilla/editor/composer/src/res/table-remove-row-active.gif differ diff --git a/mozilla/editor/composer/src/res/table-remove-row-hover.gif b/mozilla/editor/composer/src/res/table-remove-row-hover.gif new file mode 100644 index 00000000000..fd11bb52c3d Binary files /dev/null and b/mozilla/editor/composer/src/res/table-remove-row-hover.gif differ diff --git a/mozilla/editor/composer/src/res/table-remove-row.gif b/mozilla/editor/composer/src/res/table-remove-row.gif new file mode 100644 index 00000000000..d8071da0a9e Binary files /dev/null and b/mozilla/editor/composer/src/res/table-remove-row.gif differ diff --git a/mozilla/editor/idl/Makefile.in b/mozilla/editor/idl/Makefile.in index cf5061706a7..07f2e5a345a 100644 --- a/mozilla/editor/idl/Makefile.in +++ b/mozilla/editor/idl/Makefile.in @@ -42,6 +42,9 @@ XPIDLSRCS = \ nsIEditorStyleSheets.idl \ nsIHTMLEditor.idl \ nsIHTMLObjectResizer.idl \ + nsIHTMLAbsPosEditor.idl \ + nsIHTMLObjectResizeListener.idl \ + nsIHTMLInlineTableEditor.idl \ nsIPlaintextEditor.idl \ nsITableEditor.idl \ nsIURIRefObject.idl \ diff --git a/mozilla/editor/idl/nsIHTMLAbsPosEditor.idl b/mozilla/editor/idl/nsIHTMLAbsPosEditor.idl new file mode 100644 index 00000000000..e2f42e455c2 --- /dev/null +++ b/mozilla/editor/idl/nsIHTMLAbsPosEditor.idl @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Glazman (glazman@netscape.com) (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "domstubs.idl" + +[scriptable, uuid(91375f52-20e6-4757-9835-eb04fabe5498)] + +interface nsIHTMLAbsPosEditor : nsISupports +{ + /** + * true if the selection container is absolutely positioned + */ + readonly attribute boolean selectionContainerAbsolutelyPositioned; + + /** + * this contains the absolutely positioned element currently edited + * or null + */ + readonly attribute nsIDOMElement positionedElement; + + /** + * true if Absolute Positioning handling is enabled in the editor + */ + attribute boolean absolutePositioningEnabled; + + + /* Utility methods */ + + /** + * true if Snap To Grid is enabled in the editor. + */ + attribute boolean snapToGridEnabled; + + /** + * sets the grid size in pixels. + * @param aSizeInPixels [IN] the size of the grid in pixels + */ + attribute unsigned long gridSize; + + /* Selection-based methods */ + + /** + * returns the deepest absolutely positioned container of the selection + * if it exists or null. + */ + readonly attribute nsIDOMElement absolutelyPositionedSelectionContainer; + + /** + * extracts the selection from the normal flow of the document and + * positions it. + * @param aEnabled [IN] true to absolutely position the selection, + * false to put it back in the normal flow + */ + void absolutePositionSelection(in boolean aEnabled); + + /** + * adds aChange to the z-index of the currently positioned element. + * @param aChange [IN] relative change to apply to current z-index + */ + void relativeChangeZIndex(in long aChange); + + /* Element-based methods */ + + /** + * extracts an element from the normal flow of the document and + * positions it, and puts it back in the normal flow. + * @param aElement [IN] the element + * @param aEnabled [IN] true to absolutely position the element, + * false to put it back in the normal flow + */ + void absolutelyPositionElement(in nsIDOMElement aElement, + in boolean aEnabled); + + /** + * sets the position of an element; warning it does NOT check if the + * element is already positioned or not and that's on purpose. + * @param aElement [IN] the element + * @param aX [IN] the x position in pixels. + * @param aY [IN] the y position in pixels. + */ + void setElementPosition(in nsIDOMElement aElement, in long aX, in long aY); + + /** + * returns the absolute z-index of a positioned element. Never returns 'auto'. + * @return the z-index of the element + * @param aElement [IN] the element. + */ + long getElementZIndex(in nsIDOMElement aElement); + + /** + * sets the z-index of an element. + * @param aElement [IN] the element + * @param aZorder [IN] the z-index + */ + void setElementZIndex(in nsIDOMElement aElement, in long aZorder); + + /** + * adds aChange to the z-index of an arbitrary element. + * @return the new z-index of the element + * @param aElement [IN] the element + * @param aChange [IN] relative change to apply to current z-index of + * the element + */ + long relativeChangeElementZIndex(in nsIDOMElement aElement, in long aChange); + + /* Other */ + + /** + * shows a grabber attached to an arbitrary element. The grabber is an image + * positioned on the left hand side of the top border of the element. Dragging + * and dropping it allows to change the element's absolute position in the + * document. See chrome://editor/content/images/grabber.gif + * @param aElement [IN] the element + */ + void showGrabberOnElement(in nsIDOMElement aElement); + + /** + * hide the grabber if it shown. + */ + void hideGrabber(); + + /** + * refreshes the grabber if it shown, possibly updating its position or + * even hiding it. + */ + void refreshGrabber(); + +}; + diff --git a/mozilla/editor/idl/nsIHTMLEditor.idl b/mozilla/editor/idl/nsIHTMLEditor.idl index 56c07e76c9a..eacff09db02 100644 --- a/mozilla/editor/idl/nsIHTMLEditor.idl +++ b/mozilla/editor/idl/nsIHTMLEditor.idl @@ -43,6 +43,7 @@ #include "nsIAtom.idl" interface nsISupportsArray; +interface nsISelection; interface nsIContentFilter; %{C++ @@ -434,108 +435,108 @@ interface nsIHTMLEditor : nsISupports void align(in AString aAlign); /** - * Return the input node or a parent matching the given aTagName, - * starting the search at the supplied node. - * An example of use is for testing if a node is in a table cell - * given a selection anchor node. - * - * @param aTagName The HTML tagname - * Special input values: - * Use "href" to get a link node - * (an "A" tag with the "href" attribute set) - * Use "anchor" or "namedanchor" to get a named anchor node - * (an "A" tag with the "name" attribute set) - * Use "list" to get an OL, UL, or DL list node - * Use "td" to get either a TD or TH cell node - * - * @param aNode The node in the document to start the search. - * If it is null, the anchor node of the current selection is used. - * @return NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found - * (passes NS_SUCCEEDED macro) - */ + * Return the input node or a parent matching the given aTagName, + * starting the search at the supplied node. + * An example of use is for testing if a node is in a table cell + * given a selection anchor node. + * + * @param aTagName The HTML tagname + * Special input values: + * Use "href" to get a link node + * (an "A" tag with the "href" attribute set) + * Use "anchor" or "namedanchor" to get a named anchor node + * (an "A" tag with the "name" attribute set) + * Use "list" to get an OL, UL, or DL list node + * Use "td" to get either a TD or TH cell node + * + * @param aNode The node in the document to start the search. + * If it is null, the anchor node of the current selection is used. + * @return NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found + * (passes NS_SUCCEEDED macro) + */ nsIDOMElement getElementOrParentByTagName(in AString aTagName, in nsIDOMNode aNode); /** - * Return an element only if it is the only node selected, - * such as an image, horizontal rule, etc. - * The exception is a link, which is more like a text attribute: - * The Anchor tag is returned if the selection is within the textnode(s) - * that are children of the "A" node. - * This could be a collapsed selection, i.e., a caret - * within the link text. - * - * @param aTagName The HTML tagname or and empty string - * to get any element (but only if it is the only element selected) - * Special input values for Links and Named anchors: - * Use "href" to get a link node - * (an "A" tag with the "href" attribute set) - * Use "anchor" or "namedanchor" to get a named anchor node - * (an "A" tag with the "name" attribute set) - * @return NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found - * (passes NS_SUCCEEDED macro) - */ + * Return an element only if it is the only node selected, + * such as an image, horizontal rule, etc. + * The exception is a link, which is more like a text attribute: + * The Anchor tag is returned if the selection is within the textnode(s) + * that are children of the "A" node. + * This could be a collapsed selection, i.e., a caret + * within the link text. + * + * @param aTagName The HTML tagname or and empty string + * to get any element (but only if it is the only element selected) + * Special input values for Links and Named anchors: + * Use "href" to get a link node + * (an "A" tag with the "href" attribute set) + * Use "anchor" or "namedanchor" to get a named anchor node + * (an "A" tag with the "name" attribute set) + * @return NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found + * (passes NS_SUCCEEDED macro) + */ nsIDOMElement getSelectedElement(in AString aTagName); /** - * Output the contents of the section as text/HTML format - */ + * Output the contents of the section as text/HTML format + */ AString getHeadContentsAsHTML(); /** - * Replace all children of with string of HTML source - */ + * Replace all children of with string of HTML source + */ void replaceHeadContentsWithHTML(in AString aSourceToInsert); /** - * Return a new element with default attribute values - * - * This does not rely on the selection, and is not sensitive to context. - * - * Used primarily to supply new element for various insert element dialogs - * (Image, Link, NamedAnchor, Table, and HorizontalRule - * are the only returned elements as of 7/25/99) - * - * @param aTagName The HTML tagname - * Special input values for Links and Named anchors: - * Use "href" to get a link node - * (an "A" tag with the "href" attribute set) - * Use "anchor" or "namedanchor" to get a named anchor node - * (an "A" tag with the "name" attribute set) - * @return The new element created. - */ + * Return a new element with default attribute values + * + * This does not rely on the selection, and is not sensitive to context. + * + * Used primarily to supply new element for various insert element dialogs + * (Image, Link, NamedAnchor, Table, and HorizontalRule + * are the only returned elements as of 7/25/99) + * + * @param aTagName The HTML tagname + * Special input values for Links and Named anchors: + * Use "href" to get a link node + * (an "A" tag with the "href" attribute set) + * Use "anchor" or "namedanchor" to get a named anchor node + * (an "A" tag with the "name" attribute set) + * @return The new element created. + */ nsIDOMElement createElementWithDefaults(in AString aTagName); /** - * Insert an link element as the parent of the current selection - * - * @param aElement An "A" element with a non-empty "href" attribute - */ + * Insert an link element as the parent of the current selection + * + * @param aElement An "A" element with a non-empty "href" attribute + */ void insertLinkAroundSelection(in nsIDOMElement aAnchorElement); /** - * Set the value of the "bgcolor" attribute on the document's element - * - * @param aColor The HTML color string, such as "#ffccff" or "yellow" - */ + * Set the value of the "bgcolor" attribute on the document's element + * + * @param aColor The HTML color string, such as "#ffccff" or "yellow" + */ void setBackgroundColor(in AString aColor); /** - * Set an attribute on the document's element - * such as text, link, background colors - * - * 8/31/00 THIS ISN'T BEING USED? SHOULD WE DROP IT? - * - * @param aAttr The attribute to be set - * @param aValue The value of the attribute - */ + * Set an attribute on the document's element + * such as text, link, background colors + * + * 8/31/00 THIS ISN'T BEING USED? SHOULD WE DROP IT? + * + * @param aAttr The attribute to be set + * @param aValue The value of the attribute + */ void setBodyAttribute(in AString aAttr, in AString aValue); /** - * XXX Used to suppress spurious drag/drop events to workaround bug 50703 - * Don't use this method! It will go away after first release! - */ + * XXX Used to suppress spurious drag/drop events to workaround bug 50703 + * Don't use this method! It will go away after first release! + */ void ignoreSpuriousDragEvent(in boolean aIgnoreSpuriousDragEvent); /** @@ -548,29 +549,63 @@ interface nsIHTMLEditor : nsISupports nsISupportsArray getLinkedObjects(); /** - * A boolean which is true is the HTMLEditor has been instantiated - * with CSS knowledge and if the CSS pref is currently checked - * - * @return true if CSS handled and enabled - */ + * A boolean which is true is the HTMLEditor has been instantiated + * with CSS knowledge and if the CSS pref is currently checked + * + * @return true if CSS handled and enabled + */ attribute boolean isCSSEnabled; /** * Add listener for insertion override * @param inFilter function which callers want called during insertion */ - void addInsertionListener(in nsIContentFilter inFilter); /** * Remove listener for insertion override * @param inFilter function which callers do not want called during insertion */ - void removeInsertionListener(in nsIContentFilter inFilter); + /** + * parse a string containing CSS declarations and returns a DOM CSSStyleRule + * @return a DOM CSSStyleRule + * @param aString [IN] a string containing CSS declarations + */ nsIDOMCSSStyleRule parseStyleAttrIntoCSSRule(in AString aString); + /** + * Returns an anonymous nsDOMElement of type aTag, + * child of aParentNode. If aIsCreatedHidden is true, the class + * "hidden" is added to the created element. If aAnonClass is not + * the empty string, it becomes the value of the attribute "_moz_anonclass" + * @return a DOM Element + * @param aTag [IN] a string representing the desired type of + * the element to create + * @param aParentNode [IN] the parent node of the created anonymous + * element + * @param aAnonClass [IN] contents of the _moz_anonclass attribute + * @param aIsCreatedHidden [IN] a boolean specifying if the class "hidden" + * is to be added to the created anonymous + * element + */ + nsIDOMElement createAnonymousElement(in AString aTag, in nsIDOMNode aParentNode, + in AString aAnonClass, in boolean aIsCreatedHidden); + + /** + * returns the deepest container of the selection + * @return a DOM Element + */ + nsIDOMElement getSelectionContainer(); + + /** + * Checks if the anonymous nodes created by the HTML editor have to be + * refreshed or hidden depending on a possible new state of the selection + * @param aSelection [IN] a selection + */ + void checkSelectionStateForAnonymousButtons(in nsISelection aSelection); + boolean isAnonymousElement(in nsIDOMElement aElement); }; diff --git a/mozilla/editor/idl/nsIHTMLInlineTableEditor.idl b/mozilla/editor/idl/nsIHTMLInlineTableEditor.idl new file mode 100644 index 00000000000..addd59eb1a2 --- /dev/null +++ b/mozilla/editor/idl/nsIHTMLInlineTableEditor.idl @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Glazman (glazman@netscape.com) (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "domstubs.idl" + +[scriptable, uuid(eda2e65c-a758-451f-9b05-77cb8de74ed2)] + +interface nsIHTMLInlineTableEditor : nsISupports +{ + /** + * boolean indicating if inline table editing is enabled in the editor. + * When inline table editing is enabled, and when the selection is + * contained in a table cell, special buttons allowing to add/remove + * a line/column are available on the cell's border. + */ + attribute boolean inlineTableEditingEnabled; + + /** + * Shows inline table editing UI around a table cell + * @param aCell [IN] a DOM Element being a table cell, td or th + */ + void showInlineTableEditingUI(in nsIDOMElement aCell); + + /** + * Hide all inline table editing UI + */ + void hideInlineTableEditingUI(); + + /** + * Modifies the table containing the selection according to the + * activation of an inline table editing UI element + * @param aUIAnonymousElement [IN] the inline table editing UI element + */ + void doInlineTableEditingAction(in nsIDOMElement aUIAnonymousElement); + + /** + * Refresh already visible inline table editing UI + */ + void refreshInlineTableEditingUI(); +}; + diff --git a/mozilla/editor/idl/nsIHTMLObjectResizeListener.idl b/mozilla/editor/idl/nsIHTMLObjectResizeListener.idl new file mode 100644 index 00000000000..912fbca07e5 --- /dev/null +++ b/mozilla/editor/idl/nsIHTMLObjectResizeListener.idl @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Glazman (glazman@netscape.com) (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "domstubs.idl" + +[scriptable, uuid(27b00295-349c-429f-ad0c-87b859e77130)] + +interface nsIHTMLObjectResizeListener : nsISupports +{ + /** + * Listener's callback called by the editor when the user + * starts resizing an element + * @param aElement [IN] the element + */ + void onStartResizing(in nsIDOMElement aElement); + + /** + * Listener's callback called by the editor when the user + * has finalized the resizing of an element + * @param aElement [IN] the element that was resized + * @param aOldWidth [IN] the width of the element before resizing + * @param aOldHeight [IN] the height of the element before resizing + * @param aNewWidth [IN] the width of the element after resizing + * @param aNewHeight [IN] the height of the element after resizing + */ + void onEndResizing(in nsIDOMElement aElement, + in long aOldWidth, in long aOldHeight, + in long aNewWidth, in long aNewHeight); + +}; diff --git a/mozilla/editor/idl/nsIHTMLObjectResizer.idl b/mozilla/editor/idl/nsIHTMLObjectResizer.idl index 06adba0dc17..b1b758b859e 100644 --- a/mozilla/editor/idl/nsIHTMLObjectResizer.idl +++ b/mozilla/editor/idl/nsIHTMLObjectResizer.idl @@ -41,6 +41,8 @@ #include "nsIAtom.idl" #include "nsISelection.idl" +interface nsIHTMLObjectResizeListener; + [scriptable, uuid(b0338f6c-ded3-4c39-a953-56e8bae494f5)] interface nsIHTMLObjectResizer : nsISupports @@ -57,18 +59,69 @@ interface nsIHTMLObjectResizer : nsISupports const short eBottom = 6; const short eBottomRight = 7; + /** + * the element currently displaying resizers + */ readonly attribute nsIDOMElement resizedObject; - attribute boolean isImageResizingEnabled; - void getResizedObjectSize(out long aWidth, out long aHeight); + /** + * a boolean indicating if object resizing is enabled in the editor + */ + attribute boolean objectResizingEnabled; + + /** + * Shows active resizers around an element's frame + * @param aResizedElement [IN] a DOM Element + */ void showResizers(in nsIDOMElement aResizedElement); + + /** + * Hide resizers if they are visible + */ void hideResizers(); + + /** + * Refresh visible resizers + */ void refreshResizers(); + + /** + * event callback when a mouse button is pressed + * @param aX [IN] horizontal position of the pointer + * @param aY [IN] vertical position of the pointer + * @param aTarget [IN] the element triggering the event + */ void mouseDown(in long aX, in long aY, - in nsIDOMElement aResizedObject); + in nsIDOMElement aTarget); + + /** + * event callback when a mouse button is released + * @param aX [IN] horizontal position of the pointer + * @param aY [IN] vertical position of the pointer + * @param aTarget [IN] the element triggering the event + */ void mouseUp(in long aX, in long aY, - in nsIDOMElement aResizedObject); + in nsIDOMElement aTarget); + + /** + * event callback when the mouse pointer is moved + * @param aMouseEvent [IN] the event + */ void mouseMove(in nsIDOMEvent aMouseEvent); - void checkResizingState(in nsISelection aSelection); + + /* Event Listeners */ + + /** + * Creates a resize listener that can be used to get notifications + * that the user started to resize an object or finalized such an operation + * @param aListener [IN] an instance of nsIHTMLObjectResizeListener + */ + void addObjectResizeEventListener(in nsIHTMLObjectResizeListener aListener); + + /** + * Deletes a resize listener + * @param aListener [IN] an instance of nsIHTMLObjectResizeListener + */ + void removeObjectResizeEventListener(in nsIHTMLObjectResizeListener aListener); }; diff --git a/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h b/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h index 83e36accdb8..d4ffeea835b 100644 --- a/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h +++ b/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h @@ -135,6 +135,7 @@ EDITOR_ATOM(size, "size") EDITOR_ATOM(cssBackgroundColor, "background-color") EDITOR_ATOM(cssBackgroundImage, "background-image") EDITOR_ATOM(cssBorder, "border") +EDITOR_ATOM(cssBottom, "bottom") EDITOR_ATOM(cssCaptionSide, "caption-side") EDITOR_ATOM(cssColor, "color") EDITOR_ATOM(cssFloat, "float") @@ -147,12 +148,15 @@ EDITOR_ATOM(cssListStyleType, "list-style-type") EDITOR_ATOM(cssLeft, "left") EDITOR_ATOM(cssMarginRight, "margin-right") EDITOR_ATOM(cssMarginLeft, "margin-left") +EDITOR_ATOM(cssPosition, "position") +EDITOR_ATOM(cssRight, "right") EDITOR_ATOM(cssTextAlign, "text-align") EDITOR_ATOM(cssTextDecoration, "text-decoration") EDITOR_ATOM(cssTop, "top") EDITOR_ATOM(cssVerticalAlign, "vertical-align") EDITOR_ATOM(cssWhitespace, "white-space") EDITOR_ATOM(cssWidth, "width") +EDITOR_ATOM(cssZIndex, "z-index") EDITOR_ATOM(cssMozUserSelect, "-moz-user-select") diff --git a/mozilla/editor/libeditor/html/Makefile.in b/mozilla/editor/libeditor/html/Makefile.in index 6e8e67da97e..a7933992625 100644 --- a/mozilla/editor/libeditor/html/Makefile.in +++ b/mozilla/editor/libeditor/html/Makefile.in @@ -49,6 +49,8 @@ REQUIRES = xpcom \ CPPSRCS = \ nsEditProperty.cpp \ + nsHTMLAbsPosition.cpp \ + nsHTMLAnonymousUtils.cpp \ nsHTMLDataTransfer.cpp \ nsHTMLCSSUtils.cpp \ nsHTMLEditor.cpp \ @@ -57,6 +59,7 @@ CPPSRCS = \ nsHTMLEditUtils.cpp \ nsHTMLObjectResizer.cpp \ nsHTMLEditorMouseListener.cpp \ + nsHTMLInlineTableEditor.cpp \ nsHTMLURIRefObject.cpp \ nsTableEditor.cpp \ nsWSRunObject.cpp \ diff --git a/mozilla/editor/libeditor/html/nsHTMLAbsPosition.cpp b/mozilla/editor/libeditor/html/nsHTMLAbsPosition.cpp new file mode 100644 index 00000000000..12679e5005c --- /dev/null +++ b/mozilla/editor/libeditor/html/nsHTMLAbsPosition.cpp @@ -0,0 +1,757 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Glazman (glazman@netscape.com) (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "nsHTMLEditor.h" + +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIEditor.h" +#include "nsIPresShell.h" + +#include "nsISelection.h" + +#include "nsTextEditUtils.h" +#include "nsEditorUtils.h" +#include "nsHTMLEditUtils.h" +#include "nsTextEditRules.h" +#include "nsIHTMLEditRules.h" + +#include "nsIDOMHTMLElement.h" +#include "nsIDOMNSHTMLElement.h" +#include "nsIDOMNodeList.h" + +#include "nsIDOMEventTarget.h" +#include "nsIDOMEventReceiver.h" + +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsIServiceManager.h" + +#include "nsIDOMCSSValue.h" +#include "nsIDOMCSSPrimitiveValue.h" +#include "nsIDOMRGBColor.h" + +#define BLACK_BG_RGB_TRIGGER 0xd0 + +NS_IMETHODIMP +nsHTMLEditor::AbsolutePositionSelection(PRBool aEnabled) +{ + nsAutoEditBatch beginBatching(this); + nsAutoRules beginRulesSniffing(this, + aEnabled ? kOpSetAbsolutePosition : + kOpRemoveAbsolutePosition, + nsIEditor::eNext); + + // Find out if the selection is collapsed: + nsCOMPtr selection; + nsresult res = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; + + nsTextRulesInfo ruleInfo(aEnabled ? + nsTextEditRules::kSetAbsolutePosition : + nsTextEditRules::kRemoveAbsolutePosition); + PRBool cancel, handled; + res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled); + if (NS_FAILED(res) || cancel) + return res; + + return mRules->DidDoAction(selection, &ruleInfo, res); +} + +NS_IMETHODIMP +nsHTMLEditor::GetAbsolutelyPositionedSelectionContainer(nsIDOMElement **_retval) +{ + nsCOMPtr element; + nsresult res = GetSelectionContainer(getter_AddRefs(element)); + if (NS_FAILED(res)) return res; + + nsAutoString positionStr; + nsCOMPtr node = do_QueryInterface(element); + nsCOMPtr resultNode; + + do { + res = mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssPosition, + positionStr); + if (NS_FAILED(res)) return res; + if (positionStr.Equals(NS_LITERAL_STRING("absolute"))) + resultNode = node; + else { + nsCOMPtr parentNode; + res = node->GetParentNode(getter_AddRefs(parentNode)); + if (NS_FAILED(res)) return res; + node.swap(parentNode); + } + } while (!resultNode && + !nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("html"))); + + element = do_QueryInterface(resultNode ); + *_retval = element; + NS_IF_ADDREF(*_retval); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::GetSelectionContainerAbsolutelyPositioned(PRBool *aIsSelectionContainerAbsolutelyPositioned) +{ + *aIsSelectionContainerAbsolutelyPositioned = (mAbsolutelyPositionedObject != nsnull); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::GetAbsolutePositioningEnabled(PRBool * aIsEnabled) +{ + *aIsEnabled = mIsAbsolutelyPositioningEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::SetAbsolutePositioningEnabled(PRBool aIsEnabled) +{ + mIsAbsolutelyPositioningEnabled = aIsEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::RelativeChangeElementZIndex(nsIDOMElement * aElement, + PRInt32 aChange, + PRInt32 * aReturn) +{ + NS_ENSURE_ARG_POINTER(aElement); + NS_ENSURE_ARG_POINTER(aReturn); + if (!aChange) // early way out, no change + return NS_OK; + + PRInt32 zIndex; + nsresult res = GetElementZIndex(aElement, &zIndex); + if (NS_FAILED(res)) return res; + + zIndex = PR_MAX(zIndex + aChange, 0); + SetElementZIndex(aElement, zIndex); + *aReturn = zIndex; + + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::SetElementZIndex(nsIDOMElement * aElement, + PRInt32 aZindex) +{ + NS_ENSURE_ARG_POINTER(aElement); + + nsAutoString zIndexStr; + zIndexStr.AppendInt(aZindex); + + mHTMLCSSUtils->SetCSSProperty(aElement, + nsEditProperty::cssZIndex, + zIndexStr, + PR_FALSE); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::RelativeChangeZIndex(PRInt32 aChange) +{ + nsAutoEditBatch beginBatching(this); + nsAutoRules beginRulesSniffing(this, + (aChange < 0) ? kOpDecreaseZIndex : + kOpIncreaseZIndex, + nsIEditor::eNext); + + // Find out if the selection is collapsed: + nsCOMPtr selection; + nsresult res = GetSelection(getter_AddRefs(selection)); + if (NS_FAILED(res)) return res; + if (!selection) return NS_ERROR_NULL_POINTER; + nsTextRulesInfo ruleInfo((aChange < 0) ? nsTextEditRules::kDecreaseZIndex: + nsTextEditRules::kIncreaseZIndex); + PRBool cancel, handled; + res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled); + if (cancel || NS_FAILED(res)) + return res; + + return mRules->DidDoAction(selection, &ruleInfo, res); +} + +NS_IMETHODIMP +nsHTMLEditor::GetElementZIndex(nsIDOMElement * aElement, + PRInt32 * aZindex) +{ + nsAutoString zIndexStr; + *aZindex = 0; + nsCOMPtr node = do_QueryInterface(aElement); + nsresult res = mHTMLCSSUtils->GetSpecifiedProperty(node, + nsEditProperty::cssZIndex, + zIndexStr); + if (NS_FAILED(res)) return res; + if (zIndexStr.Equals(NS_LITERAL_STRING("auto"))) { + // we have to look at the positioned ancestors + // cf. CSS 2 spec section 9.9.1 + nsCOMPtr parentNode; + res = node->GetParentNode(getter_AddRefs(parentNode)); + if (NS_FAILED(res)) return res; + node = parentNode; + nsAutoString positionStr; + while (node && + zIndexStr.Equals(NS_LITERAL_STRING("auto")) && + !nsTextEditUtils::IsBody(node)) { + res = mHTMLCSSUtils->GetComputedProperty(node, + nsEditProperty::cssPosition, + positionStr); + if (NS_FAILED(res)) return res; + if (positionStr.Equals(NS_LITERAL_STRING("absolute"))) { + // ah, we found one, what's its z-index ? If its z-index is auto, + // we have to continue climbing the document's tree + res = mHTMLCSSUtils->GetComputedProperty(node, + nsEditProperty::cssZIndex, + zIndexStr); + if (NS_FAILED(res)) return res; + } + res = node->GetParentNode(getter_AddRefs(parentNode)); + if (NS_FAILED(res)) return res; + node = parentNode; + } + } + + if (!zIndexStr.Equals(NS_LITERAL_STRING("auto"))) { + PRInt32 errorCode; + *aZindex = zIndexStr.ToInteger(&errorCode); + } + + return NS_OK; +} + +nsresult +nsHTMLEditor::CreateGrabber(nsIDOMNode * aParentNode, nsIDOMElement ** aReturn) +{ + // let's create a grabber through the element factory + nsresult res = CreateAnonymousElement(NS_LITERAL_STRING("span"), + aParentNode, + NS_LITERAL_STRING("mozGrabber"), + PR_FALSE, + aReturn); + + if (!*aReturn) + return NS_ERROR_FAILURE; + + // add the mouse listener so we can detect a click on a resizer + nsCOMPtr evtTarget(do_QueryInterface(*aReturn)); + evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMouseListenerP, PR_FALSE); + + return res; +} + +NS_IMETHODIMP +nsHTMLEditor::RefreshGrabber() +{ + NS_ENSURE_TRUE(mAbsolutelyPositionedObject, NS_ERROR_NULL_POINTER); + + nsresult res = GetPositionAndDimensions(mAbsolutelyPositionedObject, + mPositionedObjectX, + mPositionedObjectY, + mPositionedObjectWidth, + mPositionedObjectHeight, + mPositionedObjectBorderLeft, + mPositionedObjectBorderTop, + mPositionedObjectMarginLeft, + mPositionedObjectMarginTop); + + if (NS_FAILED(res)) return res; + + SetAnonymousElementPosition(mPositionedObjectX+12, + mPositionedObjectY-14, + mGrabber); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::HideGrabber() +{ + nsresult res = + mAbsolutelyPositionedObject->RemoveAttribute(NS_LITERAL_STRING("_moz_abspos")); + if (NS_FAILED(res)) return res; + + mAbsolutelyPositionedObject = nsnull; + NS_ENSURE_TRUE(mGrabber, NS_ERROR_NULL_POINTER); + + // get the presshell's document observer interface. + + if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr docObserver(do_QueryInterface(ps)); + if (!docObserver) return NS_ERROR_FAILURE; + + // get the root content node. + + nsCOMPtr bodyElement; + res = GetRootElement(getter_AddRefs(bodyElement)); + if (NS_FAILED(res)) return res; + if (!bodyElement) return NS_ERROR_NULL_POINTER; + + nsCOMPtr bodyContent = do_QueryInterface(bodyElement); + if (!bodyContent) return res; + + DeleteRefToAnonymousNode(mGrabber, bodyContent, docObserver); + mGrabber = nsnull; + DeleteRefToAnonymousNode(mPositioningShadow, bodyContent, docObserver); + mPositioningShadow = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::ShowGrabberOnElement(nsIDOMElement * aElement) +{ + NS_ENSURE_ARG_POINTER(aElement); + + nsAutoString classValue; + nsresult res = CheckPositionedElementBGandFG(aElement, classValue); + if (NS_FAILED(res)) return res; + + res = aElement->SetAttribute(NS_LITERAL_STRING("_moz_abspos"), + classValue); + if (NS_FAILED(res)) return res; + + // first, let's keep track of that element... + mAbsolutelyPositionedObject = aElement; + + nsCOMPtr bodyElement; + res = GetRootElement(getter_AddRefs(bodyElement)); + if (NS_FAILED(res)) return res; + if (!bodyElement) return NS_ERROR_NULL_POINTER; + + nsCOMPtr bodyNode( do_QueryInterface(bodyElement) ); + + res = CreateGrabber(bodyNode, getter_AddRefs(mGrabber)); + if (NS_FAILED(res)) return res; + // and set its position + return RefreshGrabber(); +} + +nsresult +nsHTMLEditor::StartMoving(nsIDOMElement *aHandle) +{ + nsCOMPtr bodyElement; + nsresult result = GetRootElement(getter_AddRefs(bodyElement)); + if (NS_FAILED(result)) return result; + if (!bodyElement) return NS_ERROR_NULL_POINTER; + + nsCOMPtr bodyNode( do_QueryInterface(bodyElement) ); + + // now, let's create the resizing shadow + result = CreateShadow(getter_AddRefs(mPositioningShadow), bodyNode, + mAbsolutelyPositionedObject); + if (NS_FAILED(result)) return result; + result = SetShadowPosition(mPositioningShadow, mAbsolutelyPositionedObject, + mPositionedObjectX, mPositionedObjectY); + if (NS_FAILED(result)) return result; + + // make the shadow appear + mPositioningShadow->RemoveAttribute(NS_LITERAL_STRING("class")); + + // position it + nsAutoString w, h; + w.AppendInt(mPositionedObjectWidth); + h.AppendInt(mPositionedObjectHeight); + mHTMLCSSUtils->SetCSSProperty(mPositioningShadow, + NS_LITERAL_STRING("width"), + w + NS_LITERAL_STRING("px")); + mHTMLCSSUtils->SetCSSProperty(mPositioningShadow, + NS_LITERAL_STRING("height"), + h + NS_LITERAL_STRING("px")); + + mIsMoving = PR_TRUE; + return result; +} + +void +nsHTMLEditor::SnapToGrid(PRInt32 & newX, PRInt32 & newY) +{ + if (mSnapToGridEnabled && mGridSize) { + newX = (PRInt32) floor( ((float)newX / (float)mGridSize) + 0.5f ) * mGridSize; + newY = (PRInt32) floor( ((float)newY / (float)mGridSize) + 0.5f ) * mGridSize; + } +} + +nsresult +nsHTMLEditor::GrabberClicked() +{ + // add a mouse move listener to the editor + nsresult res = NS_OK; + if (!mMouseMotionListenerP) { + mMouseMotionListenerP = new ResizerMouseMotionListener(this); + if (!mMouseMotionListenerP) {return NS_ERROR_NULL_POINTER;} + + nsCOMPtr erP; + res = GetDOMEventReceiver(getter_AddRefs(erP)); + if (NS_SUCCEEDED(res )) + { + res = erP->AddEventListenerByIID(mMouseMotionListenerP, NS_GET_IID(nsIDOMMouseMotionListener)); + NS_ASSERTION(NS_SUCCEEDED(res), "failed to register mouse motion listener"); + } + else + HandleEventListenerError(); + } + mGrabberClicked = PR_TRUE; + return res; +} + +nsresult +nsHTMLEditor::EndMoving() +{ + if (mPositioningShadow) { + if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr docObserver(do_QueryInterface(ps)); + if (!docObserver) return NS_ERROR_FAILURE; + + // get the root content node. + + nsCOMPtr bodyElement; + nsresult res = GetRootElement(getter_AddRefs(bodyElement)); + if (NS_FAILED(res)) return res; + if (!bodyElement) return NS_ERROR_NULL_POINTER; + + nsCOMPtr bodyContent( do_QueryInterface(bodyElement) ); + if (!bodyContent) return NS_ERROR_FAILURE; + + DeleteRefToAnonymousNode(mPositioningShadow, bodyContent, docObserver); + mPositioningShadow = nsnull; + } + nsCOMPtr erP; + nsresult res = GetDOMEventReceiver(getter_AddRefs(erP)); + + if (NS_SUCCEEDED(res) && erP && mMouseMotionListenerP) { + res = erP->RemoveEventListenerByIID(mMouseMotionListenerP, NS_GET_IID(nsIDOMMouseMotionListener)); + NS_ASSERTION(NS_SUCCEEDED(res), "failed to remove mouse motion listener"); + } + mMouseMotionListenerP = nsnull; + + return NS_OK; +} +nsresult +nsHTMLEditor::SetFinalPosition(PRInt32 aX, PRInt32 aY) +{ + nsresult res = EndMoving(); + mGrabberClicked = PR_FALSE; + mIsMoving = PR_FALSE; + if (NS_FAILED(res)) return res; + + // we have now to set the new width and height of the resized object + // we don't set the x and y position because we don't control that in + // a normal HTML layout + PRInt32 newX = mPositionedObjectX + aX - mOriginalX - (mPositionedObjectBorderLeft+mPositionedObjectMarginLeft); + PRInt32 newY = mPositionedObjectY + aY - mOriginalY - (mPositionedObjectBorderTop+mPositionedObjectMarginTop); + + SnapToGrid(newX, newY); + + nsAutoString x, y; + x.AppendInt(newX); + y.AppendInt(newY); + + // we want one transaction only from a user's point of view + nsAutoEditBatch batchIt(this); + + mHTMLCSSUtils->SetCSSProperty(mAbsolutelyPositionedObject, + nsEditProperty::cssTop, + y + NS_LITERAL_STRING("px"), + PR_FALSE); + mHTMLCSSUtils->SetCSSProperty(mAbsolutelyPositionedObject, + nsEditProperty::cssLeft, + x + NS_LITERAL_STRING("px"), + PR_FALSE); + // keep track of that size + mPositionedObjectX = newX; + mPositionedObjectY = newY; + + return RefreshResizers(); +} + +void +nsHTMLEditor::AddPositioningOffet(PRInt32 & aX, PRInt32 & aY) +{ + // Get the positioning offset + nsresult res; + nsCOMPtr prefBranch = + do_GetService(NS_PREFSERVICE_CONTRACTID, &res); + PRInt32 positioningOffset = 0; + if (NS_SUCCEEDED(res) && prefBranch) { + res = prefBranch->GetIntPref("editor.positioning.offset", &positioningOffset); + if (NS_FAILED(res)) // paranoia + positioningOffset = 0; + } + + aX += positioningOffset; + aY += positioningOffset; +} + +NS_IMETHODIMP +nsHTMLEditor::AbsolutelyPositionElement(nsIDOMElement * aElement, + PRBool aEnabled) +{ + NS_ENSURE_ARG_POINTER(aElement); + + nsAutoString positionStr; + nsCOMPtr node = do_QueryInterface(aElement); + mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssPosition, + positionStr); + PRBool isPositioned = (positionStr.Equals(NS_LITERAL_STRING("absolute"))); + + // nothing to do if the element is already in the state we want + if (isPositioned == aEnabled) + return NS_OK; + + nsAutoEditBatch batchIt(this); + nsresult res; + + if (aEnabled) { + PRInt32 x, y; + GetElementOrigin(aElement, x, y); + + mHTMLCSSUtils->SetCSSProperty(aElement, + nsEditProperty::cssPosition, + NS_LITERAL_STRING("absolute"), + PR_FALSE); + + AddPositioningOffet(x, y); + SnapToGrid(x, y); + SetElementPosition(aElement, x, y); + + // we may need to create a br if the positioned element is alone in its + // container + nsCOMPtr parentNode; + res = node->GetParentNode(getter_AddRefs(parentNode)); + if (NS_FAILED(res)) return res; + + nsCOMPtr childNodes; + res = parentNode->GetChildNodes(getter_AddRefs(childNodes)); + if (NS_FAILED(res)) return res; + if (!childNodes) return NS_ERROR_NULL_POINTER; + PRUint32 childCount; + res = childNodes->GetLength(&childCount); + if (NS_FAILED(res)) return res; + + if (childCount == 1) { + nsCOMPtr brNode; + res = CreateBR(parentNode, 0, address_of(brNode)); + } + } + else { + nsAutoString emptyStr; + + mHTMLCSSUtils->RemoveCSSProperty(aElement, + nsEditProperty::cssPosition, + emptyStr, PR_FALSE); + mHTMLCSSUtils->RemoveCSSProperty(aElement, + nsEditProperty::cssTop, + emptyStr, PR_FALSE); + mHTMLCSSUtils->RemoveCSSProperty(aElement, + nsEditProperty::cssLeft, + emptyStr, PR_FALSE); + mHTMLCSSUtils->RemoveCSSProperty(aElement, + nsEditProperty::cssZIndex, + emptyStr, PR_FALSE); + + if (!nsHTMLEditUtils::IsImage(node)) { + mHTMLCSSUtils->RemoveCSSProperty(aElement, + nsEditProperty::cssWidth, + emptyStr, PR_FALSE); + mHTMLCSSUtils->RemoveCSSProperty(aElement, + nsEditProperty::cssHeight, + emptyStr, PR_FALSE); + } + + PRBool hasStyleOrIdOrClass; + res = HasStyleOrIdOrClass(aElement, &hasStyleOrIdOrClass); + if (NS_FAILED(res)) return res; + if (!hasStyleOrIdOrClass && NodeIsType(node, NS_LITERAL_STRING("div"))) { + nsCOMPtr htmlRules = do_QueryInterface(mRules); + if (!htmlRules) return NS_ERROR_FAILURE; + res = htmlRules->MakeSureElemStartsOrEndsOnCR(aElement); + if (NS_FAILED(res)) return res; + res = RemoveContainer(node); + } + } + return res; +} + +NS_IMETHODIMP +nsHTMLEditor::SetSnapToGridEnabled(PRBool aEnabled) +{ + mSnapToGridEnabled = aEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::GetSnapToGridEnabled(PRBool * aIsEnabled) +{ + *aIsEnabled = mSnapToGridEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::SetGridSize(PRUint32 aSize) +{ + mGridSize = aSize; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::GetGridSize(PRUint32 * aSize) +{ + *aSize = mGridSize; + return NS_OK; +} + +// self-explanatory +NS_IMETHODIMP +nsHTMLEditor::SetElementPosition(nsIDOMElement *aElement, PRInt32 aX, PRInt32 aY) +{ + nsAutoString x, y; + x.AppendInt(aX); + y.AppendInt(aY); + + nsAutoEditBatch batchIt(this); + + mHTMLCSSUtils->SetCSSProperty(aElement, + nsEditProperty::cssLeft, + x + NS_LITERAL_STRING("px"), + PR_FALSE); + mHTMLCSSUtils->SetCSSProperty(aElement, + nsEditProperty::cssTop, + y + NS_LITERAL_STRING("px"), + PR_FALSE); + return NS_OK; +} + +// self-explanatory +NS_IMETHODIMP +nsHTMLEditor::GetPositionedElement(nsIDOMElement ** aReturn) +{ + *aReturn = mAbsolutelyPositionedObject; + NS_IF_ADDREF(*aReturn); + return NS_OK; +} + +nsresult +nsHTMLEditor::CheckPositionedElementBGandFG(nsIDOMElement * aElement, + nsAString & aReturn) +{ + // we are going to outline the positioned element and bring it to the + // front to overlap any other element intersecting with it. But + // first, let's see what's the background and foreground colors of the + // positioned element. + // if background-image computed value is 'none, + // If the background color is 'auto' and R G B values of the foreground are + // each above #d0, use a black background + // If the background color is 'auto' and at least one of R G B values of + // the foreground is below #d0, use a white background + // Otherwise don't change background/foreground + + aReturn.Truncate(); + + nsAutoString bgImageStr; + nsresult res = + mHTMLCSSUtils->GetComputedProperty(aElement, + nsEditProperty::cssBackgroundImage, + bgImageStr); + if (NS_FAILED(res)) return res; + if (bgImageStr.Equals(NS_LITERAL_STRING("none"))) { + nsAutoString bgColorStr; + res = + mHTMLCSSUtils->GetComputedProperty(aElement, + nsEditProperty::cssBackgroundColor, + bgColorStr); + if (NS_FAILED(res)) return res; + if (bgColorStr.Equals(NS_LITERAL_STRING("transparent"))) { + + nsCOMPtr viewCSS; + res = mHTMLCSSUtils->GetDefaultViewCSS(aElement, getter_AddRefs(viewCSS)); + if (NS_FAILED(res)) return res; + nsCOMPtr cssDecl; + res = viewCSS->GetComputedStyle(aElement, nsString(), getter_AddRefs(cssDecl)); + if (NS_FAILED(res)) return res; + // from these declarations, get the one we want and that one only + nsCOMPtr colorCssValue; + res = cssDecl->GetPropertyCSSValue(NS_LITERAL_STRING("color"), getter_AddRefs(colorCssValue)); + if (NS_FAILED(res)) return res; + + PRUint16 type; + res = colorCssValue->GetCssValueType(&type); + if (NS_FAILED(res)) return res; + if (nsIDOMCSSValue::CSS_PRIMITIVE_VALUE == type) { + nsCOMPtr val = do_QueryInterface(colorCssValue); + res = val->GetPrimitiveType(&type); + if (NS_FAILED(res)) return res; + if (nsIDOMCSSPrimitiveValue::CSS_RGBCOLOR == type) { + nsCOMPtr rgbColor; + res = val->GetRGBColorValue(getter_AddRefs(rgbColor)); + if (NS_FAILED(res)) return res; + nsCOMPtr red, green, blue; + float r, g, b; + res = rgbColor->GetRed(getter_AddRefs(red)); + if (NS_FAILED(res)) return res; + res = rgbColor->GetGreen(getter_AddRefs(green)); + if (NS_FAILED(res)) return res; + res = rgbColor->GetBlue(getter_AddRefs(blue)); + if (NS_FAILED(res)) return res; + res = red->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &r); + if (NS_FAILED(res)) return res; + res = green->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &g); + if (NS_FAILED(res)) return res; + res = blue->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &b); + if (NS_FAILED(res)) return res; + if (r >= BLACK_BG_RGB_TRIGGER && + g >= BLACK_BG_RGB_TRIGGER && + b >= BLACK_BG_RGB_TRIGGER) + aReturn = NS_LITERAL_STRING("black"); + else + aReturn = NS_LITERAL_STRING("white"); + return NS_OK; + } + } + } + } + + return NS_OK; +} diff --git a/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp b/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp new file mode 100644 index 00000000000..8e999684335 --- /dev/null +++ b/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp @@ -0,0 +1,395 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Glazman (glazman@netscape.com) (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsHTMLEditor.h" + +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIEditor.h" +#include "nsIPresShell.h" + +#include "nsISelection.h" + +#include "nsTextEditUtils.h" +#include "nsEditorUtils.h" +#include "nsHTMLEditUtils.h" +#include "nsTextEditRules.h" + +#include "nsIDOMHTMLElement.h" +#include "nsIDOMNSHTMLElement.h" + +#include "nsIDOMCSSValue.h" +#include "nsIDOMCSSPrimitiveValue.h" +#include "nsIDOMCSSStyleDeclaration.h" + +// retrieve an integer stored into a CSS computed float value +static PRInt32 GetCSSFloatValue(nsIDOMCSSStyleDeclaration * aDecl, + const nsAString & aProperty) +{ + NS_ENSURE_ARG_POINTER(aDecl); + + nsCOMPtr value; + // get the computed CSSValue of the property + nsresult res = aDecl->GetPropertyCSSValue(aProperty, getter_AddRefs(value)); + if (NS_FAILED(res) || !value) return 0; + + // check the type of the returned CSSValue; we handle here only + // pixel and enum types + nsCOMPtr val = do_QueryInterface(value); + PRUint16 type; + val->GetPrimitiveType(&type); + + float f; + switch (type) { + case nsIDOMCSSPrimitiveValue::CSS_PX: + // the value is in pixels, just get it + res = val->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_PX, &f); + if (NS_FAILED(res)) return 0; + break; + case nsIDOMCSSPrimitiveValue::CSS_IDENT: { + // the value is keyword, we have to map these keywords into + // numeric values + nsAutoString str; + res = val->GetStringValue(str); + if (str.Equals(NS_LITERAL_STRING("thin"))) + f = 1; + if (str.Equals(NS_LITERAL_STRING("medium"))) + f = 3; + if (str.Equals(NS_LITERAL_STRING("thick"))) + f = 5; + break; + } + default: + f = 0; + } + + return (PRInt32) f; +} + +// Returns in *aReturn an anonymous nsDOMElement of type aTag, +// child of aParentNode. If aIsCreatedHidden is true, the class +// "hidden" is added to the created element. If aAnonClass is not +// the empty string, it becomes the value of the attribute "_moz_anonclass" +nsresult +nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aParentNode, + const nsAString & aAnonClass, PRBool aIsCreatedHidden, + nsIDOMElement ** aReturn) +{ + NS_ENSURE_ARG_POINTER(aParentNode); + NS_ENSURE_ARG_POINTER(aReturn); + + nsCOMPtr parentContent( do_QueryInterface(aParentNode) ); + if (!parentContent) + return NS_OK; + + // Get the document + nsCOMPtr domDoc; + GetDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc = do_QueryInterface(domDoc); + if (!doc) return NS_ERROR_NULL_POINTER; + + // Get the pres shell + if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + + // Create a new node through the element factory + nsCOMPtr newContent; + nsresult res = CreateHTMLContent(aTag, getter_AddRefs(newContent)); + if (NS_FAILED(res)) return res; + + nsCOMPtr newElement = do_QueryInterface(newContent); + if (!newElement) + return NS_ERROR_FAILURE; + + // add the "hidden" class if needed + if (aIsCreatedHidden) { + res = newElement->SetAttribute(NS_LITERAL_STRING("class"), + NS_LITERAL_STRING("hidden")); + if (NS_FAILED(res)) return res; + } + + // add an _moz_anonclass attribute if needed + if (!aAnonClass.IsEmpty()) { + res = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"), + aAnonClass); + if (NS_FAILED(res)) return res; + } + + // establish parenthood of the element + newContent->SetNativeAnonymous(PR_TRUE); + newContent->SetParent(parentContent); + newContent->SetDocument(doc, PR_TRUE, PR_TRUE); + newContent->SetBindingParent(newContent); + // display the element + ps->RecreateFramesFor(newContent); + + *aReturn = newElement; + NS_IF_ADDREF(*aReturn); + return NS_OK; +} + +// Deletes all references to an anonymous element +void +nsHTMLEditor::DeleteRefToAnonymousNode(nsIDOMElement* aElement, + nsIContent * aParentContent, + nsIDocumentObserver * aDocObserver) +{ + // call ContentRemoved() for the anonymous content + // node so its references get removed from the frame manager's + // undisplay map, and its layout frames get destroyed! + + if (aElement) { + nsCOMPtr content = do_QueryInterface(aElement); + if (content) { + aDocObserver->ContentRemoved(nsnull, aParentContent, content, -1); + content->SetParent(nsnull); + content->SetBindingParent(nsnull); + content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + } + } +} + +// The following method is mostly called by a selection listener. When a +// selection change is notified, the method is called to check if resizing +// handles, a grabber and/or inline table editing UI need to be displayed +// or refreshed +NS_IMETHODIMP +nsHTMLEditor::CheckSelectionStateForAnonymousButtons(nsISelection * aSelection) +{ + NS_ENSURE_ARG_POINTER(aSelection); + + // early way out if all contextual UI extensions are disabled + if (!mIsObjectResizingEnabled && + !mIsAbsolutelyPositioningEnabled && + !mIsInlineTableEditingEnabled) + return NS_OK; + + nsCOMPtr focusElement; + // let's get the containing element of the selection + nsresult res = GetSelectionContainer(getter_AddRefs(focusElement)); + if (NS_FAILED(res)) return res; + + // what's its tag? + nsAutoString focusTagName; + res = focusElement->GetTagName(focusTagName); + if (NS_FAILED(res)) return res; + ToLowerCase(focusTagName); + nsCOMPtr focusTagAtom = getter_AddRefs(NS_NewAtom(focusTagName)); + + nsCOMPtr absPosElement; + if (mIsAbsolutelyPositioningEnabled) { + // Absolute Positioning support is enabled, is the selection contained + // in an absolutely positioned element ? + res = GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(absPosElement)); + if (NS_FAILED(res)) return res; + } + + nsCOMPtr cellElement; + if (mIsObjectResizingEnabled || mIsInlineTableEditingEnabled) { + // Resizing or Inline Table Editing is enabled, we need to check if the + // selection is contained in a table cell + res = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), + nsnull, + getter_AddRefs(cellElement)); + if (NS_FAILED(res)) return res; + } + + if (mIsObjectResizingEnabled && cellElement) { + // we are here because Resizing is enabled AND selection is contained in + // a cell + nsCOMPtr tableNode, cellNode = do_QueryInterface(cellElement); + // get the enclosing table + tableNode = GetEnclosingTable(cellNode); + if (nsEditProperty::img != focusTagAtom) { + // the element container of the selection is not an image, so we'll show + // the resizers around the table + focusElement = do_QueryInterface(tableNode); + focusTagAtom = nsEditProperty::table; + } + } + + // we allow resizers only around images, tables, and absolutely positioned + // elements. If we don't have image/table, let's look at the latter case. + if (nsEditProperty::img != focusTagAtom && + nsEditProperty::table != focusTagAtom) + focusElement = absPosElement; + + // at this point, focusElement contains the element for Resizing, + // cellElement contains the element for InlineTableEditing + // absPosElement contains the element for Positioning + + // first let's cancel old settings if needed + PRBool refreshResizing = (mResizedObject != nsnull); + PRBool refreshPositioning = (mAbsolutelyPositionedObject != nsnull); + PRBool refreshTableEditing = (mInlineEditedCell != nsnull); + + if (mIsAbsolutelyPositioningEnabled && mAbsolutelyPositionedObject && + absPosElement != mAbsolutelyPositionedObject) { + res = HideGrabber(); + if (NS_FAILED(res)) return res; + refreshPositioning = PR_FALSE; + } + + if (mIsObjectResizingEnabled && mResizedObject && + mResizedObject != focusElement) { + res = HideResizers(); + if (NS_FAILED(res)) return res; + refreshResizing = PR_FALSE; + } + + if (mIsInlineTableEditingEnabled && mInlineEditedCell && + mInlineEditedCell != cellElement) { + res = HideInlineTableEditingUI(); + if (NS_FAILED(res)) return res; + refreshTableEditing = PR_FALSE; + } + + // now, let's display all contextual UI for good + + if (mIsObjectResizingEnabled && focusElement) { + if (nsEditProperty::img == focusTagAtom) + mResizedObjectIsAnImage = PR_TRUE; + if (refreshResizing) + res = RefreshResizers(); + else + res = ShowResizers(focusElement); + if (NS_FAILED(res)) return res; + } + + if (mIsAbsolutelyPositioningEnabled && absPosElement) { + if (refreshPositioning) + res = RefreshGrabber(); + else + res = ShowGrabberOnElement(absPosElement); + if (NS_FAILED(res)) return res; + } + + if (mIsInlineTableEditingEnabled && cellElement) { + if (refreshTableEditing) + res = RefreshInlineTableEditingUI(); + else + res = ShowInlineTableEditingUI(cellElement); + } + + return res; +} + +// Resizing and Absolute Positioning need to know everything about the +// containing box of the element: position, size, margins, borders +nsresult +nsHTMLEditor::GetPositionAndDimensions(nsIDOMElement * aElement, + PRInt32 & aX, PRInt32 & aY, + PRInt32 & aW, PRInt32 & aH, + PRInt32 & aBorderLeft, + PRInt32 & aBorderTop, + PRInt32 & aMarginLeft, + PRInt32 & aMarginTop) +{ + NS_ENSURE_ARG_POINTER(aElement); + + // Is the element positioned ? let's check the cheap way first... + PRBool isPositioned = PR_FALSE; + nsresult res = aElement->HasAttribute(NS_LITERAL_STRING("_moz_abspos"), &isPositioned); + if (NS_FAILED(res)) return res; + if (!isPositioned) { + // hmmm... the expensive way now... + nsAutoString positionStr; + mHTMLCSSUtils->GetComputedProperty(aElement, nsEditProperty::cssPosition, + positionStr); + isPositioned = positionStr.Equals(NS_LITERAL_STRING("absolute")); + } + + if (isPositioned) { + // Yes, it is absolutely positioned + mResizedObjectIsAbsolutelyPositioned = PR_TRUE; + + nsCOMPtr viewCSS; + res = mHTMLCSSUtils->GetDefaultViewCSS(aElement, getter_AddRefs(viewCSS)); + if (NS_FAILED(res)) return res; + + nsAutoString empty; + nsCOMPtr cssDecl; + // Get the all the computed css styles attached to the element node + res = viewCSS->GetComputedStyle(aElement, empty, getter_AddRefs(cssDecl)); + if (NS_FAILED(res)) return res; + + aBorderLeft = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("border-left-width")); + aBorderTop = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("border-top-width")); + aMarginLeft = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("margin-left")); + aMarginTop = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("margin-top")); + + aX = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("left")) + + aMarginLeft + aBorderLeft; + aY = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("top")) + + aMarginTop + aBorderTop; + aW = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("width")); + aH = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("height")); + } + else { + mResizedObjectIsAbsolutelyPositioned = PR_FALSE; + nsCOMPtr nsElement = do_QueryInterface(aElement); + if (!nsElement) {return NS_ERROR_NULL_POINTER; } + + GetElementOrigin(aElement, aX, aY); + + res = nsElement->GetOffsetWidth(&aW); + if (NS_FAILED(res)) return res; + res = nsElement->GetOffsetHeight(&aH); + + aBorderLeft = 0; + aBorderTop = 0; + aMarginLeft = 0; + aMarginTop = 0; + } + return res; +} + +// self-explanatory +void +nsHTMLEditor::SetAnonymousElementPosition(PRInt32 aX, PRInt32 aY, nsIDOMElement *aElement) +{ + nsAutoString x, y; + x.AppendInt(aX); + y.AppendInt(aY); + mHTMLCSSUtils->SetCSSProperty(aElement, + NS_LITERAL_STRING("left"), + x + NS_LITERAL_STRING("px")); + mHTMLCSSUtils->SetCSSProperty(aElement, + NS_LITERAL_STRING("top"), + y + NS_LITERAL_STRING("px")); +} diff --git a/mozilla/editor/libeditor/html/nsHTMLCSSUtils.cpp b/mozilla/editor/libeditor/html/nsHTMLCSSUtils.cpp index b6225a3ef3e..d49092583e0 100644 --- a/mozilla/editor/libeditor/html/nsHTMLCSSUtils.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLCSSUtils.cpp @@ -1429,3 +1429,31 @@ nsHTMLCSSUtils::GetElementContainerOrSelf(nsIDOMNode * aNode, nsIDOMElement ** a NS_IF_ADDREF(*aElement); return NS_OK; } + +nsresult +nsHTMLCSSUtils::SetCSSProperty(nsIDOMElement * aElement, + const nsAString & aProperty, + const nsAString & aValue) +{ + nsCOMPtr cssDecl; + PRUint32 length = 0; + nsresult res = GetInlineStyles(aElement, getter_AddRefs(cssDecl), &length); + if (NS_FAILED(res)) return res; + + return cssDecl->SetProperty(aProperty, + aValue, + nsString()); +} +nsresult +nsHTMLCSSUtils::RemoveCSSProperty(nsIDOMElement * aElement, + const nsAString & aProperty) +{ + nsCOMPtr cssDecl; + PRUint32 length = 0; + nsresult res = GetInlineStyles(aElement, getter_AddRefs(cssDecl), &length); + if (NS_FAILED(res)) return res; + + nsAutoString returnString; + return cssDecl->RemoveProperty(aProperty, returnString); +} + diff --git a/mozilla/editor/libeditor/html/nsHTMLCSSUtils.h b/mozilla/editor/libeditor/html/nsHTMLCSSUtils.h index f380b73ebdd..5691db2b3e0 100644 --- a/mozilla/editor/libeditor/html/nsHTMLCSSUtils.h +++ b/mozilla/editor/libeditor/html/nsHTMLCSSUtils.h @@ -126,6 +126,19 @@ public: nsresult RemoveCSSProperty(nsIDOMElement * aElement, nsIAtom * aProperty, const nsAString & aPropertyValue, PRBool aSuppressTransaction); + /** directly adds/remove a CSS declaration to the STYLE atrribute carried by + * a given element without going through the txn manager + * + * @param aElement [IN] a DOM element + * @param aProperty [IN] a string containing the CSS property to set/remove + * @param aValue [IN] a string containing the new value of the CSS property + */ + nsresult SetCSSProperty(nsIDOMElement * aElement, + const nsAString & aProperty, + const nsAString & aValue); + nsresult RemoveCSSProperty(nsIDOMElement * aElement, + const nsAString & aProperty); + /** gets the specified/computed style value of a CSS property for a given node (or its element * ancestor if it is not an element) * @@ -294,6 +307,14 @@ public: */ nsresult GetElementContainerOrSelf(nsIDOMNode * aNode, nsIDOMElement ** aElement); + /** Gets the default DOMView for a given node + * + * @param aNode the node we want the default DOMView for + * @param aViewCSS [OUT] the default DOMViewCSS + */ + nsresult GetDefaultViewCSS(nsIDOMNode * aNode, nsIDOMViewCSS ** aViewCSS); + + private: /** retrieves the css property atom from an enum @@ -342,13 +363,6 @@ private: nsStringArray & aValueArray, PRBool aGetOrRemoveRequest); - /** Gets the default DOMView for a given node - * - * @param aNode the node we want the default DOMView for - * @param aViewCSS [OUT] the default DOMViewCSS - */ - nsresult GetDefaultViewCSS(nsIDOMNode * aNode, nsIDOMViewCSS ** aViewCSS); - /** creates a Transaction for setting or removing a css property * * @param aElement [IN] a DOM element diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp index da6503a5117..bb7e3bf8a39 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp @@ -600,6 +600,10 @@ nsHTMLEditRules::WillDoAction(nsISelection *aSelection, return WillIndent(aSelection, aCancel, aHandled); case kOutdent: return WillOutdent(aSelection, aCancel, aHandled); + case kSetAbsolutePosition: + return WillAbsolutePosition(aSelection, aCancel, aHandled); + case kRemoveAbsolutePosition: + return WillRemoveAbsolutePosition(aSelection, aCancel, aHandled); case kAlign: return WillAlign(aSelection, info->alignType, aCancel, aHandled); case kMakeBasicBlock: @@ -610,6 +614,10 @@ nsHTMLEditRules::WillDoAction(nsISelection *aSelection, return WillMakeDefListItem(aSelection, info->blockType, info->entireList, aCancel, aHandled); case kInsertElement: return WillInsert(aSelection, aCancel); + case kDecreaseZIndex: + return WillRelativeChangeZIndex(aSelection, -1, aCancel, aHandled); + case kIncreaseZIndex: + return WillRelativeChangeZIndex(aSelection, 1, aCancel, aHandled); } return nsTextEditRules::WillDoAction(aSelection, aInfo, aCancel, aHandled); } @@ -631,6 +639,11 @@ nsHTMLEditRules::DidDoAction(nsISelection *aSelection, case kOutdent: case kAlign: return DidMakeBasicBlock(aSelection, aInfo, aResult); + case kSetAbsolutePosition: { + nsresult rv = DidMakeBasicBlock(aSelection, aInfo, aResult); + if (NS_FAILED(rv)) return rv; + return DidAbsolutePosition(); + } } // default: pass thru to nsTextEditRules @@ -809,7 +822,7 @@ nsHTMLEditRules::GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign) res = GetPromotedRanges(selection, arrayOfRanges, kAlign); if (NS_FAILED(res)) return res; - // use these ranges to contruct a list of nodes to act on. + // use these ranges to construct a list of nodes to act on. nsCOMArray arrayOfNodes; res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, kAlign, PR_TRUE); if (NS_FAILED(res)) return res; @@ -4176,7 +4189,7 @@ nsHTMLEditRules::CreateStyleForInsertText(nsISelection *aSelection, nsIDOMDocume if (NS_FAILED(res)) return res; PropItem *item = nsnull; - // if we deleted selection then also apply cached styles + // if we deleted selection then also for cached styles if (mDidDeleteSelection && ((mTheAction == nsEditor::kOpInsertText ) || (mTheAction == nsEditor::kOpInsertIMEText) || @@ -5633,7 +5646,8 @@ nsHTMLEditRules::GetNodesForOperation(nsCOMArray& inArrayOfRanges, // indent/outdent already do something special for list items, but // we still need to make sure we dont act on table elements else if ( (inOperationType == kOutdent) || - (inOperationType == kIndent) ) + (inOperationType == kIndent) || + (inOperationType == kSetAbsolutePosition)) { PRInt32 listCount = outArrayOfNodes.Count(); for (i=listCount-1; i>=0; i--) @@ -5668,10 +5682,11 @@ nsHTMLEditRules::GetNodesForOperation(nsCOMArray& inArrayOfRanges, // post process the list to break up inline containers that contain br's. // but only for operations that might care, like making lists or para's... - if ( (inOperationType == kMakeBasicBlock) || - (inOperationType == kMakeList) || - (inOperationType == kAlign) || - (inOperationType == kIndent) || + if ( (inOperationType == kMakeBasicBlock) || + (inOperationType == kMakeList) || + (inOperationType == kAlign) || + (inOperationType == kSetAbsolutePosition) || + (inOperationType == kIndent) || (inOperationType == kOutdent) ) { PRInt32 listCount = outArrayOfNodes.Count(); @@ -6274,7 +6289,6 @@ nsHTMLEditRules::ReturnInHeader(nsISelection *aSelection, return res; } - /////////////////////////////////////////////////////////////////////////// // ReturnInParagraph: do the right thing for returns pressed in paragraphs // @@ -7440,7 +7454,7 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection // are we in a text node? nsCOMPtr textNode = do_QueryInterface(selNode); - if (textNode) + if (textNode) return NS_OK; // we LIKE it when we are in a text node. that RULZ // do we need to insert a special mozBR? We do if we are: @@ -7701,7 +7715,6 @@ nsHTMLEditRules::RemoveEmptyNodes() nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("u")) || nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("tt")) || nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("s")) || - nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("span")) || nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("strike")) || nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("big")) || nsTextEditUtils::NodeIsType(node, NS_LITERAL_STRING("small")) || @@ -8541,7 +8554,7 @@ nsHTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode, PRBool aStarts) return NS_OK; } -nsresult +NS_IMETHODIMP nsHTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode) { nsresult res = MakeSureElemStartsOrEndsOnCR(aNode, PR_FALSE); @@ -8665,3 +8678,274 @@ nsHTMLEditRules::RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, PRInt } return NS_OK; } + +// +// Support for Absolute Positioning +// + +nsresult +nsHTMLEditRules::WillAbsolutePosition(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled) +{ + if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } + nsresult res = WillInsert(aSelection, aCancel); + if (NS_FAILED(res)) return res; + + // initialize out param + // we want to ignore result of WillInsert() + *aCancel = PR_FALSE; + *aHandled = PR_TRUE; + + nsCOMPtr focusElement; + res = mHTMLEditor->GetSelectionContainer(getter_AddRefs(focusElement)); + if (focusElement) { + nsCOMPtr node = do_QueryInterface(focusElement); + if (mHTMLEditor->NodeIsType(node, nsEditProperty::img)) { + mNewBlock = node; + return NS_OK; + } + } + + res = NormalizeSelection(aSelection); + if (NS_FAILED(res)) return res; + nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); + + // convert the selection ranges into "promoted" selection ranges: + // this basically just expands the range to include the immediate + // block parent, and then further expands to include any ancestors + // whose children are all in the range + + nsCOMArray arrayOfRanges; + res = GetPromotedRanges(aSelection, arrayOfRanges, kSetAbsolutePosition); + if (NS_FAILED(res)) return res; + + // use these ranges to contruct a list of nodes to act on. + nsCOMArray arrayOfNodes; + res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, kSetAbsolutePosition); + if (NS_FAILED(res)) return res; + + NS_NAMED_LITERAL_STRING(divType, "div"); + + + // if nothing visible in list, make an empty block + if (ListIsEmptyLine(arrayOfNodes)) + { + nsCOMPtr parent, thePositionedDiv; + PRInt32 offset; + + // get selection location + res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parent), &offset); + if (NS_FAILED(res)) return res; + // make sure we can put a block here + res = SplitAsNeeded(&divType, address_of(parent), &offset); + if (NS_FAILED(res)) return res; + res = mHTMLEditor->CreateNode(divType, parent, offset, getter_AddRefs(thePositionedDiv)); + if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = thePositionedDiv; + // delete anything that was in the list of nodes + nsCOMPtr curNode = arrayOfNodes[0]; + while (curNode) + { + res = mHTMLEditor->DeleteNode(curNode); + if (NS_FAILED(res)) return res; + res = arrayOfNodes.RemoveObjectAt(0); + if (NS_FAILED(res)) return res; + curNode = arrayOfNodes[0]; + } + // put selection in new block + res = aSelection->Collapse(thePositionedDiv,0); + selectionResetter.Abort(); // to prevent selection reseter from overriding us. + *aHandled = PR_TRUE; + return res; + } + + // Ok, now go through all the nodes and put them in a blockquote, + // or whatever is appropriate. Wohoo! + PRInt32 i; + nsCOMPtr curParent, curPositionedDiv, curList, indentedLI, sibling; + PRInt32 listCount = arrayOfNodes.Count(); + for (i=0; i curNode = arrayOfNodes[i]; + + // Ignore all non-editable nodes. Leave them be. + if (!mHTMLEditor->IsEditable(curNode)) continue; + + PRInt32 offset; + res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset); + if (NS_FAILED(res)) return res; + + // some logic for putting list items into nested lists... + if (nsHTMLEditUtils::IsList(curParent)) + { + // check to see if curList is still appropriate. Which it is if + // curNode is still right after it in the same list. + if (curList) + { + sibling = nsnull; + mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling)); + } + + if (!curList || (sibling && sibling != curList) ) + { + nsAutoString listTag; + nsEditor::GetTagString(curParent,listTag); + ToLowerCase(listTag); + // create a new nested list of correct type + res = SplitAsNeeded(&listTag, address_of(curParent), &offset); + if (NS_FAILED(res)) return res; + if (!curPositionedDiv) { + PRInt32 parentOffset; + nsCOMPtr curParentParent; + res = nsEditor::GetNodeLocation(curParent, address_of(curParentParent), &parentOffset); + res = mHTMLEditor->CreateNode(divType, curParentParent, parentOffset, getter_AddRefs(curPositionedDiv)); + mNewBlock = curPositionedDiv; + } + res = mHTMLEditor->CreateNode(listTag, curPositionedDiv, -1, getter_AddRefs(curList)); + if (NS_FAILED(res)) return res; + // curList is now the correct thing to put curNode in + // remember our new block for postprocessing + // mNewBlock = curList; + } + // tuck the node into the end of the active list + res = mHTMLEditor->MoveNode(curNode, curList, -1); + if (NS_FAILED(res)) return res; + // forget curPositionedDiv, if any + // curPositionedDiv = nsnull; + } + + else // not a list item, use blockquote? + { + // if we are inside a list item, we dont want to blockquote, we want + // to sublist the list item. We may have several nodes listed in the + // array of nodes to act on, that are in the same list item. Since + // we only want to indent that li once, we must keep track of the most + // recent indented list item, and not indent it if we find another node + // to act on that is still inside the same li. + nsCOMPtr listitem=IsInListItem(curNode); + if (listitem) + { + if (indentedLI == listitem) continue; // already indented this list item + res = nsEditor::GetNodeLocation(listitem, address_of(curParent), &offset); + if (NS_FAILED(res)) return res; + // check to see if curList is still appropriate. Which it is if + // curNode is still right after it in the same list. + if (curList) + { + sibling = nsnull; + mHTMLEditor->GetPriorHTMLSibling(curNode, address_of(sibling)); + } + + if (!curList || (sibling && sibling != curList) ) + { + nsAutoString listTag; + nsEditor::GetTagString(curParent,listTag); + ToLowerCase(listTag); + // create a new nested list of correct type + res = SplitAsNeeded(&listTag, address_of(curParent), &offset); + if (NS_FAILED(res)) return res; + if (!curPositionedDiv) { + PRInt32 parentOffset; + nsCOMPtr curParentParent; + res = nsEditor::GetNodeLocation(curParent, address_of(curParentParent), &parentOffset); + res = mHTMLEditor->CreateNode(divType, curParentParent, parentOffset, getter_AddRefs(curPositionedDiv)); + mNewBlock = curPositionedDiv; + } + res = mHTMLEditor->CreateNode(listTag, curPositionedDiv, -1, getter_AddRefs(curList)); + if (NS_FAILED(res)) return res; + } + res = mHTMLEditor->MoveNode(listitem, curList, -1); + if (NS_FAILED(res)) return res; + // remember we indented this li + indentedLI = listitem; + } + + else + { + // need to make a div to put things in if we haven't already + + if (!curPositionedDiv) + { + if (nsHTMLEditUtils::IsDiv(curNode)) + { + curPositionedDiv = curNode; + mNewBlock = curPositionedDiv; + curList = nsnull; + continue; + } + res = SplitAsNeeded(&divType, address_of(curParent), &offset); + if (NS_FAILED(res)) return res; + res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curPositionedDiv)); + if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = curPositionedDiv; + // curPositionedDiv is now the correct thing to put curNode in + } + + // tuck the node into the end of the active blockquote + res = mHTMLEditor->MoveNode(curNode, curPositionedDiv, -1); + if (NS_FAILED(res)) return res; + // forget curList, if any + curList = nsnull; + } + } + } + return res; +} + +nsresult +nsHTMLEditRules::DidAbsolutePosition() +{ + nsCOMPtr absPosHTMLEditor = mHTMLEditor; + nsCOMPtr elt = do_QueryInterface(mNewBlock); + return absPosHTMLEditor->AbsolutelyPositionElement(elt, PR_TRUE); +} + +nsresult +nsHTMLEditRules::WillRemoveAbsolutePosition(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled) +{ + if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } + nsresult res = WillInsert(aSelection, aCancel); + if (NS_FAILED(res)) return res; + + // initialize out param + // we want to ignore aCancel from WillInsert() + *aCancel = PR_FALSE; + *aHandled = PR_TRUE; + + nsCOMPtr elt; + res = mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); + if (NS_FAILED(res)) return res; + + nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); + + nsCOMPtr absPosHTMLEditor = mHTMLEditor; + return absPosHTMLEditor->AbsolutelyPositionElement(elt, PR_FALSE); +} + +nsresult +nsHTMLEditRules::WillRelativeChangeZIndex(nsISelection *aSelection, + PRInt32 aChange, + PRBool *aCancel, + PRBool * aHandled) +{ + if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } + nsresult res = WillInsert(aSelection, aCancel); + if (NS_FAILED(res)) return res; + + // initialize out param + // we want to ignore aCancel from WillInsert() + *aCancel = PR_FALSE; + *aHandled = PR_TRUE; + + nsCOMPtr elt; + res = mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); + if (NS_FAILED(res)) return res; + + nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); + + nsCOMPtr absPosHTMLEditor = mHTMLEditor; + PRInt32 zIndex; + return absPosHTMLEditor->RelativeChangeElementZIndex(elt, aChange, &zIndex); +} diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.h b/mozilla/editor/libeditor/html/nsHTMLEditRules.h index 61960ad6c37..a9817ca5892 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditRules.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.h @@ -91,6 +91,7 @@ public: NS_IMETHOD GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent); NS_IMETHOD GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign); NS_IMETHOD GetParagraphState(PRBool *aMixed, nsAString &outFormat); + NS_IMETHOD MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode); // nsIEditActionListener methods @@ -164,9 +165,13 @@ protected: nsresult WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled); nsresult WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled); nsresult WillAlign(nsISelection *aSelection, const nsAString *alignType, PRBool *aCancel, PRBool *aHandled); + nsresult WillAbsolutePosition(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled); + nsresult WillRemoveAbsolutePosition(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled); + nsresult WillRelativeChangeZIndex(nsISelection *aSelection, PRInt32 aChange, PRBool *aCancel, PRBool * aHandled); nsresult WillMakeDefListItem(nsISelection *aSelection, const nsAString *aBlockType, PRBool aEntireList, PRBool *aCancel, PRBool *aHandled); nsresult WillMakeBasicBlock(nsISelection *aSelection, const nsAString *aBlockType, PRBool *aCancel, PRBool *aHandled); nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult); + nsresult DidAbsolutePosition(); nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType); nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType); PRBool IsFormatNode(nsIDOMNode *aNode); @@ -285,7 +290,6 @@ protected: PRBool ListIsEmptyLine(nsCOMArray &arrayOfNodes); nsresult RemoveAlignment(nsIDOMNode * aNode, const nsAString & aAlignType, PRBool aChildrenOnly); nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode, PRBool aStarts); - nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode); nsresult AlignBlock(nsIDOMElement * aElement, const nsAString * aAlignType, PRBool aContentsOnly); nsresult RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, PRInt8 aRelativeChange); diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 1aadec20fe3..6a4437cdfc7 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -170,10 +170,14 @@ nsHTMLEditor::nsHTMLEditor() , mTypeInState(nsnull) , mSelectedCellIndex(0) , mHTMLCSSUtils(nsnull) -, mIsImageResizingEnabled(PR_TRUE) // this can be overriden -, mIsShowingResizeHandles(PR_FALSE) +, mIsObjectResizingEnabled(PR_TRUE) , mIsResizing(PR_FALSE) -, mResizedObject(nsnull) +, mIsAbsolutelyPositioningEnabled(PR_TRUE) +, mIsMoving(PR_FALSE) +, mResizedObjectIsAbsolutelyPositioned(PR_FALSE) +, mIsInlineTableEditingEnabled(PR_TRUE) +, mSnapToGridEnabled(PR_FALSE) +, mGridSize(0) { mBoldAtom = getter_AddRefs(NS_NewAtom("b")); mItalicAtom = getter_AddRefs(NS_NewAtom("i")); @@ -225,7 +229,21 @@ nsHTMLEditor::~nsHTMLEditor() NS_IMPL_ADDREF_INHERITED(nsHTMLEditor, nsEditor) NS_IMPL_RELEASE_INHERITED(nsHTMLEditor, nsEditor) +NS_INTERFACE_MAP_BEGIN(nsHTMLEditor) + NS_INTERFACE_MAP_ENTRY(nsIHTMLEditor) + NS_INTERFACE_MAP_ENTRY(nsIPlaintextEditor) + NS_INTERFACE_MAP_ENTRY(nsIEditor) + NS_INTERFACE_MAP_ENTRY(nsIHTMLObjectResizer) + NS_INTERFACE_MAP_ENTRY(nsIHTMLAbsPosEditor) + NS_INTERFACE_MAP_ENTRY(nsIHTMLInlineTableEditor) + NS_INTERFACE_MAP_ENTRY(nsIEditorMailSupport) + NS_INTERFACE_MAP_ENTRY(nsITableEditor) + NS_INTERFACE_MAP_ENTRY(nsIEditorStyleSheets) + NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTMLEditor) +NS_INTERFACE_MAP_END +/* NS_IMETHODIMP nsHTMLEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (!aInstancePtr) @@ -248,6 +266,16 @@ NS_IMETHODIMP nsHTMLEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIHTMLAbsPosEditor))) { + *aInstancePtr = NS_STATIC_CAST(nsIHTMLAbsPosEditor*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIHTMLInlineTableEditor))) { + *aInstancePtr = NS_STATIC_CAST(nsIHTMLInlineTableEditor*, this); + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(NS_GET_IID(nsIEditorMailSupport))) { *aInstancePtr = NS_STATIC_CAST(nsIEditorMailSupport*, this); NS_ADDREF_THIS(); @@ -271,7 +299,7 @@ NS_IMETHODIMP nsHTMLEditor::QueryInterface(REFNSIID aIID, void** aInstancePtr) return nsEditor::QueryInterface(aIID, aInstancePtr); } - +*/ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags) @@ -302,6 +330,13 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc, // the HTML Editor is CSS-aware only in the case of Composer mCSSAware = (0 == aFlags); + // disable Composer-only features + if (aFlags & eEditorMailMask) + { + SetAbsolutePositioningEnabled(PR_FALSE); + SetSnapToGridEnabled(PR_FALSE); + } + // Init the HTML-CSS utils if (mHTMLCSSUtils) delete mHTMLCSSUtils; @@ -6172,11 +6207,110 @@ nsHTMLEditor::EndUpdateViewBatch() res = GetSelection(getter_AddRefs(selection)); if (NS_FAILED(res)) return res; if (!selection) return NS_ERROR_NOT_INITIALIZED; - res = CheckResizingState(selection); + res = CheckSelectionStateForAnonymousButtons(selection); } return res; } +NS_IMETHODIMP +nsHTMLEditor::IgnoreSpuriousDragEvent(PRBool aIgnoreSpuriousDragEvent) +{ + mIgnoreSpuriousDragEvent = aIgnoreSpuriousDragEvent; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::GetSelectionContainer(nsIDOMElement ** aReturn) +{ + nsCOMPtrselection; + nsresult res = GetSelection(getter_AddRefs(selection)); + // if we don't get the selection, just skip this + if (NS_FAILED(res) || !selection) return res; + + PRBool bCollapsed; + res = selection->GetIsCollapsed(&bCollapsed); + if (NS_FAILED(res)) return res; + + nsCOMPtr focusNode; + + if (bCollapsed) { + res = selection->GetFocusNode(getter_AddRefs(focusNode)); + if (NS_FAILED(res)) return res; + } + else { + + PRInt32 rangeCount; + res = selection->GetRangeCount(&rangeCount); + if (NS_FAILED(res)) return res; + + if (rangeCount == 1) { + + nsCOMPtr range; + res = selection->GetRangeAt(0, getter_AddRefs(range)); + if (NS_FAILED(res)) return res; + if (!range) return NS_ERROR_NULL_POINTER; + + nsCOMPtr startContainer, endContainer; + res = range->GetStartContainer(getter_AddRefs(startContainer)); + if (NS_FAILED(res)) return res; + res = range->GetEndContainer(getter_AddRefs(endContainer)); + if (NS_FAILED(res)) return res; + PRInt32 startOffset, endOffset; + res = range->GetStartOffset(&startOffset); + if (NS_FAILED(res)) return res; + res = range->GetEndOffset(&endOffset); + if (NS_FAILED(res)) return res; + + nsCOMPtr focusElement; + if (startContainer == endContainer && startOffset + 1 == endOffset) { + res = GetSelectedElement(NS_LITERAL_STRING(""), getter_AddRefs(focusElement)); + if (NS_FAILED(res)) return res; + if (focusElement) + focusNode = do_QueryInterface(focusElement); + } + if (!focusNode) { + res = range->GetCommonAncestorContainer(getter_AddRefs(focusNode)); + if (NS_FAILED(res)) return res; + } + } + else { + PRInt32 i; + nsCOMPtr range; + for (i = 0; i < rangeCount; i++) + { + res = selection->GetRangeAt(i, getter_AddRefs(range)); + if (NS_FAILED(res)) return res; + nsCOMPtr startContainer; + range->GetStartContainer(getter_AddRefs(startContainer)); + if (!focusNode) + focusNode = startContainer; + else if (focusNode != startContainer) { + res = startContainer->GetParentNode(getter_AddRefs(focusNode)); + if (NS_FAILED(res)) return res; + break; + } + } + } + } + + if (focusNode) { + PRUint16 nodeType; + focusNode->GetNodeType(&nodeType); + if (nsIDOMNode::TEXT_NODE == nodeType) { + nsCOMPtr parent; + res = focusNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(res)) return res; + focusNode = parent; + } + } + + nsCOMPtr focusElement = do_QueryInterface(focusNode); + *aReturn = focusElement; + NS_IF_ADDREF(*aReturn); + + return NS_OK; +} + NS_IMETHODIMP nsHTMLEditor::IsAnonymousElement(nsIDOMElement * aElement, PRBool * aReturn) { @@ -6185,3 +6319,4 @@ nsHTMLEditor::IsAnonymousElement(nsIDOMElement * aElement, PRBool * aReturn) *aReturn = content->IsNativeAnonymous(); return NS_OK; } + diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index 8d15b3e27a0..f0351e722ed 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -49,7 +49,6 @@ #include "nsITableEditor.h" #include "nsIEditorMailSupport.h" #include "nsIEditorStyleSheets.h" -#include "nsIDocumentObserver.h" #include "nsEditor.h" #include "nsIDOMElement.h" @@ -68,6 +67,11 @@ #include "nsVoidArray.h" #include "nsHTMLObjectResizer.h" +#include "nsIHTMLAbsPosEditor.h" +#include "nsIHTMLInlineTableEditor.h" +#include "nsIHTMLObjectResizeListener.h" + +#include "nsIDocumentObserver.h" #include "nsPoint.h" @@ -87,7 +91,9 @@ class nsIContentFilter; class nsHTMLEditor : public nsPlaintextEditor, public nsIHTMLEditor, public nsIHTMLObjectResizer, + public nsIHTMLAbsPosEditor, public nsITableEditor, + public nsIHTMLInlineTableEditor, public nsIEditorStyleSheets, public nsICSSLoaderObserver { @@ -111,7 +117,11 @@ public: kOpRemoveTextProperty = 3011, kOpHTMLPaste = 3012, kOpLoadHTML = 3013, - kOpResetTextProperties = 3014 + kOpResetTextProperties = 3014, + kOpSetAbsolutePosition = 3015, + kOpRemoveAbsolutePosition = 3016, + kOpDecreaseZIndex = 3017, + kOpIncreaseZIndex = 3018 }; enum ResizingRequestID @@ -139,111 +149,37 @@ public: NS_IMETHOD GetIsDocumentEditable(PRBool *aIsDocumentEditable); NS_IMETHODIMP BeginningOfDocument(); + /* ------------ nsIHTMLEditor methods -------------- */ + + NS_DECL_NSIHTMLEDITOR + /* ------------ nsIHTMLObjectResizer methods -------------- */ + /* -------- Implemented in nsHTMLObjectResizer.cpp -------- */ NS_DECL_NSIHTMLOBJECTRESIZER - /* ------------ nsIHTMLEditor methods -------------- */ - NS_IMETHOD UpdateBaseURL(); + /* ------------ nsIHTMLAbsPosEditor methods -------------- */ + /* -------- Implemented in nsHTMLAbsPosition.cpp --------- */ + NS_DECL_NSIHTMLABSPOSEDITOR + /* ------------ nsIHTMLInlineTableEditor methods -------------- */ + /* ------- Implemented in nsHTMLInlineTableEditor.cpp --------- */ + NS_DECL_NSIHTMLINLINETABLEEDITOR + + /* ------------ nsIHTMLEditor methods -------------- */ NS_IMETHOD CopyLastEditableChildStyles(nsIDOMNode *aPreviousBlock, nsIDOMNode *aNewBlock, nsIDOMNode **aOutBrNode); - NS_IMETHOD ParseStyleAttrIntoCSSRule(const nsAString& aString, - nsIDOMCSSStyleRule **_retval); - - NS_IMETHOD AddDefaultProperty(nsIAtom *aProperty, - const nsAString & aAttribute, - const nsAString & aValue); - - NS_IMETHOD RemoveDefaultProperty(nsIAtom *aProperty, - const nsAString & aAttribute, - const nsAString & aValue); - - NS_IMETHOD RemoveAllDefaultProperties(); - - NS_IMETHOD SetCSSInlineProperty(nsIAtom *aProperty, - const nsAString & aAttribute, - const nsAString & aValue); - - NS_IMETHOD SetInlineProperty(nsIAtom *aProperty, - const nsAString & aAttribute, - const nsAString & aValue); - - NS_IMETHOD GetInlineProperty(nsIAtom *aProperty, - const nsAString & aAttribute, - const nsAString & aValue, - PRBool *aFirst, - PRBool *aAny, - PRBool *aAll); - NS_IMETHOD GetInlinePropertyWithAttrValue(nsIAtom *aProperty, - const nsAString &aAttribute, - const nsAString &aValue, - PRBool *aFirst, - PRBool *aAny, - PRBool *aAll, - nsAString &outValue); - NS_IMETHOD RemoveAllInlineProperties(); - NS_IMETHOD RemoveInlineProperty(nsIAtom *aProperty, const nsAString & aAttribute); - NS_IMETHOD IncreaseFontSize(); - NS_IMETHOD DecreaseFontSize(); - - NS_IMETHOD PasteNoFormatting(PRInt32 aSelectionType); - NS_IMETHOD InsertHTML(const nsAString &aInputString); - NS_IMETHOD InsertHTMLWithContext(const nsAString & aInputString, - const nsAString & aContextStr, - const nsAString & aInfoStr, - const nsAString & aFlavor, - nsIDOMDocument *aSourceDoc, - nsIDOMNode *aDestinationNode, - PRInt32 aDestinationOffset, - PRBool aDeleteSelection); - NS_IMETHOD LoadHTML(const nsAString &aInputString); - NS_IMETHOD RebuildDocumentFromSource(const nsAString& aSourceString); - NS_IMETHOD InsertElementAtSelection(nsIDOMElement* aElement, PRBool aDeleteSelection); - - NS_IMETHOD SelectElement(nsIDOMElement* aElement); - NS_IMETHOD SetCaretAfterElement(nsIDOMElement* aElement); - - NS_IMETHOD SetParagraphFormat(const nsAString& aParagraphFormat); NS_IMETHOD GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists); - NS_IMETHOD GetParagraphState(PRBool *aMixed, nsAString &outFormat); - NS_IMETHOD GetFontFaceState(PRBool *aMixed, nsAString &outFace); - NS_IMETHOD GetFontColorState(PRBool *aMixed, nsAString &outColor); - NS_IMETHOD GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor, PRBool aBlockLevel); + nsresult GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor, + PRBool aBlockLevel); NS_IMETHOD GetHTMLBackgroundColorState(PRBool *aMixed, nsAString &outColor); - NS_IMETHOD GetBackgroundColorState(PRBool *aMixed, nsAString &outColor); - NS_IMETHOD GetHighlightColorState(PRBool *aMixed, nsAString &outColor); NS_IMETHOD GetHighlightColor(PRBool *mixed, PRUnichar **_retval); - NS_IMETHOD GetListState(PRBool *aMixed, PRBool *aOL, PRBool *aUL, PRBool *aDL); - NS_IMETHOD GetListItemState(PRBool *aMixed, PRBool *aLI, PRBool *aDT, PRBool *aDD); - NS_IMETHOD GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign); - NS_IMETHOD GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent); - NS_IMETHOD MakeOrChangeList(const nsAString& aListType, PRBool entireList, const nsAString& aBulletType); - NS_IMETHOD RemoveList(const nsAString& aListType); - NS_IMETHOD Indent(const nsAString& aIndent); - NS_IMETHOD Align(const nsAString& aAlign); - - NS_IMETHOD GetElementOrParentByTagName(const nsAString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn); - NS_IMETHOD GetSelectedElement(const nsAString& aTagName, nsIDOMElement** aReturn); - NS_IMETHOD CreateElementWithDefaults(const nsAString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD GetNextElementByTagName(nsIDOMElement *aCurrentElement, const nsAString *aTagName, nsIDOMElement **aReturn); - - NS_IMETHOD InsertLinkAroundSelection(nsIDOMElement* aAnchorElement); - - NS_IMETHOD GetLinkedObjects(nsISupportsArray** aNodeList); - - NS_IMETHOD SetIsCSSEnabled(PRBool aIsCSSPrefChecked); - NS_IMETHOD GetIsCSSEnabled(PRBool *aIsCSSEnabled); - NS_IMETHOD AddInsertionListener(nsIContentFilter *aFilter); - NS_IMETHOD RemoveInsertionListener(nsIContentFilter *aFilter); - - NS_IMETHOD IsAnonymousElement(nsIDOMElement * aElement, PRBool * aReturn); - /* ------------ nsIEditorIMESupport overrides -------------- */ NS_IMETHOD SetCompositionString(const nsAString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply); @@ -340,11 +276,6 @@ public: // or calls into nsTextEditor to set the page background NS_IMETHOD SetCSSBackgroundColor(const nsAString& aColor); NS_IMETHOD SetHTMLBackgroundColor(const nsAString& aColor); - NS_IMETHOD SetBackgroundColor(const nsAString& aColor); - NS_IMETHOD SetBodyAttribute(const nsAString& aAttr, const nsAString& aValue); - // aTitle may be null or empty string to remove child contents of - - NS_IMETHOD SetDocumentTitle(const nsAString &aTitle); /* ------------ Block methods moved from nsEditor -------------- */ static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode); @@ -406,8 +337,6 @@ public: /** Internal, static version */ static nsresult NodeIsBlockStatic(nsIDOMNode *aNode, PRBool *aIsBlock); - /** This version is for exposure to JavaScript */ - NS_IMETHOD NodeIsBlock(nsIDOMNode *aNode, PRBool *aIsBlock); /** we override this here to install event listeners */ NS_IMETHOD PostCreate(); @@ -418,13 +347,6 @@ public: NS_IMETHOD Paste(PRInt32 aSelectionType); NS_IMETHOD CanPaste(PRInt32 aSelectionType, PRBool *aCanPaste); - NS_IMETHOD CanDrag(nsIDOMEvent *aDragEvent, PRBool *aCanDrag); - NS_IMETHOD DoDrag(nsIDOMEvent *aDragEvent); - NS_IMETHOD InsertFromDrop(nsIDOMEvent* aDropEvent); - - NS_IMETHOD GetHeadContentsAsHTML(nsAString& aOutputString); - NS_IMETHOD ReplaceHeadContentsWithHTML(const nsAString &aSourceToInsert); - NS_IMETHOD DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed); /** All editor operations which alter the doc should be prefaced @@ -831,7 +753,6 @@ protected: //XXX Kludge: Used to suppress spurious drag/drop events (bug 50703) PRBool mIgnoreSpuriousDragEvent; - NS_IMETHOD IgnoreSpuriousDragEvent(PRBool aIgnoreSpuriousDragEvent) {mIgnoreSpuriousDragEvent = aIgnoreSpuriousDragEvent; return NS_OK;} nsresult GetInlinePropertyBase(nsIAtom *aProperty, const nsAString *aAttribute, @@ -892,12 +813,43 @@ protected: static PRInt32 sInstanceCount; protected: - PRPackedBool mIsImageResizingEnabled; - PRPackedBool mIsShowingResizeHandles; + + /* ANONYMOUS UTILS */ + void DeleteRefToAnonymousNode(nsIDOMElement* aElement, + nsIContent * aParentContent, + nsIDocumentObserver * aDocObserver); + nsresult GetElementOrigin(nsIDOMElement * aElement, PRInt32 & aX, PRInt32 & aY); + nsresult GetPositionAndDimensions(nsIDOMElement * aElement, + PRInt32 & aX, PRInt32 & aY, + PRInt32 & aW, PRInt32 & aH, + PRInt32 & aBorderLeft, + PRInt32 & aBorderTop, + PRInt32 & aMarginLeft, + PRInt32 & aMarginTop); + + /* PACKED BOOLEANS FOR RESIZING, ABSOLUTE POSITIONING AND */ + /* INLINE TABLE EDITING */ + + // resizing + PRPackedBool mIsObjectResizingEnabled; PRPackedBool mIsResizing; PRPackedBool mPreserveRatio; PRPackedBool mResizedObjectIsAnImage; + // absolute positioning + PRPackedBool mIsAbsolutelyPositioningEnabled; + PRPackedBool mResizedObjectIsAbsolutelyPositioned; + + PRPackedBool mGrabberClicked; + PRPackedBool mIsMoving; + + PRPackedBool mSnapToGridEnabled; + + // inline table editing + PRPackedBool mIsInlineTableEditingEnabled; + + /* RESIZING */ + nsCOMPtr<nsIDOMElement> mTopLeftHandle; nsCOMPtr<nsIDOMElement> mTopHandle; nsCOMPtr<nsIDOMElement> mTopRightHandle; @@ -907,15 +859,20 @@ protected: nsCOMPtr<nsIDOMElement> mBottomHandle; nsCOMPtr<nsIDOMElement> mBottomRightHandle; + nsCOMPtr<nsIDOMElement> mActivatedHandle; + nsCOMPtr<nsIDOMElement> mResizingShadow; nsCOMPtr<nsIDOMElement> mResizingInfo; nsCOMPtr<nsIDOMElement> mResizedObject; nsCOMPtr<nsIDOMEventListener> mMouseMotionListenerP; + nsCOMPtr<nsIDOMEventListener> mMutationListenerP; nsCOMPtr<nsISelectionListener> mSelectionListenerP; nsCOMPtr<nsIDOMEventListener> mResizeEventListenerP; + nsCOMArray<nsIHTMLObjectResizeListener> objectResizeEventListeners; + PRInt32 mOriginalX; PRInt32 mOriginalY; @@ -924,18 +881,32 @@ protected: PRInt32 mResizedObjectWidth; PRInt32 mResizedObjectHeight; + PRInt32 mResizedObjectMarginLeft; + PRInt32 mResizedObjectMarginTop; + PRInt32 mResizedObjectBorderLeft; + PRInt32 mResizedObjectBorderTop; + PRInt32 mXIncrementFactor; PRInt32 mYIncrementFactor; PRInt32 mWidthIncrementFactor; PRInt32 mHeightIncrementFactor; - nsresult CreateResizer(nsIDOMElement ** aReturn, PRInt16 aLocation, nsISupportsArray * aArray); - void SetResizerPosition(PRInt32 aX, PRInt32 aY, nsIDOMElement *aResizer); - nsresult SetAllResizersPosition(nsIDOMElement * aResizedElement, PRInt32 & aX, PRInt32 & aY); - nsresult CreateShadow(nsIDOMElement ** aReturn, nsISupportsArray * aArray); - nsresult SetShadowPosition(nsIDOMElement *aResizedObject, - PRInt32 aX, PRInt32 aY); - nsresult CreateResizingInfo(nsIDOMElement ** aReturn, nsISupportsArray * aArray); + PRInt8 mInfoXIncrement; + PRInt8 mInfoYIncrement; + + nsresult SetAllResizersPosition(); + + nsresult CreateResizer(nsIDOMElement ** aReturn, PRInt16 aLocation, nsIDOMNode * aParentNode); + void SetAnonymousElementPosition(PRInt32 aX, PRInt32 aY, nsIDOMElement *aResizer); + + nsresult CreateShadow(nsIDOMElement ** aReturn, nsIDOMNode * aParentNode, + nsIDOMElement * aOriginalObject); + nsresult SetShadowPosition(nsIDOMElement * aShadow, + nsIDOMElement * aOriginalObject, + PRInt32 aOriginalObjectX, + PRInt32 aOriginalObjectY); + + nsresult CreateResizingInfo(nsIDOMElement ** aReturn, nsIDOMNode * aParentNode); nsresult SetResizingInfoPosition(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt32 aH); @@ -947,11 +918,53 @@ protected: PRInt32 GetNewResizingHeight(PRInt32 aX, PRInt32 aY); void HideShadowAndInfo(); void SetFinalSize(PRInt32 aX, PRInt32 aY); - void DeleteRefToAnonymousNode(nsIDOMElement* aElement, - nsIContent * aParentContent, - nsIDocumentObserver * aDocObserver); + void DeleteRefToAnonymousNode(nsIDOMNode * aNode); void SetResizeIncrements(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt32 aH, PRBool aPreserveRatio); - nsresult GetElementOrigin(nsIDOMElement * aElement, PRInt32 & aX, PRInt32 & aY); + void SetInfoIncrements(PRInt8 aX, PRInt8 aY); + + /* ABSOLUTE POSITIONING */ + + PRInt32 mPositionedObjectX; + PRInt32 mPositionedObjectY; + PRInt32 mPositionedObjectWidth; + PRInt32 mPositionedObjectHeight; + + PRInt32 mPositionedObjectMarginLeft; + PRInt32 mPositionedObjectMarginTop; + PRInt32 mPositionedObjectBorderLeft; + PRInt32 mPositionedObjectBorderTop; + + nsCOMPtr<nsIDOMElement> mAbsolutelyPositionedObject; + nsCOMPtr<nsIDOMElement> mGrabber; + nsCOMPtr<nsIDOMElement> mPositioningShadow; + + PRInt32 mGridSize; + + nsresult CreateGrabber(nsIDOMNode * aParentNode, nsIDOMElement ** aReturn); + nsresult StartMoving(nsIDOMElement * aHandle); + nsresult SetFinalPosition(PRInt32 aX, PRInt32 aY); + void AddPositioningOffet(PRInt32 & aX, PRInt32 & aY); + void SnapToGrid(PRInt32 & newX, PRInt32 & newY); + nsresult GrabberClicked(); + nsresult EndMoving(); + nsresult CheckPositionedElementBGandFG(nsIDOMElement * aElement, + nsAString & aReturn); + + /* INLINE TABLE EDITING */ + + nsCOMPtr<nsIDOMElement> mInlineEditedCell; + + nsCOMPtr<nsIDOMElement> mAddColumnBeforeButton; + nsCOMPtr<nsIDOMElement> mRemoveColumnButton; + nsCOMPtr<nsIDOMElement> mAddColumnAfterButton; + + nsCOMPtr<nsIDOMElement> mAddRowBeforeButton; + nsCOMPtr<nsIDOMElement> mRemoveRowButton; + nsCOMPtr<nsIDOMElement> mAddRowAfterButton; + + void AddMouseClickListener(nsIDOMElement * aElement); + void RemoveMouseClickListener(nsIDOMElement * aElement); + public: // friends diff --git a/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.cpp b/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.cpp index 803991e2ed7..47da9cf85ed 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.cpp @@ -58,6 +58,7 @@ #include "nsIHTMLObjectResizer.h" #include "nsEditProperty.h" #include "nsTextEditUtils.h" +#include "nsIHTMLInlineTableEditor.h" /* * nsHTMLEditorMouseListener implementation @@ -116,7 +117,6 @@ nsHTMLEditorMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) //non-ui event passed in. bad things. return NS_OK; } - nsresult res; // Don't do anything special if not an HTML editor nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor); @@ -126,7 +126,7 @@ nsHTMLEditorMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) //XXX This should be easier to do! // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event interface :-( PRUint16 buttonNumber; - res = mouseEvent->GetButton(&buttonNumber); + nsresult res = mouseEvent->GetButton(&buttonNumber); if (NS_FAILED(res)) return res; PRBool isContextClick; @@ -270,8 +270,7 @@ nsHTMLEditorMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) } // HACK !!! Context click places the caret but the context menu consumes // the event; so we need to check resizing state ourselves - nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(htmlEditor); - objectResizer->CheckResizingState(selection); + htmlEditor->CheckSelectionStateForAnonymousButtons(selection); // Prevent bubbling if we changed selection or // for all context clicks @@ -295,6 +294,32 @@ nsHTMLEditorMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) return nsTextEditorMouseListener::MouseDown(aMouseEvent); } +nsresult +nsHTMLEditorMouseListener::MouseClick(nsIDOMEvent* aMouseEvent) +{ + NS_ENSURE_ARG_POINTER(aMouseEvent); + nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) ); + if (!mouseEvent) { + //non-ui event passed in. bad things. + return NS_OK; + } + + // Don't do anything special if not an HTML editor + nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor); + if (htmlEditor) + { + nsCOMPtr<nsIDOMEventTarget> target; + nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target)); + if (NS_FAILED(res)) return res; + if (!target) return NS_ERROR_NULL_POINTER; + nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target); + + nsCOMPtr<nsIHTMLInlineTableEditor> inlineTableEditing = do_QueryInterface(htmlEditor); + inlineTableEditing->DoInlineTableEditingAction(element); + } + return NS_OK; +} + nsresult NS_NewHTMLEditorMouseListener(nsIDOMEventListener ** aInstancePtrResult, nsHTMLEditor *aHTMLEditor) diff --git a/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.h b/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.h index 478cdce6387..972dbc55f4b 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditorMouseListener.h @@ -70,6 +70,7 @@ public: /*BEGIN implementations of mouseevent handler interface*/ NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent); + NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent); /*END implementations of mouseevent handler interface*/ protected: diff --git a/mozilla/editor/libeditor/html/nsHTMLInlineTableEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLInlineTableEditor.cpp new file mode 100644 index 00000000000..6e88c2661ab --- /dev/null +++ b/mozilla/editor/libeditor/html/nsHTMLInlineTableEditor.cpp @@ -0,0 +1,294 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Glazman (glazman@netscape.com) (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsHTMLEditor.h" +#include "nsIDOMNSHTMLElement.h" +#include "nsIDOMEventTarget.h" +#include "nsIPresShell.h" +#include "nsIDocumentObserver.h" +#include "nsIContent.h" +#include "nsHTMLEditUtils.h" + +// 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 +nsHTMLEditor::SetInlineTableEditingEnabled(PRBool aIsEnabled) +{ + mIsInlineTableEditingEnabled = aIsEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::GetInlineTableEditingEnabled(PRBool * aIsEnabled) +{ + *aIsEnabled = mIsInlineTableEditingEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::ShowInlineTableEditingUI(nsIDOMElement * aCell) +{ + NS_ENSURE_ARG_POINTER(aCell); + + // do nothing if aCell is not a table cell... + if (!nsHTMLEditUtils::IsTableCell(aCell)) + return NS_OK; + + // the resizers and the shadow will be anonymous children of the body + nsCOMPtr<nsIDOMElement> bodyElement; + nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement)); + if (NS_FAILED(res)) return res; + if (!bodyElement) return NS_ERROR_NULL_POINTER; + + nsCOMPtr<nsIDOMNode> bodyNode( do_QueryInterface(bodyElement) ); + + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyNode, + NS_LITERAL_STRING("mozTableAddColumnBefore"), + PR_FALSE, getter_AddRefs(mAddColumnBeforeButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyNode, + NS_LITERAL_STRING("mozTableRemoveColumn"), + PR_FALSE, getter_AddRefs(mRemoveColumnButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyNode, + NS_LITERAL_STRING("mozTableAddColumnAfter"), + PR_FALSE, getter_AddRefs(mAddColumnAfterButton)); + + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyNode, + NS_LITERAL_STRING("mozTableAddRowBefore"), + PR_FALSE, getter_AddRefs(mAddRowBeforeButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyNode, + NS_LITERAL_STRING("mozTableRemoveRow"), + PR_FALSE, getter_AddRefs(mRemoveRowButton)); + CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyNode, + NS_LITERAL_STRING("mozTableAddRowAfter"), + PR_FALSE, getter_AddRefs(mAddRowAfterButton)); + + AddMouseClickListener(mAddColumnBeforeButton); + AddMouseClickListener(mRemoveColumnButton); + AddMouseClickListener(mAddColumnAfterButton); + AddMouseClickListener(mAddRowBeforeButton); + AddMouseClickListener(mRemoveRowButton); + AddMouseClickListener(mAddRowAfterButton); + + mInlineEditedCell = aCell; + return RefreshInlineTableEditingUI(); +} + +NS_IMETHODIMP +nsHTMLEditor::HideInlineTableEditingUI() +{ + mInlineEditedCell = nsnull; + + RemoveMouseClickListener(mAddColumnBeforeButton); + RemoveMouseClickListener(mRemoveColumnButton); + RemoveMouseClickListener(mAddColumnAfterButton); + RemoveMouseClickListener(mAddRowBeforeButton); + RemoveMouseClickListener(mRemoveRowButton); + RemoveMouseClickListener(mAddRowAfterButton); + + // get the presshell's document observer interface. + + if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr<nsIDocumentObserver> docObserver(do_QueryInterface(ps)); + if (!docObserver) return NS_ERROR_FAILURE; + + // get the root content node. + + nsCOMPtr<nsIDOMElement> bodyElement; + nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement)); + if (NS_FAILED(res)) return res; + + nsCOMPtr<nsIContent> bodyContent( do_QueryInterface(bodyElement) ); + if (!bodyContent) return NS_ERROR_FAILURE; + + DeleteRefToAnonymousNode(mAddColumnBeforeButton, bodyContent, docObserver); + mAddColumnBeforeButton = nsnull; + DeleteRefToAnonymousNode(mRemoveColumnButton, bodyContent, docObserver); + mRemoveColumnButton = nsnull; + DeleteRefToAnonymousNode(mAddColumnAfterButton, bodyContent, docObserver); + mAddColumnAfterButton = nsnull; + DeleteRefToAnonymousNode(mAddRowBeforeButton, bodyContent, docObserver); + mAddRowBeforeButton = nsnull; + DeleteRefToAnonymousNode(mRemoveRowButton, bodyContent, docObserver); + mRemoveRowButton = nsnull; + DeleteRefToAnonymousNode(mAddRowAfterButton, bodyContent, docObserver); + mAddRowAfterButton = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLEditor::DoInlineTableEditingAction(nsIDOMElement * aElement) +{ + NS_ENSURE_ARG_POINTER(aElement); + PRBool anonElement = PR_FALSE; + if (aElement && + NS_SUCCEEDED(aElement->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement)) && + anonElement) { + nsAutoString anonclass; + nsresult res = aElement->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass); + if (NS_FAILED(res)) return res; + + if (!Substring(anonclass, 0, 8).Equals(NS_LITERAL_STRING("mozTable"))) + return NS_OK; + + nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(mInlineEditedCell); + nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(cellNode); + nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode); + PRInt32 rowCount, colCount; + res = GetTableSize(tableElement, &rowCount, &colCount); + if (NS_FAILED(res)) return res; + + PRBool hideUI = PR_FALSE; + PRBool hideResizersWithInlineTableUI = (mResizedObject == tableElement); + + if (anonclass.Equals(NS_LITERAL_STRING("mozTableAddColumnBefore"))) + InsertTableColumn(1, PR_FALSE); + else if (anonclass.Equals(NS_LITERAL_STRING("mozTableAddColumnAfter"))) + InsertTableColumn(1, PR_TRUE); + else if (anonclass.Equals(NS_LITERAL_STRING("mozTableAddRowBefore"))) + InsertTableRow(1, PR_FALSE); + else if (anonclass.Equals(NS_LITERAL_STRING("mozTableAddRowAfter"))) + InsertTableRow(1, PR_TRUE); + else if (anonclass.Equals(NS_LITERAL_STRING("mozTableRemoveColumn"))) { + DeleteTableColumn(1); +#ifndef DISABLE_TABLE_DELETION + hideUI = (colCount == 1); +#endif + } + else if (anonclass.Equals(NS_LITERAL_STRING("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 +nsHTMLEditor::AddMouseClickListener(nsIDOMElement * aElement) +{ + nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement)); + if (evtTarget) + evtTarget->AddEventListener(NS_LITERAL_STRING("click"), mMouseListenerP, PR_TRUE); +} + +void +nsHTMLEditor::RemoveMouseClickListener(nsIDOMElement * aElement) +{ + nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement)); + if (evtTarget) + evtTarget->RemoveEventListener(NS_LITERAL_STRING("click"), mMouseListenerP, PR_TRUE); +} + +NS_IMETHODIMP +nsHTMLEditor::RefreshInlineTableEditingUI() +{ + nsCOMPtr<nsIDOMNSHTMLElement> nsElement = do_QueryInterface(mInlineEditedCell); + if (!nsElement) {return NS_ERROR_NULL_POINTER; } + + PRInt32 xCell, yCell, wCell, hCell; + GetElementOrigin(mInlineEditedCell, xCell, yCell); + + nsresult res = nsElement->GetOffsetWidth(&wCell); + if (NS_FAILED(res)) return res; + res = nsElement->GetOffsetHeight(&hCell); + if (NS_FAILED(res)) return res; + + PRInt32 xHoriz = xCell + wCell/2; + PRInt32 yVert = yCell + hCell/2; + + nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(mInlineEditedCell); + nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(cellNode); + nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode); + PRInt32 rowCount, colCount; + res = GetTableSize(tableElement, &rowCount, &colCount); + if (NS_FAILED(res)) return res; + + SetAnonymousElementPosition(xHoriz-10, yCell-7, mAddColumnBeforeButton); +#ifdef DISABLE_TABLE_DELETION + if (colCount== 1) { + mRemoveColumnButton->SetAttribute(NS_LITERAL_STRING("class"), + NS_LITERAL_STRING("hidden")); + } + else { + PRBool hasClass = PR_FALSE; + res = mRemoveColumnButton->HasAttribute(NS_LITERAL_STRING("class"), &hasClass); + if (NS_SUCCEEDED(res) && hasClass) + mRemoveColumnButton->RemoveAttribute(NS_LITERAL_STRING("class")); +#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(NS_LITERAL_STRING("class"), + NS_LITERAL_STRING("hidden")); + } + else { + PRBool hasClass = PR_FALSE; + res = mRemoveRowButton->HasAttribute(NS_LITERAL_STRING("class"), &hasClass); + if (NS_SUCCEEDED(res) && hasClass) + mRemoveRowButton->RemoveAttribute(NS_LITERAL_STRING("class")); +#endif + SetAnonymousElementPosition(xCell-7, yVert-4, mRemoveRowButton); +#ifdef DISABLE_TABLE_DELETION + } +#endif + SetAnonymousElementPosition(xCell-7, yVert+6, mAddRowAfterButton); + + return NS_OK; +} + diff --git a/mozilla/editor/libeditor/html/nsHTMLObjectResizer.cpp b/mozilla/editor/libeditor/html/nsHTMLObjectResizer.cpp index cbf489c927c..c7b4518484c 100644 --- a/mozilla/editor/libeditor/html/nsHTMLObjectResizer.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLObjectResizer.cpp @@ -43,6 +43,9 @@ #include "nsIDOMEventReceiver.h" #include "nsIDOMText.h" +#include "nsIDOMCSSValue.h" +#include "nsIDOMCSSPrimitiveValue.h" + #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDocumentObserver.h" @@ -57,34 +60,40 @@ #include "nsPoint.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsIServiceManager.h" + +#include "nsIPresContext.h" +#include "nsILookAndFeel.h" + class nsHTMLEditUtils; // ================================================================== -// ResizeEventListener +// DocumentResizeEventListener // ================================================================== -NS_IMPL_ADDREF(ResizeEventListener) -NS_IMPL_RELEASE(ResizeEventListener) +NS_IMPL_ADDREF(DocumentResizeEventListener) +NS_IMPL_RELEASE(DocumentResizeEventListener) -NS_INTERFACE_MAP_BEGIN(ResizeEventListener) +NS_INTERFACE_MAP_BEGIN(DocumentResizeEventListener) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_END -ResizeEventListener::ResizeEventListener(nsIHTMLEditor * aEditor) : +DocumentResizeEventListener::DocumentResizeEventListener(nsIHTMLEditor * aEditor) : mEditor(aEditor) { } -ResizeEventListener::~ResizeEventListener() +DocumentResizeEventListener::~DocumentResizeEventListener() { } NS_IMETHODIMP -ResizeEventListener::HandleEvent(nsIDOMEvent* aMouseEvent) +DocumentResizeEventListener::HandleEvent(nsIDOMEvent* aMouseEvent) { nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(mEditor); - objectResizer->RefreshResizers(); - return NS_OK; + return objectResizer->RefreshResizers(); } // ================================================================== @@ -116,8 +125,7 @@ ResizerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection nsISelectionListener::SELECTALL_REASON)) && aSelection) { // the selection changed and we need to check if we have to // hide and/or redisplay resizing handles - nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(mEditor); - objectResizer->CheckResizingState(aSelection); + mEditor->CheckSelectionStateForAnonymousButtons(aSelection); } return NS_OK; @@ -186,18 +194,17 @@ NS_INTERFACE_MAP_END // ================================================================== nsresult -nsHTMLEditor::CreateResizer(nsIDOMElement ** aReturn, PRInt16 aLocation, nsISupportsArray * aArray) +nsHTMLEditor::CreateResizer(nsIDOMElement ** aReturn, PRInt16 aLocation, nsIDOMNode * aParentNode) { - // let's create a span through the element factory - nsCOMPtr<nsIContent> newContent; - nsresult res = CreateHTMLContent(NS_LITERAL_STRING("span"), getter_AddRefs(newContent)); - if (NS_FAILED(res)) return res; + nsresult res = CreateAnonymousElement(NS_LITERAL_STRING("span"), + aParentNode, + NS_LITERAL_STRING("mozResizer"), + PR_FALSE, + aReturn); - nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent); - if (!newElement) + if (NS_FAILED(res)) return res; + if (!*aReturn) return NS_ERROR_FAILURE; - *aReturn = newElement; - NS_ADDREF(*aReturn); // add the mouse listener so we can detect a click on a resizer nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(*aReturn)); @@ -233,109 +240,82 @@ nsHTMLEditor::CreateResizer(nsIDOMElement ** aReturn, PRInt16 aLocation, nsISupp break; } - - res = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"), - NS_LITERAL_STRING("mozResizer")); - if (NS_FAILED(res)) return res; - res = newElement->SetAttribute(NS_LITERAL_STRING("anonlocation"), + res = (*aReturn)->SetAttribute(NS_LITERAL_STRING("anonlocation"), locationStr); - if (NS_FAILED(res)) return res; - - return aArray->AppendElement(newContent); + return res; } nsresult -nsHTMLEditor::CreateShadow(nsIDOMElement ** aReturn, nsISupportsArray * aArray) +nsHTMLEditor::CreateShadow(nsIDOMElement ** aReturn, nsIDOMNode * aParentNode, + nsIDOMElement * aOriginalObject) { // let's create an image through the element factory - nsCOMPtr<nsIContent> newContent; nsAutoString name; - if (NodeIsType(mResizedObject, NS_LITERAL_STRING("img"))) + if (NodeIsType(aOriginalObject, NS_LITERAL_STRING("img"))) name = NS_LITERAL_STRING("img"); else name = NS_LITERAL_STRING("span"); - nsresult res = CreateHTMLContent(name, getter_AddRefs(newContent)); - if (NS_FAILED(res)) return res; + nsresult res = CreateAnonymousElement(name, + aParentNode, + NS_LITERAL_STRING("mozResizingShadow"), + PR_TRUE, + aReturn); - nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent); - if (!newElement) + if (!*aReturn) return NS_ERROR_FAILURE; - *aReturn = newElement; - NS_ADDREF(*aReturn); - return aArray->AppendElement(newContent); + return res; } nsresult -nsHTMLEditor::CreateResizingInfo(nsIDOMElement ** aReturn, nsISupportsArray * aArray) +nsHTMLEditor::CreateResizingInfo(nsIDOMElement ** aReturn, nsIDOMNode * aParentNode) { - // let's create an image through the element factory - nsCOMPtr<nsIContent> newContent; - nsresult res = CreateHTMLContent(NS_LITERAL_STRING("span"), getter_AddRefs(newContent)); - if (NS_FAILED(res)) return res; + // let's create an info box through the element factory + nsresult res = CreateAnonymousElement(NS_LITERAL_STRING("span"), + aParentNode, + NS_LITERAL_STRING("mozResizingInfo"), + PR_TRUE, + aReturn); - nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent); - if (NS_FAILED(res) || !newElement) + if (!*aReturn) return NS_ERROR_FAILURE; - *aReturn = newElement; - NS_ADDREF(*aReturn); - res = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"), - NS_LITERAL_STRING("mozResizingInfo")); - if (NS_FAILED(res)) return res; - res = newElement->SetAttribute(NS_LITERAL_STRING("class"), - NS_LITERAL_STRING("hidden")); - if (NS_FAILED(res)) return res; - - return aArray->AppendElement(newContent); -} - -void -nsHTMLEditor::SetResizerPosition(PRInt32 aX, PRInt32 aY, nsIDOMElement *aResizer) -{ - nsAutoString x, y; - x.AppendInt(aX); - y.AppendInt(aY); - - mHTMLCSSUtils->SetCSSProperty(aResizer, - nsEditProperty::cssLeft, - x + NS_LITERAL_STRING("px"), - PR_TRUE); - mHTMLCSSUtils->SetCSSProperty(aResizer, - nsEditProperty::cssTop, - y + NS_LITERAL_STRING("px"), - PR_TRUE); + return res; } nsresult -nsHTMLEditor::SetAllResizersPosition(nsIDOMElement * aResizedElement, PRInt32 & aX, PRInt32 & aY) +nsHTMLEditor::SetAllResizersPosition() { - nsCOMPtr<nsIDOMNSHTMLElement> nsElement = do_QueryInterface(aResizedElement); - if (!nsElement) {return NS_ERROR_NULL_POINTER; } - - GetElementOrigin(aResizedElement, aX, aY); - - mResizedObjectX = aX; - mResizedObjectY = aY; - - nsresult res = nsElement->GetOffsetWidth(&mResizedObjectWidth ); - if (NS_FAILED(res)) return res; - res = nsElement->GetOffsetHeight(&mResizedObjectHeight); - if (NS_FAILED(res)) return res; + PRInt32 x = mResizedObjectX; + PRInt32 y = mResizedObjectY; PRInt32 w = mResizedObjectWidth; PRInt32 h = mResizedObjectHeight; // now let's place all the resizers around the image - SetResizerPosition(aX-4, aY-4, mTopLeftHandle); - SetResizerPosition(aX+w/2-3, aY-4, mTopHandle); - SetResizerPosition(aX+w-2, aY-4, mTopRightHandle); - SetResizerPosition(aX-4, aY+h/2-3, mLeftHandle); - SetResizerPosition(aX+w-2, aY+h/2-3, mRightHandle); + // get the size of resizers + nsAutoString value; + float resizerWidth, resizerHeight; + nsCOMPtr<nsIAtom> dummyUnit; + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mTopLeftHandle); + mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssWidth, value); + mHTMLCSSUtils->ParseLength(value, &resizerWidth, getter_AddRefs(dummyUnit)); + mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssHeight, value); + mHTMLCSSUtils->ParseLength(value, &resizerHeight, getter_AddRefs(dummyUnit)); - SetResizerPosition(aX-4, aY+h-2, mBottomLeftHandle); - SetResizerPosition(aX+w/2-3, aY+h-2, mBottomHandle); - SetResizerPosition(aX+w-2, aY+h-2, mBottomRightHandle); + PRInt32 rw = (PRInt32)((resizerWidth + 1) / 2); + PRInt32 rh = (PRInt32)((resizerHeight+ 1) / 2); + + SetAnonymousElementPosition(x-rw, y-rh, mTopLeftHandle); + SetAnonymousElementPosition(x+w/2-rw, y-rh, mTopHandle); + SetAnonymousElementPosition(x+w-rw-1, y-rh, mTopRightHandle); + + SetAnonymousElementPosition(x-rw, y+h/2-rh, mLeftHandle); + SetAnonymousElementPosition(x+w-rw-1, y+h/2-rh, mRightHandle); + + SetAnonymousElementPosition(x-rw, y+h-rh-1, mBottomLeftHandle); + SetAnonymousElementPosition(x+w/2-rw, y+h-rh-1, mBottomHandle); + SetAnonymousElementPosition(x+w-rw-1, y+h-rh-1, mBottomRightHandle); return NS_OK; } @@ -343,140 +323,123 @@ nsHTMLEditor::SetAllResizersPosition(nsIDOMElement * aResizedElement, PRInt32 & NS_IMETHODIMP nsHTMLEditor::RefreshResizers() { - PRInt32 x, y; - nsresult res = SetAllResizersPosition(mResizedObject, x, y); + // nothing to do if resizers are not displayed... + if (!mResizedObject) + return NS_OK; + + nsresult res = GetPositionAndDimensions(mResizedObject, + mResizedObjectX, + mResizedObjectY, + mResizedObjectWidth, + mResizedObjectHeight, + mResizedObjectBorderLeft, + mResizedObjectBorderTop, + mResizedObjectMarginLeft, + mResizedObjectMarginTop); + if (NS_FAILED(res)) return res; - return SetShadowPosition(mResizedObject, x, y); + res = SetAllResizersPosition(); + if (NS_FAILED(res)) return res; + return SetShadowPosition(mResizingShadow, mResizedObject, + mResizedObjectX, mResizedObjectY); } NS_IMETHODIMP nsHTMLEditor::ShowResizers(nsIDOMElement *aResizedElement) { - // we are going to need the PresShell - if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED; - nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak); - if (!ps) return NS_ERROR_NOT_INITIALIZED; - - nsCOMPtr<nsISupportsArray> anonymousItems; - NS_NewISupportsArray(getter_AddRefs(anonymousItems)); - if (!anonymousItems) return NS_ERROR_NULL_POINTER; - + NS_ENSURE_ARG_POINTER(aResizedElement); mResizedObject = aResizedElement; // the resizers and the shadow will be anonymous children of the body nsCOMPtr<nsIDOMElement> bodyElement; - nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement)); + nsresult res = GetRootElement(getter_AddRefs(bodyElement)); if (NS_FAILED(res)) return res; if (!bodyElement) return NS_ERROR_NULL_POINTER; - nsCOMPtr<nsIContent> bodyContent( do_QueryInterface(bodyElement) ); + nsCOMPtr<nsIDOMNode> bodyNode( do_QueryInterface(bodyElement) ); // let's create the resizers res = CreateResizer(getter_AddRefs(mTopLeftHandle), - nsIHTMLObjectResizer::eTopLeft, anonymousItems); + nsIHTMLObjectResizer::eTopLeft, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mTopHandle), - nsIHTMLObjectResizer::eTop, anonymousItems); + nsIHTMLObjectResizer::eTop, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mTopRightHandle), - nsIHTMLObjectResizer::eTopRight, anonymousItems); + nsIHTMLObjectResizer::eTopRight, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mLeftHandle), - nsIHTMLObjectResizer::eLeft, anonymousItems); + nsIHTMLObjectResizer::eLeft, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mRightHandle), - nsIHTMLObjectResizer::eRight, anonymousItems); + nsIHTMLObjectResizer::eRight, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mBottomLeftHandle), - nsIHTMLObjectResizer::eBottomLeft, anonymousItems); + nsIHTMLObjectResizer::eBottomLeft, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mBottomHandle), - nsIHTMLObjectResizer::eBottom, anonymousItems); + nsIHTMLObjectResizer::eBottom, bodyNode); if (NS_FAILED(res)) return res; res = CreateResizer(getter_AddRefs(mBottomRightHandle), - nsIHTMLObjectResizer::eBottomRight, anonymousItems); + nsIHTMLObjectResizer::eBottomRight, bodyNode); + if (NS_FAILED(res)) return res; + + res = GetPositionAndDimensions(aResizedElement, + mResizedObjectX, + mResizedObjectY, + mResizedObjectWidth, + mResizedObjectHeight, + mResizedObjectBorderLeft, + mResizedObjectBorderTop, + mResizedObjectMarginLeft, + mResizedObjectMarginTop); if (NS_FAILED(res)) return res; // and let's set their absolute positions in the document - PRInt32 x, y; - res = SetAllResizersPosition(aResizedElement, x, y); + res = SetAllResizersPosition(); if (NS_FAILED(res)) return res; // now, let's create the resizing shadow - res = CreateShadow(getter_AddRefs(mResizingShadow), anonymousItems); + res = CreateShadow(getter_AddRefs(mResizingShadow), bodyNode, + aResizedElement); if (NS_FAILED(res)) return res; // and set its position - res = SetShadowPosition(aResizedElement, x, y); + res = SetShadowPosition(mResizingShadow, mResizedObject, + mResizedObjectX, mResizedObjectY); if (NS_FAILED(res)) return res; - mResizingShadow->SetAttribute(NS_LITERAL_STRING("class"), - NS_LITERAL_STRING("hidden")); - // and then the resizing info tooltip - res = CreateResizingInfo(getter_AddRefs(mResizingInfo), anonymousItems); + res = CreateResizingInfo(getter_AddRefs(mResizingInfo), bodyNode); if (NS_FAILED(res)) return res; - PRUint32 count = 0; - anonymousItems->Count(&count); - // we are going to need the document too + // and listen to the "resize" event on the window + // first, get the script global object from the document... nsCOMPtr<nsIDOMDocument> domDoc; GetDocument(getter_AddRefs(domDoc)); nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); if (!doc) return NS_ERROR_NULL_POINTER; - for (PRUint32 i=0; i < count; i++) { - // for each anonymous node we created, set what's needed to make it work - // and create its frames - nsCOMPtr<nsIContent> content; - if (NS_FAILED(anonymousItems->QueryElementAt(i, NS_GET_IID(nsIContent), getter_AddRefs(content)))) - continue; - - content->SetNativeAnonymous(PR_TRUE); - content->SetParent(bodyContent); - content->SetDocument(doc, PR_TRUE, PR_TRUE); - content->SetBindingParent(content); - ps->RecreateFramesFor(content); - } - - // and listen to the "resize" event on the window - // first, get the script global object from the document... nsCOMPtr<nsIScriptGlobalObject> global; res = doc->GetScriptGlobalObject(getter_AddRefs(global)); if (NS_FAILED(res)) return res; if (!global) { return NS_ERROR_NULL_POINTER; } - mResizeEventListenerP = new ResizeEventListener(this); + mResizeEventListenerP = new DocumentResizeEventListener(this); if (!mResizeEventListenerP) { return NS_ERROR_NULL_POINTER; } nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(global); res = target->AddEventListener(NS_LITERAL_STRING("resize"), mResizeEventListenerP, PR_FALSE); + aResizedElement->SetAttribute(NS_LITERAL_STRING("_moz_resizing"), NS_LITERAL_STRING("true")); return res; } -void -nsHTMLEditor::DeleteRefToAnonymousNode(nsIDOMElement* aElement, - nsIContent * aParentContent, - nsIDocumentObserver * aDocObserver) -{ - // call ContentRemoved() for the anonymous content - // node so its references get removed from the frame manager's - // undisplay map, and its layout frames get destroyed! - - nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); - if (content) { - aDocObserver->ContentRemoved(nsnull, aParentContent, content, -1); - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); - content->SetParent(nsnull); - } -} - NS_IMETHODIMP nsHTMLEditor::HideResizers(void) { - if (!mIsShowingResizeHandles || !mResizedObject) + if (!mResizedObject) return NS_OK; // get the presshell's document observer interface. @@ -491,7 +454,7 @@ nsHTMLEditor::HideResizers(void) // get the root content node. nsCOMPtr<nsIDOMElement> bodyElement; - nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement)); + nsresult res = GetRootElement(getter_AddRefs(bodyElement)); if (NS_FAILED(res)) return res; if (!bodyElement) return NS_ERROR_NULL_POINTER; @@ -547,9 +510,8 @@ nsHTMLEditor::HideResizers(void) } mResizeEventListenerP = nsnull; - mIsShowingResizeHandles = PR_FALSE; + mResizedObject->RemoveAttribute(NS_LITERAL_STRING("_moz_resizing")); mResizedObject = nsnull; - mIsResizing = PR_FALSE; return NS_OK; } @@ -563,31 +525,82 @@ nsHTMLEditor::HideShadowAndInfo() mResizingInfo->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden")); } +void +nsHTMLEditor::SetInfoIncrements(PRInt8 aX, PRInt8 aY) +{ + mInfoXIncrement = aX; + mInfoYIncrement = aY; +} + nsresult nsHTMLEditor::StartResizing(nsIDOMElement *aHandle) { + // First notify the listeners if any + PRInt32 listenersCount = objectResizeEventListeners.Count(); + if (listenersCount) { + nsCOMPtr<nsIHTMLObjectResizeListener> listener; + PRInt32 index; + for (index = 0; index < listenersCount; index++) { + listener = objectResizeEventListeners[index]; + listener->OnStartResizing(mResizedObject); + } + } + mIsResizing = PR_TRUE; + mActivatedHandle = aHandle; + mActivatedHandle->SetAttribute(NS_LITERAL_STRING("_moz_activated"), NS_LITERAL_STRING("true")); + + // do we want to preserve ratio or not? + PRBool preserveRatio = NodeIsType(mResizedObject, NS_LITERAL_STRING("img")); + nsresult result; + nsCOMPtr<nsIPrefBranch> prefBranch = + do_GetService(NS_PREFSERVICE_CONTRACTID, &result); + if (NS_SUCCEEDED(result) && prefBranch && preserveRatio) { + result = prefBranch->GetBoolPref("editor.resizing.preserve_ratio", &preserveRatio); + if (NS_FAILED(result)) { + // just in case Anvil does not update its prefs file + // and because it really does not make sense to me to allow free + // resizing on corners without a modifier key + preserveRatio = PR_TRUE; + } + } // the way we change the position/size of the shadow depends on // the handle nsAutoString locationStr; aHandle->GetAttribute(NS_LITERAL_STRING("anonlocation"), locationStr); - if (locationStr.Equals(kTopLeft)) - SetResizeIncrements(1, 1, -1, -1, PR_TRUE); - else if (locationStr.Equals(kTop)) + if (locationStr.Equals(kTopLeft)) { + SetResizeIncrements(1, 1, -1, -1, preserveRatio); + SetInfoIncrements(20, 20); + } + else if (locationStr.Equals(kTop)) { SetResizeIncrements(0, 1, 0, -1, PR_FALSE); - else if (locationStr.Equals(kTopRight)) - SetResizeIncrements(0, 1, 1, -1, PR_TRUE); - else if (locationStr.Equals(kLeft)) + SetInfoIncrements(0, 20); + } + else if (locationStr.Equals(kTopRight)) { + SetResizeIncrements(0, 1, 1, -1, preserveRatio); + SetInfoIncrements(-20, 20); + } + else if (locationStr.Equals(kLeft)) { SetResizeIncrements(1, 0, -1, 0, PR_FALSE); - else if (locationStr.Equals(kRight)) + SetInfoIncrements(20, 20); + } + else if (locationStr.Equals(kRight)) { SetResizeIncrements(0, 0, 1, 0, PR_FALSE); - else if (locationStr.Equals(kBottomLeft)) - SetResizeIncrements(1, 0, -1, 1, PR_TRUE); - else if (locationStr.Equals(kBottom)) + SetInfoIncrements(-20, 0); + } + else if (locationStr.Equals(kBottomLeft)) { + SetResizeIncrements(1, 0, -1, 1, preserveRatio); + SetInfoIncrements(20, -20); + } + else if (locationStr.Equals(kBottom)) { SetResizeIncrements(0, 0, 0, 1, PR_FALSE); - else if (locationStr.Equals(kBottomRight)) - SetResizeIncrements(0, 0, 1, 1, PR_TRUE); + SetInfoIncrements(0, -20); + } + else if (locationStr.Equals(kBottomRight)) { + SetResizeIncrements(0, 0, 1, 1, preserveRatio); + SetInfoIncrements(-20, -20); + } // make the shadow appear mResizingShadow->RemoveAttribute(NS_LITERAL_STRING("class")); @@ -597,19 +610,14 @@ nsHTMLEditor::StartResizing(nsIDOMElement *aHandle) w.AppendInt(mResizedObjectWidth); h.AppendInt(mResizedObjectHeight); mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssWidth, - w + NS_LITERAL_STRING("px"), - PR_TRUE); + NS_LITERAL_STRING("width"), + w + NS_LITERAL_STRING("px")); mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssHeight, - h + NS_LITERAL_STRING("px"), - PR_TRUE); + NS_LITERAL_STRING("height"), + h + NS_LITERAL_STRING("px")); - nsresult result = NS_OK; - - if (!mMouseMotionListenerP) - { - // add a mouse move listener to the editor + // add a mouse move listener to the editor + if (!mMouseMotionListenerP) { mMouseMotionListenerP = new ResizerMouseMotionListener(this); if (!mMouseMotionListenerP) {return NS_ERROR_NULL_POINTER;} @@ -623,10 +631,10 @@ nsHTMLEditor::StartResizing(nsIDOMElement *aHandle) else HandleEventListenerError(); } - return result; } + NS_IMETHODIMP nsHTMLEditor::MouseDown(PRInt32 aClientX, PRInt32 aClientY, nsIDOMElement *aTarget) @@ -642,17 +650,21 @@ nsHTMLEditor::MouseDown(PRInt32 aClientX, PRInt32 aClientY, // and that element is a resizer, let's start resizing! mOriginalX = aClientX; mOriginalY = aClientY; - res = StartResizing(aTarget); - if (NS_FAILED(res)) return res; + return StartResizing(aTarget); + } + if (anonclass.Equals(NS_LITERAL_STRING("mozGrabber"))) { + // and that element is a grabber, let's start moving the element! + mOriginalX = aClientX; + mOriginalY = aClientY; + return GrabberClicked(); } - return NS_OK; } return NS_OK; } NS_IMETHODIMP nsHTMLEditor::MouseUp(PRInt32 aClientX, PRInt32 aClientY, - nsIDOMElement *aResizedObject) + nsIDOMElement *aTarget) { if (mIsResizing) { // we are resizing and release the mouse button, so let's @@ -661,7 +673,17 @@ nsHTMLEditor::MouseUp(PRInt32 aClientX, PRInt32 aClientY, HideShadowAndInfo(); SetFinalSize(aClientX, aClientY); } - + else if (mIsMoving || mGrabberClicked) { + if (mIsMoving) { + mPositioningShadow->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden")); + SetFinalPosition(aClientX, aClientY); + } + if (mGrabberClicked) { + EndMoving(); + mGrabberClicked = PR_FALSE; + mIsMoving = PR_FALSE; + } + } return NS_OK; } @@ -681,17 +703,76 @@ nsHTMLEditor::SetResizeIncrements(PRInt32 aX, PRInt32 aY, nsresult nsHTMLEditor::SetResizingInfoPosition(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt32 aH) { - nsAutoString x, y; - x.AppendInt(aX + 20); - y.AppendInt(aY + 20); + // get the root content + nsCOMPtr<nsIContent> rootContent; + + nsCOMPtr<nsIDOMDocument> domdoc; + nsEditor::GetDocument(getter_AddRefs(domdoc)); + + nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc)); + if (!doc) + return NS_ERROR_UNEXPECTED; + + doc->GetRootContent(getter_AddRefs(rootContent)); + nsCOMPtr<nsIDOMNSHTMLElement> nsElement = do_QueryInterface(rootContent); + if (!nsElement) {return NS_ERROR_NULL_POINTER; } + + // let's get the size of the document + PRInt32 w, h; + nsElement->GetOffsetWidth(&w); + nsElement->GetOffsetHeight(&h); + + if (mInfoXIncrement < 0) + aX = w - aX ; + if (mInfoYIncrement < 0) + aY = h - aY; + + nsAutoString xStr, yStr; + xStr.AppendInt(aX + PR_ABS(mInfoXIncrement)); + yStr.AppendInt(aY + PR_ABS(mInfoYIncrement)); + NS_NAMED_LITERAL_STRING(rightStr, "right"); + NS_NAMED_LITERAL_STRING(leftStr, "left"); + NS_NAMED_LITERAL_STRING(topStr, "top"); + NS_NAMED_LITERAL_STRING(bottomStr, "bottom"); mHTMLCSSUtils->SetCSSProperty(mResizingInfo, - nsEditProperty::cssLeft, - x + NS_LITERAL_STRING("px"), - PR_TRUE); + (mInfoXIncrement < 0) ? rightStr : leftStr, + xStr + NS_LITERAL_STRING("px")); mHTMLCSSUtils->SetCSSProperty(mResizingInfo, - nsEditProperty::cssTop, - y + NS_LITERAL_STRING("px"), - PR_TRUE); + (mInfoYIncrement < 0) ? bottomStr : topStr, + yStr + NS_LITERAL_STRING("px")); + + mHTMLCSSUtils->RemoveCSSProperty(mResizingInfo, + (mInfoXIncrement >= 0) ? rightStr : leftStr); + mHTMLCSSUtils->RemoveCSSProperty(mResizingInfo, + (mInfoYIncrement >= 0) ? bottomStr : topStr); + + // let's make sure the info box does not go beyond the limits of the viewport + nsAutoString value; + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mResizingInfo); + float f; + nsCOMPtr<nsIAtom> unit; + if (mInfoXIncrement < 0) { + mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssLeft, value); + mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); + if (f <= 0) { + mHTMLCSSUtils->SetCSSProperty(mResizingInfo, + leftStr, + NS_LITERAL_STRING("0px")); + mHTMLCSSUtils->RemoveCSSProperty(mResizingInfo, + rightStr); + } + } + if (mInfoYIncrement < 0) { + mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssTop, value); + mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); + if (f <= 0) { + mHTMLCSSUtils->SetCSSProperty(mResizingInfo, + topStr, + NS_LITERAL_STRING("0px")); + mHTMLCSSUtils->RemoveCSSProperty(mResizingInfo, + bottomStr); + } + } nsCOMPtr<nsIDOMNode> textInfo; nsresult res = mResizingInfo->GetFirstChild(getter_AddRefs(textInfo)); @@ -703,8 +784,6 @@ nsHTMLEditor::SetResizingInfoPosition(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt3 textInfo = nsnull; junk = nsnull; } - nsCOMPtr<nsIDOMDocument> domDoc; - GetDocument(getter_AddRefs(domDoc)); nsAutoString widthStr, heightStr, diffWidthStr, diffHeightStr; widthStr.AppendInt(aW); @@ -724,7 +803,7 @@ nsHTMLEditor::SetResizingInfoPosition(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt3 NS_LITERAL_STRING(")")); nsCOMPtr<nsIDOMText> nodeAsText; - res = domDoc->CreateTextNode(info, getter_AddRefs(nodeAsText)); + res = domdoc->CreateTextNode(info, getter_AddRefs(nodeAsText)); if (NS_FAILED(res)) return res; textInfo = do_QueryInterface(nodeAsText); res = mResizingInfo->AppendChild(textInfo, getter_AddRefs(junk)); @@ -738,31 +817,22 @@ nsHTMLEditor::SetResizingInfoPosition(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt3 } nsresult -nsHTMLEditor::SetShadowPosition(nsIDOMElement *aResizedObject, - PRInt32 aX, PRInt32 aY) +nsHTMLEditor::SetShadowPosition(nsIDOMElement * aShadow, + nsIDOMElement * aOriginalObject, + PRInt32 aOriginalObjectX, + PRInt32 aOriginalObjectY) { - nsAutoString x, y; - x.AppendInt(aX); - y.AppendInt(aY); - mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssLeft, - x + NS_LITERAL_STRING("px"), - PR_TRUE); - mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssTop, - y + NS_LITERAL_STRING("px"), - PR_TRUE); + SetAnonymousElementPosition(aOriginalObjectX, aOriginalObjectY, aShadow); - if(NodeIsType(mResizedObject, NS_LITERAL_STRING("img"))) { + if(NodeIsType(aOriginalObject, NS_LITERAL_STRING("img"))) { nsAutoString imageSource; - nsresult res = aResizedObject->GetAttribute(NS_LITERAL_STRING("src"), + nsresult res = aOriginalObject->GetAttribute(NS_LITERAL_STRING("src"), imageSource); if (NS_FAILED(res)) return res; - res = mResizingShadow->SetAttribute(NS_LITERAL_STRING("src"), imageSource); + res = aShadow->SetAttribute(NS_LITERAL_STRING("src"), imageSource); if (NS_FAILED(res)) return res; } - return mResizingShadow->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"), - NS_LITERAL_STRING("mozResizingShadow")); + return NS_OK; } PRInt32 @@ -792,14 +862,14 @@ nsHTMLEditor::GetNewResizingIncrement(PRInt32 aX, PRInt32 aY, PRInt32 aID) case kX: case kWidth: if (result == yi) - result *= objectSizeRatio; - result *= mWidthIncrementFactor; + result = (PRInt32) (((float) result) * objectSizeRatio); + result = (PRInt32) (((float) result) * mWidthIncrementFactor); break; case kY: case kHeight: if (result == xi) - result /= objectSizeRatio; - result *= mHeightIncrementFactor; + result = (PRInt32) (((float) result) / objectSizeRatio); + result = (PRInt32) (((float) result) * mHeightIncrementFactor); break; } return result; @@ -845,6 +915,11 @@ nsHTMLEditor::GetNewResizingHeight(PRInt32 aX, PRInt32 aY) NS_IMETHODIMP nsHTMLEditor::MouseMove(nsIDOMEvent* aMouseEvent) { + NS_NAMED_LITERAL_STRING(leftStr, "left"); + NS_NAMED_LITERAL_STRING(topStr, "top"); + NS_NAMED_LITERAL_STRING(widthStr, "width"); + NS_NAMED_LITERAL_STRING(heightStr, "height"); + if (mIsResizing) { // we are resizing and the mouse pointer's position has changed // we have to resdisplay the shadow @@ -862,23 +937,70 @@ nsHTMLEditor::MouseMove(nsIDOMEvent* aMouseEvent) h.AppendInt(newHeight); mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssLeft, - x + NS_LITERAL_STRING("px"), - PR_TRUE); + leftStr, + x + NS_LITERAL_STRING("px")); mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssTop, - y + NS_LITERAL_STRING("px"), - PR_TRUE); + topStr, + y + NS_LITERAL_STRING("px")); mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssWidth, - w + NS_LITERAL_STRING("px"), - PR_TRUE); + widthStr, + w + NS_LITERAL_STRING("px")); mHTMLCSSUtils->SetCSSProperty(mResizingShadow, - nsEditProperty::cssHeight, - h + NS_LITERAL_STRING("px"), - PR_TRUE); + heightStr, + h + NS_LITERAL_STRING("px")); - SetResizingInfoPosition(clientX, clientY, newWidth, newHeight); + return SetResizingInfoPosition(clientX, clientY, newWidth, newHeight); + } + + if (mGrabberClicked) { + nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) ); + PRInt32 clientX, clientY; + mouseEvent->GetClientX(&clientX); + mouseEvent->GetClientY(&clientY); + + if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak); + if (!ps) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr<nsIPresContext> pcontext; + ps->GetPresContext(getter_AddRefs(pcontext)); + if (!pcontext) return NS_ERROR_NOT_INITIALIZED; + nsCOMPtr<nsILookAndFeel> look; + nsresult res = pcontext->GetLookAndFeel(getter_AddRefs(look)); + + PRInt32 xThreshold, yThreshold; + if (NS_SUCCEEDED(res) && look) { + look->GetMetric(nsILookAndFeel::eMetric_DragThresholdX, xThreshold); + look->GetMetric(nsILookAndFeel::eMetric_DragThresholdY, yThreshold); + } + + if (PR_ABS(clientX - mOriginalX ) * 2 >= xThreshold || + PR_ABS(clientY - mOriginalY ) * 2 >= yThreshold) { + mGrabberClicked = PR_FALSE; + StartMoving(nsnull); + } + } + if (mIsMoving) { + nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) ); + PRInt32 clientX, clientY; + mouseEvent->GetClientX(&clientX); + mouseEvent->GetClientY(&clientY); + + nsAutoString x, y, w, h; + PRInt32 newX = mPositionedObjectX + clientX - mOriginalX; + PRInt32 newY = mPositionedObjectY + clientY - mOriginalY; + + SnapToGrid(newX, newY); + + x.AppendInt(newX); + y.AppendInt(newY); + w.AppendInt(mPositionedObjectWidth); + h.AppendInt(mPositionedObjectHeight); + mHTMLCSSUtils->SetCSSProperty(mPositioningShadow, + leftStr, + x + NS_LITERAL_STRING("px")); + mHTMLCSSUtils->SetCSSProperty(mPositioningShadow, + topStr, + y + NS_LITERAL_STRING("px")); } return NS_OK; } @@ -886,20 +1008,31 @@ nsHTMLEditor::MouseMove(nsIDOMEvent* aMouseEvent) void nsHTMLEditor::SetFinalSize(PRInt32 aX, PRInt32 aY) { - NS_ASSERTION(mResizedObject, "SetFinalSize() called with null mResizedObject ptr!"); - if (!mResizedObject) return; + if (!mResizedObject) { + // paranoia + return; + } + + if (mActivatedHandle) { + mActivatedHandle->RemoveAttribute(NS_LITERAL_STRING("_moz_activated")); + mActivatedHandle = nsnull; + } // we have now to set the new width and height of the resized object // we don't set the x and y position because we don't control that in // a normal HTML layout + PRInt32 left = GetNewResizingX(aX, aY); + PRInt32 top = GetNewResizingY(aX, aY); PRInt32 width = GetNewResizingWidth(aX, aY); PRInt32 height = GetNewResizingHeight(aX, aY); - nsAutoString w, h; + PRBool setWidth = !mResizedObjectIsAbsolutelyPositioned || (width != mResizedObjectWidth); + PRBool setHeight = !mResizedObjectIsAbsolutelyPositioned || (height != mResizedObjectHeight); + + nsAutoString x, y, w, h; + x.AppendInt(left - ((mResizedObjectIsAbsolutelyPositioned) ? mResizedObjectBorderLeft+mResizedObjectMarginLeft : 0)); + y.AppendInt(top - ((mResizedObjectIsAbsolutelyPositioned) ? mResizedObjectBorderTop+mResizedObjectMarginTop : 0)); w.AppendInt(width); h.AppendInt(height); - // keep track of that size - mResizedObjectWidth = width; - mResizedObjectHeight = height; // we need to know if we're in a CSS-enabled editor or not PRBool useCSS; @@ -912,22 +1045,36 @@ nsHTMLEditor::SetFinalSize(PRInt32 aX, PRInt32 aY) NS_NAMED_LITERAL_STRING(heightStr, "height"); PRBool hasAttr = PR_FALSE; - if (useCSS) { - if (NS_SUCCEEDED(mResizedObject->HasAttribute(widthStr, &hasAttr)) && hasAttr) + if (mResizedObjectIsAbsolutelyPositioned) { + if (setHeight) + mHTMLCSSUtils->SetCSSProperty(mResizedObject, + nsEditProperty::cssTop, + y + NS_LITERAL_STRING("px"), + PR_FALSE); + if (setWidth) + mHTMLCSSUtils->SetCSSProperty(mResizedObject, + nsEditProperty::cssLeft, + x + NS_LITERAL_STRING("px"), + PR_FALSE); + } + if (useCSS || mResizedObjectIsAbsolutelyPositioned) { + if (setWidth && NS_SUCCEEDED(mResizedObject->HasAttribute(widthStr, &hasAttr)) && hasAttr) RemoveAttribute(mResizedObject, widthStr); hasAttr = PR_FALSE; - if (NS_SUCCEEDED(mResizedObject->HasAttribute(heightStr, &hasAttr)) && hasAttr) + if (setHeight && NS_SUCCEEDED(mResizedObject->HasAttribute(heightStr, &hasAttr)) && hasAttr) RemoveAttribute(mResizedObject, heightStr); - mHTMLCSSUtils->SetCSSProperty(mResizedObject, - nsEditProperty::cssWidth, - w + NS_LITERAL_STRING("px"), - PR_FALSE); - mHTMLCSSUtils->SetCSSProperty(mResizedObject, - nsEditProperty::cssHeight, - h + NS_LITERAL_STRING("px"), - PR_FALSE); + if (setWidth) + mHTMLCSSUtils->SetCSSProperty(mResizedObject, + nsEditProperty::cssWidth, + w + NS_LITERAL_STRING("px"), + PR_FALSE); + if (setHeight) + mHTMLCSSUtils->SetCSSProperty(mResizedObject, + nsEditProperty::cssHeight, + h + NS_LITERAL_STRING("px"), + PR_FALSE); } else { // we use HTML size and remove all equivalent CSS properties @@ -935,199 +1082,102 @@ nsHTMLEditor::SetFinalSize(PRInt32 aX, PRInt32 aY) // we set the CSS width and height to remove it later, // triggering an immediate reflow; otherwise, we have problems // with asynchronous reflow - mHTMLCSSUtils->SetCSSProperty(mResizedObject, - nsEditProperty::cssWidth, - w + NS_LITERAL_STRING("px"), - PR_FALSE); - mHTMLCSSUtils->SetCSSProperty(mResizedObject, - nsEditProperty::cssHeight, - h + NS_LITERAL_STRING("px"), - PR_FALSE); - - SetAttribute(mResizedObject, widthStr, w); - SetAttribute(mResizedObject, heightStr, h); - - mHTMLCSSUtils->RemoveCSSProperty(mResizedObject, - nsEditProperty::cssWidth, - NS_LITERAL_STRING(""), - PR_FALSE); - mHTMLCSSUtils->RemoveCSSProperty(mResizedObject, - nsEditProperty::cssHeight, - NS_LITERAL_STRING(""), + if (setWidth) + mHTMLCSSUtils->SetCSSProperty(mResizedObject, + nsEditProperty::cssWidth, + w + NS_LITERAL_STRING("px"), PR_FALSE); + if (setHeight) + mHTMLCSSUtils->SetCSSProperty(mResizedObject, + nsEditProperty::cssHeight, + h + NS_LITERAL_STRING("px"), + PR_FALSE); + + if (setWidth) + SetAttribute(mResizedObject, widthStr, w); + if (setHeight) + SetAttribute(mResizedObject, heightStr, h); + + if (setWidth) + mHTMLCSSUtils->RemoveCSSProperty(mResizedObject, + nsEditProperty::cssWidth, + NS_LITERAL_STRING(""), + PR_FALSE); + if (setHeight) + mHTMLCSSUtils->RemoveCSSProperty(mResizedObject, + nsEditProperty::cssHeight, + NS_LITERAL_STRING(""), + PR_FALSE); } + // finally notify the listeners if any + PRInt32 listenersCount = objectResizeEventListeners.Count(); + if (listenersCount) { + nsCOMPtr<nsIHTMLObjectResizeListener> listener; + PRInt32 index; + for (index = 0; index < listenersCount; index++) { + listener = objectResizeEventListeners[index]; + listener->OnEndResizing(mResizedObject, + mResizedObjectWidth, mResizedObjectHeight, + width, height); + } + } + + // keep track of that size + mResizedObjectWidth = width; + mResizedObjectHeight = height; + RefreshResizers(); } -NS_IMETHODIMP -nsHTMLEditor::CheckResizingState(nsISelection *aSelection) -{ - NS_ENSURE_ARG_POINTER(aSelection); - - if (!mIsImageResizingEnabled) - return NS_OK; - - PRBool bCollapsed; - nsresult res = aSelection->GetIsCollapsed(&bCollapsed); - if (NS_FAILED(res)) return res; - - nsCOMPtr<nsIDOMNode> focusNode; - - if (bCollapsed) { - res = aSelection->GetFocusNode(getter_AddRefs(focusNode)); - if (NS_FAILED(res)) return res; - } - else { - - PRInt32 rangeCount; - res = aSelection->GetRangeCount(&rangeCount); - if (NS_FAILED(res)) return res; - - if (rangeCount == 1) { - - nsCOMPtr<nsIDOMRange> range; - res = aSelection->GetRangeAt(0, getter_AddRefs(range)); - if (NS_FAILED(res)) return res; - if (!range) return NS_ERROR_NULL_POINTER; - - nsCOMPtr<nsIDOMNode> startContainer, endContainer; - res = range->GetStartContainer(getter_AddRefs(startContainer)); - if (NS_FAILED(res)) return res; - res = range->GetEndContainer(getter_AddRefs(endContainer)); - if (NS_FAILED(res)) return res; - PRInt32 startOffset, endOffset; - res = range->GetStartOffset(&startOffset); - if (NS_FAILED(res)) return res; - res = range->GetEndOffset(&endOffset); - if (NS_FAILED(res)) return res; - - nsCOMPtr<nsIDOMElement> focusElement; - if (startContainer == endContainer && startOffset + 1 == endOffset) { - res = GetSelectedElement(NS_LITERAL_STRING(""), getter_AddRefs(focusElement)); - if (NS_FAILED(res)) return res; - if (focusElement) - focusNode = do_QueryInterface(focusElement); - } - if (!focusNode) { - res = range->GetCommonAncestorContainer(getter_AddRefs(focusNode)); - if (NS_FAILED(res)) return res; - } - } - else { - PRInt32 i; - nsCOMPtr<nsIDOMRange> range; - for (i = 0; i < rangeCount; i++) - { - res = aSelection->GetRangeAt(i, getter_AddRefs(range)); - if (NS_FAILED(res)) return res; - nsCOMPtr<nsIDOMNode> startContainer; - range->GetStartContainer(getter_AddRefs(startContainer)); - if (!focusNode) - focusNode = startContainer; - else if (focusNode != startContainer) { - res = startContainer->GetParentNode(getter_AddRefs(focusNode)); - if (NS_FAILED(res)) return res; - break; - } - } - } - } - - if (focusNode) { - PRUint16 nodeType; - focusNode->GetNodeType(&nodeType); - if (nsIDOMNode::TEXT_NODE == nodeType) { - nsCOMPtr<nsIDOMNode> parent; - res = focusNode->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(res)) return res; - focusNode = parent; - } - - nsCOMPtr<nsIDOMElement>element; - element = do_QueryInterface(focusNode); - nsAutoString tagName; - res = element->GetTagName(tagName); - if (NS_FAILED(res)) return res; - - ToLowerCase(tagName); - nsCOMPtr<nsIAtom> tagAtom = getter_AddRefs(NS_NewAtom(tagName)); - if (!tagAtom) return NS_ERROR_NULL_POINTER; - - nsCOMPtr<nsIDOMNode> tableContainer = GetEnclosingTable(focusNode); - - if (nsEditProperty::img == tagAtom || - tableContainer) { - mResizedObjectIsAnImage = PR_FALSE; - - if (nsEditProperty::img == tagAtom) - mResizedObjectIsAnImage = PR_TRUE; - else { - focusNode = tableContainer; - } - - // that node is an image, we have to show resizers - element = do_QueryInterface(focusNode); - if (mIsShowingResizeHandles) { - // we were already displaying resizers and we only have to - // refresh the position - nsCOMPtr<nsIDOMNode> resizedNode = do_QueryInterface(mResizedObject); - if (!NodesSameType(focusNode, resizedNode)) { - res = HideResizers(); - if (NS_FAILED(res)) return res; - mResizedObject = element; - res = ShowResizers(element); - } - else { - mResizedObject = element; - res = RefreshResizers(); - } - } - else { - // run through the whole thing - res = ShowResizers(element); - } - if (NS_FAILED(res)) return res; - mIsShowingResizeHandles = PR_TRUE; - return NS_OK; - } - } - if (mIsShowingResizeHandles) { - // we were showing resizers but the selection is not an image any longer - res = HideResizers(); - // just in case we were resizing... (bug 195412) - mIsResizing = PR_FALSE; - if (NS_FAILED(res)) return res; - // paranoia... - // mIsResizing = PR_FALSE; - } - return NS_OK; -} - NS_IMETHODIMP nsHTMLEditor::GetResizedObject(nsIDOMElement * *aResizedObject) { - NS_IF_ADDREF(*aResizedObject = mResizedObject); + *aResizedObject = mResizedObject; + NS_IF_ADDREF(*aResizedObject); return NS_OK; } NS_IMETHODIMP -nsHTMLEditor::GetResizedObjectSize(PRInt32 *aWidth, PRInt32 *aHeight) +nsHTMLEditor::GetObjectResizingEnabled(PRBool *aIsObjectResizingEnabled) { - *aWidth = mResizedObjectWidth; - *aHeight = mResizedObjectHeight; + *aIsObjectResizingEnabled = mIsObjectResizingEnabled; return NS_OK; } NS_IMETHODIMP -nsHTMLEditor::GetIsImageResizingEnabled(PRBool *aIsImageResizingEnabled) +nsHTMLEditor::SetObjectResizingEnabled(PRBool aObjectResizingEnabled) { - *aIsImageResizingEnabled = mIsImageResizingEnabled; + mIsObjectResizingEnabled = aObjectResizingEnabled; return NS_OK; } NS_IMETHODIMP -nsHTMLEditor::SetIsImageResizingEnabled(PRBool aIsImageResizingEnabled) +nsHTMLEditor::AddObjectResizeEventListener(nsIHTMLObjectResizeListener * aListener) { - mIsImageResizingEnabled = aIsImageResizingEnabled; + NS_ENSURE_ARG_POINTER(aListener); + if (objectResizeEventListeners.Count() && + objectResizeEventListeners.IndexOf(aListener) != -1) { + /* listener already registered */ + NS_ASSERTION(PR_FALSE, + "trying to register an already registered object resize event listener"); + return NS_OK; + } + objectResizeEventListeners.AppendObject(aListener); return NS_OK; } + +NS_IMETHODIMP +nsHTMLEditor::RemoveObjectResizeEventListener(nsIHTMLObjectResizeListener * aListener) +{ + NS_ENSURE_ARG_POINTER(aListener); + if (!objectResizeEventListeners.Count() || + objectResizeEventListeners.IndexOf(aListener) == -1) { + /* listener was not registered */ + NS_ASSERTION(PR_FALSE, + "trying to remove an object resize event listener that was not already registered"); + return NS_OK; + } + objectResizeEventListeners.RemoveObject(aListener); + return NS_OK; +} + diff --git a/mozilla/editor/libeditor/html/nsHTMLObjectResizer.h b/mozilla/editor/libeditor/html/nsHTMLObjectResizer.h index e3a5a93a775..78c94925d2c 100644 --- a/mozilla/editor/libeditor/html/nsHTMLObjectResizer.h +++ b/mozilla/editor/libeditor/html/nsHTMLObjectResizer.h @@ -110,14 +110,14 @@ public: }; // ================================================================== -// ResizeEventListener +// DocumentResizeEventListener // ================================================================== -class ResizeEventListener: public nsIDOMEventListener +class DocumentResizeEventListener: public nsIDOMEventListener { public: - ResizeEventListener(nsIHTMLEditor * aEditor); - virtual ~ResizeEventListener(); + DocumentResizeEventListener(nsIHTMLEditor * aEditor); + virtual ~DocumentResizeEventListener(); /*interfaces for addref and release and queryinterface*/ NS_DECL_ISUPPORTS @@ -129,5 +129,4 @@ public: }; - #endif /* _nshtmlobjectresizer__h */ diff --git a/mozilla/editor/libeditor/html/nsIHTMLEditRules.h b/mozilla/editor/libeditor/html/nsIHTMLEditRules.h index b0d6001c36f..f024c3827ec 100644 --- a/mozilla/editor/libeditor/html/nsIHTMLEditRules.h +++ b/mozilla/editor/libeditor/html/nsIHTMLEditRules.h @@ -56,6 +56,7 @@ public: NS_IMETHOD GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent)=0; NS_IMETHOD GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign)=0; NS_IMETHOD GetParagraphState(PRBool *aMixed, nsAString &outFormat)=0; + NS_IMETHOD MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode)=0; }; diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.h b/mozilla/editor/libeditor/text/nsTextEditRules.h index 0d22ec251c9..6604b56459e 100644 --- a/mozilla/editor/libeditor/text/nsTextEditRules.h +++ b/mozilla/editor/libeditor/text/nsTextEditRules.h @@ -99,7 +99,12 @@ public: kRemoveList = 3006, kMakeDefListItem = 3007, kInsertElement = 3008, - kLoadHTML = 3013 + kLoadHTML = 3013, + kSetAbsolutePosition = 3015, + kRemoveAbsolutePosition = 3016, + kDecreaseZIndex = 3017, + kIncreaseZIndex = 3018 + }; public: diff --git a/mozilla/editor/ui/composer/content/ComposerCommands.js b/mozilla/editor/ui/composer/content/ComposerCommands.js index 69e3e1642c4..8ce82228bb7 100644 --- a/mozilla/editor/ui/composer/content/ComposerCommands.js +++ b/mozilla/editor/ui/composer/content/ComposerCommands.js @@ -59,6 +59,8 @@ function SetupHTMLEditorCommands() commandTable.registerCommand("cmd_renderedHTMLEnabler", nsDummyHTMLCommand); + commandTable.registerCommand("cmd_grid", nsGridCommand); + commandTable.registerCommand("cmd_listProperties", nsListPropertiesCommand); commandTable.registerCommand("cmd_pageProperties", nsPagePropertiesCommand); commandTable.registerCommand("cmd_colorProperties", nsColorPropertiesCommand); @@ -286,9 +288,12 @@ function goUpdateCommandState(command) case "cmd_fontColor": case "cmd_fontFace": case "cmd_fontSize": + case "cmd_absPos": pokeMultiStateUI(command, params); break; + case "cmd_decreaseZIndex": + case "cmd_increaseZIndex": case "cmd_indent": case "cmd_outdent": case "cmd_increaseFont": @@ -2884,6 +2889,25 @@ var nsInsertBreakAllCommand = } }; +//----------------------------------------------------------------------------------- +var nsGridCommand = +{ + isCommandEnabled: function(aCommand, dummy) + { + return (IsDocumentEditable() && IsEditingRenderedHTML()); + }, + + getCommandStateParams: function(aCommand, aParams, aRefCon) {}, + doCommandParams: function(aCommand, aParams, aRefCon) {}, + + doCommand: function(aCommand) + { + window.openDialog("chrome://editor/content/EdSnapToGrid.xul","_blank", "chrome,close,titlebar,modal"); + window.content.focus(); + } +}; + + //----------------------------------------------------------------------------------- var nsListPropertiesCommand = { diff --git a/mozilla/editor/ui/composer/content/editor.xul b/mozilla/editor/ui/composer/content/editor.xul index 485dda4684e..fb1b273a9aa 100644 --- a/mozilla/editor/ui/composer/content/editor.xul +++ b/mozilla/editor/ui/composer/content/editor.xul @@ -143,6 +143,8 @@ <menu id="formatMenu" label="&formatMenu.label;" accesskey="&formatmenu.accesskey;"> <menupopup id="formatMenuPopup"> + <menuitem id="snapToGrid"/> + <menuseparator/> <menuitem id="objectProperties"/> <menuitem id="colorsAndBackground"/> <menuitem id="pageProperties"/> @@ -230,6 +232,10 @@ <toolbarbutton id="align-right-button"/> <toolbarbutton id="align-justify-button"/> + <toolbarbutton id="absolutePositionButton"/> + <toolbarbutton id="decreaseZIndexButton"/> + <toolbarbutton id="increaseZIndexButton"/> + <!-- TODO: Change to a menulist? --> <!-- menu> <button id="AlignPopupButton"/> diff --git a/mozilla/editor/ui/composer/content/editorOverlay.xul b/mozilla/editor/ui/composer/content/editorOverlay.xul index 6b22cc6c8fb..c76c7aac901 100644 --- a/mozilla/editor/ui/composer/content/editorOverlay.xul +++ b/mozilla/editor/ui/composer/content/editorOverlay.xul @@ -225,7 +225,11 @@ <command id="cmd_fontSize" oncommand="goDoCommand('cmd_fontSize')"/> <command id="cmd_align" state=""/> - + + <command id="cmd_absPos" state="" oncommand="goDoCommand('cmd_absPos')"/> + <command id="cmd_increaseZIndex" state="" oncommand="goDoCommand('cmd_increaseZIndex')"/> + <command id="cmd_decreaseZIndex" state="" oncommand="goDoCommand('cmd_decreaseZIndex')"/> + <command id="cmd_advancedProperties" oncommand="goDoCommand('cmd_advancedProperties')"/> <command id="cmd_increaseFont" oncommand="goDoCommand('cmd_increaseFont')"/> @@ -584,6 +588,9 @@ <!-- Merge property items here --> </menupopup> + <menuitem id="snapToGrid" label="&grid.label;" accesskey="&grid.accesskey;" + oncommand="goDoCommand('cmd_grid')" observes="cmd_renderedHTMLEnabler"/> + <!-- Next 3 are items to append at the bottom of the formatMenuPopup --> <!-- label and accesskey filled in during menu creation --> <menuitem id="objectProperties" oncommand="goDoCommand('cmd_objectProperties')" observes="cmd_renderedHTMLEnabler"/> @@ -852,6 +859,12 @@ onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_align', 'justify')"/> </toolbarbutton> + <toolbarbutton id="absolutePositionButton" type="checkbox" observes="cmd_absPos"> + <observes element="cmd_absPos" attribute="state" onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_absPos', 'absolute')"/> + </toolbarbutton> + <toolbarbutton id="decreaseZIndexButton" observes="cmd_decreaseZIndex"/> + <toolbarbutton id="increaseZIndexButton" observes="cmd_increaseZIndex"/> + <!-- Edit Mode toolbar --> <tab id="NormalModeButton" class="tab-bottom edit-mode _plain" type="text" selected="1" label="&NormalModeTab.label;" oncommand="goDoCommand('cmd_NormalMode');" tooltiptext="&NormalMode.tooltip;"/> diff --git a/mozilla/editor/ui/composer/content/pref-toolbars.xul b/mozilla/editor/ui/composer/content/pref-toolbars.xul index 75a5dc95a92..655ad69c89a 100644 --- a/mozilla/editor/ui/composer/content/pref-toolbars.xul +++ b/mozilla/editor/ui/composer/content/pref-toolbars.xul @@ -48,7 +48,8 @@ var _elementIDs = [ "showNew", "showOpen", "showSave", "showPublish", "showPreview", "showSmaller", "showLarger", "showBold", "showCut", "showCopy", "showPaste", "showPrint", "showFind", "showBullets", "showNumbers", "showItalic", - "showImage", "showHline", "showTable", "showLink", "showAnchor", "showOutdent", "showIndent", "showUnderline"]; + "showImage", "showHline", "showTable", "showLink", "showAnchor", "showOutdent", "showIndent", "showUnderline", + "showAbsolutePosition", "showDecreaseZIndex", "showIncreaseZIndex" ]; ]]> </script> @@ -101,6 +102,8 @@ prefstring="editor.toolbars.showbutton.IncreaseFontSize"/> <checkbox label="&bold.label;" id="showBold" prefstring="editor.toolbars.showbutton.bold"/> + <checkbox label="&absolutePosition.label;" id="showAbsolutePosition" + prefstring="editor.toolbars.showbutton.absolutePosition"/> </vbox> <vbox flex="1"> <checkbox label="&bullets.label;" id="showBullets" @@ -109,6 +112,8 @@ prefstring="editor.toolbars.showbutton.ol"/> <checkbox label="&italic.label;" id="showItalic" prefstring="editor.toolbars.showbutton.italic"/> + <checkbox label="&decreaseZIndex.label;" id="showDecreaseZIndex" + prefstring="editor.toolbars.showbutton.decreaseZIndex"/> </vbox> <vbox flex="1"> <checkbox label="&outdent.label;" id="showOutdent" @@ -117,6 +122,8 @@ prefstring="editor.toolbars.showbutton.indent"/> <checkbox label="&underline.label;" id="showUnderline" prefstring="editor.toolbars.showbutton.underline"/> + <checkbox label="&increaseZIndex.label;" id="showIncreaseZIndex" + prefstring="editor.toolbars.showbutton.increaseZIndex"/> </vbox> </groupbox> </page> diff --git a/mozilla/editor/ui/composer/locale/en-US/editorOverlay.dtd b/mozilla/editor/ui/composer/locale/en-US/editorOverlay.dtd index 04b567c95bc..dfa137db484 100644 --- a/mozilla/editor/ui/composer/locale/en-US/editorOverlay.dtd +++ b/mozilla/editor/ui/composer/locale/en-US/editorOverlay.dtd @@ -395,6 +395,9 @@ <!ENTITY decreaseindent.accesskey "D"> <!ENTITY decreaseindentkb "-"> +<!ENTITY grid.label "Positioning grid"> +<!ENTITY grid.accesskey "t"> + <!ENTITY pageProperties.label "Page Title and Properties..."> <!ENTITY pageproperties.accesskey "g"> <!ENTITY colorsAndBackground.label "Page Colors and Background..."> diff --git a/mozilla/editor/ui/composer/locale/en-US/pref-toolbars.dtd b/mozilla/editor/ui/composer/locale/en-US/pref-toolbars.dtd index 46ca8c32815..9aea6c0d8b3 100644 --- a/mozilla/editor/ui/composer/locale/en-US/pref-toolbars.dtd +++ b/mozilla/editor/ui/composer/locale/en-US/pref-toolbars.dtd @@ -65,3 +65,7 @@ <!ENTITY outdent.label "Outdent"> <!ENTITY indent.label "Indent"> <!ENTITY underline.label "Underline"> + +<!ENTITY absolutePosition.label "Absolute positioning"> +<!ENTITY decreaseZIndex.label "Sent to back"> +<!ENTITY increaseZIndex.label "Bring to front"> diff --git a/mozilla/editor/ui/dialogs/content/EdSnapToGrid.js b/mozilla/editor/ui/dialogs/content/EdSnapToGrid.js new file mode 100644 index 00000000000..3b567f19005 --- /dev/null +++ b/mozilla/editor/ui/dialogs/content/EdSnapToGrid.js @@ -0,0 +1,79 @@ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998-1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +var gPrefs = GetPrefs(); +var gEditor; + +// dialog initialization code +function Startup() +{ + gEditor = GetCurrentEditor(); + if (!gEditor) + { + window.close(); + return; + } + + gEditor instanceof Components.interfaces.nsIHTMLAbsPosEditor; + + gDialog.enableSnapToGrid = document.getElementById("enableSnapToGrid"); + gDialog.sizeInput = document.getElementById("size"); + gDialog.sizeLabel = document.getElementById("sizeLabel"); + gDialog.unitLabel = document.getElementById("unitLabel"); + + // Initialize control values based on existing attributes + InitDialog() + + // SET FOCUS TO FIRST CONTROL + SetTextboxFocus(gDialog.sizeInput); + + // Resize window + window.sizeToContent(); + + SetWindowLocation(); +} + +// Set dialog widgets with attribute data +// We get them from globalElement copy so this can be used +// by AdvancedEdit(), which is shared by all property dialogs +function InitDialog() +{ + gDialog.enableSnapToGrid.checked = gEditor.snapToGridEnabled; + toggleSnapToGrid(); + + gDialog.sizeInput.value = gEditor.gridSize; +} + +function onAccept() +{ + gEditor.snapToGridEnabled = gDialog.enableSnapToGrid.checked; + gEditor.gridSize = gDialog.sizeInput.value; + + return true; +} + +function toggleSnapToGrid() +{ + SetElementEnabledById("size", gDialog.enableSnapToGrid.checked) + SetElementEnabledById("sizeLabel", gDialog.enableSnapToGrid.checked) + SetElementEnabledById("unitLabel", gDialog.enableSnapToGrid.checked) +} diff --git a/mozilla/editor/ui/dialogs/content/EdSnapToGrid.xul b/mozilla/editor/ui/dialogs/content/EdSnapToGrid.xul new file mode 100644 index 00000000000..78d24ce5288 --- /dev/null +++ b/mozilla/editor/ui/dialogs/content/EdSnapToGrid.xul @@ -0,0 +1,87 @@ +<?xml version="1.0"?> + +<!-- ***** BEGIN LICENSE BLOCK ***** + - Version: MPL 1.1/GPL 2.0/LGPL 2.1 + - + - The contents of this file are subject to the Mozilla Public License Version + - 1.1 (the "License"); you may not use this file except in compliance with + - the License. You may obtain a copy of the License at + - http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS IS" basis, + - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + - for the specific language governing rights and limitations under the + - License. + - + - The Original Code is Mozilla.org. + - + - The Initial Developer of the Original Code is + - Netscape Communications Corporation. + - Portions created by the Initial Developer are Copyright (C) 2003 + - the Initial Developer. All Rights Reserved. + - + - Contributor(s): + - Daniel Glazman (glazman@netscape.com) (Original author) + - + - Alternatively, the contents of this file may be used under the terms of + - either the GNU General Public License Version 2 or later (the "GPL"), or + - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + - in which case the provisions of the GPL or the LGPL are applicable instead + - of those above. If you wish to allow use of your version of this file only + - under the terms of either the GPL or the LGPL, and not to allow others to + - use your version of this file under the terms of the MPL, indicate your + - decision by deleting the provisions above and replace them with the notice + - and other provisions required by the LGPL or the GPL. If you do not delete + - the provisions above, a recipient may use your version of this file under + - the terms of any one of the MPL, the GPL or the LGPL. + - + - ***** END LICENSE BLOCK ***** --> + +<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?> +<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?> + +<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> +<?xul-overlay href="chrome://global/content/globalOverlay.xul"?> +<?xul-overlay href="chrome://communicator/content/utilityOverlay.xul"?> + +<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSnapToGrid.dtd"> + +<dialog title="&windowTitle.label;" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="Startup()" + ondialogaccept="return onAccept();" + ondialogcancel="return onCancel();"> + + <!-- Methods common to all editor dialogs --> + <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/> + <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/> + <!--- Element-specific methods --> + <script type="application/x-javascript" src="chrome://editor/content/EdSnapToGrid.js"/> + + <spacer id="location" offsetY="50" persist="offsetX offsetY"/> + + <checkbox id="enableSnapToGrid" + label="&enableSnapToGrid.label;" + accesskey="&enableSnapToGrid.accessKey;" + oncommand="toggleSnapToGrid();"/> + + <spacer class="spacer"/> + + <grid> + <columns><column/><column/><column /></columns> + <rows> + <row align="center"> + <label value="&sizeEditField.label;" + id="sizeLabel" + control="size" + accesskey="&sizeEditField.accessKey;"/> + <textbox class="narrow" id="size" oninput="forceInteger('size')"/> + <label id="unitLabel" + value="&pixelsLabel.value;" /> + </row> + </rows> + </grid> + + <spacer class="spacer"/> + <separator class="groove"/> +</dialog> diff --git a/mozilla/editor/ui/dialogs/locale/en-US/EditorSnapToGrid.dtd b/mozilla/editor/ui/dialogs/locale/en-US/EditorSnapToGrid.dtd new file mode 100644 index 00000000000..0ae962910ac --- /dev/null +++ b/mozilla/editor/ui/dialogs/locale/en-US/EditorSnapToGrid.dtd @@ -0,0 +1,48 @@ +<!-- ***** BEGIN LICENSE BLOCK ***** + - Version: MPL 1.1/GPL 2.0/LGPL 2.1 + - + - The contents of this file are subject to the Mozilla Public License Version + - 1.1 (the "License"); you may not use this file except in compliance with + - the License. You may obtain a copy of the License at + - http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS IS" basis, + - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + - for the specific language governing rights and limitations under the + - License. + - + - The Original Code is Mozilla.org. + - + - The Initial Developer of the Original Code is + - Netscape Communications Corporation. + - Portions created by the Initial Developer are Copyright (C) 2003 + - the Initial Developer. All Rights Reserved. + - + - Contributor(s): + - Daniel Glazman (glazman@netscape.com) (Original author) + - + - Alternatively, the contents of this file may be used under the terms of + - either the GNU General Public License Version 2 or later (the "GPL"), or + - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + - in which case the provisions of the GPL or the LGPL are applicable instead + - of those above. If you wish to allow use of your version of this file only + - under the terms of either the GPL or the LGPL, and not to allow others to + - use your version of this file under the terms of the MPL, indicate your + - decision by deleting the provisions above and replace them with the notice + - and other provisions required by the LGPL or the GPL. If you do not delete + - the provisions above, a recipient may use your version of this file under + - the terms of any one of the MPL, the GPL or the LGPL. + - + - ***** END LICENSE BLOCK ***** --> + + +<!-- Window title --> +<!ENTITY windowTitle.label "Snap to Grid"> + +<!ENTITY enableSnapToGrid.label "enable Snap to Grid"> +<!ENTITY enableSnapToGrid.accessKey "e"> + +<!ENTITY sizeEditField.label "Size:"> +<!ENTITY sizeEditField.accessKey "S"> + +<!ENTITY pixelsLabel.value "pixels"> diff --git a/mozilla/editor/ui/jar.mn b/mozilla/editor/ui/jar.mn index e5de1a5ab98..aadb0c378e7 100644 --- a/mozilla/editor/ui/jar.mn +++ b/mozilla/editor/ui/jar.mn @@ -31,6 +31,10 @@ comm.jar: content/editor/editorTasksOverlay.xul (composer/content/editorTasksOverlay.xul) content/editor/editorApplicationOverlay.js (composer/content/editorApplicationOverlay.js) content/editor/StructBarContextMenu.js (composer/content/StructBarContextMenu.js) + content/editor/images/sendtoback.gif (composer/content/images/sendtoback.gif) + content/editor/images/sendtoback-disabled.gif (composer/content/images/sendtoback-disabled.gif) + content/editor/images/bringtofront.gif (composer/content/images/bringtofront.gif) + content/editor/images/bringtofront-disabled.gif (composer/content/images/bringtofront-disabled.gif) content/editor/images/tag-anchor.gif (composer/content/images/tag-anchor.gif) content/editor/images/tag-abr.gif (composer/content/images/tag-abr.gif) content/editor/images/tag-acr.gif (composer/content/images/tag-acr.gif) @@ -167,6 +171,8 @@ comm.jar: content/editor/EdHLineProps.js (dialogs/content/EdHLineProps.js) content/editor/EdReplace.xul (dialogs/content/EdReplace.xul) content/editor/EdReplace.js (dialogs/content/EdReplace.js) + content/editor/EdSnapToGrid.xul (dialogs/content/EdSnapToGrid.xul) + content/editor/EdSnapToGrid.js (dialogs/content/EdSnapToGrid.js) content/editor/EdSpellCheck.xul (dialogs/content/EdSpellCheck.xul) content/editor/EdSpellCheck.js (dialogs/content/EdSpellCheck.js) content/editor/EdDictionary.xul (dialogs/content/EdDictionary.xul) @@ -260,6 +266,7 @@ en-US.jar: locale/en-US/editor/EdColorPicker.dtd (dialogs/locale/en-US/EdColorPicker.dtd) locale/en-US/editor/EditorPersonalDictionary.dtd (dialogs/locale/en-US/EditorPersonalDictionary.dtd) locale/en-US/editor/EditorReplace.dtd (dialogs/locale/en-US/EditorReplace.dtd) + locale/en-US/editor/EditorSnapToGrid.dtd (dialogs/locale/en-US/EditorSnapToGrid.dtd) locale/en-US/editor/EditorSpellCheck.dtd (dialogs/locale/en-US/EditorSpellCheck.dtd) locale/en-US/editor/EditorTableProperties.dtd (dialogs/locale/en-US/EditorTableProperties.dtd) locale/en-US/editor/EditorFormProperties.dtd (dialogs/locale/en-US/EditorFormProperties.dtd)