wtorek, maja 18, 2010

Ściana, czyli rozbijam się na onclick ;-)

Zabawiając się z Buzz Troll Removerem dotarłem już do etapu na którym potrafię ukryć trollowe buzzy (trollbuzzy?) w taki sposób, że gdy użytkownik zdecyduje, że jednak odtrolluje danego delikwenta to jego komentarze znów się pojawią.

Niby super, ale jest jedno ale ;-) a mianowicie to, że wtedy nie działa guziczek "hide", który umiejscawiany jest przez BTR obok nicka użytkownika Buzza [buzzżytkownika? ;-)]. Próbowałem wielu sposobów i jak na razie odbijam się od ściany....

Guziczki tworzę tak:
var parent = b[i].parentNode;
var button = document.createElement("button");
button.innerHTML = "hide";
button.setAttribute("name",b[i].innerHTML);
button.setAttribute("link",b[i].href);
button.onclick=function() {
blockUser(this);
}

b[i].setAttribute("modifiedByBuzzTrollRemover","true");
parent.insertBefore(button,b[i].nextSibling);

Element b[i] to i-ty tag A na stronie spełniający jeszcze tam pewne wymogi.
Istotne jest to jak przypisywany jest kod do onclick.

Niestety użycie button.setAttribute("onclick","blockUser(this);") powoduje tylko tyle, że każde kliknięcie guziczka powoduje zgłoszenie na konsoli błędu mówiącego, że JavaScript nie może namierzyć funkcji blockUser(elem).

Samo kasowanie posta wygląda mniej więcej tak:
b[i].parentNode.parentNode.setAttribute("rBTK",b[i].parentNode.parentNode.innerHTML);
b[i].parentNode.parentNode.setAttribute("rBTKLink",b[i].href);
removed.push(b[i].parentNode.parentNode);
if (method*1==1) {
b[i].parentNode.parentNode.innerHTML="";
} else {
b[i].parentNode.parendNode.innerHTML="<span style='background:yellow;'>Post of "+b[i].innerHTML+" deleted by Buzz Troll Remover</span>";
}


Gdzie istotna jest pierwsza linia, która w atrybucie nad-nad-rodzica ;-) zapisuje treść kasowanego buzza.

Odnowienie Buzza wygląda tak elem.innerHTML = elem.getAttribute("rBTK");.

I problem jest taki, że onclick stworzone tak jak je tworzę w ogóle nie jest widoczne w tym co zostanie włożone do innerHTML, a jeśli użyję metody z przypisaniem stringa do onclick to co prawda jest widoczne w innerHTML, ale nie działa :-)

I pisząc to wpadłem na pomysł by jak zwykle rozwiązać problem przy pomocy oszustwa :-) Co dowodzi, że programowanie jest naprawdę sztuką oszukiwania.

A gdybyż tak "kopię" buzza, którą przechowuję, w momencie gdy będzie znów przypisywana do elementu potraktować wyrażeniem regularnym, które zamorduje wszystko od "<button" do "</button>", oraz wywali atrybut modifiedByBuzzTrollRemover? Wtedy mechanizm dodawania guziczków zobaczy taki wpis, stwierdzi, że wpis nie posiada guziczka i mu go doda....... :-)

Czyli jak dobrze pójdzie problem zrozumienia czemu onclick dodawany przez element.onclick="..." czy element.setAttribute("onclick","....") nie działa nie będzie ważny ;-) ważne będzie tylko napisanie odpowiedniego wyrażenia regularnego :-)


Podobne postybeta
IE suxx ;-)
Zasada numer 1: sprawdzaj oczywiste
Bookmarklet do robienia CSV z obligacjami i ich oprocentowaniem ;-)
Buzz Troll Remover v0.3 - potęga guzików
Go dla Java'owca ;-) odcinek 2 "kontenery dwa ;-)"

6 komentarzy:

  1. Spróbuj najpierw dodać węzeł button do strony, a dopiero później przypisz mu zdarzenie?

    Jeśli gdzieś zrobiłeś coś takiego jak przy kasowaniu, czyli użyłeś innerHTML, to wszystkie zdarzenia odlatują do krainy niebytu.

    Może to to?

    OdpowiedzUsuń
  2. To rozwiązanie z pierwszego listingu działa, po prostu kod podpięty pod zdarzenie onclick nie jest widoczny w HTMLu, ale w strukturze DOM jest i działa. Chociaż spróbuję zrobić tak jak sugerujesz, bo tego nie próbowałem :-)

    To wiem, ciekawi mnie jednak dlaczego, jak w tym co wleci innerHTML będzie onclick="alert('toster');" to po kliknięciu wyskoczy alert z tosterem ;-) Mówiąc inaczej nie do końca rozumiem czemu onclicki zrobione przez onclick="jakasFunkcja()" nie widza tej jakasFunkcja(), a gdy zrobię to tak jak w 1 listingu to widzą :-)

    OdpowiedzUsuń
  3. A dlaczego nie użyjesz button.addEventListener() zamiast button.onclick? Wtedy w funkcji wywoływanej przez listenera przez this odwołujesz się do buttona. A z niego już tylko robisz getParent() i masz dostęp do elementu z komentarzem. W TrollEyBuzzie treści komentarza nie usuwam z DOMu, po prostu ukrywam przez ustawienie display:none, więc nie ma też problemu z jego odzyskaniem.

    OdpowiedzUsuń
  4. Głównie dlatego tak to robię, że część userów się przyzwyczaiła do żółtego paska z informacją o usunięciu, ja sam zaś wolę w ogóle nie widzieć, że ktoś pisał, a łatwiej mi to było zrobić przez nadpisanie innerHTML niż insertBefore i ukrycie reszty. Choć to drugie pewnie miałoby więcej sensu ;-)
    A będzie jakaś różnica funkcjonalna przy użyciu addEventListener? No i też w this mam guziczek, choć patrząc na kod nie do końca rozumiem dlaczego ;-)

    OdpowiedzUsuń
  5. Wcześniej na to nie zwróciłem uwagi…

    Czemu przypisujesz do onclick _tekst_ funkcji?
    To jest jak wstawianie wywołań eval. Twój problem sprowadza się więc do reguł zasięgu.

    No i jeszcze jedno pytanie, czemu w ogóle używasz setAttribute?
    W przypadku atrybutów takich jak name i link to wygląda jak niepotrzebna komplikacja, natomiast jeśli używasz atrybutów, które nie zostały zdefiniowane w DOM, to wkraczasz na bardzo śliski grunt.

    Skoro już mowa o onclick. Używając addEventListener'a mógł byś stworzyć globalną obsługę dla wszystkich buttonów danej klasy.

    OdpowiedzUsuń
  6. @Red - możebne, że to wina eval.

    Bo setAttribute jest legalne i pomaga, dzięki temu nie trzeba trzymać gdzieś jakiejś dodatkowej struktury pamięci, wystarczy wykorzystać DOMa.

    OdpowiedzUsuń