Index: lams_tool_notebook/conf/language/lams/ApplicationResources_en_AU.properties
===================================================================
RCS file: /usr/local/cvsroot/lams_tool_notebook/conf/language/lams/ApplicationResources_en_AU.properties,v
diff -u -r1.27 -r1.28
--- lams_tool_notebook/conf/language/lams/ApplicationResources_en_AU.properties 17 Jul 2014 18:04:10 -0000 1.27
+++ lams_tool_notebook/conf/language/lams/ApplicationResources_en_AU.properties 31 Jul 2014 01:07:48 -0000 1.28
@@ -113,4 +113,9 @@
label.learning.comment =Comment left by teacher:
label.group.summary =Summary
+label.notify.learner =Send email with comment to learner
+event.teacher.comment.subject =Teacher has left a comment for your notebook entry.
+event.teacher.comment.body =Comment:
+label.click.to.edit =Click to edit
+
#======= End labels: Exported 100 labels for en AU =====
Index: lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/notebookApplicationContext.xml
===================================================================
RCS file: /usr/local/cvsroot/lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/notebookApplicationContext.xml,v
diff -u -r1.9 -r1.10
--- lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/notebookApplicationContext.xml 6 Jun 2014 16:42:39 -0000 1.9
+++ lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/notebookApplicationContext.xml 31 Jul 2014 01:07:48 -0000 1.10
@@ -35,6 +35,8 @@
+
+
Index: lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/INotebookService.java
===================================================================
RCS file: /usr/local/cvsroot/lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/INotebookService.java,v
diff -u -r1.9 -r1.10
--- lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/INotebookService.java 17 Jan 2014 22:10:27 -0000 1.9
+++ lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/INotebookService.java 31 Jul 2014 01:07:48 -0000 1.10
@@ -44,71 +44,73 @@
* @params newContentID
* @return
*/
- public Notebook copyDefaultContent(Long newContentID);
+ Notebook copyDefaultContent(Long newContentID);
/**
* Returns an instance of the Notebook tools default content.
*
* @return
*/
- public Notebook getDefaultContent();
+ Notebook getDefaultContent();
/**
* @param toolSignature
* @return
*/
- public Long getDefaultContentIdBySignature(String toolSignature);
+ Long getDefaultContentIdBySignature(String toolSignature);
/**
* @param toolContentID
* @return
*/
- public Notebook getNotebookByContentId(Long toolContentID);
+ Notebook getNotebookByContentId(Long toolContentID);
/**
* @param notebook
*/
- public void saveOrUpdateNotebook(Notebook notebook);
+ void saveOrUpdateNotebook(Notebook notebook);
/**
* @param toolSessionId
* @return
*/
- public NotebookSession getSessionBySessionId(Long toolSessionId);
+ NotebookSession getSessionBySessionId(Long toolSessionId);
/**
* @param notebookSession
*/
- public void saveOrUpdateNotebookSession(NotebookSession notebookSession);
+ void saveOrUpdateNotebookSession(NotebookSession notebookSession);
/**
*
* @param userId
* @param toolSessionId
* @return
*/
- public NotebookUser getUserByUserIdAndSessionId(Long userId, Long toolSessionId);
+ NotebookUser getUserByUserIdAndSessionId(Long userId, Long toolSessionId);
/**
*
* @param uid
* @return
*/
- public NotebookUser getUserByUID(Long uid);
+ NotebookUser getUserByUID(Long uid);
/**
*
* @param notebookUser
*/
- public void saveOrUpdateNotebookUser(NotebookUser notebookUser);
+ void saveOrUpdateNotebookUser(NotebookUser notebookUser);
/**
*
* @param user
* @param notebookSession
* @return
*/
- public NotebookUser createNotebookUser(UserDTO user, NotebookSession notebookSession);
+ NotebookUser createNotebookUser(UserDTO user, NotebookSession notebookSession);
+
+ boolean notifyUser(Integer userId, String comment);
/**
*
Index: lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/NotebookService.java
===================================================================
RCS file: /usr/local/cvsroot/lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/NotebookService.java,v
diff -u -r1.31 -r1.32
--- lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/NotebookService.java 6 Jun 2014 16:42:39 -0000 1.31
+++ lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/service/NotebookService.java 31 Jul 2014 01:07:48 -0000 1.32
@@ -34,7 +34,7 @@
import org.apache.log4j.Logger;
import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler;
-import org.lamsfoundation.lams.contentrepository.service.IRepositoryService;
+import org.lamsfoundation.lams.events.IEventNotificationService;
import org.lamsfoundation.lams.learning.service.ILearnerService;
import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException;
import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService;
@@ -61,6 +61,7 @@
import org.lamsfoundation.lams.tool.notebook.util.NotebookException;
import org.lamsfoundation.lams.tool.service.ILamsToolService;
import org.lamsfoundation.lams.usermanagement.dto.UserDTO;
+import org.lamsfoundation.lams.util.MessageService;
import org.lamsfoundation.lams.util.WebUtil;
import org.lamsfoundation.lams.util.audit.IAuditService;
@@ -92,6 +93,10 @@
private IExportToolContentService exportContentService;
private ICoreNotebookService coreNotebookService;
+
+ private IEventNotificationService eventNotificationService;
+
+ private MessageService messageService;
private NotebookOutputFactory notebookOutputFactory;
@@ -408,13 +413,18 @@
saveOrUpdateNotebookUser(notebookUser);
return notebookUser;
}
+
+ @Override
+ public boolean notifyUser(Integer userId, String comment) {
+ boolean isHtmlFormat = false;
- public IAuditService getAuditService() {
- return auditService;
+ return eventNotificationService.sendMessage(null, userId, IEventNotificationService.DELIVERY_METHOD_MAIL,
+ getLocalisedMessage("event.teacher.comment.subject", new Object[] {}),
+ getLocalisedMessage("event.teacher.comment.body", new Object[] { comment }), isHtmlFormat);
}
- public void setAuditService(IAuditService auditService) {
- this.auditService = auditService;
+ private String getLocalisedMessage(String key, Object[] args) {
+ return messageService.getMessage(key, args);
}
/* ===============Methods implemented from ToolContentImport102Manager =============== */
@@ -515,13 +525,29 @@
this.exportContentService = exportContentService;
}
+ public IAuditService getAuditService() {
+ return auditService;
+ }
+
+ public void setAuditService(IAuditService auditService) {
+ this.auditService = auditService;
+ }
+
public ICoreNotebookService getCoreNotebookService() {
return coreNotebookService;
}
public void setCoreNotebookService(ICoreNotebookService coreNotebookService) {
this.coreNotebookService = coreNotebookService;
}
+
+ public void setEventNotificationService(IEventNotificationService eventNotificationService) {
+ this.eventNotificationService = eventNotificationService;
+ }
+
+ public void setMessageService(MessageService messageService) {
+ this.messageService = messageService;
+ }
public NotebookOutputFactory getNotebookOutputFactory() {
return notebookOutputFactory;
Index: lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/web/actions/MonitoringAction.java
===================================================================
RCS file: /usr/local/cvsroot/lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/web/actions/MonitoringAction.java,v
diff -u -r1.13 -r1.14
--- lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/web/actions/MonitoringAction.java 17 Jul 2014 18:04:10 -0000 1.13
+++ lams_tool_notebook/src/java/org/lamsfoundation/lams/tool/notebook/web/actions/MonitoringAction.java 31 Jul 2014 01:07:48 -0000 1.14
@@ -24,17 +24,21 @@
package org.lamsfoundation.lams.tool.notebook.web.actions;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
+import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
+import org.lamsfoundation.lams.events.IEventNotificationService;
import org.lamsfoundation.lams.notebook.model.NotebookEntry;
import org.lamsfoundation.lams.tool.notebook.dto.NotebookDTO;
import org.lamsfoundation.lams.tool.notebook.dto.NotebookEntryDTO;
@@ -45,6 +49,7 @@
import org.lamsfoundation.lams.tool.notebook.service.INotebookService;
import org.lamsfoundation.lams.tool.notebook.service.NotebookServiceProxy;
import org.lamsfoundation.lams.tool.notebook.util.NotebookConstants;
+import org.lamsfoundation.lams.usermanagement.User;
import org.lamsfoundation.lams.usermanagement.dto.UserDTO;
import org.lamsfoundation.lams.util.DateUtil;
import org.lamsfoundation.lams.util.WebUtil;
@@ -122,17 +127,23 @@
HttpServletRequest request, HttpServletResponse response) throws Exception {
setupService();
- String teachersComment = WebUtil.readStrParam(request, "teachersComment");
+ String teachersComment = WebUtil.readStrParam(request, "value", true);
Long userUid = WebUtil.readLongParam(request, NotebookConstants.PARAM_USER_UID);
+ boolean isNotifyLearner = WebUtil.readBooleanParam(request, "isNotifyLearner");
NotebookUser user = notebookService.getUserByUID(userUid);
- //check user had available notebook entry
- if (user.getEntryUID() != null) {
- Long toolSessionID = user.getNotebookSession().getSessionId();
- user.setTeachersComment(teachersComment);
- notebookService.saveOrUpdateNotebookUser(user);
+ //check user had available notebook entry and teachersComment is not blank
+ if ((user.getEntryUID() == null) && StringUtils.isNotBlank(teachersComment)) {
+ return null;
}
+ user.setTeachersComment(teachersComment);
+ notebookService.saveOrUpdateNotebookUser(user);
+
+ if (isNotifyLearner) {
+ notebookService.notifyUser(user.getUserId().intValue(), teachersComment);
+ }
+
return null;
}
Index: lams_tool_notebook/web/includes/javascript/jinplace-1.0.1.js
===================================================================
RCS file: /usr/local/cvsroot/lams_tool_notebook/web/includes/javascript/jinplace-1.0.1.js,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lams_tool_notebook/web/includes/javascript/jinplace-1.0.1.js 31 Jul 2014 01:07:48 -0000 1.1
@@ -0,0 +1,726 @@
+/** @preserve Copyright © 2013, Itinken Limited.
+ * MIT Licence */
+/*
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * See (http://jquery.com/).
+ * @name jQuery
+ * @class
+ * See the jQuery Library (http://jquery.com/) for full details. This just
+ * documents the function and classes that are added to jQuery by this plug-in.
+ */
+
+/**
+ * See (http://jquery.com/)
+ * @name fn
+ * @class
+ * See the jQuery Library (http://jquery.com/) for full details. This just
+ * documents the function and classes that are added to jQuery by this plug-in.
+ * @memberOf jQuery
+ */
+
+//noinspection JSUnnecessarySemicolon
+;
+//noinspection JSUnusedLocalSymbols
+(function ($, window, document, undefined) {
+ 'use strict';
+ var pluginName = "jinplace";
+
+ /**
+ * @typedef {object} Options
+ * @class Options
+ * @property {!string} type - The type of field. Defaults to 'input'
+ * @property {string} url - The url to submit to. Defaults to same page
+ * @property {string} data - Text or JSON data as initial editing text
+ * @property {string} loadurl - The URL to load content for editing
+ * @property {string} elementId - The ID of the element
+ * @property {string} object - A name to pass back on submit
+ * @property {string} attribute - Another name to pass back on submit
+ * @property {string} okButton - Create a submit button with this name
+ * @property {string} cancelButton - Create a cancel button with this name
+ * @property {string} inputClass - A css class that is added to the input field
+ * @property {jQuery|string} activator - Object (or css selector) for object to activate editing. Defaults to the element itself.
+ * @property {boolean} textOnly - When true (the default) text returned from server is displayed literally and not as html.
+ * @property {string} placeholder - Text to display in empty elements.
+ * @property {submitFunction} submitFunction - Function that is called to submit the new value.
+ * @property {loadFunction} loadFunction - Function that is called to load the editing data
+ */
+
+ var option_list = ['type',
+ 'url',
+ 'data',
+ 'loadurl',
+ 'elementId',
+ 'object',
+ 'attribute',
+ 'okButton',
+ 'cancelButton',
+ 'checkboxLabel',
+ 'inputClass',
+ 'activator',
+ 'textOnly',
+ 'placeholder',
+ 'submitFunction'
+ ];
+
+ /**
+ * The actual constructor of the JinPlace object.
+ *
+ * @class jinplace
+ * @memberOf jQuery.fn
+ * @constructor
+ *
+ * @property {jQuery} element - The element containing plain text to be edited.
+ * @property {Options} opts - The final set of options.
+ */
+ function JinPlace(element, options) {
+ var $el = this.element = $(element); // The editable element (often a span or div).
+
+ var elementOptions = this.elementOptions($el);
+
+ var act = elementOptions.activator || element;
+ elementOptions.activator = $(act);
+
+ // So we have 1) options defined in defaults, 2) passed into the plugin, 3) set
+ // on the element. Combine all these together.
+ var opts = $.extend({},
+ $.fn[pluginName].defaults,
+ options,
+ elementOptions);
+
+ this.opts = opts;
+
+ this.bindElement(opts);
+ }
+
+ JinPlace.prototype = {
+
+ /**
+ * Get the options that are set on the editable element with the data-* attributes.
+ *
+ * @param {jQuery} $el The element that is being made editable.
+ */
+ elementOptions: function ($el) {
+ var opts = {};
+ function upperToHyphenLower(match) {
+ return '-' + match.toLowerCase();
+ }
+
+ function make_attr_name(value) {
+ return "data-" + value.replace(/[A-Z]/g, upperToHyphenLower);
+ }
+
+ $.each(option_list, function(index, value) {
+ opts[value] = $el.attr(make_attr_name(value));
+ });
+
+ opts.elementId = $el.attr('id');
+
+ if (opts.textOnly)
+ opts.textOnly = opts.textOnly !== 'false';
+
+ return opts;
+ },
+
+ /**
+ * Prepare the activator element to receive click events.
+ *
+ * This involves setting placeholder text if the element is empty.
+ *
+ * @param {Options} opts - The editor options.
+ */
+ bindElement: function(opts) {
+ // Remove any existing handler we set and bind to the activation click handler.
+ opts.activator
+ .off('click.jip')
+ .on('click.jip', $.proxy(this.clickHandler, this));
+
+ // If there is no content, then we replace it with the empty indicator.
+ var $el = this.element;
+ if ($.trim($el.html()) == "") {
+ $el.html(opts.placeholder);
+
+ // In IE<9 the html is made uppercase which means it no longer matches what think the text is.
+ // So we retrieve the html.
+ opts.placeholder = $el.html();
+ }
+ },
+
+ /**
+ * Handle a click that is activating the element. This click can be on any element
+ * so is not directly useful. Things are always set up so that 'this' is this object
+ * and not the element that the click occurred on.
+ *
+ * @this {JinPlace}
+ * @param ev The event.
+ */
+ clickHandler: function(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ // Turn off the activation handler, and disable any effect in case the activator
+ // was a button that might submit.
+ $(ev.currentTarget)
+ .off('click.jip')
+ .on('click.jip', function(ev) {
+ //*LAMS* customized
+ if ((ev.target.id == "notify-learner") || (ev.target.id == "notify-learner-label")) {
+ return;
+ }
+ ev.preventDefault();
+ });
+
+ var self = this,
+ opts = self.opts;
+
+ /** A new editor is created for every activation. So it is OK to keep instance
+ * data on it.
+ * @type {editorBase}
+ */
+ var editor = $.extend({}, editorBase, $.fn[pluginName].editors[opts.type]);
+
+ // Save original for use when cancelling.
+ self.origValue = self.element.html();
+
+ self.fetchData(opts).done(function(data) {
+
+ var field = editor.makeField(self.element, data);
+ if (!editor.inputField)
+ editor.inputField = field;
+ field.addClass(opts.inputClass);
+
+ var form = createForm(opts, field, editor.buttonsAllowed);
+
+ // Add the form to the element to be edited
+ self.element.html(form);
+
+ // Now we can setup handlers and focus or otherwise activate the field.
+
+ form
+ .on("jip:submit submit", function(ev) {
+ //*LAMS* modified the next 2 lines
+ opts.isNotifyLearner = $(this).find('#notify-learner').prop("checked");
+ self.submit(editor, opts);
+ return false;
+ })
+ .on("jip:cancel", function(ev) {
+ self.cancel(editor);
+ return false;
+ })
+ .on("keyup", function(ev) {
+ if (ev.keyCode == 27) {
+ self.cancel(editor);
+ }
+ });
+
+ editor.activate(form, field);
+
+ // The action to take on blur can be set on the editor. If not, and there
+ // are automatically added buttons, then the blur action is set according to
+ // which ones exist. By default nothing happens on blur.
+ var act = editor.blurAction || (
+ (!opts.okButton)? 'submit':
+ (!opts.cancelButton)? 'jip:cancel':
+ undefined);
+ editor.blurEvent(field, form, act);
+ });
+ },
+
+ /**
+ * Fetch the data that will be placed into the editing control. The data is
+ * obtained from the following sources in this order:
+ * 1. data-data (or options.data)
+ * 2. data-loadurl (or options.loadurl) a request is made to the given url and the
+ * resulting data is used.
+ * 3. The existing contents of 'element'.
+ *
+ * @param {Options} opts
+ */
+ fetchData: function(opts) {
+ var data;
+ if (opts.data) {
+ data = opts.data;
+
+ } else if (opts.loadurl) {
+ data = opts.loadFunction(opts);
+ } else {
+ data = $.trim(this.element.html());
+ }
+
+ var placeholderFilter = function (data) {
+ if (data == opts.placeholder)
+ return '';
+ return data;
+ };
+
+ var when = $.when(data);
+ if (when.pipe) {
+ return when.pipe(placeholderFilter);
+ } else {
+ return when.then(placeholderFilter);
+ }
+ },
+
+ /**
+ * Throw away any edits and return the element to its original text.
+ *
+ * @param {editorBase} editor The element editor.
+ * @return {void}
+ */
+ cancel: function(editor) {
+ var self = this;
+ self.element.html(self.origValue);
+
+ editor.finish();
+
+ // Rebind the element for the next time
+ self.bindElement(self.opts);
+ },
+
+ /**
+ *
+ * Called to submit the changed data to the server.
+ *
+ * This method is always called with 'this' set to this object.
+ *
+ * @this {JinPlace}
+ * @param {editorBase} editor
+ * @param {Options} opts
+ */
+ submit: function (editor, opts) {
+ var self = this;
+ var rval;
+ var rejected = $.Deferred().reject();
+
+ // Since the function is user defined protect against exceptions and
+ // returning nothing. Either problem causes the edit to be cancelled.
+ // Of course it is possible that some action has been taken depending
+ // on why the exception was thrown, but there is no way to know that.
+ try {
+
+ opts.submitFunction.call(undefined, opts, editor.value());
+ } catch (e) {
+ }
+
+ //*LAMS* modified this part
+ self.onUpdate(editor, opts, editor.value());
+ },
+
+ /**
+ * The server has received our data and replied successfully and the new data to
+ * be displayed is available.
+ *
+ * @param {editorBase} editor The element editor.
+ * @param {Options} opts The element options.
+ * @param {string} data The data to display from the server.
+ */
+ onUpdate: function(editor, opts, data) {
+ var self = this;
+ self.setContent(data);
+ editor.finish();
+ self.element.trigger('jinplace:done', [data]);
+ self.bindElement(opts);
+ },
+
+ /**
+ * Set the content of the element. Called to update the value from the value
+ * returned by the server.
+ *
+ * @param data The data to be displayed, it has been converted to the display format.
+ */
+ setContent: function(data) {
+ var element = this.element;
+
+ if (!data) {
+ element.html(this.opts.placeholder);
+ return;
+ }
+
+ if (this.opts.textOnly) {
+ element.text(data);
+ } else {
+ element.html(data);
+ }
+ }
+
+ };
+
+ /**
+ * Get the parameters that will be sent in the ajax call to the server.
+ * Called for both the url and loadurl cases.
+ *
+ * @param {Options} opts The options from the element and config settings.
+ * @param {*=} [value] The value of the control as returned by editor.value().
+ * @returns {object}
+ */
+ var requestParams = function (opts, value) {
+ var params = {
+ "id": opts.elementId,
+ "object": opts.object,
+ attribute: opts.attribute,
+ //*LAMS* added the next line
+ "isNotifyLearner":opts.isNotifyLearner
+ };
+
+ if ($.isPlainObject(value)) {
+ $.extend(params, value);
+ } else if (value !== undefined) {
+ params.value = value;
+ }
+
+ return params;
+ };
+
+ // A really lightweight plugin wrapper around the constructor,
+ // preventing against multiple instantiations
+ $.fn[pluginName] = function (options) {
+ return this.each(function () {
+ if (!$.data(this, "plugin_" + pluginName)) {
+ $.data(this, "plugin_" + pluginName, new JinPlace(this, options));
+ }
+ });
+ };
+
+ /** These are the plugin defaults. You can override these if required.
+ * @type {Options}
+ */
+ $.fn[pluginName].defaults = {
+ url: document.location.pathname,
+ type: "input",
+ textOnly: 2,
+ placeholder: '[ --- ]',
+
+ /**
+ *
+ * @name Options.submitFunction
+ *
+ * The function to call when an editor form is submitted. This can be supplied as an
+ * option to completely change the default action.
+ *
+ * @callback submitFunction
+ * @param {Options} opts The options for this element.
+ * @param {string} value The value that was submitted.
+ * @returns {string|object} Returns a string which will be used to populate the element text or
+ * a promise that will resolve to a string.
+ */
+ submitFunction: function(opts, value) {
+ return $.ajax(opts.url, {
+ type: "post",
+ data: requestParams(opts, value),
+ dataType: 'text',
+
+ // iOS 6 has a dreadful bug where POST requests are not sent to the
+ // server if they are in the cache.
+ headers: {'Cache-Control': 'no-cache'} // Apple!
+ });
+ },
+
+ /**
+ * @name Options.loadFunction
+ *
+ * @callback loadFunction
+ * @param {Options} opts
+ * @returns {string}
+ */
+ loadFunction: function(opts) {
+ return $.ajax(opts.loadurl, {
+ data: requestParams(opts)
+ });
+ }
+ };
+
+ /**
+ * Create a form for the editing area. The input element is added and if buttons
+ * are required then they are added. Event handlers are set up.
+ *
+ * @param {Options} opts The options for this editor.
+ * @param {jQuery} inputField The newly created input field.
+ * @param {boolean} [buttons] True if buttons can be added. Whether buttons really are added
+ * depends on the options and data-* attributes.
+ * @returns {jQuery} The newly created form element.
+ */
+ var createForm = function (opts, inputField, buttons) {
+ var form = $("