Kyle
Kyle

Reputation: 1672

Convert CSS style rules to HTML elements (and vice versa)

I am using a utility called FresherEditor which uses the ContentEditable plugin for jQuery to create an editable document in the browser window. I then need to take that output and generate SVG graphics from the rules obtained by parsing the HTML governed style into CSS.

The freshereditor will produce output that looks somewhat like:

<div>
  <p>
   <i>
    <u>
     <b>
      <font face="Verdana">
       Hello, World!
      </font>
     </b>
    </u>
   </i>
  </p>
</div>

When what I would prefer is something that looks like:

<div>
 <p style="font-weight: bold; font-style: italic; text-decoration: underline; font-family: Verdana;">
  Hello, World!
 </p>
</div>

Any suggestions would be helpful.

Upvotes: 1

Views: 935

Answers (1)

Phrogz
Phrogz

Reputation: 303421

This was a very fun problem; thanks! Following are scripts that add html2style() and style2html() methods. The test case shows that you can convert between the two with no visual change (though the ordering of the element nesting may be different after a round trip).

Test Case Showing These Working

http://jsfiddle.net/GaPBS/

Converting Nested HTML Phrase Elements to Style Attributes

(function(scope){
  var HTML2CSS = {
    strong: function(e){ this.style.fontWeight = "bold";                  },
    b:      function(e){ this.style.fontWeight = "bold";                  },
    em:     function(e){ this.style.fontStyle = "italic";                 },
    i:      function(e){ this.style.fontStyle = "italic";                 },
    font:   function(e){ this.style.fontFamily = e.getAttribute('face');  },
    u:      function(e){ this.style.textDecoration += ' underline';       },
    strike: function(e){ this.style.textDecoration += ' line-through';    }
  };
  scope.html2style = function(root){
    for (var name in HTML2CSS){
      var elements = root.querySelectorAll(name);
      var styler   = HTML2CSS[name];
      for (var i=elements.length;i--;){
        var toKill = elements[i],
            parent = toKill.parentNode;
        // Only swap out nodes that are the sole element child of the parent
        if (!toKill.nextElementSibling && !toKill.previousElementSibling){
          parent.removeChild(toKill);
          // Move contents into the parent
          for (var kids=toKill.childNodes,j=kids.length;j--;){
            parent.insertBefore(kids[j],parent.firstChild);
          }
          // Merge existing styles from this node onto the parent
          parent.style.cssText += toKill.style.cssText;  
          // Hard set the style for this node onto the parent
          styler.call(parent,toKill);
        }
      }
    }
  }
})(this);

Converting Style Attributes to Nested HTML Phrase Elements

(function(scope){
  var CSS2HTML = {
    "fontWeight:bold":             "b",
    "fontStyle:italic":            "i",
    "textDecoration:underline":    "u",
    "textDecoration:line-through": "strike",
    "font-family:*":                function(value){ var e=document.createElement('font'); e.setAttribute('face',value); return e; }
  };
  scope.style2html = function(root){
    var leaf = root;
    for (var style in CSS2HTML){
      var elName = CSS2HTML[style],
          parts  = style.split(':'),
          name   = parts[0],
          wild   = parts[1]=="*",
          regex  = !wild && new RegExp("(^|\\s)"+parts[1]+"(\\s|$)"),
          before = root.style[name];
      if (before && (wild || regex.test(before))){
        var el = (typeof elName==='function') ? elName(before) : document.createElement(elName);
        for (var kids=leaf.childNodes,j=kids.length;j--;){
          el.insertBefore(kids[j],el.firstChild);
        }
        leaf = leaf.appendChild(el);
        root.style[name]=wild ? "" : before.replace(regex,"");
      }
    }
    if (root.getAttribute('style')=="") root.removeAttribute('style');
  }
})(this);

Upvotes: 1

Related Questions