Reputation: 1890
I'm using a GWT RichTextArea and need to insert text at the current cursor position. I read about using the method RichTextArea.getFormatter().insertHTML() as a way to do this and it's working fine.
My one problem is that instead of inserting my text as raw HTML into the position of the cursor, it's closing the current formatting HTML tags then re-opening new ones around my HTML. To clarify, I'm not actually inserting any type of HTML string, just text. Here's an example:
Original HTML:
<font size="2">Walk the dog</font>
If my cursor is placed after the "d", and I call insertHTML("ASDF"), my resulting html will be this:
<font size="2">Walk the d</font>ASDF<font size="2">og</font>
Is there a way I can avoid this format escaping? I need the text to be formatted the same as the surrounding text. When a user manually enters the text it does this properly. I need to do the same thing in script.
I'm not familiar with coding native javascript in GWT, but I figured there might be a simple way to achieve this using a native method. Any ideas on how I can achieve this would be appreciated. I can obviously do some post processing on the HTML to remove the tags but I'd like to avoid that.
Upvotes: 4
Views: 2075
Reputation: 521
Disclaimer: I am not a JavaScript expert, and my answer may not work across all browsers. Feel free to point out any mistakes or ways to improve my answer such that it works in all browsers.
The RichTextArea.getFormatter().insertHTML()
method invokes the executeCommand("insertHTML", ...)
JavaScript method, which, as far as I understand, creates a child node at the current position while breaking the parent's formatting. Therefore, any insertHTML
method will not provide the desired behavior.
Rather, you should get the text object that contains the current position, and use insertData(pos, text)
to insert the new text. This can easily be done by extending the RichTextArea
class, and adding a JSNI method.
RichTextArea
class and added the following JSNI method:
public class CustomRichTextArea extends RichTextArea {
public native void insertText(String text, int pos) /*-{
var elem = [email protected]::getElement()();
var refNode = elem.contentWindow.getSelection().getRangeAt(0).endContainer;
refNode.insertData(pos, text);
}-*/;
}
The insertText
method gets a text object associated with the current selection, and then inserts the text at the specified position in that text object. This code provides your desired behavior, but I have only tested this in Chrome.
Also, this method could be improved by automatically finding the current position -- getting the current position of a RichTextArea is a completely different topic.
I tested the above snippet with the following entry point:
private CustomRichTextArea crta;
public void onModuleLoad() {
crta = new CustomRichTextArea();
crta.ensureDebugId("cwRichText-area");
crta.setSize("100%", "14em");
RichTextToolbar toolbar = new RichTextToolbar(crta);
toolbar.ensureDebugId("cwRichText-toolbar");
toolbar.setWidth("100%");
Button b = new Button();
b.setText("Insert HTML");
b.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
crta.setFocus(true);
crta.insertText("ASDF", ((int)crta.getText().length() / 2));
}
});
Grid grid = new Grid(2, 1);
grid.setStyleName("cw-RichText");
grid.setWidget(0, 0, toolbar);
grid.setWidget(1, 0, crta);
// display:
RootPanel.get().add(grid);
RootPanel.get().add(b);
}
Where I obtained RichTextToolbar from the project on GoogleCode.
Upvotes: 1
Reputation: 1890
So right after I posted the bounty I thought of a non-ideal but robust way around this.
I realized I have the full HTML before and after I call insertHtml. With these two HTML strings, I can safely identify the block of HTML that was inserted into via my insertHtml call. So I can easily remove the HTML that was inserted and replace it with my original text again. Here's my code snippet to do this in case that's not clear.
String originalHtml = richTextArea.getHTML();
richTextArea.getFormatter().insertHTML(text);
String newHtml = richTextArea.getHTML();
int origLength = originalHtml.length();
int newLength = newHtml.length();
int startPos = -1;
int endPos = -1;
for (int i = 0; i < origLength; i++) {
if (originalHtml.charAt(i) != newHtml.charAt(i)) {
startPos = i;
break;
}
}
for (int i = 0; i < origLength; i++) {
if (originalHtml.charAt(origLength - i - 1) != newHtml.charAt(newLength - i - 1)) {
endPos = newLength - i;
break;
}
}
String finalHtml = newHtml.substring(0, startPos) + text + newHtml.substring(endPos);
richTextArea.setHTML(finalHtml);
So this isn't the cleanest solution but to my knowledge it should always work. I'm calling getHTML, insertHTML, getHTML, and setHTML on the RichTextArea when only a single insert algorithm is needed. I'd still prefer a direct solution if anybody comes up with a better one.
Upvotes: 1