Toon posts:

[JS] Msie klapt eruit bij script

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met het uitbouwen van een feature, nl. het wijzigen van de src attribute van een script tag om zo stealth verbindingen te leggen. Op het moment dat ik de method close() aan wil roepen klapt MSIE er totaal uit.

Ik vermoed dat het ligt aan het verwijderen van de verwijzing this.connection. Zijn er mensen bekend met deze *kuch* feature :)

De code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
    <title>Untitled</title>
    <script language="JavaScript">
    
    stealthConnections = new Array();
    function stealthConnection(strLocation,strData){
        this.location = strLocation;
        this.data = strData;
        this.connection = null;
        
        stealthConnections.push(this);
        this.open();
    }
    
    stealthConnection.prototype.open = function (){
        this.connection = document.createElement('script');
        this.connection.src = this.location + "?data=" + this.data + "&nocache=" + new Date().getTime();
        document.body.appendChild(this.connection);
    }
    
    stealthConnection.prototype.close = function (){
         document.body.removeChild(this.connection);
        // this.connection = null;
    }
        
    stealthConnection.prototype.onDataReceived = function(strDataReceived){
        alert("Data Received:" + strDataReceived);  
        this.close();
    }
    </script>
</head>
<body>
<a href="#" onclick="new stealthConnection('data.js','b')">test</a>
</body>
</html>


En data.js
code:
1
2
var strData;
stealthConnections[0].onDataReceived('jaja');


En verder nog een vraagje, zijn er manieren bekend om een referer te krijgen :p Dus in een functie uitlezen, door welke functie hij is aangeroepen, of door welk element, etc.

Ik moet nu op een smerige manier stealthConnections[0].onDataReceived('jaja'); doen, terwijl ik dit liever alla this.onDataReceived('bla'); had gezien. Omdat hij geen onderdeel is van het object StealthConnection werkt het natuurlijk niet.

[ Voor 20% gewijzigd door Verwijderd op 23-09-2003 09:12 ]


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

je kan met een truuk de scope behouden, bv door in de proto.open dit te bouwen voor de onload event ipv het script dit zelf te laten doen:

code:
1
2
3
4
5
6
7
8
var self = this;
this.connection.onload = function() {
    // self == stealthConnection
}

this.connection.onreadystatechange = function() {
    if(this.readyState == 'loaded') this.onload();
}


IE kent die .onload niet, die is voor moz, en met een readystate roep je die dan handmatig aan voor IE.

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


  • André
  • Registratie: Maart 2002
  • Laatst online: 19-08 12:30

André

Analytics dude

En verder nog een vraagje, zijn er manieren bekend om een referer te krijgen Dus in een functie uitlezen, door welke functie hij is aangeroepen, of door welk element, etc.
De 'referer' kun je krijgen door in de event.srcElement te kijken, of in de event.srcElement.onload. In mozilla is dit geloof ik event.Target.

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:21

crisp

Devver

Pixelated

Ik vraag me af of het wel zin heeft om het scriptelement weer te verwijderen. Het toevoegen en parsen van een scriptelement voegt natuurlijk weer allerlei globale objecten toe, ik denk niet dat die met het verwijderen van het scriptelement weer opgeruimt worden.

Intentionally left blank


Verwijderd

Topicstarter
André schreef op 23 september 2003 @ 09:32:
[...]

De 'referer' kun je krijgen door in de event.srcElement te kijken, of in de event.srcElement.onload. In mozilla is dit geloof ik event.Target.
Ja dat klopt, dat is voor elementen, maar ik heb nog nooit zoiets gezien voor functions. Dat als function1 function2 aanroept, ik in function2 kan oproepen dat hij is aangeroepen door function 1.

Ik ga zo even bekijken wat dat van Clay psies doet :) Want de readyState van een JS, geeft niet aan dat er data is ontvangen :) Alleen dat de JS volledig is ingeladen.

Verwijderd

Topicstarter
crisp schreef op 23 September 2003 @ 09:41:
Ik vraag me af of het wel zin heeft om het scriptelement weer te verwijderen. Het toevoegen en parsen van een scriptelement voegt natuurlijk weer allerlei globale objecten toe, ik denk niet dat die met het verwijderen van het scriptelement weer opgeruimt worden.
Ja dat moet wel wil je crossbrowser blijven. Het enkel wijzigen van de src attribute pikt Mozilla niet. Msie gaat daar wel goed mee om, maar Mozilla vereist helaas een nieuw object.

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:21

crisp

Devver

Pixelated

Verwijderd schreef op 23 September 2003 @ 09:42:
[...]


Ja dat moet wel wil je crossbrowser blijven. Het enkel wijzigen van de src attribute pikt Mozilla niet. Msie gaat daar wel goed mee om, maar Mozilla vereist helaas een nieuw object.
Waar ik op doel is dat het verwijderen van je script element in feite zinloos is, tenzij je zo vaak script elementen toevoegd dat geheugengebruik een issue is.
In ieder geval heb ik mbv Clay's tip het volgende werkend gekregen:

HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
    <title>Untitled</title>
    <script language="JavaScript">
    
    stealthConnections = new Array();
    function stealthConnection(strLocation,strData){
        this.location = strLocation;
        this.data = strData;
        this.connection = null;
        
        stealthConnections.push(this);
        this.open();
    }
    
    stealthConnection.prototype.open = function (){
        this.connection = document.createElement('script');
        this.connection.src = this.location + "?data=" + this.data + "&nocache=" + new Date().getTime();
        this.connection.parent = this;
        this.connection.onload = function() { this.parent.onDataReceived('jaja'); }
        this.connection.onreadystatechange = function() { if (this.readyState == 'complete') this.onload(); }
        document.body.appendChild(this.connection);
    }
    
    stealthConnection.prototype.close = function (){
        document.body.removeChild(this.connection);
        this.connection = null;
        doAlert();
    }
        
    stealthConnection.prototype.onDataReceived = function(strDataReceived){
        alert("Data Received:" + strDataReceived);  
        this.close();
    }
    </script>
</head>
<body>
<a href="#" onclick="new stealthConnection('data.js','b')">test</a>
</body>
</html>


data.js:

JavaScript:
1
2
3
4
5
6
7
var strData = 'blabla';

function doAlert() {

  alert(strData);

}


Je ziet hier ook duidelijk dat zowel de functie doAlert als de variabele strData na het verwijderen van het script element nog gewoon bestaan.

Intentionally left blank


Verwijderd

Topicstarter
crisp schreef op 23 September 2003 @ 10:20:
[...]

Waar ik op doel is dat het verwijderen van je script element in feite zinloos is, tenzij je zo vaak script elementen toevoegd dat geheugengebruik een issue is.
In ieder geval heb ik mbv Clay's tip het volgende werkend gekregen:
Ik heb al een aantal malen meegemaakt dat pagina's gewoon te zwaar worden door gebruik van veel elementen, code, en scripts. Ik wil het best eens uitproberen of er een verschil is te merken in het opruimen van je scripts, of het gewoon lekker laten staan.

Ik ging ervanuit, dat je door het opruimen van je scripts, weer resources kon vrijmaken zoals dit normaal het geval is bij objects. Overigens kunnen derg. scripts best groot worden. Het worden dan nl. complete arrays, die je dan met OnDataReceived kunt gaan parsen. Zoals bijvoorbeeld dynamisch appenden van rows in een grid etc. ipv de hele pagina opnieuw te herladen.

Dit gebruik ik nu al in een applicatie en bevalt me echt heel goed, maar ik wilde graag naar prototyping toe omdat ik zo meerdere threads kan afvuren, en omdat het beter te onderhouden is.

Overigens zit ik eventjes scheel te kijken naar het gebruik van this.connection.parent :? Ga je hier nu de parentNode van het script element aangeven :?

edit:

ow soz, had je laatste alinea nog niet gelezen, over dat data gewoon blijft bestaan..

Erg vaag overigens dat dat gebeurt? Aangezien je this.connection op null gooit. Zal wel implementatie zijn ofzo van de JS parser.

[ Voor 32% gewijzigd door Verwijderd op 23-09-2003 11:39 ]


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

misschien dat je die dynamischie includes in soort een aparte namespace kan mikken en dan een routine bakken die dat eerste leegmaakt voordat die het script element removed (als dat daarna nog nodig is/zin heeft ) ala:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
// in de include
var naamNSNaarEneConventieOid = {
   variabele : 'waarde',
   EenObject : function () {
       // bla
   }
}

naamNSNaarEneConventieOid.EenObject.prototype = {
   eenFunctie : function () {
      // ... functies eraan hangen enzo
   }
}


en dan in de remove een for(all in namespace) delete;

?

[ Voor 7% gewijzigd door Clay op 23-09-2003 11:48 ]

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


Verwijderd

Topicstarter
Ik zal eerst is wat testjes gaan doen om te kijken of de boel verstopt raakt, als ik het object gewoon laat bestaan. Anders is het gewoon zonde van de moeite :) Ik ga in ieder geval even bekijken hoe dat nu ziet met dat .parent, dat is nog een beetje vaag :)

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:21

crisp

Devver

Pixelated

Dat .parent is eenvoudig: de onload wordt getriggered op de connection property. Je moet dus iets hebben om terug te verwijzen naar het stealthConnection object zelf om daar de onDataReceived method van aan te roepen. Daarvoor maak ik een extra property aan binnen de connection scope om die terugverwijzing te kunnen maken.
Dit is eigenlijk heel normaal, zo heb je bijvoorbeeld in de DOM ook vaak een parentElement property, en this.form binnen de scope van een form element verwijst ook weer naar de parent (het form zelf). Bij eigen objecten moet je echter dit soort constructies zelf aanmaken :)

Trouwens, als je in de js-files die je inlaadt telkens dezelfde variabelen en functies gebruikt worden de reeds bestaande variabelen en functies natuurlijk gewoon overschreven. Strict genomen is dit niet zo netjes (variabelen en methoden herdeclareren), maar ik denk niet dat de boel daarvan zo gauw verstopt raakt.

Edit: de crash van je 1e opzet is misschien te verklaren uit het feit dat in feite de JS interpreter nog bezig is met het parsen en uitvoeren van data.js als vervolgens het scriptelement alweer verwijderd wordt(?)

[ Voor 11% gewijzigd door crisp op 23-09-2003 13:33 ]

Intentionally left blank


Verwijderd

Topicstarter
crisp schreef op 23 september 2003 @ 13:05:
Edit: de crash van je 1e opzet is misschien te verklaren uit het feit dat in feite de JS interpreter nog bezig is met het parsen en uitvoeren van data.js als vervolgens het scriptelement alweer verwijderd wordt(?)
Dat zou inderdaad goed mogelijk zijn. Het is alleen jammer, dat dit moest lijden tot een algehele browser fuck up, ipv een nette message "oops something went wrong" en je alsnog kunt doorwerken :)

Verwijderd

Topicstarter
crisp schreef op 23 september 2003 @ 13:05:
Dat .parent is eenvoudig: de onload wordt getriggered op de connection property. Je moet dus iets hebben om terug te verwijzen naar het stealthConnection object zelf om daar de onDataReceived method van aan te roepen. Daarvoor maak ik een extra property aan binnen de connection scope om die terugverwijzing te kunnen maken.
Ik had het al gezien ja, was nog aan het slapen. :)

  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

Na wat gepook lijkt het erop dat script files die je voor de onload met de dom aan de head appendt meegenomen worden voor die onload, en ook netjes achter elkaar geladen worden alsof het gewone html script tags waren. Weet iemand hier misschien meer over? :P Als dit nml betrouwbaar genoeg is wil ik nooit meer wat anders doen.

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:21

crisp

Devver

Pixelated

Clay schreef op 24 September 2003 @ 11:53:
Na wat gepook lijkt het erop dat script files die je voor de onload met de dom aan de head appendt meegenomen worden voor die onload, en ook netjes achter elkaar geladen worden alsof het gewone html script tags waren. Weet iemand hier misschien meer over? :P Als dit nml betrouwbaar genoeg is wil ik nooit meer wat anders doen.
Ik doe dat vaak genoeg met document.write's in de head-sectie, en heb daar ook tot dusver nog geen problemen mee gehad in de meest gangbare browsers, dus ik denk dat het toevoegen van scripts dmv document.head.appendChild (naar ik aanneem?) ook geen problemen mag opleveren :)

wel handig idd zo'n include() functie:
JavaScript:
1
2
3
4
5
function include(url) {

  document.write('<scr'+'ipt type="text/javascript" src="'+url+'"><\/scr'+'ipt>');

}

[ Voor 13% gewijzigd door crisp op 24-09-2003 12:03 ]

Intentionally left blank


Verwijderd

Topicstarter
Clay schreef op 24 september 2003 @ 11:53:
Na wat gepook lijkt het erop dat script files die je voor de onload met de dom aan de head appendt meegenomen worden voor die onload, en ook netjes achter elkaar geladen worden alsof het gewone html script tags waren. Weet iemand hier misschien meer over? :P Als dit nml betrouwbaar genoeg is wil ik nooit meer wat anders doen.
Ik gebruik de functionaliteit eigenlijk voornamelijk voor het bijwerken van een interface, en versturen van data :) Nooit meer hele nieuwe pagina's ophalen inc. icons, etc. maar alleen wat je nodig hebt.

Je kunt natuurlijk ook xmlHTTP gebruiken :)

  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

yup, maar de xmlhttp is meer voor data, en met script wil ik ook echt scripts inladen (of prefs n.a.v een asp/jsp/php "script".
dmv document.head.appendChild (naar ik aanneem?)
document.getElementsByTagName('head')[0].appendChild

document.head schijnt niet te bestaan, hoewel het dan raar is eigenlijk dat document.body wel bestaat.

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


Verwijderd

Zoiets misschien Clay:
code:
1
2
3
4
5
6
7
var s=document.createElement('link');

s.src='path/to/javascript.js';
s.type='text/javascript';
document.getElementsByTagName('head')[0].appendChild(s);

void(0);

Verwijderd

Heeft iemand het ook werkend gekregen in Opera en/of Safari? Bij opera lijkt script-elementen aanmaken geen effect te hebben. Het wijzigen van de src property van een bestaand script-element werkt wel (zoals in IE, het script wordt in feite ge-eval-d).

Bij Safari lijkt het aanmaken van script-elementen geen effect te hebben, maar bij het wijzigen van de src-property van een bestaand script-element reageert Safari net als Mozilla.

Ergo: bij Opera kun je scripts dynamisch laden, zolang er maar een script-tag is. Bij Safari is het helemaal niet mogelijk :(

Heeft iemand het wel aan de praat gekregen? Het dynamisch laden van scripts is namelijk onmisbaar bij de leukere bookmarklets :7

Nog een URLetje over remote scripting.

[ Voor 1% gewijzigd door Verwijderd op 25-09-2003 20:20 . Reden: tiepfaut ]


Verwijderd

Topicstarter
Doekman,

Mocht het voor Opera/Safari niet werken dan zijn er nog meer mogelijkheden voor remote scripting.

Waar ik zelf een hekel aan heb, is het eeuwige klik geluid, bij het klikken op een link, posten op een formulier, en het wijzigen van de src van bijv. een frame/iframe. Daarom is deze oplossing zo cool, omdat je dan gewoon stilletjes data kan ophalen.

Voor crossbrowser support zou je dan nog gebruik kunnen maken van bijv.

- wijzigen van een iframe.src ipv script.src
- het omzetten van attributes in je functie, naar input hidden fields, en dan een form submitten
- xmlHttp, en naar wens gebruik maken van xml, of gewoon plaintext

etc. genoeg mogelijkheden om dingen verborgen te doen, en alleen de data op te halen die je nodig hebt. Voor mij was het klik geluid bij alles wat je deed gewoon storend omdat ik ook andere geluiden waaronder gesproken messages gebruikte embedded in de web applicatie.

Verwijderd

Hehe, dat klikgeluid had ik me nog niet eens gerealiseerd (het eerste wat ik doe na installatie van windows is TweakUI installeren, en dan alle geluidjes uitschakelen).

Het ging mij voornamelijk om een techniek om wat meer ingewikkelde bookmarklets te maken, en dan wil je javascript terug..

Een andere coole manier is om de img.src te gebruiken, en je data in een cookie te verstoppen (zo doet RSLite het). Dat werkt bijna overal, tenzij met de koekjes uit heeft staan (maar ja, wat werkt dan nog wel).

Verwijderd

Bij een reload krijg je geen klikgeluid.

Je zou ook de informatie achter het src attribuut van de img kunnen zetten, ipv een cookie, dmv server-side redirect.

Ik heb wel zoiets van: als een browser al niet eens een script dynamisch kunnen invoegen, zijn ze dan uberhaupt wel geschikt voor de leukere bookmarklets? :P

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:21

crisp

Devver

Pixelated

alternatief (erg ranzig): een div creeeren, en daar met innerHTML een script tag inzetten. Geen idee of dat wel werkt in Opera / Safari. Ik weet wel dat het schrijven van een scripttag dmv document.write wel werkt in al deze browsers.

Intentionally left blank


Verwijderd

Hmm, ik denk maar dat ik ga opgeven. Voor Opera werkt het dus wel, als er al een script-tag is, en voor Safari ga ik maar 's een bugje filen.

Verwijderd

Topicstarter
Verwijderd schreef op 28 September 2003 @ 20:32:
Hmm, ik denk maar dat ik ga opgeven. Voor Opera werkt het dus wel, als er al een script-tag is, en voor Safari ga ik maar 's een bugje filen.
Safari ondersteund ook gewoon xmlhttp, dus het is alsnog geen probleem.

Verwijderd

Oh? Hoe dan? XMLHttpRequest is undefined in Safari.
Geef 's code. Als dat waar is, is dat zeer goed nieuws :)
Pagina: 1