Skip to content

Port rich text field registration off of XSLT #1862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: hermione
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
class WTextAreaRenderer extends AbstractWebXmlRenderer {

private static final String TAG_RTF = "wc-rtf";

/**
* Paints the given WTextArea.
*
Expand Down Expand Up @@ -66,7 +68,7 @@ public void doRender(final WComponent component, final WebXmlRenderContext rende
* such as turning rich text features on or off, or specifying JSON config either as
* a URL attribute or a nested CDATA section.
*/
xml.append("<ui:rtf />");
xml.append(String.format("<%s></%1$s>", TAG_RTF));
}

String textString = textArea.getText();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,42 +88,33 @@ public void testDoPaint() throws IOException, SAXException, XpathException {
assertXpathEvaluatesTo("40", "//ui:textarea/@cols", field);

field.setRichTextArea(false);
assertSchemaMatch(field);
assertXpathNotExists("//ui:textarea/ui:rtf", field);
assertXpathNotExists("//ui:textarea/html:wc-rtf", field);

field.setRichTextArea(true);
assertSchemaMatch(field);
assertXpathExists("//ui:textarea/ui:rtf", field);
assertXpathExists("//ui:textarea/html:wc-rtf", field);

field.setDefaultSubmitButton(button);
assertSchemaMatch(field);
assertXpathEvaluatesTo(button.getId(), "//ui:textarea/@buttonId", field);

field.setPattern("");
assertSchemaMatch(field);
assertXpathNotExists("//ui:textarea/@pattern", field);

// Pattern is not supported on the client for TextArea, and will not be rendered
field.setPattern("test[123]");
assertSchemaMatch(field);
assertXpathNotExists("//ui:textarea/@pattern", field);

field.setText("Hello");
assertSchemaMatch(field);
assertXpathEvaluatesTo(field.getText(), "normalize-space(//ui:textarea)", field);


field.setPlaceholder("enter stuff here");
assertSchemaMatch(field);
assertXpathEvaluatesTo("enter stuff here", "//ui:textarea/@placeholder", field);


field.setAutocomplete(AddressType.BILLING);
assertSchemaMatch(field);
assertXpathEvaluatesTo(field.getAutocomplete(), "//ui:textarea/@autocomplete", field);

field.setAutocompleteOff();
assertSchemaMatch(field);
assertXpathEvaluatesTo(AutocompleteUtil.getOff(), "//ui:textarea/@autocomplete", field);
}

Expand Down
16 changes: 12 additions & 4 deletions wcomponents-theme/src/main/js/wc/ui/rtf.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Provides a Rich Text Field implementation using tinyMCE.
*
* Optional module configuration.
* The config member "initObj" can be set to an abject containing any tinyMCE cofiguration members **except**
* The config member "initObj" can be set to an abject containing any tinyMCE configuration members **except**
* selector. This allows customised RTF per implementation. This should be added in the template
*/
import initialise from "wc/dom/initialise.mjs";
Expand Down Expand Up @@ -45,7 +45,7 @@ function processNow(idArr) {
}
}

export default {
const instance = {
/**
* Register Rich Text Fields that need to be initialised.
*
Expand All @@ -58,10 +58,16 @@ export default {
const callback = () => processNow(idArr);
initialise.addCallback((element) => {
if (!tinyMCE) {
const baseUrl = resourceLoader.getUrlFromImportMap("tinymce/");
return import("tinymce/tinymce.js").then(() => {
let baseUrl = resourceLoader.getUrlFromImportMap("tinymce/");

return import(`${baseUrl}tinymce.js`).then(() => {
tinyMCE = element.ownerDocument.defaultView.tinymce;
if (baseUrl) {
// remove trailing forward slash since TinyMCE adds its own
while (baseUrl.charAt(baseUrl.length - 1) === '/') {
baseUrl = baseUrl.substring(0, baseUrl.length - 1);
}

tinyMCE.baseURL = baseUrl;
}
callback();
Expand All @@ -72,3 +78,5 @@ export default {
}
}
};

export default instance;
14 changes: 14 additions & 0 deletions wcomponents-theme/src/main/js/wc/ui/textArea.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,17 @@ initialise.register({
});

export default instance;

// Handle registration of rich text areas
const rtfTag = "wc-rtf";
class WRichTextField extends HTMLElement {
connectedCallback() {
import("wc/ui/rtf.mjs").then(({ default: c }) => {
c.register([this.parentElement.getAttribute("id")]);
});
}
}

if (!customElements.get(rtfTag)) {
customElements.define(rtfTag, WRichTextField);
}
9 changes: 9 additions & 0 deletions wcomponents-theme/src/test/resource/mock-modules/tinymce.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let tinymce = {
baseUrl : "",
init : function() {},
triggerSave : function() {}
};

document.defaultView.tinymce = tinymce;

export default tinymce;
9 changes: 9 additions & 0 deletions wcomponents-theme/src/test/spec/wc.dom.initialise.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import initialise, {setView} from "wc/dom/initialise.mjs";
import {setUpExternalHTML} from "../helpers/specUtils.mjs";

describe("wc/dom/initialise", () => {
let origWindow;

beforeAll(() => {
origWindow = window;
});

afterAll(() => {
setView(origWindow);
});

beforeEach(() => {
return setUpExternalHTML("domUsefulDom.html").then(dom => {
Expand Down
88 changes: 88 additions & 0 deletions wcomponents-theme/src/test/spec/wc.ui.rtf.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import rtf from "wc/ui/rtf.mjs";
import initialise from "wc/dom/initialise.mjs";
import tinymce from "../resource/mock-modules/tinymce.js";

describe("wc/ui/rtf", () => {
let origHead;

beforeAll(() => {
origHead = window.document.head.innerHTML;

let importMap = window.document.createElement("script");
importMap.setAttribute("type", "importmap");
importMap.innerHTML =
`{
"imports": {
"tinymce/": "../../../../test/resource/mock-modules/"
}
}`;
window.document.head.append(importMap);
});

afterAll(() => {
window.document.head.innerHTML = origHead;
delete document.defaultView.tinymce;
});

it("sets a callback for every nonempty invocation of register", (done) => {
spyOn(initialise, "addCallback");
rtf.register(["exID", "anotherEx"]);
rtf.register(["exID"]);
rtf.register([]);

expect(initialise.addCallback).toHaveBeenCalledTimes(2);
done();
});

it("passes the correct selectors to TinyMCE on editor initialisation", (done) => {
const selectors = ["textarea#exID_input", "textarea#anotherEx_input"];
const expectedCalls = 2;
let callCount = 0;

const initSpy = spyOn(tinymce, "init").and.callFake(() => {
let givenSelector = initSpy.calls.mostRecent().args[0].selector;
expect(selectors).toContain(givenSelector);

if (selectors.includes(givenSelector)) {
if (++callCount === expectedCalls) {
done();
}

const idx = selectors.indexOf(givenSelector);
if (idx > -1) {
selectors.splice(idx, 1);
}
}
});

rtf.register(["exID"]);
rtf.register(["anotherEx"]);
});

it("passes the correct default plugins to TinyMCE on editor initialisation", (done) => {
const initSpy = spyOn(tinymce, "init").and.callFake(() => {
const defaultPlugins = ["autolink", "link", "lists", "advlist", "preview", "help"];

for (const plugin of defaultPlugins) {
expect(initSpy.calls.mostRecent().args[0].plugins).toContain(plugin);
}
done();
});

rtf.register(["exID"]);
});

it("passes the correct default tools to TinyMCE on editor initialisation", (done) => {
const initSpy = spyOn(tinymce, "init").and.callFake(() => {
const defaultTools = ["undo", "redo", "formatselect", "bold", "italic", "alignleft", "aligncenter",
"alignright", "alignjustify", "bullist", "numlist", "outdent", "indent", "removeformat", "help"];

for (const tool of defaultTools) {
expect(initSpy.calls.mostRecent().args[0].toolbar).toContain(tool);
}
done();
});

rtf.register(["exID"]);
});
});
6 changes: 0 additions & 6 deletions wcomponents-xslt/src/main/xslt/all.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@
select=".//ui:dropdown[@data and not(@type) and not(@readOnly)] | .//ui:listbox[@data and not(@readOnly)] | .//ui:shuffler[@data and not(@readOnly)]" />
<xsl:variable name="filedrops" select=".//ui:multifileupload[@ajax or @dropzone]" />
<xsl:variable name="multiDDData" select=".//ui:multidropdown[@data and not(@readOnly)]" />
<xsl:variable name="rtfs" select=".//ui:textarea[ui:rtf]" />
<xsl:variable name="eagerness" select="//*[@mode eq 'eager']" />
<xsl:variable name="editors" select=".//html:wc-imageedit" />
<xsl:variable name="tableActions" select=".//ui:table/ui:actions/ui:action" />
Expand Down Expand Up @@ -387,11 +386,6 @@
<xsl:apply-templates select="$multiDDData" mode="registerIds" />
<xsl:text>]);});</xsl:text>
</xsl:if>
<xsl:if test="$rtfs">
<xsl:text>import("wc/ui/rtf.mjs").then(({ default: c }) => {c.register([</xsl:text>
<xsl:apply-templates select="$rtfs" mode="registerIds" />
<xsl:text>]);});</xsl:text>
</xsl:if>
<xsl:if test="$eagerness">
<xsl:text>import("wc/ui/containerload.mjs").then(({ default: c }) => {c.register([</xsl:text>
<xsl:apply-templates select="$eagerness" mode="registerIds" />
Expand Down
9 changes: 4 additions & 5 deletions wcomponents-xslt/src/main/xslt/wc.ui.textarea.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<xsl:template match="ui:textarea[@readOnly]">
<xsl:variable name="element">
<xsl:choose>
<xsl:when test="ui:rtf">div</xsl:when>
<xsl:when test="html:wc-rtf">div</xsl:when>
<xsl:otherwise>pre</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Expand All @@ -41,7 +41,7 @@
</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="ui:rtf">
<xsl:when test="html:wc-rtf">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
Expand All @@ -58,7 +58,7 @@
<xsl:variable name="tickerId" select="concat(@id, '_tick')"/>
<xsl:variable name="element">
<xsl:choose>
<xsl:when test="ui:rtf">
<xsl:when test="html:wc-rtf">
<xsl:text>div</xsl:text>
</xsl:when>
<xsl:otherwise>
Expand Down Expand Up @@ -166,10 +166,9 @@
<output for="{@id}_input" hidden="hidden" id="{$tickerId}" name="{$tickerId}"/>
</xsl:if>
<xsl:apply-templates select="ui:fieldindicator"/>
<xsl:apply-templates select="html:wc-rtf"/>
</xsl:element>
</xsl:template>

<xsl:template match="ui:rtf"/>


</xsl:stylesheet>
Loading