MDL-18014 Atto autosave: Show warning when the server cannot be contacted for autosave.

This commit is contained in:
Damyon Wiese 2014-07-21 12:17:19 +08:00
parent ddaeae21fd
commit 8a5db5472e
8 changed files with 196 additions and 37 deletions

View File

@ -22,6 +22,9 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$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['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.';
@ -36,9 +39,7 @@ $string['toolbarconfig_desc'] = 'The list of plugins and the order they are disp
$string['editor_command_keycode'] = 'Cmd + {$a}';
$string['editor_control_keycode'] = 'Ctrl + {$a}';
$string['plugin_title_shortcut'] = '{$a->title} [{$a->shortcut}]';
$string['confirm'] = 'Confirm';
$string['cancel'] = 'Cancel';
$string['recover'] = 'Recover';
$string['infostatus'] = 'Information';
$string['warningstatus'] = 'Warning';
$string['confirmrecover'] = 'A previously unsaved version of the text for field "{$a->label}" was found. Do you want to recover it?';
$string['autosavefailed'] = 'Could not connect to the server. If you submit this page now, your changes may be lost.';

View File

@ -128,8 +128,13 @@ class atto_texteditor extends texteditor {
'confirm',
'recover',
'cancel',
'confirmrecover'
'confirmrecover',
'autosavefailed'
), 'editor_atto');
$PAGE->requires->strings_for_js(array(
'warning',
'info'
), 'moodle');
$PAGE->requires->yui_module($modules,
'Y.M.editor_atto.Editor.init',
array($this->get_init_params($elementid, $options, $fpoptions, $jsplugins)));

View File

@ -239,6 +239,8 @@ Y.extend(Editor, Y.Base, {
// Initialize the auto-save timer.
this.setupAutosave();
// Preload the icons for the notifications.
this.setupNotifications();
},
/**
@ -493,10 +495,6 @@ function EditorNotify() {}
EditorNotify.ATTRS= {
};
// There is no error type here - because you should make errors more obvious.
var NOTIFY_WARNING = 'atto_warning',
NOTIFY_INFO = 'atto_info';
EditorNotify.prototype = {
/**
@ -507,13 +505,40 @@ EditorNotify.prototype = {
*/
messageOverlay: null,
/**
* A single timer object that can be used to cancel the hiding behaviour.
*
* @property hideTimer
* @type {timer}
*/
hideTimer: null,
/**
* Initialize the notifications.
*
* @method setupNotifications
* @chainable
*/
setupNotifications: function() {
var preload1 = new Image(),
preload2 = new Image();
preload1.src = M.util.image_url('i/warning', 'moodle');
preload2.src = M.util.image_url('i/info', 'moodle');
return this;
},
/**
* Show a notification in a floaty overlay somewhere in the atto editor text area.
*
* @method showMessage
* @param {String} message - The translated message (use get_string)
* @param {String} type - Must be either "info" or "warning"
* @param {Integer} timeout - Time in milliseconds to show this message for.
* @chainable
*/
showMessage: function(message, type) {
showMessage: function(message, type, timeout) {
if (this.messageOverlay === null) {
this.messageOverlay = Y.Node.create('<div class="editor_atto_notification"></div>');
@ -524,20 +549,34 @@ EditorNotify.prototype = {
this.messageOverlay.on('click', function() {
this.messageOverlay.hide();
}, this);
}
if (this.hideTimer !== null) {
this.hideTimer.cancel();
}
var messageTypeIcon = '';
if (type === NOTIFY_WARNING) {
if (type === "warning") {
messageTypeIcon = '<img width="16" height="16" src="' +
M.util.image_url('i/warning', 'moodle') +
'" alt="' + M.util.get_string('warning', 'moodle') + '"/>';
} else if (type === NOTIFY_INFO) {
} else if (type === "info") {
messageTypeIcon = '<img width="16" height="16" src="' +
M.util.image_url('i/info', 'moodle') +
'" alt="' + M.util.get_string('info', 'moodle') + '"/>';
} else {
Y.log('Invalid message type specified: ' + type + '. Must be either "info" or "warning".', 'debug');
}
// Parse the timeout value.
var inttimeout = parseInt(timeout, 10);
if (inttimeout <= 0) {
inttimeout = 60000;
}
// Convert class to atto_info (for example).
type = 'atto_' + type;
var bodyContent = Y.Node.create('<div class="' + type + '" role="alert" aria-live="assertive">' +
messageTypeIcon + ' ' +
Y.Escape.html(message) +
@ -546,6 +585,12 @@ EditorNotify.prototype = {
this.messageOverlay.append(bodyContent);
this.messageOverlay.show();
this.hideTimer = Y.later(inttimeout, this, function() {
Y.log('Hide Atto notification.', 'debug');
this.hideTimer = null;
this.messageOverlay.hide();
});
return this;
}
@ -688,7 +733,7 @@ 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;
var AUTOSAVE_FREQUENCY = 6000;
function EditorAutosave() {}
@ -860,6 +905,16 @@ EditorAutosave.prototype = {
method: 'POST',
data: params,
on: {
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);
},
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);
},
success: function() {
Y.log('Text auto-saved');
this.lastText = newText;
@ -867,8 +922,6 @@ EditorAutosave.prototype = {
},
context: this
});
this.lastText = newText;
}
return this;
}

File diff suppressed because one or more lines are too long

View File

@ -237,6 +237,8 @@ Y.extend(Editor, Y.Base, {
// Initialize the auto-save timer.
this.setupAutosave();
// Preload the icons for the notifications.
this.setupNotifications();
},
/**
@ -490,10 +492,6 @@ function EditorNotify() {}
EditorNotify.ATTRS= {
};
// There is no error type here - because you should make errors more obvious.
var NOTIFY_WARNING = 'atto_warning',
NOTIFY_INFO = 'atto_info';
EditorNotify.prototype = {
/**
@ -504,13 +502,40 @@ EditorNotify.prototype = {
*/
messageOverlay: null,
/**
* A single timer object that can be used to cancel the hiding behaviour.
*
* @property hideTimer
* @type {timer}
*/
hideTimer: null,
/**
* Initialize the notifications.
*
* @method setupNotifications
* @chainable
*/
setupNotifications: function() {
var preload1 = new Image(),
preload2 = new Image();
preload1.src = M.util.image_url('i/warning', 'moodle');
preload2.src = M.util.image_url('i/info', 'moodle');
return this;
},
/**
* Show a notification in a floaty overlay somewhere in the atto editor text area.
*
* @method showMessage
* @param {String} message - The translated message (use get_string)
* @param {String} type - Must be either "info" or "warning"
* @param {Integer} timeout - Time in milliseconds to show this message for.
* @chainable
*/
showMessage: function(message, type) {
showMessage: function(message, type, timeout) {
if (this.messageOverlay === null) {
this.messageOverlay = Y.Node.create('<div class="editor_atto_notification"></div>');
@ -521,20 +546,33 @@ EditorNotify.prototype = {
this.messageOverlay.on('click', function() {
this.messageOverlay.hide();
}, this);
}
if (this.hideTimer !== null) {
this.hideTimer.cancel();
}
var messageTypeIcon = '';
if (type === NOTIFY_WARNING) {
if (type === "warning") {
messageTypeIcon = '<img width="16" height="16" src="' +
M.util.image_url('i/warning', 'moodle') +
'" alt="' + M.util.get_string('warning', 'moodle') + '"/>';
} else if (type === NOTIFY_INFO) {
} else if (type === "info") {
messageTypeIcon = '<img width="16" height="16" src="' +
M.util.image_url('i/info', 'moodle') +
'" alt="' + M.util.get_string('info', 'moodle') + '"/>';
} else {
}
// Parse the timeout value.
var inttimeout = parseInt(timeout, 10);
if (inttimeout <= 0) {
inttimeout = 60000;
}
// Convert class to atto_info (for example).
type = 'atto_' + type;
var bodyContent = Y.Node.create('<div class="' + type + '" role="alert" aria-live="assertive">' +
messageTypeIcon + ' ' +
Y.Escape.html(message) +
@ -543,6 +581,11 @@ EditorNotify.prototype = {
this.messageOverlay.append(bodyContent);
this.messageOverlay.show();
this.hideTimer = Y.later(inttimeout, this, function() {
this.hideTimer = null;
this.messageOverlay.hide();
});
return this;
}
@ -685,7 +728,7 @@ 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;
var AUTOSAVE_FREQUENCY = 6000;
function EditorAutosave() {}
@ -855,14 +898,18 @@ EditorAutosave.prototype = {
method: 'POST',
data: params,
on: {
error: function(code, response) {
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
},
failure: function(code, response) {
this.showMessage(M.util.get_string('autosavefailed', 'editor_atto'), 'warning', AUTOSAVE_FREQUENCY);
},
success: function() {
this.lastText = newText;
}
},
context: this
});
this.lastText = newText;
}
return this;
}

View File

@ -23,7 +23,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
var AUTOSAVE_FREQUENCY = 60000;
var AUTOSAVE_FREQUENCY = 6000;
function EditorAutosave() {}
@ -195,6 +195,16 @@ EditorAutosave.prototype = {
method: 'POST',
data: params,
on: {
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);
},
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);
},
success: function() {
Y.log('Text auto-saved');
this.lastText = newText;
@ -202,8 +212,6 @@ EditorAutosave.prototype = {
},
context: this
});
this.lastText = newText;
}
return this;
}

View File

@ -237,6 +237,8 @@ Y.extend(Editor, Y.Base, {
// Initialize the auto-save timer.
this.setupAutosave();
// Preload the icons for the notifications.
this.setupNotifications();
},
/**

View File

@ -28,10 +28,6 @@ function EditorNotify() {}
EditorNotify.ATTRS= {
};
// There is no error type here - because you should make errors more obvious.
var NOTIFY_WARNING = 'atto_warning',
NOTIFY_INFO = 'atto_info';
EditorNotify.prototype = {
/**
@ -42,13 +38,40 @@ EditorNotify.prototype = {
*/
messageOverlay: null,
/**
* A single timer object that can be used to cancel the hiding behaviour.
*
* @property hideTimer
* @type {timer}
*/
hideTimer: null,
/**
* Initialize the notifications.
*
* @method setupNotifications
* @chainable
*/
setupNotifications: function() {
var preload1 = new Image(),
preload2 = new Image();
preload1.src = M.util.image_url('i/warning', 'moodle');
preload2.src = M.util.image_url('i/info', 'moodle');
return this;
},
/**
* Show a notification in a floaty overlay somewhere in the atto editor text area.
*
* @method showMessage
* @param {String} message - The translated message (use get_string)
* @param {String} type - Must be either "info" or "warning"
* @param {Integer} timeout - Time in milliseconds to show this message for.
* @chainable
*/
showMessage: function(message, type) {
showMessage: function(message, type, timeout) {
if (this.messageOverlay === null) {
this.messageOverlay = Y.Node.create('<div class="editor_atto_notification"></div>');
@ -59,20 +82,34 @@ EditorNotify.prototype = {
this.messageOverlay.on('click', function() {
this.messageOverlay.hide();
}, this);
}
if (this.hideTimer !== null) {
this.hideTimer.cancel();
}
var messageTypeIcon = '';
if (type === NOTIFY_WARNING) {
if (type === "warning") {
messageTypeIcon = '<img width="16" height="16" src="' +
M.util.image_url('i/warning', 'moodle') +
'" alt="' + M.util.get_string('warning', 'moodle') + '"/>';
} else if (type === NOTIFY_INFO) {
} else if (type === "info") {
messageTypeIcon = '<img width="16" height="16" src="' +
M.util.image_url('i/info', 'moodle') +
'" alt="' + M.util.get_string('info', 'moodle') + '"/>';
} else {
Y.log('Invalid message type specified: ' + type + '. Must be either "info" or "warning".', 'debug');
}
// Parse the timeout value.
var inttimeout = parseInt(timeout, 10);
if (inttimeout <= 0) {
inttimeout = 60000;
}
// Convert class to atto_info (for example).
type = 'atto_' + type;
var bodyContent = Y.Node.create('<div class="' + type + '" role="alert" aria-live="assertive">' +
messageTypeIcon + ' ' +
Y.Escape.html(message) +
@ -81,6 +118,12 @@ EditorNotify.prototype = {
this.messageOverlay.append(bodyContent);
this.messageOverlay.show();
this.hideTimer = Y.later(inttimeout, this, function() {
Y.log('Hide Atto notification.', 'debug');
this.hideTimer = null;
this.messageOverlay.hide();
});
return this;
}