Is there some JavaScript code I can execute to scroll to the top of the messages box on Facebook? So when you click 'see all' and go the main message page, if you scroll up it loads more messages. I want to force the it to keep scrolling up to keep loading messages. I've tried
document.body.scrollTop = document.documentElement.scrollTop = 0;
But that of course only scrolls to the top of the actual page. Any ideas on how to scroll the messages box up?
Select a conversation and try this script (load it through the console):
var autoLoad = {
messagesContainer: document.querySelector('#contentArea [role=main] .uiScrollableAreaContent'),
start: function (speed) {
var messagesContainer = this.messagesContainer,
loadMore = document.querySelector('[role=log] .pam.uiBoxLightblue.uiMorePagerPrimary');
speed = parseInt(speed, 10) || 1000;
clearInterval(this.interval);
this.interval = setInterval(function () {
messagesContainer.style.top = '0px';
loadMore.click();
}, speed);
},
stop: function () {
clearInterval(this.interval);
this.messagesContainer.style.top = '';
}
};
To start it, type:
// Takes a 'speed' parameter, defaults to 1000 milliseconds
autoLoad.start(1200);
And to stop it (necessary for the scrollbar to re-appear):
autoLoad.stop();
Explanation:
After exploring Facebook's DOM, I found some selectors that specifically target the elements that are needed for this to work:
The messages container, which holds the messages
The 'load more' link, that triggers facebook's script in charge of loading more messages.
The messages container scrollable area doesn't use native scrolling, instead, it uses bottom and top to set it's current scroll position.
So, if you want to scroll to the top, you set the container to top: '0', and since this way, the messages auto-load AJAX only triggers once, you need to trigger it manually after every scroll to top. I managed to do this simply by executing click in the link that triggers the AJAX.
I tried to get the most specific classes/selectors that I could find, and the ones that sounded more general, since I don't know if Facebook generates ids/classes dynamically in some way.
I tested this under Firefox and Chrome, explore the code a bit and change it to fit your needs. I hope this works for you as is, otherwise, you can use the DOM explorer to find the appropriate selectors.
I had to tweak the script to use "scrollTop" instead of "style.top".
var autoLoad = {
messagesContainer: document.querySelector('#globalContainer [role=main] .uiScrollableAreaContent'),
start: function (speed) {
var messagesContainer = this.messagesContainer,
loadMore = document.querySelector('#js_d');
speed = parseInt(speed, 10) || 1000;
clearInterval(this.interval);
this.interval = setInterval(function () {
messagesContainer.scrollTop = 0;
loadMore.scrollTop = 0;
/* loadMore.click(); */
}, speed);
},
stop: function () {
clearInterval(this.interval);
this.messagesContainer.style.top = '';
}
};
Nov 2021 #user4698813 code update:
var autoLoad = {
messagesContainer: document.querySelector('[role=main]'),
start: function (speed) {
var messagesContainer = this.messagesContainer,
loadMore = document.querySelector('[data-release-focus-from]');
speed = parseInt(speed, 10) || 1000;
clearInterval(this.interval);
this.interval = setInterval(function () {
messagesContainer.scrollTop = 0;
loadMore.scrollTop = 0;
/* loadMore.click(); */
}, speed);
},
stop: function () {
clearInterval(this.interval);
this.messagesContainer.style.top = '';
}
};
Related
I want to implement scrolling event function that forwards me to certain position on page like it's done in FullPage.js.
Example: https://alvarotrigo.com/fullPage
I tried adding onscroll event listener, which distinguishes scrolling direction and then executes scrollTo() , but it seems like a bad idea.
How do i implement this properly? Thanks in advance.
What i tried so far:
function throttle(fn, delay) {
let last;
let timer;
return () => {
const now = +new Date;
if (last && now < last + delay) {
clearTimeout(timer);
timer = setTimeout(() => {
last = now;
fn();
}, delay);
} else {
last = now;
fn();
}
};
}
var scrollPos = 0;
function smooth_scroll(){
// detects new state and compares it with the new one
if ((document.body.getBoundingClientRect()).top > scrollPos)
{
window.scrollTo({ top: 0, behavior: 'smooth' })
}
else
{
window.scrollTo({ top: 1000, behavior: 'smooth' })//as an example
}
// saves the new position for iteration.
scrollPos = (document.body.getBoundingClientRect()).top;
}
window.addEventListener('scroll', throttle(smooth_scroll, 1000));
I expect it to work like this: whenever i scroll down it forwards me to bottom (1000, 0), and when i scroll up it gets me to the top. All smoothly.
If you look onto your example website you can see that they are not scrolling a list. They are animating a wrapper and its children:
class: fullpage-wrapper
attribute they change: transform:translate3d(0px, -937px, 0px);
What happens ist that all elements are inside one wrapper which is then moved upwards the height of the box. The smooth effect of this page is provided by a specific easing which can be attached to the CSS animation.
So if you want to get the same "scrolling" effect you need to think about an animation solution. Therefore you can stick to blank CSS-Animations or Framework/Library specific ones.
For further informations about animation, I can try to help you as far as it's not getting a full Animation course :)
I have a smooth scroll in vanilla js for my one page website which i try to implement without jquery, and I want to add a timing function like cubic bezier. Is there any way to do that in javascript? Here is the code:
{
'use strict';
let currentY = 0;
let destination = 0;
let speed = 40;
let scroller = null;
function smoothScroll(id) {
destination = document.getElementById(id).offsetTop;
//if the user scrolls down
if (window.pageYOffset < destination) {
scroller = setTimeout(function () {
smoothScroll(id);
}, 1);
currentY = currentY + speed;
if (currentY >= destination) {
clearTimeout(scroller);
}
//if the user scrolls up
} else {
scroller = setTimeout(function () {
smoothScroll(id);
}, 1);
currentY = currentY - speed;
if (currentY <= destination) {
clearTimeout(scroller);
}
}
window.scroll(0, currentY);
}
window.onscroll = function () {
currentY = this.pageYOffset;
};
Array.from(document.querySelectorAll(".scroll")).forEach(e => {
e.addEventListener('click', () => {
smoothScroll(e.href.split('#')[1]);
});
});
}
And here is a codepen to watch it in action : https://codepen.io/anon/pen/NYNQym
Thanks in advance.
First, you should use requestAnimationFrame(fn) instead of setTimeout(fn,1).
Your animation system is incremental - it says 'am I there yet? if no, go closer; if yes, stop.' This is OK but the only information it gives you about the animation is whether it's finished or not finished.
Easing would be something like 'when it's close to the end, slow down', but you don't know when you are close to the end.
Let's say we want to move from scroll position 100 to scroll position 200, starting at time 0 and ending at time 500. It's a mapping of time to position. If it's time 250, we should be at position 150 - they're both halfway. The same thing works for any other time. This is called tweening and it's the most common way to do animation.
Once we're working this way, we can do easing. The easing functions themselves are really simple - here are all the classic ones.
I can post code if you want but it sounds like you're trying to figure this out yourself, hope this was helpful and good luck.
This is driving me a bit mad. I've got setInterval working fine for Chrome, IE and Safari, but FireFox is letting me down big time. With the code below, it's not setting the heights of the <li>'s I'm targeting - can you see why not?
// For fullscreen overlay navigation
var uid = '#my-ul-id'
function osuFixLiHeights(targetUl) {
var t = $(targetUl);
var ch = $(t).height();
var lih = ch / 2;
$(t).find('li').each(function(i) {
$(this).removeAttr(); // clear heights first as it seems this is needed to re-add the heights
setInterval(function () {
$(this).height(lih); // delay adding heights
},100);
});
}
osuFixLiHeights(uid);
EDIT
Thanks for the help so far, much appreciated. Updated code below - as mentioned in one of my comments, this is all working great for setting the initial heights of the <li>'s, the only outstanding issue I have is that when resizing the browser window from a smaller size to a larger size, the heights of the <li>'s are being set correctly, however, making the browser window smaller doesn't change the <li> heights.
Here's the code I'm using:
var didResize = (function(){
var timer = 0;
return function(callback, ms) {
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
function osuFixLiHeights(targetUl) {
var ch = $(targetUl).height();
var lih = ch / 2;
$(targetUl).find('li').each(function(i) {
$(this).removeAttr(); // clear heights first
var targetLi = $(this);
setTimeout(function () {
$(targetLi).height(lih); // delay adding heights
}, 100);
});
}
$(window).resize(function() {
didResize(function() {
osuFixLiHeights('#menu-overlay-nav');
}, 500);
});
I think that the problem lies in the body of the setInterval function.
Try to assign this to a variable:
$(t).find('li').each(function(i) {
$(this).removeAttr(); // clear heights first as it seems this is needed to re-add the heights
var self = this; // Capture the current 'this' value
setInterval(function () {
// Here 'this' is not the same 'this' as before
$(self).height(lih); // delay adding heights
}, 100);
});
I'm trying to make an image drop up/down from a menu whenever the user clicks on the menu image which hasonClick="move()"in the tag. So far The image starts at the top of the page, behind the menu, so it is hidden, then slides down as intended. However, after the image reaches it's stopping point, clicking the menu again does nothing at all when I test the page in both IE and Chrome. In Dreamweaver, the code executes as intended, with the ability to slide the image up after it reaches the bottom and back down again. I've tried changing the call to setInterval() because I assumed that is where the problem was but nothing seems to be working. Why does Dreamweaver execute the code properly but not Chrome or IE?
var onMusic=false;
var id;
function move() {
if(!onMusic) {
moveDown()
}
else {
moveUp()
}
}
function moveUp() {
top=100
id = setInterval(function() {
top-=10 // update parameters
document.getElementById('guitar').style.top = top + 'px' // show frame
if (top <= -500) {// check finish condition
onMusic=false
clearInterval(id)
}
}, 10) // draw every 10ms
}
function moveDown() {
var top=-500
id = setInterval(function() {
top+=10 // update parameters
document.getElementById('guitar').style.top = top + 'px' // show frame
if (top == 100) {// check finish condition
onMusic=true
clearInterval(id)
}
}, 10) // draw every 10ms
}
id is only visible from the scope of the moveDown function. Make it global so that you can call clearInterval(id) in moveUp.
Change
function moveDown() {
var top=-500
var id = setInterval(function() {
to
var id;
function moveDown() {
var top=-500
id = setInterval(function() {
And changing the dom every tenth of millisecond (.1) might be a little extrem...
I think the problem was:
top=100
// should be
var top = 100;
You can try in the console to see what I mean:
>top = 12
12
> top
Window {top: Window, window: Window, location: Location, Proxy: Object, external: Object…}
But I cleaned it up a little more in jsfiddle:
http://jsfiddle.net/pNh57/1/
I am newbie in JS. Right now i am working on an effect in which i want when page scroll first time then the natural motion animation starts but it's creating a problem because when i scroll the element animation became fast.
Check this more you got the idea.
http://jsfiddle.net/byvLy/
i know that this is a swinging box (figured it out due to the Math.sin())
however, you have to note that scrolling event is fired every few milliseconds during scrolling. in your code, you are calling animate and creating an interval every time the scroll event is fired. that's why your animation is jumpy;
try this instead:
$(function() {
$(window).on('scroll', function() {
swing.start('.cloud1, .cloud2');
});
var swing = (function() {
var animated = false;
function startAnimation(selector) {
if (!animated) {
var banner = $(selector);
var start = 0;
animated = true;
window.setInterval(function() {
banner.css('left', 100 * Math.sin(start) + 80);
start += 0.1;
}, 30);
}
}
return {
start: startAnimation
}
}());
});​