I'm implementing a scrollable time selector into my mobile web application. It all works as intended, except that when I start scrolling one of the columns and then immediately start scrolling the other column, the initial column instantly stops scrolling.
This can make it unclear to the user which value is actually selected.
UI working as intended
UI after starting new scroll before previous scroll has completed
Each scrollable column is set up as follows:
<div style="overflow: scroll; scroll-snap-align: y mandatory;">
<p></p> <!-- Buffer -->
<p></p> <!-- Buffer -->
<p style="scroll-snap-align: center;">0h</p>
<p style="scroll-snap-align: center;">1h</p>
<p style="scroll-snap-align: center;">2h</p>
<p style="scroll-snap-align: center;">3h</p>
<p style="scroll-snap-align: center;">4h</p>
...
<p></p> <!-- Buffer -->
<p></p> <!-- Buffer -->
</div>
The scroll-snap-align: y mandatory and scroll-snap-align: center make the elements naturally rest vertically centered, however triggering a touchstart or touchmove event mid-scroll appears to bypass this rule.
Ideally, I would want the scroll to continue in the initial column until it either:
completes scrolling organically, or
is directly interrupted by a touch event made on itself (not just any touch event made on the window)
I have tried disabling the touchstart and touchmove event on all other elements while the time selector is active.
element.addEventListener("touchstart", (e) => {
e.preventDefault();
}, {passive: false});
element.addEventListener("touchmove", (e) => {
e.preventDefault();
}, {passive: false});
This works (the scroll is no longer interrupted when I swipe the screen over the disabled elements) but I can't disable the touchstart or touchmove event on the second column, because that also disables the ability to scroll that column.
I have tried setting e.stopPropagation() and e.stopImmediatePropagation() on the event listeners, however these had no effect.
I have also tried adding the following properties to the column <div> element
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
These also had no effect.
Related
I am building a cordova application.
I have a page with multiple Navigation buttons on it (16). The nav buttons get wrapped to 2 buttons per line. This causes the page to be scrollable.
I have an issue where when I scroll the page with my finger, the button I am not fires. I don't want any event firing my navigation code when I "scroll" the page.
I have tried touchstart, touchend and tap. From teh docs tap seems to be what I am looking for, and it does seem to handle the scroll better, but the button stays hi-lited. It never fires my navigation code.
Markup:
<div data-role="navbar">
<ul>
<li><a href="#">
<div id="wineButton">
<img src="images/images/categories/wine.png" style="width: 45px; height: 45px;" /><br />
Wine Tasting
</div>
</a></li>
</ul>
</div>
JS Code
document.getElementById('wineButton').addEventListener('tap', function () {
currentCategory = "Wine Tasting"
do_nav();
}, false);
I ended up writing my own code to check screen tap locations on touch start and touch end, and to determine if it was a tap or a move.
Consider the following example, as demonstrated here: http://jsfiddle.net/Up38n/
<div contenteditable="true" style="background-color: #ccf;">
<p>This div is editable.</p>
</div>
<div style="background-color: #ccf; width: 2000px;">
<p>This is a wide div that causes scrollbars.</p>
</div>
Click to edit the first paragraph, and then hold down the right arrow key. Initially the text cursor will move to the right as expected. However, when the text cursor hits the end of the paragraph, the whole page will scroll to the right and you will no longer be able to see what you're editing.
Is there a way to prevent this behavior so that the arrow keys don't scroll the page while editing a div?
You can temporarily disable the scroll for the document:
$(document).on('scroll touchmove mousewheel', function(e){
e.preventDefault();
e.stopPropagation();
return false;
});
And when done, enable it again:
$(document).unbind('scroll touchmove mousewheel');
fiddle: http://jsfiddle.net/Xc3ud/4/
in Chrome, when the size of the content box changes via script, it calls a scroll event and gets rid of my scroll helper div.
in IE9, it does not fire this scroll event, so the scroll helper div is stuck on the page and won't go away because the page isn't scrolled, but it won't be able to trigger scroll now because content has changes
how can I trigger the update in IE9?
I'm using Durandal so this is a SPA
html:
<div class="page">
<div class="scrollerfade" style="display:none;">This div shows up when you are scrolled down, and should disappear when you scroll back to top<br/>click the green content box to toggle its height (no longer needs scrolling)</div>
<div class="content">scroll down to see the red box</div>
</div>
js:
var $fade = $('.scrollerfade');
$(window).on('scroll', function () {
$fade.toggle(($(window).scrollTop() > 0));
});
$('.content').on('click',function(){
$(this).height(($(this).height()>200)?200:2000);
});
had to solve this with a Durandal event
if anyone has a resolution that DOES NOT use a Durandal event that would be a better answer I think, and would work even if you weren't using Durandal
//fix for IE9, because the final scroll event is not fired when the page size changes
_i.router.on('router:navigation:composition-complete').then(function (instance, instruction, router) {
$fade.toggle((_i.$(window).scrollTop() > 0));
});
I have a jquery ui draggable div, and the HTML contents do not behave normally because of the draggable.
<div id="popup"> <!-- this popup is draggable -->
This text is not selectable. When I try to select it, the popup div is dragged.
<div style="overflow:auto; height:50px">
Lots of text here, vertical scrollbar appears. But clicking the scrollbars don't work (doesn't scroll the content). Each click (mousedown-mouseup) is considered "dragging".
</div>
</div>
How do I prevent the draggable ui to override the normal browser behavior for HTML elements?
You can disable dragging from the inner <div> like this:
$("#popup div").bind('mousedown mouseup', function(e) {
e.stopPropagation();
});
event.stopPrpagation() stops a click on that inner <div> from bubbling up to the outer <div> that has the drag events bound to it. Since the event will never get there, those drag event handlers won't interfere. You can run this code before or after creating the draggable, it'll work either way.
Try add your div unselectable attribute=off:
<div id="popup" unselectable="off">
...
and css:
[unselectable=off] {
-moz-user-select : all;
-khtml-user-select : all;
user-select : all;
}
I'm not tested in jQuerry.UI, but this is my workaround in extJs and Dojo...
Is there an alternative method or a trick to the hover method which can trigger a function when the cursor moves from one div to another as the user scrolls the page.
I have sort of got it working using some javascript (jQuery) on the hover event of the current post div. However, I've noticed the hover event only triggers when the mouse is actually moved. If the page is scrolled using the keyboard (page) up/down it does not trigger.
(I can note that soup.io for instance has found a way to get this working, but I can't find how they do it)
Unfortunately, it's quite complicated; you can no longer rely on the onMouseOver event - the only event that triggers when a page is scrolled is onScroll. The steps involved:
Go through elements, storing each of their widths, heights and offsets (distance from left/top of screen) in an array.
When the onScroll event is triggered check the last known position of the cursor against all chosen elements (go through the array) - if the cursor resides over one of the elements then call the handler.
Quick (unreliable) prototype: http://pastie.org/507589
Do you have a sample? I'm guessing that the layout of the elements on the page are blocking the mouseover event. My simple example below works as you described it should. With the cursor at the top of the page and using keyboard navigation, the mouseover events are fired.
<html>
<body>
<script>
function log(text)
{
document.getElementById('logger').value += text + "\n";
}
</script>
<div id="div1" style="background: yellow; height: 100px;margin-top: 100px" onmouseover="log('mouseover div1');">
div1
</div>
<textarea id="logger" cols="60" rows="12" style="float:right;"></textarea>
<div id="div2" style="background: red; height: 1000px" onmouseover="log('mouseover div2');">
div2
</div>
</body>
</html>
You're looking for the mousewheel event.
document.getElementById('myDiv').onmousewheel = function() {
alert('You win!');
alert('Seriously! It's just like that');
};
I only tested this in Chrome (webkit)