How to specify a button to open an URL? - button

I want to write a web application that triggers the default email client of the user to send an email.
Thus, I created a Link, that leads to an URL conforming to the mailto URI scheme (http://en.wikipedia.org/wiki/Mailto):
Link emailLink = new Link("Send Email",
new ExternalResource("mailto:someone#example.com"));
However, instead of using a Link, I want to provide a Button that allows to trigger the respective functionality. But, for buttons I cannot set an ExternalResource to be opened.
Does anybody know to solve this problem for Buttons, or how to create a Link that looks and behaves exactly like a button? I also tried some CCS modification but did not manage the task by myself. I also found some solutions for former Vaadin versions (https://vaadin.com/forum/#!/thread/69989), but, unfortunately they do not work for Vaadin 7.

I remember solving a similar problem using a ResourceReference.
Button emailButton = new Button("Email");
content.addComponent(emailButton);
Resource res = new ExternalResource("mailto:someone#example.com");
final ResourceReference rr = ResourceReference.create(res, content, "email");
emailButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Page.getCurrent().open(rr.getURL(), null);
}
});

For solving similar issue, I applied previously:
String email="info#ORGNAME.org";
Link l=new Link();
l.setResource(new ExternalResource("mailto:" + email));
l.setCaption("Send email to " + email);
addComponent(l);

After some further tries a managed to adapt the proposed LinkButton solution from https://vaadin.com/forum/#!/thread/69989 for Vaadin 7:
public class LinkButton extends Button {
public LinkButton(final String url, String caption) {
super(caption);
setImmediate(true);
addClickListener(new Button.ClickListener() {
private static final long serialVersionUID = -2607584137357484607L;
#Override
public void buttonClick(ClickEvent event) {
LinkButton.this.getUI().getPage().open(url, "_blank");
}
});
}
}
However, this solution is still not perfect as it causes the opening of a popup window being blocked by some web browsers.

Related

Passing the search term from SearchHandler to ContentPage in Xamarin Forms 4

I'm trying to make use of the new SearchHandler implemented as part of Xamarin Forms 4. I've found it pretty easy so far to get suggestions populated but now I want to raise an event, or follow the suggested method of handling when a search is confirmed.
public class FoodSearchHandler: SearchHandler
{
IFoodDataStore dataStore = new FoodDataStore();
protected override void OnQueryConfirmed()
{
base.OnQueryConfirmed();
// What to do here?
}
protected override void OnQueryChanged(string oldValue, string newValue)
{
base.OnQueryChanged(oldValue, newValue);
if(!string.IsNullOrWhiteSpace(newValue)
{
// Populate suggestions
ItemsSource = dataStore.GetSuggestions(newValue);
}
else
{
ItemsSource = null;
}
}
}
public partial class FoodsPage : ContentPage
{
ObservableCollection<Food> Foods = new ObservableCollection<Food>();
public ItemsPage()
{
InitializeComponent();
// Wire up the search handler
Shell.SetSearchHandler(this, new FoodSearchHandler());
BindingContext = this;
}
}
Unfortunately, althought the alpha docs mention the search handler they don't contain any details on how to use it and the sample apps only demonstrate populating the suggestions.
Does anyone out there have a pointer to offer on how I should be notifying my ContentPage that my SearchHandler confirmed a search?
So, after reading the Shell docs some more, it seems what I want to do in this situation is use of Shell's new Navigation and navigate to a route passing the search text as a query, for example:
protected override void OnQueryConfirmed()
{
base.OnQueryConfirmed();
var shell = Application.Current.MainPage as Shell;
shell.GoToAsync($"app:///fructika/search?query={Query}", true);
}
N.B. It doesn't look like passing data works right now or if it does I'm doing it wrong but I'll raise a separate question about that.

Add Authorization header to all requests in Xamarin Forms Android WebView

I'm trying to add custom http headers to a webview client (for authorization).
It seems to work in some cases, I'am able to login to a webpage without entering username and password, and I get redirected to another page. But when the page is calling other resources to get elements populated with data an error is thrown and OnReceivedHttpError is invoked. The error I'm getting is 401 unauthorized and when i look through the headers on the IWebResourceRequest i can't see the authorization headers at all.
Am I missing something or have anyone had same problems ?
Using Xamarin Forms 2.3.3.180 and targeting API 21 (Android 5.0 Lollipop), compile with Android 7.1 Nougat.
I've tried in postman to add headers to request and it works perfectly.
Renderer:
public class MyWebViewRenderer : WebViewRenderer
{
private MyWebViewClient _webViewClient;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if(_webViewClient == null)
_webViewClient = new MyWebViewClient();
Control.SetWebViewClient(_webViewClient);
Control.LongClickable = false;
Control.HapticFeedbackEnabled = false;
Control.Settings.JavaScriptEnabled = true;
var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);
var headers = new Dictionary<string, string>();
headers.Add("Authorization", $"Basic {base64string}")
Control.LoadUrl(Control.Url, headers);
}
}
WebViewClient:
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
WebView.SetWebContentsDebuggingEnabled(true);
var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);
var headers = new Dictionary<string, string>();
headers.Add("Authorization", $"Basic {base64string}")
view.LoadUrl(url, headers);
return true;
}
public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest urlResource)
{
//headers does not always contains authorization header, so let's add it.
if (!urlResource.RequestHeaders.ContainsKey("authorization") && !urlResource.RequestHeaders.ContainsKey("Authorization"))
{
var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);
urlResource.RequestHeaders.Add("Authorization", $"{base64string}");
}
return base.ShouldInterceptRequest(view, urlResource);
}
public override void OnReceivedHttpError(WebView view, IWebResourceRequest request, WebResourceResponse errorResponse)
{
base.OnReceivedHttpError(view, request, errorResponse);
}
If you only need the headers on the get requests, the code below will work. However POST requests are a different issue. I needed to do a similar thing (with all requests, not just GET), and all I can say is that there's not straightforward solution, at least not one that I've found (and I've tried everything short of writing my own network driver). I've tried so many methods (ShouldOverrideUrlLoading, ShouldInterceptRequest, custom LoadUrl and PostUrl etc.) and none of them give a 100% solution. There is a lot of misinformation about this so I think some clarification is needed since I've spent two days on this without success.
So here's what I've learned:
If you only need the headers in the GET requests, that's trivial. Simply create an implementation of WebViewClient and override ShouldOverrideUrlLoading like this:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(App.Android.HybridWebViewRenderer))]
namespace App.Android
{
public class HybridWebViewRenderer : WebViewRenderer
{
public HybridWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.SetWebViewClient(new CustomWebViewClient());
}
}
public class CustomWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
{
Dictionary<string, string> headers = new Dictionary<string, string>
{
["Name"] = "value"
};
view.LoadUrl(url, headers);
return true;
}
}
}
If, however, you need the headers in other requests (specifically POST requests) there really isn't a perfect solution. Many answers tell you to override ShouldInterceptRequest but this is unlikely to help. ShouldInterceptRequest provides an IWebResourceRequest which contains the URL of the request, the method (i.e. POST) and the headers. There are answers out there which state that adding the headers by doing request.Headers.Add("Name", "Value") is a viable solution but this is wrong. The IWebResourceRequest is not used by the WebView's internal logic so modifying it is useless!
You can write your own HTTP client in ShouldInterceptRequest which includes your own headers to perform the requests and return a WebResourceResponse object. Again, this works for GET requests, but the problem with this is that even though we can intercept a POST request, we cannot determine the content in the request as the request content is not included in the IWebResourceRequest object. As a result, we cannot accurately perform the request manually. So, unless the content of the POST request is unimportant or can somehow be fetched, this method is not viable.
An additional note on this method: returning null tells the WebView to handle the request for us. In other words 'I don't want to intercept the request'. If the return is not null however, the WebView will display whatever is in the WebResourceResponse object.
I also tried overriding the PostUrl and LoadUrl methods in the WebView itself. These methods are not called by the internal logic, so unless you are calling them yourself, this does not work.
So what can be done? There are a few hacky solutions (see github.com/KeejOow/android-post-webview) to get around this problem, but they rely on javascript and are not suitable in all cases (I have read that they don't work with forms). If you want to use them in Xamarin, you're going to need to adapt the code for C# anyway, and there is no guarantee that it will solve your problem.
I'm writing this so no one else has to waste countless hours finding a solution that doesn't really exist.
If only the Android devs had decided to include the POST content in the IWebResourceRequest object...
And apologies for the length, if you've read to this point, you're probably as desperate as I was.

getting no such element exception

i am getting error as element cannot be found when executing code for one of the test application. I have written code to locate element using css and xpath,but still getting same issue. can any one help?
code :
public static WebDriver driver;
public static void setUp() {
System.setProperty("webdriver.ie.driver", "Resources\\IEDriverServer.exe");
driver = new InternetExplorerDriver();
//System.setProperty("webdriver.gecko.driver", "D:\\selenium\\geckodriver\\geckodriver.exe");
driver.get("http://demo.actitime.com/");
driver.manage().window().maximize();
driver.findElement(By.id("username")).sendKeys("user");
driver.findElement(By.name("pwd")).sendKeys("user");
driver.findElement(By.cssSelector("#loginButton > div")).click();
//Wait<WebDriver> wait=new WebDriverWait(driver, 30);
//wait.until(ExpectedConditions.presenceOfElementLocated(By.id("logoutLink")));
//String parentWindow= driver.getWindowHandle();
driver.findElement(By.cssSelector("div.popup_menu_icon.support_icon > div.popup_menu_arrow")).click();
//driver.findElement(By.xpath("id('topnav')/x:tbody/x:tr[1]/x:td[5]/x:table/x:tbody/x:tr/x:td[2]/x:div/x:table/x:tbody/x:tr[2]/x:td/x:div/x:div[2]/x:div/x:div[1]/x:div[2]")).click();
driver.findElement(By.linkText("User Guide")).click();
}
public static void tearDown() {
driver.quit();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
setUp();
tearDown();
}
}
When you click on the Login Button it takes the browser a couple of seconds to send your request and return/render the response page, But in your code, You're trying to click the Help button right after clicking the login button(the help button isn't displayed yet), Which won't find the element you're looking for in the current page, because you're still on the login page.
So you need to wait till the page after the login is rendered and then you can select and click on whatever you want.
To wait for the element to be clickable use this code:
WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
wait.until(ExpectedConditions.elementToBeClickable(cssSelector("div.popup_menu_icon.support_icon > div.popup_menu_arrow")));
EDIT:
It seems that you're using the wrong css selector. Try this one:
cssSelector("div.popup_menu_button.popup_menu_button_support")

Calling a non-parental Activity method from fragment without creating a new instance

I have my MainActivity and inside that I have a number of fragments. I also have another activity that works as my launcher and does everything to do with the Google Drive section of my app. On start up this activity launches, connects to Drive and then launches the MainActivity. I have a button in one of my fragments that, when pushed, needs to call a method in the DriveActivity. I can't create a new instance of DriveActivity because then googleApiClient will be null. Is this possible and how would I go about doing it? I've already tried using getActivity and casting but I'm assuming that isn't working because DriveActivity isn't the fragments parent.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO for test only remove
directory = new Directory(SDCARD + LOCAL_STORAGE);
byte[] zippedFile = directory.getZippedFile(SDCARD + STORAGE_LOCATION + directory.getZipFileName());
//Here I need to somehow call DriveActivity.uploadFileToDrive(zippedFile);
//((DriveActivity)getActivity()).uploadFileToDrive(zippedFile);
}
});
Right, so I'm having a bit of difficulty with the heirarchy but I think what you want to do is define a method in the fragment that the activity will be required to override to use.
This will allow you to press the button, and then fire a method whos actual implementation is inside the parent.
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
example implementation:
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
//Button fired logic
}
};
so in the child you'd do just call:
this.onItemSelected("ID of Class");
EDITED
In retrospect what I believe you need is an activity whos sole purpose is to upload files, not fire off other activities.
Heres an example of a 'create file' activity:Google Demo for creating a file on drive
Heres an example of the 'base upload' activity' Base Service creator

return values from javafx dialog

I created a form with javafx that opens a login dialog, after the user enters the login information correctly the dialog closed and the main form loaded some data, what I need is that when the login dialog is closed it would return the user id (which make the login) to the main form, the code of the above case is like that:
The main form
Stage loginDialog = new LoginDialog(stage);
loginDialog.sizeToScene();
loginDialog.showAndWait();
the login dialog form
/* do the login */
close();
/* need to return thew user id to the main form*/
Any help please
The first thing I would suggest is to create your own simple dialog box. The controlsFX stuff is cool, but my experience has been that some of the controls are overly complex and others have bugs. Here is an abridged example.
public class DialogBox {
private static String[] login;
public static String[] display(String title, String message) {
Stage window = new Stage();
window.initModality(Modality.APPLICATION_MODAL);
window.setTitle(title);
window.setWidth(300);
window.setHeight(175);
window.initStyle(StageStyle.UTILITY);
Label label = new Label(message);
// Set up the JavaFX button controls and listeners and the text fields
// for the login info. The button listeners set the login values
window.setScene(new Scene(root, 300, 175);
window.showAndWait();
return login;
}
}
As you can see, there is a single static method called display() that returns a String array that contains the user login information. Simply do a static call to this method as follows.
String[] login = DialogBox.display("Login Dialog", "Enter User Name and Password");
Your answer is ControlsFX library.
I have posted here.
This library allows you to get return value from a dialog box. The best of all, you can create your own customized dialog box.

Resources