I have a script going in Javascript, the purpose of which is to make an image stay centered in the window when the window is smaller than the image. It just moves the image to the left by half the difference between the image width and the window width so that the center of the image is always the center of the screen. When the window is not smaller than the image, this left offset is set to zero. And it works perfectly, if I'm in IE or Firefox. On the webkit browsers, it doesn't ever go to zero, creating an effect akin to float:right when the window is wider than the image. Here's the code:
setTimeout(slideImageWidth, 1);
function slideImageWidth() {
var slideWidth = window.getComputedStyle(document.getElementById("slide-image")).width,
windowWidth = window.innerWidth,
slide = document.getElementById("slide-image"),
slideWidth = window.getComputedStyle(slide).width;
if (windowWidth < (slideWidth.replace("px", "") + 1) && slide.style.display !== "none") {
slide.style.left = ((((-slideWidth.replace("px", "") + windowWidth)) / 2) + "px");
}
else {
slide.style.left = 0;
setTimeout(slideImageWidth, 1);
};
I tried putting slide.style.left = 0 before the if and just letting the loop take care of it in the next millisecond, but that didn't work either. I've also tried both placements with:
slide.style.left = "0px";
slide.style.left = 0 + "px";
slide.style.left = "0" + "px";
slide.style.left = 0px;
none of which worked in Chrome or Safari, but all but the last of which worked in Firefox and IE.
When I use alert(slide.style.left) when the window is wider than the image, a positive value is returned in Chrome and Safari, unlike the 0 from Firefox and IE, which tells me that the 0 value is never being written to slide.style.left. Yet, I know that I can modify slide.style.left because it still positions itself based on the equation.
Why does this code not work with the webkit browsers, and how can I fix it?
First, the things which I think are accidental typos:
1) Your code references something called "slide1Width", which is defined nowhere.
2) Your code references something called "slide1", which is defined nowhere.
3) You don't have the right number of close brackets, and the last bracket inexplicably has a semicolon after it.
Second, the most obvious error that isn't causing your specific problem:
(slideWidth.replace("px", "") + 1)
This expression is not what you want. If slideWidth is "440px", the replace() call gives you "440", and ("440" + 1) is the string "4441". I don't think that's what you mean to do here.
Third, and finally, what I believe is the cause of the actual bug you're asking about: timing. If you open up the dev tools and manually run slideImageWidth() on a wide window after it has loaded and failed to center itself, the image will in fact jump to the center, even on Chrome. Why doesn't it do it on page load? Here:
window.getComputedStyle(slide).width
That expression returns "0px" right when the page is first loaded. If you wait until the image is done loading, you'll be able to get an actual width for it, in which case you can do the calculations you want. (Or, presumably, you could set the width yourself via styling.) It seems that IE is getting the image loaded and flowed before running the script, whereas Chrome is not.
Is there a reason you want to use setTimeout instead of a resize event? What about something like this:
window.onresize = function(event) {
setSlidePosition();
};
function setSlidePosition() {
var slideLeft = (document.getElementById("slide-image").style.left.indexOf('px') != -1 ) ? document.getElementById("slide-image").style.left : '0px';
var numLeft = slideLeft.replace('px','');
console.log(numLeft);
var element = document.getElementById("slide-image")
if(element.width > window.innerWidth) {
var newLeft = (element.width - window.innerWidth) / 2 * -1 + "px";
document.getElementById("slide-image").style.left = newLeft;
} else {
document.getElementById("slide-image").style.left = "0px";
}
};
setSlidePosition();
http://jsfiddle.net/4qomq7tb/45/
Seems to behave the same in chrome and FF at least. This doesn't specifically answer the question relating relating to your code, though :/
Related
I have discovered that my implementation of infinite scroll does not work on Firefox, but it does work on Safari and Chrome. (I am using Vue.js, and the problem is that I cannot figure out how to devise a boolean expression to discern if the user has scrolled to the bottom of the window that works on Firefox. Here is the methods section, in the script area of the .vue file of the main component:
methods: {
bottomVisible() {
/**
* This solution doesn't work for firefox
*/
const scrollY = window.scrollY
const visible = document.documentElement.clientHeight
const pageHeight = document.documentElement.scrollHeight
const bottomOfPage = visible + scrollY >= pageHeight
console.log(bottomOfPage || pageHeight < visible);
return bottomOfPage || pageHeight < visible;
},
addMoreCards() {
this.$store.dispatch(
"increaseMultiplier",
this.$store.state.cardToShowMultiplier + 1
);
}
},
watch: {
bottom(bottom) {
if (bottom) {
this.addMoreCards();
}
}
},
created() {
window.addEventListener("scroll", () => {
this.bottom = this.bottomVisible();
});
}
};
The biggest problem is that when I inspect the console in Firefox, this line never prints True: console.log(bottomOfPage || pageHeight < visible);
Can anyone help me find a find create a new boolean that would return True if the user scrolls to the bottom of the page on Firefox, Safari, and Chrome, allowing me to call the function addMoreCards() when the user scrolls to the bottom of the page? I certainly am not a front-end developer, so I could really use you guys' help!
Here are some other tidbits that may be of use:
Sometimes, in FireFox, scrolling to the bottom of the page will cause bottomVisible() to return True as intended. However, it will not consistently work. When it does, I do get this warning in the console:
This site appears to use a scroll-linked positioning effect. This may not work well with asynchronous panning; see https://developer.mozilla.org/docs/Mozilla/Performance/ScrollLinkedEffects for further details and to join the discussion on related tools and features!
In Firefox, the infinite scroll appears to work better if I make the window more narrow, though still not consistently. Not sure why...
Fixed it, with the help from the comment above. After logging the values of the variables, it seems that Mozilla's scrollY values are .5 less than it should be. To fix this, I simply added .5 to the scrollY value, so that const bottomOfPage = visible + scrollY >= pageHeight would be set to true when at the bottom.
Tested in Safari and Chrome - the same result, so I think it's iOS issue.
This happens only if there's an input inside the modal and I tap that input. In the same moment, that input gets focus and native iOS keyboard become visible.
The page below modal in the same moment is automatically scrolled to 50% of its height. This behaviour is totally unwanted and I have no clue how to prevent this default iOS "feature".
Demo:
UPDATE: the fix commit: limonte/sweetalert2/commit/4a2d36b
We are facing a similar issue at work, and I stumbled upon this question with your (excellent) demo page.
As you mentioned, the offset is always ~50% of the height of the page, which happens regardless of where your initial offset is.
In the past, when I observed a similar "jumping" with earlier iOS versions (albeit, much less dramatic jumping), I have usually worked around this by applying position: fixed (or relative) to the body (this allows overflow: hidden to properly work).
However, this has the unattended consequence of jumping the user back to the top of the page, if they've scrolled down.
So, if you're open to addressing this issue with some JavaScript, here's a fix/hack I've thrown together:
// Tapping into swal events
onOpen: function () {
var offset = document.body.scrollTop;
document.body.style.top = (offset * -1) + 'px';
document.body.classList.add('modal--opened');
},
onClose: function () {
var offset = parseInt(document.body.style.top, 10);
document.body.classList.remove('modal--opened');
document.body.scrollTop = (offset * -1);
}
And what the CSS looks like:
.modal--opened {
position: fixed;
left: 0;
right: 0;
}
Here's a fork of your demo page, to illustrate: https://jpattishall.github.io/sweetalert2/ios-bug.html
And for those who are looking for a more general fix, you could do something like the following when opening/closing a modal:
function toggleModal() {
var offset;
if (document.body.classList.contains('modal--opened')) {
offset = parseInt(document.body.style.top, 10);
document.body.classList.remove('modal--opened');
document.body.scrollTop = (offset * -1);
} else {
offset = document.body.scrollTop;
document.body.style.top = (offset * -1) + 'px';
document.body.classList.add('modal--opened');
}
}
Edit: One thing to note is that we didn't apply the fix to all devices/platforms blindly, just iOS Safari. I noticed in your other question that you weren't a fan of overflow: hidden due to the shifting of the page when the scrollbar appears/disappears (which I totally agree with). I would suggest just applying the JS to iOS devices only.
On iOS I had trouble with scroll events caused by setTimeout and setInterval (position the modal causes scrolling?). I found a solution somewhere with the following code.
Function.prototype.bind = function(parent) {
var f = this;
var args = [];
for (var a = 1; a < arguments.length; a++) {
args[args.length] = arguments[a];
}
var temp = function() {
return f.apply(parent, args);
}
return(temp);
}
setTimeout(function() {
// your animation stuff here
}.bind(this), 100);
One thing I can think of here is to probably add the Fast Click library to your code. Some iOS and Android timeout issues like the 300ms delay are handled by Fast Click. It's worth a shot
Something else to check for is that the font size of the input field is above the minimum that will trigger a zoom on the input. I'm working from memory here, but I had a similar problem. Setting the input font size to 16px (again from memory) or more prevented iOS Safari from trying to zoom the input field and thus messing with the page scroll.
Resolved!!!!! Just please add those codes to your script
https://gist.github.com/kiding/72721a0553fa93198ae2bb6eefaa3299
//reach out to that input field (When ever u r gonna click tofocus)
let inputField = document.getElementById("input_focused")
/*
* Method 1: Briefly change the opacity.
* Element might "blink" on focus in some scenarios.
*/
inputField.addEventListener("focus", () => {
methodOne.style.opacity = 0;
setTimeout(() => methodOne.style.opacity = 1);
});
<section id="modal">
<input id="input_focused">
</section>
If I have a div with overflow:auto so that it is a scrollable div and I load it with information that makes a significant scroll area, is there a way that when I load the information, the div shows the bottom results? Or essentially scrolls to the bottom?
I've seen jQuery solutions but this is for use in an HTA so I cannot use jQuery. Is there a purely javascript way to accomplish this?
var myDiv = document.getElementById('myDiv');
myDiv.scrollTop = myDiv.scrollHeight;
Works in Firefox, Safari, Opera, Chrome and even Internet Explorer, which is more than I can say for the SSE test case I Set up... lol
I will spare you the rant about the obtuse solutions offered by others, and here is an example of code that could be used for an instant messaging type client.
document.body.onload = function()
{
var myDiv = document.getElementById('myDiv');
// Pick your poison below, server sent events, websockets, AJAX, etc.
var messageSource = new EventSource('somepage');
messageSource.onmessage = function(event)
{
// You must add border widths, padding and margins to the right.
var isScrolled = myDiv.scrollTop == myDiv.scrollHeight - myDiv.offsetHeight;
myDiv.innerHTML += event.data;
if(isScrolled)
myDiv.scrollTop = myDiv.scrollHeight;
};
};
The part of that example that is relevant checks to see if the div is already scrolled to the bottom, and if it is, scrolls it to the bottom after adding data to it. If it is not already scrolled to the bottom, the div's scroll position will stay such that the visible content of the div is unaffected by adding the data.
document.getElementById('mydiv').scrollTop = 9999999;
The scrollTop property specifies the scrolling offset in pixels from the top of the region. Setting it to a very large value will force it to the bottom.
How about this?
function scroll_to_max(elm) { // {{{
if(!scroll_to_max_el) {
scroll_to_max_el = elm;
setTimeout(scroll_to_max, 10); // Allow for the element to be updated
} else {
var el = scroll_to_max_el;
var t = el.scrollTop;
el.scrollTop = t+100;
if(el.scrollTop != t) {
setTimeout(scroll_to_max, 10); // Keep scrolling till we hit max value
} else {
scroll_to_max_el = null;
}
}
}
var scroll_to_max_el = null; // Global var!
// }}}
(NOTE: Only tested it in Chrome...)
Late answer but this is much more helpful
$('#mydiv').scrollTop(($('#mydiv').height()*2));
I think you need to set the scrollTop after the element is updated.
setTimeout(function (){
el.scrollTop = 999999999
}, 10)
also, in chrome at least, 99999999999 will scroll to the bottom. but 999999999999 (an extra 9) will scroll to the top. it's probably converted to an int in the C side of webkit.
I've got some code to maximize a video panel on page load / resize. I'm using JQuery 1.4.4 and everything is working great in Chrome, Firefox and Safari. Following some examples from some other posts, I adjust the video panel size based on the rendered size and styling of the other elements on the screen.
function maximizeVideo(){
var play_height = $(window).height()-42;
var play_width = $PLAY.width() - $NAV.width();
play_width -= parseInt($NAV.css("paddingLeft"), 10) + parseInt($NAV.css("paddingRight"), 10);
play_width -= parseInt($NAV.css("marginLeft"), 10) + parseInt($NAV.css("marginRight"), 10);
play_width -= parseInt($NAV.css("borderLeftWidth"), 10) + parseInt($NAV.css("borderRightWidth"), 10);
$NAV.css('height',play_height-16+"px");
$VIDEO_PANEL.resize(play_width, play_height);
}
In IE the css accessor sometimes returns NaN. Is there a better way to account for the rendered width of the other element?
If not, what's the best way to trap these errors?
Thanks!
For your situation, I think you should be looking at the outerWidth function instead of width. Using outerWidth(true), we can obtain the width of the element including its borders, padding and margin. Therefore you can replace this line:
var play_width = $PLAY.width() - $NAV.width();
with this:
var play_width = $PLAY.width() - $NAV.outerWidth(true);
And thus eliminating the next three lines of calculations altogether.
Additionally, the height and width functions are not just getters, but also setters, so this line:
$NAV.css('height',play_height-16+"px");
can be rewritten as
$NAV.height(play_height - 16);
I know that the title is very subtle but I have absolutely no idea how I should title this issue nor what the hell is happening with this function.
function update_background(source, isSystem){
if (!isSystem) {
source.replace(/\/tn_/, '');
jQuery('div#drag_container img[alt="background"]').attr('src', source); //*1
jQuery('div#drag_container img[alt="background"]').attr('style', '');
var height = jQuery('div#drag_container img[alt="background"]').height();
var width = jQuery('div#drag_container img[alt="background"]').width();
var ratio = Storyboard['format'];
//Don't touch the paddings, they are correct!
if (height * ratio > width) {
var padding = (Storyboard['display'] - (width * (Storyboard['height'] / height))) / 2;
jQuery('div#drag_container img[alt="background"]').css({
'height': Storyboard['height'],
'padding-left': padding
});
} else {
var padding = (Storyboard['height'] - (height * (Storyboard['display'] / width))) / 2;
jQuery('div#drag_container img[alt="background"]').css({
'width': Storyboard['display'],
'padding-top': padding,
'padding-bottom': padding
});
}
} else {
jQuery('div#drag_container img[alt="background"]').attr('src', source).attr('style', '');
jQuery('div#drag_container img[alt="background"]').css({
'width': Storyboard['display'],
'height': Storyboard['height']
});
}
}
What this function is supposed to do, is take a picture, get the size of it, compare it to the the size of the container it will be shown in, resize it so that it is as big as possible without sticking out of the container and then finally, apply padding where needed to center the image. It does not matter if the picture is landscape or portrait, the function knows exactly what to do. The picture is cached so that we don't get wrong values (I already had a bug like that). In case it is a System Background, we don't care for correct size and padding. Worked flawless for 3 months.
Lately, it is behaving rather odd. At the line with the comment *1, it does not only reset the src attribute of the img-tag, but it also sets a height and a padding, as if it already were in the padding calculations. They are removed again on the next line (which wasn't actually inserted for that purpose but was inserted to get the original dimensions of a picture) and it still works.
Unless, of course, you let the function run at regular speed, where it does not reset the style. I am quite irritated by this Bug as I have no idea where to start searching.
The function is only called once. It only runs once through the function. It is not included in an event and this function is called in 2 totally different places.
Any ideas?
Edit 1
I have found out that the Bug does not occur in every Browser.
Mac OS X Snow Leopard
Firefox: behavior as described
Opera: does it all wrong, but is not supported by our company
Safari: Still works flawless
Windows XP
Chrome: Works same as Safari
Firefox: Behavior as described
IE8: Same Behavior
IE7: Actually Works!
Linux
Firefox: Behavior as described
Konqueror: does not even work with my JavaScript
You might be having problems getting the size of the image because it isn't guaranteed that it has been loaded by the time you're checking its dimensions.
var $img = jQuery('div#drag_container img[alt="background"]');
$img.bind('load', function(){
// do all of your stuff with the width and the height of the image in here...
var width = $(this).width();
var height = $(this).height();
});
$img.attr('src', source); /* kicks off the loading of the image, the bound function
* above will get called when it's done.
*/