I have the following javascript which is a loader that is triggered and created when the page is idle. It basically shows whilst the next navigated page is loading. The script resides on the (ASP.NET) master page and an Ajaxified user control.
I need to make the code cross-browser but not sure what the offender is.
It only works happily in Trident (only tested IE9 & 10) - not in Webkit or Gecko.
I'm not sure if it's a notation issue or if the page life cycle for Chrome and Safari don't ever declare themselves as "!= complete" thus not triggering the condition.
I'd also prefer to keep this a pure Javscript solution - no jQuery.
Thanks
loader = 0;
if (window.location.href.indexOf("Login.aspx") < 0) {
setInterval(function () {
if (document.readyState != 'complete') {
document.documentElement.style.overflow = "hidden";
var navLoader = document.createElement("div");
var loaderText = document.createElement("div");
var loaderImg = document.createElement("div");
navLoader.id = "navLoaderDiv";
navLoader.className = "navLoader";
loaderImg.id = "loaderImg";
loaderText.id = "loaderText";
loaderImg.className = "loaderImg";
loaderText.className = "loaderText";
navLoader.appendChild(loaderImg);
navLoader.appendChild(loaderText);
loaderText.innerHTML = "Working on it";
var zedDepth = 99999;
navLoader.style.zIndex = zedDepth;
navLoader.style.background.image = "url(~/Images/loaderHalo2.png) 0 0 / 100% 100% no-repeat";
navLoader.style.position = "absolute";
navLoader.style.right = "0px";
navLoader.style.left = "0px";
navLoader.style.top = "25px";
navLoader.style.bottom = "0px";
if (loader == 0) {
document.documentElement.appendChild(navLoader);
loader = 1;
}
} else if (document.getElementById('navLoaderDiv') != null) {
document.getElementById('navLoaderDiv').style.display = "none";
document.documentElement.style.overflow = "hidden";
}
}, 1000)
}
Related
I have been trying to make a simple "smoothscroll" function using location.href that triggers on the mousewheel. The main problem is that the EventListener(wheel..) gets a bunch of inputs over the span of ca. 0,9 seconds which keeps triggering the function. "I only want the function to run once".
In the code below I have tried to remove the eventlistener as soon as the function runs, which actually kinda work, the problem is that I want it to be added again, hence the timed function at the bottom. This also kinda work but I dont want to wait a full second to be able to scroll and if I set it to anything lover the function will run multiple times.
I've also tried doing it with conditions "the commented out true or false variables" which works perfectly aslong as you are only scrolling up and down but you cant scroll twice or down twice.
window.addEventListener('wheel', scrolltest, true);
function scrolltest(event) {
window.removeEventListener('wheel', scrolltest, true);
i = event.deltaY;
console.log(i);
if (webstate == 0) {
if (i < 0 && !upexecuted) {
// upexecuted = true;
location.href = "#forside";
// downexecuted = false;
} else if (i > 0 && !downexecuted) {
// downexecuted = true;
location.href = "#underside";
// upexecuted = false;
}
}
setTimeout(function(){ window.addEventListener('wheel', scrolltest, true); }, 1000);
}
I had hoped there was a way to stop the wheel from constantly produce inputs over atleast 0.9 seconds.
"note: don't know if it can help in some way but when the browser is not clicked (the active window) the wheel will registre only one value a nice 100 for down and -100 for up"
What you're trying to do is called "debouncing" or "throttling". (Those aren't exactly the same thing, but you can look up the difference in case it's going to matter to you.) Functions for this are built into libraries like lodash, but if using a library like that is too non-vanilla for what you have in mind, you can always define your own debounce function: https://www.geeksforgeeks.org/debouncing-in-javascript/
You might also want to look into requestanimationframe.
a different approach
okey after fiddeling with this for just about 2 days i got fustrated and started over. no matter what i did the browsers integrated "glide-scroll" was messing up the event trigger. anyway i decided to animate the scrolling myself and honestly it works better than i had imagined: here is my code if anyone want to do this:
var body = document.getElementsByTagName("BODY")[0];
var p1 = document.getElementById('page1');
var p2 = document.getElementById('page2');
var p3 = document.getElementById('page3');
var p4 = document.getElementById('page4');
var p5 = document.getElementById('page5');
var whatpage = 1;
var snap = 50;
var i = 0;
// this part is really just to read what "page" you are on if you update the site. if you add more pages you should remember to add it here too.
window.onload = setcurrentpage;
function setcurrentpage() {
if (window.pageYOffset == p1.offsetTop) {
whatpage = 1;
} else if (window.pageYOffset == p2.offsetTop) {
whatpage = 2;
} else if (window.pageYOffset == p3.offsetTop) {
whatpage = 3;
} else if (window.pageYOffset == p4.offsetTop) {
whatpage = 4;
} else if (window.pageYOffset == p5.offsetTop) {
whatpage = 5;
}
}
// this code is designet to automaticly work with any "id" you have aslong as you give it a variable called p"number" fx p10 as seen above.
function smoothscroll() {
var whatpagenext = whatpage+1;
var whatpageprev = whatpage-1;
var currentpage = window['p'+whatpage];
var nextpage = window['p'+whatpagenext];
var prevpage = window['p'+whatpageprev];
console.log(currentpage);
if (window.pageYOffset > currentpage.offsetTop + snap && window.pageYOffset < nextpage.offsetTop - snap){
body.style.overflowY = "hidden";
i++
window.scrollTo(0, window.pageYOffset+i);
if (window.pageYOffset <= nextpage.offsetTop + snap && window.pageYOffset >= nextpage.offsetTop - snap) {
i=0;
window.scrollTo(0, nextpage.offsetTop);
whatpage += 1;
body.style.overflowY = "initial";
}
} else if (window.pageYOffset < currentpage.offsetTop - snap && window.pageYOffset > prevpage.offsetTop + snap){
body.style.overflowY = "hidden";
i--
window.scrollTo(0, window.pageYOffset+i);
if (window.pageYOffset >= prevpage.offsetTop - snap && window.pageYOffset <= prevpage.offsetTop + snap) {
i=0;
window.scrollTo(0, prevpage.offsetTop);
whatpage -= 1;
body.style.overflowY = "initial";
}
}
}
to remove the scrollbar completely just add this to your stylesheet:
::-webkit-scrollbar {
width: 0px;
background: transparent;
}
I am using the removeChild method for the first time. I have use javascript to modify my navbar so that it changes to fixed position and and scroll with the user. This causes the content of the body div to jump up slightly when this happens. As a result, I have managed to insert a red box (it will later be white) to take up the extra space when the navbar's position changes.
I need that red box to be removed when the user scrolls back to the top but I can't seem to get the remove child function to fire. If somebody could take a look and point me in the right direction that would be swell!
code (relevant code section is in bold):
var fillerState = false;
// fixed positioning on scroll property for taskbar:
window.addEventListener('scroll', function (evt) {
var distance_from_top = document.body.scrollTop;
if (distance_from_top <= 80) {
document.getElementById("navBar").style.position = "static";
document.getElementById("navBarList").style.borderBottom = "solid black 4px";
document.getElementById("navBar").style.borderTop = "initial";
var myCollection = document.getElementsByClassName("navBarLink");
var collectionLength = myCollection.length;
for(var i = 0; i < collectionLength; i++){
myCollection[i].style.borderTopLeftRadius = "1em";
myCollection[i].style.borderTopRightRadius = "1em";
myCollection[i].style.borderBottomLeftRadius = "initial";
myCollection[i].style.borderBottomRightRadius = "initial";
}
// stops loads of boxes from forming:
**if(fillerState == true){
var parentRemove = document.getElementById("bodyDiv");
var fillerBoxRemove = document.getElementById("fillerBox");
parentRemove.removeChild(fillerBoxRemove);
fillerState = false;
alert(fillerState);**
}
}
else if(distance_from_top > 80) {
document.getElementById("navBar").style.position = "fixed";
document.getElementById("navBar").style.top = "0px";
document.getElementById("navBar").style.borderTop = "solid black 4px";
document.getElementById("navBarList").style.borderBottom = "initial";
var myCollection = document.getElementsByClassName("navBarLink");
var collectionLength = myCollection.length;
if(fillerState == false){
// sets filler element so that the page doesn't bounce:
var filler = document.createElement("div");
filler.style.width = "200px";
filler.style.height = "80px";
filler.style.backgroundColor = "red";
filler.style.id = "fillerBox";
//defines where the new element will be placed:
var parent = document.getElementById("bodyDiv");
var brother = document.getElementById("leftColumn");
parent.insertBefore(filler,brother);
fillerState = true;
}
for(var i = 0; i < collectionLength; i++){
myCollection[i].style.borderTopLeftRadius = "initial";
myCollection[i].style.borderTopRightRadius = "initial";
myCollection[i].style.borderBottomLeftRadius = "1em";
myCollection[i].style.borderBottomRightRadius = "1em";
}
}
});
as squint pointed out, when you're making the element, you're setting it's style.id, which is not right.
Change:
filler.style.id = "fillerBox";
To:
filler.id = "fillerBox";
And your code will work.
Alternatively, you can do as others have suggested and create the box in the html itself, set it to a class that has no display, then change it's class. Not only easier, but also stops you from creating and destroying. less resource intensive that way.
Currently createPopup() is only supported in IE (See http://help.dottoro.com/ljsxcrhv.php).
Is there a universal createPopup() replacement? Or is conditional code required based on browser detection?
Hopefully, I am looking for something that not only provides the same functionality, but has the same interface or at least could provide the ingredients to create createPopup() clone without too much work.
So I had a whole mess of legacy code that used window.createPopup() so changing to a library would have been a lot of effort, and now that IE 11 doesn't support this method, we had to do something since our app is built to support Explorer. I was able to solve this to work in other browsers by writing the following code:
if(!window.createPopup){
window.createPopup = function (){
var popup = document.createElement("iframe"), //must be iframe because existing functions are being called like parent.func()
isShown = false, popupClicked = false;
popup.src = "about:blank";
popup.style.position = "absolute";
popup.style.border = "0px";
popup.style.display = "none";
popup.addEventListener("load", function(e){
popup.document = (popup.contentWindow || popup.contentDocument);//this will allow us to set innerHTML in the old fashion.
if(popup.document.document) popup.document = popup.document.document;
});
document.body.appendChild (popup);
var hidepopup = function (event){
if(isShown)
setTimeout(function (){
if(!popupClicked){
popup.hide();
}
popupClicked = false;
}, 150);//timeout will allow the click event to trigger inside the frame before closing.
}
popup.show = function (x, y, w, h, pElement){
if(typeof(x) !== 'undefined'){
var elPos = [0, 0];
if(pElement) elPos = findPos(pElement);//maybe validate that this is a DOM node instead of just falsy
elPos[0] += y, elPos[1] += x;
if(isNaN(w)) w = popup.document.scrollWidth;
if(isNaN(h)) h = popup.document.scrollHeight;
if(elPos[0] + w > document.body.clientWidth) elPos[0] = document.body.clientWidth - w - 5;
if(elPos[1] + h > document.body.clientHeight) elPos[1] = document.body.clientHeight - h - 5;
popup.style.left = elPos[0] + "px";
popup.style.top = elPos[1] + "px";
popup.style.width = w + "px";
popup.style.height = h + "px";
}
popup.style.display = "block";
isShown = true;
}
popup.hide = function (){
isShown = false;
popup.style.display = "none";
}
window.addEventListener('click', hidepopup, true);
window.addEventListener('blur', hidepopup, true);
return popup;
}
}
function findPos(obj, foundScrollLeft, foundScrollTop) {
var curleft = 0;
var curtop = 0;
if(obj.offsetLeft) curleft += parseInt(obj.offsetLeft);
if(obj.offsetTop) curtop += parseInt(obj.offsetTop);
if(obj.scrollTop && obj.scrollTop > 0) {
curtop -= parseInt(obj.scrollTop);
foundScrollTop = true;
}
if(obj.scrollLeft && obj.scrollLeft > 0) {
curleft -= parseInt(obj.scrollLeft);
foundScrollLeft = true;
}
if(obj.offsetParent) {
var pos = findPos(obj.offsetParent, foundScrollLeft, foundScrollTop);
curleft += pos[0];
curtop += pos[1];
} else if(obj.ownerDocument) {
var thewindow = obj.ownerDocument.defaultView;
if(!thewindow && obj.ownerDocument.parentWindow)
thewindow = obj.ownerDocument.parentWindow;
if(thewindow) {
if (!foundScrollTop && thewindow.scrollY && thewindow.scrollY > 0) curtop -= parseInt(thewindow.scrollY);
if (!foundScrollLeft && thewindow.scrollX && thewindow.scrollX > 0) curleft -= parseInt(thewindow.scrollX);
if(thewindow.frameElement) {
var pos = findPos(thewindow.frameElement);
curleft += pos[0];
curtop += pos[1];
}
}
}
return [curleft,curtop];
}
I'll start by admitting that it's pretty ugly. However, this worked for me to make the code that calls this method work in other browsers, and was easier than changing dozens of legacy (and poorly coded otherwise) pages to use some outside library, so perhaps it will help someone else out there.
It uses an iframe and creates a document property on it because we had a lot of code that was along the lines of popup.document.body.innerHTML = "<span onclick = 'parent.someFunction()'>";. Using the iframe instead of a div allows this to remain in it's junky state and still work.
You may want to look at some of the JavaScript libraries out there. Things like Dojo, Yahoo UI, or JQuery can help to encapsulate most of the browser-specific headaches. For example, with Dojo, take a look at http://dojotoolkit.org/api/. This would get you similar functionality to createPopup().
Whats up with window.open()?
http://www.w3schools.com/jsref/met_win_open.asp
I have the following code. It set a filter bar in a search results page in a fixed position in the window after scrolling down to a certain point:
var docked;
var filters = document.getElementById('filters');
var init = filters.offsetTop;
function scrollTop() {
return document.body.scrollTop || document.documentElement.scrollTop;
}
window.onscroll = function () {
if (!docked && (init - scrollTop() < 0)) {
filters.style.top = 0;
filters.style.position = 'fixed';
filters.className = 'docked';
docked = true;
} else if (docked && scrollTop() <= init) {
filters.style.position = 'absolute';
filters.style.top = init + 'px';
filters.className = filters.className.replace('docked', '');
docked = false;
}
}
My issue is (and it's more curiosity) - if I place this code at the top of my file (in the <head>), it doesn't work at all. The filter section doesn't scroll with the window as it should. However, when I place this code at the bottom of the file (right above the closing </body> tag), it works just fine.
Why is this? Does this have something to do with the way the code works? Or could it be just a quirk or bug in the rest of my file causing this?
Wrap your assignments in window.onload = function(){ /* your code here */ }; and it will run. The reason being that your assignment of var filters = document.getElementById('filters'); comes back as undefined since that element does not exist during page load at the time you reference it.
Example:
var docked;
var filters;
var init;
window.onload = function(){
filters = document.getElementById('filters');
init = filters.offsetTop;
};
if you do this, it should work:
$(document).ready(window.onscroll = function () {
if (!docked && (init - scrollTop() < 0)) {
filters.style.top = 0;
filters.style.position = 'fixed';
filters.className = 'docked';
docked = true;
} else if (docked && scrollTop() <= init) {
filters.style.position = 'absolute';
filters.style.top = init + 'px';
filters.className = filters.className.replace('docked', '');
docked = false;
}
}
);
I've got a simple script that fades in and out some images. It works perfectly fine, before I switch to another tab and then switch back. After switching back seems that interval that runs animation doesn't get cleared and animateFading function keeps running.
Why is it happening, how does tab switching affects script? And how could I make it work properly? thx!
The real code:
var img0 = document.getElementById("image0");
var img1 = document.getElementById("image1");
var img2 = document.getElementById("image2");
var imgs = [img0,img1,img2];
var intervalFading;
var intervalAnimate;
var imgThis = 0;
var imgNext = 1;
var fadeIn = 0;
var fadeOut = 1;
var start;
function animateFading() {
fadeIn+=0.1;
fadeOut-=0.1;
imgs[imgThis].style.opacity = fadeOut;
imgs[imgNext].style.opacity = fadeIn;
if (fadeIn >= 1) {
clearInterval(intervalAnimate);
if (imgNext < 2) {
imgNext++;
} else {
imgNext = 0;
}
if (imgThis < 2) {
imgThis++;
} else {
imgThis = 0;
}
fadeIn = 0;
fadeOut = 1;
}
}
function fading() {
intervalAnimate = setInterval(animateFading,50);
}
function startFading() {
start = setInterval(fading, 3000);
}
window.addEventListener('load', startFading);
Solution:
var startedFading = false;
function startFading() {
if (!startedFading) {
startedFading = true;
startFading = setInterval(fading, 5000);
}
}
function stopFading() {
startedFading = false;
clearInterval(startFading);
}
window.addEventListener('focus', startFading);
window.addEventListener('blur', stopFading);
The boolean is for Chrome, as it fires twice
window.addEventListener('focus', startFading);
&
window.addEventListener('blur', stopFading);
Most browsers have a feature that redirects the memory usage capacity to the only active tab (currently being viewed). Thus, the setInterval and setTimeout timings are affected when you switch the current tab (if you're using Google Chrome, you can see the memory usage of each tab by pressing Shift+Esc. The current tab will use up to 25%, whereas the rest don't pass of the 5%)