# Eigenes HTML-Element definieren



## Parantatatam (7. Februar 2012)

Hallo Tutorianer,

ich fragte mich gerade, ob der Chrome einfach keine selbst definierten Elemente erkennt oder erkennen will, oder ob ich nicht noch etwas vergessen habe als ich mein eigenes Objekt definierte. Folgendes habe ich bereits:

```
HTMLTemplateElement = {
  content: null,
}
HTMLTemplateElement.prototype = HTMLElement;
```
Wenn ich jetzt ein solches Template-Element in meinem Quelltext platziere und aufrufe, dann gibt mir der Chrome als Elementyp _HTMLUnknownElement_ aus. Ebenso kann ich nicht auf die Eigenschaft _content_ zugreifen. Gleiches ist der Fall, wenn ich ein Element mit _document.createElement('template')_ erstelle.

Übersehe ich da etwas? Vielleicht muss man die Elemente auch vorher mit einer Methode registrieren, damit diese verfügbar sind.


----------



## tobee (8. Februar 2012)

Laut meinem Test in JSFiddle* kann man mit JS das HTML von einem selbst definierten Html Element lesen.
Soll dein Element sich anders als ein reguläres Html Element verhalten?

* http://jsfiddle.net/wfykP/


----------



## Parantatatam (8. Februar 2012)

Ja, es soll noch andere Attribute erhalten. Deshalb ist das etwas nervig mit den unbekannten Elementtypen, da diese logischerweise nicht die selbstdefinierten Attribute enthalten und somit beim Versuch darauf zuzugreifen eine Warnmeldung anzeigen.


----------



## tobee (8. Februar 2012)

Eigene Attribute lassen sich ja auch auslesen: http://jsfiddle.net/wfykP/1/
Oder hatte ich dich falsch verstanden?


----------



## Parantatatam (8. Februar 2012)

So war das nicht gemeint sondern Attribute des Elements, eher eine Art Methode. Beispielsweise brauche ich ein Attribut _content_, das den Quelltext des enthaltenen _content_-Elements ausgibt:

```
<decorator>
  <content>
    Inhalt des Dekorators
  </content>
</decorator>
```


```
var decorator = document.getElementsByTagName('decorator')[0];
decorator.content; // Gibt "Inhalt des Dekorators" aus
```


----------



## tobee (8. Februar 2012)

Du könntest das mit jQuery parseXML machen:

```
<html>

<head>
<script type="text/javascript">
function usemytag()
{
    var tag = document.getElementsByTagName('mytag')[0];
    var html = tag.innerHTML;
    var xml = jQuery.parseXML(html);
    console.log($(xml).find('decorator').find('content').text());
}
</script>
</head>

<body>
<mytag myAttribute="myValue">
    <decorator>
  <content>
    Inhalt des Dekorators2
  </content>
</decorator>

    </mytag><br>
<input type="button" value="Use My Tag" onclick="usemytag();">
</body>

</html>
```
http://jsfiddle.net/wfykP/4/


----------



## Parantatatam (8. Februar 2012)

Das hätte ich auch noch erwähnen sollen: jQuery ist nicht, genauso wenig wie jedes andere Framework.


----------



## tobee (8. Februar 2012)

einfach nur crack hat gesagt.:


> Das hätte ich auch noch erwähnen sollen: jQuery ist nicht, genauso wenig wie jedes andere Framework.


Was meinst du mit "ist nicht". Ist nicht gut? Ist nicht geeignet?
Du möchtest quasi das es nativ im Browser (Chrome) funktioniert?


----------



## wollmaus (8. Februar 2012)

Das, was du willst, ist das Erweitern des HTMLElement-prototypes. Darüber wäre es möglich, alle HTML-Elemente um eine eigene Methode zu Erweitern, welche bspw. den Inhalt  des Kind-<content/> eines Elementes liefert. 

Knackpunkt: nicht alle Browser stellen einen constructor für (HTML)Element zur Verfügung. Abgesehen davon gibt es eine Menge Gründe, das DOM nicht zu erweitern

Also besser: Finger weg davon. 

Und auch wenn du jQuery nicht leiden kannst: das ist einer der Gründe, warum jQuery im Laufe der Jahre andere Frameworks so weit hinter sich gelassen hat, es fummelt nicht wie die Kontrahenten am DOM herum. 

Wenn du dich also (hoffentlich)entschliessen solltest,  die Idee mit der DOM-Erweiterung zu vergessen, kommst du über kurz oder lang auf eine Lösung, die dem Ansatz von jQuery ähnelt(und wirst jQuery dann nicht mehr doof finden).


----------



## Parantatatam (8. Februar 2012)

Es geht mir nicht darum, dass ich jQuery nicht mag, aber es geht mir darum eine möglichst einfache Lösung zu finden, die nicht auf ein Framework setzt. Außerdem sind mir die Probleme beim Erweitern des DOM bekannt, dass stört mich aber in erster Linie nicht.

Trotzdem mag ich wissen, wie das jetzt genau aussehen muss.


----------



## wollmaus (9. Februar 2012)

```
HTMLElement.prototype.content=function()
{
  return(
          (this.getElementsByTagName('content').length)
            ? this.getElementsByTagName('content')[0].textContent
            : null
        );
}
```

Guggsdu: http://jsfiddle.net/t59gq/


----------



## Parantatatam (9. Februar 2012)

Aber damit erweitere ich doch nur das HTMElement und definiere kein eigenes neues HTML-Element..


----------



## wollmaus (9. Februar 2012)

Du kannst mit Javascript kein neues HTML-Element definieren. HTML-Elemente werden definiert durch die DTD, und wenn das Element in der HTML-DTD nicht definiert ist, dann gibt es das in HTML  nicht. 

Um ein eigenes Element zu definieren musst du also eine eigene DTD erstellen, diese kannst du dann referenzieren.
Referenzieren geht entweder dokumentweit oder per Element, aber wie auch immer, dein Dokument wird dann kein gültiges HTML-Dokument, es ist XML.

Prominenter Anwendungsfall ist Facebook, die <fb:irgendwas>-Tags der FBML sind dir sicher schon mal begegnet. Aber: auch mit Milliarden in der Hinterhand wird daraus kein HTML, diese Elemente wurden im Nachhinein per JS durch HTML-Elemente ersetzt. 
*Info:* Diese Vorgehensweise fanden die Entwickler anscheinend auf Dauer nicht mehr für anstrebenswert, FBML wird ab Juni 2012 nicht mehr unterstützt.


----------



## Parantatatam (9. Februar 2012)

Du brauchst mir nicht die Grundidee hinter HTML, XML und DTD erklären, denn diese kenne ich ausreichend. Aber ich weiß, dass man gerade in Hinsicht auf HTML5, beispielsweise in alten Versionen des Internet Explorers, die neuen Elemente, die im Quelltext enthalten sind, registrieren konnte und musste, damit der IE dieses als HTML-Elemente erkannt hat. Also muss es doch einen Ansatz geben, wie ich das lösen kann.


----------



## wollmaus (9. Februar 2012)

Du hast recht, ich brauch dir nichts erklären, anstatt zu erzählen dass du eh alles weisst:



> _Du brauchst mir nicht die Grundidee hinter HTML, XML und DTD erklären, denn diese kenne ich ausreichend. _
> [...]
> _Außerdem sind mir die Probleme beim Erweitern des DOM bekannt, dass stört mich aber in erster Linie nicht._



könntest du dir Wissen verschaffen, anstatt hier die OOP/DOM-Basics abzufragen, von denen du, mit Verlaub erwähnt, angesicht der von dir geposteten Codeschnipsel nur sehr rudimentäre Kenntnisse zu Haben scheinst.


----------



## Parantatatam (9. Februar 2012)

Ich glaube wir verstehen uns gerade sehr falsch, denn ich arbeite nicht erst seit kurzer Zeit mit Webanwendungen, sondern meine Anfänge liegen schon mindestens sechs Jahre zurück und in der Zeit habe ich mich viel und intensiv mit Sprachen wie PHP, Javascript, HTML, XML, CSS, Ruby, Java und C sowie Webtechnologien, Protokollen und Strukturen beschäftigt und habe somit einen recht guten Überblick darüber, wie das hier alles zusammen läuft.

Außerdem steht für mich nicht die Frage im Raum, wie ich denn jetzt ein Element als Objekt definiere, so dass es von einem anderen Objekt erbt, sondern es geht mir allein darum, dass es eine Möglichkeit geben muss, damit Browser beim Parsen dieses Objektes erkennen, dass es eben ein eigen-definiertes Element ist.

Um mal ein wenig mehr Code zu liefern:

```
<!DOCTYPE html>
<html>
<head>
  <title>custom elements</title>
  <script type="text/javascript" src="elements.js"></script>
  <script type="text/javascript">
    window.addEventListener('DOMContentLoaded', function () {
      var elements = ['template', 'content'];
      for(var element in elements) {
        var nodes = document.getElementsByTagName(element);
        for(var i = 0; i < nodes.length; ++i) {
          var replace = document.createElement(element);
          replace.innerHTML = nodes[i].innerHTML;
          nodes[i].parentElement.replaceChild(replace, nodes[i]);
        }
      }
    }, false);
  </script>
</head>
<body>
  <template>
    <content>Inhalt des Templates</content>
  </template>
</body>
</html>
```


```
HTMLTemplateElement = {};
HTMLTemplateElement.prototype = HTMLElement;
HTMLTemplateElement.prototype.__defineGetter('content', function () {
  var content = this.getElementsByTagName('content');
  return (content.length === 0) ? null : content[0];
}, false);
HTMLContentElement = {};
HTMLContentElement.prototype = HTMLElement;
```
Das Problem ist: auch _documen.createElement(...);_ gibt mir ein Objekt vom Typ _HTMLUnknownElement_ aus.

––––––
Ansonsten: Ich verbiete mir diesen Ton und ich finde es echt grenzwertig wie du hier willkürlich über die Kenntnisse von anderen urteilst. Wenn es für dich die falsche Uhrzeit ist, dann halte dich lieber zurück, bevor du hier abfällig bewertest und sprichst. Aber das nur für deine Zukunft.


----------



## wollmaus (9. Februar 2012)

```
HTMLTemplateElement = {};
HTMLTemplateElement.prototype = HTMLElement;
```

Dir ist angesichts deiner jahrelangen Erfahrung hoffentlich klar, dass dieser Code eine [Object]-instance namens "HTMLTemplateElement" erstellt.

Der constructor deines HTMLTemplateElement ist somit [Object], und das bleibt er auch. Daraus wird kein [HTMLElement] irgendwelcher Art mehr. 

Diese Zeile :

```
HTMLTemplateElement.prototype = HTMLElement;
```
fügt deiner Object-instance eine Eigenschaft "prototype" hinzu, mehr nicht.

Wenn HTMLTemplateElement etwas erben soll/kann, dann tut es das von Object.prototype , von nichts Anderem.


Auch wenn du es nicht wahrhaben willst, die einzige Methode, ein HTML-Element zu erzeugen ist createElement(), das ist es was das DOM und das JS-API der Browser zur Verfügung stellt. Wenn es dir nicht passt, musst du dir einen eigenen Browser programmieren, der dir das gewünschte Handwerkszeug (einen HTMLElement-constructor) bereitstellt.


Um letztendlich auf deinen ersten Codeabschnitt einzugehen:
dies hier:

```
for(var element in elements)
```
dir ist schon klar, dass diese Art Objekte zu durchlaufen in JS Schlüssel(label) liefert und keine Werte(übrigens sollte man diese Methode nur auf [Object] anwenden und nicht auf [Array] oder Sonstiges).

*element* hat da also die Werte 0 und 1, das sind die numerischen Schlüssel des Arrays.


----------



## Parantatatam (9. Februar 2012)

Erkenntnis 1: Ich sollte ebenfalls nicht mitten in der Nacht Beiträge verfassen.
Erkenntnis 2: Ich sollte vorher meine Skripte ausprobieren und sie nicht direkt hier schreiben.

Du hast natürlich in allen Punkten Recht und ich weiß das auch, aber es war spät. Also so sollte es eigentlich aussehen:

```
<!DOCTYPE html>
<html>
<head>
  <title>custom elements</title>
  <script type="text/javascript" src="elements.js"></script>
  <script type="text/javascript">
    window.addEventListener('DOMContentLoaded', function () {
      var elements = ['template', 'content'];
      for(var j = 0; j < elements.length; ++j) {
        var nodes = document.getElementsByTagName(elements[j]);
        for(var i = 0; i < nodes.length; ++i) {
          var replace = document.createElement(element);
          replace.innerHTML = nodes[i].innerHTML;
          nodes[i].parentElement.replaceChild(replace, nodes[i]);
        }
      }
    }, false);
  </script>
</head>
<body>
  <template>
    <content>Inhalt des Templates</content>
  </template>
</body>
</html>
```


```
HTMLTemplateElement = function () {};
HTMLTemplateElement.prototype = new HTMLElement();
HTMLTemplateElement.prototype.constructor = HTMLTemplateElement;
HTMLTemplateElement.prototype.__defineGetter('content', function () {
  var content = this.getElementsByTagName('content');
  return (content.length === 0) ? null : content[0];
}, false);
HTMLContentElement = function () {};
HTMLContentElement.prototype = new HTMLElement();
HTMLContentElement.prototype.constructor = HTMLContentElement;
```
Hierbei entsteht aber noch das Problem, dass man von _HTMLElement_ keine Instanzen erstellen kann, da diese Klasse keinen Konstruktor besitzt.


----------

