how to display a WebView only after a javascript code is done? - webview

I'm trying to force WebView to 'skip' images by using javascript. (like here: https://stackoverflow.com/a/31848599/13174607).
The problem is that the images are disappeared only after the WebView finished loaded. I want to display the WebView only after the javascript is finished.
This is my code:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(webView, url);
webView.loadUrl("javascript:(function(){ var imgs=document.getElementsByTagName('img');" + "for(i=0;i<imgs.length;i++) { imgs[i].style.display='none'; } })()");
}
});
}
I tried to use setVisibility() method, like this:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
webView.setVisibility(View.INVISIBLE);
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(webView, url);
webView.loadUrl("javascript:(function(){ var imgs=document.getElementsByTagName('img');" + "for(i=0;i<imgs.length;i++) { imgs[i].style.display='none'; } })()");
webView.setVisibility(View.VISIBLE);
}
});
}
but it didn't help.
Thanks!
EDIT:
By using the proposed solution and the #mustansir comments I wrote this code on 'onPageFinished':
webView.loadUrl("javascript:" + "function taskOne() {" +
"var imgFlag = 0;" + //will sign when the for loop ended
"var imgs = document.getElementsByTagName('img');" +
"if (imgs==0){imgFlag=1;} " +
"for (i = 0; i < imgs.length; i++) {" +
"imgs[i].style.display = 'none';" +
"if (i==imgs.length-1)" +
"{" +
"imgFlag=1;" +
"}"+
"}}" +
"taskOne();" +
"function taskTwo () {" +
"if(imgFlag==1){" +
"window.visibility.changeVisibility(); }" +
"else {" +
"setTimeout(taskTwo(),100);}}" +
"taskTwo();");
but the the webview doesn't become visible. Any idea why?

You can try injecting a JavaScript interface and call that interface method when you reach at the last image in the loop to change WebView visibility.
Something like this:
webview.addJavascriptInterface(this, "visibility");
and call this interface from your JavaScript like this:
var imgs = document.getElementsByTagName('img');
for (i = 0; i < imgs.length; i++) {
imgs[i].style.display = 'none';
if (i == imgs.length-1) {
visibility.changeVisibility();
}
}
Now define changeVisibility() with #JavascriptInterface annotation in that activity in which you have added javascriptInterface like this:
#JavascriptInterface
public void changeVisibility() {
runOnUiThread(() -> webview.setVisibility(View.VISIBLE));
}

Related

JavaFX WebView HyperLinks Cannot Be Disabled on Mobile Devices

The below code is used to disable hyperlinks in a JavaFX WebView object. However, when I run it on a mobile device it does not work, whilst it is working OK on desktop. Any alternative solution to affect mobile devices?
private void init() {
webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
if(newState == State.SUCCEEDED && webEngine.getDocument() != null)
disableHyperLinks(webEngine.getDocument());
});
} // init()
private void disableHyperLinks(Document document) {
NodeList nodeList = document.getElementsByTagName("a");
for (int i = 0; i < nodeList.getLength(); i++)
{
Node node= nodeList.item(i);
EventTarget eventTarget = (EventTarget) node;
eventTarget.addEventListener("click", (evt) -> {
evt.preventDefault();
}, false);
} // for
} // disableHyperLinks()
When you run on mobile, the WebView is not implemented with the JavaFX control, but instead the native one is used, both on Android and iOS.
You can see here the implementation for Android, and here the one for iOS.
On iOS there is no Document native method implemented, and it only returns the html content of the loaded page (providing that the content can be parsed, otherwise it will be null). So even if you are able to read and modify that content, it wouldn't have any effect over the real control.
The good news is that you can use executeScript, as it is implemented for iOS.
Something like this should work:
private void init() {
webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
if(newState == State.SUCCEEDED)
disableHyperLinks();
});
} // init()
private void disableHyperLinks() {
Object res = webView.getEngine().executeScript("(function() { " +
"var links = document.getElementsByTagName(\"a\");\n" +
" for (var i=0; i<links.length; i++) {\n" +
" links[i].addEventListener(\"click\",function(e) {\n" +
" e.preventDefault();\n" +
" })\n" +
" }"
+ "return ('<html>'+ links.length +'</html>'); })();");
if (res != null) {
System.out.println("Hyperlinks disabled: " + res);
} else {
System.out.println("ERROR disabling hyperlinks");
}
} // disableHyperLinks()
The above code won't work on Android, though. There is a (very hacky) possible way to do it, accessing the native control on runtime (but since the question is about iOS I won't explain here).

Calling SignalR client on a loop Fails using different browser

I have a problem using asynchronous task and signalR here is my scenario:
I have to page records using async task to create a csv file and updating the client using push notification via signalR here is my code:
private async Task WriteRecords([DataSourceRequest] DataSourceRequest dataRequest,int countno, VMEXPORT[] arrVmExport, bool createHeaderyn, string filePath )
{
string fileName = filePath.Replace(System.Web.HttpContext.Current.Server.MapPath("~/") + "Csv\\", "").Replace(".csv", "");
int datapage = (countno / 192322)+1;
for (int i = 1; i <= datapage; )
{
dataRequest.Page = i;
dataRequest.PageSize = 192322;
var write = _serviceAgent.FetchByRole("", "", CurrentUser.Linkcd, CurrentUser.Rolecd).ToDataSourceResult(dataRequest);
await Task.Run(()=>write.Data.Cast<AGENT>().WriteToCSV(new AGENT(), createHeaderyn, arrVmExport, filePath));
createHeaderyn = false;
i = i + 1;
double percentage = (i * 100) / datapage;
SendProgress(percentage, countno,fileName);
}
}
Here is the set up in my BaseController which calls the hub context:
public void SendNotification(string fileNametx, bool createdyn)
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHubHelper>();
context.Clients.User(CurrentUser.Usernm + '-' + CurrentUser.GUID)
.receiveNotification("Export", CurrentUser.Usernm, "info", fileNametx, createdyn);
}
public void SendProgress(double recordCount, int totalCount,string fileName)
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHubHelper>();
context.Clients.User(CurrentUser.Usernm + '-' + CurrentUser.GUID).reportProgress(recordCount, totalCount,fileName);
}
And Here is my controller Method:
public async Task<ActionResult> _Export([DataSourceRequest] DataSourceRequest dataRequest, string columns,int countno, string menunm)
{
var fileNametx = AgentsPrompttx + DateTime.Now.ToString(GeneralConst.L_STRING_DATE4) + ".csv";
SendNotification(fileNametx, false);
var filePath = System.Web.HttpContext.Current.Server.MapPath("~/") + "Csv\\";
var vmexport = new JavaScriptSerializer().Deserialize<VMEXPORT[]>(columns);
dataRequest.GroupingToSorting();
dataRequest.PageSize = 0; // set to zero
await WriteRecords(dataRequest,countno, vmexport, true, filePath + fileNametx);
SendNotification(fileNametx, true);
return File(filePath + fileNametx, WebConst.L_CONTENTTYPE_APP_OCTET, fileNametx);
}
the main problem is when i request 4 times download.. means 4 tasks running asynchronously. It creates notification when i use same browser. but when i use IE and Google it fails to give me the progress. It creates the file no problem with file creation but on updates only it doesnt work fine. can someone correct me in this way
Update
The problem is when I use multiple Browser which invokes OnDisconnected() when navigating to other pages. Which stops the connection to other connected Hub context.

firefox extension working on page load

I'm trying to create my first extension.
I've found this sample: http://blog.mozilla.org/addons/2009/01/28/how-to-develop-a-firefox-extension/
I need to get some html content on a specific page and write something in the same page, so I modified it and got what I needed (with javascript I added content in the table I want). But to view my content I have to launch the extension from the button on the status bar, while I would like to have it already active in the page as I load/reload it (with a check on the url so to have it working only on that page) but I can't have it automatically.
I tried to add linkTargetFinder.run(); on init area, but... nothing. Moreover the extension as an "autorun" but eve if active, I don0t see any change.
any working sample?
Thanks
Nadia
Here it is the code (I edited just the .js file), I commented a couple of test not working...
var linkTargetFinder = function () {
var prefManager = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
return {
init : function () {
gBrowser.addEventListener("load", function () {
var autoRun = prefManager.getBoolPref("extensions.linktargetfinder.autorun");
if (autoRun) {
linkTargetFinder.run();
}
//linkTargetFinder.run(); // doesn't work
}, false);
//linkTargetFinder.run(); // doesn't work
alert("ZZZZZZZZZZZZZZZZZZ"); // doesn't work
},
run : function () {
var head = content.document.getElementsByTagName("head")[0],
style = content.document.getElementById("link-target-finder-style"),
allLinks = content.document.getElementsByTagName("a"),
foundLinks = 0;
if (!style) {
style = content.document.createElement("link");
style.id = "link-target-finder-style";
style.type = "text/css";
style.rel = "stylesheet";
style.href = "chrome://linktargetfinder/skin/skin.css";
head.appendChild(style);
}
for (var i=0, il=allLinks.length; i<il; i++) {
elm = allLinks[i];
if (elm.getAttribute("target")) {
elm.className += ((elm.className.length > 0)? " " : "") + "link-target-finder-selected";
foundLinks++;
}
}
if (foundLinks === 0) {
alert("No links found with a target attribute");
}
else {
//alert("Found " + foundLinks + " links with a target attribute");
}
t = content.document.getElementById("ERSContainer"), // ID of the table
d = t.getElementsByTagName("tr")[1],
r = d.getElementsByTagName("td")[1];
var myMail = "mail: "+r.textContent; //ok scrive nella td
var myName = content.document.getElementById("buyercontactname").value;
var myAddr1 = content.document.getElementById("buyeraddress1").value;
var myAddr2 = content.document.getElementById("buyeraddress2").value;
var myCity = content.document.getElementById("buyercity").value;
var myProv = content.document.getElementById("buyerstateprovince").value;
var myCAP = content.document.getElementById("buyerzip").value;
var elt = content.document.getElementById("buyercountry");
var myCountry = elt.options[elt.selectedIndex].text;
var myTel = content.document.getElementById("dayphone1").value;
var myTag1 = "<tr><td colspan='2'>OK!!!<br />";
var myTag2 = "</td></tr>";
z= t.innerHTML;
t.innerHTML = myTag1 + myMail +
" - "+myName+
myAddr1 + "<br />" +
myAddr2 + "<br />" +
myCity + "<br />" +
myProv + "<br />" +
myCAP + "<br />" +
myCountry + "<br />" +
myTel + "<br />" +
myFlash+
myTag2+z;
}
};
}();
window.addEventListener("load", linkTargetFinder.init, false);
If what you are doing is running a bit of JavaScript on a specific web page, like adding content into a table, maybe you should consider doing a userscript for the Greasemonkey addon instead of a full addon. With this you write your JS for the page and it gets executed each time you browse this specific page.
edit:
Try with this :
init: function () {
gBrowser.addEventListener("load", linkTargetFinder.run, true);
},
...
I bet that the extensions.linktargetfinder.autorun does not exist. So getBoolPref throws an exception and the rest is history.
Change your code to the following
var autoRun;
try {
autoRun = prefManager.getBoolPref("extensions.linktargetfinder.autorun");
} catch(e){
autoRun = false;
}

Problems with addFrameScript on an instance

I'm trying to add a frame script via:
private function addFrameScript(mc:MovieClip, label:String, func:Function, arg:*):void {
var labels:Array = mc.currentLabels;
var i:int = labels.length;
while (--i > -1) {
if (FrameLabel(labels[i]).name == label) {
mc.addFrameScript(FrameLabel(labels[i]).frame-1, func(arg));
return;
}
}
trace("WARNING: The label '" + label + "' does not exist in the MovieClip '" + mc.name + "'");
}
private function dispatchFrameEvent(labelName:String):void {
dispatchEvent(new Event(labelName, true));
}
addFrameScript(instanceName, "end", dispatchFrameEvent, "end");
But it doesn't seem to be adding and I can't figure out why. Normally I add Frame scripts to the main timeline, but not to an instance on the timeline (as in the example above).
Clearly there's something I'm missing...is there a way to trace out my frame script to see if it's even being added?
The problem here is that addFrameScript functions being added take no arguments. so whatever func you are passing in must must return a function with no arguments
so your dispatchFrameEvent should look like this
private function dispatchFrameEvent(labelName:String):Function {
return function func():void{
dispatchEvent(new Event(labelName, true));
}
}

Adobe Air how to check if URL is online\gives any response exists?

I have url I want to check if it is live. I want to get bool value. How to do such thing?
You can use an URLLoader and listen for the events to check if it loads, and if not what might be the problem. Would be handy to use the AIRMonitor first to make sure the client's computer is online in the first place.
Here is a class I started to write to illustrate the idea:
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.HTTPStatusEvent;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
/**
* ...
* #author George Profenza
*/
public class URLChecker extends EventDispatcher
{
private var _url:String;
private var _request:URLRequest;
private var _loader:URLLoader;
private var _isLive:Boolean;
private var _liveStatuses:Array;
private var _completeEvent:Event;
private var _dispatched:Boolean;
private var _log:String = '';
public function URLChecker(target:IEventDispatcher = null)
{
super(target);
init();
}
private function init():void
{
_loader = new URLLoader();
_loader.addEventListener(Event.COMPLETE, _completeHandler);
_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, _httpStatusHandler);
_loader.addEventListener(IOErrorEvent.IO_ERROR, _ioErrorEventHandler);
_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityErrorHandler);
_completeEvent = new Event(Event.COMPLETE, false, true);
_liveStatuses = [];//add other acceptable http statuses here
}
public function check(url:String = 'http://stackoverflow.com'):void {
_dispatched = false;
_url = url;
_request = new URLRequest(url);
_loader.load(_request);
_log += 'load for ' + _url + ' started : ' + new Date() + '\n';
}
private function _completeHandler(e:Event):void
{
_log += e.toString() + ' at ' + new Date();
_isLive = true;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
private function _httpStatusHandler(e:HTTPStatusEvent):void
{
/* comment this in when you're sure what statuses you're after
var statusesLen:int = _liveStatuses.length;
for (var i:int = statusesLen; i > 0; i--) {
if (e.status == _liveStatuses[i]) {
_isLive = true;
dispatchEvent(_completeEvent);
}
}
*/
//200 range
_log += e.toString() + ' at ' + new Date();
if (e.status >= 200 && e.status < 300) _isLive = true;
else _isLive = false;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
private function _ioErrorEventHandler(e:IOErrorEvent):void
{
_log += e.toString() + ' at ' + new Date();
_isLive = false;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
private function _securityErrorHandler(e:SecurityErrorEvent):void
{
_log += e.toString() + ' at ' + new Date();
_isLive = false;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
public function get isLive():Boolean { return _isLive; }
public function get log():String { return _log; }
}
}
and here's a basic usage example:
var urlChecker:URLChecker = new URLChecker();
urlChecker.addEventListener(Event.COMPLETE, urlChecked);
urlChecker.check('wrong_place.url');
function urlChecked(event:Event):void {
trace('is Live: ' + event.target.isLive);
trace('log: ' + event.target.log);
}
The idea is simple:
1. You create a checked
2. Listen for the COMPLETE event(triggered when it has a result
3. In the handler check if it's live and what it logged.
In the HTTP specs, 200 area seems ok, but depending on what you load, you might need
to adjust the class. Also you need to handle security/cross domain issue better, but at least it's a start.
HTH
An important consideration that George's answer left out is the URLRequestMethod. If one were trying to verify the existence of rather large files (e.g, media files) and not just a webpage, you'd want to make sure to set the method property on the URLRequest to URLRequestMethod.HEAD.
As stated in the HTTP1.1 Protocol:
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
Hence, if you really only want to verify the existence of the URL, this is the way to go.
For those who need the code spelled out:
var _request:URLRequest = URLRequest(url);
_request.method = URLRequestMethod.HEAD; // bandwidth :)
Otherwise, George's answer is a good reference point.
NB: This particular URLRequestMethod is only available in AIR.

Resources