CKEditor autosave plugin - manual

General information

This plugin registers changes, made in editor content area, and when their number exceeds earlier defined value it sends the editor contents to server.

Plugin has three types of AJAX communication triggers: All of those triggers work independent of each other and without any conflicts.

Plugin sends data in POST request by default. There is also possibility to configure it to use GET request but when doing so one might get into query string limitation problems.

Plugin expects response in form of XML. The format of that response is hardcoded inside the plugin so the server-side connector should adjust to this format.

From version 1.0.2 plugin fires two events: "afterAutosave" (fired right after saving was finished) and "beforeAutosave" (fired right before AJAX request is made).
They can be used to fire user specific functions E.g. editor.on( 'beforeAutosave', function( evt ){ /*Do stuff here*/ } );

NOTE:As of version 1.0.1, it is also possible to use this plugin as AJAX manual save.
Please see Notes section at the bottom.

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:
  1. Register the plugin -
    config.extraPlugins = 'autosave';
  2. Add new toolbar button -
    config.toolbar = [['Source','Save','Preview','-', 'Autosave']];
  3. Specify URL for the data saving server-side script -
    config.autosaveTargetUrl = 'http://192.168.1.100:8080/AjaxAutosaveTest/cksource/core/connector/java/connector.java';
    NOTE: value for autosaveTargetUrl should be the same as the one used in browser address bar.
    If for example you have specified http://192.168.1.100:8080 then the same URL should be used in your browser address bar and not localhost.
That's it. Plugin should be up and running.

Configuration options

autosaveSensitivity : 20,
Informs after how many changes made in the editor’s data autosave should be fired. If set to zero this trigger will not be used. Default value is 20.

autosaveRefreshTime : 30,
Time in seconds after which autosave will fire. If set to zero, interval will not be used (it will be switched off). Default value is 30.
NOTE: If not set to zero then the value for this property can be either bigger or equal to autosaveMinTimeBetweenRequests.

autosaveUseOnBeforeUnload : true,
Specifies if onbeforeunload event should be used.
If user has changed editor data which haven’t yet been saved and he wants to leave the page, browser will ask him if he really wants to leave without saving the data. Default value is true.

autosaveTargetUrl : '',
Target url (required). URL for connector handling the request on server-side
E.g. http://192.168.1.115:8080/AjaxAutosave/cksource/connector/connector.java.

autosaveParentFormId : '',
Id of parent form element containing the editor instance. If specified, plugin will be disabled when form is submitted.
NOTE: If id is not specified, plugin will try to search for the parent form element and attach the same events as when id for the form is given. Default value is empty string.

autosaveMethod : 'POST',
Method used to send request. Only POST and GET are supported. Default value is POST.

autosaveContentParamName : 'content',
Name of parameter, holding editor data, to use in GET or POST request. Default value is ‘content’.

autosaveRequestParams : '',
User specific request parameters in form of querystring E.g. someName=false&someName2=someValue&someName3=5.
NOTE: This queryString should not start with ampersand sign.
Default value is empty string.

autosaveKeystroke : '',
Key shortcut for button used to invoke autosave action. It is treated the same way as if button was pressed (no counter checks are made).
Specify the shortcut and plugin will add it to CKEditor's keystroke table ( http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.keystrokes ).
NOTE: Shortcut will be added only if it does not exists in keystroke table.
Example value CKEDITOR.CTRL + 83 (CRTL+S). Default value is empty string.

autosaveRequestTimeout : 10,
Time in seconds after which client-side request will timeout if it is not yet finished on server-side. If set to zero timeout for client-side request will not be used. Default value is 10.
NOTE: This only aborts the client-side request so that application on browser side could return to its default state.

autosaveMinTimeBetweenRequests : 15
Minimum amount of time in seconds which has to pass before another request is send to server. Default value is 15.

Server-side connector

This plugin doesn’t come with server-side connector and it’s up to the user to create one.

There is a sample java application (second zip) which contains a draft of a connector. It’s a simple servlet which receives requests and sends back responses. It can be used as a jump start to create own connector.

  1. Request / response rules that server-side connector should follow:
    Autosave plugin sends three parameters – “autosaveaction” set to “draft”, “ckeditorname” set to name of instance using the plugin and “content” (this name can be changed) which holds encoded editor data. Server-side connector should refer to those parameters to get user input. Below is the example data (rewritten form Firebug) send from plugin:
    Parameters:application/x-www-form-urlencoded
    autosaveaction:draft
    ckeditorname:editor1
    content:<p>test message</p>
    Source: action=draft&ckeditorname=editor1&content=%3Cp%3E%0A%09test%20message%3C%2Fp%3E%0A
  2. Autosave plugin expects XML response in defined format. There are two general scenarios when response is returned: success and error.
    • Success - if request status is 200, Content-Type header is set to “text/xml” and response contains XML in form <result status="ok" />, it means that contents were saved and plugin can display success message with time when data was saved.
    • Error – expected XML has the following form:
      <error statuscode="404" message="message from server"/> or
      <error statuscode="500"/> or
      <error message="message from server"/>.
      As you can see either error code and message or both can be send. If message from server is provided it will be used instead of plugin predefined one.
      If only error code is send then plugin will try to match this code with one of his ready to use template messages and if it can’t find any matching message it will display a default one: “Code ### was returned. Please contact with an administrator”.
      The same scenario is applied when exception is thrown, no XML is provided or language specific method was used to send error response ( like response.sendError(500, “Server error”) used in Java ). In all of those situations format is unknown and any judgment can be made based on request status code (Note that response with status equal to 200 and no XML or unknown XML will also be treated as error). If response will be send in unknown XML format, plugin will treat it as an error and simply display the code provided

Below are the few examples written in Java:

Recommended ways to send XML response to plugin

  1. Returning success message
    Content-type is set to XML, expected “success XML” is send. This is recommended way to send success message.
    Additionally you can send response status which defaults to 200.
    response.setContentType("text/xml;charset=UTF-8");
    response.setStatus(200);
    out.println("<result status=\"ok\" />");
    response.setContentType("text/xml;charset=UTF-8");
    out.println("<result status=\"ok\" />");
  2. Returning error message
    Expected “error XML” is provided. It will be used to give information to the user. This is the recommended way to send error messages from the server.
    Additionally you can send response status which defaults to 200.
    response.setContentType("text/xml;charset=UTF-8");
    out.println("<error statuscode=\"404\" message=\"Page not found\" />");
    response.setContentType("text/xml;charset=UTF-8");
    response.setStatus(200);
    out.println("<error message=\"Page not found\" />");
  3. Returning error message only with error code
    Expected “error XML” only with status code is provided. In first example message from plugin will be used in second status code is unknown (there is no 555 HTTP status code) thus default message will be used. This is the also recommended way to send error messages from the server.
    response.setContentType("text/xml;charset=UTF-8");
    response.setStatus(200);
    out.println("<error statuscode=\"503\" />");
    response.setContentType("text/xml;charset=UTF-8");
    out.println("<error statuscode=\"555\" message=\"\ "/>");

Other ways to send XML error response to the plugin

  1. Content-type set to XML and exception or error or only exception is send to the plugin. In all of those situations plugin predefined message for code 500 will be used.
    response.setContentType("text/xml;charset=UTF-8");
    response.sendError(500, "Internal server error");
    response.setContentType("text/xml;charset=UTF-8");
    throw new ServletException("excepton on servlet was thrown");
    throw new ServletException("excepton on servlet was thrown");
  2. In the below examples there is no XML and status code is not 200 thus all of them will be treated as errors. In first case message from sever will be used. In second and third a predefined plugin message for status code 404 will be used. In fourth default error message plus some garbage HTML send from Tomcat.
    You may wonder why in second case the custom message from server is not displayed. This is because, for status different than 200, predefined plugin messages for known status codes have higher priority than custom message coming from server. This message can be garbage XML/HTML/Text or user defined. Anyway it best not to risk and display something that plugin knows is definitely understandable.
    response.setStatus(555);
    response.setContentType("text/plain;charset=UTF-8");
    out.println("Custom error message");
    response.setStatus(404);
    response.setContentType("text/plain;charset=UTF-8");
    out.println("File not found");
    response.setStatus(404);
    response.setContentType("text/plain;charset=UTF-8");
    response.setStatus(555);
    response.setContentType("text/plain;charset=UTF-8");

Troubleshooting

  1. Setting content-type to text and sending expected XML will fail in all browsers except Opera. Sending only expected XML will work in all browsers except for IE.
    response.setContentType("text/plain;charset=UTF-8");
    out.println("<result status=\"ok\" />");
    out.println("<result status=\"ok\" />");
  2. Custom XML will be displayed in the same form as it was send to the plugin.
    response.setContentType("text/xml;charset=UTF-8");
    out.println("<error errorNo=\"501\" errorD=\"\" />");
    response.setContentType("text/xml;charset=UTF-8");
    out.println("<myerror statuscode=\"555\" message=\"\" />");
  3. Although status code is set to 200, there is no XML provided thus all three examples will be treated as errors. In first case custom server message will be displayed. In the next two the default error message will be used.
    response.setStatus(200);
    response.setContentType("text/plain;charset=UTF-8");
    out.println("Some message which will be treated as an error");
    response.setContentType("text/xml;charset=UTF-8");
    response.setStatus(200);
    response.setStatus(200);

Notes

  1. Autosave plugin searches common error messages using the construction ‘error’+statuscode E.g. error404 or error500.
    If user wants to create his own custom message all he has to do is go to language file like en.js and add it.
    For example user can add error555 : ‘My custom message for custom code’. Now every time user’s connector will return status code 555 the above message will be used.
  2. In plugin language files, one key (defaultErrorMessage) contains message with placeholder (###) which is later replaced by status code. When defining own language files one should not forget about placeholder for this key.
    defaultErrorMessage: Code ### was returned. Please contact with an administrator.
  3. As of version 1.0.1, it is possible to switch off "Change counter" and "Interval" and use this plugin as AJAX manual save.
    All that needs to be done is setting autosaveSensitivity and autosaveRefreshTime configuration properties to 0.
  4. As of version 1.0.2, it is possible: to define user specific request parameters (See autosaveRequestParams) and to assign key shortcut to autosave button (See autosaveKeystroke).
    As of this version plugin also fires two events: "afterAutosave" (fired right after saving was finished) and "beforeAutosave" (fired right before AJAX request is made).