I'm writing a specific javascript plugin for a specific website.
In one of my methods i want to use window.scrollTo but unfortunately the site owner has overridden the native functionality of this function (also window.scroll).
So i'm thinking about 2 possible solutions:
Write my own myScrollTo implementation
Somehow detect if the native function is overridden and call the native function.
If you have any ideas on this, i will be very glad to hear them :)
Thanks.
Well you can create an iframe and use its window instance to get the native implementation of scrollTo. The following code should work
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
window.altScrollTo = iframe.contentWindow.scrollTo;
Now you should be able to use it as below
aScrollTo.call(window, 0, 600)
Well it's not the perfect solutions but is suites my current needs.
First i will check if the native function is overridden with this helpful piece of code :
function isFuncNative(f) {
return !!f && (typeof f).toLowerCase() == 'function'
&& (f === Function.prototype
|| /^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code\]\s*}\s*$/i.test(String(f)));
}
Source: https://stackoverflow.com/a/7536972/3009194
Then i will try the alternatives : window.scroll as the is no difference between window.scroll() and window.scrollTo()
And finally if this one is also overridden, i guess i will use document.body.scrollTop
Yes i know, there is a possibility that the body is not the scrolling Element.
Unfortunately the document.scrollingElement is still a draft and not supported in most browsers.
So the final code will look something like this:
function myScroll(left, top) {
if (isFuncNative(window.scrollTo)) {
window.scrollTo(left, top);
} else if (isFuncNative(window.scroll)) {
window.scroll(left, top);
} else {
document.body.scrollLeft = left;
document.body.scrollTop = top;
}
}
myScroll(0,150);
Related
I'm working on a responsive site with a specific set of jQuery functions for the desktop layout and mobile layout. They interfere with each other if they're both active at the same time.
By checking window.width, I'm able to deliver only the correct set of functions on page load, and I'd like to do the same on window.resize.
I've set up a stripped down Fiddle of where I'm at here: http://jsfiddle.net/b9XEj/
Two problems exist right now:
Either desktopFunctions or mobileFunctions will continuously fire on page resize, whether they have already been loaded or not.
If the window is resized beyond one breakpoint and then returned to the previous size, the incorrect set of functions will already have been loaded, interfering with the current set.
The window.resize function should behave in the following way:
Check if the correct set of functions currently active for the viewport size
If yes, return.
If no, fire correct set of functions and remove incorrect set of functions if they exist.
In the Fiddle example above, you would always see a single line, displaying either "Mobile Functions are active" or "Desktop Functions are active".
I'm a bit lost at this point, but I have tried using
if ($.isFunction(window.mobileFunctions))
to check if functions already exist, but I can't seem to get it working without breaking the overall function. Here's a fiddle for that code: http://jsfiddle.net/nA8TB/
Thinking ahead, this attempt also wouldn't take into account whether the incorrect set of functions exists already. So, I'm really hoping there's a way I can deal with this in a simpler way and solve both problems.
Any help would be much appreciated!
Following conquers 2 of the problems. The resize fires many times a second, so using a timeout will fix it firing your code constantly. It also adds a check to see if the same size is in effect, and return if it is
$(document).ready(function() {
var windowType;
var $wind = $(window);
var desktopFunctions = function() {
$('body').append('<p>Desktop functions are active</p>');
}
var mobileFunctions = function() {
$('body').append('<p>Mobile Functions are active</p>');
}
var mobileCheck = function() {
var window_w = $wind.width();
var currType = window_w < 940 ? 'mobile' :'desktop';
if (windowType == currType) {
$('body').append('<p>No Type Change, Width= '+window_w+'</p>');
return;
} else {
windowType = currType;
}
if (windowType == 'mobile') {
mobileFunctions();
} else {
desktopFunctions();
}
}
mobileCheck();
var resizeTimer;
$wind.resize(function() {
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(mobileCheck, 300)
});
});
DEMO: http://jsfiddle.net/b9XEj/1/
Without seeing some real world differences between your 2 sets of functions it is hard to provide gudance on how to stop them conflicting. One possibility is checking the windowType in your functions
You can prevent the continuous firing by adding a delay mobileCheck. Use a setTimeout along with a checkPending boolean value.
var checkPending = false;
$(window).resize(function(){
if (checkPending === false) {
checkPending = true;
setTimeout(mobileCheck, 1000);
}
});
See here: http://jsfiddle.net/2Q3pT/
Edit
As far as the second requirement, you could use this pattern to create or use the existing one:
mobileFunctions = mobileFunctions || function() {
// mobile functions active
};
See: http://jsfiddle.net/2Q3pT/2/
I have looked for solutions to this on google for what seems like an eternity, but I can't seem to formulate my search correctly, or nobody has posted the code I'm looking for earlier.
I am currently trying to make a function that will modify one or several margins of a div element. I want to use an if/else statement within the function, so that the onclick event will switch between the two conditions. This is what I have been working on so far;
function facebookToggle()
{
if($('#facebooktab').style.margin-left == "-250px";)
{
document.getElementById("facebooktab").style.marginLeft="0px";
}
else
{
document.getElementById("facebooktab").style.marginLeft="-250px";
}
}
I have tried twisting it around a little, like switching between "marginLeft" and "margin-left", to see if I was just using the wrong terms.. I'm starting to wonder if it might not be possible to combine jQuery and regular javascript? I don't know.. It's all just guesses on my part at this point.
Anyway, I have a div, which is now positioned (fixed) so almost all of it is hidden outside the borders of the browser. I want the margin to change onclick so that it will be fully shown on the page. And when it is shown, I want to be able to hide it again by clicking it.
I might be approaching this in the wrong way, but I really hope someone can help me out, or even tell me another way to get the same results. Thank you for any help you can give me.
You can see it in action at: http://www.torucon.no/test/
(EDIT: By the way, I am a complete javascript novice, I have no experience with javascript prior to this experiment. Please don't be too harsh, as I am aware I probably made some really stupid mistakes in this short code.)
Fixed problem:
function facebookToggle() {
var fb = $('#facebooktab'); // save reference to element
if( fb.css('margin-left') === '-250px' ) {
fb.css('margin-left', '0px');
} else {
fb.css('margin-left', '-250px');
}
}
A jQuery object doesn't have a property called style, so
if($('#facebooktab').style.margin-left == "-250px";)
// also remove this semi-colon! ^
is going to throw an error. Some options for accessing CSS properties are (1)
document.getElementById("facebooktab").style.marginLeft;
which you have correctly used, or (2)
$('#facebooktab').css('margin-left');
Consider being consistent and using the same approach for all three cases. You can assign css properties with jQuery like
$('#facebooktab').css('margin-left', '-250px');
With these things in mind, here's a suggested rewrite:
function facebookToggle() {
var fb = $('#facebooktab'); // save reference to element
if( fb.css('margin-left') === '-250px' ) {
fb.css('margin-left', '0px');
} else {
fb.css('margin-left', '-250px');
}
}
and here's another that uses a predefined CSS class:
#facebooktab {
margin-left: -250px; /** default state */
}
.no-left-margin {
margin-left: 0px;
}
function facebookToggle() {
$('#facebooktab').toggleClass('no-left-margin');
}
toggleClass
jQuery is just a JavaScript library. It is written in JavaScript and its API is in JavaScript. Your event handler could be rewritten as follows:
function facebookToggle() {
var el = document.getElementById('facebooktab');
if (el)
el.style.marginLeft = (el.style.marginLeft == '250px' ? 0 : -250) + 'px';
}
Since you are mixing jQuery with javascript, you got mixed up. Apart from what paislee's advice. you are do this too.
if($('#facebooktab')[0].style.margin-left == "-250px";){
document.getElementById("facebooktab").style.marginLeft="0px";
}
else {
var fb = document.getElementById("facebooktab");
fb.style.marginLeft="-250px";
}
I have the code below that will open a modal window. This works in IE 8 but not in Chrome or FF. I am new to the world of cross browser functionality.
function ShowModal(WindowID,FramesetID)
{
window.onscroll = function () { window.top.document.getElementById(WindowID).style.top = window.top.document.body.scrollTop; };
window.top.document.getElementById(WindowID).style.display = "block";
window.top.document.getElementById(WindowID).style.top = document.body.scrollTop;
widthv=parseInt(parseInt(screen.width)/1.50);
heightv=parseInt(parseInt(screen.height)/1.50);
window.top.document.getElementById(FramesetID).style.width=widthv;
window.top.document.getElementById(FramesetID).style.height=heightv;
}
Can anyone help in making this code Chrome & FF compatible?
I tried changing window.top to window.parent but no luck
Also, any rules to keep in mind when coding for multiple browsers (I have browsed through but didn't quite find any set of rules for cross browser compatibility)?
Update:
The issue is that in IE, this modal window appears in approximately half the screensize. In FF and Chrome, the modal window appears about the size of a dollar coin.
Depending on your browser's current rendering mode, you may need to use document.documentElement.scrollTop instead of document.body.scrollTop (and likewise for scrollLeft).
There's some good background on this problem in an Evolt article by Peter-Paul Koch (of quirksmode.org fame), but it's from 2002 and is a bit dated now.
As others here are suggesting, the easiest way to solve this kind of problem in 2011 is to just use an existing JavaScript framework. jQuery is quite popular (especially among StackOverflow users), but there are many others as well.
Another solution:
(document.documentElement.scrollTop || document.body.scrollTop)
you can use:
window.pageYOffset
If you don't see the need for unecessary third party libraries, you could try:
var scrollTop = (document.documentElement || document.body.parentNode || document.body).scrollTop;
It's hacky, but it's still better than JQuery.
I had the same issue and i checked my code for a set overflow, removing:
overflow:auto;
from another element worked
I ended up having to check every x milliseconds as a workaround. Not ideal, but it worked for me as I couldn't find any other solution. Note, this is ES6 code, so if you need to, you'll have to make it ES5 compatible manually, or use Babel.
/**
* Set the scroll top on load
* #param {int} scrollTop The scrollTop
*/
let setScrollTop = scrollTop => {
// Different browsers treat this differently, so set all
window.scrollTop = scrollTop;
window.document.body.scrollTop = scrollTop;
window.document.documentElement.scrollTop = scrollTop;
};
/**
* Jump to a page
* #param {string} selector
*/
let jumpToPage = selector => {
let i = 0;
let top = document.querySelector(selector).offsetTop;
let interval;
interval = window.setInterval(() => {
if ((document.body.scrollTop || document.documentElement.scrollTop) === top || i === 20) {
window.clearInterval(interval);
return;
}
setScrollTop(top);
i++;
}, 100);
setScrollTop(top);
};
/**
* On load
*/
window.addEventListener('load', () => {
if (condition) {
jumpToPage(selector);
}
});
I'd recommend jQuery like chrispanda has suggested. jQuery has a built in scroll event and the rest can be written in just a few lines to manipulate the html / css.
http://api.jquery.com/
Please, take a look at this code (I'm using Zepto http://zeptojs.com/ BTW)...
var timer = false;
$(window).bind('touchstart touchmove scroll', function (e) {
if (timer === false) {
timer = setInterval(function () {
$('footer').css('top', (this.pageYOffset + this.innerHeight - 40) + 'px');
console.log('Adjusted...');
}, 100);
}
}).bind('touchend', function () {
clearInterval(timer);
timer = false;
console.log('Cleaned it up...');
});
As you can see, I have a footer element that I'm trying to keep fixed on the bottom of the iPhone screen. I know that there are libraries that helps us make this quite easily like iScroll 4 http://cubiq.org/iscroll-4, but I was trying to see if I could make it simpler.
It turns out that the code above doesn't work properly. While I'm actually scrolling the page, for some reason setInterval doesn't execute but instead seems to pile up on the background to run every call at the same time.
At the end it doesn't do what I wanted it to do, which is to "animate" the footer and have it in place during scroll not only after. Does anyone has any idea on how such effect could be achieved on some similar manner?
Thanks!
When you pass a method to setInterval() (or any other function, for that matter), it will be invoked with a wrong this value. This problem is explained in detail in the JavaScript reference.
MDC docs
Inside your outer callback, this will be the DOM element you care about, but inside the setInterval callback, this will be window. Keep in mind that this is a keyword, not a variable, and that it is highly context sensitive.
The usual approach is to capture the value of this in a variable and then use that variable instead of this:
if(timer === false) {
var self = this; // "_that" is also a common name for the variable.
timer = setInterval(function () {
$('footer').css('top', (self.pageYOffset + self.innerHeight - 40) + 'px');
console.log('Adjusted...');
}, 100);
}
Similar issues apply to all callbacks in JavaScript, always make sure you know what this is and grab its value and build a closure over that value when it won't be what you want.
I was trying to make a javascript gallery script by my own.
When i have done with it i was pretty happy, until i noticed, that it doesn't work in IE6.
In FireFox everything looks fine. So i started debugging.
I noticed, that setAttribute is one of the problems for sure. Maybe even the biggest.
So after viewing an interetsing article about setting onclick property with parameters i was kind of happy, but one thing stayed unsolved for me. Using callback method is tricky, but i just don't know how to pass event object that way. Here is the old code sample:
var miniatury = document.getElementsByTagName ("a");
function zoom (){
for (l = 0; l < miniatury.length; l++) {
if (miniatury[l].className.match("zoom") != null ) {
var href = miniatury[l].href;
if (document.images) {
preImg[l] = new Image();
preImg[l].src = href;
miniatury[l].setAttribute("onclick", "przybliz(preImg["+[l]+"].src, event); event.returnValue=false; return false;");
}
else {
miniatury[l].setAttribute("onclick", "przybliz(href, event); event.returnValue=false; return false;");}
}
}
}
function przybliz(adres, event) {
pojemnik.style.display = 'block';
if (navigator.appName == "Microsoft Internet Explorer") {
pozycjaX= window.event.clientX + document.documentElement.scrollLeft
+ document.body.scrollLeft;
pozycjaY= window.event.clientY + document.documentElement.scrollTop
+ document.body.scrollTop;
}
if (navigator.appName != "Microsoft Internet Explorer") {
pozycjaX = event.clientX + window.scrollX;
pozycjaY = event.clientY + window.scrollY;
}
pojemnik.style.top = pozycjaY+'px';
pojemnik.style.left = pozycjaX+'px';
Question is:
How to change the code into
onclick = callback(f, arguments)
with passing event object values, and having the luxury to use them later ?
Well, doing it with jQuery:
$(miniatury[l]).bind("click", preImg[l], przybliz);
After which you could retrieve it in the function:
function przybliz(evt) {
var adres = evt.data;
//...
}
Without jQuery it becomes a bit more difficult, since you might have to store the value in a closure, which unless you're careful can force the whole scope chain to stay in memory (not a good thing).
The best way is to just append a handler to it. eg:
if (minitury.attachEvent) {
minitury.attachEvent("onclick", callback);
} else {
minitury.addEventListener("click", callback, false);
}
Where callback is a function with a single parameter. Like below:
function callback(evt) {
if (! evt) evt = window.event;
<insert other code here>
}
This should be what you're looking to do.
EDIT: I realized you were asking how to send parameterized callbacks. I doubt there is a good cross-browser method of doing this, but you could get around that by adding a custom attribute to the element in question which holds your data and through the event object (either evt.target or evt.srcElement) you can access the element. Make sure to follow the guidelines set by the w3c for custom attributes. w3c custom attributes
IE6 is pretty bad that way. Getting familiar with raw JS is essential, but ultimately you won't want to be bothered with making all kinds of accommodations for the little differences between browsers.
Antony Mills shows you how easy a framework (like jQuery or prototype) can make your life. Another key thing about frameworks is that they have usually thought long and hard about all of these cross browser issues so that you don't have to.