Before/after jQuery highlighter I have a webpage that shows shorthand code on the left, and its long form on the right. When you hover over code on the left (signified with a space-separated array in the data-from attribute), it uses jQuery to highlight corresponding code on the right (signified with a space-separated array in the data-to attribute), and vice-versa. It's working great, but it feels very long.

Script



function containsAny(haystack, needles) {
    for(needle in needles)
        if (haystack.indexOf(needles[needle]) &gt;= 0)
            return true;
}
$(document).ready(function() {
    /* from to */
    $("[data-from]").each(function(i, e) {
        var $e = $(e),
        froms = $e.data("from").toString().split(/\s+/); // must do toString in case we get an int
        $e.hover(function() {
            $e.addClass("hilighted");
            $("[data-to]").each(function(i2, e2) {
                var $e2 = $(e2),
                tos = $e2.data("to").toString().split(/\s+/);
                if (containsAny(tos, froms))
                    $e2.addClass("hilighted");
            });
        },
        function() {
            $("[data-to]").each(function(i2, e2) {
                $e.removeClass("hilighted");
                var $e2 = $(e2),
                tos = $e2.data("to").toString().split(/\s+/);
                if (containsAny(tos, froms))
                    $e2.removeClass("hilighted");
            });
        });
    });

    /* to from */
    $("[data-to]").each(function(i, e) {
        var $e = $(e),
        tos = $e.data("to").toString().split(/\s+/);
        $e.hover(function() {
            $e.addClass("hilighted");
            $("[data-from]").each(function(i2, e2) {
                var $e2 = $(e2),
                froms = $e2.data("from").toString().split(/\s+/);
                if (containsAny(froms, tos))
                    $e2.addClass("hilighted");
            });
        },
        function() {
            $("[data-from]").each(function(i2, e2) {
                $e.removeClass("hilighted");
                var $e2 = $(e2),
                froms = $e2.data("from").toString().split(/\s+/);
                if (containsAny(froms, tos))
                    $e2.removeClass("hilighted");
            });
        });
    });
});


SSCCE HTML



&lt;H3&gt;Before&lt;/H3&gt;
&lt;PRE&gt;
&lt;SPAN DATA-FROM="link-color"&gt;*:link&lt;/SPAN&gt; {
    &lt;SPAN DATA-FROM="link-color"&gt;color: blue;&lt;/SPAN&gt;
}

&lt;SPAN DATA-FROM="btn-color"&gt;button,
input[type=("button","submit","reset")]&lt;/SPAN&gt; {
    &lt;SPAN DATA-FROM="btn-color"&gt;color: match(*:link);&lt;/SPAN&gt;
}
&lt;/PRE&gt;

&lt;H3&gt;After&lt;/H3&gt;
&lt;PRE&gt;
&lt;SPAN DATA-TO="link-color"&gt;*:link,&lt;/SPAN&gt;
&lt;SPAN DATA-TO="btn-color"&gt;button,
input[type="button"],
input[type="submit"],
input[type="reset"]&lt;/SPAN&gt; {
    &lt;SPAN DATA-TO="link-color btn-color"&gt;color: blue;&lt;/SPAN&gt;
}
&lt;/PRE&gt;


Full use case

How can I make the JavaScript shorter (or at least more OO) without sacrificing functionality? I'm sure it can be shorter or more OO because it's so redundant, but I can't figure how.
Here's your code, and I've pointed out some potential problems:

for(needle in needles)
    if (haystack.indexOf(needles[needle]) &gt;= 0)
        return true;


While this is possible, I suggest you use {} instead. This avoids ambiguity, and future danger, especially when you'll be adding more functionality beyond just a single line.

Additionally, for-in runs over prototype properties. If you happen to have a property that is similarly named as a native property in the prototype, you'll be in trouble. To avoid that, check using hasOwnProperty before proceeding with the code.

$(document).ready(function() {


Probably not better, but there's a shorthand for this: $(function(){...})

$("[data-from]").each(function(i, e) {


I'd probably avoid using attribute selectors. They're known to be slow, depending on the parser implementation. I suggest you stick to classes.

froms = $e.data("from").toString().split(/\s+/); // must do toString in case 


A shorthand to convert stuff to string is to do '' + to it. Not so verbose, but it's somewhat elegant and short.