dikamilo.net

Kolejny blog w sieci...

Filtrowanie działów na forach internetowych

Często zdarza mi się odwiedzać fora internetowa które mają bogaty asortyment kategorii oraz działów. To czego mi brakuje na większości takich stronach to możliwość wyłączenia działów które są mi obojętne. Przykładem takiego forum jest forum społeczności XDA Developers. Mamy tutaj naprawdę pokaźny zbiór działów który można przewijać i przewijać. Mnie osobiście interesują tylko dwa działy, dział mojego telefonu oraz systemu na którym on bazuje + dział generalny do którego dość rzadko zaglądam. Nie ma tutaj możliwości wyłączenia wyświetlania poszczególnych działów ale za to możemy je sobie zwinąć do samego nagłówka co nie jest do końca wygodnym rozwiązaniem bo przy takiej ilości działów i tak musimy przewijać.

Dlatego też postanowiłem napisać mały skrypt w JavaScript do filtrowania działów które mnie interesują. Skrypt uruchamiany jest dzięki pluginowi Greasemonkey do Firefoxa ale jest możliwość uruchomienia go w innych przeglądarkach.

Forum XDA Developers bazuje na skrypcie vBulletin dlatego też mój skrypt może działać w zasadzie na każdym forum bazującym na tym systemie.

Podstawą działania skryptu jest wykrywanie linków działów które w vBulletin mają składnie wyglądającą tak:

adres_forum/forumdisplay.php?f=numer_dzialu

Niestety powyższa składnia używana jest też do linków poddziałów, co początkowo uważałem za małą komplikację mojego prostego rozwiązania, ale okazało się że można to bardzo prosto rozwiązać. Otóż linki działów są otoczone nagłówkiem drugiego stopnia co wygląda następująco:

<h2><a href="adres_dzialu">opis</h2>

Moje rozwiązanie wygląda następująco:

  • Definiuję tablicę nazw działów które chcę wyświetlać
  • Pobieram wszystkie linki do działów w postaci węzłów DOM
  • Sprawdzam czy nazwa działu znajduje się na liście
  • Jeżeli nazwa działu nie znajduje się na liście to pobieram główny węzeł działu i usuwam go z drzewa DOM

Do pobrania węzłów linków do działów używam funkcji evaluate() która używa XPath do wyszukiwana interesujących mnie działów. Następnie w pętli za pomocą snapshotItem() pobieram każdy element i sprawdzam czy jego innerHTML jest na mojej liście, jeżeli nie jest, pobieram rodzica węzła za pomocą parentNode i wywalam go za pomocą removeChild().

Ze względu na to że węzeł linku do działu jest umieszczony kilka węzłów niżej niż główny węzeł działu, parentNode wywoływany jest kilka razy.

<div class="forumbox view-condensed">
    <!-- glowny div dzialu -->
    <div class="forumbox-header">
        <!-- naglowek -->
        <h2><a href="adres_dzialu">opis_dzialu</a></h2>
        <!-- ... -->
    </div> 
    <!-- ... -->
</div>

Działanie parentNode:

// element wskazuje na <a>
element = forumLinkList.snapshotItem(i);

// naglowek <h2>
var parent = element.parentNode;

// header <div>
var parent = element.parentNode.parentNode;

// forumbox <div> - glowny wezel działu
var parent = element.parentNode.parentNode.parentNode;

Jako że usuwanie węzła realizowane jest za pomocą removeChild(), musimy pobrać rodzica naszego węzła i usunąć z niego nasz węzeł:

var parent = element.parentNode.parentNode.parentNode;
parent.parentNode.removeChild(parent);

W całości skrypt wygląda następująco:

// tablica działów do wyświetlania
var displayForums = new Array(
    "General discussion",
    "Android Development and Hacking",
    "HTC Buzz: Wildfire"
);

// pobranie wezlow
var forumLinkList = document.evaluate(
    '//h2//a[contains(@href,"forumdisplay.php?f=")]', 
    document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, 
    null);

for (var i = 0; i < forumLinkList.snapshotLength; i++)
{    
    element = forumLinkList.snapshotItem(i);
    if(! isInDisplayList(element.innerHTML))
    {
        // jezeli nazwa nie jest na lisice to usuwamy dzial
        var parent = element.parentNode.parentNode.parentNode;
        parent.parentNode.removeChild(parent);
    }
}

// funkcja sprawdza czy nazwa dzialu jest na naszej liscie
function isInDisplayList(forumTitle)
{    
    var flag = false;
    for(var i = 0; i < displayForums.length; i++)
    {
        if(displayForums[i] == forumTitle)
        {
            flag = true;
            break;
        }
    }
    return flag;
}

Funkcja evaluate() pobiera tylko węzły linków które są otoczone nagłówkiem H2 oraz w swoim href mają forumdisplay.php?f=. Dzięki temu nie musimy iterować po wszystkich linkach które są na stronie.

Skrypt zostanie opublikowany na userscripts.org gdy zaimplementuję możliwość wybierania działów do ukrycia w osobnym okienku tudzież w menu skryptu po kliknięciu na ikonkę greasemonkey'a.

Tagi