Detailed description of HTML editor paste Content Filtering Technology

Source: Internet
Author: User

Author: Tony Qu
Recently, a lot of progress has been made in solving the problem of data pasting. As a technology required by the HTML online editor, we will introduce it in detail and provide implementation reference here. During the study, I did take a lot of detours and tried n methods. Because PM in the United States always felt that some things that affected the user experience were unacceptable, several proposals were rejected, however, there are still many gains.
I write code now and like demand-driven. Let's take a look at the main requirements of this technology.
* Filters plain text data pasted by users.
* Filters HTML data pasted by users (without HTML encoding)
* Filters the word data pasted by the user and retains most of the word formats.
* In this process, try not to let users know that we are filtering.
* Do not prompt the user whether to enable certain permissions.
In this example, the applicable scenario is the HTML editor implemented by IFRAME, rather than the text box (textarea or input with text type ).

During the study, I mainly referred to tinymce and ckeditor, but finally I chose the implementation method of tinymce. The specific reason is as follows.
Ckeditor is implemented by extracting data from the clipboard when the onpaste event is triggered, processing the extracted text, and then saving the processed text to the clipboard. Someone said that I could not cancel the paste action in onpaste and put the obtained content into IFRAME. I did this at the time, but the result was unexpected, the data taken directly from the clipboard does not include the text of the format information, especially the data pasted from the word. data such as plain text, color, and layout do not exist. In this case, your users can only paste the unformatted data and re-edit it in the HTML editor. However, if you have the browser paste the format information, the browser will automatically convert the word paste data to XML data and put it into the Dom. So in order to retain the format information, we are afraid that this can only be achieved through the help of the browser's standard pasting behavior.
In addition, 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 signature. applets. codebase_principal_support permission. JavaScript scripts do not have the permission to be set. Although it is normal for technicians, many product managers cannot accept this permission, at least my product manager thinks so.
The following is how ckeditor obtains and sets the clipboard. Code For your reference. Copy code The Code is as follows: function setclipboard (maintext ){
If (window. clipboardData ){
Return (window. clipboardData. setdata ("text", maintext ));
}
Else if (window. Netscape ){
Netscape. Security. privilegemanager. enableprivilege ('universalxpconnect ');
VaR clip = components. classes ['@ mozilla.org/widget/clipboard=1'mirror.createinstance (components. Interfaces. nsiclipboard );
If (! Clip) return;
VaR trans = components. classes ['@ mozilla.org/widget/transferable00001').createinstance (components. Interfaces. nsitransferable );
If (! Trans) return;
Trans. adddataflavor ('text/Unicode ');
VaR STR = new object ();
VaR Len = new object ();
VaR STR = components. classes ["@ mozilla.org/supports-string1_1"]. createinstance (components. Interfaces. nsisupportsstring );
VaR copytext = maintext;
Str. Data = copytext;
Trans. settransferdata ("text/Unicode", STR, copytext. length * 2 );
VaR clipid = components. Interfaces. nsiclipboard;
If (! Clip) return false;
Clip. setdata (trans, null, clipid. kglobalclipboard );
Return true;
}
Return false;
}
Function getclipboard (){
If (window. clipboardData ){
Return (window. clipboardData. getdata ('text '));
}
Else if (window. Netscape ){
Netscape. Security. privilegemanager. enableprivilege ('universalxpconnect ');
VaR clip = components. classes ['@ mozilla.org/widget/clipboard=1'mirror.createinstance (components. Interfaces. nsiclipboard );
If (! Clip) return;
VaR trans = components. classes ['@ mozilla.org/widget/transferable00001').createinstance (components. Interfaces. nsitransferable );
If (! Trans) return;
Trans. adddataflavor ('text/Unicode ');
Clip. getdata (trans, Clip. kglobalclipboard );
VaR STR = new object ();
VaR Len = new object ();
Try {
Trans. gettransferdata ('text/Unicode ', STR, Len );
}
Catch (error ){
Return NULL;
}
If (STR ){
If (components. Interfaces. nsisupportswstring) STR = Str. value. QueryInterface (components. Interfaces. nsisupportswstring );
Else if (components. Interfaces. nsisupportsstring) STR = Str. value. QueryInterface (components. Interfaces. nsisupportsstring );
Else STR = NULL;
}
If (STR ){
Return (Str. Data. substring (0, Len. Value/2 ));
}
}
Return NULL;
}

the following code prompts you to enable permissions: copy Code the code is as follows: if (window. netscape)
{< br> try
{< br> Netscape. security. privilegemanager. enableprivilege ("universalxpconnect");
}< br> catch (Ex)
{< br> alert ("if you want to do paste, please input 'about: config 'in address bar, then input enter. \ n set \ "signed. applets. codebase_principal_support \ "to \" True \ "");
}< BR >}

so I referred to the implementation method of tinymce. When I read its code, I noticed that it can be pasted under firefox without permissions, the Word format can be retained, So I carefully read the code. 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. Put the IFRAME under the body of the main window.
2. Create a range at the current cursor position to save the cursor position and selected information.
3. make sure that the specified iframeparameter is highlighted and the command is executed, that is, document.exe ccommand ("paste"). The content will be pasted in the temporary IFRAME.
4. use innerhtml to obtain and filter the content in the temporary IFRAME
5. let the IFRAME of the HTML editor get the focus, and use the previously created range object to execute the pastehtml method to paste the filtered content.
6. cancel the default paste action
(the temporary IFRAME can be deleted from the DOM according to your preferences. However, this IFRAME can be shared among multiple htmleditor instances, so in my implementation, I only changed the left and top of IFRAME to adjust the position of IFRAME, instead of 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. This is also the key to bypassing permissions.
2. save the current cursor and focus position, and move the cursor to the newly created Div.
3. through window. setTimeout: Set a callback function to be executed after the paste action is completed instantly
4. execute the paste action (the onpaste callback function has been executed)
5. the callback function just set is executed. Obtain the innerhtml of the temporary Div and filter it.
6. restore the saved cursor and focus positions and remove the temporary Div
7. use the inserthtml command (Execcommand ("inserthtml") to paste the filtered content to the IFRAME of the HTML editor.

The Code is as follows: Copy code The Code is as follows: function getsel (W)
{
Return W. getselection? W. getselection (): Invalid Doc ument. selection;
}
Function setrange (SEL, R)
{
Sel. removeallranges ();
Sel. addrange (R );
}
Function filterpastedata (originaltext)
{
VaR newtext = originaltext;
// Do something to filter unnecessary data
Return newtext;
}
Function Block (E)
{
E. preventdefault ();
}
VaR W, or, divtemp, origintext;
VaR newdata;
Function pasteclipboarddata (editorid, E)
{
VaR objeditor = Document. getelementbyid (editorid );
VaR eddoc=objeditor.content?#doc ument;
If (isie)
{
VaR orrange1_objeditor.content1_doc ument. selection. createRange ();
VaR ifmtemp = Document. getelementbyid ("ifmtemp ");
If (! Ifmtemp)
{
Ifmtemp = Document. createelement ("iframe ");
Ifmtemp. ID = "ifmtemp ";
Ifmtemp. style. width = "1px ";
Ifmtemp. style. Height = "1px ";
Ifmtemp. style. Position = "absolute ";
Ifmtemp. style. Border = "NONE ";
Ifmtemp. style. Left = "-pixel PX ";
Ifmtemp. src = "iframeblkpage.html ";
Document. Body. appendchild (ifmtemp );
Ifmtemp.content1_doc ument. designMode = "on ";
Ifmtemp.content+doc ument. open ();
Ifmtemp.contentdomaindoc ument. Write ("<body> </body> ");
Ifmtemp.content+doc ument. Close ();
} Else
{
Ifmtemp.contentcontactdoc ument. Body. innerhtml = "";
}
Origintext?objeditor.content=doc ument. Body. innertext;
Ifmtemp. contentWindow. Focus ();
Ifmtemp.content1_document.exe ccommand ("Paste", false, null );
Objeditor. contentWindow. Focus ();
Newdata‑ifmtemp.content+doc ument. Body. innerhtml;
// Filter the pasted data
Newdata = filterpastedata (newdata );
Ifmtemp.contentcontactdoc ument. Body. innerhtml = newdata;
// Paste the data into the editor
Orrange. pastehtml (newdata );
// Block default Paste
If (E)
{
E. returnvalue = false;
If (E. preventdefault)
E. preventdefault ();
}
Return false;
} Else
{
Enablekeydown = false;
// Create the temporary HTML editor
VaR divtemp = eddoc. createelement ("Div ");
Divtemp. ID = 'htmleditor _ tempdiv ';
Divtemp. innerhtml = '\ ufeff ';
Divtemp. style. Left = "-pixel PX"; // hide the DIV
Divtemp. style. Height = "1px ";
Divtemp. style. width = "1px ";
Divtemp. style. Position = "absolute ";
Divtemp. style. Overflow = "hidden ";
Eddoc. Body. appendchild (divtemp );
// Disable keyup, keypress, mousedown and keydown
Objeditor.content+doc ument. addeventlistener ("mousedown", block, false );
Objeditor.content+doc ument. addeventlistener ("keydown", block, false );
Enablekeydown = false;
// Get current selection;
W = objeditor. contentWindow;
OR = getsel (W). getrangeat (0 );
// Move the cursor to into the DIV
VaR docbody = divtemp. firstchild;
RNG = eddoc. createRange ();
RNG. setstart (docbody, 0 );
RNG. setend (docbody, 1 );
Setrange (getsel (W), RNG );
Origintext?objeditor.content=doc ument. Body. textcontent;
If (origintext = '\ ufeff ')
{
Origintext = "";
}
Window. setTimeout (function ()
{
// Get and filter the data after onpaste is done
If (divtemp. innerhtml ===' \ ufeff ')
{
Newdata = "";
Eddoc. Body. removechild (divtemp );
Return;
}
Newdata = divtemp. innerhtml;
// Restore the old Selection
If (OR)
{
Setrange (getsel (W), or );
}
Newdata = filterpastedata (newdata );
Divtemp. innerhtml = newdata;
// Paste the new data to the editor
Objeditor.content1_document.exe ccommand ('insertml', false, newdata );
Eddoc. Body. removechild (divtemp );
}, 0 );
// Enable keydown, keyup, keypress, and mousedown;
Enablekeydown = true;
Objeditor.content+doc ument. removeeventlistener ("mousedown", block, false );
Objeditor.content+doc ument. removeeventlistener ("keydown", block, false );
Return true;
}
}

Here, pasteclipboarddata is used as the onpaste callback function. to use it, you can use the following code to add it to the onpaste event of IFRAME in the HTML editor.Copy codeThe Code is as follows: var ifrm = Document. getelementbyid ("Editor ")
If (isie)
{
Ifrm.content1_document.doc umentelement. attachevent ("onpaste", function (e) {return past1_boarddata (ifrm. ID, e );});
}
Else
{
Ifrm.content1_doc ument. addeventlistener ("Paste", function (e) {return past1_boarddata (ifrm. ID, e) ;}, false );
}

Here, the filterpastedata function is the function we specifically use for filtering. How to filter plain text, HTML, and word data will be explained in the next article.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.