dojox/editor/plugins/NormalizeStyle.js

  • Provides:

    • dojox.editor.plugins.NormalizeStyle
  • dojox.editor.plugins.NormalizeStyle

    • type
      Function
    • chains:
      • dijit._editor._Plugin: (prototype)
      • dijit._editor._Plugin: (call)
    • summary
  • dojox.editor.plugins.NormalizeStyle.mode

    • summary
  • dojox.editor.plugins.NormalizeStyle.condenseSpans

    • summary
  • dojox.editor.plugins.NormalizeStyle.setEditor

    • type
      Function
    • parameters:
      • editor: (typeof Object)
        The editor to configure for this plugin to use.
    • source: [view]
        this.editor = editor;
        editor.customUndo = true;


        if(this.mode === "semantic"){
         this.editor.contentDomPostFilters.push(dojo.hitch(this, this._convertToSemantic));
        }else if(this.mode === "css"){
         this.editor.contentDomPostFilters.push(dojo.hitch(this, this._convertToCss));
        }


        // Pre DOM filters are usually based on what browser, as they all use different ways to
        // apply styles with actions and modify them.
        if(dojo.isIE){
         // IE still uses semantic tags most of the time, so convert to that.
         this.editor.contentDomPreFilters.push(dojo.hitch(this, this._convertToSemantic));
         this._browserFilter = this._convertToSemantic;
        }else if(dojo.isWebKit){
         this.editor.contentDomPreFilters.push(dojo.hitch(this, this._convertToCss));
         this._browserFilter = this._convertToCss;
        }else if(dojo.isMoz){
         //Editor currently forces Moz into semantic mode, so we need to match. Ideally
         //editor could get rid of that and just use CSS mode, which would work cleaner
         //That's why this is split out, to make it easy to change later.
         this.editor.contentDomPreFilters.push(dojo.hitch(this, this._convertToSemantic));
         this._browserFilter = this._convertToSemantic;
        }else{
         this.editor.contentDomPreFilters.push(dojo.hitch(this, this._convertToSemantic));
         this._browserFilter = this._convertToSemantic;
        }


        // Set up the inserthtml impl over-ride. This catches semi-paste events and
        // tries to normalize them too.
        if(this.editor._inserthtmlImpl){
         this.editor._oldInsertHtmlImpl = this.editor._inserthtmlImpl;
        }
        this.editor._inserthtmlImpl = dojo.hitch(this, this._inserthtmlImpl);
    • summary
      Over-ride for the setting of the editor.
  • dojox.editor.plugins.NormalizeStyle._convertToSemantic

    • type
      Function
    • parameters:
      • node: (typeof DOMNode)
        The node to process.
    • source: [view]
        if(node){
         var w = this.editor.window;
         var self = this;
         var convertNode = function(cNode){
          if(cNode.nodeType == 1){
           if(cNode.id !== "dijitEditorBody"){
            var style = cNode.style;
            var tag = cNode.tagName?cNode.tagName.toLowerCase():"";
            var sTag;
            if(style && tag != "table" && tag != "ul" && tag != "ol"){
             // Avoid wrapper blocks that have specific underlying structure, as injecting
             // spans/etc there is invalid.
             // Lets check and convert certain node/style types.
             var fw = style.fontWeight? style.fontWeight.toLowerCase() : "";
             var fs = style.fontStyle? style.fontStyle.toLowerCase() : "";
             var td = style.textDecoration? style.textDecoration.toLowerCase() : "";
             var s = style.fontSize?style.fontSize.toLowerCase() : "";
             var bc = style.backgroundColor?style.backgroundColor.toLowerCase() : "";
             var c = style.color?style.color.toLowerCase() : "";

       
             var wrapNodes = function(wrap, pNode){
              if(wrap){
               while(pNode.firstChild){
                wrap.appendChild(pNode.firstChild);
               }
               if(tag == "span" && !pNode.style.cssText){
                // A styler tag with nothing extra in it, so lets remove it.
                dojo.place(wrap, pNode, "before");
                pNode.parentNode.removeChild(pNode);
                pNode = wrap;
               }else{
                pNode.appendChild(wrap);
               }
              }
              return pNode;
             };
             switch(fw){
              case "bold":
              case "bolder":
              case "700":
              case "800":
              case "900":
               sTag = dojo.withGlobal(w, "create", dojo, ["b", {}] );
               cNode.style.fontWeight = "";
               break;
             }
             cNode = wrapNodes(sTag, cNode);
             sTag = null;
             if(fs == "italic"){
              sTag = dojo.withGlobal(w, "create", dojo, ["i", {}] );
              cNode.style.fontStyle = "";
             }
             cNode = wrapNodes(sTag, cNode);
             sTag = null;
             if(td){
              var da = td.split(" ");
              var count = 0;
              dojo.forEach(da, function(s){
               switch(s){
                case "underline":
                 sTag = dojo.withGlobal(w, "create", dojo, ["u", {}] );
                 break;
                case "line-through":
                 sTag = dojo.withGlobal(w, "create", dojo, ["strike", {}] );
                 break;
               }
               count++;
               if(count == da.length){
                // Last one, clear the decor and see if we can span strip on wrap.
                cNode.style.textDecoration = "";
               }
               cNode = wrapNodes(sTag, cNode);
               sTag = null;
              });

              
             }
             if(s){
              var sizeMap = {
               "xx-small": 1,
               "x-small": 2,
               "small": 3,
               "medium": 4,
               "large": 5,
               "x-large": 6,
               "xx-large": 7,
               "-webkit-xxx-large": 7
              };


              // Convert point or px size to size
              // to something roughly mappable.
              if(s.indexOf("pt") > 0){
               s = s.substring(0,s.indexOf("pt"));
               s = parseInt(s);
               if(s < 5){
                s = "xx-small";
               }else if(s < 10){
                s = "x-small";
               }else if(s < 15){
                s = "small";
               }else if(s < 20){
                s = "medium";
               }else if(s < 25){
                s = "large";
               }else if(s < 30){
                s = "x-large";
               }else if(s > 30){
                s = "xx-large";
               }
              }else if(s.indexOf("px") > 0){
               s = s.substring(0,s.indexOf("px"));
               s = parseInt(s);
               if(s < 5){
                s = "xx-small";
               }else if(s < 10){
                s = "x-small";
               }else if(s < 15){
                s = "small";
               }else if(s < 20){
                s = "medium";
               }else if(s < 25){
                s = "large";
               }else if(s < 30){
                s = "x-large";
               }else if(s > 30){
                s = "xx-large";
               }
              }
              var size = sizeMap[s];
              if(!size){
               size = 3;
              }
              sTag = dojo.withGlobal(w, "create", dojo, ["font", {size: size}] );
              cNode.style.fontSize = "";
             }
             cNode = wrapNodes(sTag, cNode);
             sTag = null;
             if(bc && tag !== "font" && self._isInline(tag)){
              // IE doesn't like non-font background color crud.
              // Also, don't move it in if the background color is set on a block style node,
              // as it won't color properly once put on inline font.
              bc = new dojo.Color(bc).toHex();
              sTag = dojo.withGlobal(w, "create", dojo, ["font", {style: {backgroundColor: bc}}] );
              cNode.style.backgroundColor = "";
             }
             if(c && tag !== "font"){
              // IE doesn't like non-font background color crud.
              c = new dojo.Color(c).toHex();
              sTag = dojo.withGlobal(w, "create", dojo, ["font", {color: c}] );
              cNode.style.color = "";
             }
             cNode = wrapNodes(sTag, cNode);
             sTag = null;
            }
           }
           if(cNode.childNodes){
            // Clone it, since we may alter its position
            var nodes = [];
            dojo.forEach(cNode.childNodes, function(n){ nodes.push(n);});
            dojo.forEach(nodes, convertNode);
           }
          }
          return cNode;
         };
         return this._normalizeTags(convertNode(node));
        }
        return node;
    • summary
      A function to convert the HTML structure of 'node' into
      semantic tags where possible.
    • tags:
  • dojox.editor.plugins.NormalizeStyle._normalizeTags

    • type
      Function
    • parameters:
      • node: (typeof The)
        node to search from.
    • source: [view]
        var w = this.editor.window;
        var nodes = dojo.withGlobal(w, function() {
         return dojo.query("em,s,strong", node);
        });
        if(nodes && nodes.length){
         dojo.forEach(nodes, function(n){
          if(n){
           var tag = n.tagName?n.tagName.toLowerCase():"";
           var tTag;
           switch(tag){
            case "s":
              tTag = "strike";
              break;
            case "em":
              tTag = "i";
              break;
            case "strong":
              tTag = "b";
              break;
           }
           if(tTag){
            var nNode = dojo.withGlobal(w, "create", dojo, [tTag, null, n, "before"] );
            while(n.firstChild){
             nNode.appendChild(n.firstChild);
            }
            n.parentNode.removeChild(n);
           }
          }
         });
        }
        return node;
    • summary
      A function to handle normalizing certain tag types contained under 'node'
    • tags:
  • dojox.editor.plugins.NormalizeStyle._convertToCss

    • type
      Function
    • parameters:
      • node: (typeof DOMNode)
        The node to process
    • source: [view]
        if(node){
         var w = this.editor.window;
         var convertNode = function(cNode) {
          if(cNode.nodeType == 1){
           if(cNode.id !== "dijitEditorBody"){
            var tag = cNode.tagName?cNode.tagName.toLowerCase():"";
            if(tag){
             var span;
             switch(tag){
              case "b":
              case "strong": // Mainly IE
               span = dojo.withGlobal(w, "create", dojo, ["span", {style: {"fontWeight": "bold"}}] );
               break;
              case "i":
              case "em": // Mainly IE
               span = dojo.withGlobal(w, "create", dojo, ["span", {style: {"fontStyle": "italic"}}] );
               break;
              case "u":
               span = dojo.withGlobal(w, "create", dojo, ["span", {style: {"textDecoration": "underline"}}] );
               break;
              case "strike":
              case "s": // Mainly WebKit.
               span = dojo.withGlobal(w, "create", dojo, ["span", {style: {"textDecoration": "line-through"}}] );
               break;
              case "font": // Try to deal with colors
               var styles = {};
               if(dojo.attr(cNode, "color")){
                styles.color = dojo.attr(cNode, "color");
               }
               if(dojo.attr(cNode, "face")){
                styles.fontFace = dojo.attr(cNode, "face");
               }
               if(cNode.style && cNode.style.backgroundColor){
                styles.backgroundColor = cNode.style.backgroundColor;
               }
               if(cNode.style && cNode.style.color){
                styles.color = cNode.style.color;
               }
               var sizeMap = {
                1: "xx-small",
                2: "x-small",
                3: "small",
                4: "medium",
                5: "large",
                6: "x-large",
                7: "xx-large"
               };
               if(dojo.attr(cNode, "size")){
                styles.fontSize = sizeMap[dojo.attr(cNode, "size")];
               }
               span = dojo.withGlobal(w, "create", dojo, ["span", {style: styles}] );
               break;
             }
             if(span){
              while(cNode.firstChild){
               span.appendChild(cNode.firstChild);
              }
              dojo.place(span, cNode, "before");
              cNode.parentNode.removeChild(cNode);
              cNode = span;
             }
            }
           }
           if(cNode.childNodes){
            // Clone it, since we may alter its position
            var nodes = [];
            dojo.forEach(cNode.childNodes, function(n){ nodes.push(n);});
            dojo.forEach(nodes, convertNode);
           }
          }
          return cNode;
         };
         node = convertNode(node);
         if(this.condenseSpans){
          this._condenseSpans(node);
         }
        }
        return node;
    • summary
      A function to convert the HTML structure of 'node' into
      css span styles around text instead of semantic tags.
      Note:  It does not do compression of spans together.
    • tags:
  • dojox.editor.plugins.NormalizeStyle._condenseSpans

    • type
      Function
    • parameters:
      • node: (typeof The)
        node (and its children), to process.
    • source: [view]
        var compressSpans = function(node){
         // Okay, span with no class or id and it has styles.
         // So, merge the styles, then collapse. Merge requires determining
         // all the common/different styles and anything that overlaps the style,
         // but a different value can't be merged.
         var genStyleMap = function(styleText){
          var m;
          if(styleText){
           m = {};
           var styles = styleText.toLowerCase().split(";");
           dojo.forEach(styles, function(s){
            if(s){
             var ss = s.split(":");
             var key = ss[0] ? dojo.trim(ss[0]): "";
             var val = ss[1] ? dojo.trim(ss[1]): "";
             if(key && val){
              var i;
              var nKey = "";
              for(i = 0; i < key.length; i++){
               var ch = key.charAt(i);
               if(ch == "-"){
                i++;
                ch = key.charAt(i);
                nKey += ch.toUpperCase();
               }else{
                nKey += ch;
               }
              }
              m[nKey] = val;
             }
            }
           });
          }
          return m;
         };
         if(node && node.nodeType == 1){
          var tag = node.tagName? node.tagName.toLowerCase() : "";
          if(tag === "span" && node.childNodes && node.childNodes.length === 1){
           // Okay, a possibly compressible span
           var c = node.firstChild;
           while(c && c.nodeType == 1 && c.tagName && c.tagName.toLowerCase() == "span"){
            if(!dojo.attr(c, "class") && !dojo.attr(c, "id") && c.style){
             var s1 = genStyleMap(node.style.cssText);
             var s2 = genStyleMap(c.style.cssText);
             if(s1 && s2){
              // Maps, so lets see if we can combine them.
              var combinedMap = {};
              var i;
              for(i in s1){
               if(!s1[i] || !s2[i] || s1[i] == s2[i]){
                combinedMap[i] = s1[i];
                delete s2[i];
               }else if(s1[i] != s2[i]){
                // Collision, cannot merge.
                // IE does not handle combined underline strikethrough text
                // decorations on a single span.
                if(i == "textDecoration"){
                 combinedMap[i] = s1[i] + " " + s2[i];
                 delete s2[i];
                }else{
                 combinedMap = null;
                }
                break;
               }else{
                combinedMap = null;
                break;
               }
              }
              if(combinedMap){
               for(i in s2){
                combinedMap[i] = s2[i];
               }
               dojo.style(node, combinedMap);
               while(c.firstChild){
                node.appendChild(c.firstChild);
               }
               var t = c.nextSibling;
               c.parentNode.removeChild(c);
               c = t;
              }else{
               c = c.nextSibling;
              }
             }else{
              c = c.nextSibling;
             }
            }else{
             c = c.nextSibling;
            }
           }
          }
         }
         if(node.childNodes && node.childNodes.length){
          dojo.forEach(node.childNodes, compressSpans);
         }
        };
        compressSpans(node);
    • summary
      Method to condense spans if you end up with multi-wrapping from
      from converting b, i, u, to span nodes.
    • tags:
  • dojox.editor.plugins.NormalizeStyle._isInline

    • type
      Function
    • parameters:
      • tag: (typeof The)
        tag to examine
    • source: [view]
        switch(tag){
         case "a":
         case "b":
         case "strong":
         case "s":
         case "strike":
         case "i":
         case "u":
         case "em":
         case "sup":
         case "sub":
         case "span":
         case "font":
         case "big":
         case "cite":
         case "q":
         case "img":
         case "small":
          return true;
         default:
          return false;
        }
    • summary
      Function to determine if the current tag is an inline
      element that does formatting, as we don't want to
      try to combine inlines with divs on styles.
    • tags:
  • dojox.editor.plugins.NormalizeStyle._inserthtmlImpl

    • type
      Function
    • parameters:
      • html: (typeof The)
        HTML string to insert.
    • source: [view]
        if(html){
         var div = this.editor.document.createElement("div");
         div.innerHTML = html;
         div = this._browserFilter(div);
         html = dijit._editor.getChildrenHtml(div);
         div.innerHTML = "";


         // Call the over-ride, or if not available, just execute it.
         if(this.editor._oldInsertHtmlImpl){
          return this.editor._oldInsertHtmlImpl(html);
         }else{
          return this.editor.execCommand("inserthtml", html);
         }
        }
        return false;
    • summary
      Function to trap and over-ride the editor inserthtml implementation
      to try and filter it to match the editor's internal styling mode.
      Helpful for plugins like PasteFromWord, in that it extra-filters
      and normalizes the input if it can.
    • tags:
  • dojox.editor.plugins.NormalizeStyle.editor

    • summary
  • dojox.editor.plugins.NormalizeStyle._browserFilter

    • summary
  • dojox.editor.plugins.NormalizeStyle.editor._oldInsertHtmlImpl

    • summary
  • dojox.editor.plugins.NormalizeStyle.editor._inserthtmlImpl

    • summary
  • dojox.editor.plugins.NormalizeStyle.setEditor.editor

    • type
      Object
    • summary
      The editor to configure for this plugin to use.
  • name

    • summary
  • o.plugin

    • summary
  • dojox.editor.plugins

    • type
      Object
    • summary
  • dojox.editor

    • type
      Object
    • summary
  • dojox

    • type
      Object
    • summary