Traversing multiple unordered lists - javascript

Consider the following markup :
<div class="col6">
<h2>Accueil</h2>
<ul class="listing">
<li>Accueil</li>
<li>Homepage Takeover</li>
<li>Homepage Promo Overlay</li>
<li>Homepage Feature Overlay</li>
<li>Homepage Feature Scroll + Takeover</li>
</ul>
<h2>Thèmes & intégrations</h2>
<ul class="listing">
<li>Le 30</li>
<li>Menu à la carte</li>
<li>Intégration thème</li>
<li>Intégration papier virtuel 1</li>
<li>Intégration papier virtuel 2</li>
</ul>
<h2>Galeries</h2>
<ul class="listing">
<li>St-Valentin noir & blanc</li>
<li>Cuisinez avec le fromage</li>
<li>Des fraises pour dessert</li>
<li>Nos meilleures recettes de homard</li>
<li>Jeudi 5#7</li>
</ul>
</div>
I want to traverse the uls with my #leftArrow and #rightArrow. I have a page with an overlay and I change the background image with these arrows. However, I'm not able to pass from the first ul to the second an so on when clicking these arrows.
Here's the Jquery
$(document).ready(function(){
var current_li;
//OPEN OVERLAY
$('.innerWrap a').click(function(){
var src = $(this).attr("title");
current_li = $(this).parent();
var text = $(current_li).text();
$('#frame h2').text(text)
$('#projectOverlay').css({'background-image': 'url(img/' + src + '.jpg)' ,});
$('#frame').fadeIn(400);
$('#projectOverlay').fadeIn(400);
})
//RIGHT
$("#rightArrow").click(function(){
if(current_li.is(":last-child")) {
var next_li = current_li.parents('ul').siblings().find('li').first();
} else {
var next_li = current_li.next();
}
var next_src = next_li.children('a').attr("title");
current_li = next_li;
})
//LEFT
$("#leftArrow").click(function(){
if(current_li.is(":first-child")) {
//var prev_li = $('.innerWrap ul li').last();
var prev_li = current_li.parents('ul').siblings().find('li').last();
} else {
var prev_li = current_li.prev();
}
var prev_src= prev_li.children('a').attr("title");
current_li = prev_li;
})
});
Any help would be appreciated !
Thanks !

https://jsfiddle.net/rgwst1xj/4/
EDIT: solution
$(document).ready(function(){
// I set current_li manually, so change it
var current_li = $('a').first().parent();
// Use your own method to determine which ul is the current one
var current_ul = 0;
//RIGHT
$("#rightArrow").click(function(){
if(current_li.is(":last-child")) {
// you may want to be more specific with $('ul').length
current_ul = (current_ul + 1)%$('ul').length;
var next_li = current_li.parent().parent().find('ul:eq('+current_ul+')').find('li').first();
} else {
var next_li = current_li.next();
}
var next_src = next_li.children('a').attr("title");
current_li = next_li;
console.log(current_li.text())
var text = $(current_li).text();
$('#frame h2').text(text);
})
//LEFT
$("#leftArrow").click(function(){
if(current_li.is(":first-child")) {
//var prev_li = $('.innerWrap ul li').last();
current_ul = (current_ul - 1)%$('ul').length;
var prev_li = current_li.parent().parent().find('ul:eq('+current_ul+')').find('li').last();
} else {
var prev_li = current_li.prev();
}
var prev_src= prev_li.children('a').attr("title");
$('#projectOverlay').animate({opacity: 0}, 200, function() {
$(this)
.css({'background-image': 'url(img/' + prev_src + '.jpg)' ,})
.animate({opacity: 1});
bgSize($('#projectOverlay'), function(width, height){
$("#frame").css("height",height)
$("#projectOverlay").css("height",height);
});
});
current_li = prev_li;
console.log(current_li.text())
var text = $(current_li).text();
$('#frame h2').text(text);
})
});

Related

jQuery animated list re-ordering?

I have following jQuery code for re-ordering list:
$("li").live("click", function() {
var $myLi = $(this);
var listHeight = $("ul").innerHeight();
var elemHeight = $myLi.height();
var elemTop = $myLi.position().top;
var moveUp = listHeight - (listHeight - elemTop);
var moveDown = elemHeight;
var liId = $myLi.attr("id");
var enough = false;
var liHtml = $myLi.outerHTML();
$("li").each(function() {
if ($(this).attr("id") == liId) {
return false;
}
$(this).animate({"top": '+=' + moveDown}, 1000);
});
$myLi.animate({"top": '-=' + moveUp}, 1000, function() {
$myLi.remove();
var oldHtml = $("ul").html();
$("ul").html(liHtml + oldHtml);
$("li").attr("style", "");
});
});
(function($) {
$.fn.outerHTML = function() {
return $(this).clone().wrap('<div></div>').parent().html();
}
})(jQuery);
body {
font-size: 14px;
font-family: sans-serif;
}
li, ul {
position: relative;
top: 0;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<br /><br /><br />
<ul>
<li id="1">I am list item number 1.</li>
<li id="2">I am list item number 2.</li>
<li id="3">I am list item number 3.</li>
<li id="4">I am list item number 4.</li>
<li id="5">I am list item number 5.</li>
<li id="6">I am list item number 6.</li>
<li id="7">I am list item number 7.</li>
<li id="8">I am list item number 8.</li>
<li id="9">I am list item number 9.</li>
<li id="10">I am list item number 10.</li>
</ul>
But It's only working for re-ordering to top. I would like to know how to add reverse animation? (When the item is clicked - it moves to the bottom of the list). I'm a bit new to css animation, so I will be grateful for the help.

Is there a way to iterate over an unordered list with sublists - no jQuery?

I want to highlight every list item in my unordered list 'g1'.
The list has several sublists. I want to press 'arrow down' and 'up' to highlight the next item. I was able to iterate over the outer list, but with the sublists, my solution becomes super messy. Is there a better way than mine with pure JavaScript?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Family Tree</title>
</head>
<body id='main'>
<nav>
<h1 id=pos></h1>
</nav>
<ul id='g1' class="special">
<ul id='generation2'>
<li>John Williams</li>
<li>Filippa Williams</li>
<ul id='generation3'>
<li>Juan James</li>
<li>Catarina James</li>
<li>Aoifa James</li>
</ul>
<li>Juan Williams</li>
</ul>
<li>Mark Williams</li>
<li>Christina Johnson</li>
<li>Christina Johnson</li>
<li>Christina Johnson</li>
<li>Juan Williams</li>
<li>Juan Williams</li>
<ul id='generation2'>
<li>John Williams</li>
<li>Filippa Williams</li>
</ul>
</ul>
</body>
</html>
document.onkeydown = function (e) {
switch (e.keyCode) {
case 37:
alert('left');
break;
case 38:
up()
break;
case 39:
alert('right');
break;
case 40:
down();
break;
}
};
var pos = -1;
var posSub = -1;
var posSubSub = 0;
var pointer;
function down() {
var childrensChildren;
var childrensGrandchildren;
var gen1 = document.getElementById('g1');
var gen1children = gen1.children;
if (pos === -1) {
gen1children[0].style.backgroundColor = 'yellow';
pos++;
document.getElementById('pos').innerHTML = pos;
return null;
}
if (pos == gen1children.length - 1) {
gen1children[gen1children.length - 1].style.backgroundColor = 'white';
gen1children[0].style.backgroundColor = 'yellow';
pos = 0;
document.getElementById('pos').innerHTML = pos;
return null;
}
if (gen1children[pos].firstElementChild) {
var childrensChildren = gen1children[pos].children;
if (childrensChildren.firstChild) {
childrensGrandchildren = childrensChildren[posSub].children;
childrensGrandchildren[posSubSub].style.backgroundColor = 'yellow';
childrensGrandchildren[childrensGrandchildren.length - 1].style.backgroundColor = 'white';
posSubSub++;
} else {
if (posSub === -1) {
childrensChildren[0].style.backgroundColor = 'yellow';
posSub++;
return null;
}
if (posSub == childrensChildren.length - 1) {
childrensChildren[childrensChildren.length - 1].style.backgroundColor = 'white';
childrensChildren[0].style.backgroundColor = 'yellow';
return null;
} else {
posSub += 1;
childrensChildren[posSub - 1].style.backgroundColor = 'white';
childrensChildren[posSub].style.backgroundColor = 'yellow';
return null;
}
}
}
gen1children[pos].style.backgroundColor = 'white';
gen1children[pos + 1].style.backgroundColor = 'yellow';
pos += 1;
document.getElementById('pos').innerHTML = pos;
return null;
}
function up() {
var gen1 = document.getElementById('g1');
var gen1children = gen1.children;
if (pos === -1) {
gen1children[0].style.backgroundColor = 'yellow';
pos++;
document.getElementById('pos').innerHTML = pos;
return null;
}
if (pos == 0) {
gen1children[gen1children.length - 1].style.backgroundColor = 'yellow';
gen1children[0].style.backgroundColor = 'white';
pos = gen1children.length - 1;
document.getElementById('pos').innerHTML = pos;
return null;
}
gen1children[pos].style.backgroundColor = 'white';
gen1children[pos - 1].style.backgroundColor = 'yellow';
pos -= 1;
document.getElementById('pos').innerHTML = pos;
return null;
}
You can quickly create a flat list of all li items in your heirarchical DOM tree, and traverse this list visually with the arrow keys:
// Flat list of all `li` elements (in expected order)
let allLiElems = Array.from(document.getElementById('g1').getElementsByTagName('li'));
let liInd = null;
let highlightAtInd = ind => {
// Remove highlight from previous node
if (liInd !== null) allLiElems[liInd].classList.remove('highlight');
// Apply highlight to next node
liInd = ind;
allLiElems[liInd].classList.add('highlight');
};
window.addEventListener('keydown', evt => {
if (![ 38, 40 ].includes(evt.keyCode)) return;
// Get the new index; ensure it doesn't over/underflow
let newInd = liInd + ((evt.keyCode === 38) ? -1 : +1);
if (newInd < 0) newInd = allLiElems.length - 1;
if (newInd >= allLiElems.length) newInd = 0;
highlightAtInd(newInd);
evt.preventDefault();
});
// Initially highlight the 1st node
highlightAtInd(0);
* { overflow: hidden !important; }
#g1 { font-size: 11px; /* I want this to fit in the preview box */ }
.highlight {
background-color: rgba(255, 0, 0, 0.3);
}
<ul id='g1' class="special">
<ul id='generation2'>
<li>John Williams</li>
<li>Filippa Williams</li>
<ul id='generation3'>
<li>Juan James</li>
<li>Catarina James</li>
<li>Aoifa James</li>
</ul>
<li>Juan Williams</li>
</ul>
<li>Mark Williams</li>
<li>Christina Johnson</li>
<li>Christina Johnson</li>
<li>Christina Johnson</li>
<li>Juan Williams</li>
<li>Juan Williams</li>
<ul id='generation2'>
<li>John Williams</li>
<li>Filippa Williams</li>
</ul>
</ul>
Make sure you've focused the window before you try to perform key events!
You can create a class for all of your menu items, then set a "select" property in CSS https://www.w3schools.com/howto/howto_custom_select.asp

Right click JavaScript doesn't work on a table in PHP

Hy, I have a problem with my JavaScript that I use it for the content of a table. My function is for users when they right click on a table row appears a context menu where they can choose what they want to do. The problem is that right click doesn't work any more when I go to the next pages in the table (my page load with 10 records in the table).
My script:
<script type='text/javascript'>
$(window).load(function(){
(function ($, window) {
$.fn.contextMenu = function (settings) {
return this.each(function () {
// Open context menu
$(this).on("contextmenu", function (e) {
// return native menu if pressing control
if (e.ctrlKey) return;
//open menu
var $menu = $(settings.menuSelector)
.data("invokedOn", $(e.target))
.show()
.css({
position: "absolute",
left: getMenuPosition(e.clientX, 'width', 'scrollLeft'),
top: getMenuPosition(e.clientY, 'height', 'scrollTop')
})
.off('click')
.on('click', 'a', function (e) {
$menu.hide();
var $invokedOn = $menu.data("invokedOn");
var $selectedMenu = $(e.target);
var $selectedFileId = $menu.data("invokedOn").find('.datatable_fixed_column').attr('id');
settings.menuSelected.call(this, $invokedOn, $selectedMenu, $selectedFileId);
});
return false;
});
//make sure menu closes on any click
$('body').click(function () {
$(settings.menuSelector).hide();
});
});
function getMenuPosition(mouse, direction, scrollDir) {
var win = $(window)[direction](),
scroll = $(window)[scrollDir](),
menu = $(settings.menuSelector)[direction](),
position = mouse + scroll;
// opening menu would pass the side of the page
if (mouse + menu > win && menu < mouse)
position -= menu;
return position;
}
};
})(jQuery, window);
$("#datatable_fixed_column td").contextMenu({
menuSelector: "#contextMenu",
menuSelected: function (invokedOn, selectedMenu, id) {
switch(selectedMenu.text()){
case 'Modificare':{
var rand = invokedOn.parent().children();
var idpost = $(rand[0]).text();
window.location.href = "organigrama_add.php?control=update&id=" + idpost;
}
break;
case 'Stergere':{
var rand = invokedOn.parent().children();
var marca = $(rand[1]).text();
if (marca == '0')
{
var idpost = $(rand[0]).text();
var departament = $(rand[5]).text();
var subdepartament = $(rand[6]).text();
var schimb = $(rand[9]).text();
var functie = $(rand[10]).text();
var msg = "Sunteti sigur ca doriti sa stergeti aceasta inregistrare?" + "\nDepartament: " + departament + "\nSubdepartament: " + subdepartament + "\nSchimb: " + schimb + "\nFunctie: " + functie;
var confirmare = confirm(msg);
if (confirmare == true)
{
window.location.href = "organigrama.php?control=delete&id=" + idpost;
}
}
else
{
var msg = "Nu se poate sterge acest post. Doar posturile libere se pot sterge.";
alert(msg);
}
}
break;
case 'Renunta':{
return false;
}
break;
}
}
});
});
</script>
And context menu used for this:
<ul id="contextMenu" class="dropdown-menu" role="menu" style="display:none" >
<li><a tabindex="-1">Modificare</a></li>
<li><a tabindex="-1" href="#">Stergere</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="">Renunt</a></li>
</ul>
Edit: I forget to mention that the javascript is before the </body> end tag and context menu is after <body> start tag.
so basically the problem here is that the newly added rows in the table will not get the bindings from the initial load of the page. so the fix needed here is to bind the event to the main document by using this
$(document).on('contextmenu', target, function)
this will allow jquery to run the specific function to a targeted element on 'right click/contextmenu' event

jQuery plugin to filter a list of li elements

This is a plugin that filter an li elements.
jquery.livefilter.js:
/*
* jQuery.liveFilter
*
* Copyright (c) 2009 Mike Merritt
*
* Forked by Lim Chee Aun (cheeaun.com)
*
*/
(function($){
$.fn.liveFilter = function(inputEl, filterEl, options){
var defaults = {
filterChildSelector: null,
filter: function(el, val){
return $(el).text().toUpperCase().indexOf(val.toUpperCase()) >= 0;
},
before: function(){},
after: function(){}
};
var options = $.extend(defaults, options);
var el = $(this).find(filterEl);
if (options.filterChildSelector) el = el.find(options.filterChildSelector);
var filter = options.filter;
$(inputEl).keyup(function(){
var val = $(this).val();
var contains = el.filter(function(){
return filter(this, val);
});
var containsNot = el.not(contains);
if (options.filterChildSelector){
contains = contains.parents(filterEl);
containsNot = containsNot.parents(filterEl).hide();
}
options.before.call(this, contains, containsNot);
contains.show();
containsNot.hide();
if (val === '') {
contains.show();
containsNot.show();
}
options.after.call(this, contains, containsNot);
});
}
})(jQuery);
HTML:
<!DOCTYPE html>
<meta charset="utf-8">
<script src="jquery.min.js"></script>
<script src="jquery.livefilter.js"></script>
<script>
$(function(){
$('#livefilter-list').liveFilter('#livefilter-input', 'li', {
filterChildSelector: 'a'
});
});
</script>
<div>
<fieldset>
<legend><label for="livefilter-input">Search...</label></legend>
<input id="livefilter-input" type="text" value="">
<ul id="livefilter-list">
<li>cool</li>
<li>nice</li>
<li>interesting</li>
<li>javascript</li>
<li>css</li>
<li>html</li>
<li>script</li>
<li>international</li>
</ul>
</fieldset>
</div>
This code works great, but only with static li elements, like the li tags up there.
I have a jQuery function that append to ul tag many li elements. But, in this case, doesn't work
My code:
<div id="users" class="nav nav-second-level">
<ul id="livefilter-list" aria-expanded="true">
<li><a>Ciao</a></li>
<li><a>Come</a></li>
<li><a>Stai</a></li>
</ul>
</div>
jQuery:
for (var i in arr) {
$('#users').append('<li data-user="' + arr[i].id + '">' + arr[i].name + '</li>');
}
How can I resolve?
UPDATE:
<ul id="livefilter-list" class="nav nav-second-level" aria-expanded="true">
<li><a>Hey</a></li>
<li><a>How are</a></li>
<li><a>you?</a></li>
</ul>
I append others li element with:
for (var i in arr) {
$('#livefilter-list').append('<li data-user="' + arr[i].id + '">' + arr[i].name + '</li>');
}
and then:
$(function () {
$('#livefilter-list').liveFilter('#livefilter-input', 'li', {
filterChildSelector: 'a'
});
});
With "Hey", "How are" and "you?" works. But with the li elements added with jQuery not. Why?
This syntax :
$(function (){...});
makes the anonymous function passed in parameter executed as soon as the dom is loaded. This means :
function () {
$('#livefilter-list').liveFilter('#livefilter-input', 'li', {
filterChildSelector: 'a'
}
is run before the for loop apending elements to the livefilter-list :
for (var i in arr) {
$('#livefilter-list').append('<li data-user="' + arr[i].id + '">' + arr[i].name + '</li>');
}
I suggest you try to call liveFilter once the elements are appended to the livefilter-list :
for (var i in arr) {
$('#livefilter-list').append('<li data-user="' + arr[i].id + '">' + arr[i].name + '</li>');
}
$('#livefilter-list').liveFilter('#livefilter-input', 'li', {
filterChildSelector: 'a'
});
As your ul is #livefilter-list, you should use:
for (var i in arr) {
$('#livefilter-list').append('<li data-user="' + arr[i].id + '">' + arr[i].name + '</li>');
}
So it'll append li to <ul id="livefilter-list" aria-expanded="true">, not <div id="users" class="nav nav-second-level">
As your liveFilter is register to li under #livefilter-input, you can't have effect on #user > li, which become sibling of #livefilter-input.
Edit:
By the source code of jQuery.liveFilt,
var el = $(this).find(filterEl);
if (options.filterChildSelector) el = el.find(options.filterChildSelector);
it caches the element when created, and will not monitor further add/remove of the monitor target anymore, so it won't filter out any li added after its initialization.
You can tweak its code to force it get the newest element when filter is about to happen:
var el = $(this).find(filterEl);
if (options.filterChildSelector) el = el.find(options.filterChildSelector);
var self = this;
var filter = options.filter;
$(inputEl).keyup(function(){
el = $(self).find(filterEl);
if (options.filterChildSelector) el = el.find(options.filterChildSelector);
var val = $(this).val();
var contains = el.filter(function(){
return filter(this, val);
});
var containsNot = el.not(contains);
if (options.filterChildSelector){
contains = contains.parents(filterEl);
containsNot = containsNot.parents(filterEl).hide();
}
options.before.call(this, contains, containsNot);
contains.show();
containsNot.hide();
if (val === '') {
contains.show();
containsNot.show();
}
options.after.call(this, contains, containsNot);
So now it works. See Demo
You are finding the filter elements once, and only once:
var el = $(this).find(filterEl);
if (options.filterChildSelector) el = el.find(options.filterChildSelector);
Later, on keyup you use this variable el to further filter the elements, however if you have added any new li between intialising the plugin, and pressing a key, the new elements are not included in the pre-defined list el.
The answer is to look for elements live on each keyup and not cache it away in a variable.
That should be as easy as wrapping the above 2 lines in a function:
function getFilterElements(){
var el = $(this).find(filterEl);
if (options.filterChildSelector) el = el.find(options.filterChildSelector);
return el;
}
And calling that later in keyup:
var self = this;
$(inputEl).keyup(function(){
var val = $(this).val();
var el = getFilterElements.call(self)
var contains = el.filter(function(){
return filter(this, val);
});
...
Live example: http://jsfiddle.net/56xsvosq/

jQuery click(function(event) hyperlinks won't work

I can't figure out why the hyperlinks wont work when using a jQuery click event.
I would like 1 button to work as a link
and one as a jump to in the current page.
div class="shortcat">
<i class="icon-thumbs-up"></i>Test Now
<i class="icon-picture"></i>Learn More
</div>
//--------- jQuery ---------------//
jQuery(window).load(function() {
jQuery("#loaderInner").fadeOut();
jQuery("#loader").delay(400).fadeOut("slow");
$('.teaserTitle ').stop().animate({marginTop :'330px', opacity:"1"}, 1000, 'easeOutQuint');
$('.shortcat a ').stop().animate({marginTop :'65px', opacity:"1"}, 600, 'easeOutQuint');
});
$(document).ready(function(){
$("#mainNav ul a, .logo a, .shortcat a, .notBtn a").click(function(event){
event.preventDefault();
var full_url = this.href;
var parts = full_url.split("#");
var trgt = parts[1];
var target_offset = $("#"+trgt).offset();
var target_top = target_offset.top;
$('html,body').animate({scrollTop:target_top -80}, 800);
});
//-------------Highlight the current section in the navigation bar------------//
var sections = $("section");
var navigation_links = $("#mainNav a");
sections.waypoint({
handler: function(event, direction) {
var active_section;
active_section = $(this);
if (direction === "up") active_section = active_section.prev();
var active_link = $('#mainNav a[href="#' + active_section.attr("id") + '"]');
navigation_links.removeClass("active");
active_link.addClass("active");
},
offset: '35%'
});
First part is the HTML the second part is my script.js
I think the click function event is wrong.
When i remove the shortcut out of it the hyperlink will work but the jump to not anymore.
Will there be an easy fix?
here you go: this works well
http://jsfiddle.net/6g4j2/
$(document).ready(function(){
$("#mainNav ul a, .logo a, .shortcat a, .notBtn a").click(function(event){
var full_url = this.href;
var parts = full_url.split("#");
var trgt = parts[1];
if (trgt != undefined) {
event.preventDefault();
var target_offset = $("#"+trgt).offset();
var target_top = target_offset.top;
$('html,body').animate({scrollTop:target_top -80}, 800);
return false;
}
});
});
most likely the function from the click event fails here
var trgt = parts[1];
for the first link, because parts will be undefined

Categories