I am trying to create a "skip navigation" link without being able to use anchors. The site is built in a peculiar way, where anchor link formatting has been re-purposed. So, I am attempting to allow people to skip the navigation by using focus. However, it isn't working.
HTML code for the skip navigation link itself:
<!-- Start Top Left in Nav Bar -->
<aside>
Skip Navigation
</aside>
<!-- End Top Left in Nav Bar -->
Code to Change the Focus
var nav = document.getElementById('#skipNav');
nav.onclick=skipNav();
function skipNav(){
document.activeElement.blur();
if ($('#linkHome').hasClass('current')==true)
{
$('#homeFocus').focus();
}
if ($('#linkTeam').hasClass('current')==true)
{
$('#teamFocus').focus();
}
if ($('#linkTraining').hasClass('current')==true)
{
$('#trainingFocus').focus();
}
if ($('#linkTesting').hasClass('current')==true)
{
$('#testingFocus').focus();
}
if ($('#linkRemediation').hasClass('current')==true)
{
$('#remediationFocus').focus();
}
if ($('#linkContact').hasClass('current')==true)
{
$('#contactFocus').focus();
}
};
Script to Change Pages and Mark Current Page
var FluidNav = {
init: function() {
$('a[href*="#"]').click(function(e) {
e.preventDefault();
if($(this).attr("href").split("#")[1]) {
FluidNav.goTo($(this).attr("href").split("#")[1]);
}
});
this.goTo("home");
},
goTo: function(page) {
var next_page = $("#"+page);
var nav_item = $('nav ul li a[href=#'+page+']');
$("nav ul li").removeClass("current");
nav_item.parent().addClass("current");
FluidNav.resizePage((next_page.height() + 40), true, function() {
$(".page").removeClass("current"); next_page.addClass("current");
});
$(".page").fadeOut(500);
next_page.fadeIn(500);
document.activeElement.blur();
$('#'+page+'Focus').focus();
FluidNav.centerArrow(nav_item);
},
centerArrow: function(nav_item, animate) {
var left_margin = (nav_item.parent().position().left + nav_item.parent().width()) + 24 - (nav_item.parent().width() / 2);
if(animate != false) {
$("nav .arrow").animate({
left: left_margin - 8
}, 500, function() { $(this).show(); });
} else {
$("nav .arrow").css({ left: left_margin - 8 });
}
},
resizePage: function(size, animate, callback) {
if(size) { var new_size = size; } else { var new_size = $(".page.current").height() + 40; }
if(!callback) { callback = function(){}; }
if(animate) {
$("#pages").animate({ height: new_size }, 400, function() { callback.call(); });
} else {
$("#pages").css({ height: new_size });
}
}
};
$("nav select").change(function() {
if(this.options[this.selectedIndex].value != "#") {
var page = this.options[this.selectedIndex].value.split("#")[1];
FluidNav.goTo(page);
$("html,body").animate({ scrollTop:$('#'+page).offset().top }, 700);
}
});
Any ideas?
Sounds like you're trying to do a 'dynamic skiplink', where you determine the target at runtime?
Skip Navigation
The problem is that when you click a link, navigation happens. A href="" doesn't prevent navigation, it just means that you end up navigating to the current page - and that's going to reset the focus. This happens after your click event handler. So even though you may correctly set the focus where you want to, it ends up being 'lost' when the page reloads.
There's a couple of ways to prevent this: one is to use href="javascript:void(0)" - href specifies where to navigate, and if it evaluates to void, the browser won't navigate at all.
A somewhat cleaner way is to tell the browser not to carry out the default action in the event handler:
function skipNav(e)
{
e.preventDefault(); // prevent default action - link navigation - from taking place
...
--
Couple of other issues with the code:
Don't bother with role="link" on the A - save these attributes for when you are doing something out of the ordinary. The key thing to know is that screenreaders already know how to deal with all the standard HTML elements when they are used in a standard way. So if you are using an as a link, or a as a button, then you don't need to add a role.
But if you are creating a new control of of plain DIVs, or if you are repurposing a HTML element for a different use, then you need a role attribute to tell the screenreader how you are actually using the element.
For example, a DIV that's had an onclick handler and is behaving like a button would need role="button", otherwise a screenreader might ignore it or just say something generic like 'element'. Or if you are creating a button from an A tag, and it ends up behaving like and looking like a button from a user's point of view, then you'd need role="button" so that a screenreader will announce it as a button rather than as a link.
--
Watch for mixing plain DOM vs jQuery conventions - only jQuery uses # to find elements by ID, so use either:
var nav = document.getElementById('skipNav'); // plain DOM way, no #
or
var nav = $('#skipnav'); // jQuery way using selector
--
Watch for functions as values vs calls:
nav.onclick=skipNav();
This will actually call skipNav(), and assign the return value - null! - to onclick. Don't use ()'s when you're setting a callback. You don't need this code anyhow, since you're setting the handler using onClick in the tag anyhow.
Also, note that as your code stands, when skipNav() is called, it tries to call document.activeElement.blur() - but at that point in time - document is still loading - there's no activeElement, so calling blur() on null generates an exception - which you should see in your browser's console/debugging window.
--
Don't use .blur() - there's no need to do this:
document.activeElement.blur();
Instead, just focus the element you want to have focus. The danger with doing .blur() is that if the code after it fails to set the focus somewhere reasonable, focus will end up getting 'lost', which is very inconvenient for a keyboard user, since they have to tab from the start of the page.
--
Javascript coding practice: don't bother with == true in the if() expressions; and unless you expect you expect more than one of the elements to have the 'current' class, use else if instead of plain if: this makes it clear in the code that you're expecting only one branch to be used.
--
Finally, make friends with the browser's debugger (F12 in most): you'll learn some of the above by putting breakpoints in the event handler and your initialization code, and stepping through it to ensure it's behaving as you expect.
Related
I want to open different pages from a popup-selector menu in Tizen.
I have 8 menu items and each should open a different page in the same HTML using the active-ui-page class.
I tried doing it using the code mentioned here.
But then when I transfer back to the selector, them indicator-name doesn't change.
Please help me on this.
Try to make sure you are not closing the popup or destroying the Selector. In such way your selector is may be getting nonfunctional. tau.closePopup() will close the popUp window, thus selector won't appear back.
elSelector.addEventListener("click", function(event) {
var target = event.target;
if (tau.support.shape.circle) {
if (target.classList.contains("ui-selector-indicator")) {
tau.closePopup(popupCircle); //**comment out this line**//
//your code
}
}
});
selector.destroy() destroys & removes event listener, which might be the case in your situation, that's why indicator-name isn't changing.
selector.destroy(); //**comment out this line**//
Vice versa for solution try calling the popUp window again using tau.openPopup() :
if (tau.support.shape.circle) {
tau.openPopup(popupCircle);
}
otherwise call the selector again with tau.widget.Selector()
if (tau.support.shape.circle) {
var radius = window.innerHeight / 2 * 0.8;
selector = tau.widget.Selector(elSelector, {itemRadius: radius});
}
Code souce : 'TAUUIComponents' (Tizen Sample Web app)
Thank you.
I have a onepager site where I use scrollmagic plus all its necessary plugins/libraries (and jQuery) for different effects where animation, pinning, fading processes etc. are triggered by scroll positions.
I also use it for animated scrolling to the anchor points on the page (from the menu and from other local links) - see the according part of the script below.
The problem is that this script suppresses the default behaviour of "jumping" directly to an anchorpoint when a local link is clicked, and apparently also when the page is accessed from outside via a direct link or bookmark with an anchor appended to the URL (like http://www.example.com/index.php#part3). Altough this behaviour is desired when clicking a local link, it obviously prevents the browser from displaying the anchor position when an anchor is linked from somewhere else.
Is there any way to make the browser directly display that anchor position when a link like in the above example is clicked?
var sm_controller_1 = new ScrollMagic.Controller();
sm_controller_1.scrollTo(function(anchor_id) {
TweenMax.to(window, 2.0, {
scrollTo: {
y: anchor_id
autoKill: true
},
ease: Cubic.easeInOut
});
});
jQuery(document).on("click", "a[href^=#]", function(e) {
var id = jQuery(this).attr('href');
if(jQuery(id).length > 0) {
e.preventDefault();
sm_controller_1.scrollTo(id);
if (window.history && window.history.pushState) {
history.pushState("", document.title, id);
}
}
});
(It doesn't make sense to create a fiddle/codepen since the problem lies in calling the original URL from an external source).
Well assuming scroll magic doesnt have extra functionality that is not posted here that would get in the way of my answer you could try this:
Add a data-attribute to your links which you want to use default behavior:
<a href="example.com/index.php#part3.php" data-default="true">
Check if that data attribute exists and if it does return true in your click handler to continue with the default behavior:
var sm_controller_1 = new ScrollMagic.Controller();
sm_controller_1.scrollTo(function(anchor_id) {
TweenMax.to(window, 2.0, {
scrollTo: {
y: anchor_id
autoKill: true
},
ease: Cubic.easeInOut
});
});
jQuery(document).on("click", "a[href^=#]", function(e) {
if(e.currentTarget.dataset.default){
return true;
}
var id = jQuery(this).attr('href');
if(jQuery(id).length > 0) {
e.preventDefault();
sm_controller_1.scrollTo(id);
if (window.history && window.history.pushState) {
history.pushState("", document.title, id);
}
}
});
You can try and use this code:
jQuery(function ($) {
$(document).ready(function() {// if needed, use window.onload which fires after this event
if(window.location.hash) {
var hash = window.location.hash;
$( 'a[href=' + hash + ']' ).click();
}
});
});
It will wait till the DOM (or the page) is loaded and then simulate the user click on the nav item.
After I've read your question one more time, I am not sure anymore if you want your page loaded on the position of the element which is listed in the anchor or the scroll wasn't working when coming from an external source?
If the scroll was working but you wanted to display the page at the right place, like a jump, then I propose 2 solutions:
a) use the CSS opacity:0; on the body and after the scroll is finished, set it back to opacity:1;
b) try to jump on the proper place on the page before you load ScrollMagic
Several problems:
1) I am trying to make this script run more efficiently.
2) When the user clicks either pop out button it opens a windows and hides the element. (Currently I am using .detach() to remove the embedded video player because in Firefox .toggle() just hides the player but keeps the audio playing. Is there a better way to do this?
3) In theory by clicking the button again or closing the window manually it should un hide or .toggle() the element but does not for the video player due to detach().
4) If a user pops out the window manually closes it and then pops it out again to only close it once more the element does not .toggle() back.
See it in action here, http://www.mst3k.tv/.
$(document).ready(function() {
$('#lights').click(function(){$('#darkness').fadeToggle(500);});
$("#lights").toggle(function(){$("#lights").attr('id','lightsoff');},function(){$("#lightsoff").attr('id','lights');});
/**VIDEO**/
var videoWin;
$('#video-toggle').click(function(){
$('#video').fadeToggle(500);
$('#video').detach();
});
$('#video-toggle').click(function(){
if (videoWin && !videoWin.closed) {
videoWin.close();
return false;
}
videoWin = window.open(
$(this).attr('rel'),
'videoWin',
'width=600,height=480,toolbar=0,top=0,left=0,menubar=0,location=0,status=0,scrollbars=0,resizable=1');
return false;
}
);
var watchVideo = setInterval(function() {
if (videoWin.closed) {clearTimeout(watchVideo);$('#video').show(500)}
return false;
}, 1);
/**CHAT**/
var chatWin;
$('#chat-toggle').click(function(){
$('#chat').fadeToggle(500);
/*$('#chat').detach();*/
});
$('#chat-toggle').click(function(){
if (chatWin && !chatWin.closed) {
chatWin.close();
return false;
}
chatWin = window.open(
$(this).attr('rel'),
'chatWin',
'width=320,height=480,toolbar=0,top=0,left=601,menubar=0,location=0,status=0,scrollbars=0,resizable=1');
return false;
}
);
var watchChat = setInterval(function() {
if (chatWin.closed) {clearTimeout(watchChat);$('#chat').show(500)}
return false;
}, 1);
/*$("a.btn").fitText(1.2, { minFontSize: "6px", maxFontSize: "14px" });*/
});
It would be better if you created a jQuery plugin for your code so you can re-use it and avoid DRY. Here are a couple of options:
Plugin 1: jQuery popupWindow
Plugin 2: jQuery winPop
Also note that the closed property is not part of any W3C specification, however it might be supported across Browsers.
You could also write a JS function that could be reused. According to the w3cschools website the window.closed property is supported in most major browsers and you can check for it prior to triggering the event.
instead of
if(videoWin && !videoWin.closed)
you could use
if (typeof videoWin!='undefined'){ /* it has been created */}
elseif(typeof videoWin='undefined') { /*it's okay to open the new window*/}
Make sure you're not creating the variable if you're using this as a check though until the window open event has been fired. Since you're creating the var a couple of lines above your function declaration it will always return as defined.
You'll need to specify a target object in your function to have it throw multiple windows correctly... meaning you can't declare one var for multiple windows. Maybe a class would be better.
Something I thought was odd earlier but forgot to mention before FB posted my response prematurely was that you're adding your href in the rel attribute and specifying the href as a js:void(0) which is also non-standard. The rel attribute is for specifying the relationship between the link and the page... (eg. rel=nofollow). That might also be why it's not firing and misfiring some of the time as well, and the differences between browser response.
I have no idea how I should even call this problem … the title of this question doesn't make any sense at all, I know!
Following case: I have a single-page layout where users scroll downwards. I have sections .layer which, when inside the viewport should change the hash in the addressbar to its id. So e.g. the .layer#one is inside the viewport the url in the addressbar looks like this www.whatever.com/#!/one
$(window).scroll(function() {
hash = $('.layer:in-viewport').attr('id');
top.location.hash = "!/" + hash;
});
This works just fine and is exactly like I want it. The reason I have this syntax with the !/ is that if I would simply set the location to hash only the scroll-behaviour would be buggy because the browser tries to stick to the hash position.
The problem is now, that I want to be able to make browser history-back button working!
This would normally be rather simple with the hashchange function that comes with jQuery like so…
$(window).bind( 'hashchange', function( event ) {
//query the hash in the addressbar and jump to its position on the site
});
The only problem I have with this is that the hashchange function would also be triggered if the hash is changed while scrolling. So it would again jump or stick to the current position in the browser. Any idea how I could solve this? I could probably unbind the hashchange while scrolling, right? But is this the best solution?
Sure, you could just unbind and rebind whenever the hash changes on scroll. For example:
var old_hash;
var scroller = function() {
hash = $('.layer:in-viewport').attr('id');
if ( old_hash != hash ) {
$(window).off('hashchange', GoToHash); // using jQuery 1.7+ - change to unbind for < 1.7
top.location.hash = "!/" + hash;
setTimeout(function() { // ensures this happens in the next event loop
$(window).on('hashchange', GoToHash);
}, 0);
old_hash = hash;
}
}
var GoToHash = function() {
//query the hash in the addressbar and jump to its position on the site
}
$(window).scroll(scroller);
Using Jquery, I've managed to make a dropdown login form triggered by clicking a button. However, I am also trying to change the direction of the arrow next to it by replacing the src image, and it appears to do nothing.
$("#login_panel").slideToggle(200).toggle(
function() { $("#arrow").attr('src', '/src/east.gif';) },
function() { $("#arrow").attr('src', '/src/south.gif';) }
);
This can be seen at:
http://dev.mcmodcenter.net (The 'Login' button)
$(document).ready(function() {
$("#login_panel").slideToggle(200).toggle(
function() { $("#arrow").attr('src', '/src/east.gif';) },
function() { $("#arrow").attr('src', '/src/south.gif';) }
);
for (var i = 0; i < 2; i++) {
$(".mod").clone().insertAfter(".mod");
}
$(".mod").lazyload({
effect: "fadeIn"
});
});
You can directly access this.src - no need to create a new jQuery object for that:
$('#arrow').toggle(
function() { this.src = '/src/south.gif'; },
function() { this.src = '/src/east.gif'; }
);
And if you prefer to do it via .attr() at least use $(this) (DRY - don't repeat yourself - in this case, don't specify the selector more often than necessary)
$("#arrow").toggle(
function(){$("#arrow").attr("src", "/src/south.gif");},
function(){$("#arrow").attr("src", "/src/east.gif");}
);
You left off the "#" in the handler functions. By just referring to "arrow", you were telling jQuery to look for (presumably absent) <arrow> tags.
Now, as to the larger situation, what you're setting up there is something that'll make the image change when the image itself is clicked. Your description of your goal makes me think that that's not quite what you want, but it's hard to tell. If you want some other element to control the changes to the image, then you'd attach the handler(s) elsewhere.
Is the image you want to change that little black arrow next to the login button? If so, then what should happen is that the code to set the image should be added to the existing handler that slides the login form up and down. (By the way, in Chrome the login box shows up in what seems like an odd place, far to the left of the button.)
looks like you forget to put the # before the arrow in $("arrow")
it should be like this
$("#arrow").toggle(
function(){$("#arrow").attr("src", "/src/south.gif");},
function(){$("#arrow").attr("src", "/src/east.gif");}
);
$("arrow") will match <arrow>, you lost the #
Also, the toggle method does not take two functions as its arguments, it works in a completely different way to what you are trying to do with it. Yes, it does, there are two different toggle methods for jQuery (insert rant about awful API design)
And now you have completely edited the code…
Your code now immediately assigns strings to the this.src (where this is (I think) the document object), and then passes those two strings as arguments to the toggle method (which are not acceptable arguments for it)
And now you have completely edited it again…
This code should work:
$('#login_button').click(function() {
$(this).find('#arrow').attr('src', function(i, v) {
return v.indexOf('east.gif') < 0 ? '/src/east.gif' : '/src/south.gif';
});
$('#login_panel').slideToggle(200);
});