Click even it not working on Chrome browser - javascript

Hi I am trying to make drag drop feature in JS, It works fine in Firefox, but it doesn't work on chrome. I Think it is something to do with Event Deligation, I am attaching the link of my code base. Following are the steps to reproduce the problem:
Create a new Task
Drag it to another column
Now click on Edit or Delete Icon(E and D in circle).
Following are the Code highlights(Code is a bit bigger You can check it on Codepen):
JS:
$(function(){
function init(){
var mouseX = 0, // Mouse Position
mouseY = 0,
elmX = 0, // Element Position
elmY = 0,
pillers = $('.pillers'), // Task Container
pillerWidth = $('.pillers:nth-child(1)').width(), // Taks Container width
currentElm; // Current Element
/* When Left Mouse Button is Pressed */
$('.dragable').on('mousedown', function(e){
var temp;
$(this).addClass('rel');
mouseX = e.clientX; // Current Mouse Position and Store it to global variables
mouseY = e.clientY;
temp = +($(this).css('left').slice(0, -2)); // Get Element Position and if it not a number then change it to 0
elmX = null || isNaN(temp) ? 0 : temp;
temp = +($(this).css('top').slice(0, -2));
elmY = null || isNaN(temp) ? 0 : temp;
$(this).css({'z-index':'9999'}); // Increase the Z-Index of the Element so that it wont be overlapped by other element.
currentElm = $(this); // set the current value so that it could be use by mouse move
/* Some Hack for not let heighlight the data(Copied from net) */
document.body.focus();
document.onselectstart = function () { return false; };
$(this).ondragstart = function() { return false; };
return false;
}).on('mouseup',function(e){ // This will be fired when Mouse Button release back
if(currentElm !== null){
currentElm.removeClass('rel').prependTo('.arrived .tasks').css({ // Resetting the Position Object
left: 0,
top: 0
});
currentElm.css({'z-index' : '1'}); // Set Z-Index back to normal value.
currentElm = null; // Finally Set the Current Element to null so that it won't get dragged any more
}
}).on("mousemove", function(e){ // Mouse Move Event .. This is the main part, It will reposition the element with mouse pointer
if(currentElm !== undefined && currentElm !== null){
currentElm.addClass('draged').css({ // This sets the position of div element
left : (elmX + e.clientX - mouseX)+'px',
top : (elmY + e.clientY - mouseY)+'px'
});
/* Set Appropriate Class to Piller to Which The Element is going to be added */
if( e.clientX >= $('.pillers:nth-child(1)').offset().left && e.clientX < ($('.pillers:nth-child(1)').offset().left+pillerWidth) && e.clientY < $('.pillers:nth-child(1)').outerHeight()){
$('.pillers:nth-child(1)').addClass('arrived').siblings('.pillers').removeClass('arrived');
}else if(e.clientX >= $('.pillers:nth-child(2)').offset().left && e.clientX < ($('.pillers:nth-child(2)').offset().left+pillerWidth) && e.clientY < $('.pillers:nth-child(2)').outerHeight()){
$('.pillers:nth-child(2)').addClass('arrived').siblings('.pillers').removeClass('arrived');
}else if(e.clientX >= $('.pillers:nth-child(3)').offset().left && e.clientX < ($('.pillers:nth-child(3)').offset().left+pillerWidth) && e.clientY < $('.pillers:nth-child(3)').outerHeight()){
$('.pillers:nth-child(3)').addClass('arrived').siblings('.pillers').removeClass('arrived');
}else if(e.clientX >= $('.pillers:nth-child(4)').offset().left && e.clientX < ($('.pillers:nth-child(4)').offset().left+pillerWidth) && e.clientY < $('.pillers:nth-child(4)').outerHeight()){
$('.pillers:nth-child(4)').addClass('arrived').siblings('.pillers').removeClass('arrived');
}
}
});
$('a.remove').on('click',function(){
console.log('hey')
$(this).parents('.dragable').remove();
});
$('.add_task_button').on('click',function () {
var place= $(this).closest('.create_task_box'),
titl=place.find('input#title').val(),
disc=place.find('textarea#discription').val(),
time = new Date(),
format = time.toLocaleDateString();
if(titl || disc){
var val = $('.temp').clone(true).removeClass('temp hide').insertBefore(place);
val.find('#TaskHeading').val(titl).end().find('#task-discription').text(disc).end().find('.time').text(format).css({
left: 0,
top: 0
});
}
$('input#title, textarea#discription').val('');
});
$(document).on("click", ".edit", function(){
e.stopPropagation();
if($(this).is('.done')){
$(this).removeClass('done');
$(this).closest('.task-unit').addClass('dragable').find('input, textarea').attr('readonly', 'readonly').addClass('readonly');
}else{
$(this).addClass('done');
var task = $(this).closest('.dragable');
task.removeClass('dragable').find('input, textarea').removeAttr('readonly').removeClass('readonly');
}
});
}
init();
});
I am not mentioning the HTML and CSS part here because it will take a lot of space.. You can see full code Here on Codepen.
Let me know if anything else required.

The problem is, you have an object (parent) with a mousedown event and inside it, another object (children) with a click event. It seems that in Chrome, the first event (mousedown) is capturing the click over the buttons.
As a workaround, you can do this:
have a function for the mousedown event on the parent element.
unbind the mousedown event when the user does a mouseover event on the children.
bind again the function to the parent when the user does a mouseout off the parent.
As an example:
$(".theparent").on("mousedown",function(){
doThings();
});
$(".thechildren").on("click",function(){
alert("Child");
});
$(".thechildren").on("mouseover",function(){
$(this).closest(".theparent").off("mousedown");
console.log("Off");
});
$(".thechildren").on("mouseout",function(){
$(this).closest(".theparent").on("mousedown",doThings);
console.log("on");
});
function doThings(){
alert("Parent");
}
.theparent{
width:200px;
height:100px;
background-color:#3a3a3a;
position:absolute;
}
.thechildren{
position:relative;
background-color:#FF0000;
width:50px;
height:50px;
cursor:pointer;
left:50px;
top:25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="theparent">
<div class="thechildren">Child</div>
</div>
See it working on fiddle.

Related

OnMouseScroll increment a variable JS

I want to make a JS function.
It will work like this :
If I use my Mouse Wheel to Scroll Down so my variable will decrement. And if I use my Mouse Wheel to Scroll Up my variable will increment
I want to put that in a Condition with a max and min number.
I will send you a screenshot of my website and you will understand
So like you see, I need to make it work without scrollbar. I've only one page in 100vh.
I've make something very bad but you will understand the idea
https://jsfiddle.net/tuzycreo/
i= 1;
if (i>0 && i<5) {
//if(MouseScrollUp)
//i++;
document.querySelector('.number').innerHTML = i;
//else if(MouseScrollDown)
//i--;
// document.querySelector('.number').innerHTML = number;
}
Thanks you guys !
You can try like this,
var scrollCount = 0,
latestScrollTop = 0,
doc = document.documentElement,
top = 0;
// Bind window scroll event
$(window).bind('scroll', function (e) {
top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
if (latestScrollTop < top) {
// Scroll down, increment value
scrollCount += 1;
} else {
// Scroll up, decrement value
scrollCount -= 1;
}
// Store latest scroll position for next position calculation
latestScrollTop = top;
});
I make something that is working for me
https://jsfiddle.net/u93c9eth/2/
var scrollCount = 1;
window.addEventListener('mousewheel', function(e){
if(e.wheelDelta<0 && scrollCount<5){
scrollCount++;
}
else if(e.wheelDelta>0 && scrollCount>1){
scrollCount--;
}
document.querySelector('.number').innerHTML = scrollCount;
});

How to track mousepress event?

I have a draggable bar and it works well. https://jsfiddle.net/c2cqxcf8/2/
But if we drag it to the right border then up the mouse and try to drag it beyond the bar, crossing closest button with mouse and get the mouse back within bar, we see that mousemove event that supposed to be unbinded with help of mouseup event is not unbined and mousemove works for some reason. So i tried to track when mouse is pressed ,that is the only thing letting mousemove work but that code doesn't solve my problem so far. I count on your help, guys, i need to detect when mouse is pressed and only in that case let mousemove work and move my bar. Thanks!
This is JS and the entire document you can see in link above.
var info;
var dest;
var result;
var between = 0;
var mouseDown = 0;
$('.bar-button').on('mousedown', function(event){
mouseDown = 1;
info = event.pageX;
if(mouseDown == 1) {
$(document).on('mousemove', function(e) {
dest = e.pageX - info + between;
if(dest >= 0 && dest <= 240) {
result = dest;
}
$('.bar-button').css('left', result + 'px');
})
}
$(document).on('mouseup', function(){
mouseDown = 0;
$(document).unbind();
between = result;
})
})
I would consider using dragstart, drag, and dragend events together with your mousedown, mousemove and mouseup ones.
I added this to your code:
$('.bar-button').on('dragstart', function(event){
info = event.pageX;
$(document).on('drag', function(e) {
dest = e.pageX - info + between;
if(dest >= 0 && dest <= 240) {
result = dest;
}
$('.bar-button').css('left', result + 'px');
})
$(document).on('mouseup', function(){
$(document).unbind();
between = result;
});
$(document).on('dragend', function(){
$(document).unbind();
between = result;
});
});
To give you an idea I have forked your fiddle here https://jsfiddle.net/db5dLst2
It contains some duplicated code as a proof of concept but it can be nicely refactored into functions to avoid this.
Is it what you mean?
if(dest >= 0 && dest <= 240) {
result = dest;
}else $(document).unbind('mousemove');
I added else, wo when mouse is out of bar, mousemove vent is unbinded

Javascript drag and drop code works on div but doesn't work on img

I'm fairly new to JavaScript, so any help would be awesome!
I created this small block of code that let's me grab a div and drag it around. I assign the "dragme" id to the div and all is fine and dandy. The problem is that if I replace that div from my html and put an img element instead (obviously assigning the "dragme" id to the img), things don't work as expected.
When I click to drag the img, it actually moves for about 3 or 4 pixels then it freezes until I lift the mouse button (mouseup).
Is there some property or characteristic that would prevent the img element from acting the same way as the div does?
var isClicked = false;
var startClientX = 0;
var startClientY = 0;
var startLeft = 0;
var startTop = 0;
window.addEventListener("load", addListeners, true);
function addListeners()
{
document.getElementById("dragme").addEventListener("mousedown", mouseIsDown, false);
document.getElementById("dragme").addEventListener("mouseup", mouseIsUp, false);
window.addEventListener("mousemove", moveImage, false);
function mouseIsDown(e)
{
if (isClicked == false)
{
isClicked = true;
startClientX = e.clientX;
startClientY = e.clientY;
startLeft = document.getElementById("dragme").offsetLeft;
startTop = document.getElementById("dragme").offsetTop;
}
}
function mouseIsUp()
{
if (isClicked == true)
{
isClicked = false;
}
}
function moveImage(e)
{
if (isClicked == true)
{
imageLeftDif = e.clientX - startClientX;
imageTopDif = e.clientY - startClientY;
var newLeftPos = (startLeft + imageLeftDif) + "px";
var newTopPos = (startTop + imageTopDif) + "px";
document.getElementById("dragme").style.left = newLeftPos;
document.getElementById("dragme").style.top = newTopPos;
}
}
}
This fixed the problem (answer provided as a comment by syazdani):
I'd venture to say that the built in browser drag and drop for images
is kicking in. Try e.preventDefault and return false in the mousedown
handler. – syazdani Dec 2 '12 at 17:26

Scrolling child div scrolls the window, how do I stop that?

I have a div, with a scroll bar, When it reaches the end, my page starts scrolling. Is there anyway I can stop this behavior ?
You can inactivate the scrolling of the whole page by doing something like this:
<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
Found the solution.
http://jsbin.com/itajok
This is what I needed.
And this is the code.
http://jsbin.com/itajok/edit#javascript,html
Uses a jQuery Plug-in.
Update due to deprecation notice
From jquery-mousewheel:
The old behavior of adding three arguments (delta, deltaX, and deltaY)
to the event handler is now deprecated and will be removed in later
releases.
Then, event.deltaY must now be used:
var toolbox = $('#toolbox'),
height = toolbox.height(),
scrollHeight = toolbox.get(0).scrollHeight;
toolbox.off("mousewheel").on("mousewheel", function (event) {
var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
return !blockScrolling;
});
Demo
The selected solution is a work of art. Thought it was worthy of a plugin....
$.fn.scrollGuard = function() {
return this
.on( 'wheel', function ( e ) {
var event = e.originalEvent;
var d = event.wheelDelta || -event.detail;
this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
e.preventDefault();
});
};
This has been an ongoing inconvenience for me and this solution is so clean compared to other hacks I've seen. Curious to know how more about how it works and how widely supported it would be, but cheers to Jeevan and whoever originally came up with this. BTW - stackoverflow answer editor needs this!
UPDATE
I believe this is better in that it doesn't try to manipulate the DOM at all, only prevents bubbling conditionally...
$.fn.scrollGuard2 = function() {
return this
.on( 'wheel', function ( e ) {
var $this = $(this);
if (e.originalEvent.deltaY < 0) {
/* scrolling up */
return ($this.scrollTop() > 0);
} else {
/* scrolling down */
return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
}
})
;
};
Works great in chrome and much simpler than other solutions... let me know how it fares elsewhere...
FIDDLE
You could use a mouseover event on the div to disable the body scrollbar and then a mouseout event to activate it again?
E.g. The HTML
<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
content
</div>
And then the javascript like so:
var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
body.style.overflowY = 'auto';
}
As answered here, most modern browsers now support the overscroll-behavior: none; CSS property, that prevents scroll chaining. And that's it, just one line!
Here's a cross-browser way to do this on the Y axis, it works on desktop and mobile. Tested on OSX and iOS.
var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var deltaY = event.deltaY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
}, {passive:false});
scrollArea.addEventListener("touchstart", function(event) {
this.previousClientY = event.touches[0].clientY;
}, {passive:false});
scrollArea.addEventListener("touchmove", function(event) {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var currentClientY = event.touches[0].clientY;
var deltaY = this.previousClientY - currentClientY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
this.previousClientY = currentClientY;
}, {passive:false});
I wrote resolving for this issue
var div;
div = document.getElementsByClassName('selector')[0];
div.addEventListener('mousewheel', function(e) {
if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
e.preventDefault();
div.scrollTop = div.scrollHeight;
} else if (div.scrollTop + e.deltaY <= 0) {
e.preventDefault();
div.scrollTop = 0;
}
}, false);
If I understand your question correctly, then you want to prevent scrolling of the main content when the mouse is over a div (let's say a sidebar). For that, the sidebar may not be a child of the scrolling container of the main content (which was the browser window), to prevent the scroll event from bubbling up to its parent.
This possibly requires some markup changes in the following manner:
<div id="wrapper">
<div id="content">
</div>
</div>
<div id="sidebar">
</div>
See it's working in this sample fiddle and compare that with this sample fiddle which has a slightly different mouse leave behavior of the sidebar.
See also scroll only one particular div with browser's main scrollbar.
this disables the scrolling on the window if you enter the selector element.
works like charms.
elements = $(".selector");
elements.on('mouseenter', function() {
window.currentScrollTop = $(window).scrollTop();
window.currentScrollLeft = $(window).scrollTop();
$(window).on("scroll.prevent", function() {
$(window).scrollTop(window.currentScrollTop);
$(window).scrollLeft(window.currentScrollLeft);
});
});
elements.on('mouseleave', function() {
$(window).off("scroll.prevent");
});
You can inactivate the scrolling of the whole page by doing something like this but display the scrollbar!
<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
var scrollTop = this.scrollTop;
if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
e.preventDefault();
}
});
Based on ceed's answer, here is a version that allows nesting scroll guarded elements. Only the element the mouse is over will scroll, and it scrolls quite smoothly. This version is also re-entrant. It can be used multiple times on the same element and will correctly remove and reinstall the handlers.
jQuery.fn.scrollGuard = function() {
this
.addClass('scroll-guarding')
.off('.scrollGuard').on('mouseenter.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g[0].myCst = $g.scrollTop();
$g[0].myCsl = $g.scrollLeft();
$g.off("scroll.prevent").on("scroll.prevent", function() {
$g.scrollTop($g[0].myCst);
$g.scrollLeft($g[0].myCsl);
});
})
.on('mouseleave.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g.off("scroll.prevent");
});
};
One easy way to use is to add a class, such as scroll-guard, to all the elements in the page that you allow scrolling on. Then use $('.scroll-guard').scrollGuard() to guard them.
If you apply an overflow: hidden style it should go away
edit: actually I read your question wrong, that will only hide the scroll bar but I don't think that's what you are looking for.
I couldn't get any of the answers to work in Chrome and Firefox, so I came up with this amalgamation:
$someElement.on('mousewheel DOMMouseScroll', scrollProtection);
function scrollProtection(event) {
var $this = $(this);
event = event.originalEvent;
var direction = (event.wheelDelta * -1) || (event.detail);
if (direction < 0) {
if ($this.scrollTop() <= 0) {
return false;
}
} else {
if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
return false;
}
}
}

Detecting click event on padding only

I have an HTML element with some padding. I would like to detect for clicks on that element's padding. That is, I don't want the event to fire when the user clicks on the content, just the padding.
I needed this as well, but also wanted a "real" solution. The accepted answer does really not target the question "Detecting click event on padding only" but suggests an intrusive change to the markup.
A "padding click" can be detected simply by retrieving the elements padding settings, computed width and height and compare those values to the mouse click offsets :
function isPaddingClick(element, e) {
var style = window.getComputedStyle(element, null);
var pTop = parseInt( style.getPropertyValue('padding-top') );
var pRight = parseFloat( style.getPropertyValue('padding-right') );
var pLeft = parseFloat( style.getPropertyValue('padding-left') );
var pBottom = parseFloat( style.getPropertyValue('padding-bottom') );
var width = element.offsetWidth;
var height = element.offsetHeight;
var x = parseFloat( e.offsetX );
var y = parseFloat( e.offsetY );
return !(( x > pLeft && x < width - pRight) &&
( y > pTop && y < height - pBottom))
}
demo here -> http://jsfiddle.net/er5w47yf/
jQuery :
$('#element').on('click', function(e) {
if (isPaddingClick(this, e)) {
console.log('click on padding')
} else {
console.log('click on element')
}
})
native :
document.getElementById('element').addEventListener('click', function(e) {
if (isPaddingClick(this, e)) {
console.log('click on padding')
} else {
console.log('click on element')
}
}, false)
For convenience, this can be turned into a jQuery pseudo event handler :
(function($) {
var isPaddingClick = function(element, e) {
var style = window.getComputedStyle(element, null);
var pTop = parseInt( style.getPropertyValue('padding-top') );
var pRight = parseFloat( style.getPropertyValue('padding-right') );
var pLeft = parseFloat( style.getPropertyValue('padding-left') );
var pBottom = parseFloat( style.getPropertyValue('padding-bottom') );
var width = element.offsetWidth;
var height = element.offsetHeight;
var x = parseFloat( e.offsetX );
var y = parseFloat( e.offsetY );
return !(( x > pLeft && x < width - pRight) &&
( y > pTop && y < height - pBottom))
}
$.fn.paddingClick = function(fn) {
this.on('click', function(e) {
if (isPaddingClick(this, e)) {
fn()
}
})
return this
}
}(jQuery));
Now paddingClick works "natively" :
$('#element').paddingClick(function() {
console.log('padding click')
})
demo -> http://jsfiddle.net/df1ck59r/
Create an inner element which has 100% height/width so it fills out the whole element. Then register a click event handler on this event and prevent bubbling of the event.
Here's an example (using jQuery): http://jsfiddle.net/ThiefMaster/QPxAp/
The markup:
<div id="outer">
<div id="inner"></div>
</div>
and the JS code:
$('#outer').click(function() {
alert('click');
});
$('#inner').click(function(e) {
e.stopPropagation();
});
Since events bubble, the click event on the inner element hits this element first - stopping its propagation will prevent it from ever reaching the outer element, so its click event handler only triggers if the are that belongs to the element but is not covered by the inner element is clicked.
I think this is what ThiefMaster intended to describe. In this scenario, a click on the content will do nothing but a click on the div with lots of padding will yield an action.
Basic markup:
<div id="divWithPadding" style="padding:30px;">
<div>Content content content</div>
</div>
then
click listener for content div that prevents bubbling to divWithPadding:
$("#divWithPadding > div").click(function(e){
e.stopPropagation();
});
click listener for divWithPadding that does something:
$("#divWithPadding").click(function(){
//do something
});

Categories

Resources