jQuery to flip emphasis and italics relative to context

A fairly major annoyance about CSS and web layout to me is that you cannot invert selections. Not yet anyway. So if you have something like–

<p style="font-style:italic">“No one’s talking to you,
   <i>Jas</i>per,” said Diane.</p>

What you get is–

“No one’s talking to you, Jasper,” said Diane.

Which makes no sense. The emphasis is flattened and its contrast lost. We want it to read this way so the emphasized text stands out again–

“No one’s talking to you, Jasper,” said Diane.

Here is a more elaborate if contrived example to show how nested tags, plus two different tags which default to italic style, plus the possibility of setting the style manually can make it a less than trivial problem.

<div id="italicFlip">
 <p style="font-style:italic">
    <em><i>At maurisenim</i> erat nulla et diam suspendisse
    <i>turpis <i>in</i> venenatis</i> <i>dui</i> lacus tortor.
    Turpis <i>v<i>estibulu</i>m</i> at ac ut venenatis at
    <em>feugiat</em> <span style="font-style:italic">vestibulum
    <i>nulla</i> dui</span> dolor.</em>
 </p>
</div>

Without any help at all–

At maurisenim erat nulla et diam suspendisse turpis in venenatis dui lacus tortor. Turpis vestibulum at ac ut venenatis at feugiat vestibulum nulla dui dolor.

As expected—flat italics. With a little currying magick + jQuery hooks into CSS we can flip each node’s style based on its context: its own style versus the style of its parent. Here’s what that can look like. Not beginner JavaScript but quite terse really.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.js"
  type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
function flipItalics (n,iBit) {
    if ( n.nodeType == 3 ) return; // Don't operate on text nodes.
    // We are either in an <i/> or a CSS styled italic.
    var myI = n.nodeName.toLowerCase().match(/^(i|em)$/)
        || $(n).css("font-style") == "italic"  ? 1 : 0;
    // Flip the iBit by the italics of the parent & the current node.
    iBit = ( iBit & myI ) ? 0 : 1;
    var style = iBit ? "normal" : "italic";
    $(n).css({fontStyle:style});
    // Recurse into the children and do the same.
    var kids = n.childNodes;
    for ( var i = 0; i < kids.length; i++ ) {
        flipItalics(kids[i],iBit);
    }
}

$(function() {
    flipItalics( $("#italicFlip").get(0) );
});
//]]> </script>

With our jQuery + DOM currying helper–

At maurisenim erat nulla et diam suspendisse turpis in venenatis dui lacus tortor. Turpis vestibulum at ac ut venenatis at feugiat vestibulum nulla dui dolor.

flipItalics is our worker and it needs to be passed a DOM node into which to recurse. It cannot accept a jQuery selection object; though we could allow for that if we wanted by adding a test against the node and normalizing it. DOM currying is the one traversal style which is unnatural to jQuery so we do it manually on raw nodes. We keep jQuery in the picture though because adjusting styles is a verbose, x-browser PITA without it.

You could do an entire page with–

    flipItalics( $("body").get(0) );
digg stumbleupon del.icio.us reddit Fark Technorati Faves
Your information (required) Name*
Email*
Website

* Indicates required fields; email is used for validation and is not displayed on the site.

Your comment
Commenting on jQuery to flip emphasis and italics relative to context
Title

Body is limited to ≈1,000 words. Paragraphs—but not line breaks—are automatically inserted. Valid XHTML is required. These are the allowed tags–

<a href=""></a> <br/> <acronym title=""></acronym> <abbr title=""></abbr> <code></code> <pre></pre> <tt></tt> <ins></ins> <del></del> <hr/> <cite></cite> <b></b> <i></i> <sup></sup> <sub></sub> <strong></strong> <em></em> <h1></h1> <h2></h2> <h3></h3> <q></q> <blockquote></blockquote>