Pushing mouse click location to an array in Javascript - javascript

I'm trying to push the coordinates of a mouse click on a particular element to the end of an array. This is what I have:
IN THE HEAD:
var seatsArray = [];
IN THE BODY:
var coordinates = document.getElementById("image");
coordinates.onclick = function(event) {
seatsArray.push(offsetX, offsetY);
}
document.write("Seats array contains: " + seatsArray + ".");
Probably something simple, but I'm new to javascript, so I'd appreciate any help as to why it isn't working!
Thanks

Two things I see, alter your on click event to this:
coordinates.onclick = function(event) {
event = event || window.event;
if (!window.event) { // thanks firefox
event.offsetX = event.layerX;
event.offsetY = event.layerY;
}
seatsArray.push(event.offsetX, event.offsetY);
}
Firefox offsetX/Y is layerX/Y, and ie have a global event object.
But if you wnt global cordinates try this:
coordinates.onclick = function(e) {
e = e || window.event;
if (e && e.pageX && e.pageY) {
e.posX = e.pageX;
e.posY = e.pageY;
} else if (e && e.clientX && e.clientY) {
var scr = {x:0,y:0},
object = e.srcElement || e.target;
//legendary get scrolled
for (;object.parentNode;object = object.parentNode) {
scr['x'] += object.scrollLeft;
scr['y'] += object.scrollTop;
}
e.posX = e.clientX + scr.x;
e.posY = e.clientY + scr.y;
}
seatsArray.push(e.posX, e.posY);
}

Related

Can I capture the mouse pointer in a Figma plugin window?

I have some code that I've used to create controls for a long time, and it works well, in that it properly captures and releases the mouse (at least in chrome).
function createSlider(slider, width, height)
{
slider.width = width;
slider.height = height;
slider.style.display = 'inline';
//
slider.onchange = new Event('onchange');
//
slider.addEventListener('mousedown', function(e)
{
var e = window.event || e;
if (e.button == 0)
{
e.preventDefault();
if (slider.setCapture)
slider.setCapture();
slider.mouseDown0 = true;
slider.sx = e.clientX;
slider.sv = slider.value;
}
});
slider.addEventListener('losecapture', function()
{
slider.mouseDown0 = false;
});
document.addEventListener('mouseup', function(e)
{
var e = window.event || e;
if (e.button == 0 && slider.mouseDown0)
slider.mouseDown0 = false;
}, true);
(slider.setCapture ? slider : document).addEventListener('mousemove', function(e)
{
if (slider.mouseDown0)
{
var dx = slider.sx - e.clientX;
var adaptive = 10 * Math.pow(Math.abs(dx), slider.acc);
slider.value = Math.min(Math.max(slider.min, slider.sv - dx*slider.scale*adaptive), slider.max);
//TODO: if (log) do log scaling
slider.paint();
slider.dispatchEvent(slider.onchange);
}
}, true);
slider.onmousewheel = function(e)
{
e.preventDefault();
var s = e.target;
s.value = Math.min(Math.max(s.min, s.value + (e.wheelDeltaY > 0 ? 1 : -1) * s.scale), s.max);
s.dispatchEvent(s.onchange);
s.paint();
};
slider.paint = function()
{
//...
};
//
slider.paint();
}
But when I tried using this code inside of a Figma plugin window, it loses mouse capture as soon as the mouse leaves the window. Is there something that I need to adjust for this to work?
Apparently you cannot, but you can use pointer lock to solve the issue for some situations.

Uncaught SyntaxError: Unexpected token < in dev_touch.js

I am new to jquery. I have found this code for getting touch events. but it shows this. I don't know how to solve this problem.
error message
Uncaught SyntaxError: Unexpected token < in dev_touch.js
My code :
dev_touch.js
;(function($) {
'use strict'
var $html = $('html');
mainBody = main.find('body');
main.addClass("dev_toucher");
mainBody.append("<div></div>").attr("class", "dev_ui_toucher");
if (typeof $html.createEvent !== 'function') return false // no tap events here
// helpers
var useJquery = typeof jQuery !== 'undefined',
msPointerEnabled = !!navigator.pointerEnabled || navigator.msPointerEnabled,
isTouch = (!!('ontouchstart' in win) && navigator.userAgent.indexOf('PhantomJS') < 0) || msPointerEnabled,
msEventType = function(type) {
var lo = type.toLowerCase(),
ms = 'MS' + type
return navigator.msPointerEnabled ? ms : lo
},
touchevents = {
touchstart: msEventType('PointerDown') + ' touchstart',
touchend: msEventType('PointerUp') + ' touchend',
touchmove: msEventType('PointerMove') + ' touchmove'
},
setListener = function(elm, events, callback) {
var eventsArray = events.split(' '),
i = eventsArray.length
while (i--) {
elm.addEventListener(eventsArray[i], callback, false)
}
},
getPointerEvent = function(event) {
return event.targetTouches ? event.targetTouches[0] : event
},
getTimestamp = function () {
return new Date().getTime()
},
sendEvent = function(elm, eventName, originalEvent, data) {
var customEvent = $html.createEvent('Event')
customEvent.originalEvent = originalEvent
data = data || {}
data.x = currX
data.y = currY
data.distance = data.distance
// jquery
if (useJquery) {
customEvent = $.Event(eventName, {originalEvent: originalEvent})
jQuery(elm).trigger(customEvent, data)
}
// addEventListener
if (customEvent.initEvent) {
for (var key in data) {
customEvent[key] = data[key]
}
customEvent.initEvent(eventName, true, true)
elm.dispatchEvent(customEvent)
}
// inline
if (elm['on' + eventName])
elm['on' + eventName](customEvent)
},
onTouchStart = function(e) {
var pointer = getPointerEvent(e)
// caching the current x
cachedX = currX = pointer.pageX
// caching the current y
cachedY = currY = pointer.pageY
timestamp = getTimestamp()
tapNum++
// we will use these variables on the touchend events
},
onTouchEnd = function(e) {
var eventsArr = [],
now = getTimestamp(),
deltaY = cachedY - currY,
deltaX = cachedX - currX
// clear the previous timer in case it was set
clearTimeout(tapTimer)
if (deltaX <= -swipeThreshold)
eventsArr.push('swiperight')
if (deltaX >= swipeThreshold)
eventsArr.push('swipeleft')
if (deltaY <= -swipeThreshold)
eventsArr.push('swipedown')
if (deltaY >= swipeThreshold)
eventsArr.push('swipeup')
if (eventsArr.length) {
for (var i = 0; i < eventsArr.length; i++) {
var eventName = eventsArr[i]
sendEvent(e.target, eventName, e, {
distance: {
x: Math.abs(deltaX),
y: Math.abs(deltaY)
}
})
}
} else {
if (
cachedX >= currX - tapPrecision &&
cachedX <= currX + tapPrecision &&
cachedY >= currY - tapPrecision &&
cachedY <= currY + tapPrecision
){
if((timestamp + tapThreshold) - now >= 0){
// Here you get the Tap event
sendEvent(e.target, (tapNum === 2) && (target === e.target) ? 'dbltap' : 'tap', e)
target= e.target
}
else if((timestamp + longtapThreshold) - now <= 0){
// Here you get the Tap event
sendEvent(e.target,'longtap', e)
target= e.target
}
}
// reset the tap counter
tapTimer = setTimeout(function() {
tapNum = 0
}, dbltapThreshold)
}
},
onTouchMove = function(e) {
var pointer = getPointerEvent(e)
currX = pointer.pageX
currY = pointer.pageY
},
swipeThreshold = win.SWIPE_THRESHOLD || 100,
tapThreshold = win.TAP_THRESHOLD || 150, // range of time where a tap event could be detected
dbltapThreshold = win.DBL_TAP_THRESHOLD || 200, // delay needed to detect a double tap
longtapThreshold = win.LONG_TAP_THRESHOLD || 1000, // delay needed to detect a long tap
tapPrecision = win.TAP_PRECISION / 2 || 60 / 2, // touch events boundaries ( 60px by default )
justTouchEvents = win.JUST_ON_TOUCH_DEVICES || isTouch,
tapNum = 0,
currX, currY, cachedX, cachedY, tapTimer, timestamp, target
//setting the events listeners
setListener($html, touchevents.touchstart + (justTouchEvents ? '' : ' mousedown'), onTouchStart)
setListener($html, touchevents.touchend + (justTouchEvents ? '' : ' mouseup'), onTouchEnd)
setListener($html, touchevents.touchmove + (justTouchEvents ? '' : ' mousemove'), onTouchMove)
//test.on('tap',updateHtml);
//test.on('dbltap',updateHtml);
//test.on('longtap',updateHtml);
//test.on('swipeup',updateHtml);
//test.on('swipedown',updateHtml);
//test.on('swipeleft',updateHtml);
//test.on('swiperight',updateHtml);
}(document, window))
Can anyone help ?
I would be willing to be that you're being served an HTML file instead of your JavaScript file. Here's how to check:
Right-click anywhere on the page
Select 'Inspect Element'
Find your JS file and examine the contents.
See the picture for a pictorial representation with Firefox.

Dragging div selects text on page (some browsers)

Im using the following function to drag a div with a handle.
Problem is that in some browsers when i drag at the same time text is selected and highlighted on the page..
Any ideas how to fix it?
function enableDragging (ele) {
var dragging = dragging || false,
x, y, Ox, Oy,
current;
enableDragging.z = enableDragging.z || 1;
var grabber = document.getElementById("myHandle");
grabber.onmousedown = function (ev) {
ev = ev || window.event;
var target = ev.target || ev.srcElement;
current = target.parentElement;
dragging = true;
x = ev.clientX;
y = ev.clientY;
Ox = current.offsetLeft;
Oy = current.offsetTop;
current.style.zIndex = ++enableDragging.z;
console.log(dragging);
document.onmousemove = function(ev) {
ev = ev || window.event;
//pauseEvent(ev);
if (dragging == true) {
var Sx = ev.clientX - x + Ox,
Sy = ev.clientY - y + Oy;
current.style.top = Sy + "px";
current.style.left = Sx + "px";
document.body.focus();
// prevent text selection in IE
document.onselectstart = function () { return false; };
// prevent IE from trying to drag an image
ev.ondragstart = function() { return false; };
return false;
}
}
document.onmouseup = function(ev) {
//alert("stop");
dragging && (dragging = false);
}
};
}
function pauseEvent(e){
if(e.stopPropagation) e.stopPropagation();
if(e.preventDefault) e.preventDefault();
e.cancelBubble=true;
e.returnValue=false;
return false;
}
Drag is started by:
var ele = document.getElementById("divWrapper");
enableDragging(ele);
I'm sorry, I forget the second question in your previous post. However, you need to prevent default from onmouseup too:
document.onmouseup = function(ev) {
ev = ev || window.event;
dragging && (dragging = false);
if (ev.preventDefault) {
ev.preventDefault();
} else {
ev.cancelBubble=true;
ev.returnValue=false;
}
return false;
}
EDIT
Or simply use your pauseEvent() function. Notice, that in your code there's this: ev.ondragstart = function () {...};. It's no use to assign the eventhandler to the Event object, rather assign that to the document or document.body. And also use that pauseEvent() in every eventhandler function too.
It looks like it's better to move document.onselectstart and document.ondragstart to the onmousedown handler, since those events have already fired when execution moves to onmousemove().

Javascript: Detect a click on the scroll bar? [duplicate]

I'm trying to create custom events in JQuery that are supposed to detect when a scrollbar is clicked1.
I know there's lots of text, but all my questions are boldfaced and there's a JSFiddle example you can work on straight away.
Because I haven't found any built in functionality for this,
I had to create a hasScroll function, checking if the element has a scrollbar,
$.fn.hasScroll = function(axis){
var overflow = this.css("overflow"),
overflowAxis;
if(typeof axis == "undefined" || axis == "y") overflowAxis = this.css("overflow-y");
else overflowAxis = this.css("overflow-x");
var bShouldScroll = this.get(0).scrollHeight > this.innerHeight();
var bAllowedScroll = (overflow == "auto" || overflow == "visible") ||
(overflowAxis == "auto" || overflowAxis == "visible");
var bOverrideScroll = overflow == "scroll" || overflowAxis == "scroll";
return (bShouldScroll && bAllowedScroll) || bOverrideScroll;
};
and an inScrollRange function, checking if the click performed was within the scroll range.
var scrollSize = 18;
function inScrollRange(event){
var x = event.pageX,
y = event.pageY,
e = $(event.target),
hasY = e.hasScroll(),
hasX = e.hasScroll("x"),
rX = null,
rY = null,
bInX = false,
bInY = false
if(hasY){
rY = new RECT();
rY.top = e.offset().top;
rY.right = e.offset().left + e.width();
rY.bottom = rY.top +e.height();
rY.left = rY.right - scrollSize;
//if(hasX) rY.bottom -= scrollSize;
bInY = inRect(rY, x, y);
}
if(hasX){
rX = new RECT();
rX.bottom = e.offset().top + e.height();
rX.left = e.offset().left;
rX.top = rX.bottom - scrollSize;
rX.right = rX.left + e.width();
//if(hasY) rX.right -= scrollSize;
bInX = inRect(rX, x, y);
}
return bInX || bInY;
}
Are all scrollbar sizes uniform? E.g in Firefox and IE it's 18px.
Assuming there are no customized scrollbars, is there any extra padding or sizes in some browsers?
These functions all perform as intended (from what I can discern).
Making custom events was a bit trickier, but I got it to work somewhat. The only problem is that if the element clicked has a mousedown/up event attached to it, that will be triggered as well.
I can't seem to stop the other events from triggering while simultaneously triggering, what I call, the mousedownScroll/mouseupScroll events.
$.fn.mousedownScroll = function(fn, data){
if(typeof fn == "undefined" && typeof data == "undefined"){
$(this).trigger("mousedownScroll");
return;
}
$(this).on("mousedownScroll", data, fn);
};
$.fn.mouseupScroll = function(fn, data){
if(typeof fn == "undefined" && typeof data == "undefined"){
$(this).trigger("mouseupScroll");
return;
}
$(this).on("mouseupScroll", data, fn);
};
$(document).on("mousedown", function(e){
if(inScrollRange(e)){
$(e.target).trigger("mousedownScroll");
}
});
$(document).on("mouseup", function(e){
if(inScrollRange(e)){
$(e.target).trigger("mouseupScroll");
}
});
$("selector").mousedown(function(e){
console.log("Clicked content."); //Fired when clicking scroller as well
});
$("selector").mousedownScroll(function(e){
console.log("Clicked scroller.");
});
How do I stop the other "click" events from triggering?
While I'm asking, please feel free to optimize the code as much as possible.
Here's a JSFiddle to mess around with.
The reason I'm making this is because of a bigger plugin I'm developing. It's got a custom context menu that is showing up when I right click one of the scrollers. I don't want that. So I thought I should make an event that checks for scroll clicks (mouseup/downs) and then prevent the context menu from being displayed. In order to do that though, I need the scroll click to come before the normal click, and also, if possible, stop the normal clicks from firing.
I'm just thinking out loud here but maybe there's a way to get all the functions that are bound to the element and then switch the order in which they were added? I know that functions are executed in the order they were added (1st added 1st called), so, if I could tap into that process, perhaps the whole "registering" of the event to JQuery could just be inserted before the click events.
1 can only use mousedown/mouseup because click doesn't trigger when clicking on a scrollbar. If this is false, please provide a working example/code
Solved:
A shortest scrollbar click detection I could come up with, tested on IE, Firefox, Chrome.
var clickedOnScrollbar = function(mouseX){
if( $(window).outerWidth() <= mouseX ){
return true;
}
}
$(document).mousedown(function(e){
if( clickedOnScrollbar(e.clientX) ){
alert("clicked on scrollbar");
}
});
Working example:
https://jsfiddle.net/s6mho19z/
Use following solution to detect if user clicked mouse over element's scrollbar. Didn't test how it works with window's scrollbar. I guess Pete's solution works better with window scrolls.
window.addEventListener("mousedown", onMouseDown);
function onMouseDown(e) {
if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight)
{
// mouse down over scroll element
}
}
You may probably use this hack.
You could try hijacking the mousedown and mouseup events and avoiding them when click on a scrollbar with your custom powered function.
$.fn.mousedown = function(data, fn) {
if ( fn == null ) {
fn = data;
data = null;
}
var o = fn;
fn = function(e){
if(!inScrollRange(e)) {
return o.apply(this, arguments);
}
return;
};
if ( arguments.length > 0 ) {
return this.bind( "mousedown", data, fn );
}
return this.trigger( "mousedown" );
};
And the inverse for mousedownScroll and mouseupScroll events.
$.fn.mousedownScroll = function(data, fn) {
if ( fn == null ) {
fn = data;
data = null;
}
var o = fn;
fn = function(e){
if(inScrollRange(e)) {
e.type = "mousedownscroll";
return o.apply(this, arguments);
}
return;
};
if ( arguments.length > 0 ) {
return this.bind( "mousedown", data, fn );
}
return this.trigger( "mousedown" );
};
By the way, I think the scrollbar width is an OS setting.
Ensure that the content of your scollarea completely [over]fills the parent div.
Then, you can differentiate between clicks on your content and clicks on your container.
html:
<div class='test container'><div class='test content'></div></div>
<div id="results">please click</div>
css:
#results {
position: absolute;
top: 110px;
left: 10px;
}
.test {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: green;
}
.container {
overflow: scroll;
}
.content {
background-color: red;
}
js:
function log( _l ) {
$("#results").html( _l );
}
$('.content').on( 'mousedown', function( e ) {
log( "content-click" );
e.stopPropagation();
});
$('.container').on( 'mousedown', function( e ) {
var pageX = e.pageX;
var pageY = e.pageY;
log( "scrollbar-click" );
});
http://codepen.io/jedierikb/pen/JqaCb
I had the same problem in a previous project, and i recommend this solution. It's not very clean but it works and i doubt we can do much better with html. Here are the two steps of my solution:
1. Measure the width of the scrollbar on your Desktop environment.
In order to achieve this, at application startup, you perform the following things:
Add the following element to the body:
<div style='width: 50px; height: 50px; overflow: scroll'><div style='height: 1px;'/></div>
Measure the with of the inner div of the previously added element with jQUery's .width(), and store the width of the scrollbar somewhere (the width of the scollbar is 50 - inner div's with)
Remove the extra element used to measure scrollbar (now that you have the result, remove the element that you added to the body).
All these steps should not be visible by the user and you have the width of the scrollbar on your OS
For example, you can use this snippet:
var measureScrollBarWidth = function() {
var scrollBarMeasure = $('<div />');
$('body').append(scrollBarMeasure);
scrollBarMeasure.width(50).height(50)
.css({
overflow: 'scroll',
visibility: 'hidden',
position: 'absolute'
});
var scrollBarMeasureContent = $('<div />').height(1);
scrollBarMeasure.append(scrollBarMeasureContent);
var insideWidth = scrollBarMeasureContent.width();
var outsideWitdh = scrollBarMeasure.width();
scrollBarMeasure.remove();
return outsideWitdh - insideWidth;
};
2. Check if a click is on the scrollbar.
Now that you have the width of the scrollbar, you can with the coordinates of the event compute the coordinates of the event relative to the scrollbar's location rectangle and perfom awesome things...
If you want to filter the clicks, you can return false in the handler to prevent their propagation.
There are many answers here that involve event.clientX, element.clientHeight, etc. They are all wrong. Do not use them.
As has been discussed above, there are platforms where the overflow: scroll scrollbars appear as overlays, or you may have forced it with overflow: overlay.
Macs may switch scrollbars between persistent and overlay by plugging or unplugging a mouse. This shoots down the "measure on startup" technique.
Vertical scrollbars appear on the left side with right to left reading order. This breaks comparing client width unless you have a bunch of special logic for right to left reading order that I bet will break because you're probably not testing RTL consistently.
You need to look at event.target. If necessary, use an inner element that occupies all of the client area of the scroll element, and see if event.target is that element or a descendant of it.
It should be pointed out that on Mac OSX 10.7+, there are not persistant scroll bars. Scroll bars appear when you scroll, and disappear when your done. They are also much smaller then 18px (they are 7px).
Screenshot:
http://i.stack.imgur.com/zdrUS.png
I'll submit my own answer and accept Alexander's answer, because it made it work perfectly, and upvote Samuel's answer, because it correctly calculates the scrollbar width, which is what I needed as well.
That being said, I decided to make two independent events instead of trying to overwrite/override JQuery's mousedown event.
This gave me the flexibility I needed without messing with JQuery's own events, and was quite easy to do.
mousedownScroll
mousedownContent
Below are the two implementations using Alexanders, and my own.
Both work as I originally intended them to, but the former is probably the best.
Here's a JSFiddle that implements Alexander's answer + Samuel's answer.
$.fn.hasScroll = function(axis){
var overflow = this.css("overflow"),
overflowAxis;
if(typeof axis == "undefined" || axis == "y") overflowAxis = this.css("overflow-y");
else overflowAxis = this.css("overflow-x");
var bShouldScroll = this.get(0).scrollHeight > this.innerHeight();
var bAllowedScroll = (overflow == "auto" || overflow == "visible") ||
(overflowAxis == "auto" || overflowAxis == "visible");
var bOverrideScroll = overflow == "scroll" || overflowAxis == "scroll";
return (bShouldScroll && bAllowedScroll) || bOverrideScroll;
};
$.fn.mousedown = function(data, fn) {
if ( fn == null ) {
fn = data;
data = null;
}
var o = fn;
fn = function(e){
if(!inScrollRange(e)) {
return o.apply(this, arguments);
}
return;
};
if ( arguments.length > 0 ) {
return this.bind( "mousedown", data, fn );
}
return this.trigger( "mousedown" );
};
$.fn.mouseup = function(data, fn) {
if ( fn == null ) {
fn = data;
data = null;
}
var o = fn;
fn = function(e){
if(!inScrollRange(e)) {
return o.apply(this, arguments);
}
return;
};
if ( arguments.length > 0 ) {
return this.bind( "mouseup", data, fn );
}
return this.trigger( "mouseup" );
};
$.fn.mousedownScroll = function(data, fn) {
if ( fn == null ) {
fn = data;
data = null;
}
var o = fn;
fn = function(e){
if(inScrollRange(e)) {
e.type = "mousedownscroll";
return o.apply(this, arguments);
}
return;
};
if ( arguments.length > 0 ) {
return this.bind( "mousedown", data, fn );
}
return this.trigger( "mousedown" );
};
$.fn.mouseupScroll = function(data, fn) {
if ( fn == null ) {
fn = data;
data = null;
}
var o = fn;
fn = function(e){
if(inScrollRange(e)) {
e.type = "mouseupscroll";
return o.apply(this, arguments);
}
return;
};
if ( arguments.length > 0 ) {
return this.bind( "mouseup", data, fn );
}
return this.trigger( "mouseup" );
};
var RECT = function(){
this.top = 0;
this.left = 0;
this.bottom = 0;
this.right = 0;
}
function inRect(rect, x, y){
return (y >= rect.top && y <= rect.bottom) &&
(x >= rect.left && x <= rect.right)
}
var scrollSize = measureScrollWidth();
function inScrollRange(event){
var x = event.pageX,
y = event.pageY,
e = $(event.target),
hasY = e.hasScroll(),
hasX = e.hasScroll("x"),
rX = null,
rY = null,
bInX = false,
bInY = false
if(hasY){
rY = new RECT();
rY.top = e.offset().top;
rY.right = e.offset().left + e.width();
rY.bottom = rY.top +e.height();
rY.left = rY.right - scrollSize;
//if(hasX) rY.bottom -= scrollSize;
bInY = inRect(rY, x, y);
}
if(hasX){
rX = new RECT();
rX.bottom = e.offset().top + e.height();
rX.left = e.offset().left;
rX.top = rX.bottom - scrollSize;
rX.right = rX.left + e.width();
//if(hasY) rX.right -= scrollSize;
bInX = inRect(rX, x, y);
}
return bInX || bInY;
}
$(document).on("mousedown", function(e){
//Determine if has scrollbar(s)
if(inScrollRange(e)){
$(e.target).trigger("mousedownScroll");
}
});
$(document).on("mouseup", function(e){
if(inScrollRange(e)){
$(e.target).trigger("mouseupScroll");
}
});
});
function measureScrollWidth() {
var scrollBarMeasure = $('<div />');
$('body').append(scrollBarMeasure);
scrollBarMeasure.width(50).height(50)
.css({
overflow: 'scroll',
visibility: 'hidden',
position: 'absolute'
});
var scrollBarMeasureContent = $('<div />').height(1);
scrollBarMeasure.append(scrollBarMeasureContent);
var insideWidth = scrollBarMeasureContent.width();
var outsideWitdh = scrollBarMeasure.width();
scrollBarMeasure.remove();
return outsideWitdh - insideWidth;
};
Here's a JSFiddle of what I decided to do instead.
$.fn.hasScroll = function(axis){
var overflow = this.css("overflow"),
overflowAxis,
bShouldScroll,
bAllowedScroll,
bOverrideScroll;
if(typeof axis == "undefined" || axis == "y") overflowAxis = this.css("overflow-y");
else overflowAxis = this.css("overflow-x");
bShouldScroll = this.get(0).scrollHeight > this.innerHeight();
bAllowedScroll = (overflow == "auto" || overflow == "visible") ||
(overflowAxis == "auto" || overflowAxis == "visible");
bOverrideScroll = overflow == "scroll" || overflowAxis == "scroll";
return (bShouldScroll && bAllowedScroll) || bOverrideScroll;
};
$.fn.mousedownScroll = function(fn, data){
var ev_mds = function(e){
if(inScrollRange(e)) fn.call(data, e);
}
$(this).on("mousedown", ev_mds);
return ev_mds;
};
$.fn.mouseupScroll = function(fn, data){
var ev_mus = function(e){
if(inScrollRange(e)) fn.call(data, e);
}
$(this).on("mouseup", ev_mus);
return ev_mus;
};
$.fn.mousedownContent = function(fn, data){
var ev_mdc = function(e){
if(!inScrollRange(e)) fn.call(data, e);
}
$(this).on("mousedown", ev_mdc);
return ev_mdc;
};
$.fn.mouseupContent = function(fn, data){
var ev_muc = function(e){
if(!inScrollRange(e)) fn.call(data, e);
}
$(this).on("mouseup", ev_muc);
return ev_muc;
};
var RECT = function(){
this.top = 0;
this.left = 0;
this.bottom = 0;
this.right = 0;
}
function inRect(rect, x, y){
return (y >= rect.top && y <= rect.bottom) &&
(x >= rect.left && x <= rect.right)
}
var scrollSize = measureScrollWidth();
function inScrollRange(event){
var x = event.pageX,
y = event.pageY,
e = $(event.target),
hasY = e.hasScroll(),
hasX = e.hasScroll("x"),
rX = null,
rY = null,
bInX = false,
bInY = false
if(hasY){
rY = new RECT();
rY.top = e.offset().top;
rY.right = e.offset().left + e.width();
rY.bottom = rY.top +e.height();
rY.left = rY.right - scrollSize;
//if(hasX) rY.bottom -= scrollSize;
bInY = inRect(rY, x, y);
}
if(hasX){
rX = new RECT();
rX.bottom = e.offset().top + e.height();
rX.left = e.offset().left;
rX.top = rX.bottom - scrollSize;
rX.right = rX.left + e.width();
//if(hasY) rX.right -= scrollSize;
bInX = inRect(rX, x, y);
}
return bInX || bInY;
}
function measureScrollWidth() {
var scrollBarMeasure = $('<div />');
$('body').append(scrollBarMeasure);
scrollBarMeasure.width(50).height(50)
.css({
overflow: 'scroll',
visibility: 'hidden',
position: 'absolute'
});
var scrollBarMeasureContent = $('<div />').height(1);
scrollBarMeasure.append(scrollBarMeasureContent);
var insideWidth = scrollBarMeasureContent.width();
var outsideWitdh = scrollBarMeasure.width();
scrollBarMeasure.remove();
return outsideWitdh - insideWidth;
};
The only solution that works for me (only tested against IE11):
$(document).mousedown(function(e){
bScrollbarClicked = e.clientX > document.documentElement.clientWidth || e.clientY > document.documentElement.clientHeight;
});
I needed to detect scrollbar on mousedown but not on window but on div,
and I've had element that fill the content, that I was using to detect size without scrollbar:
.element {
position: relative;
}
.element .fill-node {
position: absolute;
left: 0;
top: -100%;
width: 100%;
height: 100%;
margin: 1px 0 0;
border: none;
opacity: 0;
pointer-events: none;
box-sizing: border-box;
}
the code for detect was similar to #DariuszSikorski answer but including offset and using the node that was inside scrollable:
function scrollbar_event(e, node) {
var left = node.offset().left;
return node.outerWidth() <= e.clientX - left;
}
var node = self.find('.fill-node');
self.on('mousedown', function(e) {
if (!scrollbar_event(e, node)) {
// click on content
}
});
Tested and working in chrome and firefox in ubuntu 21.10.
const isScrollClick =
e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight;
clickOnScrollbar = event.clientX > event.target.clientWidth || event.clientY > event.target.clientHeight;
tested on Chrome / Mac OS

Check if one event is identical to another during event retargeting in older Internet Explorer

If you try this in Internet Explorer you can see that the dispatched event is not unique during bubbling:
var x;
myinnerdiv.onclick = function() { x = window.event; };
myparentdiv.onclick = function() { alert(x === window.event); };
// false, but should be the same!
Using the equivalent standards-based method:
var x;
myinnerdiv.onclick = function(ev) { x = ev; };
myparentdiv.onclick = function(ev) { alert(x === ev); };
// true: same event, retargeted
Is there a way to uniquely identify an event in code to work around this lack of functionality?
window.event is not a data value but a getter function to create event objects. Much like most
of the DOM properties are not data values but accessor functions.
You can even do them next to each other:
div.onclick = function() {
var a = window.event;
var b = window.event;
alert( a === b ) // false
};
Anyway, just make your own function:
window.getEvent = (function() {
var e = {};
return function() {
var cur = window.event;
if( cur.type === e.type &&
cur.srcElement === e.srcElement &&
cur.clientX === e.clientX &&
cur.clientY === e.clientY &&
cur.keyCode === e.keyCode ) {
return e.evt;
}
e.type = cur.type;
e.srcElement = cur.srcElement;
e.clientX = cur.clientX;
e.clientY = cur.clientY;
e.keyCode = cur.keyCode;
e.evt = cur;
return cur;
};
})();
myinnerdiv.onclick = function () {
var event = getEvent();
event.myCustomProp = 3;
};
myparentdiv.onclick = function () {
var event = getEvent();
alert( event.myCustomProp === 3 );
};
It assumes that these 5 values are enough to see if the event objects represent the same event, which seems reasonable to me.
Test page here, precisely click the text 'asd' (red colored), as the html is:
<div id="myparentdiv">
daa
<div id="myinnerdiv">asd</div>
daa
</div>
If you want something that works for sure then just use jQuery, you basically have to create an entire event model from scratch
to do this more cleanly (and always use that event model's API).
A simple way: just compare event1.timeStamp and event2.timeStamp

Categories

Resources