We have a large GWT project and many smaller GWT sub-projects
basically the large controller project invokes the smaller projects
via many means such as some are incorporated into iframes that are shown in page,
some are shown by clicking a URL and opening the project into a new window.
The requirement is to change the Css on the fly, this is possible in the main project,
by simply changing, on the fly, the href of the link tag containing stylesheet url
is it possible to propogate this change to the sub-projects too ?
or asking in more broader terms,
how do i achieve inter - project communication in GWT ?
A browse allows you to call Javascript code across IFrames if the domains of the different GWT applications are the same.
Using JSNI you can register methods on the window object which call back into the GWT application and using JSNI the other project can invoke this method.
If all the apps are served from the same domain you could store the name of the stylesheet in a cookie. Each app would then use the cookie to select the appropriate stylesheet.
String theme = Cookies.getCookie("THEME");
if (theme == null) {
theme = "default";
}
Element e = DOM.createElement("link");
DOM.setElementProperty(e, "rel", "stylesheet");
DOM.setElementProperty(e, "href", GWT.getModuleBaseURL() + currentTheme +
".css");
DOM.appendChild(getHead(), e);
private native Element getHead() /*-{
return $doc.getElementsByTagName('head')[0];
}-*/;
Related
I am working on an app in Android Studio and am having some trouble web-scraping with JSoup. I have successfully connected to the webpage and returned some basic elements to test the library, but now I cannot actually get the elements I need for my app.
I am trying to get a number of elements with the "data-at" attribute. The weird thing is, a few elements with the "data-at" attribute are returned, but not the ones I am looking for. For whatever reason my code is not extracting all of the elements that share the "data-at" attribute on the web page.
This is the URL of the webpage I am scraping:
https://express.liatoyotaofcolonie.com/inventory?f=dealer.name%3ALia%20Toyota%20of%20Colonie&f=submodel%3ACamry&f=trim%3ALE&f=year%3A2020
The method containing the web-scraping code:
#Override
protected String doInBackground(Void... params) {
String title = "";
Document doc;
Log.d(TAG, queryString.toString());
try {
doc = Jsoup.connect(queryString.toString()).get();
Elements content = doc.select("[data-at]");
for (Element e: content) {
Log.d(TAG, e.text());
}
} catch (IOException e) {
Log.e(TAG, e.toString());
}
return title;
}
The results in Logcat
The element I want to retrieve
One of the elements that is actually being retrieved
This is because some of the content - including the one you are looking for - is created asyncronously and is not present in initial DOM (Javascript ;))
When you view the source of the page you will notice that there is only 17 data-at occurences, while running document.querySelector("[data-at]") 29 nodes are returned.
What you are able to get in the JSoup is static content of the page (initial DOM). You wont be able to fetch dynamically created content as you do not run required JS scripts.
In order to overcome this, you will have to either fetch and parse required resources manually (eg trace what AJAX calls are made by the browser) or use headless browser setup. Selenium + headless Chrome should be enough.
Letter option will allow you to scrape ANY posible web application, including SPA apps, which is not possible using plaing Jsoup.
I don't quite know what to do about this, but I'm going to try one more time... The "Problematic Lines" in your code are these:
doc = Jsoup.connect(queryString.toString()).get();
Elements content = doc.select("[data-at]");
It is the queryString that you have requested - the URL points to a page that contains quite a bit of script code. When you load up a browser and click the button (or menu-option) that reads: "View Source", the HTML you see is not the same exact HTML that is broadcast to and received by JSoup.
If the HTML that is broadcast contains any <SCRIPT TYPE="text/javascript"> ... </SCRIPT> in it (and the named URL in your question does), AND those <SCRIPT> tags are involved in the initial loading of the page, then JSoup will not know anything about it... It only parses what it receives, it cannot process any dynamic content.
There are four ways that I know of to get the "Post Script Loaded" version of the HTML from a dynamic web-page, and I will type them here, now. The first is likely the most popular method (in Java) that I have heard about on Stack Overflow:
Selenium This Answer will show how the tool can run Java-Script. These are some Selenium Docs. And then there is this page right here has a great "first class" for using the tool to retrieve post-script processed HTML. Again, there is no way JSoup can retrieve HTML that is sent to the browser by script (JS/AJAX/Angular/React) since it just a parser.
Puppeteer This requires running a language called Node.js Perhaps calling a simple Node.js program from Java could work, but it would be a "Two Language" solution. I've never used it. Here is an answer that shows getting, sort of, what you are trying to get... The HTML after the script.
WebView Android Java Programmers have a popular class called "WebView" (documented here), that I have recently been told about (yesterday ... but it has been out for years) that will execute script in a browser, and return the HTML. Here is an answer that shows "JavaScript Injection" to retrieve DOM Tree elements from a "WebView" instance (which is how I was told it was done)
Splash My favorite tool, which I don't think anyone has heard of, but has been the simplest for me... So there is an A.P.I. called the "Splash API". Here is their explanation for a "Java-Script Rendering Service." Since this one I have been using... I'll post a code snippet that shows how "Splash Tool" can retrieve post-script processed HTML below.
To run the Splash API (only if you have access to the docker loading program) ... You start a Splash Server as below. These two lines are typed into a GCP (Google Cloud Platform) Shell instance, and the server starts right up without any configurations:
Pull the image:
$ sudo docker pull scrapinghub/splash
Start the container:
$ sudo docker run -it -p 8050:8050 --rm scrapinghub/splash
In your code, just prepend the String to your URL's:
"http://localhost:8050/render.html?url="
So in your code, you would use the following command (instead), and the script would (more likely) load all the HTML Elements that you are not finding:
String SPLASH_URL = "http://localhost:8050/render.html?url=";
doc = Jsoup.connect(SPLASH_URL + queryString.toString()).get();
Using Google Web Toolkit, I'd like to code the equivalent of a hard refresh (control + F5).
I don't believe (or know) if GWT's Window.Location will work.
import com.google.gwt.user.client.Window.Location;
Window.Location = currentPage; // I don't think it'll be hard refresh
For reloading the current page you need to call Window.Location.reload() method.
Reloads the current browser window. All GWT state will be lost.
Or you can even specify your own JSNI (below how todo), because by default force reload is false :
public static native void forceReload() /*-{
$wnd.location.reload(true);
}-*/;
According to https://developer.mozilla.org/en-US/docs/DOM/window.location#Methods you would need to call window.location.reload(true) to force the reload of the current page.
Unfortunately GWT wraps only the window.location.reload() via Window.Location.reload(), and it is up to the browser to retrieve the page from the cache or from another get. This is done to achieve the most cross-browser solution.
Never tried but you should be able to use the following.
public static native void reload(boolean force) /*-{
$wnd.location.reload(force);
}-*/;
For reload gwt page, you have two options:
1) Window.Location.reload();
Reloads the current browser window. All GWT state will be lost.
2) Window.Location.replace("newurl");
Replaces the current URL with a new one. All GWT state will be lost. In the browser's history, the current URL will be replaced by the new URL.
I would like to put a flash game i made with CS.5 (it was exported to a .swf) into a java application. From research i found some ways to to it might be using a embedded web browser or some kind of a flash player:
Embed .swf file to my Jframe
Embed a web browser within a java application
But is this the best way to do it and will it keep the interactivity (ie. the game). It will also fit exactly so if a embedded web browser showed back/front/url/etc. buttons then i can't use it
So whats the best way to do this? And will a flash player inside the java application keep the interactivity (the game working the same as it would in a web browser or in the flash player application)?
You can used the swf COM API ExternalInterface.call() to communicate with the swf applcaition.
But it only support action script 3 and later.
public void callFunction( String function, String params )
{
if ( !created )
return;
String request = "<invoke name=\""
+ function
+ "\"><arguments><string>"
+ params
+ "</string></arguments></invoke>";
Variant[] args = new Variant[1];
args[0] = new Variant( request );
flashObject.invokeNoReply( DISPID_CALLFUNCTION, args );
}
This is a swt swf call function implements.
You can implement a swf container, it's very easy. Some JNI jars such as JNative, JNA can help you.
I implement a win32 library swt-win32-extension.jar, it contains a custom swf container, but it can't be used by swing.
I have been reading about the responsive web pattern and I have successfully implemented it on a test page. However I see the limitations of that the layout is limited by the order/sequence of the HTML tags. You can set the display:none property on a lot of content etc but that is not nice.
So is there a way on the server side to distinguish between what the HTML response are going to include based on what kind of device is used by the user? I am mainly interested in Scala (Lift) and Java EE solutions.
Using Lift you can identify the userAgent and if it is mobile, you can show different html than if the user is using a desktop browser.
There are a few ways to accomplish this, one is from the Sitemap, or another is from each snippet.
The mailing list is a good place to ask the specifics of each method.
Update
This is an example using Sitemap from Lift
def sitemap = SiteMap(
Menu.i("Home") / "index" >> pickTemplate(),
Menu.i("First") / "first"
)
//Show mobile or regular page
def pickTemplate() ={
//If the browser is Chrome, pick this template
if(S.request.map(_.isChrome) openOr true ){
Template( ()=>Templates("chrome" :: Nil) openOr (NodeSeq.Empty))
} else{
Template( ()=>Templates("other" :: Nil) openOr (NodeSeq.Empty))
}
}
I am using htmlunit in jython and am having trouble selecting a pull down link. The page I am going to has a table with other ajax links, and I can click on them and move around and it seems okay but I can't seem to figure out how to click on a pulldown menu that allows for more links on the page(this pulldown affects the ajax table so its not redirecting me or anything).
Here's my code:
selectField1 = page.getElementById("pageNumSelection")
options2 = selectField1.getOptions()
theOption3 = options2[4]
This gets the option I want, I verify its right. so I select it:
MoreOnPage = selectField1.setSelectedAttribute(theOption3, True)
and I am stuck here(not sure if selecting it works or not because I don't get any message, but I'm not sure what to do next. How do I refresh the page to see the larger list? When clicking on links all you have to do is find the link and then select linkNameVariable.click() into a variable and it works. but I'm not sure how to refresh a pulldown. when I try to use the webclient to create an xml page based on the the select variable, I still get the old page.
to make it a bit easier, I used htmlunit scripter and got some code that should work but its java and I'm not sure how to port it to jython. Here it is:
try
{
page = webClient.getPage( url );
HtmlSelect selectField1 = (HtmlSelect) page.getElementById("pageNumSelection");
List<HtmlOption> options2 = selectField1.getOptions();
HtmlOption theOption3 = null;
for(HtmlOption option: options2)
{
if(option.getText().equals("100") )
{
theOption3 = option;
break;
}
}
selectField1.setSelectedAttribute(theOption3, true );
Have a look at HtmlForm getSelectedByName
HtmlSelect htmlSelect = form.getSelectByName("stuff[1].type");
HtmlOption htmlOption = htmlSelect.getOption(3);
htmlOption.setSelected(true);
Be sure that WebClient.setJavaScriptEnabled is called. The documentation seems to indicate that it is on by default, but I think this is wrong.
Alternatively, you can use WebDriver, which is a framework that supports both HtmlUnit and Selenium. I personally find the syntax easier to deal with than HtmlUnit.
If I understand correctly, the selection of an option in the select box triggers an AJAX calls which, once finished, modifies some part of the page.
The problem here is that since AJAX is, by definition, asynchronous, you can't really know when the call is finished and when you may inspect the page again to find the new content.
HtmlUnit has a class named NicelyResynchronizingAjaxController, which you can pass an instance of to the WebClient's setAjaxController method. As indicated in the javadoc, using this ajax controller will automatically make the asynchronous calls coming from a direct user interaction synchronous instead of asynchronous. Once the setSelectedAttribute method is called, you'll thus be able to see the changed made to the original page.
The other option is to use WebClient's waitForBackgrounfJavascript method after the selection is done, and inspect he page once the background JavaScript has ended, or the timeout has been reached.
This isn't really an answer to the question because I've not used HtmlUnit much before, but you might want to look at Selenium, and in particular Selenium RC. With Selenium RC you are able to control the interactions with a page displayed in a native browser (Firefox for example). It has developer API's for Java and Python amongst others.
I understand that HtmlUnit uses its own javascript and web browser rendering engine and I'm wondering whether that may be a problem.