11487 sujets

JavaScript, DOM et API Web HTML5

Modérateur
Salut,

appendChild n'est pas buggué sur Firefox.

un exemple qui ressemble à ce que tu cherches... mais sans mootools :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />

		<title>Exemple</title>

		<script type="text/javascript"><!--

(function() {

var oO =
{
	connect: function(oElem, sEvType, fn, bCapture)
	{
		return document.addEventListener ?
			oElem.addEventListener(sEvType, fn, bCapture):
			oElem.attachEvent ?
				oElem.attachEvent('on' + sEvType, fn):
				false;
	},

	creaEl: function(oEl)
	{
		var oElem, oTxt;

		if(oEl.tag && oEl.text)
		{
			oElem = document.createElement(oEl.tag);
			oTxt = document.createTextNode(oEl.text);
			oElem.appendChild(oTxt);
	
			if(oEl.func)
				oElem.onclick = oEl.func;

			return document.body.appendChild(oElem);
		}

		return false;
	},

	init: function()
	{
		alert('coucou');

		oO.creaEl({
			tag:'button',
			text: 'test de appendChild',
			func: function()
			{
				oO.creaEl({
					tag: 'p',
					text: "Ajout d'une ligne"
				});

				return false;
			}
		});
	}
};

oO.connect(window, 'load', oO.init, false);

})();

		//--></script>
	</head>
	<body>
	</body>
</html>

Modifié par koala64 (26 Jul 2007 - 14:19)
@koala64

Bah alors pourquoi ca me fait ca ?

Sinon ton exemple n'est pas pareil, le createTextNode() va pas me garder les javascript et va m'afficher dans ma div : <script ....>. Ce que je ne veux pas.

@Shinuza

Les fonction InsertInside/Before/After de mootools utilisent appendChild donc le problème reste le même Smiley cligne
Modérateur
Pokemon_JOJO a écrit :
le createTextNode() va pas me garder les javascript
pas compris Smiley confuse
a écrit :
et va m'afficher dans ma div : <script ....>.
non, je ne fais qu'ajouter des éléments. Aucune balise script n'est insérée.
En fait je veux juste récupérer le contenu d'une div et l'insérer dans une autre. Et si dans ce contenu il y a du javascript, je ne veux pas qu'il soit exécuté ! Chose qui marche très bien avec le script de test, sauf sous firefox ou il exécute le javascript lors du appendChild ! Et personnellement je ne sais pas pourquoi il fait ça alors que les autres navigateurs ne le fond pas.
Modérateur
C'est tordu ce que tu fais... Smiley sweatdrop

Déjà, le Javascript dans la div n'a rien à y faire. Tu peux t'en passer et ça règlerait tes problèmes mais bon, si j'ai bien compris, c'est ça que tu cherches :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />

		<title>Exemple</title>

		<script type="text/javascript"><!--

(function() {

var oO =
{
	connect: function(oElem, sEvType, fn, bCapture)
	{
		return document.addEventListener ?
			oElem.addEventListener(sEvType, fn, bCapture):
			oElem.attachEvent ?
				oElem.attachEvent('on' + sEvType, fn):
				false;
	},

	creaEl: function(oEl)
	{
		var oElem, oTxt;

		if(oEl.tag && oEl.text)
		{
			oElem = document.createElement(oEl.tag);
			oTxt = document.createTextNode(oEl.text);
			oElem.appendChild(oTxt);

			if(oEl.func)
				oElem.onclick = oEl.func;

			return document.body.appendChild(oElem);
		}

		return false;
	},

	init: function()
	{
		var oDiv;

		oDiv = document.getElementById('maDiv').innerHTML;

		oO.creaEl({
			tag:'button',
			text: 'test de appendChild',
			func: function()
			{
				oO.creaEl({
					tag: 'p',
					text: oDiv
				});

				return false;
			}
		});
	}
};

oO.connect(window, 'load', oO.init, false);

})();

		//--></script>
	</head>
	<body>

<div id="maDiv">
	<script type="text/javascript"><!--
		alert('coucou');
	//--></script>
</div>

	</body>
</html>
Premièrement, Merci de ton aide Smiley smile

Le problème c'est que comme je le disait plus haut le createTextNode me transforme la partie javascript en ca :


<script type="text/javascript"><!--

		alert('coucou');

	//--></script>


du coup c'est pas ce que je veux :S

Et la démo n'est qu'un exemple simple et minimal pour essayer de comprendre pourquoi firefox me fait un eval() alors que les autre navigateur non.

Sinon pour parler plus concret (en gros ce que fais mon script original), imagine que je charge une page en ajax (contenant du javascript) et que je souhaite insérer ma page dans une div avec la méthode appendChild, mais que je ne veuille pas exécuter le javascript de la page. (chose qui normalement ne se fait pas par défaut !)
Modifié par Pokemon_JOJO (26 Jul 2007 - 15:31)
Modérateur
a écrit :
Le problème c'est que comme je le disait plus haut le createTextNode me transforme la partie javascript en ca
Non, c'est ce qui est dans la div... Je lui dis de récupérer le contenu de la div... et pas de la balise script. Smiley confus

a écrit :
Sinon pour parler plus concret (en gros ce que fais mon script original), imagine que je charge une page en ajax (contenant du javascript) et que je souhaite insérer ma page dans une div avec la méthode appendChild, mais que je ne veuille pas exécuter le javascript de la page. (chose qui normalement ne se fait pas par défaut !)
Alors tu t'y prends mal. C'est ce que fait le script ci-dessus. L'alerte est lancée une fois au chargement et lorsqu'on l'insère via AppendChild, le script n'est pas interprété.
Modifié par koala64 (26 Jul 2007 - 15:44)
le createTextNode considère que le contenu de la div est du texte, comprenant même la balise script Smiley cligne . As tu testé l'exemple que tu m'a donné ? ca ne fait pas la même chose que ce que fait ma démo.

Dans ton exemple le script n'est pas interprété car il est transformé en texte, le rendant ainsi inutilisable. Ce que je ne veux pas, car j'ai besoin de l'exécuter plus tard. Chose impossible avec ta méthode : Smiley ohwell

Test ma démo sous IE/Opera et test ensuite sous firefox, tu verras la différence. IE et Opéra réagissent normalement, mais pas firefox.
Modifié par Pokemon_JOJO (26 Jul 2007 - 16:01)
Modérateur
Appelle ta page et insère le gestionnaire d'événement ensuite...

a écrit :
le createTextNode considère que le contenu de la div est du texte, comprenant même la balise script cligne .
Oui parce que j'ai cru que c'est ce que tu demandais.
Modifié par koala64 (26 Jul 2007 - 16:05)
gné ? pas compris ^^

2ème question qu'on pourrait ce poser Smiley langue ourquoi la fonction AppendChild ne réagi pas pareil sous firefox (du au moteur gecko je pense) que tous les autre navigateurs ? (testé sous IE, Opera et Safari)
Modérateur
Si tu appelles ta page et que dedans tu as le lien <a href="page.htm" id="toto">lien</a>, tu mets, en externe :
function page()
{
    var oA;

    //ici, tu t'assures que tu as bien fait l'appel de page (non détaillé ici) puis tu mets ceci :

    oA = document.getElementById('toto');

    if(oA)
        oA.onclick = alerte;
}

function alerte()
{
    alert('test');

    return false;
}
Tu insères donc un gestionnaire d'événement sur le lien une fois la page chargée.
Ok, mais je ne peut pas savoir quel javascript je vais avoir dans ma page ! le alert() est un exemple. Je vais par exemple avoir des script qui appellent un DatePicker, une LightBox, etc etc...

sinon pour que tu comprennes dans l'ensemble, voici mon javascript complet :



/*
Class: BHClassPage
	Création du system d'onglets et de page

Arguments:
	Voir Options ci-dessous

Options:
	orginalPage - id de la page qui s'affiche en fond (sans onglet)
	classColor - Couleur par defaut des onglets créer si aucune couleur n'est précisé
	divPagesInject - id de la div ou on inject les pages
	divTabsInject - id de la div qui permet d'ajouter des tabs juste après celle-ci
	divTabInfo - id de la div caché qui est chargée pour créer un onglet
*/
var BHClassPage = new Class({

	options: {
		orginalPage: 'current-page',
		classColor: 'black',
		divPagesInject: 'pages',
		divTabsInject: 'tabs-top',
		divTabInfo: 'tab-name',
		onLoadingStart : Class.empty,
		onLoadingComplete : Class.empty
	},

	initialize: function(options) {
		this.setOptions(options);
		this.tabEvents = [];
		this.tabActive = false;
		this.tabLoading = false;
		this.tabRemoving = false;
		this.tabHistory = [];

		// On check si l'url n'indique pas une page à charger
		//if(document.location.hash.substr(1) != '')
		//	this.load(document.location.hash.substr(1));

		// On check périodiquement l'url 5s après le lancement du site (évite d'ouvrir 2 fois le même onglet)
		//(function(){ this.tabEventHistory = (function(){ this.checkHitory(); }.bind(this)).periodical(250); }.bind(this)).delay(3000);
		this.tabEventHistory = (function(){ if(!this.tabLoading) this.checkHitory(); }.bind(this)).periodical(250);
	},

	/*
	Property: checkHitory
		Check l'url de la page pour savoir si on à changé depage ou non
	*/
	checkHitory: function() {
		// Si url est différente de la page active
		if(document.location.hash.substr(1) != '' && document.location.hash.substr(1) != this.tabActive) {
			this.load(document.location.hash.substr(1));
		}
		// Si l'url est vide mais qu'on à actuellement une page active
		else if(document.location.hash.substr(1) == '' && this.tabActive) {

			// Cache la page visible
			if($('page-' + this.tabActive))
				$('page-' + this.tabActive).setStyle('display','none');

			// Supprime la selection de l'onglet
			if($('tab-' + this.tabActive))
				$('select-' + this.tabActive).removeClass('current');

			// Ajoute l'ancienne page dans l'historique
			this.tabHistory.extend([this.tabActive]);

			this.tabActive = false;

			// Affiche la page d'origine
			document.title = document.title.split(':')[0] + ': ';
			$(this.options.orginalPage).setStyle('display','block');
			BHScroll.toElement($(this.options.orginalPage));
		}

	},

	/*
	Property: tabEvent
		Evenements des onglets du site

	Argument:
		e - type de l'évenement
		Tab - Info de la tab select/close-UID
	*/
	tabEvent: function(e, Tab) {
		switch(e.type){
			case 'click':
				if(Tab.split('-')[0] == 'select' && !this.tabRemoving)
					this.show(Tab.split('-')[1]);
				else if(Tab.split('-')[0] == 'close')
					this.remove(Tab.split('-')[1]);
				break;
			case 'mouseover':
				if(Tab.split('-')[0] == 'select' && Tab.split('-')[1] != this.tabActive)
					$('select-' + Tab.split('-')[1]).addClass('current');
				else if(Tab.split('-')[0] == 'close')
					$('close-' + Tab.split('-')[1]).addClass('currentclose');
				break;
			case 'mouseout':
				if(Tab.split('-')[0] == 'select' && Tab.split('-')[1] != this.tabActive)
					$('select-' + Tab.split('-')[1]).removeClass('current');
				else if(Tab.split('-')[0] == 'close')
					$('close-' + Tab.split('-')[1]).removeClass('currentclose');
				break;
			default:
				return false;
		};
	},

	/*
	Property: load
		Charge une page en ajax puis créé la page et l'onglet dans le site

	Argument:
		UrlID - UID de la page (url qui deviendra son identifiant)

	Properties:
		noShow - Ne pas afficher la page après le chargement (default false)
	*/
	load: function(UrlID, properties) {alert(UrlID);
		properties = Object.extend({
			'noShow': false
		}, properties || {});

		// Si la page n'existe pas on la charge en ajax
		if(!$('page-' + UrlID)) {
			if(UrlID) {
				this.tabLoading = true;
				this.ajax = new Ajax('ajax/' + UrlID, {
					method: 'get',
					evalScripts: true,
					onComplete: function(responseText) {

						// Création de la nouvelle page
						this.newPage = new Element('div').setProperty('id', 'page-' + UrlID).addClass('page').setStyle('display', 'none').setHTML(responseText);

						// Création de l'onglet
						this.newTab = new Element('div').setProperty('id', 'tab-' + UrlID);

						// Class et titre de l'onglet par defaut
						this.newTab.classname = this.options.classColor;
						this.newTab.titlename = UrlID;

						// Charge la class et le titre de l'onglet
						if($E('div', this.newPage).getProperty('id') == this.options.divTabInfo) {
							this.newTab.info = $E('div', this.newPage);

							if(this.newTab.info.getProperty('class'))
								this.newTab.classname = this.newTab.info.getProperty('class');

							if(this.newTab.info.innerHTML)
								this.newTab.titlename = this.newTab.info.innerHTML;

							// Supprime l'info caché
							this.newTab.info.remove();
						}
						// Ajoute la class
						this.newTab.addClass(this.newTab.classname);
						// Stock le titre
						this.newTab.setProperty('name', this.newTab.titlename);

						// Création du contenu de l'onglet
						this.newTab.selectTab = new Element('div').setProperty('id', 'select-' + UrlID);
						this.newTab.closerTab = new Element('span').addClass('closetab').setProperty('id', 'close-' + UrlID);
						this.newTab.innerTab = new Element('div').addClass('intab');

						// Ajoute le bouton "fermer" dans le innerTab
						this.newTab.closerTab.injectInside(this.newTab.innerTab);
						// Ajoute le titre dans le innerTab
						this.newTab.innerTab.appendText(this.newTab.titlename);
						// Ajoute le innerTab dans le select
						this.newTab.innerTab.injectInside(this.newTab.selectTab);
						// Ajoute le select dans l'onglet
						this.newTab.selectTab.injectInside(this.newTab);

						// Ajoute les events
						this.tabEvents['select-' + UrlID] = this.tabEvent.bindAsEventListener(this, 'select-' + UrlID);
						this.tabEvents['close-' + UrlID] = this.tabEvent.bindAsEventListener(this, 'close-' + UrlID);

						this.newTab.addEvent('click', this.tabEvents['select-' + UrlID]);
						this.newTab.addEvent('mouseout', this.tabEvents['select-' + UrlID]);
						this.newTab.addEvent('mouseover', this.tabEvents['select-' + UrlID]);

						this.newTab.closerTab.addEvent('click', this.tabEvents['close-' + UrlID]);
						this.newTab.closerTab.addEvent('mouseout', this.tabEvents['close-' + UrlID]);
						this.newTab.closerTab.addEvent('mouseover', this.tabEvents['close-' + UrlID]);

						// Ajoute la nouvelle page dans le site
						this.newPage.injectInside($(this.options.divPagesInject));
						// Ajoute le nouvel onglet dans le site
						this.newTab.injectAfter(this.options.divTabsInject);
						// Slide [cligne]
						$E('div.intab', this.newTab).effects({
							duration: 500,
							transition: Fx.Transitions.backOut,
							onComplete: function() {
								// Affiche la page
								if(!properties.noShow)
									this.show(UrlID);
							}.bind(this)
						}).custom({'margin-right': [150, 15], 'margin-left': [-150, -20]});

						this.ajax = null;
						this.tabLoading = false;
					}.bind(this),
					onFailure: function() {
						this.ajax = null;
						this.tabLoading = false;
					}.bind(this)
				}).request();
			}
			else
				return false;
		}
		// Si elle existe déjà, on l'affiche
		else if(!properties.noShow)
			this.show(UrlID);
	},

	/*
	Property: show
		Affiche une page

	Argument:
		UrlID - UID de la page

	Properties:
		noScroll - Ne pas scroller la page après l'affichage (default false)
	*/
	show: function(UrlID, properties) {
		properties = Object.extend({
			'noScroll': false
		}, properties || {});

		if($('page-' + UrlID)) {
			// Si la page active est différente de celle qu'on veut afficher
			if(this.tabActive != UrlID) {
				// Si il existe une page active
				if(this.tabActive) {
					// Cache la page visible
					if($('page-' + this.tabActive))
						$('page-' + this.tabActive).setStyle('display','none');

					// Supprime la selection de l'onglet
					if($('tab-' + this.tabActive))
						$('select-' + this.tabActive).removeClass('current');

					// Ajoute l'ancienne page dans l'historique
					this.tabHistory.extend([this.tabActive]);
				}
				else if($(this.options.orginalPage))
					$(this.options.orginalPage).setStyle('display','none');

				// Change le titre de la page
				if($('tab-' + UrlID).getProperty('name'))
					document.title = document.title.split(':')[0] + ': ' + $('tab-' + UrlID).getProperty('name');

				// Affiche la selection de l'onglet
				if($('tab-' + UrlID))
					$('select-' + UrlID).addClass('current');
				// Affiche la page
				$('page-' + UrlID).setStyle('display', 'block');

				this.tabActive = UrlID;
			}
			// On scroll le contenu
			if(!properties.noScroll)
				BHScroll.toElement($('page-' + UrlID));

			// Change l'url du site
			 document.location.hash = UrlID;
		}
		else
			return false;
	},

	/*
	Property: remove
		Supprime une page

	Argument:
		UrlID - UID de la page
	*/
	remove: function(UrlID) {
		this.tabRemoving = true;

		// Permet de supprimer la page courante facilement BHPage.remove();
		if(!UrlID)
			UrlID = this.tabActive;

		// Si la page et l'onglet existe
		if($('tab-' + UrlID) && $('page-' + UrlID)) {

			// Slide [cligne]
			$E('div.intab', $('tab-' + UrlID)).effects({
				duration: 500,
				transition: Fx.Transitions.backOut,
				onComplete: function() {
					// Supprime les évennement associés à la page
					$('tab-' + UrlID).removeEvents();
					$('close-' + UrlID).removeEvents();
					// Supprime l'onglet
					$('tab-' + UrlID).remove();
					// Supprime la page
					$('page-' + UrlID).remove();
					// Supprime la page de l'historique
					this.tabHistory.remove(UrlID);

					// Supprime le wait d'affichage d'une page
					this.tabRemoving = false;

					// Si on vient de supprimer la page active
					if(UrlID == this.tabActive) {
						this.tabHistoryLast = this.tabHistory.pop();

						// Supprime la tabActive
						this.tabActive = false;

						if($('page-' + this.tabHistoryLast))
							this.show(this.tabHistoryLast);
						else if($(this.options.orginalPage)) {
							// Change l'url et le titre du site
			 				document.location.hash = '#';
							document.title = document.title.split(':')[0] + ': ';

							$(this.options.orginalPage).setStyle('display','block');
							BHScroll.toElement($(this.options.orginalPage));
						}
					}
				}.bind(this)
			}).custom({'margin-right': [15, 150], 'margin-left': [-20, -150]});
		}
	},

	/*
	Property: update
		Update une page

	Argument:
		UrlID - Url et/ou ID de la page à update
		UID - UID da la page à update
		FormID - Formulaire à poster avec la requète
	*/
	update: function(UrlID, UID, FormID) {
		// Permet d'update la page courante facilement BHPage.update();
		if(!UID)
			UID = this.tabActive;
		if(!UrlID)
			UrlID = UID;
		// Si la page existe et l'url
		if($('page-' + UID) && UrlID){
			if(FormID) {
				this.sendMethod = 'post';
			}
			else
				this.sendMethod = 'get';

			this.ajax = new Ajax('ajax/' + UrlID, {
				method: this.sendMethod,
				postBody: FormID,
				evalScripts: false,
				update: 'page-' + UID,
				onComplete: function() {
					// Suprime la div caché d'infos
					if($(this.options.divTabInfo))
						$(this.options.divTabInfo).remove();
					// Scroll en haut de la page
					if(this.tabActive == UID)
						BHScroll.toElement($('page-' + UID));
					this.ajax = null;
				}.bind(this),
				onFailure: function() {
					this.ajax = null;
				}.bind(this)
			}).request();
		}
		else
			return false;
	},

	/*
	Property: post
		Envoi un formulaire plus simplement pour update une page

	Argument:
		UrlID - Url et/ou ID de la page à update
		UID - UID da la page à update
		FormID - Formulaire à poster avec la requète
	*/
	post: function(FormID,UrlID,UID) {
		this.update(UrlID,UID,FormID);
	}
});

BHClassPage.implement(new Events, new Options);


Le problème étant identifié ici :

this.newPage.injectInside($(this.options.divPagesInject));


J'ai mon evalscript qui est a true dans ma requête ajax, donc la page reçu est évaluée, et le js qu'elle contient exécuté. Jusque la tout va bien. Mais FF en décide autrement, et me fais un deuxième evalscript lors du injectInside qui revient à un AppendChild en gros.

Donc pour résumer, si ma page charger en ajax contient un javascript avec un simple alert(), j'ai avec firefox :

- 1 alert() au chargement de la page en ajax
- 1 alert() au AppendChild

Alors que avec tous les autre navigateurs (non gecko) je n'ai qu'un alert() au chargement de la page en ajax et puis basta. <-- ce que je veux en gros et ce qui est sensé être normal ^^
Modérateur
Pokemon_JOJO a écrit :
Ok, mais je ne peut pas savoir quel javascript je vais avoir dans ma page ! le alert() est un exemple. Je vais par exemple avoir des script qui appellent un DatePicker, une LightBox, etc etc...
Tu n'as pas à mettre de JS dans le XHTML. Ce que tu identifies, c'est si les éléments auxquels tu souhaites accrocher tes gestionnaires sont présents. Si ce n'est pas le cas, les fonctions sont inactives et à l'inverse, la mise à jour du DOM active ces fonctions.
la je suis largué ! Pourquoi je ne peux pas mettre de js dans mes page ajax ? Y'a pourtant bien la fonction eval() de prévu pour exécuter ses js charger dynamiquement. Et surtout, mon script marche parfaitement partout (même sous mac) sauf sous firefox !!!! C'est quand même étrange !
Modifié par Pokemon_JOJO (26 Jul 2007 - 20:18)
Modérateur
Pokemon_JOJO a écrit :
Pourquoi je ne peux pas mettre de js dans mes page ajax ? Y'a pourtant bien la fonction eval() de prévu pour exécuter ses js charger dynamiquement.
Je n'ai pas dit que tu ne peux pas ; c'est juste inutile. L'avantage de ne pas en mettre est que tu gagnes en facilité de maintenance et que tu n'as pas à te servir d'eval().

Je trouve quand même étrange que tu sortes un code comme ci-dessus et que ce point, qui fait parti des bases, te pose problème. Smiley sweatdrop
Modifié par koala64 (27 Jul 2007 - 08:55)
Je n'ai jamais appris les base, je suis autodidact Smiley cligne

Sinon, j'ai une ancienne beta de mon site (donc le code js n'est pas tout à fait le même), et je pense que tu cmprendra pourquoi j'ai besoin de la fonction eval() du à mon site qui est totalement dynamique.

http://beta.bee-home.com
Modifié par Pokemon_JOJO (27 Jul 2007 - 12:58)