Keyboard "done" button pressed event for UIWebView and WKWebView - ios

There are resources for this when using UITextView. How do I register for the Done key button press event? The keyboard shows up when the user focuses a form inside the webview.

The main idea is to use Javascript injection to achieve what you want.
You can try catching the DOM event called onfocusout (Refer to http://www.w3schools.com/jsref/event_onfocusout.asp for more details).
Following is the example of how you could do it for UIWebView. WKWebView can be handled in a similar way.
Call this to inject some Javascript code after the first time your webview loaded
[webView stringByEvaluatingJavaScriptFromString:#"document.getElementById('youTextFieldID').addEventListener('onfocusout', function () {"
#"var frame = document.createElement('iframe');"
#"frame.src = 'doneEditing://';"
#"document.body.appendChild(frame);"
#"setTimeout(function () { document.body.removeChild(frame); }, 0);"
#"}, false);"];
Write your UIWebView delegate method like this
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([request.URL.scheme isEqualToString:#"doneEditing"]) {
// Call you event handler here
[self doneButtonTouchEventHandler]
return NO;
}
return YES;
}
Good luck

The key is to add event listeners when the web page loads. I assume that you want to know about the blur event of a text field.
Here is a basic working example:
<html>
<head>
<script>
function initPage() {
document.addEventListener('focusin', handleFocusIn);
document.addEventListener('focusout', handleFocusOut);
}
function handleFocusIn(e) {
alert('In');
}
function handleFocusOut(e) {
alert('Out');
}
</script>
</head>
<body onload="initPage()">
<form>
<input type="text" name="username">
</form>
</body>
</html>
I hope that helps, please let me know otherwise!
Good luck!

#Ducky
answers is for UIWebView
here is a solution for WkWebview
extend ViewController as WKNavigationDelegate
webView.navigationDelegate = self
implement and override function
get your button id and write on document.getElementById
this method called on page load finish
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
print("loaded")
let doneJS = """
document.getElementById('m_ara_input').addEventListener('focusout', function () {
var frame = document.createElement('iframe');
frame.src = 'doneEditing://';
document.body.appendChild(frame);
setTimeout(function () { document.body.removeChild(frame); }, 0);
}, false);
"""
webView.evaluateJavaScript(doneJS, completionHandler: nil)
}
override below method
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {return}
if (url.scheme == "doneediting") {
executeSubmit()
}
decisionHandler(.allow)
}
write this function
func executeSubmit(){
let js = """
var a = document.getElementsByClassName("btn btn-default pull-left");
a.ara_buton.click();
"""
webView.evaluateJavaScript(js, completionHandler: nil)
}
in javascript ara_buton is the attribute of "name" of button

Related

How to run Code after asynchronus code is finished, Swift

I have a asynchronus Funktion, loadHTMLString, that I call to load the Text out of an HTML File. The loading Process needs time, almost a second. The Problem is: I want to go on with my Code, if the File is loaded, but I dont know when the loading is finished. Is there a way to do that?
func generateAndLoadPDF() {
// Thats my HTML File
let html = HTML.get(from: "Vorlage.html")
// I load this HTML File in my WebView, that takes almost a second
wkWebView.loadHTMLString(html, baseURL: Bundle.main.bundleURL)
// I delayed the Following Code, so the HTML-String has time to load
// Actually I dont want to delay the Code, I want that the following Code runs after .loadHTMLString is finished.
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// I generate the PDF
let wkPDFData = PDF.generate(using: self.wkWebViewPrintFormatter())
self.loadIntoWKWebView(wkPDFData)
}
}
Thanks,
Boothosh
Conform to WKNavigationDelegate
webView.navigationDelegate = self
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
debugPrint("didFinish")
}
}

IOS - WKWebview gets null url in decidePolicy when second clicking the same button

I have a WKWebview with a button that downloads a pdf, the button link is as follows:
<img class= src="$imageurl">
I have managed to download the PDF through certain logic, that has a starting point in decidePolicyFor method:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let url = navigationAction.request.url
if openInDocumentPreview(url!) {
decisionHandler(.cancel)
executeDocumentDownloadScript(webView, forAbsoluteUrl: url!.absoluteString)
} else {
decisionHandler(.allow)
}
}
This works well, and the url is the one with the PDF. However, if I click the button again I only receive null urls, so I cannot open the document again. This is the action I receive:
<WKNavigationAction: 0x102d95fa0; navigationType = -1; syntheticClickType = 0; position x = 0.00 y = 0.00 request = <NSMutableURLRequest: 0x282e151d0> { URL: about:blank }; sourceFrame = <WKFrameInfo: 0x102d502f0; webView = 0x103048200; isMainFrame = YES; request = <NSMutableURLRequest: 0x282e116d0> { URL: https://mysite.appiancloud.com/suite/sites/home }>; targetFrame = <WKFrameInfo: 0x102d577a0; webView = 0x103048200; isMainFrame = NO; request = (null)>>
If I test this on Safari Desktop the file is downloaded ok every time, however I don't find the reason why WKWebView stops receiving the url. No other delegate method is called, not even the createWebViewWith which tends to be called when target="_blank" urls are invoked.
I wonder if WKWebview cachePolicy is taking effect, but I don't find the way to avoid that url caching, or if it is being cached, to receive the event on when it is trying to load it again.
Also, as a note, if I long-click the link, the preview element holds the URL correctly.
Ok, my theory is that by telling the handler that WKNavigationAction policy is .cancel, following requests won't be processed.
What I did is to process the URL download in the createWebViewWith method, and let the policy to be always .allow.

How can i display only the content of a website?

I need to display only a part of the website, basically the CONTENT part of the website.
I can display the website with uiwebkit but, i dont want to display the entire website but only the CONTENT part of the webpage. I have no idea how to do this , as i have never done this and i did some google search but could not find anything on ios / swift.
How can i do this? Thanks.
you can use WKNavigationDelegate which allow you to implement did finish the function of webview in this function you can hide specific content of website.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let removeelementid = "javascript:(function() { " + "document.getElementsByClassName('td-header-menu-wrap-full td-container-wrap')[0].style.display=\"none\"; " + "})()"
webView.evaluateJavaScript(removeelementid) { (res, error) in
if error != nil
{
print("Error")
}
else
{
//do any thing
}
}
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print(error.localizedDescription)
}
as you can see i am removing specific content of web by its class name td-header-menu-wrap-full td-container-wrap
Go to that web site right click -> click inspect. pick class names of content and call in this function . hope this will help you.

Is there a way to determined what element is at a point in a WKWebView or SFSafariViewController view?

I would like to know what element is "under" a particular point in a web view. For example, in the screenshot below, I would like to know what element is at point 550x, 275y. I'm hoping to get the result:
<img alt=​"Typhoon Mangkhut approaching the Philippines on September 14" src=​"/​/​upload.wikimedia.org/​wikipedia/​commons/​thumb/​3/​30/​Mangkhut_2018-09-14_0750Z.jpg/​140px-Mangkhut_2018-09-14_0750Z.jpg" width=​"140" height=​"111" srcset=​"/​/​upload.wikimedia.org/​wikipedia/​commons/​thumb/​3/​30/​Mangkhut_2018-09-14_0750Z.jpg/​210px-Mangkhut_2018-09-14_0750Z.jpg 1.5x, /​/​upload.wikimedia.org/​wikipedia/​commons/​thumb/​3/​30/​Mangkhut_2018-09-14_0750Z.jpg/​280px-Mangkhut_2018-09-14_0750Z.jpg 2x" data-file-width=​"1219" data-file-height=​"963">​
If the webview supports it, you could have javascript determine what's there, and report it to the webview. I apologize but I haven't run this code, I don't have the means to test it at the moment.
If you don't have the ability to add javascript to the page then you'll have to do it all in WKWebView .evaluateJavaScript
find the element value with:
var elem = document.elementFromPoint(550, 275);
Then tell your webview about it by creating a custom scheme request. you can do it this way:
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "customScheme://" + JSON.stringify(elem);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
Intercept it in the webview delegate.
public func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let url = navigationAction.request.url
if(url.range(of:"customScheme://") != nil){
// this is your reported info
}
return true
}
This approach will only tell you the element as it relates to the web browser coordinates, not it's position on the device's screen. If you want to do it via device position you'll have to translate that and pass the coordinates over to the webview by invoking some javascript on the device.

Use wkwebview back reload

I am using WKWebview,I want that when I click the back button, it refresh the page rather than reading the page cache.
if (self.webView.canGoBack) {
[self.webView goBack];
[self.webView reload];
}
But, when you return to certain pages these are loaded twice and can't return to the first page.
Do not know to have people meet the same requirements and how to solve? The premise is not use UIWebview.
I was also facing the same issue. After removing the reload method, it was working correctly.
if ([self.wkWebView canGoBack]) {
[self.wkWebView goBack];
}
var backNavigation: WKNavigation?
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if backNavigation?.isEqual(navigation) ?? false {
webView.reload()
backNavigation = nil
}
}
in my page's js file, I add this and it worked.
var solveLoadingProblem = function () {
window.addEventListener("popstate", function (e) {
location.reload(true);
});
};
solveLoadingProble();

Resources