wtorek, maj 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
Zasada numer 1: sprawdzaj oczywiste
IE suxx ;-)
AppInventor - pierwsze wrażenia i pierwsze programy :-)
Go dla Java'owca ;-) odcinek 2 "kontenery dwa ;-)"
Buzz Troll Remover v0.3 - potęga guzików

6 comments:

  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ń na zawsze
  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ń na zawsze
  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ń na zawsze
  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ń na zawsze
  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ń na zawsze
  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ń na zawsze