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:
Andrew Nicols
2014-08-11 12:31:36 +08:00
parent 14cb870f46
commit 4dbc02f664
5 changed files with 231 additions and 36 deletions
@@ -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;
}
};
File diff suppressed because one or more lines are too long
@@ -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
View 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);
}
}, {
+40 -11
View 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();
// 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;
}
};