Skip to content

Commit

Permalink
TextEditor: Add workaround for slab/quill#1397
Browse files Browse the repository at this point in the history
  • Loading branch information
jungm committed Apr 17, 2023
1 parent 5b9ad5e commit aa31f02
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">

<f:view contentType="text/html;charset=UTF-8" encoding="UTF-8">
<h:head>

</h:head>

<h:body>
<h:form id="form">
<p:messages id="msgs"/>

<p:textEditor id="textEditor" secure="false" value="#{textEditor003.value}">
<p:ajax event="blur" process="@this" update="@this msgs"/>
</p:textEditor>

<p:button id="doNothing" onclick="return false;" value="Do nothing"/>
</h:form>

</h:body>
</f:view>

</html>
Original file line number Diff line number Diff line change
@@ -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("<p>Hello world</p>", 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";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
},

/**
Expand Down

0 comments on commit aa31f02

Please # to comment.