Capitalize first letter of sentence in CKeditor

空扰寡人 提交于 2019-12-08 12:17:40

问题


I wish to capitalize the first letter of a sentence, on-the-fly, as the user types the text in a CKEditor content instance.

The strategy consists in catching each keystroke and try to replace it when necessary, that is for instance, when the inserted character follows a dot and a space. I'm fine with catching the event, but can't find a way to parse characters surrounding the caret position:

var instance = CKEDITOR.instances.htmlarea
instance.document.getBody().on('keyup', function(event) {
    console.log(event);
    // Would like to parse here from the event object...
    event.data.preventDefault();
});

Any help would be much appreciated including a strategy alternative.


回答1:


You should use keydown event (close to what you proposed):

var editor = CKEDITOR.instances.editor1;

editor.document.getBody().on('keydown', function(event) {
    if (event.data.getKeystroke() === 65 /*a*/ && isFirstLetter()) {
        // insert 'A' instead of 'a'
        editor.insertText('A');
        event.data.preventDefault();
    }
});

Now - how should isFirstLetter() look like?

  1. You have to start from editor.getSelection().getRanges() to get caret position.
  2. You're interested only in the first range from the collection.
  3. To extract text content from before the caret use small trick:
    • move start of the range to the beginning of document: range.setStartAt( editor.document.getBody(), CKEDITOR.POSITION_AFTER_START ),
    • use CKEDITOR.dom.walker to traverse through DOM tree in source order,
    • collect text nodes and find out what's before caret (is it /\. $/) - remember that you have to skip inline tags and stop on block tags - hint: return false from guard function to stop traversing.

Example of how you can use walker on range:

var range, walker, node;

range = editor.getSelection().getRanges()[0];
range.setStartAt(editor.document.getBody(), CKEDITOR.POSITION_AFTER_START);
walker = new CKEDITOR.dom.walker(range);
walker.guard = function(node) {
    console.log(node);
};

while (node = walker.previous()) {}

And now few sad things.

  • We assumed that selection is empty when you type - that doesn't have to be true. When selection is not collapsed (empty) then you'll have to manually remove its content before calling insertText. You can use range#deleteContents to do this.
  • But this is not all - after deleting range's content you have to place caret in correct position - this isn't trivial. Basically you can use range#select (on the range after deleteContents), but in some cases it can place caret in incorrect place - like between paragraphs. Fixing this is... is not doable without deeeeeeeep knowledge about HTML+editables+insertions+other things :).
  • This solution is not complete - you have to handle paste event, deleting content (one can delete words from the start of sentence), etc, etc.
  • I guess there are couple of other problems I didn't even thought about :P.

So this approach isn't realistic. If you still want to implement this feature I think that you should set timer and by traversing DOM (you can use walker on range containing entire document, or recently typed text (hard to find out where it is)) find all sentences starting from lower letter and fix them.



来源:https://stackoverflow.com/questions/11226226/capitalize-first-letter-of-sentence-in-ckeditor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!