MDL-18014 Atto: Make the autosave frequency configurable

This commit is contained in:
Damyon Wiese 2014-07-30 14:20:55 +08:00
parent a108fbeecf
commit 6bfd450a6d
10 changed files with 150 additions and 131 deletions

View File

@ -25,10 +25,7 @@
$string['autosavefailed'] = 'Could not connect to the server. If you submit this page now, your changes may be lost.';
$string['autosavefrequency'] = 'Autosave frequency (seconds).';
$string['autosavefrequency_desc'] = 'This is the number of seconds between auto save attempts. Atto will automatically save the text in the editor according to this setting, so that text can be automatically restored when the same user returns to the same form.';
$string['autosavesucceeded'] = 'Text was automatically saved.';
$string['cancel'] = 'Cancel';
$string['confirm'] = 'Confirm';
$string['confirmrecover'] = 'A previously unsaved version of the text for field "{$a->label}" was found. Do you want to recover it?';
$string['autosavesucceeded'] = 'A draft of this text was automatically saved.';
$string['errorcannotparseline'] = 'The line \'{$a}\' is not in the correct format.';
$string['errorgroupisusedtwice'] = 'The group \'{$a}\' is defined twice; group names must be unique.';
$string['errornopluginsorgroupsfound'] = 'No plugins or groups found; please add some groups and plugins.';
@ -38,6 +35,7 @@ $string['pluginname'] = 'Atto HTML editor';
$string['subplugintype_atto'] = 'Atto plugin';
$string['subplugintype_atto_plural'] = 'Atto plugins';
$string['settings'] = 'Atto toolbar settings';
$string['textrecovered'] = 'A draft version of this text was automatically restored.';
$string['toolbarconfig'] = 'Toolbar config';
$string['toolbarconfig_desc'] = 'The list of plugins and the order they are displayed can be configured here. The configuration consists of groups (one per line) followed by the ordered list of plugins for that group. The group is separated from the plugins with an equals sign and the plugins are separated with commas. The group names must be unique and should indicate what the buttons have in common. Button and group names should not be repeated and may only contain alphanumeric characters.';
$string['editor_command_keycode'] = 'Cmd + {$a}';

View File

@ -125,10 +125,7 @@ class atto_texteditor extends texteditor {
'editor_command_keycode',
'editor_control_keycode',
'plugin_title_shortcut',
'confirm',
'recover',
'cancel',
'confirmrecover',
'textrecovered',
'autosavefailed',
'autosavesucceeded'
), 'editor_atto');
@ -157,6 +154,7 @@ class atto_texteditor extends texteditor {
$strdate = get_string('strftimedaydate');
$lang = current_language();
$autosave = true;
$autosavefrequency = get_config('editor_atto', 'autosavefrequency');
if (isset($options['autosave'])) {
$autosave = $options['autosave'];
}
@ -167,6 +165,7 @@ class atto_texteditor extends texteditor {
'content_css' => $contentcss,
'contextid' => $options['context']->id,
'autosaveEnabled' => $autosave,
'autosaveFrequency' => $autosavefrequency,
'language' => $lang,
'directionality' => $directionality,
'filepickeroptions' => array(),

View File

@ -48,6 +48,13 @@ other = html';
$settings->add($setting);
}
$name = new lang_string('autosavefrequency', 'editor_atto');
$desc = new lang_string('autosavefrequency_desc', 'editor_atto');
$default = 60;
$setting = new admin_setting_configduration('editor_atto/autosavefrequency', $name, $desc, $default);
$settings->add($setting);
$ADMIN->add('editoratto', $settings);
foreach (core_plugin_manager::instance()->get_plugins_of_type('atto') as $plugin) {

View File

@ -190,6 +190,7 @@ div.editor_atto_content:hover .atto_control {
margin-left: 1px;
margin-right: 1px;
margin-bottom: 1em;
cursor: pointer;
}
.editor_atto_notification .atto_info {
display: inline-block;

View File

@ -406,18 +406,6 @@ Y.extend(Editor, Y.Base, {
writeOnce: true
},
/**
* Enable/Disable auto save for this instance.
*
* @attribute autosaveEnabled
* @type Boolean
* @writeOnce
*/
autosaveEnabled: {
value: true,
writeOnce: true
},
/**
* Plugins with their configuration.
*
@ -557,11 +545,11 @@ EditorNotify.prototype = {
var messageTypeIcon = '';
if (type === "warning") {
messageTypeIcon = '<img width="16" height="16" src="' +
messageTypeIcon = '<img src="' +
M.util.image_url('i/warning', 'moodle') +
'" alt="' + M.util.get_string('warning', 'moodle') + '"/>';
} else if (type === "info") {
messageTypeIcon = '<img width="16" height="16" src="' +
messageTypeIcon = '<img src="' +
M.util.image_url('i/info', 'moodle') +
'" alt="' + M.util.get_string('info', 'moodle') + '"/>';
} else {
@ -733,12 +721,36 @@ Y.Base.mix(Y.M.editor_atto.Editor, [EditorTextArea]);
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
var AUTOSAVE_FREQUENCY = 60000,
SUCCESS_MESSAGE_TIMEOUT = 5000;
var SUCCESS_MESSAGE_TIMEOUT = 5000,
RECOVER_MESSAGE_TIMEOUT = 60000;
function EditorAutosave() {}
EditorAutosave.ATTRS= {
/**
* Enable/Disable auto save for this instance.
*
* @attribute autosaveEnabled
* @type Boolean
* @writeOnce
*/
autosaveEnabled: {
value: true,
writeOnce: true
},
/**
* The time between autosaves (in seconds).
*
* @attribute autosaveFrequency
* @type Integer
* @default 60
* @writeOnce
*/
autosaveFrequency: {
value: 60,
writeOnce: true
}
};
EditorAutosave.prototype = {
@ -766,15 +778,16 @@ EditorAutosave.prototype = {
* @chainable
*/
setupAutosave: function() {
var draftid = -1,
optiontype = null,
options = this.get('filepickeroptions');
if (!this.get('autosaveEnabled')) {
// Autosave disabled for this instance.
return;
}
this.autosaveInstance = Y.stamp(this);
var draftid = -1, optiontype, options = this.get('filepickeroptions');
for (optiontype in options) {
if (typeof options[optiontype].itemid !== "undefined") {
draftid = options[optiontype].itemid;
@ -813,7 +826,9 @@ EditorAutosave.prototype = {
// Now setup the timer for periodic saves.
Y.later(AUTOSAVE_FREQUENCY, this, this.saveDraft, false, true);
Y.log(this.get('autosaveFrequency'));
var delay = parseInt(this.get('autosaveFrequency'), 10) * 1000;
Y.later(delay, this, this.saveDraft, false, true);
// Now setup the listener for form submission.
this.textarea.ancestor('form').on('submit', this.resetAutosave, this);
@ -849,30 +864,19 @@ EditorAutosave.prototype = {
/**
* Show a confirm dialogue and recover some text returned by ajax.
* Recover a previous version of this text and show a message.
*
* @method recoverText
* @param {String} text
* @chainable
*/
recoverText: function(text) {
var confirm = new M.core.confirm({
title : M.util.get_string('confirm', 'editor_atto'),
question : M.util.get_string('confirmrecover', 'editor_atto', {
label : this.textareaLabel.get('text')
}),
yesLabel : M.util.get_string('recover', 'editor_atto'),
noLabel : M.util.get_string('cancel', 'editor_atto')
});
confirm.on('complete-yes', function() {
confirm.hide();
confirm.destroy();
this.editor.setHTML(text);
this.saveSelection();
this.updateOriginal();
this.lastText = text;
}, this);
confirm.show();
this.editor.setHTML(text);
this.saveSelection();
this.updateOriginal();
this.lastText = text;
this.showMessage(M.util.get_string('textrecovered', 'editor_atto'), 'info', RECOVER_MESSAGE_TIMEOUT);
return this;
},
@ -901,6 +905,7 @@ EditorAutosave.prototype = {
pagedomid: Y.one('body').get('id'),
pageinstance: this.autosaveInstance
};
var errorDuration = parseInt(this.get('autosaveFrequency'), 10) * 1000;
Y.io(url, {
method: 'POST',
@ -909,18 +914,18 @@ EditorAutosave.prototype = {
error: function(code, response) {
Y.log('Error while autosaving text:' + code, 'warn');
Y.log(response, 'warn');
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
},
failure: function(code, response) {
Y.log('Failure while autosaving text:' + code, 'warn');
Y.log(response, 'warn');
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
},
success: function(code, response) {
if (response.response !== "") {
Y.log('Failure while autosaving text.', 'warn');
Y.log(response, 'debug');
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
} else {
// All working.
this.lastText = newText;

File diff suppressed because one or more lines are too long

View File

@ -403,18 +403,6 @@ Y.extend(Editor, Y.Base, {
writeOnce: true
},
/**
* Enable/Disable auto save for this instance.
*
* @attribute autosaveEnabled
* @type Boolean
* @writeOnce
*/
autosaveEnabled: {
value: true,
writeOnce: true
},
/**
* Plugins with their configuration.
*
@ -554,11 +542,11 @@ EditorNotify.prototype = {
var messageTypeIcon = '';
if (type === "warning") {
messageTypeIcon = '<img width="16" height="16" src="' +
messageTypeIcon = '<img src="' +
M.util.image_url('i/warning', 'moodle') +
'" alt="' + M.util.get_string('warning', 'moodle') + '"/>';
} else if (type === "info") {
messageTypeIcon = '<img width="16" height="16" src="' +
messageTypeIcon = '<img src="' +
M.util.image_url('i/info', 'moodle') +
'" alt="' + M.util.get_string('info', 'moodle') + '"/>';
} else {
@ -728,12 +716,36 @@ Y.Base.mix(Y.M.editor_atto.Editor, [EditorTextArea]);
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
var AUTOSAVE_FREQUENCY = 60000,
SUCCESS_MESSAGE_TIMEOUT = 5000;
var SUCCESS_MESSAGE_TIMEOUT = 5000,
RECOVER_MESSAGE_TIMEOUT = 60000;
function EditorAutosave() {}
EditorAutosave.ATTRS= {
/**
* Enable/Disable auto save for this instance.
*
* @attribute autosaveEnabled
* @type Boolean
* @writeOnce
*/
autosaveEnabled: {
value: true,
writeOnce: true
},
/**
* The time between autosaves (in seconds).
*
* @attribute autosaveFrequency
* @type Integer
* @default 60
* @writeOnce
*/
autosaveFrequency: {
value: 60,
writeOnce: true
}
};
EditorAutosave.prototype = {
@ -761,15 +773,16 @@ EditorAutosave.prototype = {
* @chainable
*/
setupAutosave: function() {
var draftid = -1,
optiontype = null,
options = this.get('filepickeroptions');
if (!this.get('autosaveEnabled')) {
// Autosave disabled for this instance.
return;
}
this.autosaveInstance = Y.stamp(this);
var draftid = -1, optiontype, options = this.get('filepickeroptions');
for (optiontype in options) {
if (typeof options[optiontype].itemid !== "undefined") {
draftid = options[optiontype].itemid;
@ -807,7 +820,8 @@ EditorAutosave.prototype = {
// Now setup the timer for periodic saves.
Y.later(AUTOSAVE_FREQUENCY, this, this.saveDraft, false, true);
var delay = parseInt(this.get('autosaveFrequency'), 10) * 1000;
Y.later(delay, this, this.saveDraft, false, true);
// Now setup the listener for form submission.
this.textarea.ancestor('form').on('submit', this.resetAutosave, this);
@ -843,30 +857,19 @@ EditorAutosave.prototype = {
/**
* Show a confirm dialogue and recover some text returned by ajax.
* Recover a previous version of this text and show a message.
*
* @method recoverText
* @param {String} text
* @chainable
*/
recoverText: function(text) {
var confirm = new M.core.confirm({
title : M.util.get_string('confirm', 'editor_atto'),
question : M.util.get_string('confirmrecover', 'editor_atto', {
label : this.textareaLabel.get('text')
}),
yesLabel : M.util.get_string('recover', 'editor_atto'),
noLabel : M.util.get_string('cancel', 'editor_atto')
});
confirm.on('complete-yes', function() {
confirm.hide();
confirm.destroy();
this.editor.setHTML(text);
this.saveSelection();
this.updateOriginal();
this.lastText = text;
}, this);
confirm.show();
this.editor.setHTML(text);
this.saveSelection();
this.updateOriginal();
this.lastText = text;
this.showMessage(M.util.get_string('textrecovered', 'editor_atto'), 'info', RECOVER_MESSAGE_TIMEOUT);
return this;
},
@ -894,20 +897,21 @@ EditorAutosave.prototype = {
pagedomid: Y.one('body').get('id'),
pageinstance: this.autosaveInstance
};
var errorDuration = parseInt(this.get('autosaveFrequency'), 10) * 1000;
Y.io(url, {
method: 'POST',
data: params,
on: {
error: function(code, response) {
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
},
failure: function(code, response) {
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
},
success: function(code, response) {
if (response.response !== "") {
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
} else {
// All working.
this.lastText = newText;

View File

@ -23,12 +23,36 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
var AUTOSAVE_FREQUENCY = 60000,
SUCCESS_MESSAGE_TIMEOUT = 5000;
var SUCCESS_MESSAGE_TIMEOUT = 5000,
RECOVER_MESSAGE_TIMEOUT = 60000;
function EditorAutosave() {}
EditorAutosave.ATTRS= {
/**
* Enable/Disable auto save for this instance.
*
* @attribute autosaveEnabled
* @type Boolean
* @writeOnce
*/
autosaveEnabled: {
value: true,
writeOnce: true
},
/**
* The time between autosaves (in seconds).
*
* @attribute autosaveFrequency
* @type Integer
* @default 60
* @writeOnce
*/
autosaveFrequency: {
value: 60,
writeOnce: true
}
};
EditorAutosave.prototype = {
@ -56,15 +80,16 @@ EditorAutosave.prototype = {
* @chainable
*/
setupAutosave: function() {
var draftid = -1,
optiontype = null,
options = this.get('filepickeroptions');
if (!this.get('autosaveEnabled')) {
// Autosave disabled for this instance.
return;
}
this.autosaveInstance = Y.stamp(this);
var draftid = -1, optiontype, options = this.get('filepickeroptions');
for (optiontype in options) {
if (typeof options[optiontype].itemid !== "undefined") {
draftid = options[optiontype].itemid;
@ -103,7 +128,9 @@ EditorAutosave.prototype = {
// Now setup the timer for periodic saves.
Y.later(AUTOSAVE_FREQUENCY, this, this.saveDraft, false, true);
Y.log(this.get('autosaveFrequency'));
var delay = parseInt(this.get('autosaveFrequency'), 10) * 1000;
Y.later(delay, this, this.saveDraft, false, true);
// Now setup the listener for form submission.
this.textarea.ancestor('form').on('submit', this.resetAutosave, this);
@ -139,30 +166,19 @@ EditorAutosave.prototype = {
/**
* Show a confirm dialogue and recover some text returned by ajax.
* Recover a previous version of this text and show a message.
*
* @method recoverText
* @param {String} text
* @chainable
*/
recoverText: function(text) {
var confirm = new M.core.confirm({
title : M.util.get_string('confirm', 'editor_atto'),
question : M.util.get_string('confirmrecover', 'editor_atto', {
label : this.textareaLabel.get('text')
}),
yesLabel : M.util.get_string('recover', 'editor_atto'),
noLabel : M.util.get_string('cancel', 'editor_atto')
});
confirm.on('complete-yes', function() {
confirm.hide();
confirm.destroy();
this.editor.setHTML(text);
this.saveSelection();
this.updateOriginal();
this.lastText = text;
}, this);
confirm.show();
this.editor.setHTML(text);
this.saveSelection();
this.updateOriginal();
this.lastText = text;
this.showMessage(M.util.get_string('textrecovered', 'editor_atto'), 'info', RECOVER_MESSAGE_TIMEOUT);
return this;
},
@ -191,6 +207,7 @@ EditorAutosave.prototype = {
pagedomid: Y.one('body').get('id'),
pageinstance: this.autosaveInstance
};
var errorDuration = parseInt(this.get('autosaveFrequency'), 10) * 1000;
Y.io(url, {
method: 'POST',
@ -199,18 +216,18 @@ EditorAutosave.prototype = {
error: function(code, response) {
Y.log('Error while autosaving text:' + code, 'warn');
Y.log(response, 'warn');
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
},
failure: function(code, response) {
Y.log('Failure while autosaving text:' + code, 'warn');
Y.log(response, 'warn');
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
},
success: function(code, response) {
if (response.response !== "") {
Y.log('Failure while autosaving text.', 'warn');
Y.log(response, 'debug');
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', errorDuration);
} else {
// All working.
this.lastText = newText;

View File

@ -404,18 +404,6 @@ Y.extend(Editor, Y.Base, {
writeOnce: true
},
/**
* Enable/Disable auto save for this instance.
*
* @attribute autosaveEnabled
* @type Boolean
* @writeOnce
*/
autosaveEnabled: {
value: true,
writeOnce: true
},
/**
* Plugins with their configuration.
*

View File

@ -90,11 +90,11 @@ EditorNotify.prototype = {
var messageTypeIcon = '';
if (type === "warning") {
messageTypeIcon = '<img width="16" height="16" src="' +
messageTypeIcon = '<img src="' +
M.util.image_url('i/warning', 'moodle') +
'" alt="' + M.util.get_string('warning', 'moodle') + '"/>';
} else if (type === "info") {
messageTypeIcon = '<img width="16" height="16" src="' +
messageTypeIcon = '<img src="' +
M.util.image_url('i/info', 'moodle') +
'" alt="' + M.util.get_string('info', 'moodle') + '"/>';
} else {