Primefaces javascript defer parsing - javascript

Primefaces 4.0 is generating lots of overhead during page loading as seen from PageSpeed Insights:
**605.3KiB of JavaScript is parsed during initial page load. Defer parsing JavaScript to reduce blocking of page rendering.**
http://localhost:8888/.../primefaces.js.xhtml?... (219.5KiB)
http://localhost:8888/.../jquery-plugins.js.xhtml?... (191.8KiB)
http://localhost:8888/.../jquery.js.xhtml?... (95.3KiB)
http://localhost:8888/.../tooltip.js.xhtml?... (34.5KiB)
http://localhost:8888/.../jsf.js.xhtml?... (25.4KiB)
http://localhost:8888/.../primefaces-extensions.js.xhtml?... (19.7KiB)
http://localhost:8888/.../watermark.js.xhtml?... (4.7KiB)
http://localhost:8888/.../hotkey.js.xhtml?... (1.2KiB)
Any idea how these 3rd party javascript files could be set to be in the bottom of the body section instead head or use defer/async parameters? Javascript loaders do not help in this case as these are coming from the JSF renderer. Also I tried to create a Listener for PreRenderView (Best way for JSF to defer parsing of JavaScript?) but that did not work out. Any other options that could solve this problem? Thanks for your help!

I got the moving of the scripts to work with the followind snippet:
public class ScriptValidateListener implements SystemEventListener {
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
UIViewRoot root = (UIViewRoot) event.getSource();
FacesContext ctx = FacesContext.getCurrentInstance();
List<UIComponent> resources = root.getComponentResources(ctx, "HEAD");
for (UIComponent r : resources) {
String name = (String) r.getAttributes().get("name");
if (name == null) {
continue;
}
if (name.contains(".js")) {
root.removeComponentResource(ctx, r, "HEAD");
root.addComponentResource(ctx, r, "BODY");
}
}
}
#Override
public boolean isListenerForSource(Object source) {
return (source instanceof UIViewRoot);
}
}
This moves all javascripts from HEAD to end of the BODY. But. There is this problem with Primefaces that the components rendered will try to access either JQuery ($.) or PrimeFaces javascript functions and that will break all ajax functionality on the page. Propably I will need to decide what of the scripts to move and what not to move. Also a part from the Listener I needed to define the following to faces-config.xml to make it work:
<application>
<system-event-listener>
<system-event-listener-class>com.example.listener.ScriptValidateListener</system-event-listener-class>
<system-event-class>javax.faces.event.PreRenderViewEvent</system-event-class>
</system-event-listener>
</application>

Related

upcall to javafx from javascript

I have a problem. I have two classes in same javafx package. A single html file with javascript at the head section, a java class(extending Application). Now the problem is when i tried to click the button after the page is displayed in the javafx webview, nothing is updated in the webView. Below is the code for the two file. Please i need to know why it isn't working. i have been debugging this problem since 8hrs now, no success. thanks in advance.
java class
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JavaFXApplication25 extends Application {
// inner class
public class Adder
{
public double add(double n, double m)
{
return n + m;
}
}
#Override
public void start(Stage primaryStage) throws URISyntaxException, MalformedURLException {
WebView w = new WebView();
WebEngine e = w.getEngine();
e.setJavaScriptEnabled(true);
e.load(this.getClass().getResource("tester.html").toURI().toURL().toExternalForm());
Scene scene = new Scene(new VBox(w));
primaryStage.setScene(scene);
primaryStage.show();
// make javascript aware of java object
e.getLoadWorker().stateProperty().addListener(
(p, o, n) ->{
if(n == Worker.State.SUCCEEDED){
JSObject b = (JSObject) e.executeScript("window");
b.setMember("adder", new Adder());
}
}
);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
The html file
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript">
function addNum(){
var n1 = Number(document.getElementById('num1').value);
var n2 = Number(document.getElementById('num2').value);
var n3 = adder.add(n1, n2);
document.getElementById('r').innerHTML = n3;
}
</script>
</head>
<body>
<input type="text" id="num1" />
<input type="text" id="num2" />
<p> <span id="r"> </span></p>
<button onclick="addNum()" >Add</button>
</body>
The point is that the programs runs and displays the page, but on pressing the button, nothing is updated on the page
I even tried to make the upcall before loading the html page, yet, no success. Please someone should help check the bug in the code. Thanks once again.
Now below is the output after been run. It shows nothing even after when the Add button is clicked several times! No error message on the standard console, nothing nothing!
output
if(n == Worker.State.SUCCEEDED){
JSObject b = (JSObject) e.executeScript("window");
b.setMember("adder", new Adder());
}
Welcome to the execrable pain in the ass that is DOM event sync between JavaFX and DOM stuff.
The worker state "SUCCEEDED" does not necessarily mean that the DOM is loaded in the page.
The DOM is loaded at document.onLoad() ... and even so it's kind of a can of worms since not all content is loaded by that time (images and stuff).
JQuery has a convenient JQuery(document).ready(function (e){ /*do whatever*/ }) routine you can use to trigger something that lets JavaFX know that it's ready to do stuff in the DOM (basically what you tried to accomplish with the code above [..]Worker.State.SUCCEEDED[..])
Essentially the sequence of events is something like:
1. JavaFX => Worker.state reaches SUCCEEDED STATE
2. DOM ====> Starts converting HTML into DOM components
3. ??? ====> This step is a complete mystery unbeknownst to even the savvy-est of skript kiddies. but i'm pretty sure this is where zuckerberg gets access to your webcam for a few frames. ... so beware!
4. DOM ====> Finishes doing its thing and fires off the onLoad() event which triggers the document.load() listener and associated function.
5. DOM ====> Officially inovkes the first JS function it comes across (not always the one you'd think it'd come across because JS is a magic programming language that doesn't give a shit about threads, or sequencing thereof, and anything goes when it comes JOs)
6. DOM+JS => Continues loading for some reason (i am not kidding)
7. DOM+JS => Some other weird flibbetlygibbletly bullshit done by the DOM and whatever javascript runs inside it ... if you're using timers... good luck.
8. DOM+JS => at this point, jQuery (if used) intercepts the .ready() event listener.
9. DOM+JS => believe me... stuff still isn't completely loaded. (because rampant JS scripts can add DOM components as they see fit and no .ready or .load event listener will ever be called.)
To add insult to injury, this sequence of events can take anywhere between 1ms and 1 minute to reach (8)... it's arbitrary as hell.
I wound up writing code which starts comparing node trees for changes in order to figure out when exactly to start messing with the DOM.... but i digress.
What you want is to make sure you initiate your JS-JavaFX communication protocol once the DOM is ready to run your custom javascript.
Put that shit in document.onLoad(), listen for it inside JavaFX, and then set the adder as you did so already... then hope for the best.
Thanks everyone...After a little research, i was able to come up with an extremely simple solution..Here it goes in steps:
declare a private field (which is an object of the class that contains the public methods to be called from javascript) in the main class.
instantiate the private field
add the member to the web engine after it loads
call the java method from the javascript.
so here goes the updated code
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JavaFXApplication25 extends Application {
// inner class
public class Adder
{
public double add(double n, double m)
{
return n + m;
}
}
// STEP 1: Now declare the private field (COMPULSORY)
private Adder adder;
#Override
public void start(Stage primaryStage) throws URISyntaxException, MalformedURLException {
WebView w = new WebView();
WebEngine e = w.getEngine();
e.setJavaScriptEnabled(true);
e.load(this.getClass().getResource("tester.html").toURI().toURL().toExternalForm());
Scene scene = new Scene(new VBox(w));
primaryStage.setScene(scene);
primaryStage.show();
//STEP 2: instantiate the private js object from step1
adder = new Adder();
// make javascript aware of java object
e.getLoadWorker().stateProperty().addListener(
(p, o, n) ->{
if(n == Worker.State.SUCCEEDED){
JSObject b = (JSObject) e.executeScript("window");
b.setMember("adder", new Adder());
}
}
);
}
/**
#param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
The HTML code still remains the same as before.
//Now, i think there is a bug in this aspect of javafx with jdk 8 and above. I am specifically using jdk 8_126...version. It seems there is automatic destruction of the javascript handler class by the jvm. Fortunately, wrapping the js hanler as a private field in the main class seems to prevent this terrible occurrence.

ScriptControl.AddCode without executing the code?

I'm working on a project in C# that get scripts (VBScript, Jscript and JavaScript) from the EA database and executes certain functions at specific moments.
To be able to do this I use the Microsoft ScriptControl.
First I add all script code to the ScriptControl using ScriptControl.AddCode and then I functions with a specific name.
The code that adds the code to the script control looks like this:
//create new scriptcontroller
this.scriptController = new ScriptControl();
this.scriptController.Language = this.language.name;
this.scriptController.AddObject("Repository", model.getWrappedModel());
//Add the actual code. This must be done in a try/catch because a syntax error in the script will result in an exception from AddCode
try
{
//first add the included code
string includedCode = this.IncludeScripts(this._code);
//then remove any statements that execute a function or procedure because scriptControl.AddCode actually executes those statements
string cleanedCode = this.language.removeExecutingStatements(includedCode);
//then add the cleaned code to the scriptcontroller
this.scriptController.AddCode(cleanedCode);
The problem is that apparently AddCode also executes the script code in some way, which is not what I want.
Say I have following VBScript:
sub main
MsgBox("main executed")
end sub
main
As soon as I add the code of this script to the ScriptControl using AddCode the main sub is executed and I see the messagebox appear.
Does anyone know an easy way to avoid executing the main sub in cases like this?
My current workaround (currently only implemented for VBScript) involves parsing the script code and stripping the line that calls functions or procedures, but that is pretty tedious and error prone.
/// <summary>
/// removes the statements that execute a function/procedure from the code
/// </summary>
/// <param name="code">the code with executing statements</param>
/// <returns>the code without executing statements</returns>
public override string removeExecutingStatements(string code)
{
StringReader reader = new StringReader(code);
string cleanedCode = code;
string line;
bool functionStarted = false;
bool subStarted = false;
while (null != (line = reader.ReadLine()))
{
if (line != string.Empty)
{
if (line.StartsWith(this.functionStart))
{
functionStarted = true;
}else if (line.StartsWith(this.subStart))
{
subStarted = true;
}else if (functionStarted && line.StartsWith(this.functionEnd))
{
functionStarted = false;
}
else if (subStarted && line.StartsWith(this.subEnd))
{
subStarted = false;
}else if (!functionStarted && !subStarted)
{
//code outside of a function or sub, figure out if this code calls another sub or function
foreach (string linepart in line.Split(new char[] {' ' , '(' },StringSplitOptions.RemoveEmptyEntries))
{
if (cleanedCode.Contains(this.functionStart + linepart)
||cleanedCode.Contains(this.subStart + linepart))
{
//found a line that calls an existing function or sub, replace it by an empty string.
cleanedCode = cleanedCode.Replace(Environment.NewLine +line + Environment.NewLine,
Environment.NewLine + string.Empty + Environment.NewLine);
}
}
}
}
}
return cleanedCode;
}
Any better idea is welcome.
If you want the script code modules to act as code libraries without any static initializers then you can enforce it by declaring it in coding conventions
If you want the static initializers and other side-effects not to appear until the run-time then you can postpone the script activation through delay loading the script when it is required for the first time
If you want to have more fine-grained control over the scripting environment than you can implement a scripting host and interact with the script engines more directly (e.g. using the IActiveScriptParse interface will not probably trigger any unexpected side-effects).
MSDN: Windows Script Interfaces
...To make implementation of the host as flexible as possible, an OLE Automation wrapper for Windows Script is provided. However, a host that uses this wrapper object to instantiate the scripting engine does not have the degree of control over the run-time name space, the persistence model, and so on, that it would if it used Windows Script directly.
The Windows Script design isolates the interface elements required only in an authoring environment so that nonauthoring hosts (such as browsers and viewers) and script engines (for example, VBScript) can be kept lightweight...
Main executes because you call it from a top level command. Anything not in sub/functions is executed.

GWT + SmartGWT + Javascript: external script integration

I am building a web application using GWT and SMartGWT and I need to integrate an external script for a Photo Gallery: http://slideshow.triptracker.net/.
My current attempt is:
ScriptInjector.fromUrl("http://slideshow.triptracker.net/slide.js").setCallback(
new Callback<Void, Exception>() {
public void onFailure(Exception reason) {
Window.alert("Script load failed.");
}
public void onSuccess(Void result) {
Window.alert("Script load success.");
}
}).inject();
Afterwards, I call this method:
Code:
native static void example(String p) /*-{
$wnd.viewer = new $wnd.PhotoViewer();
$wnd.viewer.add(p)
$wnd.viewer.show(0);
}-*/;
This does not give any error, but the photogallery appears BEHIND my Entry Point Layout, so it's not possible to use it.
So, I am trying to find a workaround and I would like to refer to the main layout from Javasript, to run the script on that. Is this possible? I've tried with
foo.getElement().getId();
but it returns me something like
isc_VLayout_0_wrapper
However, Javascript doesn't like it.
Then I tried
foo.getDOM.getId();
isc_1
But the result doesn't change.
Can someone help me fix this issue?
Thank You.
I think here are two things, that are possibly wrong:
You have an onSuccess() callback you can call the jsni call from within.
//1
ScriptInjector.fromUrl("http://slideshow.triptracker.net/slide.js").setCallback(
new Callback<Void, Exception>() {
public void onFailure(Exception reason) {
//3a
}
public void onSuccess(Void result) {
example("works");
//3b
}
}).inject();
//2
example("not loaded");
You may also try to call .setWindow(ScriptInjector.TOP_WINDOW) before calling .inject()

getting requestattributes in javascript

I want to retrieve the request scope attribute in javascript as follows. How can I achieve this?
function caseChanges(req) {
var innervalue= "${dashboardTicketSummary}"
alert("nand you are 1234");
alert(innervalue);
}
Assumin the javascript is included inline on the jsp page -- you're on the right track, you just need to make sure the attribute is set (typically by your controller class) on the HttpServletRequest object, ie:
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
{
DashboardTicketSummary dts = ...; // code to obtain ticket summary here
req.setAttribute("dashboardTicketSummary", dts);
// code to dispatch to your jsp page here
}
Of course there are many other more sophisticated way -- especially is you use popular MVC framework such as Spring
set value to request attributes and write this piece of code in a script tag on jsp page (like index.jsp):
<script>
function caseChanges(req){
var innervalue= "${dashboardTicketSummary}"
alert("nand you are 1234");
alert(innervalue);
}
</script>
for better maintainability, you can gathering all attributes to a global object on jsp, and refer to it on other js files:
index.jsp
<script>
var REQUEST_ATTRS = {
dashboardTicketSummary : '${dashboardTicketSummary}',
otherAttributes :'${otherAttributes}'
};
</script>
other.js
function caseChanges(req){
var innervalue= REQUEST_ATTRS.dashboardTicketSummary ;
alert("nand you are 1234");
alert(innervalue);
}

updating javascript in the body tag using zend framework

Hi not sure if this is possible or not but I want to programaticaly update the <body> tags to change the onload function in my zend framework application.
The App is using layouts so the body tag currently looks like this <body class="trandra">
However in one of my views I have a map from google being loaded and it needs the following in the body tag this particular view <body onload="initialize()" onunload="GUnload()">
As you can understand I don't want this to be hardcoded in my layout as this will cause all matter of nightmares with the different views.
How can this be done programaticaly, if at all it is possible? Im using the headScript functions to add the javascript so is there an equivalant for the body tag?
Thanks in advance...
Approach one - Use a layout variable
One idea would be the following:
<body class="trandra" <?php echo $this->layout()->bodyScripts ?>>
And in your view:
<?php
$this->layout->bodyScripts =
'onload="initialize()" onunload="GUnload()"';
Approach two - Additional JS-file that adds event handlers
Another approach, which is less obtrusive and doesn't affect the HTML whatsoever is to add an additional JS-file in the view that requires the onload- and onunload-handlers. It could look something like this:
<?php
$this->headScript()->appendScript(
'/path/to/javascripts/loadGMaps.js');
In your loadGMaps.js (using prototype)
Event.observe(window, 'load', function onLoadHandler() {
// Code for initializing Google maps here
});
Event.observe(window, 'unload', function onUnloadHandler() {
// Code for unloading Google maps here
});
Instead of putting your Javascript directly in the code, you could also use an non-obstrusive approch : plugging in the javascript when the page is fully loaded.
Have a look, for instance, at a function called addOnLoadEvent (can be found on many websites ^^ )
If you are using a JS Framework, it certainly has that kind of feature :
for jQuery : http://docs.jquery.com/Events/ready#fn
for prototype : http://www.prototypejs.org/api/event/observe
If you register the "plugging-in" with headScript, there should be no need to modify the tag directly.
Developed something like this recently, I've blogged about it here: http://www.evilprofessor.co.uk/311-zend-framework-body-tag-view-helper/
Demo on site and code is available via github.
I'm no expert on the Zend framework, so I don't know if there is any build in functions for this, but you could do something like this:
In layout-file:
body_params?>>
And then in your controller, you set or add to the body_params:
$this->view->body_params='onload="initialize()" onunload="GUnload()"';
I know this is an old thread, but I was looking through some of the suggested solutions and came up with one of my own playing off of some of the ideas I had seen. What I did was I extended Zend_View in my own library files (I'm using a vanilla MVC layout but similar things can be done using a bootstrap.php rather than the Bootstrap class described below)
class Custom_View extends Zend_View
{
protected $bodyAttrs = array();
public function _setBodyAttr($attrName,$attrValue=null) {
$attrName = strtolower(strval($attrName));
if(!(in_array($attrName, HTML::getValidBodyAttrs()))) {
throw new Zend_Exception(__METHOD__." attrName '$attrName' is not a valid BODY attribute!");
}
$this->bodyAttrs[$attrName] = strval($attrValue);
}
public function _getBodyAttrsAsString() {
$bodyAttrs = "";
if(count($this->bodyAttrs) > 0) {
$attrs = array();
foreach($this->bodyAttrs as $_k => $_v) {
array_push($attrs,sprintf("%s=\"%s\"", $_k, $_v));
}
$bodyAttrs = " " . implode(" ", $tags);
}
return $bodyAttrs;
}
}
// some useful tag definitions for HTML
class HTML
{
// HTML attributes as described by W3C
public static $BODY_ATTRIBUTES = array('alink','background','bgcolor','link','text','vlink');
public static $GLOBAL_ATTRIBUTES = array('accesskey','class','contenteditable','contextmenu','dir','draggable','dropzone','hidden','id','lang','spellcheck','style','tabindex','title');
public static $WINDOW_EVENT_ATTRIBUTES = array('onafterprint','onbeforeprint','onbeforeunload','onerror','onhaschange','onload','onmessage','onoffline','ononline','onpagehide','onpageshow','onpopstate','onredo','onresize','onstorage','onundo','onunload');
public static $MOUSE_EVENT_ATTRIBUTES = array('onclick','ondblclick','ondrag','ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop','onmousedown','onmousemove','onmouseout','onmouseover','onmouseup','onmousewheel','onscroll');
public static $KEYBOARD_EVENT_ATTRIBUTES = array('onkeydown','onkeypress','onkeyup');
public static $FORM_EVENT_ATTRIBUTES = array('onblur','onchange','oncontextmenu','onfocus','onformchange','onforminput','oninput','oninvalid','onreset','onselect','onsubmit');
public static $MEDIA_EVENT_ATTRIBUTES = array('onabort','oncanplay','oncanplaythrough','ondurationchange','onemptied','onended','onerror','onloadeddata','onloadedmetadata','onloadstart','onpause','onplay','onplaying','onprogress','onratechange','onreadystatechange','onseeked','onseeking','onstalled','onsuspend','ontimeupdate','onvolumechange','onwaiting');
public static function getValidBodyAttrs() {
return array_merge(self::$BODY_ATTRIBUTES,self::$GLOBAL_ATTRIBUTES,self::$WINDOW_EVENT_ATTRIBUTES,self::$MOUSE_EVENT_ATTRIBUTES,self::$KEYBOARD_EVENT_ATTRIBUTES);
}
}
after creating this file I added a method _initView to the Bootstrap.php file pointed to by the index.php and application.ini at the root of the application directory:
protected function _initView()
{
// Custom_View extends Zend_View
$view = new Custom_View();
// Add it to the ViewRenderer
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper( 'ViewRenderer' );
$viewRenderer->setView($view);
return $view;
}
The new, extended Zend_View now allows adding your body tags along with some simple checking for validity. Modify your layout's body tag to get the attributes:
<body<?= $this->_getBodyAttrs(); ?>>
Once you have this set up you can add your body tags to any given view
in the controller with
$this->view->_setBodyAttr('key','val');
or in the view with
$this->_setBodyAttr('key','val');

Categories