Adding inline javascript at the end of the page body

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Adding inline javascript at the end of the page body

Numa Schmeder-5
Hello,

I am using Tapestry 5.4 beta 6.
I am trying to add a script block at the very end of the page body, after tapestry has written all its javascript.
I know there are 2 ways: using javascriptSupport.addScript or javascriptSupport.require or creating one js file par page and load it via AMD.
But i want it to output a simple raw javascript block at the very end of the page.
I tried to create a component “Javascript” to do just that, but I can’t figure how to render at the very end of the page after all other javascript.
The reason is that sometimes outputting a block in the main page is simpler than to create one js file per page and then to require it.
Also it’s quit complicated to always have to modify Java files to add a bit of javascript.

Here is my component:

public class Javascript {

   @Environmental
   private JavaScriptSupport javaScriptSupport;

   @Inject
   private ComponentResources componentResources;

   void setupRender(MarkupWriter writer) {
       writer.element("script").attribute("type", "text/javascript");
   }

   public void afterRender(final MarkupWriter writer) {
       Element wrapper = writer.getElement();
       writer.end();
       final String bodyMarkup = wrapper.getChildMarkup();
       wrapper.remove();
       javaScriptSupport.addScript(bodyMarkup);

   }
}

This component does work, but I don’t like the fact that Tapestry is evaluating my js.
I want a rather simple output just before the “html” close tag:

<script type=“text/javascript">
        var myscript = “goes here”;
</script>

If I add multiple time this component, I want it to stack all the inline javascript together in the order they appeared in the page.
I use AMD a lot but forcing AMD is not a good solution. I think that was the way it worked with Tapestry 5.3.

Also the  javaScriptSupport.addScript method is deprecated, the  javaScriptSupport.require should be used, but it does not the same.
What is the equivalent of addScript in Tapestry5.4

Is there a way to bypass pageinit to initialize or add scripts and have them at the end of the page ?

Thanks for your help.

Numa
---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Adding inline javascript at the end of the page body

Thiago H de Paula Figueiredo
On Mon, 23 Jun 2014 10:53:38 -0300, Numa Schmeder <[hidden email]> wrote:

> Hello,

Hi!

> I am using Tapestry 5.4 beta 6.
> I am trying to add a script block at the very end of the page body,  
> after tapestry has written all its javascript.
> I know there are 2 ways: using javascriptSupport.addScript or  
> javascriptSupport.require or creating one js file par page and load it  
> via AMD.

You forgot about creating one .js file and using @Import.

> But i want it to output a simple raw javascript block at the very end of  
> the page.
> I tried to create a component “Javascript” to do just that, but I can’t  
> figure how to render at the very end of the page after all other  
> javascript.
> The reason is that sometimes outputting a block in the main page is  
> simpler than to create one js file per page and then to require it.

It may be simpler, but it doesn't pay off in the end. In addition, you  
don't need to create one .js file for each page: you can create a single  
one containing all the JS code you want and @Import it everywhere you need  
it. Tapestry will only include it once, no matter how many components  
@Import it.

> Also the  javaScriptSupport.addScript method is deprecated, the  
> javaScriptSupport.require should be used, but it does not the same.
> What is the equivalent of addScript in Tapestry5.4

There's none, exactly because adding raw JavaScript in Java isn't the best  
option.

> Is there a way to bypass pageinit to initialize or add scripts and have  
> them at the end of the page ?

You can write and contribute a MarkupRendererFilter, but then it's not a  
component anymore.

--
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Adding inline javascript at the end of the page body

Numa Schmeder-5
Thanks for your answer!
Le 23 juin 2014 à 16:17, Thiago H de Paula Figueiredo <[hidden email]> a écrit :

> On Mon, 23 Jun 2014 10:53:38 -0300, Numa Schmeder <[hidden email]> wrote:
>
>> Hello,
>
> Hi!
>
>> I am using Tapestry 5.4 beta 6.
>> I am trying to add a script block at the very end of the page body, after tapestry has written all its javascript.
>> I know there are 2 ways: using javascriptSupport.addScript or javascriptSupport.require or creating one js file par page and load it via AMD.
>
> You forgot about creating one .js file and using @Import.
Yes that’s what I was meaning with one js file per page, you need to use the @Import.
But I have a special use case where all js is not in the context but on separate server. And the @Import makes things a bit complicated.
Would be nice to have @Import working with absolute path or have a special @ImportUrl
>
>> But i want it to output a simple raw javascript block at the very end of the page.
>> I tried to create a component “Javascript” to do just that, but I can’t figure how to render at the very end of the page after all other javascript.
>> The reason is that sometimes outputting a block in the main page is simpler than to create one js file per page and then to require it.
>
> It may be simpler, but it doesn't pay off in the end. In addition, you don't need to create one .js file for each page: you can create a single one containing all the JS code you want and @Import it everywhere you need it. Tapestry will only include it once, no matter how many components @Import it.
That’s true, but I like to break my js on each page instead of having one big js, but you are absolutely right.
The thing is that when prototyping quickly, the ability to inline javascript is very useful.
Once you are happy with your prototype you can do some cleaning and organize your js better.
>
>> Also the  javaScriptSupport.addScript method is deprecated, the  javaScriptSupport.require should be used, but it does not the same.
>> What is the equivalent of addScript in Tapestry5.4
>
> There's none, exactly because adding raw JavaScript in Java isn't the best option.
Well actually we can use the documentLink.addScript, this one is not yet deprecated…

>
>> Is there a way to bypass pageinit to initialize or add scripts and have them at the end of the page ?
>
> You can write and contribute a MarkupRendererFilter, but then it's not a component anymore.
This sounds over complicated and as you said it’s not a component anymore.

Based on the initial work of Adam Henderson https://github.com/adamhenderson/tapestry-dojo.
I have fully ported the dojo stack to tapestry. All core components do work (forms, ajax, zones, confirm, autocomplete etc…)
I have kept only the underscore library dependency, though I could get rid of it, as most underscore functions are available within dojo.
I will release all the changes in one jar and put on github.
I am just having some difficulties with the @Symbol usage.
The dojoConfig javascript object is created by contributing specific symbols.
But some config properties of dojoConfig are optional, and if I set a Symbol to null, I get an exception.
So the workaround is to set all my symbols to strings, and an empty string value means don’t set this property.
I don’t know if there is a better way.
Also dojo amd loader doesn’t provide the ability to shim non amd libraries and have init calls per file load.
I am still figuring out how it works with tapestry module dependency amd and loading, it’s not completely clear.

While doing all this work I have notice a weird behavior that is reproducible with the jquery stack.
When you update a zone or refresh it. The divs start to nest on inside each other. Exemple:

<div id=“zone">
        My initial zone
</div>

After 2 updates, the zone content becomes:

<div id=“zone">
        <div id=“zone_84847657567">
                <div id=“zone_874747899884">
                        My initial zone after 2 updates
                </div>
        </div>
</div>

I would have thought that should replace the content and have the following html:

<div id=“zone">
                        My initial zone after 2 updates
</div>




>
> --
> Thiago H. de Paula Figueiredo
> Tapestry, Java and Hibernate consultant and developer
> http://machina.com.br
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Adding inline javascript at the end of the page body

Thiago H de Paula Figueiredo
On Mon, 23 Jun 2014 11:53:39 -0300, Numa Schmeder <[hidden email]> wrote:

> Thanks for your answer!

;)

> Yes that’s what I was meaning with one js file per page, you need to use  
> the @Import.
> But I have a special use case where all js is not in the context but on  
> separate server. And the @Import makes things a bit complicated.
> Would be nice to have @Import working with absolute path or have a  
> special @ImportUrl

If there isn't a JIRA for that, please file one.

> The thing is that when prototyping quickly, the ability to inline  
> javascript is very useful.
> Once you are happy with your prototype you can do some cleaning and  
> organize your js better.

Ok, but in software development, usually nothing gets organized with time  
. . .

> Well actually we can use the documentLink.addScript, this one is not yet  
> deprecated…

That's an internal service (DocumentLinker), so no guarantees about  
backward compatibility of it.

>>> Is there a way to bypass pageinit to initialize or add scripts and  
>>> have them at the end of the page ?
>>
>> You can write and contribute a MarkupRendererFilter, but then it's not  
>> a component anymore.
> This sounds over complicated and as you said it’s not a component  
> anymore.

Yeah, but you're requirements are too specific for a component.

> Based on the initial work of Adam Henderson  
> https://github.com/adamhenderson/tapestry-dojo.
> I have fully ported the dojo stack to tapestry. All core components do  
> work (forms, ajax, zones, confirm, autocomplete etc…)
> I have kept only the underscore library dependency, though I could get  
> rid of it, as most underscore functions are available within dojo.
> I will release all the changes in one jar and put on github.

Nice!

> I am just having some difficulties with the @Symbol usage.
> The dojoConfig javascript object is created by contributing specific  
> symbols.
> But some config properties of dojoConfig are optional, and if I set a  
> Symbol to null, I get an exception.
> So the workaround is to set all my symbols to strings, and an empty  
> string value means don’t set this property.

Symbols don't accept null values by design, so you're doing the right  
thing here.

> When you update a zone or refresh it. The divs start to nest on inside  
> each other. Exemple:
>
> <div id=“zone">
> My initial zone
> </div>
>
> After 2 updates, the zone content becomes:
>
> <div id=“zone">
> <div id=“zone_84847657567">
> <div id=“zone_874747899884">
> My initial zone after 2 updates
> </div>
> </div>
> </div>

You're probably returning the zone object instead of zone.getBody(). Did I  
get it right?

--
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Adding inline javascript at the end of the page body

Numa Schmeder-5
I will add a JIRA then :)

Concerning the zone ajax issue:

I am returning zone.getBody()

Give it try, you will see that with jquery you get the same behavior.

Maybe it’s by design, but I think it’s a bug of the core js stack the function ElementWrapper.update
adds nested div one after the other instead of completely replacing the content of the zone div…

Also the zone id shouldn’t change on subsequent request… As you have seen each nested div has a different zone id.
I don’t know what should be the normal behavior. This is the behavior I have identified.
1/ The ajax response send the zone body wrapped inside the zone div that has a new id which a combination of the original zone id and a timestamp.
2/ The core javascript replaces the zone body with the received zone body wrapped in this zone div.

But maybe it’s me doing something wrong…

The point 2/ should be:
Extract the received zone body wrapped in a div, then replace the original zone body.
Questions: what should happen if the zone div has any informal parameter changed (such as a css class) due to an ajax request. Should these changes be reflected on the client or only the changes in the body ?

Cheers,
Numa




Le 23 juin 2014 à 17:21, Thiago H de Paula Figueiredo <[hidden email]> a écrit :

> On Mon, 23 Jun 2014 11:53:39 -0300, Numa Schmeder <[hidden email]> wrote:
>
>> Thanks for your answer!
>
> ;)
>
>> Yes that’s what I was meaning with one js file per page, you need to use the @Import.
>> But I have a special use case where all js is not in the context but on separate server. And the @Import makes things a bit complicated.
>> Would be nice to have @Import working with absolute path or have a special @ImportUrl
>
> If there isn't a JIRA for that, please file one.
>
>> The thing is that when prototyping quickly, the ability to inline javascript is very useful.
>> Once you are happy with your prototype you can do some cleaning and organize your js better.
>
> Ok, but in software development, usually nothing gets organized with time . . .
>
>> Well actually we can use the documentLink.addScript, this one is not yet deprecated…
>
> That's an internal service (DocumentLinker), so no guarantees about backward compatibility of it.
>
>>>> Is there a way to bypass pageinit to initialize or add scripts and have them at the end of the page ?
>>>
>>> You can write and contribute a MarkupRendererFilter, but then it's not a component anymore.
>> This sounds over complicated and as you said it’s not a component anymore.
>
> Yeah, but you're requirements are too specific for a component.
>
>> Based on the initial work of Adam Henderson https://github.com/adamhenderson/tapestry-dojo.
>> I have fully ported the dojo stack to tapestry. All core components do work (forms, ajax, zones, confirm, autocomplete etc…)
>> I have kept only the underscore library dependency, though I could get rid of it, as most underscore functions are available within dojo.
>> I will release all the changes in one jar and put on github.
>
> Nice!
>
>> I am just having some difficulties with the @Symbol usage.
>> The dojoConfig javascript object is created by contributing specific symbols.
>> But some config properties of dojoConfig are optional, and if I set a Symbol to null, I get an exception.
>> So the workaround is to set all my symbols to strings, and an empty string value means don’t set this property.
>
> Symbols don't accept null values by design, so you're doing the right thing here.
>
>> When you update a zone or refresh it. The divs start to nest on inside each other. Exemple:
>>
>> <div id=“zone">
>> My initial zone
>> </div>
>>
>> After 2 updates, the zone content becomes:
>>
>> <div id=“zone">
>> <div id=“zone_84847657567">
>> <div id=“zone_874747899884">
>> My initial zone after 2 updates
>> </div>
>> </div>
>> </div>
>
> You're probably returning the zone object instead of zone.getBody(). Did I get it right?
>
> --
> Thiago H. de Paula Figueiredo
> Tapestry, Java and Hibernate consultant and developer
> http://machina.com.br
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Adding inline javascript at the end of the page body

JumpStart
A while back I stopped returning Zone, or its body, preferring to use AjaxResponseRenderer#addRender instead. So I'm curious - do you see the same effect if you use AjaxResponseRenderer#addRender?

On 24 Jun 2014, at 7:34 pm, Numa Schmeder <[hidden email]> wrote:

> I will add a JIRA then :)
>
> Concerning the zone ajax issue:
>
> I am returning zone.getBody()
>
> Give it try, you will see that with jquery you get the same behavior.
>
> Maybe it’s by design, but I think it’s a bug of the core js stack the function ElementWrapper.update
> adds nested div one after the other instead of completely replacing the content of the zone div…
>
> Also the zone id shouldn’t change on subsequent request… As you have seen each nested div has a different zone id.
> I don’t know what should be the normal behavior. This is the behavior I have identified.
> 1/ The ajax response send the zone body wrapped inside the zone div that has a new id which a combination of the original zone id and a timestamp.
> 2/ The core javascript replaces the zone body with the received zone body wrapped in this zone div.
>
> But maybe it’s me doing something wrong…
>
> The point 2/ should be:
> Extract the received zone body wrapped in a div, then replace the original zone body.
> Questions: what should happen if the zone div has any informal parameter changed (such as a css class) due to an ajax request. Should these changes be reflected on the client or only the changes in the body ?
>
> Cheers,
> Numa
>
>
>
>
> Le 23 juin 2014 à 17:21, Thiago H de Paula Figueiredo <[hidden email]> a écrit :
>
>> On Mon, 23 Jun 2014 11:53:39 -0300, Numa Schmeder <[hidden email]> wrote:
>>
>>> Thanks for your answer!
>>
>> ;)
>>
>>> Yes that’s what I was meaning with one js file per page, you need to use the @Import.
>>> But I have a special use case where all js is not in the context but on separate server. And the @Import makes things a bit complicated.
>>> Would be nice to have @Import working with absolute path or have a special @ImportUrl
>>
>> If there isn't a JIRA for that, please file one.
>>
>>> The thing is that when prototyping quickly, the ability to inline javascript is very useful.
>>> Once you are happy with your prototype you can do some cleaning and organize your js better.
>>
>> Ok, but in software development, usually nothing gets organized with time . . .
>>
>>> Well actually we can use the documentLink.addScript, this one is not yet deprecated…
>>
>> That's an internal service (DocumentLinker), so no guarantees about backward compatibility of it.
>>
>>>>> Is there a way to bypass pageinit to initialize or add scripts and have them at the end of the page ?
>>>>
>>>> You can write and contribute a MarkupRendererFilter, but then it's not a component anymore.
>>> This sounds over complicated and as you said it’s not a component anymore.
>>
>> Yeah, but you're requirements are too specific for a component.
>>
>>> Based on the initial work of Adam Henderson https://github.com/adamhenderson/tapestry-dojo.
>>> I have fully ported the dojo stack to tapestry. All core components do work (forms, ajax, zones, confirm, autocomplete etc…)
>>> I have kept only the underscore library dependency, though I could get rid of it, as most underscore functions are available within dojo.
>>> I will release all the changes in one jar and put on github.
>>
>> Nice!
>>
>>> I am just having some difficulties with the @Symbol usage.
>>> The dojoConfig javascript object is created by contributing specific symbols.
>>> But some config properties of dojoConfig are optional, and if I set a Symbol to null, I get an exception.
>>> So the workaround is to set all my symbols to strings, and an empty string value means don’t set this property.
>>
>> Symbols don't accept null values by design, so you're doing the right thing here.
>>
>>> When you update a zone or refresh it. The divs start to nest on inside each other. Exemple:
>>>
>>> <div id=“zone">
>>> My initial zone
>>> </div>
>>>
>>> After 2 updates, the zone content becomes:
>>>
>>> <div id=“zone">
>>> <div id=“zone_84847657567">
>>> <div id=“zone_874747899884">
>>> My initial zone after 2 updates
>>> </div>
>>> </div>
>>> </div>
>>
>> You're probably returning the zone object instead of zone.getBody(). Did I get it right?
>>
>> --
>> Thiago H. de Paula Figueiredo
>> Tapestry, Java and Hibernate consultant and developer
>> http://machina.com.br
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [hidden email]
>> For additional commands, e-mail: [hidden email]
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Adding inline javascript at the end of the page body

Thiago H de Paula Figueiredo
In reply to this post by Numa Schmeder-5
On Tue, 24 Jun 2014 06:34:25 -0300, Numa Schmeder <[hidden email]> wrote:

> Also the zone id shouldn’t change on subsequent request… As you have  
> seen each nested div has a different zone id.

Use Zone's id parameter and that won't happen.

--
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]