How to avoid the unsaved form warning in Safari - javascript

Safari has a feature to prompt you if you're sure you want to close/refresh the page on which there are some forms which you typed into. This is useful in most cases, but in this case it's bugging me.
I'm hijacking the "submit" event on some forms and sending them to the server via XMLHttpRequest. However, Safari doesn't know that, so when I want to close the tab it displays that damn warning that form values have changed.
I know how to turn it off in OS X and I don't want that. I want to turn it off on this specific web page I'm building, and for all users with Safari. Surely there must be some JavaScript way—I don't care if it's proprietary to webkit.
Update: I tried this, but to no effect. Safari first warns about unsaved data, then triggers the "beforeunload" event.
if (Prototype.Browser.WebKit)
window.addEventListener('beforeunload', function(e) {
forms.invoke('reset')
})

I don't know Safari that deeply, but if you just submit the values and don't need them afterwards, why not simply reset the form? I would expect no change = no warning.
If you don't want to reset it straight away, you could even try hooking the reset command to the unbeforeunloadevent to do it when you close the page. Whether that works depends on when Safari checks for the changed form, though - before or after calling unload.

That's application behavior, so there mustn't really be any JavaScript way of modifying it. Every WebKit specific feature is documented pretty well, and I've never seen anything of the sort. Just clear your form fields if you're really that worried about it.
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/Introduction/Introduction.html#//apple_ref/doc/uid/TP40002079-SW1
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariHTMLRef/Introduction.html#//apple_ref/doc/uid/30001261

The only way I see left around this is having a form consisiting of hidden inputs only, and a bunch of input elements that are not associated with the form. On submit, you fetch the values from the the elements, make your request and reset the internal form. You could even do the moving of the input elements out of the form via DOM so it would even degrade gracefully.
A lot of work and a bit hacky, but as far as I can see the only option if you can't change the workflow.

Try removing the action and method attributes from your form tag with Javascript after you bind submit. This way, Safari should no longer see the inputs as being part of a real form.

Related

Selenium click event does not trigger angularjs event

I have this page where an angularjs modal-content popup, in there i fill up some fields and click save. After save is initiated, popup should dissapear an event should happen and so on.
My selenium test does all that perfectly except that when it clicks on the save button, popup dissapears but no event is triggered or saved so when i open up the window again everything is empty. I've tried stuff that i know with selenium and it still doesn't work. Can anyone help me out here?
This is the save button:
<button class="save-button" data-ng-click="onSettingsSave()" ng-hide="readOnlyMode || !canSave()">Save</button>
Stuff i've tried:
var saveButton = driver.FindElement(By.CssSelector("button.save-button"));
saveButton.Click();
var saveButton = driver.FindElement(By.XPath(saveXpath));
saveButton.SendKeys(Keys.Enter);
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].focus();",saveButton);
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click();",saveButton );
Try force clicking the element using pure JS:
driver.execute_script("arguments[0].click();", yourElement)
You can't use $ as a shortcut for document.querySelector in a script like that.
driver.ExecuteScript("document.querySelector('#base_element_id div input').click()");
Also this probably won't trigger an onClick in react / angular
Like the OP I have tried everything I can think of to get Selenium to trigger client side javascript events. I've seen some posts across the web of people having partial success where it randomly works; in my case it never works.
Selenium does successfully trigger the browsers primary click action, be it checking a checkbox or pressing a button, but it does not trigger any attached client side javascript events.
Both the native element.Click() method in selenium, and the abstracted ExecuteScript with arguments method of clicking as suggested by #csaladenes have the same result.
The only solution I have found so far is to use pure JS through that same ExecuteScript method; basically avoid the overload with params selenium can embed.
driver.ExecuteScript("$('#base_element_id div input').click()");
In my case I am using the JQuery that is already on my page to make locating the element easier, but any form of truly pure JS should do the same thing.
EDIT:
After some additional testing, it turns out that my "fix" really did nothing. However, performing the same click more than once did cause the client side events to fire.
In my case I am checking a checkbox, so I needed to perform the click 3 times to leave it in the correct state and still have the client side events run.
This is very odd, and definitely needs some more work to figure out where the issue is at that makes this necessary.
Edit 2:
I think I have finally found a solution, and at least partial answer, that does not make me cringe.
It seems as though Selenium has an issue where sometimes it "loses" the focus of the browser. Considering how consistent and repeatable my issue is I don't think focus is the only problem in my case, however the solution works pretty well.
I was able to get the immediate parent of my checkbox, which was a div element, click that first to return focus to the page, then click the checkbox. After that sequence of events the client side events worked correctly.

Is there a way to become aware of an input being autofilled as a result of the built in "remember password" browser functionality?

Browsers like Firefox or Chrome offer to remember the password when you login for the first time on a page; this functionality autofills the corresponding user/password combination in the login form the next time the user visits said page.
My question is, is there any way to become aware that the browser has autofilled these fields? the event change does not fire; in fact, according to monitorEvents nothing fires. I've resorted to use an interval that periodically checks whether the fields are empty or not, but is there a better way?
I am quite sure Chrome does fire the change event. I have experienced it recently (by accident). It is also already documented in Chromium Issue 135307.
Not sure about other browsers, but if you are write a periodic check will probably be the only solution. This code seems solid.

Form input history select event

I've been struggling to deal with a few forms that have users entering in a lot of repeat data. In these cases it helps users to have access to form history (ie. to select the name of a person they've sent multiple notices to, etc. The issue here is that in most browsers there is no event fired with a user selects a chunk of text from their form history. So with the help of a few other posts on stackoverflow I decided to use setInterval instead.
What I'm looking for now is feedback to spot anything that might be a bad idea and anything to make this better.
I have a demo of it here http://lab.atworkinthecloud.com/form-history-select/
I believe you shouldn't base your implementation on the behavior of the browser (remembering the history), which might or might not be available to the user.
If you want to design a useful interface, you should provide the access to the history yourself, or use features like autocomlete
since you trigger the handler so frequently , (and I noticed that you also bind the propterychange event), then why don't just bind the propertychange only, that will do it as well.
you don't need to bind all those events at all.
I met the same problem, but I still prefer to have a way that only trigger the hanlder after the user finished typing.

Pressing Escape under Firefox kills my Ajax requests. I'd like to prevent this

I'm developing a web application which requires long-running Ajax requests. Unfortunately, under Firefox, pressing Escape during a request has the drawback of killing the request and any information it was holding. This is rather annoying, as this can lead to all sorts of nasty complications if this happens at the wrong time. Therefore, I would like to deactivate this feature.
My first reflex was to intercept keypresses at the boundaries of <body>, to ensure that they would not reach the window. For this purpose, I installed a [keypress] event handler, just for events whose [keyChar] is 27, and had it invoke [stopPropagation] and [preventDefault]. And for a time, it looked like this was working.
Then, I realized that it wouldn't work when the user hadn't clicked anywhere on the window, as <body> event handlers never received the event. I tried to attach my handler to <document> or <window> to no avail, so I eventually ended up adding a [load] event handler and had it force focus to <body>. And for a time, it looked like this was working.
Then, I realized that when the user was editing an <input>, for some reason, once again, the <body>, <document> or <window> event handler never seem to receive the event. So, I added yet another [keypress] handler, intercepting with [preventDefault] on the <input> when the [keyChar] is 27.
For the moment, it looks like it's working. However, with the history of this bug in my application, I'm a tad pessimistic.
So, I'm wondering if there's a better -- and reproducible -- method. Recall that the bug seems to appear only in Firefox, so I'm quite willing to take a Firefox-only approach here.
I'd be worried about other nasty complications that will happen when the users choose a bookmark or otherwise navigate away in the middle of the request. You might want to look at why you're using long running requests and see if that's something you can change...
If it isn't something you can change (or even if you can) you should look at why your requests aren't fault tolerant. Is there a way to put the communication into transactions, and roll the latest one back if the connection is interrupted?
I know this is kind of an old thread but there's an active bug logged against Mozilla regarding this issue (which I'm also facing). See https://bugzilla.mozilla.org/show_bug.cgi?id=614304 for more info.
One suggestion from this bug is to intercept and prevent the ESC key press at the window level (as also mentioned by OP):
window.addEventListener('keydown', function(e) {(e.keyCode == 27 && e.preventDefault())});
This might have unwanted side-effects though.

How to disable firefox's form auto completion without change events?

So firefox has a nifty mechanism which will try to autocomplete values in fields when a page is reloaded or the back button is used. Which is great and all except when you have something like a drop-down which when set to a value modifies the page using ajax.
What winds up happening is that the browser reloads the page, the drop down is pre-filled with the remembered value, and then no change event is fired when the dom is ready. And therefore the change handlers attached don't fire and thus the page does not update.
Is there a good way to "fix" this behavior so that it works for the user as expected:
a) We do want the browser to auto-complete because that is a good user experience.
b) Still want that onchange event firing.
The only thing I can think of doing at the moment is to add an on-ready event to the document which has javascript pre-populated with initial values in the form, when the document loads the javascript will check the pre-populated values and if not matching what is in the input will trigger the change handlers.
Anyone have a better solution? Is there a lib that does this already?
(Using Rails 2.3.5 + jQuery)
Unfortunately there appears to be no way of actually disabling firefox from auto-filling fields when reloading a page or using the back-forward button. Fortunately the values are already there during $(document).ready() event so as long as everything in those inputs can have the .change even initially fired on them, it don't matter where the values came from and it just works.
I think you can add autocomplete="off" to prevent the browser from prefilling those fields.
You can also have a function that runs onload and basically checks to see if the value of the field matches what was specified in the value="" parameter.

Categories