We embed CKEditor into an application that has lots of controls and elements that are not related to CKEditor. Buttons to SAVE and CANCEL (revert changes) apply to all of the elements, not just the editor.
What is the best mechanism to use to detect that a user has "left the editor" so we can determine if the editor data has changed so it can be transferred to the server?
We have tried using the CKEditor.editor.on('blur') scheme, but it has a 100msec delay that means if the user leaves the editor focus and clicks on a button elsewhere, the most recent changes won't be detected because the blur even fires too late (the actual blur only occurs when the user clicks outside of the editor).
We have tried doing "force blur" but that seems to cause issues with intermediate editor data states.
I noted there's a CKEditor.editable.blur that supposedly is for the data area only, not for the buttons etc. Would that work?
How about a way to note that the mouse has moved out of the editor area?
Any good ideas out there? Thanks!
Based on feedback from a
Based on feedback from a ticket, we're using this to help reduce issues for us:
CKEDITOR.focusManager._.blurDelay = 70; // from 200 the default
We still have some issues with Safari browsers, but it's generally working. It seems brittle, though, to use a timer like this. After all, if we change it to 100, we start to see the bug of the BLUR event firing too late for us.
If anybody has better suggestions on telling when we can safely read the editor's data for changes, we'd appreciate it. In our scenario, the editor is just one several widgets, and the Save button on the page doesn't really know anything about CKEditor (or any other input fields). So we cannot just read the editor when the save button is pressed and then send the contents.
Instead, we need to determine when the user has left the editor area and assume that we can then read the contents. This works well with the editor's BLUR event in that when that event fires, we get the right data. But sadly, the Save button will trigger faster than the blur delay on the editor, so that button doesn't yet see the latest data in the editor (if it's pressed twice, it'll work since the blur will have fired by then).
It would be great if there were a reliable BLUR event that only fired as soon as the editor lost focus, or perhaps a MOUSEOUT event that we could capture whenever the user left the editor area.
Reduced blurDelay breaks Safari blur/focus events
After reducing CKEDITOR.focusManager._.blurDelay to 70, we had what seemed like a nice balance, but it was only for our PC it seems. Some (perhaps with faster processors?) were still seeing issues of "missing updates".
The button that submits data in a Vaadin app is not tied directly any of the possibly multi-CKEditor instances on the page. When the button even fires, we need the BLUR event to fire on the CKEditor instances so we can detect the most recent changes to the editor data and send it to the server.
The default delay of 200 reproduced the bug on every browser we tested (Windows Firefox, IE, Chrome, Safari, Opera). We reduced it down to 70 before we found that we could not reproduce the issue ourselves, and Safari was handling the blur/focus events just fine.
Sadly, others found it was still too slow and could reproduce the missing update issue. So we've now reduced it all the way 20. We can see how brittle this kind of tweaking is, but it still seems better than when we tried to force the blur() function to be synchronous with no-delay.
At 20, we see no issues with the button event submitting data before the editor fires the blur event. But now on Safari, right-clicks for context menus appear broken because it seems only Safari can confuse the blur/focus events when the blur delay is set this low (and we found it needed to be around 70 to only see the event firing issue rarely in Safafi). None of the other browser seem to show this.
I don't know how to reproduce this in a standalone CKEditor page, unfortunately, as I believe it's a timing issue of some sort where the Vaadin-framework button event can be triggered and sent to the server before the editor fires the blur instance and we can send its contents to the server. And so we reduce the blur delay to fix that, but then it uncovers this issue in CKEditor with respect to Safari firing of its blur/focus events when the delay is less than 70.
YouTube video showing Safari focus/blur issue
Here's a YouTube video (http://www.youtube.com/watch?v=FuA6KI_y5R0) show the basic issue. On the left, if the Vaadin app running CKEditor 4.0.1, and on the right on the console where focus/blur events are shown as they occur.
First, using IE, we see no issues. It seems like no matter where in the editor I click, the focus event fires as expected. Click outside, and the blur event fires.
Second, using Chrome, we see some oddities crop up. The first time I click in the lower area of the editor, a focus even fires, and click outside the blur event fires. But if I just do those two clicks again, neither event fires, yet you can see that when I click in the editor area, even though no focus event fires, you can see the insertion bar appear at the end of the document. If I type, the focus event fires then. Or if I highlight the text, the focus even then fires. But if I backspace to remove the ending characters, no focus event fires, and so if we click the SAVE button, we lose those changes because no blur event fired (and because no prior focus event fired either).
Third, using Safari, we see the most oddities. It has the same issues with the initial focus/blur working and then subsequent ones not registering even though the insertion bar is present at the end of the editor buffer, but if you type, highlight or backspace, it seems to trigger the focus event. But unlike the other browsers, issues arise with the right-click context menu. Sometimes it works, and sometimes it doesn't. You'll see that repeated right clicks in a table cell will cause blur, then focus events even though we never left the browser. You can get it to think it's been blurred even while still in the editor.
Note that this is with the blur delay set to 20 instead of the default of 200.
But when we test without modifying the blur delay, we see the same oddities for the blur/focus events, but we get even more issues with missing editor content changes because the blur takes too long to fire.
HTML-only example of BLUR/FOCUS issue
Okay, I found that I can recreate the blur delay issue using just CKEditor in HTML. The code is below. The idea is that when the BLUR event fires, I save the editor contents into a variable. And on a button, I put a call that compares that buffer with the current buffer and you will see that with the delay set at its default, it often is not right. But if you uncomment the blur delay, you will see that the editor contents are not out of sync.
You can also see how if you click in the lower right of the editor (below any content) and just outside the editor, the blur/focus events will stop firing in Safari, but the insertion bar will be present and the focus doesn't fire until a key is hit (and in Chrome a simple backspace that erases the last character doesn't fire it at all).
Did you create a ticket and
Did you create a ticket and post your findings on our Development site? Our QA/ developers do not follow the forum and they can only deal with issues posted on the tracker. It would be great if you could publish your ideas there as this is the only way to solve the issue. Thanks!
Documentation Manager, CKSource
See CKEditor 5 docs, CKEditor 4 docs, CKEditor 3 docs, CKFinder 3 docs, CKFinder 2 docs for help.
Visit the new CKEditor SDK for samples showcasing editor features to try out and download!
Finally I've got some time to
Finally I've got some time to check your sample.
And I'll repeat what I've already said:
To prove that I tested your sample on IE9 and IE8.
I've very quickly found that with delay around 100ms buffers do not match. But with delay less than 100ms from time to time editor was firing blur when the focus was in elements path and I was clicking inside editable.
And who knows how many other bugs I would find if I tested longer. We also can't be sure what would happen on Opera, FF, Chrome and on slower computers.
Therefore to have safe focus/blur events we need so long timeout (200ms). Perhaps we could lower this value basing on browser and some very precise tests, but that would take us a lot of time and we couldn't be sure the final result.
So you just need to remember that focus is not synchronous and that your approach is incorrect.
Regarding focus not being fired on Chrome when clicking in editable (what shows the caret). I added native focus listeners and it turned out that Chrome has an ugly bug, because focus isn't fired at all. You need to start typing to trigger it.
Piotrek (Reinmar) Koszuliński
CKEditor JavaScript Developer
--
CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+
possibly knockout.js might help?
Tried this .. ??
http://knockoutjs.com/documentation/hasfocus-binding.html
Thanks - suggestions on doing it correctly?
Thank you for testing it out and for your comments.
I am not surprised our approach is "not correct," but of course in the 3.x branch we managed to replace blur with forceBlur and had no ill side effects (that we noted):
Anyway, can you suggest a "correct approach" since using the blur event to trigger checking if the editor buffer has changed is not correct as you say.
We really preferred not having a separate SAVE button just on the editor field in our forms as it would be confusing that users would click the form save button (which itself has no knowledge of any CKEditor instances) to save all of the data except the editor's contents which they'd have to save separately using a button in the editor to trigger savings its contents specially.
I'll also check with the Vaadin team to see if there are any client-side hooks we can use to detect when they are going to send updates to the server via AJAX so we can perhaps check the editor contents then.
knockout
No, never seen kockout before. Not sure if would help or not. I noted that Chrome has no issues with the focus on the knockout input field (whenver I click in it, it says it has the focus without needing any typing to trigger it) as reported back earlier today.
I've never heard of focus or blur needing to be delayed to "work" as these are events that should fire automatically when you click inside an input field or click outside of it, though of course CKEditor isn't just a simple input field and so that's likely playing a role here.
There's mention above about our trying to make this "synchronous" but that is not valid as we don't do anything special except reduce the hard-coded blur event delay -- it should be just as async as ever as we dont' do anything but wait for the blur even to fire.
ko .. binding to blur
Here's an example found of knockout code .. binding to blur
http://jsfiddle.net/NDry4/
What element would I hook this up to?
Thanks again for the example. I think I see how it works, but what I don't know is what element I'd attach this to since CKEditor is not a simple INPUT element. The blur needs to fire when you leave any of the myriad CKEditor components that presented.
I don't know all aspects of
I don't know all aspects of your case, but I'd just stick to these rules:
Piotrek (Reinmar) Koszuliński
CKEditor JavaScript Developer
--
CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+
CKEditor onChange event would be useful
Okay, it seems that focus/blur is not the right approach. How about an onChange event? Seems like a generally useful event that could be fired anytime the editor buffer is changed. This would match the DOM standard onchange event for regular DOM input elements.
Again, the 3.x branch, we used the ideas specified here:
http://alfonsoml.blogspot.com/2011/03/onchange-event-for-ckeditor.html
It worked by listening to the editor's 'saveSnapshot' event, the editor.getCommand('undo') 'afterUndo' event, the editor.getCommand('redo') 'afterRedo' event, as well as the editor's 'afterCommandExec' event.
Seems like the event system has changed quite a bit in 4.0. Is there a comparable set of events we can listen to detect changes in the editor contents? This would be generally useful and would avoid the poor choice of using the blur event to check.
Thanks!
UPDATED: Appears it is scheduled to be added in 4.2:
full thread not showing?
From the index there appears to be further posts in this thread today .. but I'm not seeing them here.
This is just a test post.
Due to the threaded replies
Due to the threaded replies is really hard to follow this kind of post because you have to check every reply in the middle to look for the "new" tag instead of just jumping to the bottom and keep on reading.
I thought that threaded forums were dead long ago but it seems that they are still alive.
It is tricky
Yeah, it's a bit confusing for that reason. We're still hopeful we can find the main events to look for to create a work-around for onchange until 4.2 (or whenever) comes out with a built-in scheme. We generally don't need keystroke change events, but we'd like to know enough so that if they leave the editor and click on a button outside we can be sure we're sending the latest contents, and the blur event works somewhat for this, but it's buggy because ckeditor puts in a 200msec delay before firing the event, which is generally too slow for our needs.
jQuery bind to ckeditor events
Here is another approach I've found for binding ckeditor textarea using jQuery ..
http://jsfiddle.net/soulcyon/T63Df/2/
http://api.jquery.com/category/events/
In this latter page see example for binding custom events such as "blur mouseenter mouseleave click dblclick focus etc. "
So in the ckeditor textarea bind example you might change it as follows ..
$("textarea").bind("blur keydown keyup keypress", function(){
$(".preview").html( $(this).val() );
// add your custom actions here ..
});
$(".wysiwyg").ckeditor({ toolbar: 'Basic' } );
Note that for jQuery to work with ckeditor you have to include in <head></head>
I just use blur with the div
I just use blur with the div element ckeditor is attached to. You can also create a save button/ an autosave feature if you need additional reliability, but I cannot reproduce your issue when I put a blur event in the div with the "contenteditable=true"
Just for HTML5 then?
Not sure, but isn't contenteditable=true just for HTML5 or do most browsers (any browser released since at least IE8 came out?) support it? I hadn't thought of it, but will check it out if I find it's supported on most browsers out there today. We're not relying on HTML5 yet since there are too many pre-HTML5 users out there.
I understand that CKEditor 4.2 is supposed to have an onchange event that may also work generally.
contentEditable was
contentEditable was introduced with IE 5.5 and it's the basis of all the editing for most of the editors outthere, including CKEditor of course.
Thanks, do you have an example of what you did?
Yes, I discovered that as well. Can you provide the test code that you did where this works? Our code actually uses a DIV and CKEditor.appendTo(divId) rather than a textarea. I'm not sure how to find the CKEditor DIV versus our DIV.
I have tried to patch our code, and I can see that my DIV has contenteditable="true" in it, but it appears that when I append CKEditor to that DIV, it also adds all sorts of stuff and the editors are not really working with my blur event handler (currently just doing an alert).
That is, after I did this, I cannot even get my editor to have focus so I can change the contents (in IE9), one editor fails to render entirely, when I do a CTRL-A inside the editor, it highlights the entire editor area an no longer just the text in the editor area.
Anyway, if I can see what you did, maybe I can fix my code here. Not sure how to reliably find the DIV you are speaking about (since the rendering seems to vary quite a bit by browser type). Thanks!
Here is how I am using it on
Here is how I am using it on my website to create a Recent Events section that is only editable when you login as an admin with level 9 access and above. Let me know if you have questions. The coding seems to work great on Apple 10.8 with Safari 6.0.2, and Firefox 19.0.2. Since I am developing a small church site, there will not be alot of traffic. I have not speed tested any of my coding for this reason. Once I get a working product I will work on optimization, and may find a better solution. Will keep an eye on this dicussion until then.
Onblur event with Jquery's Ajax Function:
onblur="$.post('Functions/UpdatePost.php', { Page: '<?php echo __FILE__; ?>', Title: 'Recent Announcements', 'SubTitle': this.id , 'NewSubTitle': this.innerHTML })
Full Code Used:
<?php
$sql = "SELECT Title, `Sub-Title`, Post, DATE_FORMAT(`Last Modified`,'%m/%d/%y') as 'Last Modified', concat(`First Name`,' ',`Last Name`) as 'Name' FROM Posts JOIN Users ON Users.ID=Posts.`Modified By` WHERE Page = '".__FILE__."' and Title='Recent Announcements' order by `Post Date` Desc";
if(!$result = $db->query($sql)){
die('There was an error running the query [' . $db->error . ']');
}
while($row = $result->fetch_assoc()){
echo "<h4 id='".$row['Sub-Title']."' ";
if($_SESSION['Permission']>8){
echo "contenteditable='true' ";
}
?>
onblur="$.post('Functions/UpdatePost.php', { Page: '<?php echo __FILE__; ?>', Title: 'Recent Announcements', 'SubTitle': this.id , 'NewSubTitle': this.innerHTML }); this.nextSibling.id = this.innerHTML; this.id=this.innerHTML;" ><?php echo $row['Sub-Title'];?></h4>
<?php
echo "<div id='".$row['Sub-Title']."' ";
if($_SESSION['Permission']>8){
echo "contenteditable='true' ";
}
?>
onblur="$.post('Functions/UpdatePost.php', { Page: '<?php echo __FILE__; ?>', Title: 'Recent Announcements', 'SubTitle': this.previousSibling.id, 'Post': this.innerHTML});">
<?php echo $row['Post']; ?></div>
<?php
echo "<h6><br /> Last updated by ".$row['Name']." on ".$row['Last Modified']."<hr /></h6>";
}
$db->close();
?>
Not sure where ckeditor is
Thanks for sharing your code, but I don't even see how any of that is tied into CKEditor, so I'm not sure where you are even putting the onblur. I thought perhaps you had a modified version of the code that shows the issue we see and that version would show to be working.
I found that if I create a DIV, and then CKEditor.appendTo() that element, the onblur and contenteditable='true' did not seem to work. In fact, on IE9, I couldn't even use the editor anymore. I also tried on the DIV (and SPAN on IE9 I think) that is created immediately under the DIV I used to appendTo(), and that didn't work.
Also, it is a timing issue and I don't see that your code even uses the editor.getData() method to retrieve as you seem to just use innerHTML, but since I don't know PHP, I could just be missing the obvious to you!
Yep, we also noticed this
Yep, we also noticed this problem. We'll try to find a solution. We're sorry for this inconvenience.
Piotrek (Reinmar) Koszuliński
CKEditor JavaScript Developer
--
CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+