How to catch element click by ID in Android webview? - javascript

I have the viewPager component which is containing the several webviews with HTML content from remote server.
Is it simple HTML code without possibility to change the HTMl output on the server side.
I would like to ask, how can i catch the click(tap) event on the specified element with the given ID in Android?
ViewPager
private void initViewPager() {
pager = (ViewPager) findViewById(R.id.my_pager);
adapter = new FragmentStatePagerAdapter(
getSupportFragmentManager()
) {
#Override
public int getCount() {
// This makes sure getItem doesn't use a position
// that is out of bounds of our array of URLs
Logger.d(String.valueOf(mWelcomeController.loadedPagesToDisplay.size()));
return mWelcomeController.loadedPagesToDisplay.size();
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
Logger.d(mWelcomeController.loadedPagesToDisplay.toString());
return BrowserFragment.newInstance(
mWelcomeController.loadedPagesToDisplay.get(position)
);
}
};
//Let the pager know which adapter it is supposed to use
pager.setAdapter(adapter);
}
Because I cannot modify the HTML output on the server side (maybe inject some attributes into DOM on device ?) I cannot use something like that:
http://www.scriptscoop.com/t/21b53b896c9e/javascript-how-to-detect-button-click-in-webview-android.html
Detect click on HTML button through javascript in Android WebView.
I would like just something like this:
Find the given element in the HTML code
Update the HTML code (add
onclick event)
Catch this event in native code

For that you need to parse the html, a good html parser for Java (and therefor also Android) is Jsoup.
You can do something like:
// Connect to the web site
Document doc = Jsoup.connect(url).get();
Element button = doc.select("#buttonid");
button.html("new stuff here");
//parse back and put in webview
String finaloutput = doc.html();

1.
// setting
wv.addJavascriptInterface(new MyJsToAndroid(),"my");
WebSettings settings = wv.getSettings();
settings.setJavaScriptEnabled(true);
2.
// JsCallBack
class MyJsToAndroid extends Object{
#JavascriptInterface
public void myClick(String idOrClass) {
Log.d(TAG, "myClick-> " + idOrClass);
}
}
3.
// JS--
public static String addMyClickCallBackJs() {
String js = "javascript:";
js += "function myClick(event){" +
"if(event.target.className == null){my.myClick(event.target.id)}" +
"else{my.myClick(event.target.className)}}";
js += "document.addEventListener(\"click\",myClick,true);";
return js;
}
4.
#Override
public void onPageFinished(WebView wv, String url) {
//...
wv.evaluateJavascript(addMyClickCallBackJs(),null);
//...
}
So, look at the 2 log.

Related

Force open a new tab in mobile browser from an app

I have an app that has a webview in xamarin and shows a web which has links that are configured in this way:
<a target="_blank" href="http://www.web.com"> http://www.web.com </a>
but they do not work, I suppose this happens because when viewing the web from an app, it is not able to open the link in a new window.
I have also tried window.open without any changes.
How I could configure the link to force open the browser with a new link window.
Thanks.
I think this should happen on Android,if you want to open a new window with browser,you could use SetWebChromeClient method for your WebView in your custom renderer.
create a custom renderer in android project:
[assembly: ExportRenderer(typeof(WebView), typeof(AndroidWebView))]
namespace your namespace
{
class AndroidWebView:WebViewRenderer
{
public AndroidWebView(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
Control.SetWebChromeClient(new MywebviewChrome());
}
private class MywebviewChrome : Android.Webkit.WebChromeClient
{
public override bool OnCreateWindow(Android.Webkit.WebView view, bool isDialog, bool isUserGesture, Message resultMsg)
{
Android.Webkit.WebView.HitTestResult result = view.GetHitTestResult();
string data = result.Extra;
Context context = view.Context;
Intent browserIntent = new Intent(Intent.ActionView,Android.Net.Uri.Parse(data));
context.StartActivity(browserIntent);
return false;
}
}
}
}
in your forms project xaml :
<WebView HeightRequest="800" WidthRequest="600" x:Name="webview" ></WebView>
in your page.xaml.cs:
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = #"<a target='_blank' href='http://www.web.com'> http://www.web.com </a>";
webview.Source = htmlSource;
As you supposed, Xamarin.Forms doesn't support opening new tabs / windows.
BUT the Webview component has an event handler called "Navigating" on which you can subscribe to execute code every time the webview tries to open a new page.
public void NavigatingEventHandler(object sender, WebNavigatingEventArgs args)
{
if (args.Url.StartsWith("https://"))
{
//If you want to open the new window in the OS browser
Device.OpenUri(new Uri(args.Url));
//If you want to open the new window inside the webview
webview.Source = args.Url;
args.Cancel = true;
}
}
XAML:
<WebView x:Name="webview" Navigating="NavigatingEventHandler" />

SWT Browser not displaying pages using D3

I would like to display a html page that uses D3 in an SWT Browser.
If I load a URL like www.google.com it loads correctly and allows me to search etc. If I try loading a page that contains D3 I find that nothing gets displayed and no errors are output.
Example
public class D3BrowserExample {
public static void main(String args[]) {
Display display = new Display();
final Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new FillLayout());
Browser browser = new Browser(shell, SWT.NONE);
browser.addTitleListener(new TitleListener() {
#Override
public void changed(TitleEvent event) {
shell.setText(event.title);
}
});
browser.setBounds(0, 0, 1200, 900);
shell.pack();
shell.open();
browser.setJavascriptEnabled(true);
browser.setUrl("https://observablehq.com/#d3/force-directed-graph");
browser.addProgressListener(new ProgressListener() {
#Override
public void completed(ProgressEvent event) {
System.out.println("Page loaded");
}
#Override
public void changed(ProgressEvent event) {
}
});
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
Is it possible to execute D3 using an SWT Browser? Also how can I get the Javascript output to debug the issue?
Update
I've tried this on another Windows 10 PC with version 4.3 of SWT. The complete method is called for the progress listener but nothing displays.
Eclipse Bugzilla
https://bugs.eclipse.org/bugs/show_bug.cgi?id=568789

JavaScript/Jsoup - Get background-image url from "i class"

So I'm loading a webpage in my app's webview and there's an HTML i class="img profimage" and it has a background-image url and that's my target...
I want to get that target either with JavaScript or using Jsoup...
What I tried so far with Jsoup is this:
public class GetImage extends AsyncTask<String, String, String> {
protected String doInBackground(String... strings) {
Document document = null;
try {
document = Jsoup.connect(url).get();
} catch (IOException e) {
e.printStackTrace();
}
String temp = document.select("i.img.profpic").first().getElementsByAttribute("style").toString();
return temp.substring(temp.indexOf("(") + 1, temp.indexOf(")"));
}
 
protected void onPostExecute(String result) {
Log.d("ChatScreen", result);
Toast.makeText(ChatScreen.this, result, LENGTH_SHORT).show();
}
}
But I'm getting NPE...
I don't know how to get background-image url of an i class using JavaScript... I can find plenty of examples on web for how to get it for div using ids
HTML structure of page is similar to this:
<div ....>
<div ....>
<i class="img profimage" style="background-image: url("url here");"/>
</div>
</div>
Check this Answer may be this will work but I didn't try this. The JS function is written bellow in evaluateJavascript() which will read style attribute then you can use substring method to get the URL.
webview.evaluateJavascript(
"(function() { return (document.getElementsByTagName('i')[index].getAttribute('style')); })();",
new ValueCallback<String>() {
#Override
public void onReceiveValue(String html) {
Log.d("HTML", html);
// now use substring to get url.....
}
});
Hope this help you.
Referencing this answer, you could try something like below (assuming it's the only/first element with the class profimage, otherwise change the index, i.e. [n], where n is the index). Alternatively, just give the element a unique id and use document.getElementById('imgid') and remove the [0]. Wrapped it in a function in case you want to call it on a specific event.
function getUrl() {
var img = document.getElementsByClass('profimage'),
style = img[0].currentStyle || window.getComputedStyle(img[0], false),
bi = style.backgroundImage.slice(5, -2);
return bi;
}
Slicing will remove url(" before and ") after the URL itself. Note that this returns the full url.
If that doesn't work, you can try style = img.style, in lieu of the longer expression in the code above, since the background image is added with inline css in the element itself (<i ... style="background-image: url("url here");"/>). This will return the url in the inline style, in this case url here.

Detect parents' and grandparents' links in Javascript

I am making a Web Browser in C# and displaying custom context menus based on the element right clicked by the user. I am having trouble figuring out which elements should be treated as links?
if (el_tag == "a")
showLinkMenu();
else if (el_tag == "img" && parent_tag == "a")
showAdvancedMenu();
else if (el_tag == "img")
showImgMenu();
Shot1: Google chrome detected this as a link
Shot2: Structure a > div > div > div > div > img
What should I do to detect such links?
You should iterate up the list of parent tags and call it a link if any of them are an <a> with an href attribute.
I recommend implementing your own IContextMenuHandler and use the built in CefMenuCommand's and TypeFlag's to help you. With this, you can add or remove context menu items based on the element that has been right-clicked.
MenuHandler.cs
internal class MenuHandler : IContextMenuHandler
{
private const int SaveImage = 26503;
private const int OpenLinkNewTab = 26501;
public event EventHandler OnSaveImage = delegate { };
void IContextMenuHandler.OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
if(parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents)
{
model.AddItem((CefMenuCommand)SaveImage, "Save image");
}
if(!string.IsNullOrEmpty(parameters.UnfilteredLinkUrl))
{
model.AddItem((CefMenuCommand)OpenLinkNewTab, "Open link in new tab");
}
}
bool IContextMenuHandler.OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
return false;
}
void IContextMenuHandler.OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
if ((int)commandId == SaveImage)
{
OnSaveImage?.Invoke(this, new ImageSaveEventArgs(parameters.SourceUrl)); //ImageSaveEventArgs is just a class with one property that houses the source url of the image to download.
}
}
bool IContextMenuHandler.RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}
Then wherever you create your ChromiumWebBrowser instance, you can do something like this:
ChromiumWebBrowser browser = new ChromiumWebBrowser();
MenuHandler menuHandler = new MenuHandler();
menuHandler.OnSaveImage += Handler_OnSaveImage;
browser.MenuHandler = menuHandler;
private void Handler_OnSaveImage(object sender, EventArgs e)
{
DownloadImage(((ImageSaveEventArgs)e).SourceUrl);
}
Note, this is just an example of using the built-in IContextMenuHandler to obtain what the user has right-clicked, and then handling my own event so I can implemented the required behaviour. In this case, the ability to download a file from the URL.
See MenuHandler.cs on CefSharp's GitHub page for more details and other examples.

Awesomium .NET. Wpf. TitleChanged event

I have a very basic application, that shows website content within the WPF app. Everything works fine, except TitleChangedEvent. Here is the code sample (XAML):
<Window xmlns:awe="http://schemas.awesomium.com/winfx" x:Class="ShopChat.Desktop.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:webControls="clr-namespace:System.Web.UI.WebControls;assembly=System.Web"
Title="{Binding ElementName=WebControl, Path=Title}" MinHeight="480" MinWidth="640">
<Grid>
<awe:WebControl x:Name="WebControl"/>
</Grid>
And this is main window code-behind:
public MainWindow()
{
InitializeComponent();
string url = #"http://shopchat.dev";
try
{
url = ConfigurationManager.AppSettings.Get("Url");
}
catch (Exception)
{
}
WebControl.Source = new Uri(url);
WebControl.TitleChanged += WebControl_OnTitleChanged;
this.WindowTitle = "Quickchat";
}
public string WindowTitle
{
get { return (string)GetValue(WindowTitleProperty); }
set { SetValue(WindowTitleProperty, value); }
}
// Using a DependencyProperty as the backing store for WindowTitle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WindowTitleProperty =
DependencyProperty.Register("WindowTitle", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
private void WebControl_OnTitleChanged(object sender, TitleChangedEventArgs e)
{
this.WindowTitle = e.Title;
}
I've also tried to bind to window title directly using Binding ElementName=WebControl. That didn't help me either.
JavaScript client code is very simple: it changes the document title on timer (setInterval).
What am I doing wrong?
try like this code
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyTitle = "Title";
}
Then you just need in the XAML
Title="{Binding MyTitle}"
Then you don't need the dependency property.
Then I would like to use this INotifyPropertyChanged with a standard property.
The issue was solved. TitleChanged event seemed to be insufficient. I've incorporated the usage of global js object to get the necessary behavior.

Categories

Resources