Long Polling, tutorial – cześć 1

(poprzednia część tego tutoriala)

Teraz, kiedy mamy wygenerowane drzewo dyskusji, następnym krokiem będzie umożliwienie odpowiedzi w wątku. Użytkownik powinien móc kliknąć pod konkretną wypowiedzią i natychmiast zacząć wpisywać odpowiedź.

Dlatego pod każdym elementem li.post utwórzmy div’a, którym będzie konterem dla formularza odpowiedzi. Znajdź w thread.js linie odpowiedzialne za tworzenie elementów li zawierających posty i dodaj html z div’em do parametru innerHTML:

//app/webroot/js/thread.js
$("
  • ", { id: v.Post.id, innerHTML: "
    "+v.Post.message+"
    " + "
    " //<--- , class: "post child" }). appendTo("#"+v.Post.parent_id+">ul");
  • Przyda się teraz nieco css’ów. Kontener powinien zajmować nieco więcej miejsca (żeby łatwiej było w niego kliknąć) oraz po najechaniu na niego myszką powinien zmienić kolor, sugerując użytkownikowi, że może tam kliknąć. Podlinkuj nowy plik css do layoutu:

    //app/views/layouts/default.ctp
    echo $this->Html->css('cake.generic');
    echo $this->Html->css('thread'); //<-add this
    echo $this->Javascript->link(array("thread")); 
    

    a następnie stwórz plik thread.css z taką zawartością:

    /* app/webroot/css/thread.css */
    div.reply {
    	height: 5px;
    	cursor: text;
    }
    div.reply:hover{
    	background-color: #8EAFEB;
    }
    

    Tak to powinno wyglądać teraz:

    Bardziej spostrzegawczy zauważyli od razu, że miejsce pod pierwszą wypowiedzią w wątku nie zachowuje się tak jak powinno, poprawmy nieco thread.js:

    if($("#"+v.Post.parent_id).find("ul").length == 0){
    	if($("#"+v.Post.parent_id).find("div.reply").length == 0){
    		$("
    ", {class: "reply"}).appendTo("#"+v.Post.parent_id); } $("
      ", {class: "posts children"}).appendTo("#"+v.Post.parent_id); }

    Teraz pojawiło nam się odrobinę redundancji w kodzie – dwa miejsca, gdzie jest tworzony element div.reply. Naprawmy to. Usuniemy dodawanie stringa

    <div class='reply'/>
    

    i zastąpimy go tworzeniem elementu DOM przy pomocy jQuery, a następnie wyekstrahujemy motodę, która to robi. Ostatecznie kod powinien wyglądać tak:

    (function(window, document, udefined){
    	window.Thread = function(_posts) {
    		this.posts = _posts;
    		return this;	
    	};
    })(window, document);
    
    Thread.prototype.createReplyDiv = function(){
    	return $("
    ", {class: "reply"}); } Thread.prototype.createThread = function(){ if(this.posts.length <1){ return this; } var _this = this; //* patrz poniżej $(this.posts).each(function(k, v){ if($("#"+v.Post.parent_id).find("ul").length == 0){ if($("#"+v.Post.parent_id).find("div.reply").length == 0){ _this.createReplyDiv().appendTo("#"+v.Post.parent_id); } $("
      ", {class: "posts children"}).appendTo("#"+v.Post.parent_id); } $("
    • ", { id: v.Post.id, innerHTML: "
      "+v.Post.message+"
      " , class: "post child" }). append(_this.createReplyDiv()). appendTo("#"+v.Post.parent_id+">ul"); }); return this; }

    (*)Jeśli zastanawiasz się po co zapamiętujemy `this` w zmiennej `_this` śpieszę z wyjaśnieniem. W kodzie chcemy wywołać, wyodrębnioną dopiero co, metodę createReplyDiv. Niestety w anonimowej funkcji, która jest przekazana do metody each(), `this` wskazuje już na konkretny element z kolekcji po której ów each() iteruje. Musimy zapamiętać “starą” referencję `this` (czyli obiekt klasy Thread).

    Share Button

    Leave a Reply

    Your email address will not be published. Required fields are marked *