I try to automatically fill in a login formula and confirm data by clicking the login button. I would like to use Swift 5, macOS 10.15 and a WKWebView.
The first step is done, I can fill in my login data like this:
import Cocoa
import WebKit
class ViewController: NSViewController, WKUIDelegate, WKNavigationDelegate {
let webView = WKWebView()
let button = NSButton()
override func viewDidLoad() {
super.viewDidLoad()
button.frame = CGRect(x: 400, y: 0, width: 40, height: 20)
button.image = NSImage(named: NSImage.Name("Button"))
button.target = self
button.action = #selector(self.fillIn)
self.view.addSubview(button)
self.webView.uiDelegate = self
self.webView.navigationDelegate = self
webView.frame = CGRect(x: 0, y: 0, width: 400, height: 270)
view.addSubview(webView)
let url = URL(string: "https://lobby.ogame.gameforge.com/de_DE/hub")
let request = URLRequest(url: url!)
webView.load(request)
}
#objc func fillIn() {
setWebViewValue(name: "email", data: "user#web.de")
setWebViewValue(name: "password", data: "pwdpwd")
}
func setWebViewValue(name: String, data: String) {
let jsFunc = "document.getElementsByName(\"\(name)\")[0].value = \"\(data)\""
webView.evaluateJavaScript(jsFunc) {(result, error) in
print(result, error)
}
}
}
But when I click the login button, all data will be removed. So the email and password input fields are empty while logging in and I get an invalid input data error.
Example
Please note, even if the email address is wrong, the address and password input fields are not cleared when clicking to the login button.
Question:
Why is the auto-filled data deleted when you click the login button and why is the data that was entered normally not deleted?
Check the javascript code on the page to see if it is clearing the fields on it's own or maybe it was waiting for typing into the fields.
Related
This is a macOS app, I'm trying to take a full page screenshot of a webview, but i'm unable to get the screenshot of the full page.
Screenshot function.
func takescreenshot(
_ webView: WKWebView,
didFinish navigation: WKNavigation!) {
let configuration = WKSnapshotConfiguration()
configuration.afterScreenUpdates = true
webView.takeSnapshot(with: configuration) { (image, error) in
if let image = image {
//Save Image
}
}
}
from the answers I've seen here the solution seems to be setting the webview scrollview offset, but this is only available for ios. This is the error i get:
Value of type "WKWebView" has no member "scrollView"
I guess the problem is caused by an internal scroll view that optimizes drawing for scrolling - by redrawing only parts that are soon to be visible.
To overcome this, you can temporarily resize the web view to it's full content extent. I know it's not an ideal solution, but you may derive better one based on this idea.
webView.evaluateJavaScript("[document.body.scrollWidth, document.body.scrollHeight];") { result, error in
if let result = result as? NSArray {
let orig = webView.frame
webView.frame = NSRect(x: 0, y: 0, width: (result[0] as! NSNumber).intValue, height: (result[1] as! NSNumber).intValue)
let configuration = WKSnapshotConfiguration()
webView.takeSnapshot(with: configuration) { image, error in
if let image = image {
NSPasteboard.general.clearContents()
NSPasteboard.general.setData(image.tiffRepresentation, forType: .tiff)
}
}
webView.frame = orig
}
}
I have an NSAttributedString that can contain NSTextAttachments. I have subclassed the NSTextAttachment and have a property that stores an error message if there was a problem downloading the attachment's image.
I am also subclassing NSLayoutManager to enumerate over attachments and if an error is present in an attachment, it shows the error message on screen in the middle of a CGRect that I provide as a default. In the simulator this works as planned; however, on a device there is a default icon over the bounds of the CGRect. Please see attached images to understand this default icon. How can I override or get rid of this default icon?
Example of the results in the simulator.
Example of the results on a device.
I have researched how to override this icon being displayed but have not found anything. Any ideas?
My initializers in the NSTextAttachment subclass are very basic:
override init(data contentData: Data?, ofType uti: String?) {
super.init(data: contentData, ofType: uti)
}
required convenience init?(coder: NSCoder) {
self.init()
imageCloudID = (coder.decodeObject(forKey: "imageLocation") as! String)
setImage()
}
public override func encode(with coder: NSCoder) {
coder.encode(imageCloudID, forKey: "imageLocation")
}
And then if there is an error downloading the image, it sets the optional error property to that error.
In the NSLayoutManager here is my code:
// Enumerate attachments and draw a placeholder rectangle with error message if an error exists.
textStorage.enumerateAttribute(.attachment, in: textStorage.entireRange, options: []) { optValue, range, stop in
guard let attachment = optValue as? MyImageAttachment else { return }
let glyphRange = self.glyphRange(forCharacterRange: range, actualCharacterRange: nil)
self.enumerateLineFragments(forGlyphRange: glyphRange) { rect, usedRect, textContainer, suppliedGlyphRange, stop in
// Get the size of the rectangle we want to show for the attachment placeholder.
let width = rect.size.width
let imageRect = CGRect(x: rect.minX + 5, y: rect.minY + 10, width: width - 10, height: width / 2)
<<Create a bezier path to outline the rectangle.>>
// Set the UI message to the error message, if present.
guard let imageError = attachment.imageError else {
// If there is not an error present, exit the function.
return
}
let errorMessage: String
switch imageError {
case .no_Internet:
errorMessage = "Internet not available."
<< other error messages >>
}
// Show the error message in the placeholder rectangle.
let messageFont = UIFont.systemFont(ofSize: 16, weight: .light)
let attributedMessage = NSAttributedString(string: errorMessage, attributes: [NSAttributedString.Key.font: messageFont])
// Center the message.
let messageWidth = attributedMessage.size().width
let startingPoint = (imageRect.width - messageWidth) / 2
attributedMessage.draw(in: CGRect(x: startingPoint, y: imageRect.midY, width: imageRect.width, height: imageRect.height))
return
}
}
Recently, I had a similar issue. Assigning nil for image in NSTextAttachment did not work for me.
So this is the workaround I implemented.
let attachment = NSTextAttachment()
attachment.image = UIImage()
return attachment
For the life of me I can't get the GIF to display using the SwiftyGif library. Is there something I'm missing here?
var outgoingMessageView: UIImageView!
outgoingMessageView = UIImageView(frame:
CGRect(x: llamaView.frame.maxX - 50,
y: llamaView.frame.minY + 75,
width: bubbleImageSize.width,
height: bubbleImageSize.height))
outgoingMessageView.delegate = self
if textIsValidURL == true {
print("URL is valid")
outgoingMessageView.image = bubbleImage
let maskView = UIImageView(image: bubbleImage)
maskView.frame = outgoingMessageView.bounds
outgoingMessageView.mask = maskView
outgoingMessageView.frame.origin.y = llamaView.frame.minY - 25
let url = URL(string: text)
outgoingMessageView.setGifFromURL(url, manager: .defaultManager, loopCount: -1, showLoader: true)
} else {
outgoingMessageView.image = bubbleImage
}
// Set the animations
label.animation = "zoomIn"
//outgoingMessageView.animation = "zoomIn"
// Add the Subviews
view.addSubview(outgoingMessageView)
print("outgoingMessageView added")
The delegate lets me know it runs successfully via:
gifDidStart
gifURLDidFinish
Checking outgoingMessageView.isAnimatingGif() tells me it's still running.
Checking outgoingMessageView.isDisplayedInScreen(outgoingMessageView) tells me it's not being displayed
It "finishes" almost immediately, but it's the same in the example project, yet the gif still loops and displays in the project. I've changed loop counts, imageviews, not running via a mask as I intended and instead just a UIImageView, changed the GIF urls, all to no avail. Is this problem related to my view structure?
I am calling this function based on actions in a collectionView.Image Example Here
Using the latest SwiftyGIF version.
I just made a sample about this with the following code:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
testSwiftyGif()
}
public func testSwiftyGif() {
let imgPath = "https://github.com/kirualex/SwiftyGif/blob/master/SwiftyGifExample/1.gif?raw=true"
let imgUrl = URL(string: imgPath)!
var outgoingMessageView: UIImageView!
outgoingMessageView = UIImageView(frame:
CGRect(x: llamaView.frame.maxX - 50,
y: llamaView.frame.minY + 75,
width: 200,
height: 200))
outgoingMessageView.setGifFromURL(imgUrl, manager: .defaultManager, loopCount: -1, showLoader: true)
self.view.addSubview(outgoingMessageView)
print("outgoingMessageView added")
}
And it adds the gif as intended:
Aparently the issue is your view structure. The image is being added to the view, but the view is not visible due mask, frame or superview position.
Try to check the view hierarchy using the xCode View Hierarchy Debugger
I am trying to display an OS X application statusItem in the System Status Bar and am having success with everything except the fact that the title is being cut off. I am initializing everything like so:
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
func applicationDidFinishLaunching(aNotification: NSNotification) {
let icon = NSImage(named: "statusIcon")
icon?.template = true
statusItem.image = icon
statusItem.menu = statusMenu
statusItem.title = "This is a test title"
}
The problem is the statusItem.title is appearing like so:
As you can see the application next to mine (iStatMenuBar) is cutting off the title to my application (or something similar is happening)
If I comment out the icon for the statusItem, it works and shows the entire title but when I re-add the icon it cuts off again. Is there a way for the two (icon and title) to co exist? I have reviewed some Apple docs and may have missed a critical piece which explains this.
Thanks guys.
One option would be to assign a custom view to your statusBarItem and within that view's class override drawRect(dirtyRect: NSRect) e.g.
private var icon:StatusMenuView?
let bar = NSStatusBar.systemStatusBar()
item = bar.statusItemWithLength(-1)
self.icon = StatusMenuView()
item!.view = icon
and StatusMenuView might look like:
// This is an edited copy & paste from one of my personal projects so it might be missing some code
class StatusMenuView:NSView {
private(set) var image: NSImage
private let titleString:NSString = "really long title..."
init() {
icon = NSImage(named: "someImage")!
let myWideStatusBarItemFrame = CGRectMake(0, 0, 180.0, NSStatusBar.systemStatusBar().thickness)
super.init(frame.rect)
}
override func drawRect(dirtyRect: NSRect)
{
self.item.drawStatusBarBackgroundInRect(dirtyRect, withHighlight: self.isSelected)
let size = self.image.size
let rect = CGRectMake(2, 2, size.width, size.height)
self.image.drawInRect(rect)
let titleRect = CGRectMake( 2 + size.width, dirtyRect.origin.y, 180.0 - size.width, size.height)
self.titleString.drawInRect(titleRect, withAttributes: nil)
}
}
Now, the above might change your event handling, you'll need to handle mouseDown in the StatusMenuView class.
I am having some trouble using the text in textField. I've copied the relevant code below (and removed some things here and there that shouldn't affect the errors I am getting).
The code builds and runs fine.
I can input text into the textFields (email, password).
But when I try to use the text anywhere, it errors: fatal error: attempt to bridge an implicitly unwrapped optional containing nil on the Alamofire code, specifically the parameters.
Even when I just try to print(email) I get a nil error.
Am I missing something here? I feel like this should be easy but I can't seem to figure it out.
class loginPageViewController: UIViewController, TextFieldDelegate {
private var email: TextField!
private var password: TextField!
func loginButton(sender: RaisedButton!){
let parameters = [
"email" : email,
"password" : password
]
Alamofire.request(.POST, "https://kidgenius.daycareiq.com/api/v1/sessions", parameters: parameters, encoding: .URL)
//other alamofire code not relevant to question
}
override func viewDidLoad() {
super.viewDidLoad()
prepareEmail()
preparePassword()
prepareLoginButton()
}
private func prepareEmail() {
let email : TextField = TextField(frame: 100, 100, 200, 45))
email.delegate = self
email.placeholder = "Email"
//I removed some non relevant code here, just styling stuff
view.addSubview(email)
}
private func preparePassword() {
let password : TextField = TextField(100, 200, 200, 25))
password.secureTextEntry = true
password.delegate = self
password.placeholder = "Password"
//some more removed styling code
view.addSubview(password)
}
private func prepareLoginButton() {
let loginButton : RaisedButton = RaisedButton(frame: 100, 250, 150 , 35))
loginButton.setTitle("Login", forState: .Normal)
loginButton.addTarget(self, action: "loginButton:", forControlEvents: UIControlEvents.TouchUpInside)
//removed some styling code here
view.addSubview(loginButton)
}
}
The issue is you declare your email variable on the top
private var email: TextField!
And then you also declare the email inside the function prepareEmail() again
let email : TextField = TextField(frame: 100, 100, 200, 45))
But your private var email: TextField! never gets instantiated
In order to fix your issue, remove the let when you instantiate the variable inside your prepareEmail()