In the following example, I use checkbox for making a pure CSS dropdown navigation, also available in this jsFiddle example.
Open that fiddle, click "Menu", click "Link 1", and click the "Back" button on the browser toolbar, as you can see the checkbox remains checked, so the navigation is still open.
My question is - would it be possible to reset that checkbox to unchecked automatically when going back from the browser history? Any suggestions please? Do I need to use Javascript/jQuery?
HTML
<label for="m">Menu</label>
<input id="m" type="checkbox">
<nav id="n">
<ul>
<li>Link 1</li>
</ul>
</nav>
CSS
#n {
display: none;
}
#m:checked ~ #n {
display: block;
}
No need for JS or CSS, just add autocomplete="off" to the checkbox. This will prevent the browser from caching the 'checked' status.
Example: https://jsfiddle.net/6g5u8wkb/
Also, if you have multiple checkboxes, I beleive you can add autocomplete="off" to the form element to apply the effect to all inputs fields.
Try adding something like this:
$( document ).ready(function() {
$("#m").prop('checked',false );
});
$( document ).ready(function() {
$("#m").prop('checked',false );
});
#n {
display: none;
}
#m:checked ~ #n {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<label for="m">Menu</label>
<input id="m" type="checkbox">
<nav id="n">
<ul>
<li>Link 1</li>
</ul>
</nav>
Further to the other comments, if you are writing an AJAX driven page that uses pushState/replaceState, and the back button would not actually reload a page (i.e. no HTTP request), you can listen for the popState event and clear the checkbox.
window.onpopstate = function(event) {
$("#m").prop('checked',false );
};
It's a HTML 5 feature that's not fully supported across all browsers (although support is pretty good)
https://developer.mozilla.org/en-US/docs/Web/Events/popstate
Other options would be to use libraries like history.js, jquery-bbq, sammyjs, and so on.
add autocomplete="off" to the checkbox.
Related
I'm working on a combobox, and in doing so, I want to use the new :focus-within pseudo selector to manage displaying the expandable listbox that's associated with the combobox.
:focus-within is a great solution and works like a charm. The only problem I'm having is figuring out how to keep the aria-expanded attribute on the listbox updated. Because all of the hide/show functionality is happening in browser-land due to the pseudo-selector, I'm unsure of a hook I can use in Javascript to determine when the item is visible or not in order to update that property.
Is there an elegant solution anyone knows about? I'd hate to have to replicate the logic for focus/blur that :focus-within is handling right now just to update this attribute. I'm also concerned they may get out of sync. There any way to spy on an element with :focus-within or something like that?
.list {
display: none;
}
.combobox-container:focus-within .list {
display: block;
}
<section class="combobox-container">
<div role="combobox" aria-expanded="false" aria-owns="listbox" aria-haspopup="listbox">
<label> Foo
<input type="text" aria-autocomplete="list" aria-controls="listbox" />
</label>
</div>
<ul class="list" id="listbox" role="listbox" tabindex="0" aria-multiselectable="true">
<!-- items for autocomplete. focusable anchors inside li tags. -->
<li>Javascript</li>
<li>HTML</li>
<li>CSS</li>
</ul>
</section>
Accessibility guidelines for a combobox
focus-within only has 84% browser coverage
For this reason that instantly makes your solution inaccessible as a lot of screen reader users still use JAWs with Internet Explorer.
Additionally you have the problem that while this works as a demo, in the real world an auto-complete list will be populated via AJAX or via a preloaded list that is filtered.
This means that the list will always be shown the second you focus the <input>, even when nothing has been typed into the combobox (which is not expected behaviour).
This is one of the few circumstances where relying solely on JavaScript is acceptable (with a fallback that the form can still be submitted without JavaScript).
Instead of trying to use :focus-within you can instead use JavaScript to toggle aria-expanded="true" when you return some suggestions and then use standard CSS3 selectors to show and hide the results.
The below example shows the CSS to achieve this. The + operator is the key, it is the Adjacent Sibling Combinator that selects the next sibling within a parent element.
CSS: .combobox-container div[aria-expanded="true"]+.list
For the example below I have made it so that once you type more than 1 character into the box it will change the aria-expanded attribute to true (and back again if the input is empty) - this makes it feel more like a 'real world' example.
Side note: You do not need to add a tabindex to the <ul>, the expected behaviour is to tab directly to the first suggested item, I have removed that in the example below.
//ignore this, this is my standard jQuery replacement for snippets
if(typeof $=="undefined"){!function(b,c,d,e,f){f=b['add'+e]
function i(a,d,i){for(d=(a&&a.nodeType?[a]:''+a===a?b.querySelectorAll(a):c),i=d.length;i--;c.unshift.call(this,d[i]));}
$=function(a){return /^f/.test(typeof a)?/in/.test(b.readyState)?setTimeout(function(){$(a);},9):a():new i(a);};$[d]=i[d]={on:function(a,b){return this.each(function(c){f?c['add'+e](a,b,false):c.attachEvent('on'+a,b)})},off:function(a,b){return this.each(function(c){f?c['remove'+e](a,b):c.detachEvent('on'+a,b)})},each:function(a,b){for(var c=this,d=0,e=c.length;d<e;++d){a.call(b||c[d],c[d],d,c)}
return c},splice:c.splice}}(document,[],'prototype','EventListener');var props=['add','remove','toggle','has'],maps=['add','remove','toggle','contains'];props.forEach(function(prop,index){$.prototype[prop+'Class']=function(a){return this.each(function(b){if(a){b.classList[maps[index]](a);}});};});$.prototype.hasClass=function(a){return this[0].classList.contains(a);};}
$.prototype.find=function(selector){return $(selector,this);};$.prototype.parent=function(){return(this.length==1)?$(this[0].parentNode):[];};$.prototype.findWithin=function(a){console.log("THIS IS",this[0],a);return this[0].getElementsByClassName(a);};$.prototype.first=function(){return $(this[0]);};$.prototype.focus=function(){return this[0].focus();};$.prototype.css=function(a,b){if(typeof(a)==='object'){for(var prop in a){this.each(function(c){c.style[prop]=a[prop];});}
return this;}else{return b===[]._?this[0].style[a]:this.each(function(c){c.style[a]=b;});}};$.prototype.text=function(a){return a===[]._?this[0].textContent:this.each(function(b){b.textContent=a;});};$.prototype.html=function(a){return a===[]._?this[0].innerHTML:this.each(function(b){b.innerHTML=a;});};$.prototype.attr=function(a,b){return b===[]._?this[0].getAttribute(a):this.each(function(c){c.setAttribute(a,b);});};$.param=function(obj,prefix){var str=[];for(var p in obj){var k=prefix?prefix+"["+p+"]":p,v=obj[p];str.push(typeof v=="object"?$.param(v,k):encodeURIComponent(k)+"="+encodeURIComponent(v));}
return str.join("&");};$.prototype.append=function(a){return this.each(function(b){b.appendChild(a[0]);});};$.ajax=function(a,b,c,d){var xhr=new XMLHttpRequest();var type=(typeof(b)==='object')?1:0;var gp=['GET','POST'];xhr.open(gp[type],a,true);if(type==1){xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");}
xhr.responseType=(typeof(c)==='string')?c:'';var cb=(!type)?b:c;xhr.onerror=function(){cb(this,true);};xhr.onreadystatechange=function(){if(this.readyState===4){if(this.status>=200&&this.status<400){cb(this,false);}else{cb(this,true);}}};if(type){xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');xhr.send($.param(b));}else{xhr.send();}
xhr=null;};
//only part of the demo, not for production use
$('input').on('keyup', function(e){
if($(this)[0].value.length > 0){
$('div[role=combobox]').attr('aria-expanded', true);
return;
}
$('div[role=combobox]').attr('aria-expanded', false);
return;
});
.list {
display: none;
}
.combobox-container div[aria-expanded="true"]+.list{
display: block;
border:2px solid #333;
}
<section class="combobox-container">
<div role="combobox" aria-expanded="false" aria-owns="listbox" aria-haspopup="listbox">
<label> Foo
<input type="text" aria-autocomplete="list" aria-controls="listbox" />
</label>
</div>
<ul class="list" id="listbox" role="listbox" aria-multiselectable="true">
<!-- items for autocomplete. focusable anchors inside li tags. -->
<li>Javascript</li>
<li>HTML</li>
<li>CSS</li>
</ul>
</section>
I've got a page with jQuery tabs, and I'm trying to link a div element inside a secondary tab with zeroclipboard. Unfortunately, it's not working because I suspect the secondary tab is initially hidden when the page is loaded.
The html is the following:
<span id="form" class="tabs tabs-normal grid100">
<!-- HEADER BUTTONS -->
<div class="row_btns_header">
<button class="btn_neutral">Cancel</button>
<button class="btn_primary last save">Save</button>
</div>
<!-- TABS -->
<div class="row">
<ul id="tabs-list">
<li>Blog</li>
<li>Links</li>
<li>Images</li>
<li>More..</li>
</ul>
</div>
<!-- DEFAULT TAB -->
<div id="blog" class="container">
</div>
<!-- LINKS TAB -->
<div id="links" class="container">
<div id="embed" style="position: relative">
Copy into the clipboard
</div>
</div>
<!-- etc. -->
The javascript is:
$(".tabs").tabs();
$("#embed").zclip({
path: "http://www.steamdev.com/zclip/js/ZeroClipboard.swf",
copy: "aaaaaaaaaaaa"
});
zeroclipboard works correctly, if I move the #embed div inside the #blog div. I suspect this is because #blog is visible by default.
Any ideas what I need to do in order to get the zeroclipboard element to work when it's located inside a secondary non-default tab?
Much thanks.
Bardi
I realize this is an old thread, but hopefully this helps someone out there.
I just had the same problem and the solution I came up with was to bind the creation of the zclip object to a mouseover event tied to the desired trigger button/link. Also, to prevent the script from reinitializing the zclip object each time a mouseover event occurs, just turn it off when it is first called. Here's an example:
The HTML:
<input type='text' value='Text being copied.'/> <input type='button' class='clipcopy' value='Copy'/>
The Javascript:
$(document).ready(function(){
$(".clipcopy").on('mouseover', function(){
//turn off this listening event for the element that triggered this
$(this).off('mouseover');
//initialize zclip
$(this).zclip({
path: "js/zclip/ZeroClipboard.swf",
copy: function(){return $(this).prev().prop('value');}
});
});
});
Hope it helps!
The tabs plugin sets the tab panels to display: none, which means the Flash doesn't get started right away. You could try hacking it with CSS:
.container.ui-helper-hidden {
display: block !important;
position: absolute;
left: -99999px;
}
This will override the display: none and instead position the panel off the screen - this way the content is loaded and the panel is measured, but won't be visible to the user. (This is the same way the .ui-helper-hidden-accessible used to work)
The point is initialize it on a mouseover event, I am use jquery.clipboard and this also work
$("a.button-copy-shortcode").on('mouseover', function(event){
event.preventDefault();
//initialize clipboard
$(this).clipboard({
path: pluginDir+'/tonjoo-tom/assets/js/jquery.clipboard.swf',
copy: function() {
var shortcode = $(this).find('.shortcodeValue').text();
return shortcode;
}
});
});
I have built a drop down menu in pure css and it works perfectly. Right now it only works when hovered over. Hovering over #headerNav causes the menu to my .dropdownMenu to drop down and as soon as cursor is taken away from dropdownMenu or the #headerNav the menu disappears.
Because I want users with js enabled to have a better experience, I've decided to use some jquery to get the same effect as click here. Which basically keeps the drop down menu open after a click and click only not hovering.
By default I have set .dropdownMenu to "display: none" and then to show the drop down menu I have something like this:
#headerNav:hover .dropdownMenu {
display:block;
//more code
}
Here is my html:
<header>
<div id='headerContent'>
<div id='LogoHolder'>
</div>
<nav id='headerNav'>
<ul>
<li id='photoThumbnail'></li>
<li id='currentUser'>
<ul class="dropdownMenu">
<li>link1</li>
<li>link2</li>
<li>link3</li>
<li>link4</li>
<li>link5</li>
<li>link6</li>
</ul>
</li>
</ul>
</nav>
</div>
</header>
I've been experimenting for 2 days now and can't seem to come up with a way of doing this. I'd appreciate some help with clear examples. Thanks
Kind regards
Instead of targeting your nav by it's ID, add a class to it, say hover-nav and update your CSS accordingly:
.hover-nav:hover .dropdownMenu
Then in your javascript remove the css class from the ul
$(#headerNav').removeClass('hover-nav');
and use your click to show plugin as you normally would.
I think the most elegant way to deal with javascript enabled/disabled is to add :
<html class='no-js'>
then removing the class with Javascript.
So, in your case, you would use
.no-js #headerNav:hover .dropdownMenu {
display:block;
}
to target only users with javascript disabled.
See : http://paulirish.com/2009/avoiding-the-fouc-v3/ for more details.
Nathan hit it on the head. I'll go ahead and paste the code, since I was already nearly finished with it.
CSS
#headerNav .hideable{ display:none; }
#headerNav:hover .hideable{ display:block; }
HTML (just add hideable to your UL)
<ul class="dropDownMenu hideable">
jQuery
$('.hideable').hide().removeClass('hideable');
$('#headerNav').click( function(){
$(this).find('.dropDownMenu').slideToggle();
});
Replace above with this jQuery to add the ability to close the menu if anywhere else is clicked.
$('.hideable').hide().removeClass('hideable');
$('#headerNav').click( function(e){
$(this).find('.dropDownMenu').slideToggle();
e.stopPropagation();
});
$('html').click( function(e){
$('.dropDownMenu').slideUp();
});
Try something like this:
$(document).ready(function(){
$('#headerNav .dropDownMenu').hover(function() {
$(this).show();
});
$('*:not(#headerNav .dropDownMenu)').click(function() {
event.stopPropagation();
$("#headerNav .dropDownMenu").hide();
});
});
Your CSS is .dropdownMenu
Your Html is class="drop DownMenu"
CSS is case sensitive.
I want to have a tab-navigation in my jQuery Mobile project. I know I can use the data-role 'navbar' but I only want to change the content below that navbar without swiping to a new page. So far I could only have several different pages with the same navbar linking to each other but that's not what I want.
Can anyone help me?
Thank you in advance
You can use the jQuery Mobile navbar styling but use your own click-handler so instead of changing pages the click will just hide/show the proper content on the same page.
HTML
<div data-role="navbar">
<ul>
<li>One</li>
<li>Two</li>
</ul>
</div><!-- /navbar -->
<div class="content_div">onLoad Content</div>
<div id="a" class="content_div">Some 'A' Content</div>
<div id="b" class="content_div">Some 'B' Content</div>
JAVASCRIPT
$(document).delegate('[data-role="navbar"] a', 'click', function () {
$(this).addClass('ui-btn-active');
$('.content_div').hide();
$('#' + $(this).attr('data-href')).show();
return false;//stop default behavior of link
});
CSS
.content_div {
display: none;
}
.content_div:first-child {
display: block;
}
Here is a jsfiddle of the above code: http://jsfiddle.net/3RJuX/
NOTE:
Each of the links in the navbar have a "data-href" attribute set to the id of the div (or whatever container you want to use) that will be displayed.
Update
After 1 year I came back to this answer and noticed that the delegated event handler selector can be optimized a bit to utilize a class rather than an attribute (which is a lot faster of a lookup):
$(document).delegate('.ui-navbar a', 'click', function () {
$(this).addClass('ui-btn-active');
$('.content_div').hide();
$('#' + $(this).attr('data-href')).show();
});
Update
This code can be made to be more modular by using relative selectors rather than absolute ones (like $('.content_div'), as this will select all matching elements in the DOM rather than just ones relative to the button clicked).
//same selector here
$(document).delegate('.ui-navbar ul li > a', 'click', function () {
//un-highlight and highlight only the buttons in the same navbar widget
$(this).closest('.ui-navbar').find('a').removeClass('ui-navbar-btn-active');
//this bit is the same, you could chain it off of the last call by using two `.end()`s
$(this).addClass('ui-navbar-btn-active');
//this starts the same but then only selects the sibling `.content_div` elements to hide rather than all in the DOM
$('#' + $(this).attr('data-href')).show().siblings('.content_div').hide();
});
This allows you to nest tabs and/or have multiple sets of tabs on a pages or pseudo-pages.
Some documentation for the "relative selectors" used:
.closest() : http://api.jquery.com/closest
.siblings() : http://api.jquery.com/siblings
Here was an example: http://jsfiddle.net/Cfbjv/25/ (It's offline now)
UPDATE: Check out my jsfiddle at http://jsfiddle.net/ryanhaney/eLENj/
I just spent some time figuring this out, so I thought I would answer this. Note I am using multi-page single file, YMMV.
<div data-role="footer" data-position="fixed">
<div data-role="navbar">
<ul>
<li>Page 1</li>
<li>Page 2</li>
<li>Page 3</li>
</ul>
</div>
</div>
$("div[data-role=page]").bind("pagebeforeshow", function () {
// prevents a jumping "fixed" navbar
$.mobile.silentScroll(0);
});
$("a[data-role=tab]").each(function () {
// bind to click of each anchor
var anchor = $(this);
anchor.bind("click", function () {
// change the page, optionally with transitions
// but DON'T navigate...
$.mobile.changePage(anchor.attr("href"), {
transition: "none",
changeHash: false
});
// cancel the click event
return false;
});
});
#Mike Bartlett
I struggled with this myself but after breaking Jasper's code down it looks like there is a slight nuance from his posted code and that on the jsfiddle page.
Where he has posted
$(document).delegate('[data-role="navbar"] a', 'click', function () {
$(this).addClass('ui-btn-active');
$('.content_div').hide();
$('#' + $(this).attr('data-href')).show(); });
I found it useful to change the last line to simply call whatever content you set the "data-href" value to be in your navbar.
$('div[data-role="navbar"] a').live('click', function () {
$(this).addClass('ui-btn-active');
$('div.content_div').hide();
$($(this).attr('data-href')).show();
});
my navbar html then reads
<div data-role="navbar">
<ul>
<li>One</li>
<li>Two</li>
</ul>
Which is pretty much the same as his but for some reason I got no "error loading page" message. Hope that helps...
Please refers this below link for all kind of nav bar in jquery
http://jquerymobile.com/demos/1.0rc2/docs/toolbars/docs-navbar.html
<div data-role="navbar">
<ul>
<li>One</li>
<li>Two</li>
</ul>
</div>
thanks
I noticed that the question was asked four years ago, so i'm not sure whether the Tab widget were available with JQ Mobile at that time. anyway i'm a guy from 2015
the awesome solution that i use as below with Jquery Mobile 1.4.5
<div data-role="tabs" id="tabs">
<div data-role="navbar">
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</div>
<div id="one" class="ui-body-d ui-content">
<h1>First tab contents</h1>
</div>
<div id="two">
<ul data-role="listview" data-inset="true">
<li>Acura</li>
<li>Audi</li>
<li>BMW</li>
<li>Cadillac</li>
<li>Ferrari</li>
</ul>
</div>
</div>
I liked #Ryan-Haney's answer, but thought I'd add my own rough draft in, if anyone can find a more efficient way of doing this, then please add a comment.. thanks
I did it this way because I have a bunch of "include" files that get loaded into the DOM at runtime, so I couldn't hard-code that the n-th tab is highlighted/active for each page like Ryan could. I also do have the luxury of having only a single tabbar in my app.
$(document).delegate('.ui-navbar a', 'tap', function ()
{
$('.ui-navbar').find('li').find('a').removeClass('ui-btn-active');
$('.ui-navbar').find('li:nth-child(' + ($(this).parent().index() + 1) + ')').find('a').addClass('ui-btn-active');
});
There seem to be some problems with tabindex in several browsers so I want to work around these issues using javascript/jquery. Specifically FF3.5 (Mac) doesn't accept tabindex or focus on links at all. I have jquery 1.3.2 and js-hotkeys 0.7.9 running on my website.
I have 4 forms on 1 page which I can switch between using a link. Now when the page loads I what 1 of the links to have the focus using it's id. Then I want to be able to tab between each link to display each form.
Stripped down code looks like this:
HTML
<nav id="postNav">
<ul>
<li class="Nav1">1</li>
<li class="Nav2">2</li>
<li class="Nav3">3</li>
<li class="Nav4">4</li>
</ul>
</nav>
<form class="postForm" id="post1">
</form>
<form class="postForm" id="post2">
</form>
<form class="postForm" id="post3">
</form>
<form class="postForm" id="post4">
</form>
Jquery
$(document).ready(function(){
$("#postNav ul li a").click(function(event){
var postOptionSelected = $(this).parent("li").attr("class").substr(3);
$("form#post"+postOptionSelected).show();
$("form.postForm:not(#post"+postOptionSelected+")").hide();
event.preventDefault();
});
});
This isn't a Firefox issue. It's a system setting for Mac OS. In System Preferences, Keyboard & Mouse, and Keyboard Shortcuts, there's a Full keyboard access setting that allows users to configure whether they want Tab to enable changing keyboard focus to text boxes and lists only or to all controls. It is set to text boxes and lists only by default.
Safari on Mac OS has a setting in Safari, Preferences, Advanced, Press Tab to highlight each item on a webpage to override this behavior.
I think you forgot the "Form" after "post":
$("form#postForm"+postOptionSelected).show();
$("form.postForm:not(#postForm"+postOptionSelected+")").hide();