onscroll event and scrollbar buttons - javascript

Here's the simplified html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function handle() { console.log("fired"); };
</script>
</head>
<body>
<div style="width:200px; height:100px; overflow-y: scroll; border: 1px solid gray;" onscroll="handle()">
<div style="width:150px; height:400px;"> </div>
</div>
</body>
</html>
The problem is, when div is not scrolled at all (initial position) the small button with triangle symbol on top of scrollbar does not fire an event. Maybe it's logical, but I search a way to work around this behaviour, because it's the only way for now to work around dojo framework tree widget with enabled drag-n-drop. Yep, I know, workaround for workaround.

Well, it's not pretty, but this should do the trick:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function handle() { console.log("fired"); };
</script>
</head>
<body>
<div id="div" style="width:200px; height:100px; overflow-y: scroll; border: 1px solid gray;">
<div style="width:150px; height:400px;"> </div>
</div>
<script>
//Get the element
var div = document.getElementById("div");
var ignore = true;
//Set the scroll to 1 (this will allow it to scroll up)
div.scrollTop = 1;
div.addEventListener("scroll", function(){
//Ignore generating output if the code set the scroll position
if(ignore) {
ignore = !ignore;
return;
}
//CODE GOES HERE
handle();
//If the scroll is at the top, go down one so that the user
//is still allowed to scroll.
if(div.scrollTop <= 1) {
ignore = true;
div.scrollTop = 1;
}
//If the scroll is at the bottom, go up one so the user can
//still scroll down
else if(div.scrollTop >= div.scrollHeight-div.clientHeight - 1) {
ignore = true;
div.scrollTop = div.scrollHeight-div.clientHeight - 1;
}
}, true);
</script>
</body>
</html>
I removed the inline function call and replaced it with an eventListener. Basically, it makes sure the user never scrolls completely to the top or bottom, ensuring that there will always be a scroll event.

Related

To Check "user has scrolled to the bottom code" is not working on chrome but it works on Microsoft Edge. WHY?

I use this code to check whether user has scrolled to the bottom code or not but it don't work on Google Chrome but it successfully works on Microsoft Edge.
In Google Chrome when i scroll to bottom and again scroll to top then it works but I don't know why.
Here is the code i am using.
<script>
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
alert("bottom!");
}
});
</script>
<!decotype html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div style="height: 4000px">Scroll down!</div>
</body>
</html>
Assuming you use a div to load some data... (Because of #load_data)
You need to get 3 values on scroll:
The scrolled position
The div height
The div scrollable height
This last one is an element property of the real element height, including its overflow.
Additionnally, you need to define what's near the bottom... In pixels.
So... In the below example, I'm faking an Ajax request. Just look for the code you need.
$(document).ready(function() {
// Function to replace Ajax in this demo.
function createContent(n){
var fakeContent = "";
for(i=0;i<n;i++){
fakeContent += i+"<br>";
}
$("#load_data").append(fakeContent);
}
// Simulate initial content...
createContent(100);
// The code you need
var near = 20; // pixels buffer yet to be scrolled when the Ajax triggers.
$("#load_data").on("scroll",function(){
if( $(this).scrollTop() + $(this).height() + near > this.scrollHeight ){
console.log("Faking Ajax...");
createContent(50);
}
});
}); // END ready
#load_data{
height: 150px;
width: 300px;
border: 1px solid grey;
overflow-y:scroll;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
There is 100 (0-99) lines on load.<br>
<div id="load_data"></div>
The problem is when you use margin (top or bottom) you should use .outerHeight(true) instead of .height or the sum of height and margin in this case. If you have padding is the same issue.
$(window).scroll(function(){
if($(window).scrollTop()+$(window).height()>$("h3").outerHeight( true ) ){
alert("bottom!")
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<h3 style="margin-top:2000px">hello world</h3>
</body>
<html>
About .outerHeight()
Get the current computed outer height (including padding, border, and
optionally margin) for the first element in the set of matched
elements or set the outer height of every matched element
.

How to prevent text selection from obstructing onMouseMove event?

I'm implementing a "resize handle" to change the width of my left navigation panel. It is a div that receives an onMouseDown() event, calculates the necessary widths and applies them to the right elements in the subsequent calls to onMouseMove(). But I'm having some problems.
1) The article element, to the right of the navigation panel and handle, does not activate the onMouseUp() if I release the mouse there. Is this because the onMouseDown() was activated in other element?
2) If I move the mouse fast to the right, I can't prevent the text in the article from being selected, even calling methods like preventDefault() and stopPropagation().
3) Even if there's no text in the article, the resizing only works if I move the mouse very slowly. If the mouse moves fast over the article element, the resize stops, unless I release the mouse button - in this case the resize goes smoothly (suggesting it was the text-selecting that was stopping the resize, even with no text at all). But if I release the mouse button, the resize should stop (see point 1).
I've seen some solutions using CSS user-select: none, but this would prevent any text from being selected inside article, which is obviously an overkill.
So, how can I make the resizing smooth, without selecting any text, when I move the mouse over any element in my document? (After pressing the button in the right div, of course.)
That's my HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>CSS Template</title>
</head>
<body>
<header>Header</header>
<main>
<nav id='nav'>
<div class='navcont' onmousemove='handMm(event)' onmouseup='handMu(event)'>
<p>nav 1</p>
<p>nav 2</p>
</div>
<div class='handle' onmousedown='handMd(event)' onmousemove='handMm(event)' onmouseup='handMu(event)'>
</div>
</nav>
<article id='article' onmousemove='handMm(event)' onmouseup='handMu(event)'>
</article>
</main>
<footer>Footer</footer>
</body>
</html>
That's my CSS:
html, body {
height:100%;
margin:0;
}
body {
display:flex;
flex-direction:column;
}
header {
text-align:center;
}
main {
flex:1;
display:flex;
min-height:0;
}
article {
background:#CCC;
width:auto;
overflow:auto;
padding:10px;
flex-grow:1;
}
nav {
width:300px;
height:auto;
overflow: hidden;
display:flex;
}
.navcont {
background:#8C8;
width:auto;
flex-grow:1;
}
.handle {
background:#333;
right:0px;
width:30px;
cursor:col-resize;
}
footer {
text-align:center;
}
That's my Javascript:
var mx,px,moving=false;
function handMd(e) {
mx = e.pageX;
px = document.getElementById('nav').clientWidth;
moving = true;
}
function handMm(e) {
if (moving) {
e.preventDefault();
e.stopPropagation();
e.cancelBubble = true;
e.returnValue = false;
var diff = e.pageX - mx;
document.getElementById('nav').style.width = (px + diff)+'px';
document.getElementById('article').style.width = (window.innerWidth-px-diff)+'px';
}
}
function handMu(e) {
moving = false;
}
And here is a working example: https://jsfiddle.net/45h7vq7u/
Another example, including Ryan Tsui's answer: https://jsfiddle.net/v1cmk2f6/1/ (the text-selection is gone, but the div still won't move smoothly, but only when moving fast to the right).
Catch the events of start moving and finish moving with your preferred method (onMouseDown and onMouseUp are fine). Add a CSS class to specify the moving state when the action starts. Remove the CSS class when the action finishes.
In your case, you may try the followings:
Add a new CSS class:
.moving {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
Extend your handMd() and handMu() functions:
function handMd(e) {
mx = e.pageX;
px = document.getElementById('nav').clientWidth;
moving = true;
document.getElementById('article').classList.toggle('moving', true); // Add this line. 'article' is the id of the element where you don't want the selection to occur.
}
function handMu(e) {
moving = false;
document.getElementById('article').classList.toggle('moving', false); // Add this line. 'article' is the id of the element where you don't want the selection to occur.
}
After analyzing how this was solved somewhere else, I came to the following changes.
HTML - only one event handler needed:
...
<main>
<nav id='nav'>
<div class='navcont'>
<p>nav 1</p>
<p>nav 2</p>
</div>
<div class='handle' onmousedown='handMd(event)'>
</div>
</nav>
<article id='article'>
</article>
</main>
...
Javascript - attach and detach the onmousemove event handler is way better than calling onmousemove every time the mouse moves (to only then test if the mouse button has been pressed). Also, the event is now attached to the document, not to each div on screen:
var mx,px,minW = 200;
function handMd(e) {
mx = e.pageX;
px = document.getElementById('nav').clientWidth;
document.addEventListener('mousemove',handMm);
document.addEventListener('mouseup',handMu);
document.getElementById('article').classList.toggle('moving',true);
document.getElementById('nav').classList.toggle('moving',true);
}
function handMm(e) {
var diff = e.pageX - mx;
if (px+diff >= minW && window.innerWidth-px-diff >= minW) {
document.getElementById('nav').style.width = (px+diff)+'px';
document.getElementById('article').style.width = (window.innerWidth-px-diff)+'px';
}
}
function handMu(e) {
document.removeEventListener('mousemove',handMm);
document.removeEventListener('mouseup',handMu);
document.getElementById('article').classList.toggle('moving',false);
document.getElementById('nav').classList.toggle('moving',false);
}
CSS - thanks to Ryan Tsui's answer, I eliminated the unwanted text selection while resizing:
.moving {
user-select:none;
-moz-user-select:none;
-webkit-user-select:none;
-ms-user-select:none;
}
I don't know how to stop the selection but I can tell you for some help that the event triggered when something is selected is onselect.

Forcing a scroll trigger after certain points

So what I want to do is have a page that is split into 4 divs (let's say 1, 2, 3, and 4). So whenever I try to scroll down after div 1, the page would automatically scroll to div 2; if I try to scroll my mouse down below div 2, it would scroll automatically to div 3; and the same way for div 3 to div 2, etc. I'm sure you have seen something similar to this in some online pages (can't think of any right now but if I find something I will link it).
Basically what it would do is, when you scroll up from a div it would animate the transition to the top of the previous div on its own.
I tried using jQuery and doing scrollTop, but couldn't get it to work.
See this:
$('html, body').animate({scrollTop: $('#div1').offset().top},'slow');
The whole code took me a long time to make
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<script>
$(document).ready(function () {
var n=1;
var classes=$('.class').length;
$(window).bind('mousewheel', function(event) {
if (event.originalEvent.wheelDelta >= 0) {
n--;
n=n<1?1:n;
} else {
n++;
n=n>classes?classes:n;
}
//to prevent duplicate event
setTimeout(function () {
$('html,body').animate({scrollTop: $('.class[data-number='+n+']').offset().top},'fast');
},10);
});
});
</script>
<style>
html, body {
margin: 0;
height: 100%;
}
.class{
height: 100%;
}
.class:nth-child(2n){
background: red;
}
.class:nth-child(2n+1){
background: blue;
}
</style>
</head>
<body>
<div class="class" data-number="1" ></div>
<div class="class" data-number="2" ></div>
<div class="class" data-number="3" ></div>
<div class="class" data-number="4" ></div>
</body>
</html>

.animate() not working more than once

I wrote the following code that includes a "down arrow" which when pressed, is meant to scroll the page down one section at a time. It only seems to work once though - can anyone see what I've done wrong?
Note: The body height intentional and is enough to support my needs.
<STYLE>
*{margin:0;padding:0}
body{height:1000px; width:2000px; overflow:hidden;}
SECTION{border: 1px dashed black; height:100px; width:300px; overflow:auto; float:top;}
.int{position:relative; width:100px;height:100px;background:#fff; float:left;}
</STYLE>
<SECTION ID="1">1</SECTION>
<SECTION ID="2">2</SECTION>
<SECTION ID="3">3</SECTION>
<SCRIPT SRC="jquery.js"></SCRIPT>
<SCRIPT SRC="jquery.easing.1.3.min.js"></SCRIPT>
<SCRIPT>
function scroll($dir){
// This is the main scroll function
if($dir=="down")
$('html,body').stop().animate({
scrollTop: $('html,body').offset().top + $("SECTION#1").height()
}, 800, "easeInQuart");
}
// Function which controls key-based navigation
$(document).on("keydown", function(e) {
if(e.which == 40) scroll("down");
});
</SCRIPT>
$('html,body').offset().top + $("SECTION#1").height() always returns the same value. So that is why it is not working.
As a solution, try $(document).offset().top or use a counter like so:
var currentPage = 0;
function scrollDown() {
$(...).animate({scrollTop: pageHeight * (currentPage++)});
}

Once user reaches a particular point on a page, automatically scroll to particular point/achor

So, here it is:
I'll have 4 divs. Example below. Each div a particular height (around 1500px) but have a width of 100%. Each div is a different colour.
I want it so that when the user scrolls the page and reach a particular point, javascript will kick in and automatically scroll the user to the next div.
So, say the user is vertically scrolling and div #2 is appear and div #1 is disappearing. When div #1 has about 200px left, the page will automatically scroll down so that div #2 is flush with the top of the browser window.
A good example: http://thejuly16.com/ Which basically does it but can't work out how.
1
Content here
2
Content here
3
Content here
4
Content here
That page isn't doing anything for me :/
Anyway, if I get what you mean, you should have some anchors on top of every div, hook some code to the scroll event, check scrollTop() value on it, and scroll to the anchors when this value is in a desired range. You can check this fiddle and the relevant jQuery code:
$(window).bind('scroll', function(){
if (($(window).scrollTop() > 1300) && ($(window).scrollTop() < 1350)) {
window.scrollTo(0,1500);
}
});
This might be a strange behavior for the user, since scrolling up is pretty messed up. However, we can fix this by checking if the user is going up or down in the page, like in this fiddle, just checking if the last scroll position was higher or lower than the current scroll position:
var currentScroll = 0;
var previousScroll = 0;
$(window).bind('scroll', function(){
currentScroll = $(window).scrollTop();
if (($(window).scrollTop() > 1300) && ($(window).scrollTop() < 1350) && currentScroll > previousScroll) {
window.scrollTo(0,1500);
}
previousScroll = $(window).scrollTop();
});
Obviously, you'd need to add as many if statements as "jumps" you want in your page.
I have a solution as given in the code below. Somehow its not working on jsFiddle but working on my machine. Please try it in your own editor
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
var isWorking = false;
var lastScrollPosition
function adjust(oDiv) {
if(oDiv.scrollTop > lastScrollPosition && !isWorking && oDiv.scrollTop % 400 > 300) {
isWorking = true
scroll(oDiv);
} else
lastScrollPosition = oDiv.scrollTop;
}
function scroll(div) {
if(div.scrollTop % 400 > 10) {
div.scrollTop = div.scrollTop + 10;
lastScrollPosition = div.scrollTop;
setTimeout(function(){scroll(div);}, 10);
} else
isWorking = false;
}
</SCRIPT>
</HEAD>
<BODY>
<div style="height: 440px; border: solid 1px red; overflow-Y: auto" onscroll="adjust(this)">
<div style="height: 400px; border: solid 1px green"></div>
<div style="height: 400px; border: solid 1px green"></div>
<div style="height: 400px; border: solid 1px green"></div>
<div style="height: 400px; border: solid 1px green"></div>
<div style="height: 100px"></div>
</div>
</BODY>
</HTML>
I think this functionality is available with jQuery. I have tried this but I was doing this on OnClick event in Javascript. In your case, onFocus or any other suitable event like mouseover etc should work.
Hope this helps.

Categories