[Proto-Scripty] Re: Ajax.Updater and JavaScript source files inclusions
I cam across these related tickets: http://dev.rubyonrails.org/ticket/6722 http://dev.rubyonrails.org/ticket/9871 I think it would probably be critical for many use cases that the scripts load synchronously in order of appearance after an element is updated. Maybe another value for the evalScripts option could be used like 'all' or 'all-sync', signifying that both inline and external js would be loaded dynamically, async or sync. -Mark --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group. To post to this group, send email to prototype-scriptaculous@googlegroups.com To unsubscribe from this group, send email to prototype-scriptaculous+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en -~--~~~~--~~--~--~---
[Proto-Scripty] Re: Ajax.Updater and JavaScript source files inclusions
Thanks for all your advices T.J.! I read some snippets of the Proto- Scripty wiki and my dynamic script loading was in the right way. > It doesn't process them if you assign them as strings via innerHTML, > which is what your modified update would do (Element#update uses > innerHTML behind the scenes). It does process them correctly if you > insert them using DOM methods as your code does, even if you don't put > them in the head. Hm, actually I'm already using Prototype 1.6.1 RC2 (by the way, thanks for this IE8 special release) and it seems that Element#update has been completely reworked but still uses the innerHTML approach. I'm I wrong? > Ah, interesting approach. I think I'd prefer to leave Prototype > unmodified and build my own updater-like-thing via Ajax.Request, but > obviously it's up to you. Don't worry, the registration of the Ajax.Responders callback is not done in prototype.js but in a specific initialization script! ;) Actually, all our asynchronous updates are already delegating to Ajax.Request because validation and exception messages thrown by the usecase workflow do not produce failed requests but are instead redirected to some specific forward page, which will allow to capture these kind of errors: Ajax.Request.prototype.error = false; Ajax.Responders.register({ onComplete: function(responder) { // Ensure that external scripts are successfully loaded: var reponseText = responder.transport.responseText; reponseText.scan(/]*src="(.*)"[^>]*>/, function(match){ Application.loadScript(match[1]); }); } }); /* This should be part of Prototype Ajax core... ;) */ Object.extend(Ajax.Updater, { callbacks : [], register : function(callback){ this.callbacks.push(callback); }, }); Object.extend(Ajax, { [...] update: function(element, url, options){ element = $(element); options = Ajax._checkOptions(options); options.onComplete = options.onComplete.wrap(function(original, transport){ element.update(transport.responseText); // Apply update callbacks: Ajax.Updater.callbacks.each(function(callback){ callback(element); }); original(transport); }); // Delegate: return Ajax.request(url, options); }, request : function(url, options){ options = Ajax._checkOptions(options); options.onComplete = options.onComplete.wrap(function(original, transport){ // Check for worflow errors (note that response has already been evaluated): if (transport.request.error){ options.onError(transport); } else { original(transport); } }); // Delegate: return new Ajax.Request(url, options); }, } Don't hesitate to 'pimp' my code, if you detect some conflict. Hope this may be usefull for anyone using the Struts forward engine. > Very likely. The inline scripts will get evaluated very, very soon > after the content is updated (Element#update does it via Function#defer > [1]), whereas the external scripts may still be downloading at that > point. A really robust solution would probably walk through the > script tags (inline and external) in the order in which they appear > and load/execute them sequentially... You're right. Currently, I'm using events to notify observers that script successfully loaded but your idea about scanning and executing all script tags may be implemented when I'll get some time to spend on JS optimization. Thanks a lot! --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group. To post to this group, send email to prototype-scriptaculous@googlegroups.com To unsubscribe from this group, send email to prototype-scriptaculous+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en -~--~~~~--~~--~--~---
[Proto-Scripty] Re: Ajax.Updater and JavaScript source files inclusions
Hi, > Yes, I could control this as output mostly comes from source files > that have been automatically generated (MDA approach) but I think this > solution would break browser file cache. It wouldn't, but you couldn't have known that as you couldn't see the wiki article. :-) > I couldn't check Proto- > Scripty wiki (seems to be down...) to learn about dynamic script > loading but this put me in the way. Wow, I've never known wikidot (where the wiki is hosted) to be down. I suppose it must happen. :-) It's working right now as I write this (I followed the link in my earlier note to make sure it wasn't a typo). > Nevertheless, it seems that Firefox does not load external script > files unless they are inserted in the HTML head element (can someone > confirm that?). It doesn't process them if you assign them as strings via innerHTML, which is what your modified update would do (Element#update uses innerHTML behind the scenes). It does process them correctly if you insert them using DOM methods as your code does, even if you don't put them in the head. But putting them in the head is probably the most appropriate thing to do anyway, and indeed is exactly what the unofficial wiki article does. :-) > In fact, I choose to use Ajax.Responders to parse response text from > output and dynamically load any external source files... Ah, interesting approach. I think I'd prefer to leave Prototype unmodified and build my own updater-like-thing via Ajax.Request, but obviously it's up to you. > Nevertheless, I think that inline scripts may be executed before > external resource has been completely interpreted, which may lead to > invalid references. Very likely. The inline scripts will get evaluated very, very soon after the content is updated (Element#update does it via Function#defer [1]), whereas the external scripts may still be downloading at that point. A really robust solution would probably walk through the script tags (inline and external) in the order in which they appear and load/execute them sequentially. I think if you were going to do that, you'd have to retrieve the script files directly (via XHR calls) rather than inserting script tags, because otherwise I'm not sure how you'd be able to know that the file had finished loading. XHR stuff *should* use the browser cache, and I understand it mostly does although there are some revalidation issues reported in the XHR Wikipedia article (mostly indicating that stale content may get reused, as opposed to getting re-retrieved too often).[2] [1] http://prototypejs.org/api/function/defer [2] http://en.wikipedia.org/wiki/XMLHttpRequest Have fun, -- T.J. Crowder tj / crowder software / com Independent Software Engineer, consulting services available On May 6, 2:45 pm, almeidap wrote: > Thanks for your quick and complete answer! I've followed your hints > and I think that I've reached an elegant (but maybe not performant) > solution. > > > String#evalScripts uses String#extractScripts[4], which uses this > > regex repeatedly to build an array of the contents of script tags: > > ']*>([\\S\\s]*?)<\/script>' ... > > Right! I adapted Prototype's regex to leave script tags that reference > an external source file, simply by redefining the Prototype's > ScriptFragment property (argh, it took me about 1 hour to find that > crazy regex): > Prototype.ScriptFragment = ']*>([\\S\\s]*?)<\/ > script>'; > > Nevertheless, it seems that Firefox does not load external script > files unless they are inserted in the HTML head element (can someone > confirm that?). That means that even if the script element was > inserted into the DOM after update, script contents were never > interpreted. > > > The second approach, which may be simpler, only works if you're in > > control of what comes back (e.g., you're not calling some third-party > > code you don't have control over). If you are in control of it, you > > could change it to use inline script to load external scripts, rather > > than script tags. > > Yes, I could control this as output mostly comes from source files > that have been automatically generated (MDA approach) but I think this > solution would break browser file cache. I couldn't check Proto- > Scripty wiki (seems to be down...) to learn about dynamic script > loading but this put me in the way. > > In fact, I choose to use Ajax.Responders to parse response text from > output and dynamically load any external source files by appending a > script element in the HTML head (inspired by [1], feel free to reveal > problems or to suggest optimizations): > > Ajax.Responders.register({ > onComplete: function(responder) { > var reponseText = responder.transport.responseText; > reponseText.scan(/]*src="(.*)"[^>]*>/, function(match){ > ActionUtils.loadScript(match[1]); > }); > } > > }); > > ActionUtils = { > > ... > > Resources : [], > > loadScript : function(resource, onload) { > if(
[Proto-Scripty] Re: Ajax.Updater and JavaScript source files inclusions
Thanks for your quick and complete answer! I've followed your hints and I think that I've reached an elegant (but maybe not performant) solution. > String#evalScripts uses String#extractScripts[4], which uses this > regex repeatedly to build an array of the contents of script tags: > ']*>([\\S\\s]*?)<\/script>' ... Right! I adapted Prototype's regex to leave script tags that reference an external source file, simply by redefining the Prototype's ScriptFragment property (argh, it took me about 1 hour to find that crazy regex): Prototype.ScriptFragment = ']*>([\\S\\s]*?)<\/ script>'; Nevertheless, it seems that Firefox does not load external script files unless they are inserted in the HTML head element (can someone confirm that?). That means that even if the script element was inserted into the DOM after update, script contents were never interpreted. > The second approach, which may be simpler, only works if you're in > control of what comes back (e.g., you're not calling some third-party > code you don't have control over). If you are in control of it, you > could change it to use inline script to load external scripts, rather > than script tags. Yes, I could control this as output mostly comes from source files that have been automatically generated (MDA approach) but I think this solution would break browser file cache. I couldn't check Proto- Scripty wiki (seems to be down...) to learn about dynamic script loading but this put me in the way. In fact, I choose to use Ajax.Responders to parse response text from output and dynamically load any external source files by appending a script element in the HTML head (inspired by [1], feel free to reveal problems or to suggest optimizations): Ajax.Responders.register({ onComplete: function(responder) { var reponseText = responder.transport.responseText; reponseText.scan(/]*src="(.*)"[^>]*>/, function(match){ ActionUtils.loadScript(match[1]); }); } }); ActionUtils = { ... Resources : [], loadScript : function(resource, onload) { if(!this.Resources.include(resource)){ var script = new Element('script', { 'type' : 'text/javascript', 'src' : resource }); script.onload = onload | this.emptyFunction; this.getHtmlHead().insert(script); this.Resources.push(resource); } } } (Prototype's ScriptFragment property has not been changed in this scenario!) In this way, developpers don't bother how to include external JS files, the asynchronous circuit does all the job for them. Nevertheless, I think that inline scripts may be executed before external resource has been completely interpreted, which may lead to invalid references. This has only been tested on Firefox, so let me know if it works with other main browsers. [1] http://www.phpied.com/javascript-include-ready-onload/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group. To post to this group, send email to prototype-scriptaculous@googlegroups.com To unsubscribe from this group, send email to prototype-scriptaculous+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en -~--~~~~--~~--~--~---
[Proto-Scripty] Re: Ajax.Updater and JavaScript source files inclusions
Hi, > Is there a work around to force Prototype to leave JavaScript source > files inclusions after Ajax updates? Nothing built into Prototype. If you search through Lighthouse[1] or this group (I forget which) there was a discussion about possibly adding that at some stage. In the meantime, I see two options: One is that you can use Ajax.Request rather than Ajax.Updater and process the result yourself. At its core, Ajax.Updater just processes a successful result by calling Element#update[2], which uses String#evalScripts[3] to execute the inline scripts (but not the ones referencing external files). You could replace it with Ajax.Request, look for the script tags referencing external files, and process them yourself. String#evalScripts uses String#extractScripts[4], which uses this regex repeatedly to build an array of the contents of script tags: ']*>([\\S\\s]*?)<\/script>' As you can see, the only capture group there is for the content between the script tags, and so the array String#extractScripts builds is only for inline scripts. You'd have to use a modified form to search for tags for external scripts. Once you have the external scripts, you can load them dynamically; some tips on doing that here[5] on the unofficial wiki. The second approach, which may be simpler, only works if you're in control of what comes back (e.g., you're not calling some third-party code you don't have control over). If you are in control of it, you could change it to use inline script to load external scripts, rather than script tags. E.g., instead of having the result contain: you could have it do this: loadExternalScript('somescriptfile.js'); ...where loadExternalScript is defined on the main page and (again) uses techniques like those suggested[5] on the unofficial wiki. [1] http://prototype.lighthouseapp.com/projects/8886-prototype/overview [2] http://prototypejs.org/api/element/update [3] http://prototypejs.org/api/string/evalScripts [4] http://prototypejs.org/api/string/extractScripts [5] http://proto-scripty.wikidot.com/prototype:how-to-load-scripts-dynamically HTH, -- T.J. Crowder tj / crowder software / com Independent Software Engineer, consulting services available On May 6, 9:30 am, almeidap wrote: > Hi, > > Our application has been enhanced with an asynchronous circuit (based > over the Prototype's Ajax class) that is able to load and navigate > through usecases in a modal window. > > When calling an usecase action in a asynchronous way, the circuit > returns only the needed HTML content (and not a full web page with the > HTML or HEAD tags) that may contain JavaScript source file inclusions, > like: > > "> script> > > When performing a such update (using Ajax.Updater(container, > actionUrl, {evalJS : true, evalScripts : true})), scripts are > correctly evaluated and removed from output. But script tags that > reference a source file are also removed and the contents of the > Javascript file will never be interpreted! > > Is there a work around to force Prototype to leave JavaScript source > files inclusions after Ajax updates? > > Thanks --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group. To post to this group, send email to prototype-scriptaculous@googlegroups.com To unsubscribe from this group, send email to prototype-scriptaculous+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en -~--~~~~--~~--~--~---