From aa31f025f4d33d4f583761388a0def4a5fff9b32 Mon Sep 17 00:00:00 2001 From: Markus Jung Date: Mon, 17 Apr 2023 16:21:32 +0200 Subject: [PATCH] TextEditor: Add workaround for https://github.com/quilljs/quill/issues/1397 --- .../texteditor/TextEditor003.java | 48 ++++++++++ .../webapp/texteditor/textEditor003.xhtml | 26 ++++++ .../texteditor/TextEditor003Test.java | 92 +++++++++++++++++++ .../primefaces/texteditor/1-texteditor.js | 9 ++ 4 files changed, 175 insertions(+) create mode 100644 primefaces-integration-tests/src/main/java/org/primefaces/integrationtests/texteditor/TextEditor003.java create mode 100644 primefaces-integration-tests/src/main/webapp/texteditor/textEditor003.xhtml create mode 100644 primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/texteditor/TextEditor003Test.java diff --git a/primefaces-integration-tests/src/main/java/org/primefaces/integrationtests/texteditor/TextEditor003.java b/primefaces-integration-tests/src/main/java/org/primefaces/integrationtests/texteditor/TextEditor003.java new file mode 100644 index 0000000000..8ca308b3da --- /dev/null +++ b/primefaces-integration-tests/src/main/java/org/primefaces/integrationtests/texteditor/TextEditor003.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * + * Copyright (c) 2009-2023 PrimeTek Informatics + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.primefaces.integrationtests.texteditor; + +import lombok.Data; + +import javax.faces.application.FacesMessage; +import javax.faces.context.FacesContext; +import javax.faces.view.ViewScoped; +import javax.inject.Named; +import java.io.Serializable; + +@Named +@ViewScoped +@Data +public class TextEditor003 implements Serializable { + private static final long serialVersionUID = 1L; + + private String value; + + public void setValue(String value) { + this.value = value; + + FacesContext.getCurrentInstance().addMessage( + null, new FacesMessage(FacesMessage.SEVERITY_INFO, value, value)); + } +} diff --git a/primefaces-integration-tests/src/main/webapp/texteditor/textEditor003.xhtml b/primefaces-integration-tests/src/main/webapp/texteditor/textEditor003.xhtml new file mode 100644 index 0000000000..1c3609a7be --- /dev/null +++ b/primefaces-integration-tests/src/main/webapp/texteditor/textEditor003.xhtml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/texteditor/TextEditor003Test.java b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/texteditor/TextEditor003Test.java new file mode 100644 index 0000000000..29f9a04fa7 --- /dev/null +++ b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/texteditor/TextEditor003Test.java @@ -0,0 +1,92 @@ +/* + * The MIT License + * + * Copyright (c) 2009-2023 PrimeTek Informatics + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.primefaces.integrationtests.texteditor; + +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.primefaces.selenium.AbstractPrimePage; +import org.primefaces.selenium.AbstractPrimePageTest; +import org.primefaces.selenium.PrimeSelenium; +import org.primefaces.selenium.component.Button; +import org.primefaces.selenium.component.Messages; +import org.primefaces.selenium.component.TextEditor; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TextEditor003Test extends AbstractPrimePageTest { + + @Test + public void testFocusLostToButton(Page page) { + // Arrange + Messages messages = page.messages; + TextEditor textEditor = page.editor; + Button doNothing = page.doNothing; + + // Act + textEditor.getEditor().click(); + textEditor.setValue("Hello world"); + PrimeSelenium.guardAjax(doNothing).click(); + + // Assert + assertEquals(1, messages.getAllMessages().size()); + assertEquals("

Hello world

", messages.getMessage(0).getSummary()); + } + + @Test + public void testNoBlurOnPaste(Page page) { + // Arrange + Messages messages = page.messages; + WebElement quillEditor = page.editor.findElement(By.className("ql-editor")); + Keys command = PrimeSelenium.isSafari() ? Keys.COMMAND : Keys.CONTROL; + + // Act + quillEditor.sendKeys("Hello world"); + quillEditor.sendKeys(Keys.chord(command, "a")); + quillEditor.sendKeys(Keys.chord(command, "c")); + quillEditor.sendKeys(Keys.DELETE); + quillEditor.sendKeys(Keys.chord(command, "v")); + + // Assert + assertEquals(0, messages.getAllMessages().size()); + } + + public static class Page extends AbstractPrimePage { + @FindBy(id = "form:msgs") + Messages messages; + + @FindBy(id = "form:textEditor") + TextEditor editor; + + @FindBy(id = "form:doNothing") + Button doNothing; + + @Override + public String getLocation() { + return "texteditor/textEditor003.xhtml"; + } + } +} diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/texteditor/1-texteditor.js b/primefaces/src/main/resources/META-INF/resources/primefaces/texteditor/1-texteditor.js index 60c50ca84f..f8676c3fda 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/texteditor/1-texteditor.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/texteditor/1-texteditor.js @@ -151,6 +151,15 @@ PrimeFaces.widget.TextEditor = PrimeFaces.widget.DeferredWidget.extend({ } }); + // QuillJS doesn't handle blurring when focus is lost to e.g. a button, handle blur event separately here as a workaround + // See https://github.com/quilljs/quill/issues/1397 + this.editor.root.addEventListener('blur', function(e) { + if (e.relatedTarget === $this.editor.clipboard.container) { + return; // Ignore pasting + } + + $this.editor.blur(); // Triggers selection-change event above + }); }, /**