Alle Kindknoten eines Knoten ermitteln ohne Rekursion

Parantatatam

mag Cookies & Kekse
Hallo Tutorianer,

meine letzte Aktivität hier liegt schon ein Weilchen zurück, aber ich bin gerade bei einem Problem, was ich zwar lösen könnte, aber für sehr unschön halte. Es geht darum, dass ich alle Knoten (also Text-Knoten und Element-Knoten) eines Elementes erhalten möchte, aber nicht nur die Kindknoten, sondern auch deren Kindknoten und deren Kindknoten und so weiter. Dabei ist mir aber wichtig, dass ich es nicht durch Rekursion lösen möchte. Folgende Ansätze habe ich bereits:
Code:
// Element, dessen Kindknoten durchlaufen werden sollen
var parent = document.getElementById('parent');

// == Ansatz 1
var children = parent.getElementsByTagName('*');

// == Ansatz 2
var children = parent.childNodes;
Beide Ansätze haben ein Problem, das jeweils durch den anderen Ansatz gelöst wird: Ansatz 1 liefert mir alle Element-Knoten, Ansatz 2 liefert mir alle direkten Text- und Element-Knoten.

Also meine konkrete Frage: Hat jemand sich bereits mal mit so etwas auseinandergesetzt oder könnte mir ad hoc einen schönen, kurzen, rekursionsfreien Ansatz für mein Problem nennen?
 
Ich danke dir vielmals, denn so sieht der Ansatz aus, denn ich wollte. Bisher wusste ich gar nicht, dass Javascript so etwas implementiert hat, also den TreeWalker – man lernt eben nie aus.
 
Ich werde mein kleines MDV-Framework erstmal soweit entwickeln, dass es fließend im Chrome 16 läuft, und dann auf solche Ausnahmen eingehen. Aber ich danke dir für den Hinweis.
 
Leider musste ich gerade einsehen, dass das, was ich mir so vorgestellt habe, nicht so geht, wie ich es mir eben vorgestellt habe. Denn leider fehlt jetzt der Bezug der Knoten zu ihrem eigentlichen HTML-Element. Mh, also erstmal hier meine Funktion (verzeiht, dass ich die ganze Funktion poste, aber anders kann man den Zusammenhang nicht erklären):
Code:
// setter for the <-model-> property
HTMLElement.prototype.__defineSetter__('model', function (value) {
  // break if value is no object (pseudo-associative array)
  if(typeof value !== 'object') {
    return;
  }
  
  // pre-define instance var as null so we can check if it was found
  var instance = null;
  
  // search for model instance of the current element
  for(var i = 0; i < instances.length; ++i) {
    if(instances[i][0] === this) {
      instance = instances[i];
    }
  }
  
  // check if element has model instance
  if(instance === null) {
    return;
  }
  
  // fetch all element sub nodes of the current element
  var node;
  var elements = [];
  var children = document.createTreeWalker(instance[1], NodeFilter.SHOW_ALL, null, false);
  
  // iterate through all nodes
  while(node = children.nextNode()) {
    // only select element nodes and text nodes containing text
    if((node.nodeType === 1) || ((node.nodeType === 3) && (node.nodeValue.search(/\S+/) !== -1))) {
      elements.push(node);
    }
  }
  
  var parents = [instance[1]];
  var scopes  = [];
  
  for(var i = 0; i < elements.length; ++i) {
    // element node
    if(elements[i].nodeType === 1) {
      var parent = parents[parents.length-1];
      // current element is on the same level as the element before
      if(elements[i].parentElement === parent) {
      // current element is on one level deeper then the element before (the element before is the parent element)
      } else if(i > 0 && elements[i].parentElement === elements[i-1]) {
        parents.push(elements[i-1]);
      // current element is on one level higher then the current parent element
      } else {
        while(elements[i].parentElement !== parent) {
          parent = parents.pop();
        }
        parents.push(parent);
      }
      
      // children inside this node should be iterated
      if(elements[i].getAttribute('iterate') !== null) {
        
      // children inside this node use a shortcut for the access to the model's values
      } else if(elements[i].getAttribute('scope') !== null) {
        
      // nothing special inside this node
      } else {
        
      }
    // text node with placeholder
    } else if(elements[i].nodeValue.search(/\{\{ *(\w+(\.\w+)*) *\}\}/) !== -1) {
      // fetch placeholders in the current text node
      var placeholders = elements[i].nodeValue.match(/\{\{ *(\w+(\.\w+)*) *\}\}/gi);
      // replace placeholders with its replacement value
      for(var j = 0; j < placeholders.length; ++j) {
        // fetch name of the placeholder
        var placeholder = placeholders[j].match(/\w+(\.\w+)*/gi)[0];
        // replace placeholder with its value
        elements[i-1].innerHTML = elements[i].nodeValue.replace(placeholders[j], value[placeholder]);
      }
    }
  }
  
  // set value as new value of the model instance
  models[instance[2]] = value;
});
Konkret geht es um Zeile 75, in welcher ich nun die Platzhalter ({{platzhalter}}) durch die entsprechenden Werte ersetzen will. Leider scheint aber die Verbindung zwischen dem Elementknoten und seiner Entsprechung im HTML-Quelltext verloren zu sein. Deshalb meine Frage:

Gibt es eine Möglichkeit diese Relation zu behalten oder muss ich das anders lösen?
 
Zuletzt bearbeitet:
Du brauchst doch gar kein innerHTML mehr, wenn du wirklich nur den Textknoten ändern willst.

textKnoten.nodeValue = 'foo';

Ich habe mir aber ehrlich gesagt außer Zeile 75 nichts angeguckt. Also vielleicht willst du auch was anderes.

Ich hatte mal angefangen eine Bibliothek zur Manipulation von Textknoten zu erstellen: https://github.com/Prinzhorn/Linguigi vielleicht ist da was inspirierendes drin.

Ich nehme an du erstellst etwas Richtung knockout.js?
 
Den Ansatz, denn du gerade meintest, hatte ich als ersten. Da dieser aber nicht funktionierte, habe ich eben diesen hier ausprobiert. Aber ich habe so eben rausgefunden, warum das hier nicht funktioniert hat: ich habe an einem Klon des Original-Elements gearbeitet. Das konnte natürlich nicht funktionieren.

Ich weiß leider nicht, was knockout.js ist, aber ich arbeite an etwas Ähnlichem zu dem MDV-Projekt von Chrome. Letztendlich soll man das Layout von Skripten komplett befreien durch eine Kombination aus Observern und Modeln.

Beispiel:
Code:
var links = document.getElementById('links');
links.observer = {
  // on click
  click: function () {
    document.getElementById('content').model = {
      headline: 'angeklickter Artikel'
    };
  },
  // on double-click
  dblclick: function () {
    document.getElementById('content').model = {
      headline: 'doppelt angeklickter Artikel'
    };
  }
};

document.getElementById('content').model = {
  headline: 'Erster Artikel'
};
HTML:
<div id="content" model="content">
  <h1>{{headline}}</h1>
</div>
<ul id="links">
  <li><a href="#article1">Artikel 1</a></li>
</ul>
 
Zurück