I have been working on a small application for the last little while. I am by no means a pro at this. I would like to have a jQuery UI Menu show up where the user clicks on my table. The problem is that the menu never shows up "over" the table but underneath (below as in farther down the page not under the table) it instead.
$("table.selectTable").delegate("tr", "click", function(event) {
event.stopPropagation();
lastClicked = $(this);
var menu = '#' + $(this).parent().parent().attr('name') + 'Menu';
console.log(menu); //getting the result (the show and hide work as well)
$(menu).hide();
if (!event.shiftKey) {
if ($(this).children().hasClass("highlight")) {
console.log('event coords' + event.pageX + "," + event.pageY);
console.log($(this).offset());
//$(this).children().removeClass("highlight");
position = $(this).position();
if ($(menu).css('display') === 'none') {
$(menu).menu().position({
my: "right top",
of: event
});
$(menu).show();
} else {
console.log('no menu to show');
$(this).children().removeClass("highlight");
}
} else {
console.log('add');
$(this).parent().children().children().removeClass("highlight");
$(this).children().addClass("highlight");
}
} else {
if ($(this).children().hasClass("highlight")) {
$(this).children().removeClass("highlight");
} else {
$(this).children().addClass("highlight");
}
}
clearSelection();
});
This chunk of code which is ugly and no longer in use DOES work:
(was too specific, not terribly reusable, and depended on ugly checkboxes for selection - the highlighting was just to show which row the menu related to)
$("#groupList tbody").delegate("tr", "click", function(event) {
lastClicked = $(this).children("td").next().html();
$(this).parent().children().children().removeClass("highlight");
event.stopPropagation();
if (event.target.nodeName !== "INPUT" && $(event.target).children("input").first().attr('rel') === undefined) {
$(this).children().addClass("highlight");
$("#gListMenu").menu().position({
my: "right top",
of: event
});
$("#gListMenu").show();
} else {
$("#gListMenu").hide();
}
});
I sincerely appreciate any input anyone has to offer as I've researched as much as I can.
Related
I am working on closing toggle menu for mobiles and having a small problem. So what i want is when the toggle menu is active, user to be able to close it by touching somewhere on the screen on his device. I almost got it working, but when closed the basket in the header disappears and the menu doesn't retrieve to a hamburger icon. I am working on Wordpress website, just to notice.
I guess the problem comes from this: aria-expanded="true" , because the default value should be false after the user has closed it.
So my website is:
https://www.ngraveme.com/bg
my JQuery code is:
jQuery(document).ready(function($) {
var $menu = $('.menu');
$('.menu-toggle').click(function() {
$menu.toggle();
});
$(document).mouseup(function(e) {
if (!$menu.is(e.target) // if the target of the click isn't the container...
&&
$menu.has(e.target).length === 0) // ... nor a descendant of the container
{
$menu.hide();
}
});
});
and the original js code written from the theme i am using in wordpress is:
/**
* navigation.js
*
* Handles toggling the navigation menu for small screens.
* Also adds a focus class to parent li's for accessibility.
* Finally adds a class required to reveal the search in the handheld footer bar.
*/
(function() {
// Wait for DOM to be ready.
document.addEventListener('DOMContentLoaded', function() {
var container = document.getElementById('site-navigation');
if (!container) {
return;
}
var button = container.querySelector('button');
if (!button) {
return;
}
var menu = container.querySelector('ul');
// Hide menu toggle button if menu is empty and return early.
if (!menu) {
button.style.display = 'none';
return;
}
button.setAttribute('aria-expanded', 'false');
menu.setAttribute('aria-expanded', 'false');
menu.classList.add('nav-menu');
button.addEventListener('click', function() {
container.classList.toggle('toggled');
var expanded = container.classList.contains('toggled') ? 'true' : 'false';
button.setAttribute('aria-expanded', expanded);
menu.setAttribute('aria-expanded', expanded);
});
// Add class to footer search when clicked.
document.querySelectorAll('.storefront-handheld-footer-bar .search > a').forEach(function(anchor) {
anchor.addEventListener('click', function(event) {
anchor.parentElement.classList.toggle('active');
event.preventDefault();
});
});
// Add focus class to parents of sub-menu anchors.
document.querySelectorAll('.site-header .menu-item > a, .site-header .page_item > a, .site-header-cart a').forEach(function(anchor) {
var li = anchor.parentNode;
anchor.addEventListener('focus', function() {
li.classList.add('focus');
});
anchor.addEventListener('blur', function() {
li.classList.remove('focus');
});
});
// Add an identifying class to dropdowns when on a touch device
// This is required to switch the dropdown hiding method from a negative `left` value to `display: none`.
if (('ontouchstart' in window || navigator.maxTouchPoints) && window.innerWidth > 767) {
document.querySelectorAll('.site-header ul ul, .site-header-cart .widget_shopping_cart').forEach(function(element) {
element.classList.add('sub-menu--is-touch-device');
});
}
});
})();
Try replacing your jQuery code with this:
jQuery(document).ready(function($) {
$(document).mouseup(function(e) {
var $menuContainer = $('.menu');
var $menu = $menu.find('ul');
var $container = $('.site-navigation');
var $button = $container.find('button')
if (!$menuContainer.is(e.target) && $menuContainer.has(e.target).length === 0) {
if ($container.hasClass('toggled')) {
$button.attr('aria-expanded', false);
$menu.attr('aria-expanded', false);
}
}
});
});
It uses the vanilla-js code from the template for hiding/showing the menu, but with jQuery synthax.
I can get this to work using the mouse. I can't get it to work using the keyboard.
This works and adds a message when dropped using the mouse:
$('.drop_01').droppable ({
drop: function() {
$('span.movedItem1').remove();
$(this).prepend('<span class=\"movedItem1\">Item moved to Program philisophy drop area Vision/mission.</span>');
}
});
I need to have the same happen when using the keyboard combination Alt+1. I have this and tried several variations but cannot get it to work. The item still moves to the dropped position but the message does not display.
$(".activity").on("keydown", "#activity_contents a", function (e) {
if(e.altKey && ( e.which === 49 )) {
$('.drop_01').droppable ({
drop: function() {
$('span.movedItem1').remove();
$(this).prepend('<span class=\"movedItem1\">Item moved to Program philisophy drop area Vision/mission.</span>');
}
});
}
});
If this is achievable can someone help please. To clarify this is just to display the message the drag/drop function is a lot of additional code not posted.
I was looking at this the wrong way. The solution I have (although a bit untidy) is:
// CtRL key moves something to next column
$(".activity").on("keydown", ".connected-sortable.draggable li", function (event) {
var $this = $(this)
, key = event.keyCode || e.which
, $holder = $this.parents(".activity")
, $selectedul = $this.parent()
, $availableuls = $holder.find(".connected-sortable")
, currentlistindex = $selectedul.data("list-index")
, nextlistindex = currentlistindex + 1
, $nextul = $holder.find(".connected-sortable[data-list-index='" + nextlistindex + "']")
, $originalul = $holder.find(".connected-sortable[data-list-index='0']");
if ($nextul.length == 0) {
$nextul = $originalul;
}
if(nextlistindex === 1) {
$('span.movedItema').remove();
$('span.movedItemb').remove();
$('span.movedItemc').remove();
$('span.movedItemd').remove();
$(this).focus().prepend('<span class=\"movedItema offscreenText\">Item moved to Program philisophy drop area Vision/mission.</span>');
}
if(nextlistindex === 2) {
$('span.movedItema').remove();
$('span.movedItemb').remove();
$('span.movedItemc').remove();
$('span.movedItemd').remove();
$(this).focus().prepend('<span class=\"movedItemb offscreenText\">Item moved to Program philisophy drop area Beliefs/values.</span>');
}
if(nextlistindex === 3) {
$('span.movedItema').remove();
$('span.movedItemb').remove();
$('span.movedItemc').remove();
$('span.movedItemd').remove();
$(this).focus().prepend('<span class=\"movedItemc offscreenText\">Item moved to Program philisophy drop area Strategies.</span>');
}
if(nextlistindex === 4) {
$('span.movedItema').remove();
$('span.movedItemb').remove();
$('span.movedItemc').remove();
$('span.movedItemd').remove();
$(this).focus().prepend('<span class=\"movedItemd offscreenText\">Item moved back to Program philisophy Factors list.</span>');
}
Ok so I'm using Jquery UI Selectable to highlight some cells in a table. I would like to be able to add a border around the highlighted cells using like a 2px border. This way each time you highlight a section you can tell the separation between each section that has been highlighted. I am also hoping I can achieve this result with overlapping sections.
I've done quite a bit of reading and haven't really seen anyone trying to do this yet. So I'm wondering if someone might be able to point me in the right direction on how to achieve this effect.
Here's a fiddle of my example and some code below.
var shadeColor = $(".color-pallet > .active").css("background-color");
applySelectable = function() {
$(".block-tools > .shade-btn").click(function() {
var $this = $(this);
if (!$this.hasClass("active")) {
$this.siblings().removeClass("active");
$this.addClass("active");
}
});
$(".color-pallet > span").click(function() {
var $this = $(this);
if (!$this.hasClass("active")) {
$this.siblings().removeClass("active");
$this.addClass("active");
shadeColor = $(this).css("background-color");
}
});
// keep selected shade color selected after new question
if (shadeColor !== $(".color-pallet > .active")) {
$(".color-pallet > span").filter(function(){
var color = $(this).css("background-color");
if (color === shadeColor) {
$(this).click();
};
});
}
$(".blocks").bind("mousedown", function(e) {
e.metaKey = true;
}).selectable({
filter: "td",
selecting: function (event, ui) {
if ($('.block-shade').hasClass("active")) {
$(ui.selecting).addClass('marked').css("background-color", shadeColor);
} else {
$(ui.selecting).removeClass('marked').css("background-color", "");
}
userAns = $('.marked').length+"";
}
});
};
applySelectable();
Thank you in advance for you time.
EDIT: For bonus points, can someone tell me when im dragging a selection, why is the containers height growing and creating a scroll bar? This has been seriously bugging me for some time and I chose to ignore it but I guess while I'm here maybe someone could explain this as well?
Huh... here is some kind of solution, i've added 4 css classes, and some ugly code... but it is working...
$(".blocks").bind("mousedown", function(e) {
e.metaKey = true;
}).selectable({
filter: "td",
selecting: function (event, ui) {
if ($('.block-shade').hasClass("active")) {
$(ui.selecting).addClass('marked').css("background-color", shadeColor);
$(ui.selecting).addClass('top');
$(ui.selecting).addClass('left');
$(ui.selecting).addClass('bottom');
$(ui.selecting).addClass('right');
if($(ui.selecting).prev().hasClass('marked')) {
$(ui.selecting).removeClass('left');
$(ui.selecting).prev().removeClass('right');
}
if($(ui.selecting).next().hasClass('marked')) {
$(ui.selecting).removeClass('right');
$(ui.selecting).next().removeClass('left');
}
top_elem=$(ui.selecting).parent().prev('tr').find('td');
// console.log(top_elem);
$(top_elem).each(function(i) {
if($(this).hasClass('marked')) {
if($(this).offset().left==$(ui.selecting).offset().left)
{
$(this).removeClass('bottom');
$(ui.selecting).removeClass('top');
}
}
});
bottom_elem=$(ui.selecting).parent().next('tr').find('td');
$(bottom_elem).each(function(i) {
if($(this).hasClass('marked')) {
if($(this).offset().left==$(ui.selecting).offset().left)
{
$(this).removeClass('top');
$(ui.selecting).removeClass('bottom');
}
}
});
} else {
$(ui.selecting).removeClass('marked').css("background-color", "");
$(ui.selecting).removeClass('top');
$(ui.selecting).removeClass('left');
$(ui.selecting).removeClass('bottom');
$(ui.selecting).removeClass('right');
}
userAns = $('.marked').length+"";
}
});
};
applySelectable();
});
DEMO: http://jsfiddle.net/wh2ehzo3/10/
However, overlapping is really, really tricky IF YOU WANT to KEEP borders on overlapping parts.. test... (just OUTER border of both shapes is saved, i hope you will see what i mean)
Idea: check siblings -> remove classes accordingly, if there is .marked element, check up and down rows -> do the same...
I'm trying to add an autocomplete option to the title field in Wordpress - the titles of one of my custom document types will often (but not always) have a standard name.
I've hooked into Wordpress to add a div with an id of suggestions below title, and add a javascript onKeyUp event to title telling it to make an ajax request to a page that suggests names based on what's typed so far. This is all working fine.
Currently, however, I'm only able to select the suggestions via a mouseclick (which then uses val to update the value of #title. I'd also like users to be able to use the arrow keys to select a suggestion, a la Google.
I'm working on building this by giving each suggestion focus (each line is a li element with a dynamically generated tabindex.)
This works for a split second - the expected element gets the focus - but then it immediately loses it, going back to the body. Why is this happening?
Code for gethint.php:
<?php
$sofar = stripslashes($_GET['sofar']); // This is important as otherwise the url gets confused and won't work on anything with an apostrophe in it.
$common_file_names = array(
"Here's suggestion 1",
"This is suggestion 2",
"Suggestion 3");
if(strlen($_GET['sofar'])>1) { //Ignores single letters
echo '<ul id="autocomplete">';
$tabindex=0;
foreach ($common_file_names as $suggestion) {
if(false !== stripos($suggestion, $sofar)) : ?>
<li
tabindex="<?=$tabindex?>"
onClick="acceptSuggestion('<?=addslashes($suggestion)?>')"
onBlur="console.log('Lost focus!'); console.log(document.activeElement);";
><?=$suggestion?></li>
<?php $tabindex++; endif;
}
echo '</ul>';
}
?>
JS Code:
$.ajaxSetup({ cache: false });
window.onload = function () {
$( "<div id='suggestions'></div>" ).insertAfter( "#title" );
$(document).on('keydown', '#title', function (){
var hint_slash = this.value;
showHint(hint_slash);
checkKey(event);
});
$(document).on('focus', '#acf-field-extranet_client_area', function (){
clearSuggestions();
});
$(document).on('focus', '#acf-field-extranet_document_type', function (){
clearSuggestions();
});
$(document).on('focus', '#acf-date_picker', function (){
clearSuggestions();
});
$(document).on('focus', '#acf-file-value', function (){
clearSuggestions();
});
console.log("Scripts loaded successfully");
}
function showHint(str) { //If the user has typed 2 or more characters, this function looks for possible matches among common document names to speed up data entry.
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("suggestions").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "/gethint.php?sofar=" + str, true);
xmlhttp.send();
}
function acceptSuggestion(str) {
$('#title').val(str); //Puts the clicked suggestion into the title box.
clearSuggestions();
}
function clearSuggestions() {
showHint(""); //Clears suggestions.
}
function checkKey(event) {
console.log('Key press: ' + event.keyCode);
if(40 == event.keyCode) {
event.preventDefault(); // Stops scrolling.
var autocomplete = $("#autocomplete");
$(autocomplete.children('li:nth-child(' + 2 + ')')).focus() ;
console.log(document.activeElement);
}
}
This is just test code currently, hence always setting focus to the 3rd child element.
I wouldn't try focus on the suggestions. You'll have to add the keychecking code to every suggestion in this case, because the input will lose focus. Instead, create a CSS class for the "focused" suggestion, remove the class on key up/down and add it to the previous/next suggestion...
$input.keyup(function(e) {
if(e.which == 38) {
// up key
var active = $('.suggestions li.active');
if(active.length) {
active.removeClass('active');
active.prev().addClass('active');
} else {
$('.suggestions li:last').addClass('active');
}
} else if(e.which == 40) {
// down key
var active = $('.suggestions li.active');
if(active.length) {
active.removeClass('active');
active.next().addClass('active');
} else {
$('.suggestions li:first').addClass('active');
}
}
});
Building on #evilunix's answer, I realised that each keystroke was resetting the #suggestions div, which meant that it could never hold focus (or keep an appended class etc).
So, wrote a new function called checkKey:
function checkKey(e) {
if(e.which == 38) {
// up key
e.preventDefault(); //Stops scrolling and cursor movement.
var active = $('#suggestions li.active');
if(active.length) {
active.removeClass('active');
active.prev().addClass('active');
} else {
$('#suggestions li:last').addClass('active');
}
} else if(e.which == 40) {
// down key
e.preventDefault(); //Stops scrolling and cursor movement.
var active = $('#suggestions li.active');
if(active.length) {
active.removeClass('active');
active.next().addClass('active');
} else {
$('#suggestions li:first').addClass('active');
}
} else if(e.which == 13) {
//Return key
e.preventDefault(); //Stops form submission.
acceptSuggestion(document.getElementsByClassName('active')[0].innerHTML);
} else {
console.log(e.which);
showHint($('#title').val());
}
}
and changed #title's onKeydown event to:
$(document).on('keydown', '#title', function (){
checkKey(event);
});
Now #suggestions only refreshes if the keystroke is not an up arrow, down arrow or return, and on a return runs acceptSuggestion on whichever li has the active class.
I have some code for a mega navigation and I need it to hover to drop the menu on desktop and click to the drop the menu on mobile.
Here is a snippet of code that I'm having problems with:
if( $('js-full-menu').hasClass('js-touch-menu') ) {
(function(megaNavTray){
menu.on('click', function(e){
e.preventDefault();
var wasOpen = megaNavTray.hasClass('is-active');
megaNavTrays.find('.js-mega-nav-tray').removeClass('is-active');
if(!wasOpen) {
megaNavTray.addClass('is-active');
megaNavTrays.addClass('is-active');
} else {
megaNavTrays.removeClass('is-active');
}
});
})(megaNavTray);
} else {
(function(megaNavTray){
menu.hoverIntent( function(){
megaNavTray.addClass('is-active');
megaNavTrays.addClass('is-active');
var wasOpen = megaNavTray.hasClass('is-active');
megaNavTrays.find('.js-mega-nav-tray').removeClass('is-active');
if(wasOpen) {
megaNavTray.addClass('is-active');
megaNavTrays.addClass('is-active');
} else {
megaNavTray.removeClass('is-active');
}
});
})(megaNavTray);
var fullNav = $('.js-full-menu');
fullNav.hoverIntent( function() {}, function() {
$('.js-mega-nav-tray').removeClass('is-active');
megaNavTrays.removeClass('is-active');
});
}
Basically the problem is that with the if else statement removed leaving only the following code, the preventdefault works fine. Using the full code above the links direct to their pages instead of dropping the meganav on click.
(function(megaNavTray){
menu.on('click', function(e){
e.preventDefault();
var wasOpen = megaNavTray.hasClass('is-active');
megaNavTrays.find('.js-mega-nav-tray').removeClass('is-active');
if(!wasOpen) {
megaNavTray.addClass('is-active');
megaNavTrays.addClass('is-active');
} else {
megaNavTrays.removeClass('is-active');
}
});
})(megaNavTray);
Any ideas why the if / else would be stopping the preventdefault from working?
Thanks in advance!
if( $('js-full-menu').hasClass('js-touch-menu') )
should be
if( $('.js-full-menu').hasClass('js-touch-menu') )
you forgot the . in the class selector.
I may be wrong, but try putting
function(event)
instead of
function(e)
Solved an issue for me in FF the other day.