Hello all. I've been trying to figure out a way to apply styles to specific words in an instance of ckeditor. For a specific example of what I mean, check the SCAYT demo here: http://sdk.ckeditor.com/samples/spellchecker.html
...I want to do something similar where I can apply a css style to misspelled words. Approaches I've already tried:
(1) calling editor.getData(), modifying the contents to be surrounded with something like:
<span style='bottom-border: 1px dotted red;">WORD_HERE</span>
...and then calling editor.setData(data) with the updated content. This works fine except for the fact that replacing the entire DOM makes me lose my cursor position and trying to save and restore the location where someone was typing seems EXTREMELY convoluted and also inconsistent across browsers.
(2) Try and use the CKEDITOR.dom API to get an array or element list or node list of all the items in the editor, including the text nodes. Unfortunately I haven't been able to find a good example of this being done and was having a difficult time parsing the API and putting it all together in a way that I could get a list of elements and modify their style information.
(3) Looking at the SCAYT plugin code that is available. I wasn't quite able to understand how it was applying its markup. It seems to call methods and fire off events that I don't see in the plugin.js or any other associated files or CKEDITOR core but it's certainly possible I am missing something.
Anyhow, what I want to do is clearly possible since SCAYT is doing it. I was hoping maybe someone had some examples of how they implemented this or could point me towards an approach I have not already thought about taking. Thanks!
Just an update here... I am
Just an update here... I am continuing to try and get my attempt at #1 above working. I am:
- calling getData()
- modifying the contents to contain <span>'s with style around specific words
- calling setData() with the new modified contents
The big issue with doing this is that the cursor location is lost after I replace the entire inner DOM. I have been trying to use the intrusive bookmark capability to insert a bookmark span tag (internally a span with data-cke-bookmark="1") and then re-select the bookmark after setting the data. Unfortunately this is not working because the data-cke-bookmark attribute is being stripped out on both getData and setData. I have tested setting allowContent to allow spans with that tag specifically and also tested with allowedContent=true but in both cases it is still strpping seeming all data-cke-* tags from the data on get and set. I found one other individual who had this same issue here:
http://stackoverflow.com/questions/27524002/retain-cursor-position-after-reloading-the-page-in-ckeditor
...his solution though was to work around it and write his own code that creates a custom data attribute and then selects that range after reload. This is a solution but I was hoping that maybe someone had some insight into why the data-cke-* tags were being stripped because I'd much rather use the cleaner method of just calling selectBookmarks or moveToBookmark from the CKEditor API than rolling my own solution. Thanks again for any help.
Wanted to give another update
Wanted to give another update. I have come up with a solution that seems to mostly work and I wanted to just share it in case anyone else finds this post down the line and has a similar question:
I was able to get things functioning using the approach I mentioned above... grabbing the latest data using getData, modifying the contents to have styled spans with "bottom-border: 1px red dotted" and then inserting the data back into the editor and replacing the cursor where it was before. This was a bit more challenging than it sounds because:
(1) Dealing with the range/selection API in javascript is HORRIBLE. Fortunately I found a great library called "rangy" that provides a number of much more convenient functions to work with and also handles all of the cross-brower nastiness (because there is a lot). Here is a link to that: https://github.com/timdown/rangy
(2) Replacing the data back into the editor using setData provides a terrible experience for users if they are trying to type and work on the fly while the spellchecking is happening at the same time. The problem is that when you use setData, it reloads the entire iframe and causes things to flash and causes styling to momentarily not exist and then get reapplied... it doesn't look good and it's not a good experience for a user. I was able to overcome this by getting the body object out of the iframe directly and setting the innerHtml manually as described here: http://stackoverflow.com/questions/15674496/ckeditor-smooth-setdata. Doing it this way might not be the recommended approach by CKEditor but it prevents the entire iframe and DOM above the body from being recreated and is much more seamless.
(3) The bookmark functionality in ckeditor has not been working properly for me. It's entirely possible I just don't understand how some of the rule and allowContent stuff works but I could not find a way to get it to NOT strip the data-cke-* tags from my html. As a result I wound up just creating my own bookmark tag using a span with a custom id and then replacing the caret back onto that bookmark after each time I applied misspelling markup.
Here are some links that were very useful to me while figuring this out:
<removed to get around the spam filter>
Anyhow this isn't all perfect yet, there are lots of quirks I am still working out but it seems very promising and is almost there. It also seems to be the same approach that SCAYT and a couple of other web-based spellcheck libraries use. Hope this is helpful to someone.
For some reason the spam
For some reason the spam filter in the forum blocked me from pasting these links in my post so here they are, the links I wanted to paste for (3) in my previous post:
http://stackoverflow.com/questions/16835365/set-cursor-to-specific-position-in-ckeditor
http://stackoverflow.com/questions/27524002/retain-cursor-position-after-reloading-the-page-in-ckeditor