Remove DIV from a webpage for webview android using Jsoup - android-webview

I want to partially view a webpage on webview android and remove some div element from the webpage. I have a webpage like this
<!DOCTYPE html>
<body>
<div id="a"><p>Remove aa</p></div>
<div id="b"><p>bb</p></div>
</body></html>
Now I want to remove the div with id 'a' from the webpage.
I tried to code it with Jsoup but I am not well enough to make it out. Please see my full code:
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class CustomWebsite extends Activity {
private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_website);
Document doc;
String htmlcode = "";
try {
doc = Jsoup.connect("http://skyasim.info/ab.html").get();
doc.head().getElementsByTag("DIV#a").remove();
htmlcode = doc.html();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
webView = (WebView) findViewById(R.id.webView_test);
webView.setWebViewClient(new myWebClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("htmlcode");
}
public class myWebClient extends WebViewClient
{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
view.loadUrl(url);
return true;
}
}
}

You can do this without using Jsoup you know. Just use plain old javascript. The following code will show how to remove an element from the HTML page and display the rest.
final WebView mWebView = (WebView) findViewById(R.id.mWebViewId);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url)
{
mWebView.loadUrl("javascript:(function() { " +
"document.getElementById('a')[0].style.display='none'; " +
"})()");
}
});
mWebView.loadUrl(youUrl);

Remove it from the document by selecting it and then using the remove-method.
doc.select("div#a").remove();
System.out.println(doc);
Example:
Document doc = Jsoup.parse(html);
System.out.println("Before removal of 'div id=\"a\"' = ");
System.out.println("-------------------------");
System.out.println(doc);
doc.select("div#a").remove();
System.out.println("\n\nAfter removal of 'div id=\"a\"' = ");
System.out.println("-------------------------");
System.out.println(doc);
will result in
Before removal of 'div id="a"' =
-------------------------
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="a">
<p>Remove aa</p>
</div>
<div id="b">
<p>bb</p>
</div>
</body>
</html>
After removal of 'div id="a"' =
-------------------------
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="b">
<p>bb</p>
</div>
</body>
</html>

I had tried to use Jsoup to do something similar before, but my app always crash. If you are open to using Javascript only (which helps to make your app size smaller), here is what I did for my app:
webview3.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:var con = document.getElementById('a'); " +
"con.style.display = 'none'; ");
}
});
Hope my Javascript is correct. The idea here is to use Javascript to hide the div after the page has finished loading.

Related

Vertx3.0 Simple Form upload

Vertx3.0 http simpleform file uploader is throwing error for multiple file.
Am using vertx3.0 simple form upload. It is working fine when i upload single file. If the form has the input "multiple" and choose multiple files, The HTTPServerUpload is throwing error "Response has already been written". Since the response is end in the endhandler for 1st file, it is throwing this error for subsequent files. is there any other way for multiple files ?
Simpleform file upload using vertx3.0
public class SimpleFormUploadServer extends AbstractVerticle {
public static void main(String[] args) {
Runner.runExample(SimpleFormUploadServer.class);
}
#Override
public void start() throws Exception {
vertx.createHttpServer()
.requestHandler(req -> {
if (req.uri().equals("/")) {
// Serve the index page
req.response().sendFile("index.html");
} else if (req.uri().startsWith("/form")) {
req.setExpectMultipart(true);
req.uploadHandler(upload -> {
upload.exceptionHandler(cause -> {
req.response().setChunked(true)
.end("Upload failed");
});
upload.endHandler(v -> {
req.response()
.setChunked(true)
.end("Successfully uploaded to "
+ upload.filename());
});
// FIXME - Potential security exploit! In a real
// system you must check this filename
// to make sure you're not saving to a place where
// you don't want!
// Or better still, just use Vert.x-Web which
// controls the upload area.
upload.streamToFileSystem(upload.filename());
});
} else {
req.response().setStatusCode(404);
req.response().end();
}
}).listen(8080);
}
}
Exception :
SEVERE: Unhandled exception
java.lang.IllegalStateException: Response has already been written
at io.vertx.core.http.impl.HttpServerResponseImpl.checkWritten(HttpServerResponseImpl.java:561)
at io.vertx.core.http.impl.HttpServerResponseImpl.end0(HttpServerResponseImpl.java:389)
at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:307)
at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:292)
at com.nokia.doas.vertx.http.upload.SimpleFormUploadServer$1$1$2.handle(SimpleFormUploadServer.java:85)
at com.nokia.doas.vertx.http.upload.SimpleFormUploadServer$1$1$2.handle(SimpleFormUploadServer.java:1)
at io.vertx.core.http.impl.HttpServerFileUploadImpl.notifyEndHandler(HttpServerFileUploadImpl.java:213)
at io.vertx.core.http.impl.HttpServerFileUploadImpl.lambda$handleComplete$165(HttpServerFileUploadImpl.java:206)
at io.vertx.core.file.impl.AsyncFileImpl.lambda$doClose$226(AsyncFileImpl.java:470)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$16(ContextImpl.java:335)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
at java.lang.Thread.run(Unknown Source)
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
<form action="/form" ENCTYPE="multipart/form-data" method="POST" name="wibble">
choose a file to upload:<input type="file" name="files" multiple="multiple"/><br>
<input type="submit"/>
</form>
</body>
</html>
You can use vertx-web to easily handle file uploads:
router.route().handler(BodyHandler.create());
router.post("/some/path/uploads").handler(routingContext -> {
Set<FileUpload> uploads = routingContext.fileUploads();
// Do something with uploads....
});
Moreover, you will take benefits of the routing facility, and you can even serve static files such as index.html.
Hope this will help.
Multiple file upload is achievable in vert.x. Use multiple upload button in HTML and use uploadHandler of HttpRequest. UploadHandler would be invoked as many times any many files have been uploaded.
HttpServerRequest request = routingContext.request();
request.setExpectMultipart(true);
request.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
MultiMap entries = request.formAttributes();
Set<String> names = entries.names();
logger.info("UPLOAD_CONTENT: fileName = "+entries.get("fileName"));
logger.info("UPLOAD_CONTENT: type = "+entries.get("type"));
logger.info("UPLOAD_CONTENT: names = "+names);
request.response().setChunked(true).end(createResponse("SUCCESS"));
}
});
// This would be called multiple times
request.uploadHandler(upload -> {
upload.exceptionHandler(new Handler<Throwable>() {
#Override
public void handle(Throwable error) {
logger.error("UPLOAD_CONTENT: Error while uploading content "+upload.filename());
logger.error("UPLOAD_CONTENT: error = "+error.toString());
error.printStackTrace();
request.response().setChunked(true).end(createResponse("FAILURE"));
}
});
upload.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
logger.info("UPLOAD_CONTENT: fileName = "+upload.filename());
logger.info("UPLOAD_CONTENT: name = "+upload.name());
logger.info("UPLOAD_CONTENT: contentType = "+upload.contentType());
logger.info("UPLOAD_CONTENT: size = "+upload.size());
UtilityFunctions.uploadToS3(upload.filename(), "testfolder");
}
});
upload.streamToFileSystem(upload.filename());
});

Wicket submit action doesn't work

After updating Wicket from version 6.12 to 6.13/6.14 onSubmit action doesn't work. For Example class:
public class LoginPage extends WebPage {
private String username = "";
private String password = "";
public LoginPage() {
super();
Form<?> form = new Form<Void>("form");
setDefaultModel(new CompoundPropertyModel<>(this));
form.add(new Button("submit") {
#Override
public void onSubmit() {
System.out.println("SUBMIT "+username+":"+password);
}
});
form.add(new TextField<String>("username").setRequired(true));
form.add(new PasswordTextField("password").setRequired(true));
add(form);
}
}
with HTML:
<!DOCTYPE html>
<html xmlns:wicket>
<body>
<form wicket:id="form">
<input id="name" type="text" placeholder="Username" wicket:id="username">
<input id="password" type="password" placeholder="Password" wicket:id="password">
<input type="submit" wicket:id="submit" value="Enter">
</form>
</body>
</html>
doesn't works with wicket version 6.13+ and great work with wicket 6.12-. Changing Button on something like SubmitLink doesn't help.
Could you tell me what's wrong?
Well... hacky but it seems to work with 6.15.
Replace encodePageComponentInfo with the following one.
#Override
protected void encodePageComponentInfo(Url url, PageComponentInfo info) {
Args.notNull(url, "url");
if (info != null) {
String s = info.toString();
if (!Strings.isEmpty(s)) {
try {
Integer.parseInt(s);
} catch (Exception e) {
QueryParameter parameter = new QueryParameter(s, "");
url.getQueryParameters().add(parameter);
}
}
}
}
I found problem in my test project. I use changed MountedMapper for hiding version number in the URL:
/**
* Wrapper for hiding the version number in the URL
*/
public class SimpleMountedMapper extends MountedMapper {
public SimpleMountedMapper(String mountPath, Class<? extends IRequestablePage> pageClass) {
super(mountPath, pageClass, new PageParametersEncoder());
}
#Override
protected void encodePageComponentInfo(Url url, PageComponentInfo info) {
}
public Url mapHandler(IRequestHandler requestHandler) {
if (requestHandler instanceof ListenerInterfaceRequestHandler) {
return null;
} else {
return super.mapHandler(requestHandler);
}
}
}
In new version of wicket something wrong with this implementation (got it from this question).

Phonegap Screen-orientation plugin update for 2.7.0 or 2.8.0

Is there anybody out there, who knows how to fix this plugin to work with the newest cordova/phonegap version?
I have no idea how i can fix the errors in eclipse and i really need a method to change orientation for several pages in my phonegap app!
You need to make the following changes:
ScreenOrientation.java
Replace with this:
package com.tsukurusha.phonegap.plugins;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
public class ScreenOrientation extends CordovaPlugin {
// Refer to http://developer.android.com/reference/android/R.attr.html#screenOrientation
private static final String UNSPECIFIED = "unspecified";
private static final String LANDSCAPE = "landscape";
private static final String PORTRAIT = "portrait";
private static final String USER = "user";
private static final String BEHIND = "behind";
private static final String SENSOR = "sensor";
private static final String NOSENSOR = "nosensor";
private static final String SENSOR_LANDSCAPE = "sensorLandscape";
private static final String SENSOR_PORTRAIT = "sensorPortrait";
private static final String REVERSE_LANDSCAPE = "reverseLandscape";
private static final String REVERSE_PORTRAIT = "reversePortrait";
private static final String FULL_SENSOR = "fullSensor";
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("set")) {
String orientation = args.optString(0);
Activity activity = this.cordova.getActivity();
if (orientation.equals(UNSPECIFIED)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
} else if (orientation.equals(LANDSCAPE)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else if (orientation.equals(PORTRAIT)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (orientation.equals(USER)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
} else if (orientation.equals(BEHIND)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_BEHIND);
} else if (orientation.equals(SENSOR)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
} else if (orientation.equals(NOSENSOR)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
} else if (orientation.equals(SENSOR_LANDSCAPE)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else if (orientation.equals(SENSOR_PORTRAIT)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
} else if (orientation.equals(REVERSE_LANDSCAPE)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
} else if (orientation.equals(REVERSE_PORTRAIT)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
} else if (orientation.equals(FULL_SENSOR)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
callbackContext.success();
return true;
} else {
return false;
}
}
}
pg-plugin-screen-orientation.js
Replace with this:
cordova.define("cordova/plugin/screenorientation", function(require, exports, module) {
var exec = require('cordova/exec');
var ScreenOrientation = function() {};
ScreenOrientation.prototype.set = function(str, successCallback, errorCallback) {
exec(successCallback,
errorCallback,
'ScreenOrientation',
'set',
[str]);
};
var screenorientation = new ScreenOrientation();
module.exports = screenorientation;
});
Then you can replace sample.html with this:
<!DOCTYPE html>
<html>
<head>
<title>ScreenOrientation PhoneGap Plugin Sample</title>
<meta charset="utf-8">
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8" src="pg-plugin-screen-orientation.js"></script>
<script type="text/javascript">
function setOrientation(type){
cordova.require('cordova/plugin/screenorientation').set(
type,
function() {
console.log("Successfully set "+type);
},
function() {
console.error("Failed to set "+type);
}
);
}
</script>
</head>
<body>
<h1>ScreenOrientation PhoneGap Plugin Sample</h1>
<input type="button" onclick="setOrientation('landscape');" value="Landscape" />
<input type="button" onclick="setOrientation('portrait');" value="Portrait" />
<input type="button" onclick="setOrientation('sensorLandscape');" value="Sensor Landscape" />
<input type="button" onclick="setOrientation('sensorPortrait');" value="Sensor Portrait" />
<input type="button" onclick="setOrientation('reverseLandscape');" value="Reverse Landscape" />
<input type="button" onclick="setOrientation('reversePortrait');" value="Reverse Portrait" />
<input type="button" onclick="setOrientation('fullSensor');" value="Full Sensor" />
</body>
</html>
I've put this together as an Eclipse project - you can download it and the resulting APK here
Note: You might want downgrade from Cordova 2.8.0 to Cordova 2.4.0 until issues with pausing the app in Cordova 2.5.0+ have been resolved - see here

how to add script to the body (similar functionality like method renderHead(Component component, IHeaderResponse response))

With the following code, I add trackingpixel to some page page.html by overriding the method renderHead(Component component, IHeaderResponse response). This works fine.
page.html looks like this:
<!doctype html>
<html xmlns:wicket="http://wicket.apache.org/">
<head>
..
<wicket:container wicket:id="header"></wicket:container>
</head>
<body>
..
<script wicket:id="scriptHolder" type="text/javascript" > I would like to add my script here
</script>
..
</body>
</html>
TrackingPixel.java:
public abstract class TrackingPixel extends AbstractDefaultAjaxBehavior {
protected TrackingPixel(TrackingPixelType type) {
..
}
#Override
public void renderHead(Component component, IHeaderResponse response) {
response.renderOnDomReadyJavaScript("WebtrekkInstance = {
..
'path' : 'anyPath',
...:...
..
};
");
}
}
renderHead-method adds a trackingpixel to the main page. Right mouse click on the page -> source code shows that the following script is added to the page:
<script type="text/javascript" >
Wicket.Event.add(window, "domready", function(event) {
WebtrekkInstance = {
..
'path' : 'anyPath',
...:...
..
};
..
;});
</script>
Now I would like to add trackingpixel to a popup. My problem is that I can't add a script to the body. The method renderHead(Component component, IHeaderResponse response) doesn't do that, because (I guess) the popup pops up on the same page, so there is only one head and it will not render twice. So I tried to do this with WebMarkupContainer as you can see below.
OurServicePopup.java
/**
* Class to display our service as popup
*/
public class OurServicePopupPage<T> extends WebPage {
public OurServicePopupPage(PageParameters parameters) {
super(parameters);
}
#Override
protected void onInitialize() {
add(new OurServicePixel());
super.onInitialize();
}
}
OurServicePixel.java looks like this:
public class OurServicePopupPixel extends TrackingPixel{
public OurServicePopupPixel() {
}
WebMarkupContainer scriptContainer = new WebMarkupContainer("scriptContainer");
#Override
public void renderHead(Component component, IHeaderResponse response) {
scriptContainer.add(new AttributeAppender("type", Model.of("text/javascript")));
scriptContainer.add(
new AttributeAppender("src","WebtrekkInstance = {
..
'path' : 'anyPath',
...:...
..
};
");
}
add(scriptContainer); //this shows error
}
The problem here is that I cannot add the scriptContainer. add(scriptContainer); will not work, because OurServicePopupPixel is a behaviour and not a page.
Maybe you can simple use a Label component with setEscapeModelStrings(false). But it seems a bit strange.
I didn't full understand what is your javascript doing, but maybe you can try to execute it when the DOM is ready. Using a renderHead like this:
public void renderHead(IHeaderResponse response) {
response.render(OnDomReadyHeaderItem.forScript( ... YOUR SCRIPT HERE ... ));
}
I hope it helps.

Reusing wicket component in a form

I have built a wicket component that contains input/labels and methods to change presentation (required, enabled, etc.). The components render fine, but what happens is when the form submits I see only 1 form parameter 'input', and it's the last InputRow component.
InputRow.html
<html xmlns:wicket="http://wicket.apache.org">
<head>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<wicket:panel>
<label wicket:id="label">abc: <span class="req">*</span></label>
<span class="input">
<input wicket:id="input" type="text" id="name"></input>
</span>
<span wicket:id="input_feedback"></span>
</wicket:panel>
</body>
</html>
InputRow.java
package com.wicket;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
public class InputRow extends Panel{
#SuppressWarnings("unused")
private String id;
public InputRow(String id, String label) {
super(id);
this.id = id;
Label memberIdLabel = new Label("label",label);
memberIdLabel.setEscapeModelStrings(false)
.add(new AttributeAppender("for", new Model<String>(id),""));
add(memberIdLabel);
TextField<String> name = new TextField<String>("input");
name.setType(String.class)
.setMarkupId(id)
.setOutputMarkupId(true);
add(name);
add(new Label("input_feedback",""));
}
public InputRow disable()
{
get("input")
.setEnabled(false)
.add(new AttributeAppender("class", new Model<String>("disabled"),""));
get("label")
.add(new AttributeAppender("class", new Model<String>("disabled"),""));
return this;
}
public InputRow required()
{
Model model = (Model)get("label").getInnermostModel();
StringBuffer label = new StringBuffer((String)model.getObject());
label.append(" <span class=\"req\">*</span>");
model.setObject(label);
((TextField)get("input")).setRequired(true);
return this;
}
#Override
protected void onBeforeRender() {
super.onBeforeRender();
Label feedback = (Label)get("input_feedback");
if (get("input").getFeedbackMessage() != null)
{
feedback.setDefaultModel(new Model<String>("Required"));
}
}
}
Adding to the form component
add(new InputRow("name","Name:").required());
edit
I didn't set up a ListView or repeater since I know what rows / fields I want to add to the form at build time.
Your InputFields are missing their models. This way, wicket doesn't know where to store the formdata. If you add models to the fields they will be populated automatically.
There's not just one form parameter submitted. The submits are of the named like name:input, name2:input, ...
But as Nicktar suggests in the comment you should use a model to bind the value of the form component to your entity object. You have to accept an IModel in the constructor and use it in the constructor of TextField.
A better approach to what you are trying to do is to write a Behavior which adds decorating markup for your FormComponent. That way it works for more than just simple text input fields and you can fully customize the instances of your FormComponents.
It could look like this:
public class FormComponentBehavior extends Behavior {
#Override
public void bind(Component component) {
if (!(component instanceof FormComponent)) {
throw new IllegalArgumentException();
}
}
#Override
public void beforeRender(Component component) {
FormComponent<?> fc = (FormComponent<?>) component;
Response r = component.getResponse();
r.write("<label" + (fc.isRequired() ? " class='required'" : "") + ">");
r.write(fc.getLabel().getObject());
r.write("</label>");
r.write("<span class='input'>");
}
#Override
public void afterRender(Component component) {
component.getResponse().write("</span>");
// if feedback errors write them to markup...
}
}
Then you have to add this behavior to your FormComponent instances.
Maybe the problem with your form is that your input text fields have all the same id. Try using attribute 'name' instead of 'id'