Skip to content

Commit

Permalink
Merge branch 'MDL-18014-master' of git://github.com/damyon/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
marinaglancy committed Aug 19, 2014
2 parents dd924ea + 9eea856 commit 430529b
Show file tree
Hide file tree
Showing 21 changed files with 1,568 additions and 11 deletions.
155 changes: 155 additions & 0 deletions lib/editor/atto/autosave-ajax.php
@@ -0,0 +1,155 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Save and load draft text while a user is still editing a form.
*
* @package editor_atto
* @copyright 2014 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

define('AJAX_SCRIPT', true);

require_once(dirname(__FILE__) . '/../../../config.php');

$contextid = required_param('contextid', PARAM_INT);
$elementid = required_param('elementid', PARAM_ALPHANUMEXT);
$pagehash = required_param('pagehash', PARAM_ALPHANUMEXT);
$pageinstance = required_param('pageinstance', PARAM_ALPHANUMEXT);
$now = time();
// This is the oldest time any autosave text will be recovered from.
// This is so that there is a good chance the draft files will still exist (there are many variables so
// this is impossible to guarantee).
$before = $now - 60*60*24*4;

list($context, $course, $cm) = get_context_info_array($contextid);
$PAGE->set_url('/lib/editor/atto/autosave-ajax.php');
$PAGE->set_context($context);

require_login($course, false, $cm);
require_sesskey();

$action = required_param('action', PARAM_ALPHA);

if ($action === 'save') {
$drafttext = required_param('drafttext', PARAM_RAW);
$params = array('elementid' => $elementid,
'userid' => $USER->id,
'pagehash' => $pagehash,
'contextid' => $contextid);

$record = $DB->get_record('editor_atto_autosave', $params);
if ($record && $record->pageinstance != $pageinstance) {
print_error('concurrent access from the same user is not supported');
die();
}

if (!$record) {
$record = new stdClass();
$record->elementid = $elementid;
$record->userid = $USER->id;
$record->pagehash = $pagehash;
$record->contextid = $contextid;
$record->drafttext = $drafttext;
$record->pageinstance = $pageinstance;
$record->timemodified = $now;

$DB->insert_record('editor_atto_autosave', $record);

// No response means no error.
die();
} else {
$record->drafttext = $drafttext;
$record->timemodified = time();
$DB->update_record('editor_atto_autosave', $record);

// No response means no error.
die();
}
} else if ($action == 'resume') {
$params = array('elementid' => $elementid,
'userid' => $USER->id,
'pagehash' => $pagehash,
'contextid' => $contextid);

$newdraftid = required_param('draftid', PARAM_INT);

$record = $DB->get_record('editor_atto_autosave', $params);

if (!$record) {
$record = new stdClass();
$record->elementid = $elementid;
$record->userid = $USER->id;
$record->pagehash = $pagehash;
$record->contextid = $contextid;
$record->pageinstance = $pageinstance;
$record->pagehash = $pagehash;
$record->draftid = $newdraftid;
$record->timemodified = time();
$record->drafttext = '';

$DB->insert_record('editor_atto_autosave', $record);

// No response means no error.
die();
} else {
// Copy all draft files from the old draft area.
$usercontext = context_user::instance($USER->id);
$stale = $record->timemodified < $before;
require_once($CFG->libdir . '/filelib.php');

// This function copies all the files in one draft area, to another area (in this case it's
// another draft area). It also rewrites the text to @@PLUGINFILE@@ links.
$newdrafttext = file_save_draft_area_files($record->draftid,
$usercontext->id,
'user',
'draft',
$newdraftid,
array(),
$record->drafttext);

// Final rewrite to the new draft area (convert the @@PLUGINFILES@@ again).
$newdrafttext = file_rewrite_pluginfile_urls($newdrafttext,
'draftfile.php',
$usercontext->id,
'user',
'draft',
$newdraftid);
$record->drafttext = $newdrafttext;

$record->pageinstance = $pageinstance;
$record->draftid = $newdraftid;
$record->timemodified = time();
$DB->update_record('editor_atto_autosave', $record);

// A response means the draft has been restored and here is the auto-saved text.
if (!$stale) {
echo $record->drafttext;
}
die();
}
} else if ($action == 'reset') {
$params = array('elementid' => $elementid,
'userid' => $USER->id,
'pagehash' => $pagehash,
'contextid' => $contextid);

$DB->delete_records('editor_atto_autosave', $params);
die();
}

print_error('invalidarguments');
25 changes: 25 additions & 0 deletions lib/editor/atto/db/install.xml
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/editor/atto/db" VERSION="20140819" COMMENT="XMLDB file for Moodle lib/editor/atto"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="editor_atto_autosave" COMMENT="Draft text that is auto-saved every 5 seconds while an editor is open.">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="elementid" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The unique id for the text editor in the form."/>
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The contextid that the form was loaded with."/>
<FIELD NAME="pagehash" TYPE="char" LENGTH="64" NOTNULL="true" SEQUENCE="false" COMMENT="The HTML DOM id of the page that loaded the form."/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the user that loaded the form."/>
<FIELD NAME="drafttext" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The draft text"/>
<FIELD NAME="draftid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Optional draft area id containing draft files."/>
<FIELD NAME="pageinstance" TYPE="char" LENGTH="64" NOTNULL="true" SEQUENCE="false" COMMENT="The browser tab instance that last saved the draft text. This is to prevent multiple tabs from the same user saving different text alternately."/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Store the last modified time for the auto save text."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="autosave_uniq_key" TYPE="unique" FIELDS="elementid, contextid, userid, pagehash" COMMENT="Unique key for the user in the form in the page."/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
43 changes: 43 additions & 0 deletions lib/editor/atto/db/upgrade.php
Expand Up @@ -53,6 +53,49 @@ function xmldb_editor_atto_upgrade($oldversion) {

// Moodle v2.7.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2014081400) {

// Define table editor_atto_autosave to be created.
$table = new xmldb_table('editor_atto_autosave');

// Adding fields to table editor_atto_autosave.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('elementid', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
$table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
$table->add_field('pagehash', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null);
$table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
$table->add_field('drafttext', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
$table->add_field('draftid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('pageinstance', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null);

// Adding keys to table editor_atto_autosave.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_key('autosave_uniq_key', XMLDB_KEY_UNIQUE, array('elementid', 'contextid', 'userid', 'pagehash'));

// Conditionally launch create table for editor_atto_autosave.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}

// Atto savepoint reached.
upgrade_plugin_savepoint(true, 2014081400, 'editor', 'atto');
}

if ($oldversion < 2014081900) {

// Define field timemodified to be added to editor_atto_autosave.
$table = new xmldb_table('editor_atto_autosave');
$field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'pageinstance');

// Conditionally launch add field timemodified.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}

// Atto savepoint reached.
upgrade_plugin_savepoint(true, 2014081900, 'editor', 'atto');
}


return true;
}
8 changes: 8 additions & 0 deletions lib/editor/atto/lang/en/editor_atto.php
Expand Up @@ -22,6 +22,10 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

$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'] = 'Draft 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.';
Expand All @@ -31,8 +35,12 @@
$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}';
$string['editor_control_keycode'] = 'Ctrl + {$a}';
$string['plugin_title_shortcut'] = '{$a->title} [{$a->shortcut}]';
$string['recover'] = 'Recover';
$string['infostatus'] = 'Information';
$string['warningstatus'] = 'Warning';
18 changes: 17 additions & 1 deletion lib/editor/atto/lib.php
Expand Up @@ -125,7 +125,14 @@ public function use_editor($elementid, array $options=null, $fpoptions=null) {
'editor_command_keycode',
'editor_control_keycode',
'plugin_title_shortcut',
'textrecovered',
'autosavefailed',
'autosavesucceeded'
), '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)));
Expand All @@ -146,15 +153,24 @@ protected function get_init_params($elementid, array $options = null, array $fpo
$strtime = get_string('strftimetime');
$strdate = get_string('strftimedaydate');
$lang = current_language();
$autosave = true;
$autosavefrequency = get_config('editor_atto', 'autosavefrequency');
if (isset($options['autosave'])) {
$autosave = $options['autosave'];
}
$contentcss = $PAGE->theme->editor_css_url()->out(false);

$params = array(
'elementid' => $elementid,
'content_css' => $contentcss,
'contextid' => $options['context']->id,
'autosaveEnabled' => $autosave,
'autosaveFrequency' => $autosavefrequency,
'language' => $lang,
'directionality' => $directionality,
'filepickeroptions' => array(),
'plugins' => $plugins
'plugins' => $plugins,
'pageHash' => sha1($PAGE->url)
);
if ($fpoptions) {
$params['filepickeroptions'] = $fpoptions;
Expand Down
Expand Up @@ -280,7 +280,7 @@ Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.Edit
* @private
*/
_changeListener: function(e) {
if (e.event.type.indexOf('key') !== -1) {
if (e.event && e.event.type.indexOf('key') !== -1) {
// These are the 4 arrow keys.
if ((e.event.keyCode !== 39) &&
(e.event.keyCode !== 37) &&
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -280,7 +280,7 @@ Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.Edit
* @private
*/
_changeListener: function(e) {
if (e.event.type.indexOf('key') !== -1) {
if (e.event && e.event.type.indexOf('key') !== -1) {
// These are the 4 arrow keys.
if ((e.event.keyCode !== 39) &&
(e.event.keyCode !== 37) &&
Expand Down
2 changes: 1 addition & 1 deletion lib/editor/atto/plugins/undo/yui/src/button/js/button.js
Expand Up @@ -278,7 +278,7 @@ Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.Edit
* @private
*/
_changeListener: function(e) {
if (e.event.type.indexOf('key') !== -1) {
if (e.event && e.event.type.indexOf('key') !== -1) {
// These are the 4 arrow keys.
if ((e.event.keyCode !== 39) &&
(e.event.keyCode !== 37) &&
Expand Down
7 changes: 7 additions & 0 deletions lib/editor/atto/settings.php
Expand Up @@ -48,6 +48,13 @@

$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) {
Expand Down

0 comments on commit 430529b

Please sign in to comment.