define("dijit/_editor/html", [ "dojo/_base/array", "dojo/_base/lang", // lang.setObject "dojo/sniff" // has("ie") ], function(array, lang, has){ // module: // dijit/_editor/html // summary: // HTML serialization utility functions used by editor var exports = {}; lang.setObject("dijit._editor.html", exports); var escape = exports.escapeXml = function(/*String*/ str, /*Boolean?*/ noSingleQuotes){ // summary: // Adds escape sequences for special characters in XML: `&<>"'`. // Optionally skips escapes for single quotes. str = str.replace(/&/gm, "&").replace(//gm, ">").replace(/"/gm, """); if(!noSingleQuotes){ str = str.replace(/'/gm, "'"); } return str; // string }; exports.getNodeHtml = function(/*DomNode*/ node){ // summary: // Return string representing HTML for node and it's children var output = []; exports.getNodeHtmlHelper(node, output); return output.join(""); }; exports.getNodeHtmlHelper = function(/*DomNode*/ node, /*String[]*/ output){ // summary: // Pushes array of strings into output[] which represent HTML for node and it's children switch(node.nodeType){ case 1: // element node var lName = node.nodeName.toLowerCase(); if(!lName || lName.charAt(0) == "/"){ // IE does some strange things with malformed HTML input, like // treating a close tag without an open tag , as // a new tag with tagName of /span. Corrupts output HTML, remove // them. Other browsers don't prefix tags that way, so will // never show up. return ""; } output.push('<', lName); // store the list of attributes and sort it to have the // attributes appear in the dictionary order var attrarray = [], attrhash = {}; var attr; if(has("dom-attributes-explicit") || has("dom-attributes-specified-flag")){ // IE8+ and all other browsers. var i = 0; while((attr = node.attributes[i++])){ // ignore all attributes starting with _dj which are // internal temporary attributes used by the editor var n = attr.name; if(n.substr(0,3) !== '_dj' && (!has("dom-attributes-specified-flag") || attr.specified) && !(n in attrhash)){ // workaround repeated attributes bug in IE8 (LinkDialog test) var v = attr.value; if(n == 'src' || n == 'href'){ if(node.getAttribute('_djrealurl')){ v = node.getAttribute('_djrealurl'); } } if(has("ie") === 8 && n === "style"){ v = v.replace("HEIGHT:", "height:").replace("WIDTH:", "width:"); } attrarray.push([n,v]); attrhash[n] = v; } } }else{ // IE6-7 code path var clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false); var s = clone.outerHTML; // Split up and manage the attrs via regexp // similar to prettyPrint attr logic. var rgxp_attrsMatch = /[\w-]+=("[^"]*"|'[^']*'|\S*)/gi var attrSplit = s.match(rgxp_attrsMatch); s = s.substr(0, s.indexOf('>')); array.forEach(attrSplit, function(attr){ if(attr){ var idx = attr.indexOf("="); if(idx > 0){ var key = attr.substring(0,idx); if(key.substr(0,3) != '_dj'){ if(key == 'src' || key == 'href'){ if(node.getAttribute('_djrealurl')){ attrarray.push([key,node.getAttribute('_djrealurl')]); return; } } var val, match; switch(key){ case 'style': val = node.style.cssText.toLowerCase(); break; case 'class': val = node.className; break; case 'width': if(lName === "img"){ // This somehow gets lost on IE for IMG tags and the like // and we have to find it in outerHTML, known IE oddity. match=/width=(\S+)/i.exec(s); if(match){ val = match[1]; } break; } case 'height': if(lName === "img"){ // This somehow gets lost on IE for IMG tags and the like // and we have to find it in outerHTML, known IE oddity. match=/height=(\S+)/i.exec(s); if(match){ val = match[1]; } break; } default: val = node.getAttribute(key); } if(val != null){ attrarray.push([key, val.toString()]); } } } } }, this); } attrarray.sort(function(a,b){ return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1); }); var j = 0; while((attr = attrarray[j++])){ output.push(' ', attr[0], '="', (typeof attr[1] === "string" ? escape(attr[1], true) : attr[1]), '"'); } switch(lName){ case 'br': case 'hr': case 'img': case 'input': case 'base': case 'meta': case 'area': case 'basefont': // These should all be singly closed output.push(' />'); break; case 'script': // Browsers handle script tags differently in how you get content, // but innerHTML always seems to work, so insert its content that way // Yes, it's bad to allow script tags in the editor code, but some people // seem to want to do it, so we need to at least return them right. // other plugins/filters can strip them. output.push('>', node.innerHTML, ''); break; default: output.push('>'); if(node.hasChildNodes()){ exports.getChildrenHtmlHelper(node, output); } output.push(''); } break; case 4: // cdata case 3: // text // FIXME: output.push(escape(node.nodeValue, true)); break; case 8: // comment // FIXME: output.push(''); break; default: output.push(""); } }; exports.getChildrenHtml = function(/*DomNode*/ node){ // summary: // Returns the html content of a DomNode's children var output = []; exports.getChildrenHtmlHelper(node, output); return output.join(""); }; exports.getChildrenHtmlHelper = function(/*DomNode*/ dom, /*String[]*/ output){ // summary: // Pushes the html content of a DomNode's children into out[] if(!dom){ return; } var nodes = dom["childNodes"] || dom; // IE issue. // If we have an actual node we can check parent relationships on for IE, // We should check, as IE sometimes builds invalid DOMS. If no parent, we can't check // And should just process it and hope for the best. var checkParent = !has("ie") || nodes !== dom; var node, i = 0; while((node = nodes[i++])){ // IE is broken. DOMs are supposed to be a tree. But in the case of malformed HTML, IE generates a graph // meaning one node ends up with multiple references (multiple parents). This is totally wrong and invalid, but // such is what it is. We have to keep track and check for this because otherwise the source output HTML will have dups. // No other browser generates a graph. Leave it to IE to break a fundamental DOM rule. So, we check the parent if we can // If we can't, nothing more we can do other than walk it. if(!checkParent || node.parentNode == dom){ exports.getNodeHtmlHelper(node, output); } } }; return exports; });