Author: Tony Qu
Recently, a lot of progress has been made in solving data pasting. As a technology that is necessary for Html online editors, I will introduce it in detail and provide implementation references here. During the research process, I did take many detours and tried n methods. Since the PM in the United States always felt that some things that affect the user experience could not be accepted, several proposals were denied, but the gains were still very rich.
I now write code like demand-driven, let's take a look at the main requirements of this technology
* Able to filter plain text data posted by users
* Able to filter html data posted by users (not encoded by Html)
* Can filter Word data posted by users and retain most of the Word formats.
* Try not to let users know that we are doing filtering
* Do not prompt the user whether to enable certain permissions
The scenario for this example is an Html editor implemented using an iframe, not a text box (textarea or input with type text).
During the research process, I mainly refer to tinymce and ckeditor, but in the end I chose the implementation method of tinymce. You will understand the specific reason after reading the following paragraph.
The implementation of ckeditor is to extract data from the clipboard when the onpaste event is triggered, process the retrieved text, and then store the processed text into the clipboard. Some people say, can I cancel the paste action directly in onpaste and then put the obtained content into the iframe myself? I did this at that time, but unexpectedly, the data taken out directly from the clipboard is text that does not include format information, especially the data pasted from Word. The plain text, color, layout and other data do not exist. In this way, your user can only paste the data without format and edit it in the Html editor by himself. However, if the browser is asked to paste by itself, the format information will be retained, and the browser will automatically convert Word's paste data into XML data and put it into the dom. So in order to retain format information, we may only achieve this through the help of standard pasting behavior of the browser.
In addition, the implementation of ckeditor has a fatal weakness in Firefox. If you want to read and write data from the clipboard, you must prompt the user to set a permission called .codebase_principal_support by yourself. JavaScript scripts do not have permission to set it. Although this is normal from the perspective of technicians, many product managers cannot accept this, at least my product manager thinks so.
The following is the code for ckeditor to obtain and set the clipboard for your reference.
function setClipboard(maintext) {
if () {
return (("Text", maintext));
}
else if () {
('UniversalXPConnect');
var clip = ['@/widget/clipboard;1'].createInstance();
if (!clip) return;
var trans = ['@/widget/transferable;1'].createInstance();
if (!trans) return;
('text/unicode');
var str = new Object();
var len = new Object();
var str = ["@/supports-string;1"].createInstance();
var copytext=maintext;
=copytext;
("text/unicode",str,*2);
var clipid=;
if (!clip) return false;
(trans,null,);
return true;
}
return false;
}
function getClipboard() {
if () {
return(('Text'));
}
else if () {
('UniversalXPConnect');
var clip = ['@/widget/clipboard;1'].createInstance();
if (!clip) return;
var trans = ['@/widget/transferable;1'].createInstance();
if (!trans) return;
('text/unicode');
(trans,);
var str = new Object();
var len = new Object();
try {
('text/unicode',str,len);
}
catch(error) {
return null;
}
if (str) {
if () str=();
else if () str=();
else str = null;
}
if (str) {
return((0, / 2));
}
}
return null;
}
The following is the code that prompts the user to enable permissions
if ()
{
try
{
("UniversalXPConnect");
}
catch (ex)
{
alert("If you want to do paste, please input 'about:config' in address bar, then input Enter.\n Set \".codebase_principal_support\" to \"true\"");
}
}
So I referenced the implementation method of tinymce. When I looked at its code, I noticed that it can paste under Firefox without permission, and it can also retain the Word format, so I carefully read the code in it. The implementation steps of tinymce are different in IE and Firefox:
IE implementation
1. Create a temporary iframe in the onpaste callback function to paste the content. This iframe can be placed under the body of the main window.
2. Create a Range at the current cursor position to save the cursor position and selection information.
3. Let the temporary iframe get focus, execute the paste command, that is ("paste"), and the content will be pasted in the temporary iframe
4. Obtain content in a temporary iframe through innerHTML and filter it
5. Let the Iframe of the Html editor gain focus, and use the previously created Range object to execute the pasteHTML method to paste the filtered content
6. Finally cancel the default paste action
(Temporary iframes can be removed from the DOM according to personal preference, but since this iframe can be shared among multiple htmleditors, my implementation only changed the left and top of the iframe to adjust the position of the iframe, rather than removing it. The purpose of adjusting left and top is to move the focus to the temporary iframe. If the iframe and temporary iframe of the Html editor are not in the same view, the screen will scroll, which will cause the screen to flash for no reason.)
Firefox implementation
1. Create a temporary div in the onpaste callback function, which is placed in the iframe of the Html editor, which is also the key to bypassing the permissions issue.
2. Save the current cursor and focus position, and move the cursor to the temporarily created div
3. Set a callback function to execute after the paste action is completed instantly.
4. Let the paste action be executed (the onpaste callback function is executed)
5. The callback function just set is executed, and the innerHTML of the temporary div is obtained and filtered.
6. Restore the cursor and focus position you just saved, and remove the temporary div
7. Use the inserttml command (execCommand("inserthtml")) to paste the filtered content into the iframe of the Html editor.
The detailed code is as follows:
function getSel(w)
{
return ? () : ;
}
function setRange(sel,r)
{
();
(r);
}
function filterPasteData(originalText)
{
var newText=originalText;
//do something to filter unnecessary data
return newText;
}
function block(e)
{
();
}
var w,or,divTemp,originText;
var newData;
function pasteClipboardData(editorId,e)
{
var objEditor = (editorId);
var edDoc=;
if(isIE)
{
var orRange=();
var ifmTemp=("ifmTemp");
if(!ifmTemp)
{
ifmTemp=("IFRAME");
="ifmTemp";
="1px";
="1px";
="absolute";
="none";
="-10000px";
="";
(ifmTemp);
= "On";
();
("<body></body>");
();
}else
{
="";
}
originText=;
();
("Paste",false,null);
();
newData=;
//filter the pasted data
newData=filterPasteData(newData);
=newData;
//paste the data into the editor
(newData);
//block default paste
if(e)
{
= false;
if()
();
}
return false;
}else
{
enableKeyDown=false;
//create the temporary html editor
var divTemp=("DIV");
='htmleditor_tempdiv';
='\uFEFF';
="-10000px"; //hide the div
="1px";
="1px";
="absolute";
="hidden";
(divTemp);
//disable keyup,keypress, mousedown and keydown
("mousedown",block,false);
("keydown",block,false);
enableKeyDown=false;
//get current selection;
w=;
or=getSel(w).getRangeAt(0);
//move the cursor to into the div
var docBody=;
rng = ();
(docBody, 0);
(docBody, 1);
setRange(getSel(w),rng);
originText=;
if(originText==='\uFEFF')
{
originText="";
}
(function()
{
//get and filter the data after onpaste is done
if(==='\uFEFF')
{
newData="";
(divTemp);
return;
}
newData=;
// Restore the old selection
if (or)
{
setRange(getSel(w),or);
}
newData=filterPasteData(newData);
=newData;
//paste the new data to the editor
('inserthtml', false, newData );
(divTemp);
},0);
//enable keydown,keyup,keypress, mousedown;
enableKeyDown=true;
("mousedown",block,false);
("keydown",block,false);
return true;
}
}
The pasteClipboardData here is used as an onpaste callback function. To use it, you can add it to the onpaste event of the Iframe of the Html editor through the following code.
var ifrm=("editor")
if(isIE)
{
("onpaste", function(e){return pasteClipboardData(,e);});
}
else
{
("paste", function(e){return pasteClipboardData(,e);},false);
}
The filterPasteData function here is a function we use specifically for filtering. How to filter plain text, html and Word data will be explained in the next article.
Recently, a lot of progress has been made in solving data pasting. As a technology that is necessary for Html online editors, I will introduce it in detail and provide implementation references here. During the research process, I did take many detours and tried n methods. Since the PM in the United States always felt that some things that affect the user experience could not be accepted, several proposals were denied, but the gains were still very rich.
I now write code like demand-driven, let's take a look at the main requirements of this technology
* Able to filter plain text data posted by users
* Able to filter html data posted by users (not encoded by Html)
* Can filter Word data posted by users and retain most of the Word formats.
* Try not to let users know that we are doing filtering
* Do not prompt the user whether to enable certain permissions
The scenario for this example is an Html editor implemented using an iframe, not a text box (textarea or input with type text).
During the research process, I mainly refer to tinymce and ckeditor, but in the end I chose the implementation method of tinymce. You will understand the specific reason after reading the following paragraph.
The implementation of ckeditor is to extract data from the clipboard when the onpaste event is triggered, process the retrieved text, and then store the processed text into the clipboard. Some people say, can I cancel the paste action directly in onpaste and then put the obtained content into the iframe myself? I did this at that time, but unexpectedly, the data taken out directly from the clipboard is text that does not include format information, especially the data pasted from Word. The plain text, color, layout and other data do not exist. In this way, your user can only paste the data without format and edit it in the Html editor by himself. However, if the browser is asked to paste by itself, the format information will be retained, and the browser will automatically convert Word's paste data into XML data and put it into the dom. So in order to retain format information, we may only achieve this through the help of standard pasting behavior of the browser.
In addition, the implementation of ckeditor has a fatal weakness in Firefox. If you want to read and write data from the clipboard, you must prompt the user to set a permission called .codebase_principal_support by yourself. JavaScript scripts do not have permission to set it. Although this is normal from the perspective of technicians, many product managers cannot accept this, at least my product manager thinks so.
The following is the code for ckeditor to obtain and set the clipboard for your reference.
Copy the codeThe code is as follows:
function setClipboard(maintext) {
if () {
return (("Text", maintext));
}
else if () {
('UniversalXPConnect');
var clip = ['@/widget/clipboard;1'].createInstance();
if (!clip) return;
var trans = ['@/widget/transferable;1'].createInstance();
if (!trans) return;
('text/unicode');
var str = new Object();
var len = new Object();
var str = ["@/supports-string;1"].createInstance();
var copytext=maintext;
=copytext;
("text/unicode",str,*2);
var clipid=;
if (!clip) return false;
(trans,null,);
return true;
}
return false;
}
function getClipboard() {
if () {
return(('Text'));
}
else if () {
('UniversalXPConnect');
var clip = ['@/widget/clipboard;1'].createInstance();
if (!clip) return;
var trans = ['@/widget/transferable;1'].createInstance();
if (!trans) return;
('text/unicode');
(trans,);
var str = new Object();
var len = new Object();
try {
('text/unicode',str,len);
}
catch(error) {
return null;
}
if (str) {
if () str=();
else if () str=();
else str = null;
}
if (str) {
return((0, / 2));
}
}
return null;
}
The following is the code that prompts the user to enable permissions
Copy the codeThe code is as follows:
if ()
{
try
{
("UniversalXPConnect");
}
catch (ex)
{
alert("If you want to do paste, please input 'about:config' in address bar, then input Enter.\n Set \".codebase_principal_support\" to \"true\"");
}
}
So I referenced the implementation method of tinymce. When I looked at its code, I noticed that it can paste under Firefox without permission, and it can also retain the Word format, so I carefully read the code in it. The implementation steps of tinymce are different in IE and Firefox:
IE implementation
1. Create a temporary iframe in the onpaste callback function to paste the content. This iframe can be placed under the body of the main window.
2. Create a Range at the current cursor position to save the cursor position and selection information.
3. Let the temporary iframe get focus, execute the paste command, that is ("paste"), and the content will be pasted in the temporary iframe
4. Obtain content in a temporary iframe through innerHTML and filter it
5. Let the Iframe of the Html editor gain focus, and use the previously created Range object to execute the pasteHTML method to paste the filtered content
6. Finally cancel the default paste action
(Temporary iframes can be removed from the DOM according to personal preference, but since this iframe can be shared among multiple htmleditors, my implementation only changed the left and top of the iframe to adjust the position of the iframe, rather than removing it. The purpose of adjusting left and top is to move the focus to the temporary iframe. If the iframe and temporary iframe of the Html editor are not in the same view, the screen will scroll, which will cause the screen to flash for no reason.)
Firefox implementation
1. Create a temporary div in the onpaste callback function, which is placed in the iframe of the Html editor, which is also the key to bypassing the permissions issue.
2. Save the current cursor and focus position, and move the cursor to the temporarily created div
3. Set a callback function to execute after the paste action is completed instantly.
4. Let the paste action be executed (the onpaste callback function is executed)
5. The callback function just set is executed, and the innerHTML of the temporary div is obtained and filtered.
6. Restore the cursor and focus position you just saved, and remove the temporary div
7. Use the inserttml command (execCommand("inserthtml")) to paste the filtered content into the iframe of the Html editor.
The detailed code is as follows:
Copy the codeThe code is as follows:
function getSel(w)
{
return ? () : ;
}
function setRange(sel,r)
{
();
(r);
}
function filterPasteData(originalText)
{
var newText=originalText;
//do something to filter unnecessary data
return newText;
}
function block(e)
{
();
}
var w,or,divTemp,originText;
var newData;
function pasteClipboardData(editorId,e)
{
var objEditor = (editorId);
var edDoc=;
if(isIE)
{
var orRange=();
var ifmTemp=("ifmTemp");
if(!ifmTemp)
{
ifmTemp=("IFRAME");
="ifmTemp";
="1px";
="1px";
="absolute";
="none";
="-10000px";
="";
(ifmTemp);
= "On";
();
("<body></body>");
();
}else
{
="";
}
originText=;
();
("Paste",false,null);
();
newData=;
//filter the pasted data
newData=filterPasteData(newData);
=newData;
//paste the data into the editor
(newData);
//block default paste
if(e)
{
= false;
if()
();
}
return false;
}else
{
enableKeyDown=false;
//create the temporary html editor
var divTemp=("DIV");
='htmleditor_tempdiv';
='\uFEFF';
="-10000px"; //hide the div
="1px";
="1px";
="absolute";
="hidden";
(divTemp);
//disable keyup,keypress, mousedown and keydown
("mousedown",block,false);
("keydown",block,false);
enableKeyDown=false;
//get current selection;
w=;
or=getSel(w).getRangeAt(0);
//move the cursor to into the div
var docBody=;
rng = ();
(docBody, 0);
(docBody, 1);
setRange(getSel(w),rng);
originText=;
if(originText==='\uFEFF')
{
originText="";
}
(function()
{
//get and filter the data after onpaste is done
if(==='\uFEFF')
{
newData="";
(divTemp);
return;
}
newData=;
// Restore the old selection
if (or)
{
setRange(getSel(w),or);
}
newData=filterPasteData(newData);
=newData;
//paste the new data to the editor
('inserthtml', false, newData );
(divTemp);
},0);
//enable keydown,keyup,keypress, mousedown;
enableKeyDown=true;
("mousedown",block,false);
("keydown",block,false);
return true;
}
}
The pasteClipboardData here is used as an onpaste callback function. To use it, you can add it to the onpaste event of the Iframe of the Html editor through the following code.
Copy the codeThe code is as follows:
var ifrm=("editor")
if(isIE)
{
("onpaste", function(e){return pasteClipboardData(,e);});
}
else
{
("paste", function(e){return pasteClipboardData(,e);},false);
}
The filterPasteData function here is a function we use specifically for filtering. How to filter plain text, html and Word data will be explained in the next article.