JavaScript – contrôle du point d'insertion pour document.write

Je voudrais créer une page qui exécute un script tiers qui comprend document.write après que le DOM était déjà complètement chargé.

Ma page n'est pas XHTML. Mon problème est que le document.write écrase ma propre page. (C'est ce qu'il fait une fois que le DOM a été chargé).

J'ai essayé de remplacer la fonction document.write (d'une manière similaire à http://ejohn.org/blog/xhtml-documentwrite-and-adsense/ ), mais cela ne couvre pas les cas où document.write contient des étiquettes partielles.

Un exemple qui romprait le code ci-dessus est:

 document.write("<"+"div"); document.write(">"+"Done here<"+"/"); document.write("div>"); 

Existe-t-il un moyen de modifier le point d'insertion document.write via JavaScript? Est-ce que quelqu'un a une meilleure idée de comment faire cela?

Si vous rencontrez des scripts tiers, il suffit de remplacer document.write pour capturer la sortie et de la coller au bon endroit, elle n'est pas suffisante, car elle pourrait modifier le script et que votre site se brise.

WriteCapture.js fait ce dont vous avez besoin (divulgation complète: je suis l'auteur). Il réinscrit essentiellement les balises de script pour que chacune capture son propre document.write Écrivez la sortie et la place dans l'endroit correct. L'utilisation (en utilisant jQuery) serait quelque chose comme:

 $(document.body).writeCapture().append('<script type="text/javascript" src="http://3rdparty.com/foo.js"></script>'); 

Je suppose que vous souhaitez ajouter à la fin du corps. Tous les sélecteurs jQuery et les méthodes de manipulation fonctionneront avec le plugin, afin que vous puissiez l'injecter n'importe où et comme vous le souhaitez. Il peut également être utilisé sans jQuery, s'il s'agit d'un problème.

Il est possible de remplacer la méthode document.write. Vous pouvez donc tamponner les chaînes envoyées à document.write et afficher le tampon où vous le souhaitez. Cependant, changer un script de synchrone en asynchrone peut provoquer des erreurs s'il n'est pas traité correctement. Voici un exemple:

Remplacement simplifié du document.

 (function() { // WARNING: This is just a simplified example // to illustrate a problem. // Do NOT use this code! var buffer = []; document.write = function(str) { // Every time document.write is called push // the data into buffer. document.write can // be called from anywhere, so we also need // a mechanism for multiple positions if // that's needed. buffer.push(str); }; function flushBuffer() { // Join everything in the buffer to one string and put // inside the element we want the output. var output = buffer.join(''); document.getElementById("ad-position-1").innerHTML = output; } // Inject the thid-party script dynamically and // call flushBuffer when the script is loaded // (and executed). var script = document.createElement("script"); script.onload = flushBuffer; script.src = "http://someadserver.com/example.js"; })(); 

Contenu de http://someadserver.com/example.js

 var flashAdObject = "<object>...</object>"; document.write("<div id='example'></div>"); // Since we buffer the data the getElementById will fail var example = document.getElementById("example"); example.innerHTML = flashAdObject; // ReferenceError: example is not defined 

J'ai documenté les différents problèmes que j'ai rencontrés lors de l'écriture et de l'utilisation de mon remplacement document.write: https://github.com/gregersrygg/crapLoader/wiki/What-to-think-about-when-replacing-document.write

Mais le danger d'utiliser un remplacement document.write sont tous les problèmes inconnus qui peuvent survenir. Certains ne sont même pas possibles pour se déplacer.

 document.write("<scr"+"ipt src='http://someadserver.com/adLib.js'></scr"+"ipt>"); adLib.doSomething(); // ReferenceError: adLib is not defined 

Heureusement, je n'ai pas rencontré le problème ci-dessus dans la nature, mais cela ne garantit pas que cela n'arrive pas;)

Vous voulez toujours l'essayer? Essayez crapLoader (mine) ou writeCapture :

Vous devriez également consulter des iframes amicaux . Fondamentalement, il crée un iframe de même domaine et charge tout ce qu'il y a à la place de votre document. Malheureusement, je n'ai pas encore trouvé de bonnes bibliothèques pour gérer cela.

Réponse initiale avant l'édition:


Fondamentalement, le problème de document.write est qu'il ne fonctionne pas dans les documents XHTML . La solution la plus large alors (aussi difficile qu'elle puisse paraître) est de ne pas utiliser XHTML / xml pour votre page. En raison de IE + XHTML et du problème de mimetype , Google Adsense break (peut-être une bonne chose :), et le changement général vers HTML5 Je ne pense pas que ce soit aussi mauvais qu'il le semble.

Cependant, si vous souhaitez vraiment utiliser XHTML pour votre page, alors le script de John auquel vous avez été lié est le meilleur que vous avez sur ce point. Il suffit de renifler pour IE sur le serveur. Si la demande provient d'IE, ne faites rien (et ne servez pas l' application/xhtml+xml mimetype!). Sinon, laissez-la dans la <head> de votre page et vous quittez les courses.

En relisant votre question, y at-il un problème spécifique avec le script de John? Il est connu de l'échec dans Safari 2.0, mais c'est à ce sujet.

Vous pouvez être intéressé par la bibliothèque Javascript que j'ai développée qui permet de charger des scripts tiers en utilisant document.write après window.onload. En interne, la bibliothèque supprime document.write, en ajoutant les éléments DOM de manière dynamique, en exécutant tous les scripts inclus qui peuvent également utiliser document.write.

Contrairement à la solution de John Resig (qui faisait partie de l'inspiration pour mon propre code), le module développé prend en charge des écritures partielles telles que l'exemple que vous donnez avec la div:

 document.write("<"+"div"); document.write(">"+"Done here<"+"/"); document.write("div>"); 

Ma bibliothèque attendra la fin du script avant d'analyser et de rendre le balisage. Dans l'exemple ci-dessus, il fonctionnerait une fois avec la chaîne complète "<div>Done here</div>" au lieu de 3 fois avec un balisage partiel.

J'ai configuré une démo, dans laquelle je charge 3 Google Ads, un widget Amazon ainsi que Google Analytics de façon dynamique .

FWIW, j'ai trouvé que les publications postsecondaires étaient la meilleure option de nos jours – il gère l'emballage d'un module de rendu d'annonces gênant comme un charme permettant à notre page de charger sans être bloqué.

Afin de modifier le contenu de la page après le rendu du DOM, vous devez soit utiliser une bibliothèque javascript pour ajouter du HTML ou du texte à certains points (jQuery, mootools, prototype, …) ou tout simplement utiliser la propriété innerHTML de chaque DOM Élément pour modifier / annexer du texte. Cela fonctionne crossbrowser et ne nécessite aucune bibliothèque.

Il existe de meilleurs moyens de le faire. 2 façons

1) Ajouter

 <html><head> <script> window.onload = function () { var el = document.createTextNode('hello world'); document.body.appendChild(el); } </script></head><body></body></html> 

2) InnerHTML

 <html><head><script> window.onload = function () { document.body.innerHTML = 'hello world'; } </script></head><body></body></html>