MDL-45780 editor_atto: Update the textarea more often
This change updates the frequency of the textarea update to additionally update it: * on keypress; and * on content paste.
This commit is contained in:
+76
-11
@@ -148,6 +148,14 @@ Y.extend(Editor, Y.Base, {
|
||||
*/
|
||||
plugins: null,
|
||||
|
||||
/**
|
||||
* Event Handles to clear on editor destruction.
|
||||
*
|
||||
* @property _eventHandles
|
||||
* @private
|
||||
*/
|
||||
_eventHandles: null,
|
||||
|
||||
initializer: function() {
|
||||
var template;
|
||||
|
||||
@@ -162,6 +170,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" ' +
|
||||
@@ -221,6 +231,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();
|
||||
},
|
||||
@@ -271,6 +284,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 = {};
|
||||
@@ -336,6 +361,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);
|
||||
}
|
||||
|
||||
}, {
|
||||
@@ -435,6 +471,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.
|
||||
*
|
||||
@@ -455,11 +510,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());
|
||||
}
|
||||
},
|
||||
|
||||
@@ -470,14 +521,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();
|
||||
|
||||
// Trigger the onchange callback on the textarea, essentially to notify moodle-core-formchangechecker.
|
||||
this.textarea.simulate('change');
|
||||
if (newValue === "" && this.isActive()) {
|
||||
// The content was entirely empty so get the empty content placeholder.
|
||||
newValue = this._getEmptyContent();
|
||||
}
|
||||
|
||||
// Trigger handlers for this action.
|
||||
this.fire('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');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
+76
-11
@@ -148,6 +148,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 = {};
|
||||
@@ -333,6 +358,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);
|
||||
}
|
||||
|
||||
}, {
|
||||
@@ -432,6 +468,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.
|
||||
*
|
||||
@@ -452,11 +507,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());
|
||||
}
|
||||
},
|
||||
|
||||
@@ -467,14 +518,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();
|
||||
|
||||
// Trigger the onchange callback on the textarea, essentially to notify moodle-core-formchangechecker.
|
||||
this.textarea.simulate('change');
|
||||
if (newValue === "" && this.isActive()) {
|
||||
// The content was entirely empty so get the empty content placeholder.
|
||||
newValue = this._getEmptyContent();
|
||||
}
|
||||
|
||||
// Trigger handlers for this action.
|
||||
this.fire('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');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+36
@@ -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);
|
||||
}
|
||||
|
||||
}, {
|
||||
|
||||
+40
-11
@@ -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();
|
||||
|
||||
// Trigger the onchange callback on the textarea, essentially to notify moodle-core-formchangechecker.
|
||||
this.textarea.simulate('change');
|
||||
if (newValue === "" && this.isActive()) {
|
||||
// The content was entirely empty so get the empty content placeholder.
|
||||
newValue = this._getEmptyContent();
|
||||
}
|
||||
|
||||
// Trigger handlers for this action.
|
||||
this.fire('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');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user