Der arme, missverstandene Innentext

Wenige Dinge werden im Web so missverstanden und missbraucht wie innerTextEigentum.

Diese skurrile, nicht standardmäßige Methode zum Abrufen von Elementtext , die vom Internet Explorer eingeführt und aus Gründen der Webkompatibilität von WebKit / Blink und Opera "kopiert" wurde. Es wird normalerweise in Kombination mit textContent- als browserübergreifende Methode zur Verwendung von Standardeigenschaften gefolgt von einer proprietären gesehen:

 <div> foo <span> bar </ span> baz </ div>
var text = element.textContent || element.innerText; // "foo bar baz"

Oder als Hauptverursacher von Webcompat in zahlreichen Mozilla-Tickets - da Mozilla einer der wenigen großen Browser ist, die sich weigern, diese nicht standardmäßige Eigenschaft hinzuzufügen - wenn jemand nicht weiß, was er tut, textContent"Fallback" auslassen:


     newDiv . get ( 0 ). innerText  =  $ ( this ) [ 0 ]. Titel ; // schlägt in Mozilla fehl
     
 

innerTextist so ziemlich immer verpönt. Warum sollten Sie eine Nicht-Standard-Eigenschaft verwenden, die das Gleiche wie eine Standard-Eigenschaft tut? Nur sehr wenige Leute wagen es, die Unterschiede tatsächlich zu überprüfen, und auf den ersten Blick sieht es so aus, als gäbe es keine. Diejenigen, die neugierig genug sind, um weitere Nachforschungen anzustellen , finden sie normalerweise , aber nur geringfügige, und zwar nur, wenn sie Text abrufen, ohne ihn zu setzen .

2009 habe ich genau das getan. Und ich habe diese StackOverflow-Antwort sogar über die genauen Unterschiede geschrieben - geringfügige Leerzeichenabweichungen, Dinge wie die Einbeziehung von <script> -Inhalten durch textContent(aber nicht innerText), Unterschiede in der Benutzeroberfläche ( Nodevs. HTMLElement) und so weiter.

Die ganze Zeit war ich fest davon überzeugt , dass es nicht viel anderes wissen textContentvs. innerText. Lenken Sie einfach ab innerText, verwenden Sie diese "Kombo" für browserübergreifenden Code, beachten Sie die geringfügigen Unterschiede, und Sie sind goldrichtig.

Ich wusste nicht, dass ich nur auf die Spitze des Eisbergs schaute und dass sich meine Wahrnehmung innerTextdrastisch ändern wird. Was Sie gleich hören werden, ist die Geschichte, in der Internet Explorer etwas richtig macht, die tatsächlichen Unterschiede zwischen diesen Eigenschaften und wie wir dieses rothaarige Stiefkind wahrscheinlich standardisieren wollen.

Der wahre Unterschied

Vor einiger Zeit half ich jemandem bei der Implementierung des Texteditors in einem Browser. Dabei wurde mir klar, wie lächerlich wichtig diese scheinbar unbedeutenden Leerzeichenabweichungen zwischen textContentund innerTextsind.

Hier ist ein einfaches Beispiel:

Beachten Sie, wie innerTextfast genau repräsentiert genau , wie der Text auf der Seite angezeigt wird . textContentAuf der anderen Seite macht es etwas Seltsames - es ignoriert Zeilenumbrüche, die von <br> und um blockartige Elemente (in diesem Fall <span>) erstellt wurden. Es werden jedoch Leerzeichen beibehalten, wie sie im Markup definiert sind. Was macht es eigentlich?

Wenn wir uns die Spezifikation ansehen , erhalten wir Folgendes:

Dieses Attribut gibt den Textinhalt dieses Knotens und seiner Nachkommen zurück. [...]

Beim Abrufen wird keine Serialisierung durchgeführt, der zurückgegebene String enthält kein Markup. Es wird keine Leerraumnormalisierung durchgeführt und die zurückgegebene Zeichenfolge enthält keine Leerzeichen im Elementinhalt (siehe Attribut Text.isElementContentWhitespace). [...]

Die zurückgegebene Zeichenfolge besteht aus dem Textinhalt dieses Knotens, abhängig von seinem Typ, wie unten definiert:

Für ELEMENT_NODE , ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, DOCUMENT_FRAGMENT_NODE:

     Verkettung des Attributwerts textContent jedes untergeordneten Knotensmit Ausnahme der Knoten COMMENT_NODE und PROCESSING_INSTRUCTION_NODE. Dies ist die leere Zeichenfolge, wenn der Knoten keine untergeordneten Elemente hat.

Für TEXT_NODE , CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE

     nodeValue

Mit anderen Worten, es wird textContentverketteter Text aller Textknoten zurückgegeben. Das ist fast so, als würde man Markup (dh innerHTML) nehmen und von den Tags entfernen. Beachten Sie, dass keine Whitespace-Normalisierung durchgeführt wird. Text und Whitespace werden im Wesentlichen so ausgespuckt, wie sie im Markup definiert sind . Wenn Sie in der HTML-Quelle einen riesigen Teil von Zeilenumbrüchen haben, werden Sie diese auch als Teil davon haben textContent.

Bei der Untersuchung dieser Probleme stieß ich auf einen fantastischen Blogbeitrag von Mike Wilcox aus dem Jahr 2010, der so ziemlich der einzige Ort ist, an dem jemand versucht, auf dieses Problem aufmerksam zu machen. Darin trifft Mike auf die gleichen Dinge zu, die ich hier beschreibe, und sagt diese zutreffenden Worte:

Internet Explorer hat innerText in Version 4.0 implementiert und es ist eine nützliche Funktion, wenn sie missverstanden wird. [...]

Die häufigste Verwendung für diese Eigenschaften ist die Arbeit an einem Rich-Text-Editor, wenn Sie "Nur-Text" benötigen oder aus anderen funktionalen Gründen. [...]

Da keine Whitespace-Normalisierung durchgeführt wird, verhält sich textContent im Wesentlichen wie ein PRE-Element. Das Markup wird entfernt, aber ansonsten erhalten wir genau das, was im HTML-Dokument enthalten war - einschließlich Tabulatoren, Leerzeichen, fehlenden Leerzeichen und Zeilenumbrüchen. Es holt sich den Quellcode aus dem HTML! Was das bringt, weiß ich wirklich nicht.

Wenn wir diese Unterschiede kennen, können wir sehen, wie irreführend (und gefährlich) ein typischer textContent || innerTextAbruf sein kann. Es ist fast so, als würde man sagen:

  Element . Apfel  ||  Element . Apfelsoße 

Der Fall für innerText

Zurück zu einem Texteditor ...

Nehmen wir an, wir haben einen inhaltsbearbeitbaren Bereich, in dem ein Benutzer etwas schreibt. Und wir möchten eine eigene Rechtschreibkorrektur für einen Text in diesem Bereich haben. Zu diesem Zweck möchten wir Text genau so analysieren, wie er im Browser und nicht im Markup angezeigt wird. Wir möchten wissen, ob ein Benutzer Zeilenumbrüche oder Leerzeichen eingibt, und nicht diejenigen, die sich im Markup befinden, damit wir den Text entsprechend korrigieren können.

Dies ist nur ein Anwendungsfall für das Abrufen von Klartext. Vielleicht möchten Sie geschriebenen Text in ein anderes Format konvertieren (PDF, SVG, Bild über Leinwand usw.). In diesem Fall muss der Text genau so aussehen, wie er eingegeben wurde. Oder Sie müssen die Cursorposition in einem Text (oder in seiner gesamten Länge) kennen, damit Sie einen Text so bearbeiten können, wie er dargestellt wird.

Ich bin mir sicher, dass es noch mehr Szenarien gibt.

Eine gute Möglichkeit, darüber nachzudenken, innerTextbesteht darin, dass der Text ausgewählt und von der Seite kopiert wurde. Genau das macht WebKit / Blink - es verwendet denselben Code für die Selection#toStringSerialisierung und innerText!

Apropos - wenn innerTextes im Wesentlichen dasselbe ist wie eine stringierte Auswahl, sollte es nicht möglich sein, sie über zu emulieren Selection#toString?

Es ist sicher, aber wie Sie sich vorstellen können, lässt die Leistung solcher Dinge zu wünschen übrig - wir müssen die aktuelle Auswahl speichern, dann die Auswahl so ändern, dass sie den gesamten Elementinhalt enthält, die Zeichenfolgendarstellung abrufen und dann die ursprüngliche Auswahl wiederherstellen:

 
    function getSelectionString(el, win) {
    win = win || window;
    var doc = win.document, sel, range, prevRange, selString;
    if (win.getSelection && doc.createRange) {
        sel = win.getSelection();
        if (sel.rangeCount) {
          prevRange = sel.getRangeAt(0);
        }
        range = doc.createRange();
        range.selectNodeContents(el);
        sel.removeAllRanges();
        sel.addRange(range);
        selString = sel.toString();
        sel.removeAllRanges();
        prevRange && sel.addRange(prevRange);
    } 
    else if (doc.body.createTextRange) {
        range = doc.body.createTextRange();
        range.moveToElementText(el);
        range.select();
    }
    return selString;
}
    

Die Probleme mit diesem Frankenstein einer Problemumgehung sind Leistung, Komplexität und Klarheit. Es sollte nicht so schwer sein, eine "Klartext" -Darstellung eines Elements zu erhalten. Besonders wenn es eine bereits "implementierte" Eigenschaft gibt, die genau das tut.

Internet Explorer hat das richtig verstanden - textContentund Selection#toStringist in solchen Fällen ein schlechter Konkurrent. innerTextist genau das, was wir brauchen. Außer, dass es nicht dem Standard entspricht und nicht von einem großen Browser unterstützt wird. Zum Glück waren zumindest Chrome (Blink) und Safari (WebKit) rücksichtsvoll genug, um dies nachzuahmen. Man würde hoffen, dass es keine Abweichungen zwischen ihren Implementierungen gibt. Oder ist da?

Unterschiede zu textContent

Als ich die Bedeutung von erkannte innerText, wollte ich die Unterschiede zwischen zwei Motoren sehen. Da es da draußen nichts Vergleichbares gab, machte ich mich auf den Weg, um es zu erkunden. In wahren "Cross-Browser-Madness" -Traditionen war das, was ich gefunden habe, nichts für schwache Nerven.

Ich habe mit der (inzwischen ausgestorbenen) Testsuite von Aryeh Gregor begonnen und ein paar weitere Dinge hinzugefügt . Ich habe auch nach WebKit / Blink-Bug-Trackern gesucht und alle relevanten Dinge aufgenommen, die ich dort gefunden habe.

Die Tabelle oben (und in der Testsuite) zeigt alle wichtigen Details, aber nur wenige erwähnenswerte Punkte. Erstens: Gute Nachrichten - Internet Explorer <= 9 verhalten sich identisch :) Jetzt schlecht - alles andere läuft anders. Sogar IE-Änderungen mit jeder neuen Version - 9, 10, 11 und Tech Preview (die unveröffentlichte Version von IE, die derzeit in Vorbereitung ist) sind unterschiedlich. Interessant ist auch, wie WebKit einige der alten IE-Merkmale kopiert hat - z. B. den Verzicht auf den Inhalt von <script> - und <style> -Elementen - und als sich der IE änderte, traten diese natürlich auseinander. Derzeit ähnelt das Verhalten von WebKit / Blink zum Teil dem des alten IE, zum Teil nicht. Aber selbst im Vergleich zu den Originalversionen hat WebKit diese Funktion schlecht kopiert, oder besser gesagt, sie haben versucht, sie zu verbessern !

Im Gegensatz zum IE können mit WebKit / Blink Tabulatoren zwischen Tabellenzellen eingefügt werden. Sie bewahren auch Text in Groß- / Kleinschreibung, was wohl besser ist. Sie enthalten keine versteckten Elemente ("Anzeige: keine", "Sichtbarkeit: versteckt"), was ebenfalls sinnvoll ist. Und sie enthalten keine Inhalte von <select> -Elementen und <canvas> / <video> -Fallback - vielleicht ein fragwürdiger Aspekt -, aber auch vernünftig.

Ok, es gibt noch mehr gute Neuigkeiten.

Beachten Sie, dass IE Tech Preview (Spartan) jetzt viel näher an WebKit / Blink ist. Es gibt nur 9 Aspekte, in denen sie sich unterscheiden (im Vergleich zu 10-11 in früheren Versionen). Das ist immer noch viel , aber es gibt zumindest einige Hoffnung für die Konvergenz. Vor allem hat der IE wieder aufgehört, <script> - und <style> -Inhalte einzuschließen, und - zum ersten Mal überhaupt - aufgehört, "display: none" -Elemente einzuschließen (aber nicht "visible: hidden" - dazu später mehr).

Opera Chaos

Möglicherweise haben Sie den Mangel an Opera in einem Tisch festgehalten. Es liegt nicht nur daran, dass Opera jetzt die Blink-Engine verwendet (im Wesentlichen mit WebKit-Verhalten). Es liegt auch an der Tatsache, dass es, wenn es nicht auf Blink war, wirklich ungezogen war, wenn es darum geht innerText. Um die Web-Kompatibilität aufrechtzuerhalten, ging Opera einfach vor und "stimmte" innerTextzu textContent. Das ist richtig, würde in Opera innerTextnichts in der Nähe von dem, was wir in IE oder WebKit sehen, zurückgeben. Es hat einfach keinen Sinn, in eine Tabelle aufzunehmen. es würde sich in jedem einzelnen Aspekt unterscheiden, und wir können es einfach als nie umgesetzt betrachten.

Hinweis zur Leistung

Ein weiterer Unterschied lauert hinter textContentund innerText- Leistung.

Sie können Dutzende von finden Tests auf jsperf.com zu vergleichen und innertext textcontent - innerTextist oft Dutzende Zeit langsamer.

In diesem Blogbeitrag spricht Kelly Norton davon innerText, bis zu 300x langsamer zu sein (obwohl dies ein besonders seltener Fall zu sein scheint) und rät davon ab, ihn vollständig zu verwenden.

Dies sollte nicht überraschen, wenn man die zugrunde liegenden Konzepte beider Eigenschaften kennt. Schließlich sind Layoutkenntnisse innerTexterforderlich und alles, was das Layout berührt, ist teuer .

Also in jeder Hinsicht innerTextdeutlich langsamer als textContent. Und wenn Sie lediglich einen Text eines Elements ohne Stilbewusstsein abrufen möchten, sollten Sie auf jeden Fall textContentstattdessen verwenden. Dieses Stilbewusstsein innerTextist jedoch genau das , was wir zum Abrufen von Text "wie dargestellt" benötigen. und das kommt mit einem Preis.

Was ist mit jQuery?

Sie sind wahrscheinlich mit der text()Methode von jQuery vertraut . Aber wie genau funktioniert es und was nutzt es - textContent || innerTextCombo oder etwas anderes? Es hat sich herausgestellt, dass jQuery einen sicheren Weg einschlägt - entweder wird es zurückgegeben textContent(falls verfügbar) oder es wird manuell ausgeführt, was textContentzu tun ist - und alle untergeordneten Elemente werden durchlaufen und ihre verkettet nodeValue. Offenbar jQuery an einem Punkt tat Gebrauch innerText, aber dann lief in guten alten Leerzeichen Unterschiede und beschlossen , es ganz zu Graben.

Wenn wir also jQuery verwenden möchten, um eine echte Textdarstellung (à la innerText) zu erhalten, können wir jQuery nicht verwenden, text()da es sich im Grunde um einen Cross-Browser handelt textContent. Wir müssten unsere eigene Lösung entwickeln.

Standardisierungsversuche

Hoffentlich habe ich dich inzwischen davon überzeugt, dass innerTextdas verdammt nützlich ist. Wir gingen auf das zugrunde liegende Konzept, die Unterschiede im Browser und die Auswirkungen auf die Leistung ein und stellten fest, dass selbst eine mächtige jQuery keine Hilfe ist.

Sie würden denken, dass diese Eigenschaft inzwischen standardisiert ist oder zumindest ihren Weg in den Standard findet.

Na ja, nicht so schnell.

Bereits 2010 schlug Adam Barth (von Google) vor, innerText in einer WHATWG-Mailingliste anzugeben . Es ist schon komisch, dass alles, was Adam möchte, darin besteht, reinen Text (kein Markup!) Eines Elements auf sichere Weise festzulegen. Er weiß auch nichts darüber textContent, was sicherlich ein bevorzugter (Standard-) Weg wäre, dies zu tun. Zum Glück meldet sich Mike Wilcox, dessen Blogbeitrag ich bereits erwähnt habe, bei:

Zusätzlich zu Adams Kommentaren gibt es keine standardmäßige, stabile Methode , um den Text aus einer Reihe von Knoten zu erhalten. textContent gibt alles zurück, einschließlich Tabulatoren, Leerzeichen und sogar Skriptinhalt. [...] innerText ist genau wie innerHTML eines der Dinge, die der IE richtig gemacht hat. Lassen Sie uns bitte überlegen, dies als Standard zu definieren, anstatt ihn zu entfernen.

Im selben Thread bezweifelt Robert O'Callahan (von Mozilla) die Nützlichkeit von innerText , fügt jedoch hinzu:

Aber wenn Mike Wilcox oder andere behaupten wollen, dass innerText eine nützliche und notwendige Funktion ist, sollten wir es hören. Oder wenn jemand von Webkit oder Opera erklären möchte, warum er es hinzugefügt hat, wäre das auch nützlich.

Ian Hixie ist offen, es zu einer Spezifikation hinzuzufügen, wenn es für die Webkompatibilität benötigt wird. Während Rob O'Callahan dies für überflüssig hält, trifft Maciej Stachowiak (von WebKit / Apple) mit dieser fantastischen Antwort den Nagel auf den Kopf :

Ist es eine wirklich nützliche Funktion? Ja, die Fähigkeit, Klartextinhalte so abzurufen, wie sie gerendert werden, ist eine nützliche Funktion, deren Implementierung von Grund auf ärgerlich ist. Um einen sehr marginalen Datenpunkt anzugeben, wird er von unserem Regressionstext-Framework verwendet, um die Klartextversion einer Seite auszugeben, für Tests, bei denen das Layout irrelevant ist. Eine hypothetischere Verwendung wäre ein Rich-Text-Editor mit der Funktion "In Klartext konvertieren". textContent ist für diese Anwendungsfälle nicht so nützlich, da Zeilenumbrüche und nicht gerenderte Leerzeichen nicht ordnungsgemäß verarbeitet werden.
[...]
Diese Faktoren würden dazu neigen, sie zu beseitigen.

Auf die Rob eine vernünftige Antwort gibt:

Es gibt viele Möglichkeiten, wie die Leute das tun könnten. Beispielsweise werden bei der Konvertierung in Klartext häufig Zeichen für Aufzählungszeichen (z. B. '*') und Artikelnummern eingefügt. (Zum Beispiel Mac TextEdit.) Safari 5 funktioniert auch nicht. [...] Es kann schwierig sein, mehr als eine kleine Anzahl potenzieller Benutzer mit einem einzigen Attribut zufrieden zu stellen.

Und das Gespräch hört auf.

Ist innerText wirklich nützlich?

Rob weist darauf hin, dass "In Klartext konvertieren" sicherlich eine mehrdeutige Aufgabe sein könnte. Tatsächlich können wir leicht ein Test-Markup erstellen, das nichts mit seiner "Nur-Text" -Version zu tun hat:

Beachten Sie, dass "opacity: 0" -Elemente nicht angezeigt werden, jedoch Teil von sind innerText. Das Gleiche gilt für die berüchtigte "Text-Indent: -999px" -Technik. Die Aufzählungszeichen aus der Liste werden nicht berücksichtigt und es wird auch kein Inhalt dynamisch generiert (über :: after pseudo selector). Absätze erzeugen nur eine neue Zeile, obwohl sie in Wirklichkeit gigantische Ränder haben könnten.

Aber ich denke das ist OK.

Wenn Sie sich einen innerTextvon der Seite kopierten Text vorstellen, sind die meisten dieser "Artefakte" durchaus sinnvoll. Nur weil ein Textblock mit "Deckkraft: 0" versehen ist, bedeutet dies nicht, dass er nicht Teil der Ausgabe sein sollte. Es ist ein rein präsentatives Anliegen, genau wie Aufzählungszeichen, Leerzeichen zwischen Absätzen oder eingerückter Text. Entscheidend ist der Erhalt der Struktur - Elemente im Blockstil sollten Zeilenumbrüche erzeugen, Inline-Elemente sollten Inline-Elemente sein.

Ein zweifelhafter Aspekt ist wahrscheinlich "Texttransformation". Soll großgeschriebener oder großgeschriebener Text beibehalten werden? WebKit / Blink denke, es sollte; Internet Explorer nicht. Ist es Teil eines Textes selbst oder nur ein Styling?

Ein anderes ist "Sichtbarkeit: versteckt". Ähnlich wie bei "Deckkraft: 0" (und anders als bei "Anzeige: keine") ist ein Text immer noch Teil des Textflusses und kann einfach nicht gesehen werden. Der gesunde Menschenverstand würde vorschlagen, dass es immer noch Teil der Ausgabe sein sollte . Und während Internet Explorer genau das tut, ist WebKit / Blink anderer Meinung (was auch merkwürdigerweise nicht mit dem Verhalten "Deckkraft: 0" vereinbar ist).

Elemente, die einem Browser nicht bekannt sind, stellen ein zusätzliches Problem dar. Beispielsweise unterstützt WebKit / Blink seit kurzem das Element <template>. Dieses Element wird nicht angezeigt und ist daher nicht Teil von innerText. Für Internet Explorer ist es jedoch nichts anderes als ein unbekanntes Inline-Element und es gibt natürlich seinen Inhalt aus.

Standardisierung, nimm 2

 

2011 wird ein weiterer innerTextVorschlag auf der WHATWG-Mailingliste veröffentlicht , diesmal von Aryeh Gregor. Aryeh schlägt entweder vor:

  1. Drop innerTextganz
  2. Spec innerTextzu mögentextContent
  3. Tatsächlich spezifizieren Sie innerTextentsprechend, was IE / WebKit tun

Ähnlich wie in früheren Diskussionen lehnt Mozilla die dritte Option ab (Standardisierung), während Microsoft und Opera die erste ablehnen (Streichung).

In demselben Thread äußert Aryeh seine Besorgnis über die Standardisierung innerText:

Das Problem mit (3) ist, dass es sehr schwer zu spezifizieren wäre; Es wäre noch schwieriger, eine Spezifikation zu erstellen, die von allen Browsern implementiert werden kann. und jede Spezifikation müsste wahrscheinlich ohnehin ziemlich inkompatibel mit den vorhandenen Implementierungen sein, die dem allgemeinen Ansatz folgen. [...]

 

Wie wir aus den Tests gesehen haben, ist die Kompatibilität ein ernstes Problem. Wenn wir standardisieren würden innerText, welches der beiden Verhaltensweisen sollten wir in eine Spezifikation einfügen?

Ein weiteres Problem ist das Vertrauen in Selection.toString()(wie von Boris Zbarsky ausgedrückt):

Es ist nicht klar, ob letzteres tatsächlich eine Option ist; Das hängt davon ab, wie Selection.toString angegeben wird und ob Benutzeroberflächen bereit sind, für innerText dasselbe zu tun wie für Selection.toString.

Bisher habe ich für Selection.toString nur den Vorschlag "do what the copy" gesehen operation does ", was für innerText weder gut definiert noch akzeptabel ist. Meiner Meinung nach.

 

Am Ende verbleibt uns dieses WHATWG-Ticket von Aryeh zum Festlegen innerText. Die Dinge sehen ziemlich düster aus, wie aus einem der Kommentare hervorgeht:

 

Mir wurde unmissverständlich gesagt, dass das Entfernen von Browsern, die nicht von Gecko stammen, nicht praktikabel ist . Abhängig vom Rendering-Baum, inwieweit WebKit dies tut, ist die Spezifikation in Bezug auf Standard-Inhalte wie DOM und CSS jedoch wahnsinnig kompliziert. Außerdem kann es bei getrennten Knoten zu Brüchen kommen (in diesem Fall verhält sich WebKit völlig anders). [...] Aber die Gecko-Leute schienen ziemlich unglücklich über diese Komplexität und die Abhängigkeit in einer DOM-Eigenschaft zu sein . Andererseits hatte ich den Eindruck, dass WebKit ihre InnerText-Implementierung nur ungern umschreibtüberhaupt. Ich gehe davon aus, dass die Spezifikation, die von den meisten Browsern implementiert wird, so einfach wie möglich ist, im Grunde genommen nur ein kompatibles Shim. Wenn mehrere Implementierer tatsächlich so etwas wie die InnerText-Spezifikation implementieren möchten, die ich zu schreiben begonnen habe, würde ich gerne die Arbeit daran wieder aufnehmen, aber das war nicht mein Eindruck.

 

Wir können es nicht entfernen, können es nicht ändern, können es nicht so spezifizieren, dass es vom Rendering abhängt, und es wäre ziemlich schwierig, es zu spezifizieren :)

 

Licht am Ende eines Tunnels?

 

Könnte es noch Hoffnung geben innerTextoder wird es für immer ein unspezifisches Erbe mit 2 verschiedenen Implementierungen bleiben?

Ich hoffe, dass die Testsuite und die Kompatibilitätstabelle der erste Schritt sind, um die Dinge zu verbessern. Wir müssen genau wissen, wie sich Motoren unterscheiden, und wir müssen genau wissen, was in einer Spezifikation enthalten sein muss. Ich bin sicher, dass dies nicht alle Fälle abdeckt, aber es ist ein Anfang (andere Aspekte, die es zu untersuchen gilt: Schatten-DOM, getrennte Knoten).

Ich denke, diese Testsuite sollte ausreichen, um eine zu 90% vollständige Spezifikation zu schreiben innerText. Das größte Problem ist die Entscheidung, welches Verhalten zwischen IE und WebKit / Blink zu wählen ist .

Der Plan könnte sein:

  1. Schreiben Sie eine Spezifikation
  2. Versuchen Sie, das Verhalten von IE und WebKit / Blink zusammenzuführen
  3. Implementieren Sie das angegebene Verhalten in Firefox

Angesichts der Tatsache, wie beeindruckend Microsoft in letzter Zeit war, hoffe ich sehr, dass wir dies umsetzen können.

 

Die naive Spezifikation

 

Ich probierte eine relativ einfache Version von innerText:

  1. Sei sdie leere Zeichenfolge.
  2. Für jeden Nachkommen des Kontextknotens in Baumreihenfolge:
  3. Wenn der Knoten ein Textknoten ist: 1. Wenn die CSS - Eigenschaft "Leerraum" des übergeordneten Knotens "normal" ist :
    1. Sei collapsed_sder Wert der Knotendaten.
    2. Ersetzen Sie jede Folge von 1+ Leerzeichen collapsed_sdurch ein einzelnes Leerzeichen.
    3. Anhängen collapsed_san s. 1. Fügen Sie andernfalls Knotendaten an an s. 2. Wenn das übergeordnete Element des Knotens eines der Elemente <td> und <th> ist, fügen Sie "\ t" an s.
  4. Wenn der Knoten ein Elementknoten ist: 1. Wenn es sich bei einem Element um <script>, <style>, <link> oder <canvas> handelt, fahren Sie mit dem nächsten Knoten fort. 1. Wenn ein Element ausgeblendet ist (dh die CSS- Eigenschaft "display" auf "none" gesetzt ist ), fahren Sie mit dem nächsten Knoten fort. 1. Wenn es sich bei einem Element um ein Element im Blockstil handelt (d. H. , Die CSS- Eigenschaft "display" ist auf Folgendes festgelegt : "block" , "list-item" , "table" , "table-caption" , "table- Zeile " ):
    1. füge "\ n" an s.
    2. Führen Sie für jeden untergeordneten Knoten des Nachkommens in Baumreihenfolge denselben Algorithmus rekursiv aus.
    3. füge "\ n" an s. 1. Wenn ein Element ein <br> Element ist, fügen Sie "\ n" an s.
  5. Trimmen s(dh führende und nachfolgende Leerzeichen entfernen).
  6. Rückkehr s.

Einige wichtige Aufgaben hier:

  1. Prüfen, ob sich ein Textknoten im "formatierten" Kontext befindet (dh ein untergeordnetes Element des Knotens "white-space: pre- *"). In diesem Fall sollte der Inhalt so verkettet werden, wie er ist. Andernfalls reduzieren Sie alle Leerzeichen auf 1.

  2. Prüfen, ob ein Knoten blockförmig ist ("Block", "Listenelement", "Tabelle" usw.). In diesem Fall muss er von Zeilenumbrüchen umgeben sein. Andernfalls ist es inline und der Inhalt wird unverändert ausgegeben.

Dann gibt es Dinge wie das Ignorieren von <script>, <style> usw. Knoten und das Einfügen von Tabulatoren ("\ t") zwischen <td> Elementen (um WebKit / Blink zu folgen).

Dies ist immer noch eine sehr minimale und naive Implementierung . Zum einen werden keine Zeilenumbrüche zwischen Blockelementen ausgeblendet - ein ziemlich wichtiger Aspekt. Um dies zu tun, müssen wir mehr Status verfolgen - um Informationen über den Stil des vorherigen Knotens zu erhalten. Außerdem werden Leerzeichen nicht auf "echte" Weise normalisiert. Bei einem Textknoten mit führenden und nachfolgenden Leerzeichen sollten diese Leerzeichen beispielsweise entfernt werden, wenn es sich um den einzigen Knoten in einem Blockelement handelt.

Dies erfordert mehr Arbeit, ist aber ein guter Anfang.

Es wäre auch eine gute Idee, die innerTextImplementierung in Javascript mit Unit-Tests für jedes der "Features" in einer kompatiblen Tabelle zu schreiben. Möglicherweise werden sogar 2 Modi unterstützt - IE und WebKit / Blink. Eine Implementierung wie diese könnte dann einfach in nicht unterstützende Engines integriert (oder als geeignete Polyfüllung verwendet) werden.

Ich würde gerne Ihre Gedanken, Ideen, Erfahrungen, Kritik hören. Ich hoffe (mit all Ihrer Hilfe), dass wir uns in dieser Richtung verbessern können. Und selbst wenn sich nichts ändert, wurde zumindest etwas Licht auf dieses sehr missverstandene alte Merkmal geworfen.

Update: ein halbes Jahr später

Es ist ein halbes Jahr her, seit ich diesen Beitrag geschrieben habe und ein paar Dinge haben sich zum Besseren verändert!

Zunächst unternahm Robert O'Callahan von Mozilla einige großartige Anstrengungen - er entschied sich , den inneren Text zu spezifizieren und ihn dann in Firefox zu implementieren. Die Idee war, etwas Einfaches, aber Vernünftiges zu schaffen. Die vorgeschlagene Spezifikation - erst nach ca. 11 Jahren - ist jetzt in Firefox 45 implementiert :)

Ich habe einer kompatiblen Tabelle FF45-Ergebnisse hinzugefügt, und abgesehen von einigen Unterschieden ist FF der Implementierung von Chrome ziemlich nahe. Ich plane auch, weitere Tests hinzuzufügen, um weitere Unterschiede zwischen Chrome, FF und Edge festzustellen.

Die Spezifikation enthüllte bereits einige Fehler in Chrome, für die ich hoffentlich Tickets einreichen und die behoben sehen werde. Wenn wir dann auch Edge zur Konvergenz bringen können, sind wir sehr nahe dran, dass sich alle drei größten Browser ähnlich verhalten, was innerTextin naher Zukunft eine brauchbare Funktion darstellt.


Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0