I need to open a window after the dom is loaded, and scroll the y position to the element, preferably centered on the screen. I looked on stack overflow and I put something together with the bits i found.
The problem with this is that it's using a timer to see my element is available, and it is really slow - altering the interval time does not effect the speed at all. Also, it does not work in IE and i need it to. thought on this?
linkToComment: function(e){
var link = 'https://****';
var commentId = 21
var w = window.open(link);
var interval = setInterval(function(){
if ( $(w.document.body).find("div[data-commentoriginalid=" + commentId + "]")) {
$(w.document.body).animate({
scrollTop: ( $(w.document.body).find("div[data-commentoriginalid=" + commentId + "]").offset().top)
},500);
clearInterval(interval);
}
}, 500)
},
Try this instead of the interval:
$(w.document).ready(function () {
$(w.document.body).animate({
scrollTop: ( $(w.document.body).find("div[data-commentoriginalid=" + commentId + "]").offset().top)
},500);
});
but I don't understand why would you make this scroll from the parent window, instead of adding the javascript to the opened window...
Do you have access to the code/source in the child window? If I was doing this, I would add an onload handler in the child window, rather than trying to control it from the parent. If you need to pass in a variable to the child from the parent, you could either use a querystring or a hash parameter.
e.g. mysite.com#2345
And then pick that id up in the child window, select the element with that ID and scroll to it.
Remember - the parent window could be closed by the user while the child window is opening meaning the timer would be killed.
Related
I'm developing a website which involves the user being able to navigate to different parts of a page from other pages using # values in the address bar.
I have written a jQuery function to handle the scrolling here:
jQuery.fn.scrollToDiv = function(navheight)
{
if (!navheight)
{
navheight = 30;
}
var offset = this.offset();
var offsetTop = offset.top;
var totalScroll = offsetTop-navheight-27;
$('body,html').animate({
scrollTop: totalScroll
}, 500);
}
And I am calling the function in 2 different scenarios; when the user clicks a link where the object is on the current page, and when the user clicks a link that takes them to another page before scrolling to the element. See below:
When you are on the page:
$('.gotoPage').on('click', function(e)
{
e.preventDefault();
var sPath = window.location.pathname;
var sPage = sPath.substring(sPath.lastIndexOf('/') + 1);
if (sPath != '' && sPath != 'home')
{
var href = $(this).attr('href');
handleScroll(href);
}
});
and when you are not on the page:
$(document).ready(function(e)
{
var target = window.location.hash;
if (target != '')
{
$(target).scrollToDiv(30);
}
});
It works perfectly when you are on the page and click the link, however when you're not on the page, it takes you to the subsequent page as you'd expect but it doesn't then scroll to the required element.
Let me know if you need any more information
Thanks in advance
EDIT: Added function handleScroll(target)
function handleScroll(target)
{
if (target != '')
{
$(target).scrollToDiv(30);
}
}
Following your comment:
I've noticed when refreshing the page is that it scrolls down then
jumps back to the top of the page
It seems that your script does work, but something affecting it afterwards.
I believe that there are some resources as additional css codes or images that aren't being taken in account when the scroll animation takes effect and since that function works by top offset - you must be sure that you're using it after all the resources that might affect the document's height or element's offset, are being loaded.
Therefore, instead of using your script in .ready(), use .load().
.ready() vs. .load()
In most cases, the script can be run as soon as the DOM hierarchy has
been fully constructed. The handler passed to .ready() is guaranteed
to be executed after the DOM is ready, so this is usually the best
place to attach all other event handlers and run other jQuery code.
In cases where code relies on loaded assets (for example, if the
dimensions of an image are required), the code should be placed in a
handler for the load event instead.
I have an HTML page with 2 iframes within it. I want each iframe to display the Y scroll offset of the parent window. One iframe works on page load, the other does not.
The parent HTML page just has the iframe embeds. Here is the code running in the iframe:
function run(){
document.write("<div id='scrollY' style='float:left;'></div><br>");
scrollY = 'no';
document.getElementById("scrollY").innerHTML = scrollY;
window.parent.onscroll = function(){
scrollY = window.parent.pageYOffset;
document.getElementById("scrollY").innerHTML = scrollY;
}
}
run();
The result on load and a scroll downwards will display something like:
iframe1 = 100
iframe2 = no
Can I only call window.parent.onscroll once? This doesn't seem right to me.
This is happening because in both frames, window.parent makes reference to the same window object, and you are setting the onscroll property/event on the same object, twice. This means that the second time around you set the window.parent.onscroll property, you're actually overwriting the first attempt to set the event, and you're overwriting it with the second frame's window.document object, which is why it only updates the contents of the elements in the second frame.
To overcome this issue, you can simply just use addEventListener instead of onscroll:
http://jsfiddle.net/x046o0p7/
function run() {
document.write("<div id='scrollY' style='float:left;'></div><br>");
scrollY = 'no';
document.getElementById("scrollY").innerHTML = scrollY;
window.parent.addEventListener('scroll', function() {
scrollY = window.parent.pageYOffset;
document.getElementById("scrollY").innerHTML = scrollY;
});
}
addEventListener allows you to set multiple events of the same type for the same element, while the .onstuff listeners don't.
I have some tabs on my page, and inside one tab of that page I have an iframe (#quiz_iframe).
This iframe is quiz frame, which is contained in a div (.quiz-div). After hitting a button (.start-quiz), quiz is loaded, and new div (.quiz-content) appears inside (.quiz-div).
In quiz content I have 20 another divs (.quiz-question), which are paginated, so after clicking a button next, prev, you can hide or show 5 next/prev divs.
Well the point is, I'd like to adjust iframe height to that content and I don't know how, after clicking .start-quiz.
Now I have a code which works fine, when the iframe is loaded for the first time (it adjust height to the laoded content)
function iframeLoaded() {
var iFrameID = document.getElementById('quiz_iframe');
if(iFrameID) {
iFrameID.height = "";
iFrameID.height = iFrameID.contentWindow.document.body.scrollHeight + "px";
}
}
<iframe onload="iframeLoaded()" id="quiz_iframe" src="'.$link.'" style="width:100%;"></iframe>'
How I can modify that code, to update iframe height on every .quiz-div height change? And yes, iframe is in the same domain :)
Thanks!
You can use a solution based on postMessage
You'll have to include some JavaScript in the iframe and on the parent page as well.
In your iframe :
window.addEventListener("load", function() {
parent.postMessage(getDocumentHeight(), "*");
});
In your parent page :
function receiveIframeHeight(frameWindow, height) {
$("iframe").each(function () {
if (this.contentWindow === frameWindow) this.height = height;
});
};
window.addEventListener("message", function (e) {
receiveIframeHeight(e.source, e.data);
});
You can now listen to the resize event and postMessage from your iframe to the parent page. But beware of infinite loop.
To see the whole code you should take a look at this Github repo iframe-autoheight-using-postmessage
In jQuery, you could use
$("myContainer .quiz_div").on("resize", function () {
$("#quiz_idrame").attr("height", your height calc goes here);
});
The "on" is a delegated event binding and thus if you add/remove items with the class of .quiz_div to the "myContainer" i.e. whatever contains the divs, it should bind.
I am new to jQuery, I built this page and what I would like to happen is when a block e.g. 2011 1 October reaches the top of the page it displays the content for that specific div via the id or date-attr.
When you click on a date it will display the content for that date but I would like it to appear once that date block reaches the top of the page.
I have looked around the net but no luck thus far.
Use scroll event to make checks for divs you are interested in - assing class for them for instance.
http://api.jquery.com/scroll/
In that event callback you can check each elements position
http://api.jquery.com/each/
To determine position element on page use
http://api.jquery.com/offset/ - top component
But don't take this value - you need to substract Window scroll position which is returned by
$(window).scrollTop()
And make some border values when element should be opened and when closed.
As per your description that I understood, you will have to add one line of code to your "main.js" file.
// javascript + jquery scripts
// script for fading in content boxes -->
$(".square").on("click", function() {
var id= $(this).attr("contentId");
//$("#details");
$('#details').fadeOut('slow', function() {
$(this).html($("#" + id).html()).fadeIn('fast');
});
});
// active link -->
$(".square").click(function() {
$(".square").removeClass("active");
$(this).addClass("active");
$("html, body").scrollTop($(this).position().top); // THIS IS THE LINE TO BE ADDED TO SCROLL TO THE CURRENT DATE ITEM
});
// fade in main content div / intro
$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 10) {
$('.topBlock').fadeOut();
} else {
$('.topBlock').fadeIn();
}
});
// hide intro text onClick on list
$( "li" ).click(function() {
$( ".topBlock" ).hide().animate();
});
var viewportHeight = $(window).height();
//$j(".parallax_section_holder").css("height",$j(window).height()-116);
//alert(viewportHeight);
I hope I have solved your issue, and if not, then please provide me the exact code link in jsfiddle.
Regards.
I have an iframe inside which i detect a right click and pass the mouse event to a function in the parent. Here, (inside the parent function), i have the logic to display a custom context menu and the context menu html markup is inserted into the parent DOM. Thus is need the mouse position according to the viewport (or the parent DOM), but what i received is relative to the iframe.
I tried using offsetTop and offsetParent, but this iterated only till the body tag of the innerpage.
This is the function I used:
// Define class that will hold Object coordinates
function CTopLeft(i_nTop, i_nLeft) {
this.nTop = i_nTop;
this.nLeft = i_nLeft;
}
function GetTopLeftFromIframe(i_oElem) {
var cTL = new CTopLeft(0, 0);
var oElem = i_oElem;
var oWindow = window;
do {
cTL.nLeft += oElem.offsetLeft;
cTL.nTop += oElem.offsetTop;
oElem = oElem.offsetParent;
if (oElem == null) { // If we reach top of the ancestor hierarchy
oElem = oWindow.frameElement; // Jump to IFRAME Element hosting the document
oWindow = oWindow.parent; // and switching current window to 1 level up
}
} while (oElem)
return cTL;
}
This is from http://codecorner.galanter.net/2012/02/26/absolute-coordinates-of-element-inside-of-iframe/
You can get the top and left by calling the iframe from the parent document. Say your iFrame has the id 'my_iframe' in the parent document:
offset_left = parent.document.getElementById('my_iframe').offsetLeft;
offset_top = parent.document.getElementById('my_iframe').offsetTop;
BUT this will only work if the content in the iFrame belongs to the same origin (same host, port and protocol)!
Edit: also found this similar question on bytes.com: iframe relative mouse position
The Yuriy solution works well until the element is a child of an element with position:absolute and that is scrolled. (I was looking for the element position rather than mouse, but I'm sure you could modify this to work for that too)
My fix :
function iframe_offset(e){
var x=e.getBoundingClientRect().x
,y=e.getBoundingClientRect().y
,w=e.ownerDocument.defaultView
do{
e = e.offsetParent
if(e == null){
e = w.frameElement
w = w.parent
if(e){
x += e.offsetLeft+e.scrollLeft
y += e.offsetTop+e.scrollTop
}
}
}while(e)
return {x:x,y:y}
}
At least now (probably before also), you have a lot of coordinates on the event object (layerX, screenX, etc.) that mean that you might be better to just use one of those sets if you can, to avoid this sort of extra calculation - it simplified things in my use case quite considerably to use screenX/screenY as a base rather than try and calculate, and did the trick.