The correct approach is to modify the DocumentLinker service (which is internal) to place the <script> tags where you want.
On Thu, Oct 21, 2010 at 1:52 AM, janp <[email protected]> wrote: > > This post describes a service, that enables Tapestry to append JavaScript > files and script parts at the end of a html file. Script files and scripts > can be "dropped into the service" from any page class or component and will > be rendered in that order (FIFO) at the end of the page. > > Upgrade Tapestry 5.0.x to Tapestry 5.1. loads included JavaScript files in > the HTML head. Reasons are discussed in the Upgrade Notes: > http://tapestry.apache.org/tapestry5.1/upgrade.html > project-wide release notes. They told me that in fix for bug TAP5-544: > Firstly, JavaScript libraries would have to move (back) to the head, > permanently, no configuration [...]. > Maybe I did not understand the real concern, but: Why isn't it up to the > developer to decide where to place script files? > I decided to write a component that appends my script files at the end of my > html files. The most important reason for this descicion is, that--following > Yahoo's performance guidelines--I'd like to first load my HTML DOM before > loading the script files. > > Write a Service to Collect Files to Append > We need an Interface to be able to use the perthread scope (more about > scoypes: "a per-thread instance is created on demand, behind a shared > proxy"). > The Interface just consists of 4 methods. 2 to add Script files and Scripts > to the list and 2 to get the lists when they should be rendered: > public interface IAppendedScriptsService { > > /** > * Add a script file to the list of script files to append. > * > * @param scriptFile > */ > public void addScriptFile(String scriptFile); > > /** > * Add a script to the list of scripts to append. > * > * @param script > */ > public void addScript(String script); > > /** > * Returns a list with script files to append. Needs to be a list to > preserve order of script files. > * > * @return list with script files to append. > */ > public List getScriptFiles(); > > /** > * Returns a list with scripts to append. Needs to be a list to preserve > order of scripts. > * > * @return list with scripts to append. > */ > public List getScripts(); > } > The implementation of the Interface could looks like the following block. > Don't forget to set the scope to perthread. > @Scope(value = ScopeConstants.PERTHREAD) > public class AppendedScriptsService implements IAppendedScriptsService { > > private final List scriptFiles = new ArrayList(); > private final List scripts = new ArrayList(); > > �...@override > public void addScriptFile(String scriptFile) { > this.scriptFiles.add(scriptFile); > } > > �...@override > public void addScript(String script) { > this.scripts.add(script); > } > > �...@override > public List getScriptFiles() { > return this.scriptFiles; > } > > �...@override > public List getScripts() { > return this.scripts; > } > > } > Build the Component > The Component was easy to write. It consists of just one method to render > the scripts: > // Inject the service we just wrote. > �...@inject > private IAppendedScriptsService appendedScriptsService; > > // This method is called when component should be rendered. (Markup > writer infos here) > void beginRender(MarkupWriter markupWriter) { > > // Output script files. > if (!this.appendedScriptsService.getScriptFiles().isEmpty()) { > for (final String file : > this.appendedScriptsService.getScriptFiles()) { > // There might be another (tapestry conform way) to create > the source link. My way is > String fileUrl = "MyAssetsServerURL".resolveRelative(file); > markupWriter.element("script", "type", "text/javascript", > "src", fileUrl); > markupWriter.end(); > } > } > > // Output script snippets. > if (!this.appendedScriptsService.getScripts().isEmpty()) { > for (final String script : > this.appendedScriptsService.getScripts()) { > markupWriter.element("script", "type", "text/javascript"); > markupWriter.getElement().text(script); > markupWriter.end(); > } > } > > } > That's all to implement. Just one last step to make this run: > > Activate Service in AppModule > To activate your Service, following method must be inserted into > AppModule.java (or just insert the binder-line if there is already such a > method): > public static void bind(ServiceBinder binder) { > binder.bind(IAppendedScriptsService.class, AppendedScriptsService.class); > } > User Component > To use this Component, you just have to add this into a class of a page or > component: > > @Inject > private IAppendedScriptsService appendedScriptsService; > > /** > * Append JavaScripts > **/ > void setupRender() { > this.appendedScriptsService.addScriptFile("UrlToScript"); > appendedScriptsService.addScript("var x = 'cool';"); > } > The order of scripts and script files is preserved. > > Do you have any comments? Please, let's discuss this. > > > > > -- > View this message in context: > http://tapestry.1045711.n5.nabble.com/Append-JavaScript-at-the-end-of-my-html-file-Component-for-Tapestry-5-1-tp3230082p3230082.html > Sent from the Tapestry - Dev mailing list archive at Nabble.com. > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > > -- Howard M. Lewis Ship Creator of Apache Tapestry The source for Tapestry training, mentoring and support. Contact me to learn how I can get you up and productive in Tapestry fast! (971) 678-5210 http://howardlewisship.com --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
