There are similar threads here discussing the fact that Firefox doesn't focus anchored elements properly, and they suggest some kind of timeout-focus etc.
focus() doesn't work with anchor link
I start from a Page URL e.g.
http://myapp.com/page#elementID
Firefox anchors elementID on page load correctly (scrolls into view), but it doesn't auto-focus elementID. I need to also focus the field.
When I add this in my jQuery Document.Ready,
$(document).ready(function() {
// Handle the possible #-Anchor
// Firefox does not focus the anchored element (Chrome does).
// Firefox workaround: If #-Anchor detected in URL, focus this element manually w/timeout
if (window.location.href.indexOf("#") != -1) {
var elementID = window.location.href.split("#")[1];
setTimeout(function() {
document.getElementById(elementID).focus();
}, 10);
}
}
then the Focus starts working, but the Anchor scroll breaks i.e. the page isn't scrolled correctly to the anchor, it gets stuck a little high.
How do I get both Anchor and Focus to work inside the Document Ready for FF?
The .focus() seems to be breaking the hash scroll to, which needs time to acheive.
A longer delay, but short enought for the user not noticing it, will do.
By the way, you could use:
if (window.location.hash != "") {
setTimeout(function() {
$(window.location.hash).focus();
}, 500);
}
Instead of:
if (window.location.href.indexOf("#") != -1) {
var elementID = window.location.href.split("#")[1];
setTimeout(function() {
document.getElementById(elementID).focus();
}, 10);
}
But that is more about code "cosmetic"...
;)
Related
I have in http://www.g3eo.com/#!/page_About the following in line 96:
<li>Side scan sonar surveys</li>
and need to create an anchor to go to line 180:
<li id="sidescan"><strong>Side scan sonar surveys</strong></li>
I understand that to get this working I would need to do:
<li>Side scan sonar surveys</li>
<li id="sidescan"><a name="sss"><strong>Side scan sonar surveys</strong></a></li>
But this does nothing. I was wondering if the problem is the hashbang in #!/page_Services, without it the web page stops working properly.
Something like this will work:
// Run the code on page load. Change this to whatever your page callback is
window.addEventListener('load', function(e)
{
// Find any of the anchors that have a hash link.
// Change document to whatever the container is for your new elements
as = document.querySelectorAll('a[href^="#"]');
as.forEach(function(a)
{
a.addEventListener('click', function(e)
{
// This stops the hash being added to the URL on click
e.preventDefault();
// Find the hash and the target element (based on ID)
var hash = e.target.href.split('#')[1];
var targetEl = document.getElementById(hash);
// Scroll the window to the target elements offsetTop
window.scrollTo(0, targetEl.offsetTop);
});
});
});
But you'll need to run this code after the content that you want to use is loaded (rather than on page load).
Basically, this simulates hash linking without adding the hash to the url. See here for a working version - https://plnkr.co/edit/mubdlfjuFTgLeYq6ZpCR?p=preview
I started working on a solution very similar to #Liam Egan's, which is good, but I thought "What if someone wants to share a link to an anchor tag? I'll just try using both a hashbang and an anchor hash in the URL!".
After multiple tests, as it turns out, it's really hard to maintain, especially if you use an external library which uses the hash. It will break, so I abandoned that idea.
Here is a solution for clicks on links, which I tested on your website:
$(function(){
$('a[href^="#"]').click(function(e){
// Get the hashes in link
var h = this.href.split('#');
// If the first hash is not a hashbang or if there are several hashes
if(h[1].indexOf('!') !== 0 || h.length > 2) {
// Prevent default behavior of the link so it does not break the site
e.preventDefault();
// If the first hash is a hashbang (but there are multiple hashes),
// only include the first one in the page URL
if(h[1].indexOf('!') === 0) { window.location.hash = '#' + h[1]; }
// Get the element with the right ID (last hash) and its scrolling container
var el = $('#' + h.pop()), cont = el.closest('div[class^="scroll"]');
// Scroll the scrolling container to that element after a delay,
// because it does not work during the page transition
setTimeout(function() {
cont.scrollTop(0) // Reset it first to get the right position below
.scrollTop( el.position().top );
},500);
}
});
});
I had to adapt it for two reasons:
Not the whole document should scroll, just your wrapping .scroll div
The scrolling won't work during page transition, so it needs a delay
It does not affect links such as #!/page_XXX, and will work with links such as #myID or #!/page_XXX#myID.
Finally, for simplicity, since you are using jQuery, I did too. Place that piece of code anywhere on your page after loading jQuery, and it should work.
I have a problem with my script.
It was working perfectly until last week, when my client talked about it.
My website has some links with an hash added to scroll smoothly to id when page is loaded. Now it doesn't scroll smoothly anymore. I did check my variables, and it gets the hash has id (e.g. #content) and also the height of the header nav.
I can't find the problem.
Here's the script:
if (window.location.hash) {
//bind to scroll function
$(document).scroll( function() {
var hash = window.location.hash;
//var hashName = hash.substring(1, hash.length);
var element;
//if element has this id then scroll to it
if ($(hash).length !== 0) {
element = $(hash);
}
//if we have a target then go to it
if (element !== undefined) {
window.scrollTo(0);
}
//unbind the scroll event
$(document).unbind("scroll");
$("html, body").animate({scrollTop: ($(element).offset().top - $('header nav ul').height()) }, 500);
});
}
Thanks in advance
Native scrollers dont work nice. Handling different browsers and mobile devices is realy difficult. Use iScroll my friend http://cubiq.org/iscroll-5 .. it works like a charm and comes with a lot of features!!!
I am using zeroclipboard to add a "copy" link to each row in a fairly large list, within a user script. To accomplish that, I using a method similar to the one listed on this page, where the ZeroClipboard.Client() element for each row is created when the user mouses over the row. This is working great in FireFox, but not in Chrome.
Also as a note: I copied the contents of the ZeroClipboard.js file into the user script itself instead of including it in an external file.
Here is the markup that creates the copy button for each element
<span style="color:blue; text-decoration:underline; cursor:pointer" id="copy_'+id+'" class="CopyLink" link="'+url+'" onmouseover="clipboard.add(this)">Copy</span>
Here is the code segment that adds the clipboard's client object:
function main(){
window.clipboard = {
load: function (){
if(!clipboard.initialized){
ZeroClipboard.setMoviePath("http://www.swfcabin.com/swf-files/1343927328.swf");
clipboard.initialized=true;
console.log("Clipboard intialized");
}
},
add: function(element){
clipboard.load();
var clip = new ZeroClipboard.Client();
console.log('Clipboard client loaded: ' + element.id);
clip.glue(element, element.parentNode);
console.log('Clipboard glued: ' + element.id);
clip.setText(element.getAttribute('link'));
console.log('Clipboard text set: ' + element.getAttribute('link'));
clip.addEventListener('complete',function(client,text) {
console.log('Clipboard copied: ' + text);//doesn't fire in chrome
});
clip.addEventListener('load',function(client) {
console.log('Clipboard loaded: ' + element.getAttribute('link'));
});
}
}
//other code in user script including injecting above markup
//as well as contents of ZeroClipboard.js
window.ZeroClipboard = { ... }
}
var script = document.createElement("script");
script.appendChild(document.createTextNode('('+main+')()'));
(document.head || document.body || document.documentElement).appendChild(script);
In this block, every console.log fires in FireFox when I mouse over and click the copy span, but in chrome, all except the 'complete' listener fire. I was able to verify that ZeroClipboard is working in my Chrome by using the example on this page. I am also able to verify that the flash object is being added to the page in the correct location, but it is simply not responding to a click.
Since the zeroclipboard code is no longer being maintained according to the site, I'm hoping someone out there can help me out. I'm thinking there is possibly some issue with dynamically adding the embedded flash objects in chrome on mouseover, or perhaps some difference between user scripts in chrome vs firefox with greasemonkey? Any help would be greatly appreciated, thanks
I'm not sure the reason behind it but I have been running into this on Chrome as well. I had two zeroclipboard implementations, one that was visible on page load, and one that was only visible when the user opened a dialog. The one that was visible on page load worked as expected, but the other one didn't. In order to "solve" the issue, I had to render the zeroclipboard link, set its absolute position to be off the screen (-500 px), then add some javascript to move the link into place when the dialog opens. This is an ugly solution but I think is the only way to get it to work in Chrome. Your case is particularly hairy since you have lots of dynamic zeroclipboards on your page whereas I only had one, but it seems to me that there's no reason this won't work for you.
<!-- <script type="text/javascript" src="http://davidwalsh.name/demo/ZeroClipboard.js"></script> -->
function copyText(fieldName,buttonName){
var fieldNameTemp =fieldName;
var buttonNameTemp =buttonName;
var val = "";
try{
val = navigator.userAgent.toLowerCase();
}catch(e){}
var swfurl = "js/ZeroClipboard.swf";
setTimeout(function () {
ZeroClipboard.setMoviePath(swfurl);
var clip = new ZeroClipboard.Client();
clip.addEventListener('mousedown', function () {
clip.setText(document.getElementById(fieldNameTemp).value);
});
clip.addEventListener('complete', function (client, text) {
try{
if(val.indexOf("opera") > -1 || val.indexOf("msie") > -1 || val.indexOf("safari") > -1 || val.indexOf("chrome") > -1){
alert('Your text has been copied');
}
}catch(e){
alert('Please alert not use on fireFox');
}
});
clip.glue(buttonNameTemp);
}, 2000);
}
If you go to a page a and scroll around then refresh the page will refresh at the spot where you left it. This is great, however this also occurs on pages where there is a anchor location in the url. An example would be if you clicked on a link http://example.com/post/244#comment5 and refreshed the page after looking around you would not be at the anchor and the page jumps around. Is there any way to prevent this with javascript? So that no-matter-what you would always navigate to the anchor.
On Chrome, even if you force scrollTop to 0 it will jump afterwards after the first scroll event.
You should bind the scroll to this:
$(window).on('beforeunload', function() {
$(window).scrollTop(0);
});
So the browser is tricked to believe that it was on the beginning before the refresh.
To disable automatic scroll restoration just add this tag to head section.
<script>history.scrollRestoration = "manual"</script>
Supported by all modern browsers
After number of failures finally I managed to do the trick. anzo is correct here as using beforeunload will make the page jump to top when a user reloads the page or clicks a link. So unload is the clearly way to do this.
$(window).on('unload', function() {
$(window).scrollTop(0);
});
Javascript way(Thanks ProfNandaa):
window.onunload = function(){ window.scrollTo(0,0); }
EDIT: 16/07/2015
The jump issue is still there with Firefox even with unload event.
This solution is no longer recommended due to changes in browser behavior. See other answers.
Basically, if an anchor is used we bind to the windows scroll event. The idea being that the first scroll event has to belong to the automatic repositioning done by the browser. When this occurs we do our own repositioning and then remove the bound event. This prevents subsequent page scrolls from borking the system.
$(document).ready(function() {
if (window.location.hash) {
//bind to scroll function
$(document).scroll( function() {
var hash = window.location.hash
var hashName = hash.substring(1, hash.length);
var element;
//if element has this id then scroll to it
if ($(hash).length != 0) {
element = $(hash);
}
//catch cases of links that use anchor name
else if ($('a[name="' + hashName + '"]').length != 0)
{
//just use the first one in case there are multiples
element = $('a[name="' + hashName + '"]:first');
}
//if we have a target then go to it
if (element != undefined) {
window.scrollTo(0, element.position().top);
}
//unbind the scroll event
$(document).unbind("scroll");
});
}
});
This works for me.
//Reset scroll top
history.scrollRestoration = "manual"
$(window).on('beforeunload', function(){
$(window).scrollTop(0);
});
Here's a a more general approach. Instead of trying to prevent the browser from scrolling (or jumping to the top as it would look like) I just restore the previous position on the page.
I.e. I'm recording the current y-offset of the page in localStorage and scroll to this position once the page has loaded.
function storePagePosition() {
var page_y = window.pageYOffset;
localStorage.setItem("page_y", page_y);
}
window.addEventListener("scroll", storePagePosition);
var currentPageY;
try {
currentPageY = localStorage.getItem("page_y");
if (currentPageY === undefined) {
localStorage.setItem("page_y") = 0;
}
window.scrollTo( 0, currentPageY );
} catch (e) {
// no localStorage available
}
You can just put a # at the end so the page will load at the top.
Works on all browsers, mobile and desktop, because it is so simple.
$(document).ready(function() {
var url = window.location.href;
console.log(url);
if( url.indexOf('#') < 0 ) {
window.location.replace(url + "#");
} else {
window.location.replace(url);
}
});
// This loads the page with a # at the end.
this works absolutely fine. Nice and clean javascript
var objDiv = document.getElementById("chatbox");
if ( window.history.replaceState ) {
objDiv.scrollTop = objDiv.scrollHeight;
window.history.replaceState( null, null, window.location.href );
}
You should be able to.
Onload, check if window.location.hash has a value. If it does, grab the element with an id that matches the hash value. Find the position of the element (recursive calls to offsetTop/offsetLeft) and then pass those values into the window.scrollTo(x, y) method.
This should scroll the page to the desired element.
There is a tree menu in my application and on click of the menu items, it loads a url in a iFrame. I like to set the focus in an element of the page loaded in the iFrame.
I'm using this code, and it works perfectly in all the browsers except IE:
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').focus();
I have tried all different options like using setTimeout, but no chance.
After the page loads, when I hit the tab key, it goes to the second input, which means it's been on the first input, but it doesn't show the cursor!
I am using ExtJS and the ManagedIFrame plugin.
Any help is appreciated.
You need to call the focus() method of the iframe's window object, not the iframe element. I'm no expert in either jQuery or ExtJS, so my example below uses neither.
function focusIframe(iframeEl) {
if (iframeEl.contentWindow) {
iframeEl.contentWindow.focus();
} else if (iframeEl.contentDocument && iframeEl.contentDocument.documentElement) {
// For old versions of Safari
iframeEl.contentDocument.documentElement.focus();
}
}
Is the iFrame visible onload, or shown later? The elements are created in different order which is the basis of the setTimeout approach. Did you try a high value wait time on a set timeout?
Try something like at least a half second to test...IE tends to do things in a different order, so a high timeout may be needed to get it not to fire until render/paint finishes:
$(function(){
setTimeout(function() {
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').focus();
}, 500);
});
Difficult to troubleshoot without a working example, but you might try hiding and showing the input as well, to force IE to redraw the element.
Something like:
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').hide();
var x = 1;
myIFrame.contents().find('#inputName').show().focus();
This might jolt IE into displaying the cursor.
I could get IE to focus an input field in an iframe with:
iframe.focus();
var input = iframe...
input.focus();
iframe.contentWindow.document.body.focus();
input.focus();