问题
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?
- You have to start from
editor.getSelection().getRanges()
to get caret position. - You're interested only in the first range from the collection.
- 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: returnfalse
fromguard
function to stop traversing.
- move start of the range to the beginning of document:
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 userange#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 afterdeleteContents
), 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