jEditable submit onBlur fails with ALT+TAB - javascript

I have jEditable working fine with a textarea to edit the content inside an object. I'm submitting onBlur using jEditable's onblur option directly to a function (instead of an url) and all works as expected UNLESS you change windows using for e.g. alt+tab. When I use alt+tab it looks like the content is submitted through an actual http request ignoring my callback function.
My very basic sample implementation looks like this:
$(".editable").editable(function(content,settings){
content = content.replace(/\n/gi,"<br />");
return content;
},{
data: function(value, settings) {
return value.replace(/<br[\s\/]?>/gi, '\n');
},
type: "textarea",
onblur: "submit"
});​
You can test it here: http://jsfiddle.net/xmajox/wePp5/
I've tried all other window operations: resize, move, etc and even moving between tabs on the browser works great (submits the data and exits the edit mode).
Any ideas of how this might be tamed?
UPDATE:
After a few more tests and some colaboration from other people, it seems that this depends on the os (window manager?). It happens consistently on ubuntu 12.10 with unity but doesn't happen on mac or windows (haven't tested other linux boxes).
Also, it is now proved that my callback method does run when I use alt-tab but the form gets POST'd anyway afterwards. Adding a live preventDefault didn't seem to help.

Found the fix for this, but coulnd't quite understand why it happens on such a specific situation.
First of, I must be the (un)luckiest guy in the world because I've tried this on 10ths of other combinations and it didn't have this problem, only place I could get it to happen was:
Ubuntu 12.10 (with Unity) and Chrome (v22 at the time of this post)
Disclaimer: This doesn't mean it does not happen on other places, I just couldn't reproduce it on the ones I tested (or asked friends to test).
Problem:
When focus is lost, jEditable - as of version 1.7.1 - sets a timeout before actually executing any action (200ms by default) to prevent duplicate actions according to the comments in the source. If you (using the above browser/os combination) alt+tab out of the browser window before the timeout is fired (aka. before the data is submitted and your method is ran) it will force a POST request with the data, completely ignoring the preventDefaults or return falses. It won't have this problem if you press alt... keep it pressed (more than those 200ms, i.e. enough time for the timeout to be fired) and then press alt to move away.
Solution:
I edited jEditable's source to reduce the timeout (or even remove it). So I around line 280, where it says:
(...)
input.blur(function(e) {
// prevent double submit if submit was clicked
t = setTimeout(function() {
form.submit();
}, 200);
});
(...)
I changed it to:
(...)
input.blur(function(e) {
form.submit();
});
(...)
Notes:
I removed this because on my situation (submitting textareas ONLY on blur and without any other controls that allow the user to submit the data) I coulnd't reproduce the double submit issue that Mika Tuupola was mentioning on the comments. If you have text input fields (that are submitted pressing enter) with the submit onBlur active, you might fall into that situation. On those cases I suggest you just reduce the timeout or simply avoid to use onBlur submits.

Related

Client side form validation for Copy/Pastes via Right-Click

I'm using the following line (Struts1 syntax) to display a text field and allow some client side checks via Javascript.
<html:text styleId="myField" property="myProperty" onkeyup="function()" />
My intention is for a message to appear and a dropdown to disable whenever there is text entered into the form field (regardless of content). The onkeyup attribute works fine for all cases except for when the user pastes in text using mouse right-click.
It doesn't appear that onmousedown and onmouseup events notice right clicks. The same goes for onfocus.
onchange only makes the check when focus is lost, however the user can circumvent this by pasting data and clicking the form submit (same for onblur).
onmouseout somewhat works (I can break functionality) in IE8, but doesn't work at all in Chrome v41.0.2272.89
Has anyone encountered client-side form checks on Mouse-Right Click? I'd like to cover this use case across browsers and cannot count on the end user to always paste via keyboard shortcuts.
I went with a jQuery solution as suggested by Aleksandr M above in comments.
Initially I had this function:
$(document).ready(function(){
$('#myField').bind("paste",function(e) {
toggleFunction(); //preserve already existing function in use with other cases
});
});
But then came to find that while the function would run following the user's paste, it would run prior to the text actually being pasted.
Example:
User pastes (Right-click > paste OR Ctrl+V);
Function is called and executes, condition checks made
Text is pasted.
So instead I replaced the function call in the jQuery with my intended end result, making some additional changes elsewhere so that my assumptions are met.
But those conditions aside, the below ends up doing what I needed.
$(document).ready(function(){
$('#myField').bind("paste",function(e) {
document.getElementById("dropdownID").disabled = true;
document.getElementById("showMessage").style.visibility = "visible";
});
});

Postback not triggered after javascript on change event

In my asp.NET application I have implemented a control to validate forms input data using server side logic.
The idea is to drag the control to wherever it's needed, set it up in the code behind and the form will be validated.
This validation occurs on the onchange event of each field and on form submission - synchronous ajax call to the server side.
This was working fine until I published it to IIS.
The problem is the following: the user is writing something in a textbox. Then, with the focus on that textbox, clicks on a button or linkbutton, not related to the form being validated.
The validation ajax call occurs (jQuery onchange fires) and the button postback is not reached. Through debugging I found the problem to be the ajax call is somehow preventing the postback to fire (almost feels like a synchronism problem).
I reduced the problem to the point that an alert seems to be causing the same thing as the ajax call. Please have a look at the following project: EDIT: Link removed because I can't post more than 2 links on the same post - sorry!
Consider the first 2 textboxes and the button:
1) If you write something on the first, then click the button: the onchange fires, an alert is shown and the postback does not occurr.
2) If you write something on the second, then click the button: the onchange fires and the postback occurrs.
Can someone please explain why this behavior happens and if there's any solution to this, ie, make the postback fire after the javascript finishes running?
I can think of 2 ways to solve my problem but I need to know (inside the textbox change event) the ID of the control clicked by the user. Any way of getting it?
That way I could: trigger the control explicitly OR verifiy if it doesn't belong to the form controls and don't event validate the input in that moment (that would make sense).
Thanks in advance.
EDITED 22-10-2014:
The plot thickens. This seems to be a synchronism problem. Check this other test application where I removed the alerts (this concentrated too much attention and is not actually related to the issue as I'm not using alert boxes in my project - I'm using little balloons) and just left the AJAX call.
Now, on the server side (WebMethod) I put a Thread.Sleep(). If the thread sleeps for too long, it seems to miss the postback. In my case, on my development environment, the threshold seems to be 80ms. If the ajax call takes less than ~80ms, then the postback is done, if it takes more than that, it misses the postback. Any ideas or similar (resolved) issues you have seen? Note that my ajax call has async: false.
EDITED 24-10-2014:
Finally had another look into this. I think I may have come to a possible solution, although I don't like the idea of relying on a setTimeout to handle the submit button 'click' before the 'focusin' (same control).
I changed the logic (still achieving the same goal) and now use different events.
Now I need to distinguish when the submit control fires the 'focusin' event because it just gained focus (1) or it was clicked (2):
The user could just be tabbing (validates the last field that had focus - if it belongs to the form being validated)
The user could have clicked (does not validate the last field that had the focus, but the whole form and then submits or not)
Have a look at this new test app which is closer to what I have in my project.
Can you help me finding a better way to handle/process the click event before the focusin event on the same control without something unpredictable like a setTimeout? If I do need to rely on the setTimeout, how much do you think the wait should be set to? On my machine 150ms works, but on another persons, it may require more time? Something like some sort of callback would be ideal.
Thanks again
Use __doPostBack('',''); at end of your javascript function
It does appear that an alert box stops postback in this situation. The sensible solution I found was to use a jQuery dialog which doesn't seem to suppress a postback. Problem is of course the dialog doesn't persist itself through the postback but this is solved by a hidden field containing a 'flag' to display the dialog after postback or not.
You will need to add jquery-ui.js and some style for the dialog, if this is a serious application I suggest you download both files and put them in scripts folder as you already have with the jquery min.
<head runat="server">
<title>Postback with dialog</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#TextBox1").on('change', function(e) {
$("#doDisplayDialog").val("yes"); // Add a flag so it shows after postback.
$('#jqAlert').dialog({
closeOnEscape: true,
open: function(event, ui) {
$(this).parent().appendTo("form");
}
});
});
if ($("#doDisplayDialog").val() == "yes") {
$('#jqAlert').dialog({
closeOnEscape: true,
open: function(event, ui) {
$(this).parent().appendTo("form");
}
});
$("#doDisplayDialog").val("no"); // Clear the flag so it doesn't display after postback.
}
});
</script>
</head>
Add a hidden field:
<asp:HiddenField ID="doDisplayDialog" runat="server" />
And a Div to be the dialog box:
<div id="jqAlert" title="Alert" style="display: none;">
<p>Postback will happen!</p>
</div>
Code is based on your downloadable test website application.
-- not a working solution below --
Try this - copy/paste replace these lines in your test web application:
$(document).ready(function() {
$("#TextBox1").on('change', function() {
alert('T1 Postback does not fire');
return true;
//return AjaxCall();
});
$("#TextBox2").on('change', function() {
alert('T2 Postback does not fire');
return true;
//return AjaxCall();
});
});
The only change I did was replace single quotes with double quotes in jquery selector here
$('#TextBox2')
with
$("#TextBox2")
Edit: actually it doesn't work, I had a bug in my test code. Will look more into this.

How do I prevent the Enter button from running its default behavior in Firefox 12?

I have a form built in ASP.NET. The first control allows the user to choose a person from an auto-complete list. When the user pressed enter it would refresh the page and duplicate any information acquired through this first control. I am trying to remove the capability of the enter key from refreshing the page. This code all works in Chrome and IE7/8/9 (Don't care about 6). All I NEED is the return false for it to work in all browsers we support besides Firefox. The .click() is a bonus to add a bit of usability back to the key (so that it will activate the controls and check or uncheck check boxes, etc.)
None of this works in Firefox 12. The click occurs (proof that the code is reached when I want it) but the page refreshes every single time.
The focusNextInputfield() was one of the suggestions from a similar question and didn't do anything I wanted. It may have done what it was intended for but I can't tell because the page refreshed.
I found preventDefault() and stopPropagation() from yet another similar question on my own and it did nothing in FF.
I have even tried returning true for the heck of it.
$(document).keydown(function (event) {
//handles what happens when the user hits enter
if (document.activeElement.nodeName !== 'TEXTAREA') {
if (event.keyCode === 13 || event.which === 13) {
$(document.activeElement).click();
// $(document.activeElement).focusNextInputField();
event.preventDefault();
event.stopPropagation();
return false;
}
}
});
I am just looking for any suggestions or news on any reason none of this has any effect in FireFox 12? And I know that the code is reached and it all runs properly without error and even with all the excess code it still runs properly in Chrome and IE 7/8/9 as I said.
And through an earlier iteration I tried forcing the submit button to be clicked but it still refreshed anyway and validated and was overall a bad user experience.
Looks like you are using jQuery so all you need is to preventDefault in form submit event.
$j("#form-id").submit(function(e) {
e.preventDefault();
...
});
Or:
$j("#form-id").submit(false);

Suppress Safari’s “You have entered text…” warning?

Safari helpfully (?) prompts before closing a tab or window when text has been entered into an input.
There are some cases where, as a web developer, this isn’t desirable — for example, when the input is a live search where the user has probably already gotten the results he’s looking for when the window is closed, even though there’s still text in the field.
How can I let Safari know that text in a particular input doesn’t need its protection?
It seems like you are able to disable this warning for an entire page by having an onbeforeunload handler on <body> (even an empty one will do). For example, the following will not produce the warning:
<body onbeforeunload="">
<form method="get"><input></form>
</body>
I'm not sure if this is the intended behaviour, or a bug.
I think I've got a solution to this problem, though it's unquestionably a hack (i.e. if Safari changes how this feature is implemented, it could stop working). Shown here with a touch of jQuery:
$('.unimportant').live('blur', function(){
var olddisplay = this.style.display;
this.style.display = 'none';
this.clientLeft; // layout
this.style.display = olddisplay;
});
Demo (try typing in the "unimportant" field, click somewhere else on the page, then close the window).
In short:
Hide the input
Trigger layout
Show the input
You can also change the value of the input, trigger layout, and change it back.
The one limitation here is that cleaning the input has to be done explicitly. In this case, it will be dirty until blur. This works well in my situation, and probably in many others, since the input will be protected from an accidental window close until something else on the page is manipulated (e.g. a link is clicked). You could choose to run this on keyup if you're willing to live with a flicker of the insertion point every time a key is pressed.
I'm open to cleaner solutions.
I found what I think is a pretty good solution to this problem. When I use AJAX to submit the form then I want the warning to suppress. This is accomplished with onbeforeunload.
window.onbeforeunload=function(e){}
But after I submit I might make additional changes and so I want the warning to show again. To do this I added a keyup handler to a form element.
$('txtarea').onkeyup=dirty;
What dirty does is checks is the input field has changed if it has then I set onbeforeunload to null.
function dirty(e){
if (e.srcElement.value != e.srcElement.defaultValue){
window.onbeforeunload=null;
}
}
I just found another solution to prevent Safari from displaying the "Are you sure you want to reload this page?" dialog when textareas have changed their content.
It turns out that setting the value through Javascript clears Safari's changed state:
$(document).on('blur', 'textarea', function() {
var value = $(this).val();
$(this).val('').val(value);
});
Clearing the value first is important, directly setting it to the content it already is does not work.
EDIT Apparently setting window.onbeforeunload to an empty function still works, however $(window).on('beforeunload', function() {}) does not.

Is there any way to use window.onbeforeunload on Mobile Safari for iOS devices?

Looks like Apple has disabled the window.onbeforeunload event for iOS devices (iPhone, iPad, iPod Touch). Unfortunately I can't find any documentation as to why this event doesn't work in Mobile Safari.
Does anyone know if there's a reliable alternative to this function? Android's browser appears to support it just fine, and the Safari desktop application also supports the onbeforeunload event without issue.
I see that it's an old question, but i faced this problem recently.
I'm using window.unload and it works fine in ios browsers (although if you look at Apple documentation it seems to be deprecated and they recommend to use document.pagehide)
If you really need it, you cant just get all links, forms and DOM objects that have a handler changing the url and make those wait until you've done what you want.
For the links, you get them by getElementsByTagName, check if the href starts with anything but a # and just add your onbeforeunload function add onclick (which will be invoked before the href is looked at).
Same for the forms but with onsubmit.
And finaly, for the elements changing the href with JavaScript, you should make sure when you add the lsitener that you call your onbeforeunlaod function (or, if you use DOM0 or DOM1 listeners, you can just add some class and then use a global script that checks all elements with the class and adds it to the event listener with a closure.
But you should normaly be able to avoid the use of this event (probably using cookies to store the thing you wanted to send every x seconds and allowing to, in the worst case, have a look at it next time the user loads a page and, in the best case, be able to send an Ajax request at onbeforeunload or onunload which, even if it sends only the http headers, woudl allow you to get what you want).
Based on Xavier's answer, I devised a solution along these lines:
function doStuff() {
// here goes your logic
}
function isSafariMobile() {
return navigator && /Safari/.test(navigator.userAgent) && /iPhone|iPad/.test(navigator.userAgent)
}
function addWatcherToLinks(baseNode) {
if (!baseNode || !baseNode.querySelectorAll) { return; } // ignore comments, text, etc.
for (const link of baseNode.querySelectorAll("a")) {
link.addEventListener('click', doStuff);
}
for (const form of baseNode.querySelectorAll("form")) {
form.addEventListener('submit', doStuff);
}
}
// ...when the page loads...
// we watch the page for beforeunload to call doStuff
// Since Safari mobile does not support this, we attach a listener (watcher) to each link and form and then call doStuff.
// Also, we add such a watcher to all new incoming nodes (DOMNodeInserted).
if (isSafariMobile()) {
addWatcherToLinks(document);
window.addEventListener("DOMNodeInserted", (event) => { addWatcherToLinks(event.target); }, false);
} else {
window.addEventListener('beforeunload', doStuff);
}
This solution has some limitations. The biggest one is that it attaches itself to all forms and all links. Sometimes this might not be desired. If you need it you can skip some nodes (e.g. mark them with a particular data- attribute).
I was having the same problem. it seems safari browser in iphone triggers only focus and blur events and almost every other event is not triggered, e.g.(pagehide, pageshow, visibility change) but the good news is focus and blur event are supported and triggered on iphone, ipad & android mobiles as well.
window.addEventListener('focus', function(){
// do stuff
});
window.addEventListener('blur', function(){
// do stuff
});
hope this helps anyone.

Categories