I have a script that makes me able to drag some content in a div.
But because you can drag around, no matter where you place the cursor in the div, I am not able to input some text in a text field.
Is it possible to allow that?
I can eaily click links in the div container. But not input text in a html input field.
This is the javascript:
$(document).ready(function () {
$('#roadmap').mousedown(function (event) {
$(this)
.data('down', true)
.data('x', event.clientX)
.data('scrollLeft', this.scrollLeft);
return false;
}).mouseup(function (event) {
$(this).data('down', false);
}).mousemove(function (event) {
if ($(this).data('down') == true) {
this.scrollLeft = $(this).data('scrollLeft') + $(this).data('x') - event.clientX;
}
}).mousewheel(function (event, delta) {
this.scrollLeft -= (delta * 30);
}).css({
'overflow': 'hidden',
'cursor': 'col-resize'
});
});
$(window).mouseout(function (event) {
if ($('#roadmap').data('down')) {
try {
if (event.originalTarget.nodeName == 'BODY' || event.originalTarget.nodeName == 'HTML') {
$('#roadmap').data('down', false);
}
} catch (e) { }
}
});
This is my extended mousewheel function (if needed)
(function ($) {
$.event.special.mousewheel = {
setup: function () {
var handler = $.event.special.mousewheel.handler;
// Fix pageX, pageY, clientX and clientY for mozilla
if ($.browser.mozilla)
$(this).bind('mousemove.mousewheel', function (event) {
$.data(this, 'mwcursorposdata', {
pageX: event.pageX,
pageY: event.pageY,
clientX: event.clientX,
clientY: event.clientY
});
});
if (this.addEventListener)
this.addEventListener(($.browser.mozilla ? 'DOMMouseScroll' : 'mousewheel'), handler, false);
else
this.onmousewheel = handler;
},
teardown: function () {
var handler = $.event.special.mousewheel.handler;
$(this).unbind('mousemove.mousewheel');
if (this.removeEventListener)
this.removeEventListener(($.browser.mozilla ? 'DOMMouseScroll' : 'mousewheel'), handler, false);
else
this.onmousewheel = function () { };
$.removeData(this, 'mwcursorposdata');
},
handler: function (event) {
var args = Array.prototype.slice.call(arguments, 1);
event = $.event.fix(event || window.event);
// Get correct pageX, pageY, clientX and clientY for mozilla
$.extend(event, $.data(this, 'mwcursorposdata') || {});
var delta = 0, returnValue = true;
if (event.wheelDelta) delta = event.wheelDelta / 120;
if (event.detail) delta = -event.detail / 3;
if ($.browser.opera) delta = -event.wheelDelta;
event.data = event.data || {};
event.type = "mousewheel";
// Add delta to the front of the arguments
args.unshift(delta);
// Add event to the front of the arguments
args.unshift(event);
return $.event.handle.apply(this, args);
}
};
$.fn.extend({
mousewheel: function (fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
unmousewheel: function (fn) {
return this.unbind("mousewheel", fn);
}
});
})(jQuery);
And here goes the HTML
<div id="roadmap">
<ul>
<li class="roadmap_description">
<h2>Welcome</h2>
<p>Description</p>
</li>
<li><h3 class="milestone_name">v. 1.0.2.3</h3>
<ul>
<li class="milestone_item">Title description</li>
</ul>
<div class="milestone_item_add">
<input class="field" name="milestone_item_name" type="text" /><img src="/Intranet/admin/Intranet/css/images/icons/wand.png" alt="Add new" />
</div>
</li>
</ul>
</div>
Thank you.
The return false in mousedown prevents the mouse button press from having its default action, which is to focus the child <input>.
You could test event.target in the mousedown function to see if it's the <input> element, and if so just stop trying to handle it (return or return true straight away).
If you wanted to still allow the element to be dragged when the mouse is in the <input>, you could still return false but manually call focus() on the input in mousedown. The disadvantage of that would be that the user couldn't use drags to select part of the text, as inputs would normally allow.
Why dont you add a mouseover event to the textfield that sets this: $(this).data('down', false); ?
Related
I'm using the script below (adapted from https://htmldom.dev/drag-to-scroll/) which enables a website to be scrolled by dragging it. Additionally, I remove the default draggability for links and images via css such that the page can be dragged when the cursor is currently positioned on these elements.
document.addEventListener('DOMContentLoaded', () => {
let dragging; const pos = {};
const onClick = (e) => {
if(!dragging)
return;
e.preventDefault(); // somehow does not work: why?
e.stopImmediatePropagation();
};
const onMouseMove = (e) => {
dragging = true;
window.scroll(0, pos.top - (e.clientY - pos.y));
};
const onMouseUp = (e) => {
dragging = false;
e.target.removeEventListener('mousemove', onMouseMove);
e.target.removeEventListener('mouseup', onMouseUp);
e.target.removeEventListener('click', onClick);
};
const onMouseDown = (e) => {
pos.top = window.scrollY;
pos.y = e.clientY;
e.target.addEventListener('mousemove', onMouseMove);
e.target.addEventListener('mouseup', onMouseUp);
e.target.addEventListener('click', onClick);
};
document.addEventListener('mousedown', onMouseDown);
});
a, img {
user-drag: none;
-webkit-user-drag: none;
}
<div style="height:200vh; background:lightblue; padding:1em;">
<h1>Drag to scroll me</h1>
Dragging this link should NOT open the website (but does)
</div>
Problem
Preventing the default action (opening the link) does not work somehow. How can it be canceled in case of dragging?
The solution was a bit more complex than I thought, perhaps someone else has a better one. It requires an additional global function preventClick which prevents the event default and propagation.
The rest of the code looks like this now:
$(() => {
/*
require 'preventClick()';
*/
//------------------------------------------------------------------------------------
// $
//------------------------------------------------------------------------------------
const
$body = $('body'),
$head = $('head')
;
//------------------------------------------------------------------------------------
// var
//------------------------------------------------------------------------------------
const
pos = {}
;
let
clone
;
//------------------------------------------------------------------------------------
// ()
//------------------------------------------------------------------------------------
const
//------------------------------------------
onMouseMove = (e) => {
//------------------------------------------
window.scroll(0, pos.top - (e.originalEvent.clientY - pos.y));
},
//------------------------------------------
onMouseUp = function(e){
//------------------------------------------
$body.css('cursor', 'grab');
$(this)
.off('mousemove', null, onMouseMove)
.off('mouseup', null, onMouseUp)
;
}
;
//------------------------------------------------------------------------------------
// Events
//------------------------------------------------------------------------------------
$(document)
//------------------------------------------
.mousedown(function(e){
//------------------------------------------
$body.css('cursor', 'grabbing');
pos.top = window.scrollY;
pos.y = e.originalEvent.clientY;
$(this)
.one('dragstart', function(e){
clone = $(e.target).clone(true);
$(e.target)
.attr('onclick', 'preventClick(event)')
.one('click', function(e){
$(this).attr('onclick', clone.attr('onclick') || '');
})
;
})
.mousemove(onMouseMove)
.mouseup(onMouseUp)
;
})
;
$body
//------------------------------------------
.css('cursor', 'grab')
//------------------------------------------
;
//------------------------------------------------------------------------------------
// >>
//------------------------------------------------------------------------------------
$head.append(`<style>
a, img {
user-drag: none;
-webkit-user-drag: none;
}
</style>`);
});
I'm trying to make a sort of drag and drop puzzle website using uniform square images, and I've written the drag code to drag individual images by their <img> element.
However I noticed that while dragging an <img> element over another element with addEventListener("mousenter", function () {//code};) attached, the mouseenter event doesn't fire. If I move my mouse over the element without dragging the image, the event fires as normal.
Does anyone have any ideas on how to fix this problem? My only guess atm is that the <img> element is blocking the listener from seeing the mouse.
var dragImg = document.querySelector(".images img");
dragImg.addEventListener("mousedown", function () {
console.log("mousedown detected " + dragImg.clientHeight);
dragImg.setAttribute("id", "drag");
dragging = true;
});
dragImg.addEventListener("mousemove", function (event) {
if (dragging) {
dragImg.style.top = (event.clientY - dragImg.clientHeight/2) + "px";
dragImg.style.left = (event.clientX - dragImg.clientWidth/2) + "px";
}
});
dragImg.addEventListener("mouseup", function () {
console.log("mouseup detected");
dragging = false;
//reset position if not in clipboard
dragImg.removeAttribute("id");
dragImg.style.top = "";
dragImg.style.left = "";
});
//Clipboard behavior - This listener doesn't fire when dragging an img?
var clipboard = document.querySelector(".clipboard");
clipboard.addEventListener("mouseover", function () {
if (dragging) {
console.log("mouse entered clipboard!");
clipboard.style.backgroundColor = "red";
}
});
#drag {
position: absolute;
}
The problem is that the mouse never hover the .clipboard because the image always below the pointer.
The simple solution is to add pointer-events:none; (not supported on older browsers).
var dragImg = document.querySelector(".images img");
var dragging = false;
dragImg.addEventListener("mousedown", function (event) {
event.stopPropagation();
console.log("mousedown detected " + dragImg.clientHeight);
dragImg.setAttribute("id", "drag");
dragging = true;
document.addEventListener('mousedown', function documentMouseDown(){
if (dragging) {
dragImg.removeAttribute("id");
dragging = false;
document.removeEventListener('mousedown', documentMouseDown);
}
});
});
document.addEventListener("mousemove", function (event) {
if (dragging) {
dragImg.style.top = (event.clientY - dragImg.clientHeight/2) + "px";
dragImg.style.left = (event.clientX - dragImg.clientWidth/2) + "px";
}
});
dragImg.addEventListener("mouseup", function () {
console.log("mouseup detected");
dragging = false;
//reset position if not in clipboard
dragImg.removeAttribute("id");
dragImg.style.top = "";
dragImg.style.left = "";
});
//Clipboard behavior - This listener doesn't fire when dragging an img?
var clipboard = document.querySelector(".clipboard");
clipboard.addEventListener("mouseover", function () {
if (dragging) {
console.log("mouse entered clipboard!");
clipboard.style.backgroundColor = "red";
}
});
#drag {
position: absolute;
pointer-events:none;
}
.clipboard {
width:200px;
height:200px;
background:green;
}
img {
-webkit-user-select:none;
}
<div class="clipboard"></div>
<div class="images">
<img src="http://i.stack.imgur.com/NghNQ.jpg" />
</div>
http://jsbin.com/hugewi/edit?html,css,js
I have a little script running so i can scroll trough a div with the mousedown option. Unfortunately it resets on each click and i can't quite figure out why it is doing this.
<script>
$(function () {
var clicked = false, clickX;
$("#gallery").on({
'mousemove': function(e) {
clicked && updateScrollPos(e);
},
'mousedown': function(e) {
clicked = true;
clickX = e.pageX;
},
'mouseup': function() {
clicked = false;
$('html').css('cursor', 'auto');
}
});
var updateScrollPos = function(e) {
$('#gallery').scrollLeft($(window).scrollLeft() + (clickX - e.pageX));
}
});
</script>
I am assuming it has something to do with
clickX = e.pageX;
$('#gallery').scrollLeft($(window).scrollLeft() + (clickX - e.pageX));
Why am I? because : "Returns the horizontal coordinate of the event relative to whole document."
So I am assuming it takes the original position when you click but it doesnt update when you actually scroll this. Anyone has a fix for this?
http://jsfiddle.net/fLr4d7kt/6/
We have fixed it like this :
$(function () {
var scroll = 0;
$(function () {
var clicked = false, clickX;
$("#gallery").on({
'mousemove': function(e) {
clicked && updateScrollPos(e);
},
'mousedown': function(e) {
clicked = true;
clickX = e.pageX;
scroll = $('#gallery').scrollLeft();
},
'mouseup': function() {
clicked = false;
$('html').css('cursor', 'auto');
}
});
var updateScrollPos = function(e) {
$('#gallery').scrollLeft(scroll + (clickX - e.pageX));
}
});
});
js: http://jsfiddle.net/fLr4d7kt/10/
I use this function to enable swipe for navigation on my website.
Now it needs to read and proceed to the url with the class 'next'
<li class="next">Next</li>
Here I need you help to create that.
$(function () {
$(document).on('mousedown', 'div', function (e) {
var ref = arguments.callee;
var handle = $(this);
var startX = e.clientX;
var startY = e.clientY;
handle.off('mousedown', ref);
handle.on('mouseup', function(e) {
handle.off('mouseup', argument.call);
handle.on('mousedown', ref);
var endX = e.clientX;
var endY = e.clientY;
var distanceX = Math.(endX - startX);
var distanceY = Math.(endY - startY);
if (distanceX > 50) {
handle.trigger((endX > startX) ? 'swipeRight' : 'swipeLeft');
}
if (distanceY > 50) {
handle.trigger((endY < startY) ? 'swipeDown' : 'swipeUp');
}
e.preventDefault();
return false;
});
});
$(document).on('swipeRight', 'div', function(e) {
});
$(document).on('swipeLeft', 'div', function(e) {
});
$(document).on('swipeUp', 'div', function(e) {
});
$(document).on('swipeDown', 'div', function(e) {
});
});
Inside the swipeRight callback do:
window.location = $(".next a").attr("href")
First this code gets the element with a class of .next with children of a then gets the href property using the .attr() function and redirects the browser to the value of the href.
You can just query the anchor tag (a) which is a direct child of list with class next:
$(document).ready(function() {
console.log($('li.next > a').prop('href'));
});
Working fiddle:http://jsbin.com/ibIGoma/6/edit
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
});