Merge branch 'MDL-46748-master' of git://github.com/damyon/moodle
authorDan Poltawski <dan@moodle.com>
Mon, 11 Aug 2014 07:37:35 +0000 (08:37 +0100)
committerDan Poltawski <dan@moodle.com>
Mon, 11 Aug 2014 07:37:35 +0000 (08:37 +0100)
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/editor.js
lib/editor/atto/yui/src/editor/js/textarea.js
mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js
mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js
mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js
mod/quiz/yui/src/autosave/js/autosave.js

index 7eca9c5..c3a6a7a 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 47da04c..38b4105 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index ac817d3..b2d7442 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index b83bc16..931086c 100644 (file)
@@ -146,6 +146,14 @@ Y.extend(Editor, Y.Base, {
      */
     plugins: null,
 
+    /**
+     * Event Handles to clear on editor destruction.
+     *
+     * @property _eventHandles
+     * @private
+     */
+    _eventHandles: null,
+
     initializer: function() {
         var template;
 
@@ -160,6 +168,8 @@ Y.extend(Editor, Y.Base, {
             return;
         }
 
+        this._eventHandles = [];
+
         this._wrapper = Y.Node.create('<div class="' + CSS.WRAPPER + '" />');
         template = Y.Handlebars.compile('<div id="{{elementid}}editable" ' +
                 'contenteditable="true" ' +
@@ -219,6 +229,9 @@ Y.extend(Editor, Y.Base, {
         // Add handling for saving and restoring selections on cursor/focus changes.
         this.setupSelectionWatchers();
 
+        // Add polling to update the textarea periodically when typing long content.
+        this.setupAutomaticPolling();
+
         // Setup plugins.
         this.setupPlugins();
     },
@@ -269,6 +282,18 @@ Y.extend(Editor, Y.Base, {
         return this;
     },
 
+    /**
+     * Set up automated polling of the text area to update the textarea.
+     *
+     * @method setupAutomaticPolling
+     * @chainable
+     */
+    setupAutomaticPolling: function() {
+        this._registerEventHandle(this.editor.on(['keyup', 'paste', 'cut'], this.updateOriginal, this));
+
+        return this;
+    },
+
     setupPlugins: function() {
         // Clear the list of plugins.
         this.plugins = {};
@@ -334,6 +359,17 @@ Y.extend(Editor, Y.Base, {
                 currentPlugin[target]();
             }, this);
         }
+    },
+
+    /**
+     * Register an event handle for disposal in the destructor.
+     *
+     * @method _registerEventHandle
+     * @param {EventHandle} The Event Handle as returned by Y.on, and Y.delegate.
+     * @private
+     */
+    _registerEventHandle: function(handle) {
+        this._eventHandles.push(handle);
     }
 
 }, {
index 0dfdfb6..3d27188 100644 (file)
@@ -33,6 +33,25 @@ EditorTextArea.ATTRS= {
 };
 
 EditorTextArea.prototype = {
+
+    /**
+     * Return the appropriate empty content value for the current browser.
+     *
+     * Different browsers use a different content when they are empty and
+     * we must set this reliable across the board.
+     *
+     * @method _getEmptyContent
+     * @return String The content to use representing no user-provided content
+     * @private
+     */
+    _getEmptyContent: function() {
+        if (Y.UA.ie && Y.UA.ie < 10) {
+            return '<p></p>';
+        } else {
+            return '<p><br></p>';
+        }
+    },
+
     /**
      * Copy and clean the text from the textarea into the contenteditable div.
      *
@@ -53,11 +72,7 @@ EditorTextArea.prototype = {
 
         // Insert a paragraph in the empty contenteditable div.
         if (this.editor.getHTML() === '') {
-            if (Y.UA.ie && Y.UA.ie < 10) {
-                this.editor.setHTML('<p></p>');
-            } else {
-                this.editor.setHTML('<p><br></p>');
-            }
+            this.editor.setHTML(this._getEmptyContent());
         }
     },
 
@@ -68,14 +83,28 @@ EditorTextArea.prototype = {
      * @chainable
      */
     updateOriginal : function() {
-        // Insert the cleaned content.
-        this.textarea.set('value', this.getCleanHTML());
+        // Get the previous and current value to compare them.
+        var oldValue = this.textarea.get('value'),
+            newValue = this.getCleanHTML();
+
+        if (newValue === "" && this.isActive()) {
+            // The content was entirely empty so get the empty content placeholder.
+            newValue = this._getEmptyContent();
+        }
 
-        // Trigger the onchange callback on the textarea, essentially to notify moodle-core-formchangechecker.
-        this.textarea.simulate('change');
+        // Only call this when there has been an actual change to reduce processing.
+        if (oldValue !== newValue) {
+            // Insert the cleaned content.
+            this.textarea.set('value', newValue);
+
+            // Trigger the onchange callback on the textarea, essentially to notify moodle-core-formchangechecker.
+            this.textarea.simulate('change');
+
+            // Trigger handlers for this action.
+            this.fire('change');
+        }
 
-        // Trigger handlers for this action.
-        this.fire('change');
+        return this;
     }
 };
 
index c9fccf5..16b9616 100644 (file)
Binary files a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js and b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js differ
index ccbd6a6..a833973 100644 (file)
Binary files a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js and b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js differ
index e6a8f44..d9903dd 100644 (file)
Binary files a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js and b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js differ
index 546d722..e74b210 100644 (file)
@@ -89,7 +89,7 @@ M.mod_quiz.autosave = {
      */
     SELECTORS: {
         QUIZ_FORM:             '#responseform',
-        VALUE_CHANGE_ELEMENTS: 'input, textarea',
+        VALUE_CHANGE_ELEMENTS: 'input, textarea, [contenteditable="true"]',
         CHANGE_ELEMENTS:       'input, select',
         HIDDEN_INPUTS:         'input[type=hidden]',
         CONNECTION_ERROR:      '#connection-error',
@@ -192,7 +192,7 @@ M.mod_quiz.autosave = {
     init: function(delay) {
         this.form = Y.one(this.SELECTORS.QUIZ_FORM);
         if (!this.form) {
-            Y.log('No response form found. Why did you try to set up autosave?');
+            Y.log('No response form found. Why did you try to set up autosave?', 'debug', 'moodle-mod_quiz-autosave');
             return;
         }
 
@@ -254,12 +254,12 @@ M.mod_quiz.autosave = {
             if (repeatcount > 0) {
                 Y.later(this.TINYMCE_DETECTION_DELAY, this, this.init_tinymce, [repeatcount - 1]);
             } else {
-                Y.log('Gave up looking for TinyMCE.');
+                Y.log('Gave up looking for TinyMCE.', 'debug', 'moodle-mod_quiz-autosave');
             }
             return;
         }
 
-        Y.log('Found TinyMCE.');
+        Y.log('Found TinyMCE.', 'debug', 'moodle-mod_quiz-autosave');
         this.editor_change_handler = Y.bind(this.editor_changed, this);
         tinyMCE.onAddEditor.add(Y.bind(this.init_tinymce_editor, this));
     },
@@ -272,7 +272,7 @@ M.mod_quiz.autosave = {
      * @param {Object} editor The TinyMCE editor object
      */
     init_tinymce_editor: function(e, editor) {
-        Y.log('Found TinyMCE editor ' + editor.id + '.');
+        Y.log('Found TinyMCE editor ' + editor.id + '.', 'debug', 'moodle-mod_quiz-autosave');
         editor.onChange.add(this.editor_change_handler);
         editor.onRedo.add(this.editor_change_handler);
         editor.onUndo.add(this.editor_change_handler);
@@ -280,16 +280,19 @@ M.mod_quiz.autosave = {
     },
 
     value_changed: function(e) {
-        if (e.target.get('name') === 'thispage' || e.target.get('name') === 'scrollpos' ||
-                e.target.get('name').match(/_:flagged$/)) {
+        var name = e.target.getAttribute('name');
+        if (name === 'thispage' || name === 'scrollpos' || (name && name.match(/_:flagged$/))) {
             return; // Not interesting.
         }
-        Y.log('Detected a value change in element ' + e.target.get('name') + '.');
+
+        // Fallback to the ID when the name is not present (in the case of content editable).
+        name = name || '#' + e.target.getAttribute('id');
+        Y.log('Detected a value change in element ' + name + '.', 'debug', 'moodle-mod_quiz-autosave');
         this.start_save_timer_if_necessary();
     },
 
     editor_changed: function(editor) {
-        Y.log('Detected a value change in editor ' + editor.id + '.');
+        Y.log('Detected a value change in editor ' + editor.id + '.', 'debug', 'moodle-mod_quiz-autosave');
         this.start_save_timer_if_necessary();
     },
 
@@ -321,12 +324,12 @@ M.mod_quiz.autosave = {
         this.dirty = false;
 
         if (this.is_time_nearly_over()) {
-            Y.log('No more saving, time is nearly over.');
+            Y.log('No more saving, time is nearly over.', 'debug', 'moodle-mod_quiz-autosave');
             this.stop_autosaving();
             return;
         }
 
-        Y.log('Doing a save.');
+        Y.log('Doing a save.', 'debug', 'moodle-mod_quiz-autosave');
         if (typeof tinyMCE !== 'undefined') {
             tinyMCE.triggerSave();
         }
@@ -349,11 +352,11 @@ M.mod_quiz.autosave = {
             return;
         }
 
-        Y.log('Save completed.');
+        Y.log('Save completed.', 'debug', 'moodle-mod_quiz-autosave');
         this.save_transaction = null;
 
         if (this.dirty) {
-            Y.log('Dirty after save.');
+            Y.log('Dirty after save.', 'debug', 'moodle-mod_quiz-autosave');
             this.start_save_timer();
         }
 
@@ -368,7 +371,7 @@ M.mod_quiz.autosave = {
     },
 
     save_failed: function() {
-        Y.log('Save failed.');
+        Y.log('Save failed.', 'debug', 'moodle-mod_quiz-autosave');
         this.save_transaction = null;
 
         // We want to retry soon.