Only show one div in webview - javascript

I have been trying to implement this but I could not get it work. Anyway here is the deal:
In the main page of a website, I only want a specific div to be shown in a webview. Hide all other elements. But keep the styling and scripts of that page of course.(This means no Jsoup)
I tried doing it by using javascript in webview and here is what I tried:
webview = (WebView) this.findViewById(R.id.webView);
final WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAppCacheEnabled(true);
WebViewClient myClient = new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.e("LogTxt","Test");
view.loadUrl("javascript:var con = document.getElementsByClassName('page-content'); " +"con[0].style.display = 'none'; ");
}
};
String cookieString = ".ASPXAUTH="+ getIntent().getStringExtra("key");
headers = new HashMap<>();
headers.put("Cookie", cookieString);
headers.put("Accept","mobile");
webview.setWebViewClient(myClient);
webview.loadUrl("http://www.myurl.com",headers);
Looks like this:
So how can I do this? What are other alternative ways? Thanks!

Try this:
"javascript:(function() {document.getElementsByTagName('YourDivTag')[0].remove();})()"

Related

Resizing IE11 using Java

I have an issue with trying to resizing IE11 in kiosk mode but launching in kiosk mode would force it to go fullscreen but if I turn off kiosk mode, the toolbar & navbar, etc. will all be visible which is not what I want to prevent user from editing the url, so I would I be able to achieve that? I tried using JS, but it didnt work. Is it possible to do it without using JS?
I tried Process p = new ProcessBuilder("cmd.exe", "/c", "start iexplore -k javascript:resizeTo(400,300)\"" + newUrl +"\"").inheritIO().start(); , but it prompt save file dialog, instead of resizing.
Tried this too javascript:moveTo(0,0);resizeTo(1024,768);}, cant find out what is wrong for that, since the console is disabled in kiosk mode.
Currently using java-8.
private static String newUrl = replaceUserID(url);
public static void main(String[] args) {
try{
Process p = new ProcessBuilder("cmd.exe", "/c", "start iexplore -k \"" + newUrl +"\"").inheritIO().start();
resizeBrowser();
try{
p.waitFor();
}
catch( InterruptedException ie ){
System.out.println("InterruptedException " + ie.getMessage());
}
InputStream err = p.getErrorStream();
int ctr = 0;
if ( (ctr = err.available()) > 0 ){
byte[] buf = new byte[ctr];
System.out.println("Process failed with error:\n" + new String(buf, 0, ctr));
}
}
catch(IOException ioe)
{
System.out.println("InterruptedException " + ioe.getMessage());
}
}
public static void resizeBrowser() {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine javaScript = scriptEngineManager.getEngineByName("nashorn");
try {
javaScript.eval("function resizeIE(){"
+ "newWindow = window.open(\"" + newUrl + "\", IEWindow, resizable);"
+ "newWindow.resizeTo(500,400);}");
}catch (ScriptException e) {
e.printStackTrace();
}
}
I'm afraid it's impossible to resize IE kiosk window. Kiosk mode means run browser in fullscreen window. You can't tell the browser to run in fullscreen and non-fullscreen window at the same time. That doesn't make any sense.
For similar thread, you can also refer to this link.

How to force Android-WebView to Redraw/Re-Render immediately?

Basically the JavascriptInterface receive a Click event from WebView, then I need to change an HTML element multiple times, the problem is the WebView show only the last change, that's mean the rendering is not immediate.
Question: How to make webview.loadUrl("javascript:updateProgress(20);"); take effect and change WebView content immediately?
- - - - - - - - - - - - - - - - -
Old question:
I have a HTML progress-bar in my WebView, I can simply update the progress-bar value by running webview.loadUrl("javascript:updateProgress(20);"); this work fine from onCreate().
// JavaScript in WebView
function updateProgress(percentage){
document.getElementById('progressBar').style.width = percentage + '%';
}
Now, I have a class that send binary data to an connected BLE device, I toke the example from Google BluetoothLeGatt, and I added a method to write to an characteristic (send data) in BluetoothLeService.java.
public void WriteCharacteristic(BluetoothGattCharacteristic characteristic, byte[] data, MainActivity mainactivity){
byte[] data_twenty_byte = new byte [20];
int progress_count = 0;
while(get_next_twenty_byte(data, data_twenty_byte)){
characteristic.setValue(data_twenty_byte);
mBluetoothGatt.writeCharacteristic(characteristic);
progress_count++;
mainactivity.webview.loadUrl("javascript:updateProgress(" + progress_count + ");");
}
}
The problem is the WebView won't be updated (Redraw/Re-Render) while WriteCharacteristic() is running, the WebView Redraw/Re-Render only after WriteCharacteristic() finish, mean at progress-bar 100%.
Note: I already tried runOnUiThread(new Runnable() {});
My Question is, How to force mainactivity.webview to Redraw/Re-Render immediately ?
Thank you,
As noted in my comment, pushing the long-running process to a background thread, then running the webview update on the ui thread should do what you are looking to achieve. Here's a quick example that I threw together:
package com.example.myapplication
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.JavascriptInterface
import android.webkit.WebView
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity() {
lateinit var webView: WebView
#SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
webView = WebView(this)
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(this, "app")
setContentView(webView)
val html =
"""
<html>
<head>
<script type='text/javascript'>
function updateProgress(progress) {
let el = document.getElementById('progress');
el.innerText = progress;
}
</script>
</head>
<body>
<p>Value: <span id='progress'>0</span></p>
<button onclick='app.startUpdates();'>Start Update</button>
</body>
</html>
""".trimIndent()
webView.loadData(html, "text/html", "UTF-8")
}
#JavascriptInterface
fun startUpdates() {
doSomething()
}
private fun doSomething() {
thread {
for (i in 1..100) {
runOnUiThread { webView.evaluateJavascript("updateProgress($i);", null) }
Thread.sleep(10)
}
}
}
}

How to disable Webview scrolling and set it's height to fit the entire content

I am using webview to show and edit the content in my UWP application. I want to disable the scrolling within the Webview control and make it adapt the height just to fit the entire content it has. And then it should respect the scrolling of it's parent control's scrollviewer. I have uploaded a sample application on OneDrive here: https://1drv.ms/u/s!AhChIerZubKRjQKBH5nA0KGTtPYP
In the sample app, you can see that once you reach at the end of the scrollviewer, the webview will start scrolling within itself. Instead what I would like to do is, keep scrolling (the parent scrollviewr) to the end of the webview.
Edit: Here's the code:
MainPage.xaml:
<ScrollViewer VerticalScrollBarVisibility="Auto" VerticalScrollMode="Auto" Height="200" Width="400">
<StackPanel>
<Button Content="Navigate web page 1"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click"/>
<Button Content="Navigate web page 2"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click_1"/>
<Button Content="Navigate web page 3"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click_2"/>
<Button Content="Navigate web page 4"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Click="Button_Click_3"/>
<WebView Name="WebView" Width="400" MinHeight="200"></WebView>
</StackPanel>
</ScrollViewer>
MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
private const string EditableParameter = "~editable~";
private const string SetBodyEditableScript = #"
try
{
document.body.contentEditable = '" + EditableParameter + #"';
}
catch(e)
{
}";
private const string SetTextFromClipBoardFunctionName = "setTextFromClipBoard";
private const string SetHtmlTextFromClipboardFunction =
"function " + SetTextFromClipBoardFunctionName + #"(htmlFromClipboard)
{
if (window.getSelection)
{
var range;
var sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
var el = document.createElement('div');
el.innerHTML = htmlFromClipboard + '<span></span>';
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
range.collapse(false);
window.external.notify('RefreshAndReportHtml');
}
else if (typeof document.selection != 'undefined' && document.selection.type != 'Control') {
var html = (node.nodeType == 1) ? node.outerHTML : node.data;
html += '<span></span>';
var textRange = document.selection.createRange();
textRange.pasteHTML(html);
textRange.collapse(false);
window.external.notify('RefreshAndReportHtml');
}
}
};";
private const string GetHtmlFunctionName = "getHtml";
private const string GetHtmlFunction =
"function " + GetHtmlFunctionName + #"(skipParam)
{
return document.documentElement.innerHTML;
};";
public MainPage()
{
this.InitializeComponent();
MakeWebviewEditable();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://tsn.ua");
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://buzzfeed.com");
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://microsoft.com");
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
//(Window.Current.Content as Frame).Navigate(typeof(WebviewPage), "http://cnn.com");
}
private const string EventNotificationFormat = #"window.external.notify('{0}');";
private async void MakeWebviewEditable()
{
WebView.NavigateToString("I do not know how that about righting wrongs can be, said the bachelor, for from 707" +
"straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case" +
"has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures." +
"I do not know how that about righting wrongs can be, said the bachelor, for from 707" +
"straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case" +
"has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures.");
//await InjectJavaScriptAsync(SetBodyEditableScript.Replace(EditableParameter, "true"));
await InjectJavaScriptAsync("document.designMode='on'");
await InjectJavaScriptAsync(GetHtmlFunction);
}
private async Task InjectJavaScriptAsync(string jscript)
{
await WebView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
try
{
// Only execute JS if a document is fully loaded. This should eliminate JS exception related to UNKNOWN name errors.
//if (IsHtmlLoaded)
string result = await WebView.InvokeScriptAsync("eval", new string[] { jscript });
}
catch (Exception ex)
{
}
});
}
}
Can it be done?
To autosize WebView according to its HTML content, we can try with following code:
private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
var webView = sender as WebView;
int width;
int height;
// get the total width and height
var widthString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });
var heightString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });
if (!int.TryParse(widthString, out width))
{
throw new Exception("Unable to get page width");
}
if (!int.TryParse(heightString, out height))
{
throw new Exception("Unable to get page height");
}
// resize the webview to the content
webView.Width = width;
webView.Height = height;
}
And then we can use this method in XAML like:
<WebView Name="WebView" Width="400" MinHeight="200" NavigationCompleted="WebView_NavigationCompleted"/>
Or in code-behind:
public MainPage()
{
this.InitializeComponent();
MakeWebviewEditable();
this.NavigationCacheMode = NavigationCacheMode.Required;
WebView.NavigationCompleted += WebView_NavigationCompleted;
}
Here I used WebView.NavigationCompleted event because we need to make sure the current content has loaded before we try to get the content's width and height.
Update:
While on Windows 10 Mobile, above method might not completely work. This is because WebView on Windows 10 Mobile is not compatible with parent controls that require gestures to propagate up from the WebView control to the parent, such as FlipView, ScrollViewer class, and other related controls.
Ref Remarks of WebView class:
By default, WebView content is hosted on the UI thread on devices in the desktop device family, and off the UI thread on all other devices. You can use the WebView.DefaultExecutionMode static property to query the default threading behavior for the current client. If necessary, you can use the WebView(WebViewExecutionMode) constructor to override this behavior.
Note There might be performance issues when hosting content on the UI thread on mobile devices, so be sure to test on all target devices when you change DefaultExecutionMode.
A WebView that hosts content off the UI thread is not compatible with parent controls that require gestures to propagate up from the WebView control to the parent, such as FlipView, ScrollViewer, and other related controls. These controls will not be able to receive gestures initiated in the off-thread WebView.
As a workaround, usually we can try using something like
WebView WebView = new WebView(WebViewExecutionMode.SameThread);
in code-behind instead of creating web browser in XAML to solve this problem. However as the Note said, hosting content on the UI thread on mobile devices is not a good practice and in my test, this will cause HTML content can't be editable. So this may be not an acceptable solution for your question.
I'm not sure what do you want to achieve. Based on your requirement, you can try like #DecadeMoon said to put the buttons into HTML page. Or you can get the content of the HTML into a RichEditBox. Or you can change your layout and just put the WebView outside the ScrollViewer.
So you're saying you want the height of the WebView control to equal the height of the webpage it is displaying? I don't think that's possible. I imagine the WebView would employ some form of rendering optimizations such that it doesn't need to render what's not visible in the viewport. If the entire height of the webpage is visible, then it has to render everything which would be terrible for performance.
It looks like you're trying to control the webpage directly through the WebView by injecting javascript. You're going to have a hard time doing that. If there's no way to achieve what you want in XAML only, then maybe you can rewrite your app in WinJS instead?
The easiest way to achieve what you want would be to put the buttons directly in the webpage and notify the host when they are clicked so you can act.
XAML
<Grid>
<WebView x:Name="webView" ScriptNotify="webView_ScriptNotify" Height="300"/>
</Grid>
CS
private void prepareWebViewContent()
{
var html = #"
<style>
button {
padding: 15px 20px;
font-size: 40px;
border: none;
background-color: #ccc;
font-family: inherit;
display: block;
margin: 10px auto;
}
button:active {
background-color: #aaa;
}
</style>
<button onclick=""window.external.notify('Navigate1')"">Navigate to web page 1</button>
<button onclick=""window.external.notify('Navigate2')"">Navigate to web page 2</button>
<p>
I do not know how that about righting wrongs can be, said the bachelor, for from 707
straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case
has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures.
I do not know how that about righting wrongs can be, said the bachelor, for from 707
straight you have made me crooked, leaving me with a broken leg that will never see itself straight again all the days of its life and the injury you have redressed in my case
has been to leave me injured in such a way that I shall remain injured for ever and the height of misadventure it was to fall in with you who go in search of adventures.
</p>
";
webView.NavigateToString(html);
}
private void webView_ScriptNotify(object sender, NotifyEventArgs e)
{
switch (e.Value)
{
case "Navigate1":
// Handle this case
break;
case "Navigate 2":
// Handle this case
break;
}
}
It's very rudimentary, but you get the idea.

Hide WebView until JavaScript is done

I have a webview
WebView wv;
wv = (WebView)findViewById(R.id.webView1);
wv.loadUrl("http://example.com/");
Simply said.
at:
onPageFinished
I have:
wv.loadUrl("javascript:(function() { " + "document.getElementsByClassName('centered leaderboard_container')[0].style.display = 'none'; " + "document.getElementsByClassName('n')[0].style.display = 'none'; " + "document.getElementsByClassName('paginator')[0].style.display = 'none'; " + "document.getElementsByTagName('ul')[0].style.display = 'none'; " + "document.getElementsByTagName('tr')[0].style.display = 'none'; " + "})()");
I've set webview visibility to INVISIBLE
How can I set visibility to VISIBLE after the JavaScript is done?
Now you get to see the whole page for a second and than the JavaScript is done..
Anyone?
ps. The website is not mine, its a 3rd party website
Tested on API 17 emulator and it works.
You can inject javascript from Java to the web.
And do vice-versa, once the url is loaded call from javascript to a function on our Java code, and execute the setVisibility(). For that purpose you are going to add a JS interface.
Here the code:
private final static String HOST = "stackoverflow.com";
private WebView wb;
#SuppressLint("SetJavaScriptEnabled")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_home);
wb = (WebView) findViewById(R.id.home_webview);
//Make the webview invisible
wb.setVisibility(View.INVISIBLE);
WebSettings webSettings = wb.getSettings();
webSettings.setJavaScriptEnabled(true);
wb.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url){
//Inject javascript code to the url given
//Not display the element
wb.loadUrl("javascript:(function(){"+"document.getElementById('Id').style.display ='none';"+"})()");
//Call to a function defined on my myJavaScriptInterface
wb.loadUrl("javascript: window.CallToAnAndroidFunction.setVisible()");
}
});
//Add a JavaScriptInterface, so I can make calls from the web to Java methods
wb.addJavascriptInterface(new myJavaScriptInterface(), "CallToAnAndroidFunction");
wb.loadUrl("http://"+HOST);
}
public class myJavaScriptInterface {
#JavascriptInterface
public void setVisible(){
runOnUiThread(new Runnable() {
#Override
public void run() {
wb.setVisibility(View.VISIBLE);
}
});
}
}
This functionality is going to be executed for every page. Once on the 3rd party server you have to manage what to do with every request, webClient.shouldOverrideUrlLoading() can help you.
Updated answer:
I could reproduce it as you commented, for the last version we should do:
Beginning in Android 4.2, you will now have to explicitly annotate public methods with #JavascriptInterface in order to make them accessible from hosted JavaScript. Note that this also only takes effect only if you have set your app's minSdkVersion or targetSdkVersion to 17 or higher.
I added it and imported android.webkit.JavascriptInterface
Reference: JavascriptInterface methods in WebViews must now be annotated
I had the same problem of #GromDroid.
Maybe not the best solution but it works:
public class myJavaScriptInterface {
#JavascriptInterface
public void setVisible(){
runOnUiThread(new Runnable() {
#Override
public void run() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
wb.setVisibility(View.VISIBLE);
}
}, 500);
}
});
}
}
I've added a delay of half second before make the webview visible.

restoring Webview(page) from an android activity

I'm loading a URL from the Main activity,
super.loadUrl("file:///android_asset/www/index.html");
after performing some activities on the web, on a event, I call another activity using droidgap.
I'm not able to give back control to the webpage on finishing the activity.
Basically I need restoring/webpage mechanism where I left to the android activity.
Below are some of the snippets,
MyClass(DroidGap) giving access to JS-
public class MyClass extends DroidGap{
static WebView mAppView;
static DroidGap mGap;
private String RInfo[] = new String[5];
public MyClass(DroidGap gap, WebView view)
{
mAppView = view;
mGap = gap;
}
public void initiateDP(){
Intent intent = new Intent(mGap, DPActivity.class);
mGap.startActivity(intent);
}
MainActivity :-
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init();
super.setIntegerProperty("loadUrlTimeoutValue", 40000);
mc = new MyClass(this, appView);
appView.addJavascriptInterface(mc, "MyCls");
super.loadUrl("file:///android_asset/www/index.html");
}
Index.html:-
alert('shaken');
var r = window.confirm('Do you want to enable remote');
if(r == true)
{
// alert('before redirecting');
window.MyCls.initiateDP();
}
this starts the DPActivity. So from DPActivity, I have to come back to the page where I left.
in DPActivity :-
if(MyClass.mAppView.canGoBack()) {
MyClass.mAppView.goBack();
}
else{
finish();
}
this is not happening. Please suggest me any other mechanism or correct me if wrong.

Categories