Firefox outerHTML implementation code

Source: Internet
Author: User

Reducing the number of DOM can accelerate the construction of DOM Tree and render tree during page parsing by the browser, thus improving the page performance. For this reason, we can save the HTML that is invisible to the first screen rendering in TextArea, and then process the HTML after rendering. To add the temporary HTML content in TextArea to the page, it is easiest and convenient to use the element's outerHTML attribute. However, the DOM standard does not define outerHTML, supported browsers include IE6 +, safari, operal and Chrome, which are not supported yet after FF4.0-test. So we can implement a cross-browser outerHTML.
OuterHTML is the html used to obtain or set tags containing elements. The following is the implementation code:
Copy codeThe Code is as follows:
If (typeof HTMLElement! = "Undefined "&&! ("OuterHTML" in HTMLElement. prototype )){
// Console. log ("defined outerHTML ");
HTMLElement. prototype. _ defineSetter _ ("outerHTML", function (str ){
Var fragment = document. createDocumentFragment ();
Var div = document. createElement ("div ");
Div. innerHTML = str;
For (var I = 0, n = div. childNodes. length; I <n; I ++ ){
Fragment. appendChild (div. childNodes [I]);
}
This. parentNode. replaceChild (fragment, this );
});
//
HTMLElement. prototype. _ defineGetter _ ("outerHTML", function (){
Var tag = this. tagName;
Var attributes = this. attributes;
Var attr = [];
// For (var name in attributes) {// traverse the members in the prototype chain
For (var I = 0, n = attributes. length; I <n; I ++) {// n specifies the number of attributes
If (attributes [I]. specified ){
Attr. push (attributes [I]. name + '= "' + attributes [I]. value + '"');
}
}
Return ((!! This. innerHTML )?
'<' + Tag + ''+ attr. join ('') + '>' + this. innerHTML + '</' + tag + '> ':
'<' + Tag + ''+ attr. join ('') + '/> ');
});
}

Code Description:
1. Check whether the browser supports outerHTML to avoid overwriting the native Implementation of the browser.
2 "_ defineSetter _", "_ defineGetter _" is the private aspect of the firefox browser. Define the operations to be performed when setting property values and obtaining properties respectively.
3. In "_ defineSetter _" "outerHTML", to avoid frequent reflow caused by too many elements inserted into the page, performance is affected. The fragment object of the document fragment is used to temporarily store DOM elements that need to be inserted into the page.
4. Use the element attributes attribute in "_ defineGetter _" "outerHTML" to traverse the attribute specified for the element. In combination with innerHTML, an html string containing the original owner is returned.
Test code:
Copy codeThe Code is as follows:
<! DOCTYPE html>
<Html>
<Head>
<Meta charset = "UTF-8"/>
<Title> outerHTML </title>
</Head>
<Body>
<Div id = "content" class = "test">
<P> This is <strong> paragraph </strong> with a list following it </p>
<Ul>
<Li> Item 1 </li>
<Li> Item 2 </li>
<Li> Item 3 </li>
<Li> Item 4 </li>
</Ul>
</Div>
<Script>
If (typeof HTMLElement! = "Undefined "&&! ("OuterHTML" in HTMLElement. prototype )){
Console. log ("defined outerHTML ");
HTMLElement. prototype. _ defineSetter _ ("outerHTML", function (str ){
Var fragment = document. createDocumentFragment ();
Var div = document. createElement ("div ");
Div. innerHTML = str;
For (var I = 0, n = div. childNodes. length; I <n; I ++ ){
Fragment. appendChild (div. childNodes [I]);
}
This. parentNode. replaceChild (fragment, this );
});
//
HTMLElement. prototype. _ defineGetter _ ("outerHTML", function (){
Var tag = this. tagName;
Var attributes = this. attributes;
Var attr = [];
// For (var name in attributes) {// traverse the members in the prototype chain
For (var I = 0, n = attributes. length; I <n; I ++) {// n specifies the number of attributes
If (attributes [I]. specified ){
Attr. push (attributes [I]. name + '= "' + attributes [I]. value + '"');
}
}
Return ((!! This. innerHTML )?
'<' + Tag + ''+ attr. join ('') + '>' + this. innerHTML + '</' + tag + '> ':
'<' + Tag + ''+ attr. join ('') + '/> ');
});
}
Var content = document. getElementById ("content ");
Alert (content. outerHTML)
</Script>
</Body>
</Html>

Assume that you want to obtain the outerHTML of p of <p id = "outerID"> sdfdsdfsd </P>
Code:
Copy codeThe Code is as follows:
Var _ p = document. getElementById ('outerid ');
_ P = _ P. cloneNode ();
Var _ DIV = document. createElement ();
_ DIV. appendChild (_ P );
Alert (_ DIV. innerHTML); is P's outerHTML;

Firefox does not have outerHTML. Use the following methods to solve this problem:
Copy codeThe Code is as follows:
/**
* After firefox-compatible outerHTML uses the following code, firefox can use element. outerHTML
**/
If (window. HTMLElement ){
HTMLElement. prototype. _ defineSetter _ ("outerHTML", function (sHTML ){
Var r = this. ownerDocument. createRange ();
R. setStartBefore (this );
Var df = r. createContextualFragment (sHTML );
This. parentNode. replaceChild (df, this );
Return sHTML;
});
HTMLElement. prototype. _ defineGetter _ ("outerHTML", function (){
Var attr;
Var attrs = this. attributes;
Var str = "<" + this. tagName. toLowerCase ();
For (var I = 0; I <attrs. length; I ++ ){
Attr = attrs [I];
If (attr. specified)
Str + = "" + attr. name + '= "' + attr. value + '"';
}
If (! This. canHaveChildren)
Return str + "> ";
Return str + ">" + this. innerHTML + "</" + this. tagName. toLowerCase () + "> ";
});
HTMLElement. prototype. _ defineGetter _ ("canHaveChildren", function (){
Switch (this. tagName. toLowerCase ()){
Case "area ":
Case "base ":
Case "basefont ":
Case "col ":
Case "frame ":
Case "hr ":
Case "img ":
Case "br ":
Case "input ":
Case "isindex ":
Case "link ":
Case "meta ":
Case "param ":
Return false;
}
Return true;
});
}

Valid test.
New solutions for insertAdjacentHTML compatibility
Copy codeThe Code is as follows:
// --- Insert html code at the end of the component
Function InsertHtm (op, code, isStart ){
If (Dvbbs_IsIE5)
Op. insertAdjacentHTML (isStart? "Afterbegin": "afterEnd", code );
Else {
Var range = op. ownerDocument. createRange ();
Range. setStartBefore (op );
Var fragment = range. createContextualFragment (code );
If (isStart)
Op. insertBefore (fragment, op. firstChild );
Else
Op. appendChild (fragment );
}
}

Reference for inner/outerHTML in NC6
DOM level 1 has no methods to allow for insertion of unparsed HTML into the document tree (as IE allows with insertAdjacentHTML or assignment to inner/outerHTML ). NN6 (currently in beta as NN6PR3) know supports. innerHTMLproperty of HTMLElements so that you can read or write the innerHTML of a page element like in IE4 +. NN6 also provides a DOM level 2 compliant Range object to which a createConte XtualFragment ('html source string') was added to spare DOM scripters the task of parsing html and creating DOM elements. you create a Range with var range = document. createRange (); Then you shoshould set its start point to the element where you want to insert the html for instance var someElement = document. getElementById ('elementid'); range. setStartAfter (someElement); Then you create a document fragment From the html source to insert for example var docFrag = range. createContextualFragment ('<P> Kibology for all. </P> '); and insert it with DOM methods someElement. appendChild (docFrag); The Netscape JavaScript 1.5 version even provides so called setters for properties which together with the ability to prototype the DOM elements allows to emulate setting of outerHMTL for NN6: <script language = "JavaScrip T1.5 "> if (navigator. appName = 'netscape ') {HTMLElement. prototype. outerHTML setter = function (html) {this. outerHTMLInput = html; var range = this. ownerDocument. createRange (); range. setStartBefore (this); var docFrag = range. createContextualFragment (html); this. parentNode. replaceChild (docFrag, this) ;}</SCRIPT> If you insert that script block you can then write cross browser code assigning. I NnerHTML. outerHTMLfor instance document. body. innerHTML = '<P> Scriptology for all </P>'; which works with both IE4/5 and NN6.The following provides getter functions. outerHTMLto allow to read those properties in NN6 in a IE4/5 compatible way. note that while the scheme of traversing the document tree shocould point you in the right direction the code example might not satisfy your needs as there Re subtle difficulties when trying to reproduce the html source from the document tree. see for yourself whether you like the result and improve it as needed to cover other exceptions than those handled (for the empty elements and the textarea element ). <HTML> <HEAD> <STYLE> </STYLE> <script language = "JavaScript1.5"> var emptyElements = {HR: true, BR: true, IMG: true, INPUT: true}; var specialElements = {TEXTAREA: true}; HTMLElement. prototype. outerHTML getter = function () {return getOuterHTML (this);} function getOuterHTML (node) {var html = ''; switch (node. nodeType) {case Node. ELEMENT_NODE: html + = '<'; html + = node. nodeName; if (! SpecialElements [node. nodeName]) {for (var a = 0; a <node. attributes. length; a ++) html + = ''+ node. attributes [a]. nodeName. toUpperCase () + '= "' + node. attributes [a]. nodeValue + '"'; html + = '>'; if (! EmptyElements [node. nodeName]) {html + = node. innerHTML; html + = '<\/' + node. nodeName + '>';} else switch (node. nodeName) {case 'textarea ': for (var a = 0; a <node. attributes. length; a ++) if (node. attributes [a]. nodeName. toLowerCase ()! = 'Value') html + = ''+ node. attributes [a]. nodeName. toUpperCase () + '= "' + node. attributes [a]. nodeValue + '"'; else var content = node. attributes [a]. nodeValue; html + = '>'; html + = content; html + = '<\/' + node. nodeName + '>'; break;} break; case Node. TEXT_NODE: html + = node. nodeValue; break; case Node. COMMENT_NODE: html + = '<! '+' -- '+ Node. nodeValue + '--' + '>'; break;} return html ;}</SCRIPT> </HEAD> <BODY> <a href = "javascript: alert(document.doc umentElement. outerHTML); void 0 "> show document.doc umentElement. outerHTML </A> | <a href = "javascript: alert (document. body. outerHTML); void 0 "> show document. body. outerHTML </A> | <a href = "javascript: alert(document.doc umentElement. innerHTML); void 0 "> show document.doc umentElement. innerHTML </A> | <a href = "javascript: alert (document. body. innerHTML); void 0 "> show document. body. innerHTML </A> <form name = "formName"> <textarea name = "aTextArea" ROWS = "5" COLS = "20"> JavaScript. FAQTs. comKibology for all. </TEXTAREA> </FORM> <DIV> <P> JavaScript.FAQTs.com </P> <BLOCKQUOTE> Kibology for all. <BR> All for Kibology. </BLOCKQUOTE> </DIV> </BODY> </HTML> Note that the getter/setter feature is experimental and its syntax is subject to change.
HTMLElement. prototype. innerHTML setter = function (str) {var r = this. ownerDocument. createRange (); r. selectNodeContents (this); r. deleteContents (); var df = r. createContextualFragment (str); this. appendChild (df); return str;} HTMLElement. prototype. outerHTML setter = function (str) {var r = this. ownerDocument. createRange (); r. setStartBefore (this); var df = r. createContextualFragment (str); this. parentNode. replaceChild (df, this); return str ;}
HTMLElement. prototype. innerHTML getter = function () {return getInnerHTML (this );}
Function getInnerHTML (node) {var str = ""; for (var I = 0; I <node. childNodes. length; I ++) str + = getOuterHTML (node. childNodes. item (I); return str ;}
HTMLElement. prototype. outerHTML getter = function () {return getOuterHTML (this )}
Function getOuterHTML (node) {var str = ""; switch (node. nodeType) {case 1: // ELEMENT_NODE str + = "<" + node. nodeName; for (var I = 0; I <node. attributes. length; I ++) {if (node. attributes. item (I ). nodeValue! = Null) {str + = "" str + = node. attributes. item (I ). nodeName; str + = "= \" "; str + = node. attributes. item (I ). nodeValue; str + = "\"";}}
If (node. childNodes. length = 0 & leafElems [node. nodeName]) str + = ">"; else {str + = ">"; str + = getInnerHTML (node); str + = "<" + node. nodeName + ">"} break; case 3: // TEXT_NODE str + = node. nodeValue; break; case 4: // CDATA_SECTION_NODE str ++ = "<! [CDATA ["+ node. nodeValue +"]> "; break; case 5: // ENTITY_REFERENCE_NODE str + =" & "+ node. nodeName +"; "break;
Case 8: // COMMENT_NODE str + = "<! -- "+ Node. nodeValue +" --> "break ;}
Return str ;}
Var _ leafElems = ["IMG", "HR", "BR", "INPUT"]; var leafElems ={}; for (var I = 0; I <_ leafElems. length; I ++) leafElems [_ leafElems [I] = true;
Then we can block it as JS reference.
If (/Mozilla \/5 \. 0 /. test (navigator. userAgent) document. write ('<script type = "text/javascript" src = "mozInnerHTML. js "> </SC '+ 'ript> ');
Copy codeThe Code is as follows:
<Script language = "JavaScript" type = "Text/JavaScript">
<! --
Var emptyElements = {HR: true, BR: true, IMG: true, INPUT: true}; var specialElements = {TEXTAREA: true };
HTMLElement. prototype. outerHTML getter = function (){
Return getOuterHTML (this );
}
Function getOuterHTML (node ){
Var html = '';
Switch (node. nodeType ){
Case Node. ELEMENT_NODE: html + = '<'; html + = node. nodeName; if (! SpecialElements [node. nodeName]) {
For (var a = 0; a <node. attributes. length; a ++)
Html + = ''+ node. attributes [a]. nodeName. toUpperCase () + '="' + node. attributes [a]. nodeValue + '"';
Html + = '> ';
If (! EmptyElements [node. nodeName]) {
Html + = node. innerHTML;
Html + = '<\/' + node. nodeName + '> ';
}
} Else
Switch (node. nodeName ){
Case 'textarea ': for (var a = 0; a <node. attributes. length; a ++)
If (node. attributes [a]. nodeName. toLowerCase ()! = 'Value ')
Html
+ = ''+ Node. attributes [a]. nodeName. toUpperCase () + '="' + node. attributes [a]. nodeValue
+ '"';
Else
Var content = node. attributes [a]. nodeValue;
Html + = '>'; html + = content; html + = '<\/' + node. nodeName + '>'; break;
} Break;
Case Node. TEXT_NODE: html + = node. nodeValue; break;
Case Node. COMMENT_NODE: html + = '<! '+' -- '+ Node. nodeValue +' -- '+'> '; break;
}
Return html;
}
// -->
</Script>

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.