jQuery event.stopPropagation() and event issues - javascript

I'm creating a jQuery script that add a pin to a map on click event, the problem is that i need that event to work only on the map not his sons too..
This is my code:
$("div#map").click(function (e) {
$('<div class="pin"></div>').css({
left: a_variable,
top: another_variable
}).appendTo(this);
$("div.pin").click(function (e) { e.stopPropagation(); });
})
Another problem is that under this code i have something like this:
$("div.pin").mousedown(function (e) {
if(e.which == 1) {
console.log("down");
moving = true;
$(this).addClass("moving");
} else if(e.which == 3) {
console.log("right");
}
});
Will this work with pins created after the script load too?
JsFiddle: http://jsfiddle.net/vB2Gb/

I made a number of adjustments to your code:
JSFiddle: http://jsfiddle.net/TrueBlueAussie/vB2Gb/1/
$(function () {
var $map = $("div#map");
$map.click(function (e) {
var $pin = $('<div class="pin"></div>').css({
left: (((e.pageX + 3 - $map.position().left) * 100) / $map.width()) + "%",
top: (((e.pageY - 10 - $map.position().top) * 100) / $map.height()) + "%"
});
$pin.appendTo($map);
})
$map.on('click', "div.pin", function (e) {
e.stopPropagation();
});
var moving = false;
var pin_id;
var pin_left;
var pin_top;
$map.on('mousedown', "div.pin", function (e) {
if (e.which == 1) {
console.log("down");
moving = true;
$(this).addClass("moving");
} else if (e.which == 3) {
console.log("right");
}
});
$map.on('contextmenu', "div.pin", function (e) {
return false;
});
$(document).mousemove(function (e) {
if (moving) {
if (e.pageX <= $map.position().left) {
pin_left = 0;
} else if (e.pageY <= $map.position().top) {
pin_top = 0;
} else {
console.log("moving");
pin_id = 1;
pin_left = (((e.pageX + 3 - $map.position().left) * 100) / $map.width());
pin_top = (((e.pageY - 10 - $map.position().top) * 100) / $map.height());
$(".moving").css("left", pin_left + "%");
$(".moving").css("top", pin_top + "%");
}
}
});
$(document).mouseup(function (e) {
if (moving) {
console.log("up");
moving = false;
$(".moving").removeClass("moving");
dbMovePin(pin_id, pin_left, pin_top);
}
});
});
function dbMovePin(pin_id, pin_left, pin_top) {
$.post(
"mapsave.php", {
action: "move_pin",
id: pin_id,
left: pin_left,
top: pin_top
},
function (data, status) {
//alert("Data: " + data + "\nStatus: " + status);
});
}
This includes using delegated events (with on) for both the mouse down events and the pin click. Sharing a single variable for the map etc

Event Delegation does what i need:
I've changed
$("div.pin").mousedown(function (e) { ... });
with
$("div#map").on("mousedown", "div", function (e) {

Since you are dealing with dynamically added elements, you need to use event delegation.
$("#map").click(function (e) {
$('<div class="pin"></div>').css({
left: a_variable,
top: another_variable
}).appendTo(this);
}).on('click', '.pin', function (e) {
//have a single delegated click handler
e.stopPropagation();
}).on('mousedown', '.pin', function (e) {
//use a delegated handler for mousedown also
if (e.which == 1) {
console.log("down");
moving = true;
$(this).addClass("moving");
} else if (e.which == 3) {
console.log("right");
}
})
Also see
Event binding on dynamically created elements?

Related

scrollIntoView not executed in touch event listener

I'm trying to make a vertical slide, it works on desktop with wheel event but the scrollIntoView methode doesn't get executed in a touch event listener.
Here is the code
let startClientY, endClientY;
page.addEventListener("touchstart", (event) => {
startClientY = event.touches[0].pageY;
}, false);
page.addEventListener("touchmove", (event) => {
endClientY = event.touches[0].pageY;
}, false);
page.addEventListener("touchend", (event) => {
let diff = startClientY - endClientY;
if (diff < -35) {
if( i !== 0 ) {
slides[i - 1].scrollIntoView({
behavior: "smooth", block: "start"
});
i--;
console.log('scroll top'); // this code is executed as well
}
} else if (diff > 35) {
if( i < slides.length -1) {
slides[i + 1].scrollIntoView({
behavior: "smooth", block: "start"
});
i++;
console.log('scroll down'); // this code is executed
}
}
startClientY = undefined;
endClientY = undefined;
}, false);
The weird point is that the console logs inside the conditions are executed and the scrollIntoView method works outside the eventListeners
What am I missing ?
The problem comes from scrollIntoView behavior option inside a touch event listener, I've found another way to achieve what I want.
let slideHeight = page.offsetHeight;
page.addEventListener("touchstart", function (event) {
startClientY = event.touches[0].pageY;
}, {
capture: true,
passive: true
});
page.addEventListener("touchmove", function (event) {
endClientY = event.touches[0].pageY;
}, {
capture: true,
passive: true
});
page.addEventListener("touchend", (event) => {
let diff = startClientY - endClientY;
if (diff < -35) {
if (i !== 0) {
page.scrollBy(0, -slideHeight);
i--;
}
} else if (diff > 35) {
if (i < slides.length - 1) {
page.scrollBy(0, slideHeight);
i++;
}
}
startClientY = undefined;
endClientY = undefined;
}, {
capture: true,
passive: true
});
Where page variable are my slides
Hope it helps !
add touch-action: none; to your css
Using event.preventDefault() keep the browser from continuing to process the touch event.
page.addEventListener("touchstart", (event) => {
event.preventDefault();
......
}, false);
ref: https://developer.mozilla.org/en-US/docs/Web/API/Touch_events

jQuery change page and show tab on menu entry click

var tab = null;
var menuSelector = null;
jQuery(function ($) {
console.log('test');
//howtos tab
function changeMenuSelector() {
if ($( document ).width() > 967) {
menuSelector = 'top-menu-nav';
} else {
menuSelector = 'mobile_menu';
}
}
changeMenuSelector();
$( window ).resize(function() {
changeMenuSelector();
});
$('#'+menuSelector+' a[href*="howtos"]').on('click', function(event){
var e = event;
var $ = jQuery;
setTimeout(function () {
e.preventDefault();
console.log('pluto');
window.localStorage.setItem('tab', 'et_pb_tab_0');
if(window.location.pathname.indexOf('blog-posts') === -1)
{
window.location.href='http://www.davidepugliese.com/blog-posts/';
} else {
tab = localStorage.getItem('tab');
$("li."+tab+">a")[0].click();
window.localStorage.removeItem('tab');
}
},1000);});
$('#'+menuSelector +' a[href*="projects"]').on('click', function(e){
e.preventDefault();
console.log('pluto');
localStorage.setItem('tab', 'et_pb_tab_1');
if(window.location.pathname.indexOf('blog-posts') === -1)
{
window.location.href='http://www.davidepugliese.com/blog-posts/';
} else {
tab = localStorage.getItem('tab');
$("li."+tab+">a")[0].click();
localStorage.removeItem('tab');
}
});
$('#'+menuSelector +' a[href*="reviews"]').on('click', function(e){
e.preventDefault();
console.log('pluto');
localStorage.setItem('tab', 'et_pb_tab_2');
if(window.location.pathname.indexOf('blog-posts') === -1)
{
window.location.href='http://www.davidepugliese.com/blog-posts/';
} else {
tab = localStorage.getItem('tab');
$("li."+tab+">a")[0].click();
localStorage.removeItem('tab');
}
});
$('#'+menuSelector +' a[href*="elearning"]').on('click', function(e){
e.preventDefault();
console.log('pluto');
localStorage.setItem('tab', 'et_pb_tab_3');
if(window.location.pathname.indexOf('blog-posts') === -1)
{
window.location.href='http://www.davidepugliese.com/blog-posts/';
} else {
tab = localStorage.getItem('tab');
$("li."+tab+">a")[0].click();
localStorage.removeItem('tab');
}
});
$('#'+menuSelector +' a[href*="others"]').on('click', function(e){
e.preventDefault();
console.log('pluto');
localStorage.setItem('tab', 'et_pb_tab_4');
if(window.location.pathname.indexOf('blog-posts') === -1)
{
window.location.href='http://www.davidepugliese.com/blog-posts/';
} else {
tab = localStorage.getItem('tab');
$("li."+tab+">a")[0].click();
localStorage.removeItem('tab');
}
});
if (!!localStorage.getItem('tab')) {
tab = localStorage.getItem('tab');
console.log(tab);
setTimeout(function(){$("li."+tab+">a")[0].click();}, 1)
$("html, body").animate({ scrollTop: $('.et_pb_module.et_pb_tabs.et_pb_tabs_0').offset().top },
1000);
localStorage.removeItem('tab');
}
});
I have created a script to show tabs in Divi when you click on a menu entry. Divi does not use ids and hrefs for this, so I had to use a script.
The problem that I am facing is that this script that I made does not work with Divi's mobile menu.
I checked if menuSelector changed properly and if changeMenuSelector got executed as expected.
Furthermore, $('#'+menuSelector+' a[href*="howtos"]').length returns 1 in console and if I run $('#'+menuSelector+' a[href*="howtos"]')[0] in console I obtain the expected DOM element whehter I have the browser window sized for mobile or for desktop devices.
I also tried using setTimeout in case the issue was that it needed some time to accomplish an earlier action without any luck.
Therefore, is there anyone that could tell me why this does not work when the website is running in mobile mode?
I solved the issue by refactoring the code like this:
jQuery(function ($) {
console.log('test');
var tab = null;
var menuSelector = null;
var guard = false;
function changeMenuSelector() {
if ($(document).width() > 967) {
menuSelector = 'top-menu-nav';
guard = false;
initEventListeners(guard);
} else {
menuSelector = 'mobile_menu';
guard = true;
initEventListeners(guard);
}
}
function initEventListeners(guard) {
var localGuard = null;
if (localGuard != guard) {
var hrefs = ['howtos', 'projects', 'reviews', 'elearning', 'others'];
hrefs.forEach(
function (element, index, array) {
$('#' + menuSelector + ' a[href*="' + element + '"]').off();
console.log(element);
$('#' + menuSelector + ' a[href*="' + element + '"]').on('click', function (e) {
e.preventDefault();
console.log('pluto');
window.localStorage.setItem('tab', 'et_pb_tab_' + index);
if (window.location.pathname.indexOf('blog-posts') === -1) {
window.location.href = 'http://www.davidepugliese.com/blog-posts/';
} else {
tab = localStorage.getItem('tab');
$("li." + tab + ">a")[0].click();
$("html, body").animate({ scrollTop: $('.et_pb_module.et_pb_tabs.et_pb_tabs_0').offset().top },
1000);
window.localStorage.removeItem('tab');
}
});
});
localGuard = guard;
}
}
changeMenuSelector();
initEventListeners();
$(window).resize(function () {
changeMenuSelector();
});
if (!!localStorage.getItem('tab')) {
tab = localStorage.getItem('tab');
console.log(tab);
setTimeout(function(){$("li."+tab+">a")[0].click();}, 1)
$("html, body").animate({ scrollTop: $('.et_pb_module.et_pb_tabs.et_pb_tabs_0').offset().top },
1000);
localStorage.removeItem('tab');
}
});

Navigating long un-ordered list

I have this long list with overflow: auto to scroll through it, i set it up for keyboard navigation, the problem is that when using the keyboard it doesn't scroll correctly!
check this jsFiddle
$('ul').keydown(function (e) {
if (e.keyCode == 38) { // up
var selected = $(".selected");
$listItems.removeClass("selected");
if (selected.prev().length == 0) {
selected.siblings().last().addClass("selected");
} else {
selected.prev().addClass("selected");
}
}
if (e.keyCode == 40) { // down
var selected = $(".selected");
$listItems.removeClass("selected");
if (selected.next().length == 0) {
selected.siblings().first().addClass("selected");
} else {
selected.next().addClass("selected");
}
}
})
});
$listItems.click(function () {
if ($(this).is('.selected')) {
return true;
} else {
$('li').removeClass('selected');
$(this).addClass('selected');
}
the behavior i'm looking for is the same behavior of the element when scrolling through a long list of elements using the keyboard this plugin SelectBoxIt show's what i'm looking for.
you can use this code instead, i used animate function to navigate inside the div if the list exceed the width of the ul tag :
http://jsfiddle.net/goldendousa/p6243/13/
$('ul').focus(function() {
if ($('ul li').is('.selected')) {
$('ul li').first().removeClass('selected');
} else {
$('ul li').first().addClass('selected');
}
});
$('ul').keydown(function(e) {
if (e.keyCode == 38) { // up
e.preventDefault();
var selected = $(".selected");
$("ul li").removeClass("selected");
if (selected.prev().length == 0) {
selected.siblings().last().addClass("selected");
var selectedTopOffset = selected.siblings().last().offset().top;
$('div').animate({
scrollTop: selectedTopOffset
}, 200);
} else {
selected.prev().addClass("selected");
var selectedTopOffset = $("div").scrollTop() + selected.position().top - $("div").height()/2 + selected.height()/2;
$('div').animate({
scrollTop: selectedTopOffset
}, 200);
}
}
if (e.keyCode == 40) { // down
e.preventDefault();
var selected = $(".selected");
$("ul li").removeClass("selected");
if (selected.next().length == 0) {
selected.siblings().first().addClass("selected");
if (selected.siblings().first().offset().top < 0) {
$('div').animate({
scrollTop: selected.siblings().first().offset().top
}, 200);
}
} else {
selected.next().addClass("selected");
var selectedTopOffset = $("div").scrollTop() + selected.position().top - $("div").height()/2 + selected.height()/2;
$('div').animate({
scrollTop: selectedTopOffset
}, 200);
}
}
});
$('li').click(function() {
if ($(this).is('.selected')) {
return true;
} else {
$('li').removeClass('selected');
$(this).addClass('selected');
}
});

hotspots not linking in product viewer

So using a script for 360 image rotation, i've set up a tags to act as hot spots and lead to different pages within a jquery mobile document. Everything works a desktop, but when i test the page on an ipad, none of the links do anywhere. Heres the script for the rotation.
<script>
jQuery(document).ready(function ($) {
var $product = $('#product'),
$imgs = $product.find(".child"),
imageTotal = $imgs.length - 1,
clicked = false,
widthStep = 4,
currPos,
currImg = 0,
lastImg = 0;
$imgs.bind('mousedown', function (e) {
e.preventDefault(); // prevent dragging images
})
.filter(':gt(0)').addClass('notseen');
$product.bind('mousedown touchstart', function (e) {
if (e.type == "touchstart") {
currPos = window.event.touches[0].pageX;
} else {
currPos = e.pageX;
}
clicked = true;
return false;
});
$(document)
.bind('mouseup touchend', function () {
clicked = false;
})
.bind('mousemove touchmove', function (e) {
if (clicked) {
var pageX;
if (e.type == "touchmove") {
pageX = window.event.targetTouches[0].pageX;
} else {
pageX = e.pageX;
}
widthStep = 4;
if (Math.abs(currPos - pageX) >= widthStep) {
if (currPos - pageX >= widthStep) {
currImg++;
if (currImg > imageTotal) {
currImg = 0;
}
} else {
currImg--;
if (currImg < 1) {
currImg = imageTotal;
}
}
currPos = pageX;
$imgs.eq(lastImg).addClass('notseen');
$imgs.eq(currImg).removeClass('notseen');
lastImg = currImg;
// $obj.html('<img src="' + aImages[options.currImg] + '" />');
}
}
});
});
</script>
I'm know its the script because when i remove it, the links work. Any ideas?
jQuery(document).ready() is not supported in jQM.
http://view.jquerymobile.com/1.3.0/docs/faq/dom-ready-not-working.php

How can I use the arrow keys in Jquery

I'm trying to mimic the Google suggestions list with this:
function el(tid) {
return document.getElementById(tid);
}
function addScript(u) {
var head = document.getElementsByTagName('head')[0],
sc2 = document.createElement('script');
sc2.src = u;
head.appendChild(sc2);
setTimeout(function () {
head.removeChild(sc2);
sc2 = null;
}, 600);
} //end addScript()
function suggest(data) {
var sel = el("test");
sel.innerHTML = '';
for (x = 0; x < data[1].length; x++) {
sel.innerHTML += '<li class="uli" >' + data[1][x][0] + '</li>';
}
}
el("inp").onkeyup = function () {
addScript("http://www.google.nl/complete/search?callback=suggest&q=" + this.value);
};
The problem is that I want to be able to come down in the suggestions list using the arrow keys, and secondary I want to show the 'current' suggestion value inside the input field. So I tried something like this using Jquery:
$("#inp").live("keydown", function (e) {
var curr = $('#test').find('.current');
if (e.keyCode == 40) {
if (curr.length) {
$(curr).attr('class', 'uli');
curr = $(curr).next();
}
if (curr.length) {
curr.attr('class', 'uli current');
} else {
$('#center li:first-child').attr('class', 'uli current');
}
}
if (e.keyCode == 38) {
if (curr.length) {
$(curr).attr('class', 'uli');
curr = $(curr).prev();
}
if (curr.length) {
curr.attr('class', 'uli current');
} else {
$('#center li:last-child').attr('class', 'uli current');
}
}
$("#inp").live("keydown", function (e) {
var search_terms = $('li.current').text();
if (e.keyCode == 40) {
$('#inp').val(search_terms);
}
if (e.keyCode == 38) {
$('#inp').val(search_terms);
}
It doesn't work because (I think..) the 'current' suggestion is immediately being requested by the previous code.
I have put everything over here: JS Bin
Why recreate the wheel?
jQuery UI Autocomplete
Or look at other plugins
The problem with your code is you need to cancel out the arrow keypresses when you call to get the values.
el("inp").onkeyup = function () {
//if not the arrow keys, fetch the list
if( ... ){
addScript("http://www.google.nl/complete/search?callback=suggest&q=" + this.value);
}
}
Also what is with el("inp") when you are using jQuery? I expected to see $("foo").keyup( function(){} );

Categories