General information:
The autosave plugin lets you save automatically the content created with CKEditor, what helps to protect you against losing your work.
The autosaving can be carried out in three ways:
All communication between plugin and server is made with XML messages.
Plugin fires two events: "afterAutosave" (fired right after saving was finished) and "beforeAutosave" (fired right before AJAX request is made) which can be used to execute user specific functions while saving process takes place.
Important Update:
On the 8th of January 2012 AJAX autosave has been updated to version 1.0.1. It is now possible to use this plugin as simple manual AJAX save by switching off Interval and Change counter triggers. Special thanks to @lsdzung for bringing this up.
License
Licensed under the terms of any of the following licenses at your choice: GPL, LGPL and MPL.
Installation:
Unpack downloaded zip file and copy autosave folder to /ckeditor/plugins/ or /ckeditor/_source/plugins/ folder (It all depends whether you use ckeditor_source.js or ckeditor.js script on your page). If you are interested only in using the plugin then the first path is what you are looking for.
Next you have to make three things which are in fact providing values for three parameters:
More information can be found in readme files provided with zips archives.
Download
There are three archives attached to this post. One containing the plugin (minified plus folders for making source version), second containing sample java application showing usage of the plugin and third containing sample PHP connector (Special thanks to Wiktor Walc for providing this one).
Autosave Plugin
http://code.google.com/p/ckeditor-ajax-autosave-plugin/downloads/detail?name=autosave_1.0.2.zip
Sample Java Application
http://code.google.com/p/ckeditor-ajax-autosave-plugin/downloads/detail?name=test_java_application1.0.2.zip
Sample PHP Connector
http://code.google.com/p/ckeditor-ajax-autosave-plugin/downloads/detail?name=autosave_php_connector.zip
As I was saying before the above archives contain two sample connectors, for Java and PHP. If you would like to attach sample connector for other programming language you are welcome.
Your Contribution
If you have found a bug, have got an idea for a new feature for this plugin or have a general idea how this plugin could be improved, please leave a comment.
If idea is interesting and possible to implement I will try to include it in future releases.
Updates
The autosave plugin lets you save automatically the content created with CKEditor, what helps to protect you against losing your work.
The autosaving can be carried out in three ways:
- Change counter - Optional trigger which sends data to server only after specified amount changes was made in the editor.
- Interval - Optional trigger which sends data to server after specified amount of time.
- Toolbar button - sends data to server when user click on a button (This is not quite automatic
). As of version 1.0.2 it is possible to assign keystroke to button.
All communication between plugin and server is made with XML messages.
Plugin fires two events: "afterAutosave" (fired right after saving was finished) and "beforeAutosave" (fired right before AJAX request is made) which can be used to execute user specific functions while saving process takes place.
Important Update:
On the 8th of January 2012 AJAX autosave has been updated to version 1.0.1. It is now possible to use this plugin as simple manual AJAX save by switching off Interval and Change counter triggers. Special thanks to @lsdzung for bringing this up.
License
Licensed under the terms of any of the following licenses at your choice: GPL, LGPL and MPL.
Installation:
Unpack downloaded zip file and copy autosave folder to /ckeditor/plugins/ or /ckeditor/_source/plugins/ folder (It all depends whether you use ckeditor_source.js or ckeditor.js script on your page). If you are interested only in using the plugin then the first path is what you are looking for.
Next you have to make three things which are in fact providing values for three parameters:
- Register the plugin -
config.extraPlugins = 'autosave';
- Add new toolbar button -
config.toolbar = [['Source','Save','Preview','-', 'Autosave']];
- Specify URL for the data saving server-side script -
config.autosaveTargetUrl = 'http://example.com/path_to_script_that_saves_data';
More information can be found in readme files provided with zips archives.
Download
There are three archives attached to this post. One containing the plugin (minified plus folders for making source version), second containing sample java application showing usage of the plugin and third containing sample PHP connector (Special thanks to Wiktor Walc for providing this one).
Autosave Plugin
http://code.google.com/p/ckeditor-ajax-autosave-plugin/downloads/detail?name=autosave_1.0.2.zip
Sample Java Application
http://code.google.com/p/ckeditor-ajax-autosave-plugin/downloads/detail?name=test_java_application1.0.2.zip
Sample PHP Connector
http://code.google.com/p/ckeditor-ajax-autosave-plugin/downloads/detail?name=autosave_php_connector.zip
As I was saying before the above archives contain two sample connectors, for Java and PHP. If you would like to attach sample connector for other programming language you are welcome.
Your Contribution
If you have found a bug, have got an idea for a new feature for this plugin or have a general idea how this plugin could be improved, please leave a comment.
If idea is interesting and possible to implement I will try to include it in future releases.
Updates
- Version 1.0.1 - It is now possible to use this plugin as manual AJAX save by simply setting autosaveSensitivity and autosaveRefreshTime configuration properties to 0. Special thanks to @lsdzung for bringing this up.
- Version 1.0.2 - It is now possible to define user specific request parameters with configuration option autosaveRequestParams, assign key shortcut to autosave button with configuration option autosaveKeystroke and execute user specific functions on two events fired by the plugin (afterAutosave and beforeAutosave). Special thanks to @petr82 for bringing this up.

Your solution is what I am looking for. But I develop in ASP.NET and C#.
Can you suggest a sample for ASP.NET and C# to use your plugin.
Can I use your plugin for many CKEditor instances in one page.
Thank you in advance.
Hi here is my ASP.Net implementation based on PHP Connector.
Create the page AutoSaveCallBack_.aspx. Be careful, ValidateRequest must set to "false" (to accept non encoded html in post request).
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AutoSaveCallBack_.aspx.cs" Inherits="webservices_AutoSaveCallBack_" ValidateRequest="false" %>
the code behind :
using System;
/// <summary>
/// My implemention in ASP.Net C# is a translation of PHP Connector.
/// </summary>
public partial class webservices_AutoSaveCallBack_ : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// If you want to secure access to this page, you can pass
// additionnal parameters like userid via querystring.
//
// In my case, on the "edit" page, i drive CKEditor programmaticly in code-behind via C#. (I use the "dll-wrapper" CKEditor.Net 3.6.4 in my \Bin directory.) :
//
// this.myEditor.ExtraPlugins = "autosave";
// this.myEditor.config.ExtraOptions["autosaveTargetUrl"] = "'https://localhost/webservices/AutoSaveCallBack.aspx?id_user=<mylogin>'";
// this.myEditor.config.ExtraOptions["autosaveRefreshTime"] = "'30'";
// NOTE IMPORTANT :
// If your "edit" page (ie, the page containing CKEditor) is accessed in "https", the autosaveTargetUrl must have the same
// http scheme, so "https" too.
this.SaveContent();
}
private bool SaveContent()
{
int id_rubrique = 0;
string exceptionMessage = null;
bool result = false;
// Invalid requests
if (String.IsNullOrEmpty(Request.Form["content"]) || String.IsNullOrEmpty(Request.Form["ckeditorname"]) || String.IsNullOrEmpty(Request.Form["autosaveaction"]))
{
this.SendResponse(400, null);
return false;
}
if (!Request.Form["autosaveaction"].Equals("draft"))
{
this.SendResponse(400, null);
return false;
}
if ((String.IsNullOrEmpty(Request.QueryString["id_rubrique"])) || (!int.TryParse(Request.QueryString["id_rubrique"], out id_rubrique)))
{
this.SendResponse(400, null);
return false;
}
if (String.IsNullOrEmpty(Request.QueryString["id_rubrique"]))
{
this.SendResponse(400, null);
return false;
}
// Save datas here...
result = this.SaveContent(Request.Form["content"], out exceptionMessage);
if (result)
{
this.SendResponse(200, null);
return result;
}
this.SendResponse(403, null);
return result;
}
/// <summary>
/// Send the response to the ajax request initiated by CKEditor plugin.
/// </summary>
/// <param name="errorCode">http error code</param>
/// <param name="errorMessage">custom exception message (optionnal)</param>
protected void SendResponse(int errorCode, string errorMessage)
{
this.SendXmlHeaders();
if (errorCode == 200)
{
Response.Write("<result status=\"ok\" />");
}
else
{
Response.Write("<error statuscode=\"" + errorCode + "\" ");
if (!String.IsNullOrEmpty(errorMessage))
{
Response.Write("message=\"" + Server.HtmlEncode(errorMessage) + "\" ");
}
Response.Write("/>");
}
}
/// <summary>
/// Send the appropriate headers.
/// </summary>
protected void SendXmlHeaders()
{
string gmtDate = DateTime.Now.ToString("r");
Response.Headers.Add("Expires", gmtDate);
Response.Headers.Add("Last-Modified", "Mon, 26 Jul 1997 05:00:00 GMT");
// HTTP/1.1
Response.AddHeader("Cache-Control", "no-store, no-cache, must-revalidate");
Response.AddHeader("Cache-Control", "post-check=0, pre-check=0");
// HTTP/1.0
Response.AddHeader("CPragma", "no-cache");
// Set the response format.
Response.AddHeader("Content-Type", "text/xml; charset=utf-8");
}
/// <summary>
/// This is the function used to save user-data.
/// </summary>
/// <param name="content">html content provided by CKEditor</param>
/// <param name="exceptionMessage">exception message if you want to have clear errors messages.</param>
/// <returns>return true if operation succeeded.</returns>
protected bool SaveContent(string content, out string exceptionMessage)
{
// Build you own persistence function to store
// CKEditor content in database or filesystem.
bool result = false;
exceptionMessage = "";
try
{
// Put your code here...
result = true;
}
catch (Exception ex)
{
exceptionMessage = ex.Message;
result = false;
}
return result;
}
/// <summary>
/// Optionnal security function to check if user is allowed to call this page
/// via ajax request by CKEditor Autosave plugin.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
protected bool IsUserAllowed(string userId)
{
// Build your owncode here to check
// if user is allowed to use this page.
return false;
}
}
About
As I was saying before I'm not a .NET developer so it will be hard for me to come up with anything.
But this shouldn't be a problem even for a beginner .NET developer
@roseholcomb143
I'm not sure if I understand correctly but if you have any problems with your solution please write about them I will try to help.
@roseholcomb143 and @lsdzung - as I understand correctly you are .NET developers. If you are able to come up with a sample connector you are welcome to contribute. It is enough when this connector simply writes something to file or only reads request parameters and does nothing else (it can be used as a template for other developers).
@lsdzung thanks for idea on how to improve this plugin.
I thought this was being handled by assigning request params to URL. I thought that my plugin handles all the rest but it does handle it only for GET requests (which probably no one uses) and not for POST.
I think I will treat it as bug and will try to fix it this week. I'm also working on other change suggested by @robC user so I'm not yet sure If I will make two releases or just one.
Although I hate to bring another config option I think that this will be the only solution here. Of course I could tell user to simply add his params to URL in form of queryString but in case of POST request it does not seam right even if plugin could done all the queryString stripping in background.
@petr82 what do you think?
I was testing the plugin a bit more and was wondering if there's a way to intercept when content has been saved, e.g. via an event handler. So i can display a message to the user (in addition to the tick symbol). Something on the lines of :
CKEDITOR.instances.editor_id.on('autosave', ...)I also haven't found a way to fire the autosave plugin using a shortcut. For standard save I've been able to configure Ctrl+S this way:But if a try to change 'save' for 'autosave' or 'Autosave' it doesn't work. Could you please try if this also doesn't work for you.
There was no code to handle extra parameters so I think new config option is something that allows for adding new (even generated) parameters without modifying the code.
No, plugin does not fire it's own event. This is however something to consider. I'm not sure though when to fire such event. The content is being saved in asynchronous way - in callback function... it's to late. The first thing that comes to my mind is just before making AJAX request call.
But plugin displays it's own messages in form of tooltip. Just hover the cross or tick and you will see. You can also change/add new messages.
Plugin does not have such option, yet again this is something to consider.
It does not break it. It uses it. I guess that this is the main drawback of this plugin - checking and resetting dirty state. As I was saying in previous post I'm working on a way to change it but I'm not sure if this will work.
The tick / cross icons are really nice but a normal user might not understand that. I'd like to show my own messages to ensure the user the content has been saved successfully.
I thought that ckeditor itself is handling that. Anyway that would be very useful if shortcuts could trigger autosave. Many users (incl. me) have the habit of using Ctrl+S when writing longer documents:-)
I see you're resetting in order to count changes. Wouldn't it be enough to count key presses? Surely, you'll miss using mouse events changing the style for example but I think the main proportion of editing a document will still be key presses.
Thanks for your response and also thanks for the work on this plugin, it's one of the most useful ones in CKEditor!
Messages: Before you implement your own messages pleas bear in mind that this plugin has it's own "messaging system". Please also have a look at manual as it IMO explains it well.
Just to give a quick summary - when contents were saved - message with time when it happened is displayed.
When error occurs either message from server or plugin predefined one is displayed.
To see the message you have to put mouse cursor over the icon.
Shotcut - Sorry it was quite late when I was reading and writing it:). Yes, this should be handled. I will check if there are any problems with it.
- There are other events fired by dialog, non-dialog plugins, by undo/redo, fired in source-mode etc. Plugin registering only some changes and not all of them? Hmmm... I just don't see it, sorry.
Anyway I have started to think of other way to handle saves. Method would be more intelligent and eventually could let me drop changes counter, interval and using dirty mechanism but this part might take some time as this change is quite big and to be honest it's back to the drawing board for me
var currentLength = getCurrentLength(); // just a mock method if ( lastLength != currentLength ) { autosaveCounter++ ; lastLength = currentLength; // change Icon to saveDirty autosaveChangeIcon( editor, autosaveIcons[1].path, autosaveIcons[1].title ); }It's just my guess because i'm not aware of the inner logic of the plugin that much, but do you think it might work or is there some catch to it?It is now possible to define user specific request parameters, assign key shortcut to autosave button and execute user specific functions on two events fired by the plugin.
@petr82 thanks for the tips.
Maybe you can use my onchange plugin (as-is or just picking up the relevant parts) to get info about any change. When you perform a save store a copy in memory of the current data, then wait for the onchange event + timers or whatever and if now the getData() is different save again. That wait you don't touch the "is dirty" property and rely just on your code.
That is why I had to add this extra check to see if editor was "really dirty".
Right-Click your project > Add New Item... > Generic Handler
Give it a name of AutoSave.ashx.
Replace all the code with whichever flavor below you like:
<%@ WebHandler Language="VB" Class="AutoSave" %> Public Class AutoSave Implements IHttpHandler, IRequiresSessionState Public Sub ProcessRequest(ByVal context As HttpContext) _ Implements IHttpHandler.ProcessRequest ' Do something with the data IO.File.WriteAllText("d:\path\to\save\content.txt", _ context.Request.Form("Content").ToString) context.Response.Clear() context.Response.ContentType = "text/xml;charset=UTF-8" context.Response.StatusCode = 200 context.Response.Write("<result status=""ok"" />") context.Response.Flush() End Sub Public ReadOnly Property IsReusable() As Boolean _ Implements IHttpHandler.IsReusable Get Return False End Get End Property End Class<%@ WebHandler Language="C#" Class="AutoSave" %> public class AutoSave : IHttpHandler, IRequiresSessionState { public void ProcessRequest(HttpContext context) { // Do something with the data IO.File.WriteAllText("d:\path\to\save\content.txt", context.Request.Form("Content").ToString); context.Response.Clear(); context.Response.ContentType = "text/xml;charset=UTF-8"; context.Response.StatusCode = 200; context.Response.Write("<result status=\"ok\" />"); context.Response.Flush(); } public bool IsReusable { get { return false; } } }In your config.js...
Finally, if you're using .Net 4, you'll have to add the following to your web.config to avoid an HttpRequestValidationException: "A potentially dangerous Request.Form value was detected" because the content is pushed without any encoding:
MrG
I'm using Backbone.js so when autosave fires, I only want the Autosave plugin to call my custom callback (not fire off any HTTP requests on its own). Would that be possible without hacking in to your code?
Something like:
$('#editor').ckeditor(config).ckeditorGet().on('autosave', function(event) { // Backbone Model .save() method will take care of hitting my API event.editor.config.model.save({content: event.editor.getData()}); // return true/false so the plugin knows if saving was successful return true; });If that's the case then what you really need is the onChange event part from the plugin. You're in luck because such event was created by @alfonsoml. You can find it on this forum and on his blog:
viewtopic.php?f=18&t=23605
http://alfonsoml.blogspot.com/2011/03/o ... ditor.html
Is this something you were looking for or my plugin has something more that you also need?
Well I like (and could use) other functionality bundled in your plugin. The onChange plugin you mention fires on every keypress I think ... I want less granular notification like your plugin provides.
But I guess I'm going to try a different route today. There's a decent jQuery plugin http://github.com/narfdotpl/jquery-typing I've used before that fires an event when a user stops typing. I'll see if I can integrate that.
Thanks for the response!
And it doesn't take into account just keypresses but it tries to detect any change to the content (formatting, inserting elements, etc...)
Ooh nice. I hadn't considered the formatting stuff. I'll give the onChange plugin another go. Thanks
I have an odd behavior in Internet Explorer (9.0.8112.16421). When pressing any CKeditor button (e.g. Bold or Italic), the plugin shows the message about abandon the page: "You will lose changes you have made in the editor since last save". Both Firefox and Chrome works without any problem.
To warn if there are unsaved modifications is a great functionality, so I wouldn't want to disable it.
Thanks in advance for any hint!
@ leocofre I have just tried this plugin and didn't get behaviour you were talking about.
Could you perhaps send me private message explaining in more detail how you are getting this problem.
Above all, Thanks for your work and your sharing.
I am new to plugin installation.
Sorry for my english google translation. I am French. : s
I downloaded the archive:
http://code.google.com/p/ckeditor-ajax- ... _1.0.2.zip
I put the autosave folder in the ckeditor plugins folder ...
I added the lines in the config.js file of ckeditor:
/* Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ CKEDITOR.editorConfig = function( config ) { config.font_names = 'Arial/Arial, Helvetica, sans-serif;' + 'Courier New/Courier New, Courier, monospace;' + 'Times New Roman/Times New Roman, Times, serif;'; config.resize_enabled = false; config.width = '96%'; config.disableNativeSpellChecker = false; // Lignes à rajouter : config.extraPlugins = 'autosave'; config.toolbar = [['Source','Save','Preview','-', 'Autosave']]; config.autosaveTargetUrl = 'http://mywebsite.fr/media/autosave/save/'; config.filebrowserUploadUrl = 'media/kcfinder/upload.php?type=files'; config.filebrowserImageUploadUrl = 'media/kcfinder/upload.php?type=images'; config.filebrowserFlashUploadUrl = 'media/kcfinder/upload.php?type=flash'; // Fin Lignes à rajouter // ADVANCED EDITOR || DESACTIVED : SAVE - FORM,CHECKBOX,RADIO,TEXTFILED,TEXTAREA,SELECT,BUTTON,IMAGEBUTTON,HIDDENFIELD - FLASH - ABOUT config.toolbar_Full = [ { name: 'document', items : [ 'Source','-','NewPage','DocProps','Preview','Print','-','Templates' ] }, { name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] }, { name: 'editing', items : [ 'Find','Replace','-','SelectAll','-','SpellChecker', 'Scayt' ] }, { name: 'links', items : [ 'Link','Unlink','Anchor' ] }, '/', { name: 'basicstyles', items : [ 'Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat' ] }, { name: 'paragraph', items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl' ] }, { name: 'tools', items : [ 'Maximize', 'ShowBlocks' ] }, { name: 'insert', items : [ 'Video','syntaxhighlight' ] }, '/', { name: 'styles', items : [ 'Styles','Format','Font','FontSize' ] }, { name: 'colors', items : [ 'TextColor','BGColor' ] }, { name: 'insert', items : [ 'Image','Table','HorizontalRule','Smiley','SpecialChar','PageBreak' ] }, ]; // BASIC EDITOR config.toolbar_Basic = [ [ 'Source', '-', 'Bold', 'Italic', 'Underline', '-', 'Image', 'Link', 'Smiley', '-', 'TextColor', 'RemoveFormat', '-', 'Scayt' ] ]; };But nothing happens ... I think I missed something.
Sorry for my noob attitude
My CMS is Nuked Klan 1.7.9 RC6 :s
http://www.nuked-klan.org/
tanks a lot for your help! :s
Please also note that under this URL config.autosaveTargetUrl = 'http://mywebsite.fr/media/autosave/save/';
you must have server-side code that will take data from editor and return proper response.
This is AJAX plugin - it works with server side code.
Aren't you getting any errors in Firebug console or net tab? I assume you may be getting JS errors or 404 HTTP error. BY installing plugin correctly (not just Java Script, server code is also important) you should be able to work them out.
@j.swiderski Hi, Thanks for your help! I realized what the problem was: I use ckeditor with a plugin for redmine 1.3 *, and this plugin allows to add or remove the autosave button from the toolbar. So the button was not there while the autosave plugin tried to access it. Firefox and Chrome don't bother the problem, but IE complained in that odd way. I modified the t(D,E,F) function to handle this exception.
The solution seems easy, but I can post it if useful. If there is an elegant workaround I'll be pleased to learn about it.
Thanks a lot!
* Redmine CKEditor Plugin: https://github.com/ebrahim/redmine_ckeditor.