author | Masayuki Nakano <masayuki@d-toybox.com> |
Wed, 04 Apr 2018 22:27:49 +0900 | |
changeset 830010 | d21676503e6642937f54219f0e3c5a36682cd426 |
parent 830009 | 641d0c0f8190fc7329a47450c16901621491eb20 |
child 830011 | 0aa4ba4f041b207e9c400b0ef18ef13519b11c5b |
push id | 118808 |
push user | masayuki@d-toybox.com |
push date | Sat, 18 Aug 2018 08:51:19 +0000 |
reviewers | m_kato |
bugs | 1449564 |
milestone | 63.0a1 |
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -2723,16 +2723,17 @@ static const struct MidasCommand gMidasC { "formatblock", "cmd_paragraphState", "", false, false }, { "heading", "cmd_paragraphState", "", false, false }, { "styleWithCSS", "cmd_setDocumentUseCSS", "", false, true }, { "contentReadOnly", "cmd_setDocumentReadOnly", "", false, true }, { "insertBrOnReturn", "cmd_insertBrOnReturn", "", false, true }, { "defaultParagraphSeparator", "cmd_defaultParagraphSeparator", "", false, false }, { "enableObjectResizing", "cmd_enableObjectResizing", "", false, true }, { "enableInlineTableEditing", "cmd_enableInlineTableEditing", "", false, true }, + { "enableAbsolutePositionEditing", "cmd_enableAbsolutePositionEditing", "", false, true }, #if 0 // no editor support to remove alignments right now { "justifynone", "cmd_align", "", true, false }, // the following will need special review before being turned on { "saveas", "cmd_saveAs", "", true, false }, { "print", "cmd_print", "", true, false }, #endif
--- a/editor/libeditor/HTMLAbsPositionEditor.cpp +++ b/editor/libeditor/HTMLAbsPositionEditor.cpp @@ -104,24 +104,24 @@ HTMLEditor::GetAbsolutelyPositionedSelec element = element->GetParentElement(); } return nullptr; } NS_IMETHODIMP HTMLEditor::GetAbsolutePositioningEnabled(bool* aIsEnabled) { - *aIsEnabled = AbsolutePositioningEnabled(); + *aIsEnabled = IsAbsolutePositionEditorEnabled(); return NS_OK; } NS_IMETHODIMP HTMLEditor::SetAbsolutePositioningEnabled(bool aIsEnabled) { - mIsAbsolutelyPositioningEnabled = aIsEnabled; + EnableAbsolutePositionEditor(aIsEnabled); return NS_OK; } nsresult HTMLEditor::RelativeChangeElementZIndex(Element& aElement, int32_t aChange, int32_t* aReturn) {
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp +++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp @@ -290,17 +290,17 @@ NS_IMETHODIMP HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection) { if (NS_WARN_IF(!aSelection)) { return NS_ERROR_INVALID_ARG; } // early way out if all contextual UI extensions are disabled if (NS_WARN_IF(!IsObjectResizerEnabled() && - !mIsAbsolutelyPositioningEnabled && + !IsAbsolutePositionEditorEnabled() && !IsInlineTableEditorEnabled())) { return NS_OK; } // Don't change selection state if we're moving. if (mIsMoving) { return NS_OK; } @@ -315,17 +315,17 @@ HTMLEditor::CheckSelectionStateForAnonym if (!focusElement->IsInUncomposedDoc()) { return NS_OK; } // what's its tag? nsAtom* focusTagAtom = focusElement->NodeInfo()->NameAtom(); RefPtr<Element> absPosElement; - if (mIsAbsolutelyPositioningEnabled) { + if (IsAbsolutePositionEditorEnabled()) { // Absolute Positioning support is enabled, is the selection contained // in an absolutely positioned element ? absPosElement = GetAbsolutelyPositionedSelectionContainer(); } RefPtr<Element> cellElement; if (IsObjectResizerEnabled() || IsInlineTableEditorEnabled()) { // Resizing or Inline Table Editing is enabled, we need to check if the @@ -356,17 +356,17 @@ HTMLEditor::CheckSelectionStateForAnonym // at this point, focusElement contains the element for Resizing, // cellElement contains the element for InlineTableEditing // absPosElement contains the element for Positioning // Note: All the Hide/Show methods below may change attributes on real // content which means a DOMAttrModified handler may cause arbitrary // side effects while this code runs (bug 420439). - if (mIsAbsolutelyPositioningEnabled && mAbsolutelyPositionedObject && + if (IsAbsolutePositionEditorEnabled() && mAbsolutelyPositionedObject && absPosElement != mAbsolutelyPositionedObject) { HideGrabber(); NS_ASSERTION(!mAbsolutelyPositionedObject, "HideGrabber failed"); } if (IsObjectResizerEnabled() && mResizedObject && mResizedObject != focusElement) { nsresult rv = HideResizers(); @@ -397,17 +397,17 @@ HTMLEditor::CheckSelectionStateForAnonym } else { nsresult rv = ShowResizers(*focusElement); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } } - if (mIsAbsolutelyPositioningEnabled && absPosElement && + if (IsAbsolutePositionEditorEnabled() && absPosElement && IsModifiableNode(*absPosElement) && absPosElement != hostContent) { if (mAbsolutelyPositionedObject) { nsresult rv = RefreshGrabber(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { nsresult rv = ShowGrabber(*absPosElement);
--- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -115,17 +115,17 @@ HTMLEditor::HTMLEditor() : mCRInParagraphCreatesParagraph(false) , mCSSAware(false) , mSelectedCellIndex(0) , mHasShownResizers(false) , mIsObjectResizingEnabled(false) , mIsResizing(false) , mPreserveRatio(false) , mResizedObjectIsAnImage(false) - , mIsAbsolutelyPositioningEnabled(true) + , mIsAbsolutelyPositioningEnabled(false) , mResizedObjectIsAbsolutelyPositioned(false) , mHasShownGrabber(false) , mGrabberClicked(false) , mIsMoving(false) , mSnapToGridEnabled(false) , mHasShownInlineTableEditor(false) , mIsInlineTableEditingEnabled(false) , mOriginalX(0)
--- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -242,22 +242,32 @@ public: { mIsInlineTableEditingEnabled = aEnable; } bool IsInlineTableEditorEnabled() const { return mIsInlineTableEditingEnabled; } - // non-virtual methods of interface methods - bool AbsolutePositioningEnabled() const + /** + * Enable/disable absolute position editor, resizing absolute positioned + * elements (required object resizers enabled) or positioning them with + * dragging grabber. + */ + void EnableAbsolutePositionEditor(bool aEnable) + { + mIsAbsolutelyPositioningEnabled = aEnable; + } + bool IsAbsolutePositionEditorEnabled() const { return mIsAbsolutelyPositioningEnabled; } + // non-virtual methods of interface methods + /** * returns the deepest absolutely positioned container of the selection * if it exists or null. */ already_AddRefed<Element> GetAbsolutelyPositionedSelectionContainer(); Element* GetPositionedElement() const {
--- a/editor/libeditor/HTMLEditorCommands.cpp +++ b/editor/libeditor/HTMLEditorCommands.cpp @@ -1079,46 +1079,45 @@ AlignCommand::SetState(HTMLEditor* aHTML AbsolutePositioningCommand::AbsolutePositioningCommand() : StateUpdatingCommandBase(nsGkAtoms::_empty) { } NS_IMETHODIMP AbsolutePositioningCommand::IsCommandEnabled(const char* aCommandName, nsISupports* aCommandRefCon, - bool* outCmdEnabled) + bool* aOutCmdEnabled) { - *outCmdEnabled = false; + *aOutCmdEnabled = false; nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon); if (!editor) { return NS_OK; } mozilla::HTMLEditor* htmlEditor = editor->AsHTMLEditor(); if (!htmlEditor) { return NS_OK; } if (!htmlEditor->IsSelectionEditable()) { return NS_OK; } - *outCmdEnabled = htmlEditor->AbsolutePositioningEnabled(); + *aOutCmdEnabled = htmlEditor->IsAbsolutePositionEditorEnabled(); return NS_OK; } nsresult AbsolutePositioningCommand::GetCurrentState(HTMLEditor* aHTMLEditor, nsICommandParams* aParams) { if (NS_WARN_IF(!aHTMLEditor)) { return NS_ERROR_INVALID_ARG; } nsCommandParams* params = aParams->AsCommandParams(); - bool isEnabled = aHTMLEditor->AbsolutePositioningEnabled(); - if (!isEnabled) { + if (!aHTMLEditor->IsAbsolutePositionEditorEnabled()) { params->SetBool(STATE_MIXED, false); params->SetCString(STATE_ATTRIBUTE, EmptyCString()); return NS_OK; } RefPtr<Element> container = aHTMLEditor->GetAbsolutelyPositionedSelectionContainer(); params->SetBool(STATE_MIXED, false); @@ -1138,40 +1137,41 @@ AbsolutePositioningCommand::ToggleState( RefPtr<Element> container = aHTMLEditor->GetAbsolutelyPositionedSelectionContainer(); return aHTMLEditor->SetSelectionToAbsoluteOrStatic(!container); } NS_IMETHODIMP DecreaseZIndexCommand::IsCommandEnabled(const char* aCommandName, - nsISupports* refCon, - bool* outCmdEnabled) + nsISupports* aRefCon, + bool* aOutCmdEnabled) { - nsCOMPtr<nsIEditor> editor = do_QueryInterface(refCon); + nsCOMPtr<nsIEditor> editor = do_QueryInterface(aRefCon); if (NS_WARN_IF(!editor)) { return NS_ERROR_FAILURE; } mozilla::HTMLEditor* htmlEditor = editor->AsHTMLEditor(); if (NS_WARN_IF(!htmlEditor)) { return NS_ERROR_FAILURE; } - *outCmdEnabled = htmlEditor->AbsolutePositioningEnabled(); - if (!(*outCmdEnabled)) + if (!htmlEditor->IsAbsolutePositionEditorEnabled()) { + *aOutCmdEnabled = false; return NS_OK; + } RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement(); - *outCmdEnabled = false; if (!positionedElement) { + *aOutCmdEnabled = false; return NS_OK; } int32_t z = htmlEditor->GetZIndex(*positionedElement); - *outCmdEnabled = (z > 0); + *aOutCmdEnabled = (z > 0); return NS_OK; } NS_IMETHODIMP DecreaseZIndexCommand::DoCommand(const char* aCommandName, nsISupports* refCon) { nsCOMPtr<nsIEditor> editor = do_QueryInterface(refCon); @@ -1204,34 +1204,34 @@ DecreaseZIndexCommand::GetCommandStatePa nsresult rv = IsCommandEnabled(aCommandName, refCon, &enabled); NS_ENSURE_SUCCESS(rv, rv); return aParams->AsCommandParams()->SetBool(STATE_ENABLED, enabled); } NS_IMETHODIMP IncreaseZIndexCommand::IsCommandEnabled(const char* aCommandName, - nsISupports* refCon, - bool* outCmdEnabled) + nsISupports* aRefCon, + bool* aOutCmdEnabled) { - nsCOMPtr<nsIEditor> editor = do_QueryInterface(refCon); + nsCOMPtr<nsIEditor> editor = do_QueryInterface(aRefCon); if (NS_WARN_IF(!editor)) { return NS_ERROR_FAILURE; } mozilla::HTMLEditor* htmlEditor = editor->AsHTMLEditor(); if (NS_WARN_IF(!htmlEditor)) { return NS_ERROR_FAILURE; } - *outCmdEnabled = htmlEditor->AbsolutePositioningEnabled(); - if (!(*outCmdEnabled)) + if (!htmlEditor->IsAbsolutePositionEditorEnabled()) { + *aOutCmdEnabled = false; return NS_OK; + } - Element* positionedElement = htmlEditor->GetPositionedElement(); - *outCmdEnabled = (nullptr != positionedElement); + *aOutCmdEnabled = !!htmlEditor->GetPositionedElement(); return NS_OK; } NS_IMETHODIMP IncreaseZIndexCommand::DoCommand(const char* aCommandName, nsISupports* refCon) { nsCOMPtr<nsIEditor> editor = do_QueryInterface(refCon);
--- a/editor/libeditor/HTMLEditorController.cpp +++ b/editor/libeditor/HTMLEditorController.cpp @@ -64,17 +64,18 @@ HTMLEditorController::RegisterEditorDocS // commands that may get or change state NS_REGISTER_FIRST_COMMAND(SetDocumentStateCommand, "cmd_setDocumentModified") NS_REGISTER_NEXT_COMMAND(SetDocumentStateCommand, "cmd_setDocumentUseCSS") NS_REGISTER_NEXT_COMMAND(SetDocumentStateCommand, "cmd_setDocumentReadOnly") NS_REGISTER_NEXT_COMMAND(SetDocumentStateCommand, "cmd_insertBrOnReturn") NS_REGISTER_NEXT_COMMAND(SetDocumentStateCommand, "cmd_defaultParagraphSeparator") NS_REGISTER_NEXT_COMMAND(SetDocumentStateCommand, "cmd_enableObjectResizing") - NS_REGISTER_LAST_COMMAND(SetDocumentStateCommand, "cmd_enableInlineTableEditing") + NS_REGISTER_NEXT_COMMAND(SetDocumentStateCommand, "cmd_enableInlineTableEditing") + NS_REGISTER_LAST_COMMAND(SetDocumentStateCommand, "cmd_enableAbsolutePositionEditing") NS_REGISTER_ONE_COMMAND(SetDocumentOptionsCommand, "cmd_setDocumentOptions") return NS_OK; } // static nsresult
--- a/editor/libeditor/HTMLEditorDocumentCommands.cpp +++ b/editor/libeditor/HTMLEditorDocumentCommands.cpp @@ -357,16 +357,31 @@ SetDocumentStateCommand::DoCommandParams bool enabled = params->GetBool(STATE_ATTRIBUTE, error); if (NS_WARN_IF(error.Failed())) { return error.StealNSResult(); } htmlEditor->EnableInlineTableEditor(enabled); return NS_OK; } + if (!nsCRT::strcmp(aCommandName, "cmd_enableAbsolutePositionEditing")) { + NS_ENSURE_ARG_POINTER(aParams); + HTMLEditor* htmlEditor = textEditor->AsHTMLEditor(); + if (NS_WARN_IF(!htmlEditor)) { + return NS_ERROR_INVALID_ARG; + } + ErrorResult error; + bool enabled = params->GetBool(STATE_ATTRIBUTE, error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + htmlEditor->EnableAbsolutePositionEditor(enabled); + return NS_OK; + } + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP SetDocumentStateCommand::GetCommandStateParams(const char* aCommandName, nsICommandParams* aParams, nsISupports* refCon) { @@ -519,16 +534,28 @@ SetDocumentStateCommand::GetCommandState // and nsHTMLDocument::QueryCommandState(). rv = params->SetBool(STATE_ALL, htmlEditor->IsInlineTableEditorEnabled()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } + // cmd_enableAbsolutePositionEditing is a Gecko specific command, + // "cenableAbsolutePositionEditing". + if (!nsCRT::strcmp(aCommandName, "cmd_enableAbsolutePositionEditing")) { + NS_ENSURE_ARG_POINTER(aParams); + HTMLEditor* htmlEditor = textEditor->AsHTMLEditor(); + if (NS_WARN_IF(!htmlEditor)) { + return NS_ERROR_INVALID_ARG; + } + return params->SetBool(STATE_ALL, + htmlEditor->IsAbsolutePositionEditorEnabled()); + } + return NS_ERROR_NOT_IMPLEMENTED; } /** * Commands just for state notification * As of 11/21/02, possible commands are: * "obs_documentCreated" * "obs_documentWillBeDestroyed"
--- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -254,16 +254,20 @@ skip-if = toolkit == 'android' # bug 131 [test_bug1385905.html] [test_bug1390562.html] [test_bug1394758.html] [test_bug1399722.html] [test_bug1406726.html] [test_bug1409520.html] [test_bug1425997.html] +[test_abs_positioner_appearance.html] +skip-if = toolkit == 'android' && debug # bug 1480702, causes permanent failure of non-related test +[test_abs_positioner_positioning_elements.html] +skip-if = android_version == '18' # bug 1147989 [test_CF_HTML_clipboard.html] subsuite = clipboard [test_composition_event_created_in_chrome.html] [test_contenteditable_focus.html] [test_documentCharacterSet.html] [test_dom_input_event_on_htmleditor.html] skip-if = toolkit == 'android' # bug 1054087 [test_dom_input_event_on_texteditor.html]
copy from editor/libeditor/tests/test_resizers_appearance.html copy to editor/libeditor/tests/test_abs_positioner_appearance.html --- a/editor/libeditor/tests/test_resizers_appearance.html +++ b/editor/libeditor/tests/test_abs_positioner_appearance.html @@ -1,12 +1,12 @@ <!DOCTYPE html> <html> <head> - <title>Test for resizers appearance</title> + <title>Test for absolute positioner appearance</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <p id="display"></p> <div id="content" style="display: none;"> @@ -28,68 +28,140 @@ SimpleTest.waitForFocus(async function() resolve(); }, {once: true}); }); } let editor = document.getElementById("editor"); let outOfEditor = document.getElementById("clickaway"); - const kTests = [ - { description: "<img>", - innerHTML: "<img id=\"target\" src=\"green.png\" width=\"100\" height=\"100\">", - resizable: true, - }, - { description: "<table>", - innerHTML: "<table id=\"target\" border><tr><td>1-1</td><td>1-2</td></tr><tr><td>2-1</td><td>2-2</td></tr></table>", - resizable: true, - }, - { description: "absolute positioned <div>", - innerHTML: "<div id=\"target\" style=\"position: absolute; top: 50px; left: 50px;\">positioned</div>", - resizable: true, - }, - { description: "fixed positioned <div>", - innerHTML: "<div id=\"target\" style=\"position: fixed; top: 50px; left: 50px;\">positioned</div>", - resizable: false, - }, - { description: "relative positioned <div>", - innerHTML: "<div id=\"target\" style=\"position: relative; top: 50px; left: 50px;\">positioned</div>", - resizable: false, - }, - ]; + async function testIfAppears() { + const kTests = [ + { description: "absolute positioned <div>", + innerHTML: "<div id=\"target\" style=\"position: absolute; top: 50px; left: 50px;\">positioned</div>", + movable: true, + }, + { description: "fixed positioned <div>", + innerHTML: "<div id=\"target\" style=\"position: fixed; top: 50px; left: 50px;\">positioned</div>", + movable: false, + }, + { description: "relative positioned <div>", + innerHTML: "<div id=\"target\" style=\"position: relative; top: 50px; left: 50px;\">positioned</div>", + movable: false, + }, + ]; + + for (const kTest of kTests) { + const kDescription = "testIfAppears, " + kTest.description + ": "; + editor.innerHTML = kTest.innerHTML; + let target = document.getElementById("target"); + + document.execCommand("enableAbsolutePositionEditing", false, false); + ok(!document.queryCommandState("enableAbsolutePositionEditing"), + kDescription + "Absolute positioned element editor should be disabled by the call of execCommand"); + + synthesizeMouseAtCenter(outOfEditor, {}); + let promiseSelectionChangeEvent1 = waitForSelectionChange(); + synthesizeMouseAtCenter(target, {}); + await promiseSelectionChangeEvent1; + + ok(!target.hasAttribute("_moz_abspos"), + kDescription + "While enableAbsolutePositioner is disabled, positioner shouldn't appear"); + + document.execCommand("enableAbsolutePositionEditing", false, true); + ok(document.queryCommandState("enableAbsolutePositionEditing"), + kDescription + "Absolute positioned element editor should be enabled by the call of execCommand"); + + synthesizeMouseAtCenter(outOfEditor, {}); + let promiseSelectionChangeEvent2 = waitForSelectionChange(); + synthesizeMouseAtCenter(target, {}); + await promiseSelectionChangeEvent2; + + is(target.hasAttribute("_moz_abspos"), kTest.movable, + kDescription + (kTest.movable ? "While enableAbsolutePositionEditing is enabled, positioner should appear" : + "Even while enableAbsolutePositionEditing is enabled, positioner shouldn't appear")); + } + } - for (const kTest of kTests) { - const kDescription = kTest.description + ": "; - editor.innerHTML = kTest.innerHTML; - let target = document.getElementById("target"); - - document.execCommand("enableObjectResizing", false, false); - ok(!document.queryCommandState("enableObjectResizing"), - kDescription + "Object resizer should be disabled by the call of execCommand"); - - synthesizeMouseAtCenter(outOfEditor, {}); - let promiseSelectionChangeEvent1 = waitForSelectionChange(); - synthesizeMouseAtCenter(target, {}); - await promiseSelectionChangeEvent1; + async function testStyle() { + // See HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(). + const kTests = [ + { description: "background-color: transparent; color: white;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-color: transparent; " + + "color: white;\">positioned</div>", + value: "black", + }, + { description: "background-color: transparent; color: black;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-color: transparent; " + + "color: black;\">positioned</div>", + value: "white", + }, + { description: "background-color: black; color: white;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-color: black; " + + "color: white;\">positioned</div>", + value: "", + }, + { description: "background-color: white; color: black;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-color: white; " + + "color: black;\">positioned</div>", + value: "", + }, + { description: "background-image: green.png; background-color: black; color: white;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-image: green.png; " + + "background-color: black; " + + "color: white;\">positioned</div>", + value: "", + }, + { description: "background-image: green.png; background-color: white; color: black;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-image: green.png; " + + "background-color: white; " + + "color: black;\">positioned</div>", + value: "", + }, + { description: "background-image: green.png;", + innerHTML: "<div id=\"target\" style=\"position: absolute; " + + "top: 50%; left: 50%; " + + "background-image: green.png;\">positioned</div>", + value: "white", // XXX Why? background-image is not "none"... + }, + ]; - ok(!target.hasAttribute("_moz_resizing"), - kDescription + ": While enableObjectResizing is disabled, resizers shouldn't appear"); + document.execCommand("enableAbsolutePositionEditing", false, true); + ok(document.queryCommandState("enableAbsolutePositionEditing"), + "testStyle, Absolute positioned element editor should be enabled by the call of execCommand"); - document.execCommand("enableObjectResizing", false, true); - ok(document.queryCommandState("enableObjectResizing"), - kDescription + "Object resizer should be enabled by the call of execCommand"); + for (const kTest of kTests) { + const kDescription = "testStyle, " + kTest.description + ": "; + + editor.innerHTML = kTest.innerHTML; + let target = document.getElementById("target"); - synthesizeMouseAtCenter(outOfEditor, {}); - let promiseSelectionChangeEvent2 = waitForSelectionChange(); - synthesizeMouseAtCenter(target, {}); - await promiseSelectionChangeEvent2; + synthesizeMouseAtCenter(outOfEditor, {}); + let promiseSelectionChangeEvent = waitForSelectionChange(); + synthesizeMouseAtCenter(target, {}); + await promiseSelectionChangeEvent; - is(target.hasAttribute("_moz_resizing"), kTest.resizable, - kDescription + (kTest.resizable ? "While enableObjectResizing is enabled, resizers should appear" : - "Even while enableObjectResizing is enabled, resizers shouldn't appear")); + is(target.getAttribute("_moz_abspos"), kTest.value, + kDescription + "The value of _moz_abspos attribute is unexpected"); + } } + await testIfAppears(); + await testStyle(); + SimpleTest.finish(); }); </script> </pre> </body> </html>
copy from editor/libeditor/tests/test_resizers_resizing_elements.html copy to editor/libeditor/tests/test_abs_positioner_positioning_elements.html --- a/editor/libeditor/tests/test_resizers_resizing_elements.html +++ b/editor/libeditor/tests/test_abs_positioner_positioning_elements.html @@ -1,230 +1,120 @@ <!DOCTYPE HTML> <html> <head> - <title>Test for resizers of some elements</title> + <title>Test for positioners of absolute positioned elements</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <style> #target { background-color: green; } </style> </head> <body> <p id="display"></p> -<div id="content" contenteditable style="width: 200px; height: 200px;"></div> -<div id="clickaway" style="width: 10px; height: 10px"></div> +<div id="content" contenteditable style="height: 200px; width: 200px;"></div> +<div id="clickaway" style="position: absolute; top: 250px; width: 10px; height: 10px; z-index: 100;"></div> <img src="green.png"><!-- for ensuring to load the image at first test of <img> case --> <pre id="test"> <script type="application/javascript"> "use strict"; SimpleTest.waitForExplicitFinish(); SimpleTest.waitForFocus(async function() { - document.execCommand("enableObjectResizing", false, true); - ok(document.queryCommandState("enableObjectResizing"), - "Object resizer should be enabled by the call of execCommand"); + document.execCommand("enableAbsolutePositionEditing", false, true); + ok(document.queryCommandState("enableAbsolutePositionEditing"), + "Absolute positioned element editor should be enabled by the call of execCommand"); let outOfEditor = document.getElementById("clickaway"); - function cancel(e) { e.stopPropagation(); } + function cancel(e) { /* TODO: e.stopPropagation(); */ } let content = document.getElementById("content"); content.addEventListener("mousedown", cancel); content.addEventListener("mousemove", cancel); content.addEventListener("mouseup", cancel); async function waitForSelectionChange() { return new Promise(resolve => { document.addEventListener("selectionchange", () => { resolve(); }, {once: true}); }); } - async function doTest(aDescription, aPreserveRatio, aInnerHTML) { - let description = aDescription; - if (SpecialPowers.getBoolPref("editor.resizing.preserve_ratio")) { - description += " (preserve ratio pref is true)"; - } - description += ": "; + async function doTest(aDescription, aInnerHTML) { content.innerHTML = aInnerHTML; + let description = aDescription + ": "; let target = document.getElementById("target"); + target.style.position = "absolute"; - /** - * This function is a generic resizer test. - * We have 8 resizers that we'd like to test, and each can be moved in 8 different directions. - * In specifying baseX, W can be considered to be the width of the image, and for baseY, H - * can be considered to be the height of the image. deltaX and deltaY are regular pixel values - * which can be positive or negative. - */ - const W = 1; - const H = 1; - async function testResizer(baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY) { - ok(true, description + "testResizer(" + [baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY].join(", ") + ")"); + async function testPositioner(aDeltaX, aDeltaY) { + ok(true, description + "testPositioner(" + [aDeltaX, aDeltaY].join(", ") + ")"); - // Reset the dimensions of the target. - target.style.width = "150px"; - target.style.height = "150px"; - let rect = target.getBoundingClientRect(); - is(rect.width, 150, description + "Sanity check the width"); - is(rect.height, 150, description + "Sanity check the height"); + // Reset the position of the target. + target.style.top = "50px"; + target.style.left = "50px"; - // Click on the target to show the resizers + // Click on the target to show the positioner. let promiseSelectionChangeEvent = waitForSelectionChange(); synthesizeMouseAtCenter(target, {}); await promiseSelectionChangeEvent; - // Determine which resizer we're dealing with. - let basePosX = rect.width * baseX; - let basePosY = rect.height * baseY; + let rect = target.getBoundingClientRect(); + + ok(target.hasAttribute("_moz_abspos"), + description + "While enableAbsolutePositionEditing is enabled, the positioner should appear"); - // Click on the correct resizer - synthesizeMouse(target, basePosX, basePosY, {type: "mousedown"}); - // Drag it delta pixels to the right and bottom (or maybe left and top!) - synthesizeMouse(target, basePosX + deltaX, basePosY + deltaY, {type: "mousemove"}); + // left is abs positioned element's left + margin-left + border-left-width + 12. + // XXX Perhaps, we need to add border-left-width here if you add new test to have thick border. + const kPositionerX = 18 + // top is abs positioned element's top + margin-top + border-top-width - 14. + // XXX Perhaps, we need to add border-top-width here if you add new test to have thick border. + const kPositionerY = -7; + + // Click on the positioner. + synthesizeMouse(target, kPositionerX, kPositionerY, {type: "mousedown"}); + // Drag it delta pixels. + synthesizeMouse(target, kPositionerX + aDeltaX, kPositionerY + aDeltaY, {type: "mousemove"}); // Release the mouse button - synthesizeMouse(target, basePosX + deltaX, basePosY + deltaY, {type: "mouseup"}); + synthesizeMouse(target, kPositionerX + aDeltaX, kPositionerY + aDeltaY, {type: "mouseup"}); // Move the mouse delta more pixels to the same direction to make sure that the - // resize operation has stopped. - synthesizeMouse(target, basePosX + deltaX * 2, basePosY + deltaY * 2, {type: "mousemove"}); - // Click outside of the editor to hide the resizers + // positioning operation has stopped. + synthesizeMouse(target, kPositionerX + aDeltaX * 2, kPositionerY + aDeltaY * 2, {type: "mousemove"}); + // Click outside of the image to hide the positioner. synthesizeMouseAtCenter(outOfEditor, {}); - // Get the new dimensions for the target + // Get the new dimensions for the absolute positioned element. let newRect = target.getBoundingClientRect(); - isfuzzy(newRect.width, rect.width + expectedDeltaX, 1, description + "The width should be increased by " + expectedDeltaX + " pixels"); - isfuzzy(newRect.height, rect.height + expectedDeltaY, 1, description + "The height should be increased by " + expectedDeltaY + "pixels"); + isfuzzy(newRect.x, rect.x + aDeltaX, 1, description + "The left should be increased by " + aDeltaX + " pixels"); + isfuzzy(newRect.y, rect.y + aDeltaY, 1, description + "The top should be increased by " + aDeltaY + "pixels"); } - // Account for changes in the resizing behavior when we're trying to preserve - // the aspect ration of image. - // ignoredGrowth means we don't change the size of a dimension because otherwise - // the aspect ratio would change undesirably. - // needlessGrowth means that we change the size of a dimension perpendecular to - // the mouse movement axis in order to preserve the aspect ratio. - // reversedGrowth means that we change the size of a dimension in the opposite - // direction to the mouse movement in order to maintain the aspect ratio. - const ignoredGrowth = aPreserveRatio ? 0 : 1; - const needlessGrowth = aPreserveRatio ? 1 : 0; - const reversedGrowth = aPreserveRatio ? -1 : 1; - - // top resizer - await testResizer(W/2, 0, -10, -10, 0, 10); - await testResizer(W/2, 0, -10, 0, 0, 0); - await testResizer(W/2, 0, -10, 10, 0, -10); - await testResizer(W/2, 0, 0, -10, 0, 10); - await testResizer(W/2, 0, 0, 0, 0, 0); - await testResizer(W/2, 0, 0, 10, 0, -10); - await testResizer(W/2, 0, 10, -10, 0, 10); - await testResizer(W/2, 0, 10, 0, 0, 0); - await testResizer(W/2, 0, 10, 10, 0, -10); - - // top right resizer - await testResizer( W, 0, -10, -10, -10 * reversedGrowth, 10); - await testResizer( W, 0, -10, 0, -10 * ignoredGrowth, 0); - await testResizer( W, 0, -10, 10, -10, -10); - await testResizer( W, 0, 0, -10, 10 * needlessGrowth, 10); - await testResizer( W, 0, 0, 0, 0, 0); - await testResizer( W, 0, 0, 10, 0, -10 * ignoredGrowth); - await testResizer( W, 0, 10, -10, 10, 10); - await testResizer( W, 0, 10, 0, 10, 10 * needlessGrowth); - await testResizer( W, 0, 10, 10, 10, -10 * reversedGrowth); - - // right resizer - await testResizer( W, H/2, -10, -10, -10, 0); - await testResizer( W, H/2, -10, 0, -10, 0); - await testResizer( W, H/2, -10, 10, -10, 0); - await testResizer( W, H/2, 0, -10, 0, 0); - await testResizer( W, H/2, 0, 0, 0, 0); - await testResizer( W, H/2, 0, 10, 0, 0); - await testResizer( W, H/2, 10, -10, 10, 0); - await testResizer( W, H/2, 10, 0, 10, 0); - await testResizer( W, H/2, 10, 10, 10, 0); - - // bottom right resizer - await testResizer( W, H, -10, -10, -10, -10); - await testResizer( W, H, -10, 0, -10 * ignoredGrowth, 0); - await testResizer( W, H, -10, 10, -10 * reversedGrowth, 10); - await testResizer( W, H, 0, -10, 0, -10 * ignoredGrowth); - await testResizer( W, H, 0, 0, 0, 0); - await testResizer( W, H, 0, 10, 10 * needlessGrowth, 10); - await testResizer( W, H, 10, -10, 10, -10 * reversedGrowth); - await testResizer( W, H, 10, 0, 10, 10 * needlessGrowth); - await testResizer( W, H, 10, 10, 10, 10); - - // bottom resizer - await testResizer(W/2, H, -10, -10, 0, -10); - await testResizer(W/2, H, -10, 0, 0, 0); - await testResizer(W/2, H, -10, 10, 0, 10); - await testResizer(W/2, H, 0, -10, 0, -10); - await testResizer(W/2, H, 0, 0, 0, 0); - await testResizer(W/2, H, 0, 10, 0, 10); - await testResizer(W/2, H, 10, -10, 0, -10); - await testResizer(W/2, H, 10, 0, 0, 0); - await testResizer(W/2, H, 10, 10, 0, 10); - - // bottom left resizer - await testResizer( 0, H, -10, -10, 10, -10 * reversedGrowth); - await testResizer( 0, H, -10, 0, 10, 10 * needlessGrowth); - await testResizer( 0, H, -10, 10, 10, 10); - await testResizer( 0, H, 0, -10, 0, -10 * ignoredGrowth); - await testResizer( 0, H, 0, 0, 0, 0); - await testResizer( 0, H, 0, 10, 10 * needlessGrowth, 10); - await testResizer( 0, H, 10, -10, -10, -10); - await testResizer( 0, H, 10, 0, -10 * ignoredGrowth, 0); - await testResizer( 0, H, 10, 10, -10 * reversedGrowth, 10); - - // left resizer - await testResizer( 0, H/2, -10, -10, 10, 0); - await testResizer( 0, H/2, -10, 0, 10, 0); - await testResizer( 0, H/2, -10, 10, 10, 0); - await testResizer( 0, H/2, 0, -10, 0, 0); - await testResizer( 0, H/2, 0, 0, 0, 0); - await testResizer( 0, H/2, 0, 10, 0, 0); - await testResizer( 0, H/2, 10, -10, -10, 0); - await testResizer( 0, H/2, 10, 0, -10, 0); - await testResizer( 0, H/2, 10, 10, -10, 0); - - // top left resizer - await testResizer( 0, 0, -10, -10, 10, 10); - await testResizer( 0, 0, -10, 0, 10, 10 * needlessGrowth); - await testResizer( 0, 0, -10, 10, 10, -10 * reversedGrowth); - await testResizer( 0, 0, 0, -10, 10 * needlessGrowth, 10); - await testResizer( 0, 0, 0, 0, 0, 0); - await testResizer( 0, 0, 0, 10, 0, -10 * ignoredGrowth); - await testResizer( 0, 0, 10, -10, -10 * reversedGrowth, 10); - await testResizer( 0, 0, 10, 0, -10 * ignoredGrowth, 0); - await testResizer( 0, 0, 10, 10, -10, -10); + await testPositioner( 10, 10); + await testPositioner( 10, -10); + await testPositioner(-10, 10); + await testPositioner(-10, -10); } const kTests = [ - { description: "Resiziers for <img>", + { description: "Positioner for <img>", innerHTML: "<img id=\"target\" src=\"green.png\">", - mayPreserveRatio: true, }, - { description: "Resiziers for <table>", + { description: "Positioner for <table>", innerHTML: "<table id=\"target\" border><tr><td>cell</td><td>cell</td></tr></table>", - mayPreserveRatio: false, }, - { description: "Resiziers for absolute positioned <div>", - innerHTML: "<div id=\"target\" style=\"position: absolute; top: 50px; left: 50px;\">positioned</div>", - mayPreserveRatio: false, + { description: "Positioner for <div>", + innerHTML: "<div id=\"target\">div element</div>", }, ]; - await SpecialPowers.pushPrefEnv({"set": [["editor.resizing.preserve_ratio", false]]}); for (const kTest of kTests) { - await doTest(kTest.description, false, kTest.innerHTML); - } - await SpecialPowers.pushPrefEnv({"set": [["editor.resizing.preserve_ratio", true]]}); - for (const kTest of kTests) { - await doTest(kTest.description, kTest.mayPreserveRatio, kTest.innerHTML); + await doTest(kTest.description, kTest.innerHTML); } content.innerHTML = ""; SimpleTest.finish(); }); </script> </pre> </body> </html>
--- a/editor/libeditor/tests/test_resizers_appearance.html +++ b/editor/libeditor/tests/test_resizers_appearance.html @@ -39,57 +39,62 @@ SimpleTest.waitForFocus(async function() resizable: true, }, { description: "<table>", innerHTML: "<table id=\"target\" border><tr><td>1-1</td><td>1-2</td></tr><tr><td>2-1</td><td>2-2</td></tr></table>", resizable: true, }, { description: "absolute positioned <div>", innerHTML: "<div id=\"target\" style=\"position: absolute; top: 50px; left: 50px;\">positioned</div>", - resizable: true, + resizable: function () { return document.queryCommandState("enableAbsolutePositionEditing"); }, }, { description: "fixed positioned <div>", innerHTML: "<div id=\"target\" style=\"position: fixed; top: 50px; left: 50px;\">positioned</div>", resizable: false, }, { description: "relative positioned <div>", innerHTML: "<div id=\"target\" style=\"position: relative; top: 50px; left: 50px;\">positioned</div>", resizable: false, }, ]; - for (const kTest of kTests) { - const kDescription = kTest.description + ": "; - editor.innerHTML = kTest.innerHTML; - let target = document.getElementById("target"); + for (let kEnableAbsolutePositionEditor of [true, false]) { + document.execCommand("enableAbsolutePositionEditing", false, kEnableAbsolutePositionEditor); + for (const kTest of kTests) { + const kDescription = kTest.description + + (kEnableAbsolutePositionEditor ? " (enabled absolute position editor)" : "") + ": "; + editor.innerHTML = kTest.innerHTML; + let target = document.getElementById("target"); - document.execCommand("enableObjectResizing", false, false); - ok(!document.queryCommandState("enableObjectResizing"), - kDescription + "Object resizer should be disabled by the call of execCommand"); + document.execCommand("enableObjectResizing", false, false); + ok(!document.queryCommandState("enableObjectResizing"), + kDescription + "Object resizer should be disabled by the call of execCommand"); - synthesizeMouseAtCenter(outOfEditor, {}); - let promiseSelectionChangeEvent1 = waitForSelectionChange(); - synthesizeMouseAtCenter(target, {}); - await promiseSelectionChangeEvent1; + synthesizeMouseAtCenter(outOfEditor, {}); + let promiseSelectionChangeEvent1 = waitForSelectionChange(); + synthesizeMouseAtCenter(target, {}); + await promiseSelectionChangeEvent1; - ok(!target.hasAttribute("_moz_resizing"), - kDescription + ": While enableObjectResizing is disabled, resizers shouldn't appear"); + ok(!target.hasAttribute("_moz_resizing"), + kDescription + ": While enableObjectResizing is disabled, resizers shouldn't appear"); - document.execCommand("enableObjectResizing", false, true); - ok(document.queryCommandState("enableObjectResizing"), - kDescription + "Object resizer should be enabled by the call of execCommand"); + document.execCommand("enableObjectResizing", false, true); + ok(document.queryCommandState("enableObjectResizing"), + kDescription + "Object resizer should be enabled by the call of execCommand"); - synthesizeMouseAtCenter(outOfEditor, {}); - let promiseSelectionChangeEvent2 = waitForSelectionChange(); - synthesizeMouseAtCenter(target, {}); - await promiseSelectionChangeEvent2; + synthesizeMouseAtCenter(outOfEditor, {}); + let promiseSelectionChangeEvent2 = waitForSelectionChange(); + synthesizeMouseAtCenter(target, {}); + await promiseSelectionChangeEvent2; - is(target.hasAttribute("_moz_resizing"), kTest.resizable, - kDescription + (kTest.resizable ? "While enableObjectResizing is enabled, resizers should appear" : - "Even while enableObjectResizing is enabled, resizers shouldn't appear")); + const kResizable = typeof kTest.resizable === "function" ? kTest.resizable() : kTest.resizable; + is(target.hasAttribute("_moz_resizing"), kResizable, + kDescription + (kResizable ? "While enableObjectResizing is enabled, resizers should appear" : + "Even while enableObjectResizing is enabled, resizers shouldn't appear")); + } } SimpleTest.finish(); }); </script> </pre> </body> </html>
--- a/editor/libeditor/tests/test_resizers_resizing_elements.html +++ b/editor/libeditor/tests/test_resizers_resizing_elements.html @@ -42,16 +42,19 @@ SimpleTest.waitForFocus(async function() }); } async function doTest(aDescription, aPreserveRatio, aInnerHTML) { let description = aDescription; if (SpecialPowers.getBoolPref("editor.resizing.preserve_ratio")) { description += " (preserve ratio pref is true)"; } + if (document.queryCommandState("enableAbsolutePositionEditing")) { + description += " (absolute position editor is enabled)"; + } description += ": "; content.innerHTML = aInnerHTML; let target = document.getElementById("target"); /** * This function is a generic resizer test. * We have 8 resizers that we'd like to test, and each can be moved in 8 different directions. * In specifying baseX, W can be considered to be the width of the image, and for baseY, H @@ -197,33 +200,41 @@ SimpleTest.waitForFocus(async function() await testResizer( 0, 0, 10, 0, -10 * ignoredGrowth, 0); await testResizer( 0, 0, 10, 10, -10, -10); } const kTests = [ { description: "Resiziers for <img>", innerHTML: "<img id=\"target\" src=\"green.png\">", mayPreserveRatio: true, + isAbsolutePosition: false, }, { description: "Resiziers for <table>", innerHTML: "<table id=\"target\" border><tr><td>cell</td><td>cell</td></tr></table>", mayPreserveRatio: false, + isAbsolutePosition: false, }, { description: "Resiziers for absolute positioned <div>", innerHTML: "<div id=\"target\" style=\"position: absolute; top: 50px; left: 50px;\">positioned</div>", mayPreserveRatio: false, + isAbsolutePosition: true, }, ]; + // Resizers for absolute positioned element are available only when + // enableAbsolutePositionEditing is enabled. So, let's enable it + // during testing resizers for absolute positioned elements. await SpecialPowers.pushPrefEnv({"set": [["editor.resizing.preserve_ratio", false]]}); for (const kTest of kTests) { + document.execCommand("enableAbsolutePositionEditing", false, kTests.isAbsolutePosition); await doTest(kTest.description, false, kTest.innerHTML); } await SpecialPowers.pushPrefEnv({"set": [["editor.resizing.preserve_ratio", true]]}); for (const kTest of kTests) { + document.execCommand("enableAbsolutePositionEditing", false, kTests.isAbsolutePosition); await doTest(kTest.description, kTest.mayPreserveRatio, kTest.innerHTML); } content.innerHTML = ""; SimpleTest.finish(); }); </script> </pre> </body>