bert84: DIV-Inhalte austauschen

Hallo!

Ich habe ein Miniforum programmiert.
Leute können da Beiträge einstellen und diese werden in einer Liste angezeigt

Nun möchte ich, dass man die Beiträge direkt editieren kann.

Dazu gibt es an jedem Beitrag einen EDIT-Button und ich wollte jetzt gern - ohne das eine andere oder die gleiche Seite neu geladen wird - den Bereich, der aktuell den Beitragstext anzeigt, editierbar machen.

Gedacht habe ich mir, dass ich jeden Beitrag zu einem DIV mache, welchem ich eine eindeutige ID vergebe und bei Klick auf den EDIT-Button, tausche ich das DIV komplett durch ein DIV aus, welches jetzt nicht einfach den Beitragstext anzeigt, sondern eine TEXTAREA.
Aus dem EDIT-Button soll ein SAVE-Button werden.

Ist meine Idee mit Javascript/ CSS umsetzbar? Ich habe mich mit "innerHTML" versucht, aber da gescheitert. "outerHTML" liefert mir ein "undefind" zurück.
Das DIV hole ich mir mit "var div=document.getElementById(divId);"

Kennt von euch jmd. vielleicht eine Bespielseite, wo ich mir das ansehen kann oder kann mir einen Tipp geben, welche Javascriptfunktion ich mir genauer ansehen sollte?

Vielen Dank,
Bert

  1. Lieber bert84,

    Ist meine Idee mit Javascript/ CSS umsetzbar?

    ja.

    Ich habe mich mit "innerHTML" versucht, aber da gescheitert. "outerHTML" liefert mir ein "undefind" zurück.
    Das DIV hole ich mir mit "var div=document.getElementById(divId);"

    Du solltest mit den http://de.selfhtml.org/javascript/objekte/node.htm@title=Dokumentknoten arbeiten, anstatt mit innerHTML oder gar dem IE (und vielleicht Opera) vorbehaltenen outerHTML arbeiten.

    Kennt von euch jmd. vielleicht eine Bespielseite, wo ich mir das ansehen kann oder kann mir einen Tipp geben, welche Javascriptfunktion ich mir genauer ansehen sollte?

    Wie schon gesagt: http://de.selfhtml.org/javascript/objekte/node.htm@title=Nodes

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Du solltest mit den http://de.selfhtml.org/javascript/objekte/node.htm@title=Dokumentknoten arbeiten, anstatt mit innerHTML oder gar dem IE (und vielleicht Opera) vorbehaltenen outerHTML arbeiten.

      Ok, vielen Dank!

      Hatte das mit den Nodes vorhins auch gefunden, war mir aber nicht sicher, ob das richtige Weg war. Jetzt weiss ich es ... und werd mich dran versuchen :-)

      Danke noch mal!

      Bert

    2. Ich tausche auch den Inhalt eines div mit innerHtml aus. Funktioniert bei mir auch gut.
      Bei mir gehts halt nicht nur um Text, da steckt schon ein bisschen mehr dahinter. Das alles zur Laufzeit zusammensetzen wäre Wahnsinn. Wie könnte ich das anders machen?
      Ich krieg das HTML des div-Inhalts in die JS-Funktion. Was muss ich damit machen um innerHtml zu umgehen?

  2. Hallo Bert,

    das sind doch sehr gute und ausgegorene Vorüberlegungen.

    Ist meine Idee mit Javascript/ CSS umsetzbar? Ich habe mich mit "innerHTML" versucht, aber da gescheitert.

    Es ist mittels Javascript umsetzbar, jedoch würde ich nicht auf innerHTML zurückgreifen. Das aber ist eine Geschmackssache.

    <form action="beitrag_bearbeite.script">  
     <ul>  
      <li><div>Beitrag 1</div><input type="submit" value="bearbeiten" onclick="beitrag(this);return(false)></li>  
      <!-- andere Beiträge -->  
     </ul>  
    </form>
    

    Mittels DOM hast Du aus einem HTML-Element auf den Elementenbaum des Dokumentes Zugriff.

    function beitrag(element){  
    /*	Elternelement von <input>, was mit "this" übergeben wurde, ist <li>  
    	den Beitragstext enthält der Textknoten, den Du über ".firstChild"  
    	erreichst und deren Inhalt Du über ".nodeValue" ansprichst und ab-  
    	speicherst */  
    	var text=element.parentNode.getElementsByTagName('div')[0].firstChild.nodeValue  
    //	jetzt erstellst Du Dein Element Textarea  
    	var textarea=document.createElement('textarea')  
    //	und übergibst den Inhalt des oben angesprochenen <div>-Elements  
    	textarea.value=text  
    /*	nun tauschst Du nur noch den Textknoten gegen das geschaffene Text-  
    	area-Element aus */  
    	element.parentNode.getElementsByTagName('div')[0].replaceChild(textarea, element.parentNode.getElementsByTagName('div')[0].firstChild)  
    //	element, was ja <input> ist, soll ja auch geändert werden:  
    	element.value="SAVE"  
    /*	durch onclick und "return(false)" wurde festgelegt, dass das Formu-  
    	nicht abgesendet wurde, dies muss nun auch geändert werden: */  
    	element.onclick=""  
    }
    

    Für dich zum nachlesen:
    http://de.selfhtml.org/javascript/objekte/node.htm
    http://de.selfhtml.org/javascript/objekte/document.htm

    Gruß aus Berlin!
    eddi

    --
    VEB Opel, Geruchsproben und Stasi 2.0, Zensur...
    IHR WOLLTET MERKEL!
    1. Lieber Edgar,

      jedoch würde ich nicht auf innerHTML zurückgreifen. Das aber ist eine Geschmackssache.

      nach meinen Erfahrungen kann man mit innerHTML sogar manchmal unerklärliches Browserverhalten ernten, z.B. wenn man so einem Element etwas hinzufügt:

      var myElement = ...; // erzeugt Referenz  
      myElement.innerHTML += '<span id="blubb" onclick="alert(\'Huhuu Welt!\');">Klick mich bloß nicht an!</span>';
      

      Gerade im Zusammenhang mit innerHTML habe ich beim dynamischen Erweitern eines Dokuments mit einem weiteren TinyMCE-Editor "verrückte" Ergebnisse erhalten (bereits bestehende Editoren verloren ihre Inhalte und waren nicht mehr benutzbar), die nur dadurch abzustellen waren, indem ich auf innerHTML verzichtet hatte, um stattdessen mit den DOM-Funktionen zu arbeiten (Thread im dortigen Forum).

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Hallo Felix,

        var myElement = ...; // erzeugt Referenz

        myElement.innerHTML += '<span id="blubb" onclick="alert('Huhuu Welt!');">Klick mich bloß nicht an!</span>';

        
        >   
        > ...TinyMCE-Editor "verrückte"...  
          
        Dennoch halte ich den vergleich zu einem ganz normalen Dokument, was man mit Javascript und innerHTML ändert für Geschmackssache!  
          
          
        Gruß aus Berlin!  
        eddi  
        
        -- 
        VEB Opel, Geruchsproben und Stasi 2.0, Zensur...  
          
        IHR WOLLTET MERKEL!
        
        1. Lieber Edgar,

          | ...TinyMCE-Editor "verrückte"...

          vergleich zu einem ganz normalen Dokument

          naja, was ist schon "normal"... ;-)

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
          1. Re:

            | | ...TinyMCE-Editor "verrückte"...
            | vergleich zu einem ganz normalen Dokument
            naja, was ist schon "normal"... ;-)

            In meinen Augen kein konstruiertes Beispiel, was auf einer Anwendung beruht, die Javascript nutzt, um Javascript zur Anzeige zubringen - wo es also auch zu Kollisionen kommen kann.

            Gruß aus Berlin!
            eddi

            --
            VEB Opel, Geruchsproben und Stasi 2.0, Zensur...
            IHR WOLLTET MERKEL!
    2. var text=element.parentNode.getElementsByTagName('div')[0].firstChild.nodeValue

      element.parentNode.getElementsByTagName('div')[0].replaceChild(textarea, element.parentNode.getElementsByTagName('div')[0].firstChild)

      »Don't repeat yourself«. Einmal ausführen, dann die Variable verwenden:

      var div = element.parentNode.getElementsByTagName('div')[0];
      var text = dev.firstChild.nodeValue;
      div.replaceChild(textarea, div.firstChild);

      Verbessert sowohl Lesbarkeit als Performance.

      Mathias

      1. var div = element.parentNode.getElementsByTagName('div')[0];
        var text = dev.firstChild.nodeValue;
        div.replaceChild(textarea, div.firstChild);

        Also, das klappt fast einwandfrei.

        Ein Problem habe ich, nämlich das der Beitragstext  nur bis zum ersten Tag gegriffen wird.

        Also als Beispiel, so sieht der Beitrag im Qellcode im Original aus.

        ---schnipp---
        <div id="ta_88260">
        Wo warst du?<br>
        <p>
        Freu mich auf deine Erzählung        </p></div>
        ---schnipp---

        Nach dem Austausch der Elemente sieht das dann so aus:

        ---schnipp---
        <div id="ta_88260"><textarea style="border: 1px solid ; width: 395px;"></textarea><br>
        <p>
        Freu mich auf deine Erzählung        </p></div>
        ---schnipp---

        In dem Textarea-Bereich steht dann noch das "Wo warst du?" mit drin, was ok, aber eben nicht der ganze Text ist.

        Warum wird nur der Text bis zum ersten vorkommenden Tag, hier ein "<br>" gegriffen?

        In der SELFHTML-Erkärung zu "nodes" steht das zwar auch drin, aber leider nicht, wie man das umgehen kann, bzw. warum das so behandelt wird. Weil, nach meiner Denke :-), wenn ich sage, hole mir das DIV-Element, dann sollte er doch alles bis zum entsprechenden </DIV> holen und nicht mitten drin abbrechen.

        Danke,
        Bert

        1. Hi,

          var div = element.parentNode.getElementsByTagName('div')[0];
          var text = dev.firstChild.nodeValue;
          div.replaceChild(textarea, div.firstChild);

          Also, das klappt fast einwandfrei.

          Ein Problem habe ich, nämlich das der Beitragstext  nur bis zum ersten Tag gegriffen wird.

          Du fügst nur das firstChild ein - also darfst du dich auch nicht wundern, wenn nur dieses eingefügt wird.

          MfG ChrisB

          --
          Light travels faster than sound - that's why most people appear bright until you hear them speak.
        2. Lieber bert84,

          | var text = dev.firstChild.nodeValue;

          ---schnipp---
          <div id="ta_88260">
          Wo warst du?<br>
          <p>
          Freu mich auf deine Erzählung        </p></div>
          ---schnipp---

          nachdem Du Dich ja ausführlich über Dokumentknoten informiert hast (Links wurden Dir ja einige genannt), ist Dir sicherlich klar, dass Dein <div> mindestens drei (eigentlich sogar vier) Knoten enthält... von denen Du nur den ersten in die Variablen "text" einliest.

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        3. Hallo Bert,

          wie bereits geschrieben, ist der Gebrauch von innerHTML Geschmackssache. Du kannst es hier als einfache Alternative zum DOM nutzen:

          function beitrag(element){  
          	var div        =element.parentNode.getElementsByTagName('div')[0];  
          	var text       =div.innerHTML  
          	var textarea   =document.createElement('textarea')  
          	textarea.value =text  
          	element.value  ="SAVE"  
          	element.onclick=""  
          	  
          	while(div.firstChild){  
          		div.removeChild(div.firstChild)  
          	}  
          	div.appendChild(textarea);  
          }
          

          Wenn Du über DOM arbeiten magst, könnte eine Lösungsvariante so aussehen:

          function plain_HTML(element){  
          	var text ="";  
          	var clone=element.cloneNode(true);  
          	while(clone.firstChild){  
          		if(clone.firstChild.nodeType==3){  
          			text+=clone.firstChild.nodeValue;  
          		}  
          		else{  
          			node=clone.firstChild.nodeName  
          			text+="<"+clone.firstChild.nodeName+">";  
          			text+=plain_HTML(clone.firstChild);  
          			text+="</"+clone.firstChild.nodeName+">";  
          		}  
          		clone.removeChild(clone.firstChild)  
          	}  
          	return(text);  
          }  
          function beitrag(element){  
          	var div		=element.parentNode.getElementsByTagName('div')[0];  
          	var textarea	=document.createElement('textarea');  
          	textarea.value	=plain_HTML(div);  
          	element.value	="SAVE"  
          	element.onclick	=""  
            
          	while(div.firstChild)  
          		div.removeChild(div.firstChild);  
            
          	div.appendChild(textarea);  
          }
          

          Das ist leider nunmehr alles andere als -mal eben so- aus dem Ärmel geschüttelt. Aller Anfang ist schwer und ich bitte Dich, die Beispiele selbständig anhand der verschiedenen Verweise hier im Thread nachzuvollziehen und natürlich auch Dich auszuprobieren. ;)

          Gruß aus Berlin!
          eddi

          --
          VEB Opel, Geruchsproben und Stasi 2.0, Zensur...
          IHR WOLLTET MERKEL!
          1. Also noch mals vielen Dank euch allen!!!

            Eure Tipps haben mir sehr geholfen, in die Materie reinzukommen.

            Als ich gestern festgestellt habe, dass das DIV noch 4 weitere Child-Knoten hat, hatte ich mir währendessen eine eigene Funktion geschrieben, die aber bei weitem nicht so elegant wie die von Edgar ist und auch nicht rekursiv arbeitet, wie die von Edgar.

            for (var i = 0; i < div.childNodes.length ; i++)  
            {  
             if (div.childNodes[i].firstChild)  
             {  
               text = text + div.childNodes[i].firstChild.nodeValue  
               div.removeChild(div.childNodes[i].firstChild)  
             }  
             else  
                {  
                text = text + div.childNodes[i].nodeValue;  
                div.removeChild(div.childNodes[i])  
                }  
            }  
            
            

            Was bei mir nicht funktioniert, ist das "removeChild".
            Hätte gedacht, das sollte so gehen?!

            Wenn in dem Beispiel "<br>" oder "<p>" sind, so sollen die durch echte Zeilenumbrüche in der Textarea dargestellt werden. Kann man direkt einen Node darauf prüfen, ob er ein "<br>" ist?
            Hatte gesehen, dass wenn ich mir den Node anzeigen lasse, dieser als "HTMLBRelement" angezeigt wird. Kann ich darauf testen? Ist das Browsersicher?
            Bei einen "<p>" würd ich einen Stringvergleich machen ...

            Danke,
            Bert

            1. Hi,

              for (var i = 0; i < div.childNodes.length ; i++)

              {
              if (div.childNodes[i].firstChild)
              {
                 text = text + div.childNodes[i].firstChild.nodeValue
                 div.removeChild(div.childNodes[i].firstChild)
              }
              else
                  {
                  text = text + div.childNodes[i].nodeValue;
                  div.removeChild(div.childNodes[i])
                  }
              }

              
              >   
              > Was bei mir nicht funktioniert, ist das "removeChild".  
              > Hätte gedacht, das sollte so gehen?!  
                
              Was heisst "funktioniert nicht", und was hätte gehen sollen?  
                
              Mach dir klar, dass wenn du einen HTML-Element-Knoten mit removeChild entfernst, du alle seine Nachfahrenelemente gleich mit rauslöschst.  
                
              Wenn du von <div>Text Text Text</div> den Div entfernst, dann ist der darinb liegende Textknoten gleich mit hops.  
                
              
              > Kann man direkt einen Node darauf prüfen, ob er ein "<br>" ist?  
                
              [nodeName](http://de.selfhtml.org/javascript/objekte/node.htm#node_name)-Eigenschaft auswerten. (Da nicht so genau geregelt ist(?), wie das mit Gross-/Kleinschreibung aussieht, empfiehlt es sich, immer erst mittels strToLower zu "normalisieren", bevor man Vergleiche darauf durchführt.)  
                
              MfG ChrisB  
                
              
              -- 
              Light travels faster than sound - that's why most people appear bright until you hear them speak.
              
              1. nodeName-Eigenschaft auswerten. (Da nicht so genau geregelt ist(?), wie das mit Gross-/Kleinschreibung aussieht, empfiehlt es sich, immer erst mittels strToLower zu "normalisieren", bevor man Vergleiche darauf durchführt.)

                strToLower? du meinst http://de.selfhtml.org/javascript/objekte/string.htm#to_lower_case@title=toLowerCase()

                Struppi.

                  1. » strToLower? du meinst http://de.selfhtml.org/javascript/objekte/string.htm#to_lower_case@title=toLowerCase()

                    PHP-Programmierer, pah! *verächtlich lach* ;-)

                    Das war auch mein Gedanke, mir ist vorhin leider keine passende hämische Formulierung eingefallen, aber auch von mir ein: Pah! ;-)

                    Struppi.

              2. Lieber ChrisB,

                immer erst mittels strToLower zu "normalisieren"

                diese Funktion gibt es so nicht in JavaScript (in PHP dagegen schon) -
                Du meintest sicherlich String.[ref:self812;javascript/objekte/string.htm#to_lower_case@title=toLowerCase()]

                Liebe Grüße,

                Felix Riesterer.

                --
                ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
            2. Re:

              for (var i = 0; i < div.childNodes.length ; i++)

              {
              if (div.childNodes[i].firstChild)
              {
                 text = text + div.childNodes[i].firstChild.nodeValue
                 div.removeChild(div.childNodes[i].firstChild)

              // Du machst etwas grundsätzliches falsch.
                 // div.childNodes[i] wird nämlich in diesem Fall nicht gelöscht

              }
              else
                  {
                  text = text + div.childNodes[i].nodeValue;
                  div.removeChild(div.childNodes[i])
                  }
              }

                
              also wäre Folgendes für Dein eigentliches Ansinnen exakter (aber dennoch falsch, dazu aber gleich mehr):  
                
              ~~~javascript
              for (var i = 0; i < div.childNodes.length ; i++){  
              	if (div.childNodes[i].firstChild){  
              		text = text + div.childNodes[i].firstChild.nodeValue  
              		div.removeChild(div.childNodes[i].firstChild)  
              	}  
              	else{  
              		text = text + div.childNodes[i].nodeValue;  
              	}  
              	// jetzt wird immer gelöscht  
              	div.removeChild(div.childNodes[i])  
              	// Testausgabe 1:  
              	alert(div.childNodes.length);  
              }  
              // Testausgabe 2:  
              alert(div.childNodes[0].nodeName);
              

              Nun zu Deinem eigentlichen Fehler: div.childNodes.length verändert sich, wie "Testausgabe 1" verdeutlichen soll. Im ersten Durchlauf hast Du also noch volle vier Elemente, ziehst aber dann ein Element ab. Anders als bei einem array, den div.childNodes ist kein array sondern ein NodeList rutscht beim Löschen des ersten Elements das vormalig Zweite Element an die erste Stelle. Daher habe ich mit while (also ohne Zähler) gearbeitet.
              "Testausgabe 2" bestätigt dieses Verhalten, denn nach Deiner for-Schleife ist das erste Element (.childNode[0]) immernoch belegt.

              Leider gibt es noch einen weiteren, logischen Fehler in Deinem Programm:

              <div>Wo warst du?<br/>  
                 <p>Freu mich auf <span>deine</span> Erzählung</p>  
              </div>
              

              Hierbei wird der Inhalt <span> durch div.childNodes[i].firstChild nicht berücksichtigt. Es tut mir leid. Du musst es leider rekursiv angehen. ;(

              Gruß aus Berlin!
              eddi

              --
              Wer mit Kanonen auf Spatzen schießt, mag zwar immernoch Augen für die Tauben auf dem Dach haben, aber keine Hand mehr zum reichen.
              1. Und wieder "vielen Dank" :-)

                Ok, dann werd ichs heut abend mal rekursiv angehen mit der Sache.

                Was ich mit "geht nicht" in meinem vorigen Post meinte, war, dass der Childknoten nicht gelöscht worden ist. Also trotz "div.removeChild(xxxx)" blieben die Childs noch dran hängen. Ich hatte zwar die Textarea mit vollständigem Inhalt, aber der zweite Absatz war auch noch als normaler Text zu sehen.
                Aber evtl. liegt das am Verschieben der Knoten und meiner fehlerhaften Annahme, dass ich ein Array vor mir habe. Das mit dem Konzpet der NodeList muss ich mir mal mehr verdeutlichen.

                Ansonsten gaaaaaanz am Rande die Frage: wie merkt ihr, dass es in diesem Thread neue Beiträge gibt? Aufgrund der hohen Postingfrequenz bei SelfHTML rutscht ja ein Thema recht schnell ausser Sichtweite.
                Wie sind bspw. die "neuen" Mitschreiber wie molily und Struppi noch auf diesen Thread gestossen?

                Also, noch mal DANKE, DANKE, DANKE! und wünsche einen schönen Tag.

                1. Hi,

                  Ansonsten gaaaaaanz am Rande die Frage: wie merkt ihr, dass es in diesem Thread neue Beiträge gibt? Aufgrund der hohen Postingfrequenz bei SelfHTML rutscht ja ein Thema recht schnell ausser Sichtweite.
                  Wie sind bspw. die "neuen" Mitschreiber wie molily und Struppi noch auf diesen Thread gestossen?

                  Die haben entweder - Überraschung! -  die Scrollbar benutzt, die ihr Browser ihnen anbietet :-)
                  Oder vielleicht auch in ihren Benutzereinstellungen angegeben, dass sie die Threadliste anders sortiert haben möchten als in der Defaultansicht.

                  MfG ChrisB

                  --
                  Light travels faster than sound - that's why most people appear bright until you hear them speak.
                  1. Oder vielleicht auch in ihren Benutzereinstellungen angegeben, dass sie die Threadliste anders sortiert haben möchten als in der Defaultansicht.

                    und lassen sich die Threads markieren, wenn Chris mal Mist schreibt ;-)

                    @Bert84, als registrierter Benutzer hast du viele Möglichkeiten das Forum, bzw. die Art wie die Threads erscheinen, einzustellen.

                    Und ich glaube die Meisten, die hier regelmäßig posten, lassen es sich so sortieren, dass die Threads mit neuen Postings oben erscheinen. Daneben kann man auch einzelne Personen und Themen markieren die einen interssieren (in meinem Fall u.a. Javascript und ChrisB)

                    Struppi.

                    1. Hallo,

                      »» Oder vielleicht auch in ihren Benutzereinstellungen angegeben, dass sie die Threadliste anders sortiert haben möchten als in der Defaultansicht.

                      richtig, zum Beispiel vorwärts (neue Einträge ganz unten) anstatt rückwärts.

                      @Bert84, als registrierter Benutzer hast du viele Möglichkeiten das Forum, bzw. die Art wie die Threads erscheinen, einzustellen.

                      ACK. Damit sollte so ziemlich jeder Sortierwunsch erfüllt werden können.

                      Und ich glaube die Meisten, die hier regelmäßig posten, lassen es sich so sortieren, dass die Threads mit neuen Postings oben erscheinen.

                      Möglich - ich gehöre nicht dazu. Ich orientiere mich an der chronologischen Reihenfolge der Threads und würde durcheinanderkommen, wenn ein Thread von vorgestern plötzlich wieder ganz unten oder ganz oben stünde.

                      Daneben kann man auch einzelne Personen und Themen markieren die einen interssieren (in meinem Fall u.a. Javascript und ChrisB)

                      Darüber hinaus kann man noch Threads, die man komplett gelesen hat, automatisch "zuklappen" lassen, so dass nur noch der Link auf den Startbeitrag sichtbar ist. Sobald neue Beiträge im Thread dazukommen, wird der ganze Threadbaum wieder ausgeklappt. Sehr praktisch!

                      So long,
                       Martin

                      --
                      Der Alptraum jedes Computers:
                      "Mir war, als hätte ich gerade eine 2 gesehen."