123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- define("dijit/_editor/html", [
- "dojo/_base/array",
- "dojo/_base/lang", // lang.getObject
- "dojo/_base/sniff", // has("ie")
- ".." // for exporting symbols to dijit._editor (remove for 2.0)
- ], function(array, lang, has, dijit){
- // module:
- // dijit/_editor/html
- // summary:
- // Utility functions used by editor
- // Tests for DOMNode.attributes[] behavior:
- // - dom-attributes-explicit - attributes[] only lists explicitly user specified attributes
- // - dom-attributes-specified-flag (IE8) - need to check attr.specified flag to skip attributes user didn't specify
- // - Otherwise, in IE6-7. attributes[] will list hundreds of values, so need to do outerHTML to get attrs instead.
- var form = document.createElement("form");
- has.add("dom-attributes-explicit", form.attributes.length == 0); // W3C
- has.add("dom-attributes-specified-flag", form.attributes.length > 0 && form.attributes.length < 40); // IE8
- lang.getObject("_editor", true, dijit);
- dijit._editor.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, ">").replace(/"/gm, """);
- if(!noSingleQuotes){
- str = str.replace(/'/gm, "'");
- }
- return str; // string
- };
- dijit._editor.getNodeHtml=function(/* DomNode */node){
- var output;
- 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 </span> without an open tag <span>, 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 = '<' + 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 += ' ' + attr[0] + '="' +
- (lang.isString(attr[1]) ? dijit._editor.escapeXml(attr[1], true) : attr[1]) + '"';
- }
- if(lName === "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 += '>' + node.innerHTML +'</' + lName + '>';
- }else{
- if(node.childNodes.length){
- output += '>' + dijit._editor.getChildrenHtml(node)+'</' + lName +'>';
- }else{
- 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 += ' />';
- break;
- default:
- // Assume XML style separate closure for everything else.
- output += '></' + lName + '>';
- }
- }
- }
- break;
- case 4: // cdata
- case 3: // text
- // FIXME:
- output = dijit._editor.escapeXml(node.nodeValue, true);
- break;
- case 8: //comment
- // FIXME:
- output = '<!--' + dijit._editor.escapeXml(node.nodeValue, true) + '-->';
- break;
- default:
- output = "<!-- Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName + "-->";
- }
- return output;
- };
- dijit._editor.getChildrenHtml = function(/* DomNode */dom){
- // summary:
- // Returns the html content of a DomNode and children
- var out = "";
- if(!dom){ return out; }
- 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 otherise 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){
- out += dijit._editor.getNodeHtml(node);
- }
- }
- return out; // String
- };
- return dijit._editor;
- });
|