1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/trace", 5 "firebug/lib/string" 6 ], 7 function(FBTrace, Str) { 8 9 // ********************************************************************************************* // 10 // Constants 11 12 var Ci = Components.interfaces; 13 var Cc = Components.classes; 14 var Cu = Components.utils; 15 16 var Xml = {}; 17 18 // ************************************************************************************************ 19 // HTML and XML Serialization 20 21 var getElementType = Xml.getElementType = function(node) 22 { 23 if (isElementXUL(node)) 24 return 'xul'; 25 else if (isElementSVG(node)) 26 return 'svg'; 27 else if (isElementMathML(node)) 28 return 'mathml'; 29 else if (isElementXHTML(node)) 30 return 'xhtml'; 31 else if (isElementHTML(node)) 32 return 'html'; 33 } 34 35 var getElementSimpleType = Xml.getElementSimpleType = function(node) 36 { 37 if (isElementSVG(node)) 38 return 'svg'; 39 else if (isElementMathML(node)) 40 return 'mathml'; 41 else 42 return 'html'; 43 } 44 45 var isElementHTML = Xml.isElementHTML = function(node) 46 { 47 return node.nodeName == node.nodeName.toUpperCase() && node.namespaceURI == 'http://www.w3.org/1999/xhtml'; 48 } 49 50 var isElementXHTML = Xml.isElementXHTML = function(node) 51 { 52 return node.nodeName != node.nodeName.toUpperCase() && node.namespaceURI == 'http://www.w3.org/1999/xhtml'; 53 } 54 55 var isElementMathML = Xml.isElementMathML = function(node) 56 { 57 return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; 58 } 59 60 var isElementSVG = Xml.isElementSVG = function(node) 61 { 62 return node.namespaceURI == 'http://www.w3.org/2000/svg'; 63 } 64 65 var isElementXUL = Xml.isElementXUL = function(node) 66 { 67 return node instanceof XULElement; 68 } 69 70 var getNodeName = Xml.getNodeName = function(node) 71 { 72 var name = node.nodeName; 73 return isElementHTML(node) ? name.toLowerCase() : name; 74 } 75 76 var getLocalName = Xml.getLocalName = function(node) 77 { 78 var name = node.localName; 79 return isElementHTML(node) ? name.toLowerCase() : name; 80 } 81 82 // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML 83 Xml.selfClosingTags = 84 { 85 "meta": 1, 86 "link": 1, 87 "area": 1, 88 "base": 1, 89 "col": 1, 90 "input": 1, 91 "img": 1, 92 "br": 1, 93 "hr": 1, 94 "param":1, 95 "embed":1 96 }; 97 98 Xml.isSelfClosing = function(element) 99 { 100 if (isElementSVG(element) || isElementMathML(element)) 101 return true; 102 var tag = element.localName.toLowerCase(); 103 return (Xml.selfClosingTags.hasOwnProperty(tag)); 104 }; 105 106 // xxxFlorent: could be replaced with outerHTML... if only Firebug.shouldIgnore was not called 107 Xml.getElementHTML = function(element) 108 { 109 function toHTML(elt) 110 { 111 if (elt.nodeType == Node.ELEMENT_NODE) 112 { 113 if (Firebug.shouldIgnore(elt)) 114 return; 115 116 var nodeName = getNodeName(elt); 117 html.push('<', nodeName); 118 119 for (var i = 0; i < elt.attributes.length; ++i) 120 { 121 var attr = elt.attributes[i]; 122 123 // Hide attributes set by Firebug 124 // XXX Do we even have any? 125 if (Str.hasPrefix(attr.localName, "firebug-")) 126 continue; 127 128 // MathML 129 if (Str.hasPrefix(attr.localName, "-moz-math")) 130 { 131 // just hide for now 132 continue; 133 } 134 135 html.push(' ', attr.name, '="', Str.escapeForElementAttribute(attr.value), '"'); 136 } 137 138 if (elt.firstChild) 139 { 140 html.push('>'); 141 142 for (var child = elt.firstChild; child; child = child.nextSibling) 143 toHTML(child); 144 145 html.push('</', nodeName, '>'); 146 } 147 else if (isElementSVG(elt) || isElementMathML(elt)) 148 { 149 html.push('/>'); 150 } 151 else if (Xml.isSelfClosing(elt)) 152 { 153 html.push((isElementXHTML(elt))?'/>':'>'); 154 } 155 else 156 { 157 html.push('></', nodeName, '>'); 158 } 159 } 160 else if (elt.nodeType == Node.TEXT_NODE) 161 html.push(Str.escapeForTextNode(elt.textContent)); 162 else if (elt.nodeType == Node.CDATA_SECTION_NODE) 163 html.push('<![CDATA[', elt.nodeValue, ']]>'); 164 else if (elt.nodeType == Node.COMMENT_NODE) 165 html.push('<!--', elt.nodeValue, '-->'); 166 } 167 168 var html = []; 169 toHTML(element); 170 return html.join(""); 171 }; 172 173 Xml.getElementXML = function(element) 174 { 175 function toXML(elt) 176 { 177 if (elt.nodeType == Node.ELEMENT_NODE) 178 { 179 if (Firebug.shouldIgnore(elt)) 180 return; 181 182 var nodeName = getNodeName(elt); 183 xml.push('<', nodeName); 184 185 for (var i = 0; i < elt.attributes.length; ++i) 186 { 187 var attr = elt.attributes[i]; 188 189 // Hide attributes set by Firebug 190 if (Str.hasPrefix(attr.localName, "firebug-")) 191 continue; 192 193 // MathML 194 if (Str.hasPrefix(attr.localName, "-moz-math")) 195 { 196 // just hide for now 197 continue; 198 } 199 200 xml.push(' ', attr.nodeName, '="', Str.escapeForElementAttribute(attr.nodeValue),'"'); 201 } 202 203 if (elt.firstChild) 204 { 205 xml.push('>'); 206 207 for (var child = elt.firstChild; child; child = child.nextSibling) 208 toXML(child); 209 210 xml.push('</', nodeName, '>'); 211 } 212 else 213 xml.push('/>'); 214 } 215 else if (elt.nodeType == Node.TEXT_NODE) 216 xml.push(elt.nodeValue); 217 else if (elt.nodeType == Node.CDATA_SECTION_NODE) 218 xml.push('<![CDATA[', elt.nodeValue, ']]>'); 219 else if (elt.nodeType == Node.COMMENT_NODE) 220 xml.push('<!--', elt.nodeValue, '-->'); 221 } 222 223 var xml = []; 224 toXML(element); 225 return xml.join(""); 226 }; 227 228 // ************************************************************************************************ 229 // Whitespace and Entity conversions 230 231 var domUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils); 232 233 /** 234 * Returns true if given document is based on a XML and so displaying pretty printed XML elements. 235 */ 236 Xml.isXMLPrettyPrint = function(context, win) 237 { 238 if (!context) 239 return; 240 241 if (context.isXMLPrettyPrintDetected) 242 return context.isXMLPrettyPrint; 243 244 try 245 { 246 var doc = win ? win.document : context.window.document; 247 if (!doc) 248 { 249 if (FBTrace.DBG_ERRORS) 250 FBTrace.sysout("lib.isXMLPrettyPrint; NO DOCUMENT", {win:win, context:context}); 251 return false; 252 } 253 if (!doc.documentElement) 254 return false; 255 256 var bindings = domUtils.getBindingURLs(doc.documentElement); 257 for (var i = 0; i < bindings.length; i++) 258 { 259 var bindingURI = bindings.queryElementAt(i, Ci.nsIURI); 260 if (FBTrace.DBG_CSS) 261 FBTrace.sysout("bindingURL: " + i + " " + bindingURI.resolve("")); 262 263 context.isXMLPrettyPrintDetected = true; 264 return context.isXMLPrettyPrint = (bindingURI.resolve("") === 265 "chrome://global/content/xml/XMLPrettyPrint.xml"); 266 } 267 } 268 catch (e) 269 { 270 if (FBTrace.DBG_ERRORS) 271 FBTrace.sysout("xml.isXMLPrettyPrint; EXCEPTION "+e, e); 272 } 273 }; 274 275 // ************************************************************************************************ 276 277 Xml.isVisible = function(elt) 278 { 279 if (Xml.isElementXUL(elt)) 280 { 281 //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ 282 // elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); 283 return (!elt.hidden && !elt.collapsed); 284 } 285 286 try 287 { 288 return (!Xml.isElementHTML(elt) && !Xml.isElementXHTML(elt)) || 289 elt.offsetWidth > 0 || 290 elt.offsetHeight > 0 || 291 elt.localName in Xml.invisibleTags; 292 } 293 catch (err) 294 { 295 if (FBTrace.DBG_ERRORS) 296 FBTrace.sysout("lib.isVisible; EXCEPTION " + err, err); 297 } 298 299 return false; 300 }; 301 302 var invisibleTags = Xml.invisibleTags = 303 { 304 "HTML": 1, 305 "HEAD": 1, 306 "TITLE": 1, 307 "META": 1, 308 "LINK": 1, 309 "STYLE": 1, 310 "SCRIPT": 1, 311 "NOSCRIPT": 1, 312 "BR": 1, 313 "PARAM": 1, 314 "COL": 1, 315 316 "html": 1, 317 "head": 1, 318 "title": 1, 319 "meta": 1, 320 "link": 1, 321 "style": 1, 322 "script": 1, 323 "noscript": 1, 324 "br": 1, 325 "param": 1, 326 "col": 1, 327 /* 328 "window": 1, 329 "browser": 1, 330 "frame": 1, 331 "tabbrowser": 1, 332 "WINDOW": 1, 333 "BROWSER": 1, 334 "FRAME": 1, 335 "TABBROWSER": 1, 336 */ 337 }; 338 339 // ********************************************************************************************* // 340 341 return Xml; 342 343 // ********************************************************************************************* // 344 }); 345