Have stumbled upon what seems to be a bug with how mobile safari renders the cursor when a window.scrollTo() is executed while a user is entering text into a textarea. Have attached source code which illustrates the issue. I'm wondering if anyone has any advice on how I might work around this.
The issue: If a user is entering text into a textarea and a window.scrollTo() is executed, the cursor remains rendered at the position the textarea used to be, not at it's current position.
To recreate: Load the following web page using mobile safari. Touch the textarea, which will open the keyboard. Type a couple of characters and wait. As text is added dynamically to the page, and the window scrolled, you'll see the cursor artifact
Have tried setting the focus() back to the textarea after the scroll, but that doesn't seem to have any effect.
Thanks!
<html>
<head>
<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;" />
<style type="text/css" media="screen">
textarea {
margin-top:50px;
}
</style>
<script type="text/javascript" charset="utf-8">
window.addEventListener('load', function() {
setTimeout(addContent,5000);
}, false);
function addContent() {
var elem = document.createElement('p');
elem.appendChild(document.createTextNode('Some new text'))
document.getElementById('newContentContainer').appendChild(elem);
window.scrollTo(0,20);
setTimeout(addContent,5000);
}
</script>
</head>
<body>
<div id="newContentContainer"></div>
<div>
<textarea></textarea>
</div>
</body>
</html>
Here's a photo which shows the problem:
I'm pretty sure this may solve the problem, and most likely will also make the on-screen keyboard flash off and back on for a tiny bit too. Call this code after you use scrollTo():
yourTextArea.blur();
yourTextArea.focus();
Related
I'm looking for a way to run some JS when a textarea gets resized.
After an hour of searching and fiddling I have something that kinda works, but it is not good enough.
titleTextArea.mouseup(function() {
popup.update(); titleTextArea.focus();
});
The problem with the above code is that it also runs when clicking in the textarea. The code I am running causes the textarea to get re-rendered, which should not happen while someone is working in it, as it messes with the focus.
I've tried using jQuery resizable as per this SO post. For some reason the resize event does not fire. And really I'd prefer not needing to pull in jQuery UI for this.
Is there a way to run code on textbox resize (only on completion of resize is fine) that does not get triggered by a bunch of different actions as well?
(PS: why is there no vanilla event for this?!)
A simple solution can be just adding a check for width/height, not a perfect solution though:
var ta = document.getElementById("text-area");
var width = ta.clientWidth, height = ta.clientHeight
document.getElementById("text-area").addEventListener("mouseup", function(){
if(ta.clientWidth != width || ta.clientHeight != height){
//do Something
console.log('resized');
}
width = ta.clientWidth;
height = ta.clientHeight;
});
<textarea id="text-area" rows="4" cols="50"></textarea>
Please try this.
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery-ui.css"
type="text/css" media="all">
</head>
<body>
<textarea></textarea>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script type="text/javascript">
$("textarea").resizable({
resize: function() {
alert("xxx");
}
});
</script>
</body>
</html>
Chrome v75 appears to have introduced a bug whereby if you replace an iFrame's src programatically, it will replace the entire page instead of the iFrame.
This didn't happen on v74 and I can't get a test case to work (yet), it just fails in our site. (The site hasn't changed since going from v74 to v75, only Chrome has changed)
It appears to work fine the first time but then when you change it again (in our case viewing report drill downs) it causes the entire page (i.e. the iFrame's Parent) to load the src you were trying to load into the iFrame.
It also doesn't matter if you use pure Javascript or (in our case) JQuery, both cause the same issue.
EDIT: After a few hours detective work, I've found the bug. Setting the tag in the iFrame's content causes Chrome to load the iFrame's content into it's parent rather than the iFrame itself.
I've setup a Plunker account with a demo: https://plnkr.co/edit/UQ0gBY?plnkr=legacy&p=info
Just so I can post the link to Plunker, here is the code for the main file & the iframe content
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function onLoaded() {
// find element
let button = document.getElementById("button");
button.addEventListener("click",function(e){
// Add a random number on the end as a cache buster
document.getElementById('frame-finance-custom').src = 'test2.html?rnd=' + Math.random();
},false);
};
document.addEventListener('DOMContentLoaded', onLoaded, false);
</script>
</head>
<body>
<div>IFrame Src Changing Test</div>
<div>
<div id="div-frame-finance-custom" style="float:left;width:33%">
<iframe id="frame-finance-custom" name="frame-finance-custom" class="iframe"
style="border:1px solid black; width: 100%; height: 350px; overflow-y: scroll; vertical-align: top;">
no data
</iframe>
</div>
<div style="float:left;margin-left:1em;">
Detail: Loading an iframe page with a <Base> tag in it with target set to "_parent" will cause any refresh of that frame to replace the parent document<BR>
<BR>Instruction: <UL><LI>Click the 'Update Frame' Button, this will load test2.html into the frame. <LI>Click it again & it will replace the iframe's parent with the content of the iFrame.</UL>
<BR>Confirmation: Remove the <Base> tag from the header of test2.html & reload, it will work as expected.
</div>
</div>
<br clear=both>
<div>
<button id="button">
Update Frame
</button>
</div>
</body>
</html>
IFrame Content (test2.html):
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_parent"/>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>This is the frame content</div>
</body>
</html>
Note, using their new layout it doesn't work, but using their legacy layout it does. Feel free to save the files locally and use chrome directly too.
Ok, so this turned out to be a bug in Chrome rather than anything else, so yes, strictly not a SO question, but seeing as SO ranks so well in Google (other search engines are available), I thought it better to leave it here as a solution rather than simply delete it, just incase anyone else has a similar problem.
The reason is outlined as an edit in my question, the solution is to remove the <base target="_parent"> tag from the iFrame and programatically add the 'target="_parent"' attribute to any links in the iFrame.
We do this via jQuery, I'm sure its just as easy via vanilla Javascript.
$('a').attr('target','_parent');
Add that to the javascript that runs when a page has loaded and it'll replace add target="_parent" to any links on the page.
e.g.
<script>
function onLoaded() {
// find all links and add the target attribute
$('a').attr('target','_parent');
};
document.addEventListener('DOMContentLoaded', onLoaded, false);
</script>
As #Kaiido says in his comment, its apparently fixed in Chrome v77, but this isn't the current (as of June 2019) stable release, so we've had to add the workaround into production so that our CRM works with Chrome v75. Thanks to #Kaiido for confirming that.
I using Benalman JS to control the back button window redirect url to home.
I tested in normal browser and Android phone, it work accordingly.
But it does not work in Ipad,
here is a part of the code.
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="jquery.min.js"></script>
<script src="jquery.ba-hashchange.min.js"></script>
<script>
// control back button
// includes in js mean contains
if(!window.location.href.includes('#state')){
history.pushState(null ,document.title, '#state'); // forwards
}
// Bind an event handler.
jQuery(window).bind('hashchange', function(e) {
window.location = _contextPath + "/home/";
});
</script>
</html>
I notice that in Ipad the url will not append the "#state".
I suspect history.pushState not work in Ipad.
How can I fix this?
Thank you
The problem fixed after I change
includes
To
indexOf
Nothing to do with Benalman Js library. This js can excluded.
Thank you.
This is potentially a somewhat oddly specific question.
The situation:
I have a page with a position:fixed modal dialog (actually several, but that's irrelevant to the problem, as far as I've been able to determine). The modal opens when clicking a certain link. A script listens for hashchange events in order to close the modal when the user hits the back button.
The expected behaviour is that when back:ing out of the dialog, the page returns to the scroll position where it was before opening the modal. This happens in nearly every modern browser I've tested (desktop FF, Chrome, IE9/10/11 and Safari, and Chrome for Android).
On iPhone/mobile Safari, the page instead scrolls back to the top.
Test code
This is as reduced as I've been able to make it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html, charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Modal test</title>
</head>
<body>
<h1>Header</h1>
<p>Enough<br>content<br>to<br>cause<br>some<br>scrolling</p>
<br><br><br><br><br><br><br>
<br><br><br><br><br><br><br>
<br><br><br><br><br><br><br>
<h1>Header</h1>
<p>Open popup</p>
<p>Enough<br>content<br>to<br>cause<br>some<br>scrolling<br>
<br><br><br><br><br><br>
<br><br><br><br><br><br>
<br><br><br><br><br><br>
<div id="#popup" style="background:#fff; width:300px; height:100px; border:2px solid #000; position:fixed; top:50px; left:50px; display:none">
Modal dialog.<br>
Hitting 'back' should close this modal.<br><br>
Close modal
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">
(function($){
$(document).ready(function(){
$('.js-close-popup').click(function(ev){
window.history.back();
return false;
});
$('.js-open-popup').click(function(ev){
$('#\\#popup').fadeIn(400);
});
});
$(window).on('hashchange', function(){
hash = window.location.hash.replace('#','');
if(hash == '' || hash.lastIndexOf('#', 0) !== 0){
$('#\\#popup').fadeOut(400);
}
});
})(jQuery);
</script>
</body>
</html>
What I want to do is kill the scroll-to-top on iPhones, if at all possible without changing too much of the back-button logic for the popups (or breaking something in any other browsers).
I've searched SO for X number of hours but haven't been able to find a mention of this particular problem, or indeed a solution that works. Feel free to slap me on the fingers and point me in the right direction if I've missed an existing thread that answers my question.
EDIT: To clarify, opening the popup works as expected and does not cause any "auto-scroll".
This is definitely related to having "#" for "a href" value in your code. Also, I see a "##" in your code for a name of the ID, which i believe the reason for this. Try using some other name convention. When you are writing ID's, you don't need to give "#" in the HTML code. Try working on these lines, it might work for you.
Thanks!!
In FireFox, using JavaScript, when a user presses enter to select "ok" on an alert Window the onkeyup get fired. In Internet Explore this does not happen.
This HTML code demonstrates what I'm saying. Open it, type a character in the text field and select "ok" by pressing enter. Try it in FireFox and IE.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JS example</title>
<script type="text/javascript">
function popup()
{
alert("bam")
}
</script>
</head>
<body>
<form>
Each inputted character causes an alert window:<input type="text" onkeyup="popup()" />
</form>
</body>
</html>
Is this as designed or is this a problem? How do you prevent FireFox from firing again?
EDIT: I found it on bugzilla, does bugzilla have a "vote-up" or equivalent feature? This through me astray when trying to trouble shoot and I was looking for infinite loop/recursion in the function that was being called.
This is because Firefox destroys its alerts much more quickly than other browsers, and it's possible for the focus to return to your field while the Enter key is still down. It's possible to reproduce this in other browsers by holding the Enter key down a bit longer.