Randomblue
Randomblue

Reputation: 116273

Keep only a subtree of the DOM tree

On BBC articles, such as this one, there is a DOM element with class story-body, deep in the DOM chain.

I want to hide all DOM element "outside" of this (unique) DOM element. The problem is that I can't just do

$('*').hide();
$('.story-body');

because I need to make sure to keep the parents, grand-parents, etc. of story-body. I also can't do

$('*').hide();

var current = $('.story-body').show();
while(current = current.parent()) {
   current.show();
}

because that would simply show everything.

Any suggestions?

Upvotes: 1

Views: 653

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074238

You could hide everything, then show .story-body, its chain of ancestors, and all of its descendants:

$("body *").hide();               // Hide all
var sb = $(".story-body").show(); // Find and show story-body
sb.parents().show();              // ...and its parents
sb.find("*").show();              // ...and its contents

Or as a two-liner if you like to super-compact things:

$("body *").hide();
$(".story-body").show().parents().show().end().find("*").show();

But I wouldn't count on the effect of hiding all of those other elements. Although when I tried it on that story, it worked fine.

Here's a bookmarklet for it, copy the javascript: line below and paste it in as the target of a bookmark, then navigate to a BBC News page and click the bookmark:

javascript:(function(){(function(){var d=document,s=d.createElement("script"),st=new Date();s.src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js";d.body.appendChild(s);after();function after(){var $,sb;if(typeof jQuery!=="function"){if(new Date()-st<5000){setTimeout(after,100);}return;}$=jQuery.noConflict();$("body *").hide();sb=$(".story-body").show();sb.parents().show();sb.find("*").show();}})();})();

Source:

(function() {
    // Load jQuery
    var d = document,
        s = document.createElement("script"),
        st = new Date();
    s.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js";
    d.body.appendChild(s);

    // Wait for it to load
    after();
    function after() {
        var $, sb;
        if (typeof jQuery !== "function") {
            // Not loaded yet
            if (new Date() - st < 5000) { // Give up after 5 seconds
                // Try again in 100ms
                setTimeout(after, 100);
            }
            return;
        }

        // Minimize impact
        $ = jQuery.noConflict();

        // Do the work
        $("body *").hide();
        sb = $(".story-body").show();
        sb.parents().show();
        sb.find("*").show();
    }
})();

Seems to work just fine on the four or five stories I tried.

Upvotes: 1

jfriend00
jfriend00

Reputation: 707288

You could detach the story, remove everything else, then reinsert the story:

 var stories = $('.story-body');
 stories.detach();
 $(document.body).children().remove();
 stories.appendTo(document.body);

Upvotes: 1

Related Questions