I'm using firebug and the latest FF to debug this bit of javascript. When line #30 is hit in the debugger the screen tries to refresh with message
"To display this page, firefox must
send information that will repeat any
action (such as a search or order
confirmation) that was performed
earlier.
Javascript with line #'s Called via OnClick()
function EnterComment(divName, /*...couple other params*/) {
25
26 thatDiv = divName;
27 //...comment
28
29 // Mouse Position with offset
30 var x = window.event.screenX + 10;
31 var y = document.body.scrollTop + 20;
This doesn't work in IE either. Is there any way to get an exception from Firebug? Any other tips to fix this?
Firefox doesn't have a global "event" object at all. Instead, a reference to an essentially similar object is passed in to event handlers by the runtime system.
I can't tell what sort of code is that fragment you posted. As an example, if you're binding event handlers with the basic DOM 0 attributes, you can do this:
<a onclick='yourhandler(event)'>hi</a>
and then:
function yourhandler(event) {
event = event || window.event;
var X = event.screenX;
// ...
}
If, as you mention in a comment, you were to use jQuery to bind handlers, then it's even easier because it's the same in all browsers:
$(function() {
$('#myAnchor').click(function(event) {
var X = event.pageX;
});
});
Related
I have very basic promise based self-calling function that:
takes collection of divs with certain class
checks whether they have just been moved left or right
based on result makes choice to move (transform: translate) them
with classList.add() / classList.remove()
and on transitionend - calls itself
here is function:
function transitionTest(){
console.log('called --- transitionTest() ');
var dummies = document.getElementsByClassName('dummy'),
count = dummies.length;
if(window.cache==='right'){
var transitionCollection=0;
for(var i = 0; i < dummies.length; i++){
dummies[i].classList.remove('right');
dummies[i].addEventListener('transitionend', function(){
transitionCollection++;
if( transitionCollection === dummies.length ){
transitionTest();
}
});
}
window.cache='';
} else {
var transitionCollection=0;
for(var i = 0; i < dummies.length; i++){
dummies[i].classList.add('right');
dummies[i].addEventListener('transitionend', function(){
transitionCollection++;
if( transitionCollection === dummies.length ){
transitionTest();
}
});
}
window.cache='right';
}
and here is working fiddle
So, what is wrong?
Nothing, if you are accessing via modern browser but not latest versions
of Chrome on Windows
Nothing, if you are accessing via latest versions of Chrome on Windows but refrain from causing any mouse events such as mouseenter/leave, click, even window focus event (e.g. if you stand still)
If you do such, infinite left - right movement of dummy div will occasionally break, under unclear circumstances
What gets wrong:
Dummy div, which is moving left-right infinitely, on mouseenter, mouseleave, click, sometimes and sometimes not (exact conditions are unclear) will:
go to end CSS value without transition and resumes normal operation after a while
stop entirely and resumes normal operation after a while
slow down (!? yeah, I wish I was kidding ) and stop/go to end CSS value
These errors are occurring in Chrome 45 (Win 7) and, less intensively Chrome 42 (Win XP) - which are platforms that I was able to test by now. Just to note, upper code does not need to be cross browser, I'm fully aware of implications.
I noticed mousewheel event is happening multiple times in mac osx. Can be atributed to inertia feature.
Is there a way to fix this behaviour?
(self signed ssl no worries please!)
https://sandbox.idev.ge/roomshotel/html5_v2/
I'm using scrollSections.js https://github.com/guins/jQuery.scrollSections
And it uses mousewheel jquery plugin: https://github.com/brandonaaron/jquery-mousewheel
I'm seeing a lot of people having the same issue: https://github.com/brandonaaron/jquery-mousewheel/issues/36
There are some solutions but none works with scrollSections plugin.
Any ideas how to disable this inertia feature from JS?
My attempted fix:
// Fix for OSX inertia problem, jumping sections issue.
if (isMac) {
var fireEvent;
var newDelta = deltaY;
if (oldDelta != null) {
//check to see if they differ directions
if (oldDelta < 0 && newDelta > 0) {
fireEvent = true;
}
//check to see if they differ directions
if (oldDelta > 0 && newDelta < 0) {
fireEvent = true;
}
//check to see if they are the same direction
if (oldDelta > 0 && newDelta > 0) {
//check to see if the new is higher
if (oldDelta < newDelta) {
fireEvent = true;
} else {
fireEvent = false;
}
}
//check to see if they are the same direction
if (oldDelta < 0 && newDelta < 0) {
//check to see if the new is lower
if (oldDelta > newDelta) {
fireEvent = true;
} else {
fireEvent = false;
}
}
} else {
fireEvent = true;
}
oldDelta = newDelta;
} else {
fireEvent = true;
}
You can see fix implemented here: https://sandbox.idev.ge/roomshotel/html5_v2/ But it is a hit/miss.
The latest solution with timeouts had one major drawback: kinetic scrolling effect could last rather long (even 1s or so)... and disabling scrolling for 1-2 seconds wouldn't be the best decision.
Soooo, as promised, here's another approach.
Our goal is to provide one response for one user action, which in this case is scrolling.
What's 'one scrolling'? For the sake of solving this problem, let's say that 'one scrolling' is an event that lasts from the moment the page has started to move till the moment the movement has ended.
Kinetic scrolling effect is achieved by moving the page many times (say, every 20ms) for a small distance. It means that our kinetic scrolling consists of many-many little linear 'scrollings'.
Empirical testing has showed that this little 'scrollings' happen every 17-18ms in the middle of kinetic scroll, and about 80-90ms at the beginning and the end. Here's a simple test we can set up to see that:
var oldD;
var f = function(){
var d = new Date().getTime();
if(typeof oldD !== 'undefined')
console.log(d-oldD);
oldD = d;
}
window.onscroll=f;
Important! Every time this mini-scroll happens, scroll event is triggered. So:
window.onscroll = function(){console.log("i'm scrolling!")};
will be fired 15 to 20+ times during one kinetic scroll. BTW, onscroll has really good browser support (see compatibility table), so we can rely on it (except for touch devices, I'll cover this issue a bit later);
Some may say that redefining window.onscroll is not the best way to set event listeners. Yes, you're encouraged to use
$(window).on('scroll',function(){...});
or whatever you like, it's not the point of the problem (I personally use my self-written library).
So, with the help of onscroll event we can reliably say whether this particular mini-movement of the page belongs to one long-lasting kinetic scroll, or is it a new one:
var prevTime = new Date().getTime();
var f = function(){
var curTime = new Date().getTime();
if(typeof prevTime !== 'undefined'){
var timeDiff = curTime-prevTime;
if(timeDiff>200)
console.log('New kinetic scroll has started!');
}
prevTime = curTime;
}
window.onscroll=f;
Instead of "console.log" you can call your desired callback function (or event handler) and you're done!
The function will be fired only once on every kinetic or simple scroll, which was our goal.
You may have noticed that I've used 200ms as a criteria of whether it's a new scroll or a part of the previous scroll. It's up to you to set it to greater values to be 999% sure you prevent any extra calls. However, please keep in mind that it's NOT what we have used in my previous answer. It's just a period of time between any two page movements (whether it's a new scroll or a little part of a kinetic scroll). To my mind, there's a very little chance that there will be a lag more than 200ms between steps in kinetic scroll (otherwise it will be not smooth at all).
As I've mentioned above, the onscroll event works differently on touch devices. It won't fire during every little step of kinetic scroll. But it will fire when the movement of the page has finally ended. Moreover, there's ontouchmove event... So, it's not a big deal. If necessary, I can provide solution for touch devices too.
P.S. I understand that I've written a bit too much, so I'd be happy to answer all your questions and provide further code if you need one.
Provided solution is supported in all browsers, very lightweight and, what's more important, is suitable not only for macs, but for every device that might implement kinetic scrolling, so I think it's really a way to go.
You know, I think it's a better idea to use timeouts in this case. Why not write something like this:
// Let's say it's a global context or whatever...:
var fireEvent = true;
var newDelta, oldDelta, eventTimeout;
newDelta = oldDelta = eventTimeout = null;
// ... and the function below fires onmousewheel or anything similar:
function someFunc(){
if(!fireEvent) return; // if fireEvent is not allowed => stop execution here ('return' keyword stops execution of the function), else, execute code below:
newDelta = deltaY;
if(oldDelta!=null&&oldDelta*newDelta>0){ // (1.1) if it's not the first event and directions are the same => prevent possible dublicates for further 50ms:
fireEvent = false;
clearTimeout(eventTimeout); // clear previous timeouts. Important!
eventTimeout = setTimeout(function(){fireEvent = true},500);
}
oldDelta = newDelta;
someEventCallback(); // (1.2) fire further functions...
}
So, any mousewheel event fired within half a second after any previous mousewheel event call will be ignored, if it is made in the same direction as previous (see condition at 1.1). It will solve the problem and there's no way user would spot this. Delay amount may be changed to better meet your needs.
The solution is made on pure JS. You're welcome to ask any questions about integrating it in your environment, but then I'll need you to provide further code of your page.
P.S. I have not seen anything similar to eventCallback() call in your code (see 1.2 of my solution). there was only fireEvent flag. Were you doing something like:
if(fireEvent)
someEventCallback();
later on or something?
P.P.S.note that fireEvent should be in global scope in order to work here with setTimeout. If it's not, it's also quite easy to make it work fine, but the code needs to be altered a bit. If it's your case, tell me and I'll fix it for you.
UPDATE
After a brief search I found out, that similar mechanism is used in Underscore's _debounce() function. See Underscore documentation here
Have you though about using fullpage.js instead?
It has a delay between arriving to a section and the moment you are able to scroll to the next section which solves part of the problem Mac users experience with track-pads or Apple magic mouses.
It would also provide you some other benefits, such as much more options, methods and compatibility with touch devices and old browsers with no CSS3 support.
To have something to start with, let's make your solution shorter (therefore easier to understand & debug):
var fireEvent;
var newDelta = deltaY;
var oldDelta = null;
fireEvent = EventCheck();
oldDelta = newDelta;
function EventCheck(){
if(oldDelta==null) return true; //(1.1)
if(oldDelta*newDelta < 0) return true; // (1.2) if directions differ => fire event
if(Math.abs(newDelta)<Math.abs(oldDelta)) return true; // (1.3) if oldDelta exceeds newDelta in absolute values => fire event
return false; // (1.4) else => don't fire;
}
As you see, it does absolutely what your code does.
However, I can't understand this part of your code (which corresponds to (1.3) in my snippet):
//check to see if the new is lower
if (oldDelta > newDelta) {
fireEvent = true;
} else {
fireEvent = false;
}
from code provided it's unclear how deltaY is calculated. As one could assume, delta equals to endPosition - initialPosition. So, oldDelta>newDelta does not mean that the new position is lower, but that the new gap between these two values is bigger. If it's what it mean and you still use it, I suppose you try to track inertia with that. Then you should alter comparative operator (use less than, instead of greater then and vice-versa). In other words, I'd write:
if(Math.abs(newDelta)>Math.abs(oldDelta)) return true; // (1.3)
you see, now I've used 'greater than' operator, which means: newDelta exceeds oldDelta in absolute values => it's not inertia and you can still fire the event.
Is it what you're trying to achieve or have I misinterpreted your code? If so, please explain how deltaY is calculated and what was your goal by comparing old&new Deltas.
P.S. I'd suggest not to use if(isMac) in this step, while a problem can also potentially hide there.
It's OS/user dependant. Not the browser, not the website, but the OS decides how fast and slow a double click must be.
I'd like to use that number in my app. Is there a way to get that number with JS?
Simple question. Might not be possible.
Thanks
Simple answer: no, sorry.
The best you could do would be something like this (example uses jQuery simply because it was quicker to write, the principle holds if jQuery is unavailable. Also note that this could well be simplified, this is just what came to mind first):
var timer,
num = 0;
$("#example").click(function() {
/*This condition is required because 2 click events are fired for each
dblclick but we only want to record the time of the first click*/
if(num % 2 === 0) {
timer = (new Date()).getTime();
}
num++;
}).dblclick(function() {
var time2 = (new Date()).getTime(),
dblClickTime = time2 - timer;
});
Unfortunately, that's probably not very helpful. You may be able to record the dblClickTime values and check for the longest, but that still is very unlikely to be the actual value you're after. That sort of thing is just not available through JavaScript.
Answer 2021 - as far as I know - still not. There is a reason: we should not care.
In principle dblclick is somehow obsolete …
We have the not well known detail property. Maybe because of the name.
From MDN:
The MouseEvent object passed into the event handler for click has its detail property set to the number of times the target was clicked. In other words, detail will be 2 for a double-click, 3 for triple-click, and so forth. This counter resets after a short interval without any clicks occurring; the specifics of how long that interval is may vary from browser to browser and across platforms. The interval is also likely to be affected by user preferences; for example, accessibility options may extend this interval to make it easier to perform multiple clicks with adaptive interfaces.
With detail ie. click_count it is possible to stop propagation of CLICK when detail != 1
So pseudcode:
if evt.detail==1
do_click()
if evt.detail==2
do_dblclick()
...
if evt.detail!=1
evt.stopPropagation()
If someone really needs to distinguish between click, double-click, triple-click, … like an 'XOR', they should really rethink the design.
The DblClickTime can be very long, that means the app feels like not responding, if the user just wants the click-action.
The other problem is, that it is possible, that users intention is a double-click, but is to slow - then there are two click-actions, they should not be to different to dblclick.
I'd like to use that number in my app. Is there a way to get that number with JS?
Definitely not - stuff like this is outside JavaScript's scope.
You may be able to find out values that work for a double click by asking the user to double-click, listen to the click events and see whether the dblclick event is fired - I'm nnot sure whether event handling works that way, though. But even if that works, it is still a long way from actually finding out the actual value.
This is my 2015 solution, would like to see a pure js version tho.
var start;
var click = null;
$(document).click(function() {
var now = performance.now();
start = click ? click : now;
click = now;
}).dblclick(function() {
alert(performance.now()-start)
});
EDIT
Pure JS
var start;
var click = null;
var getStart = function() {
var now = performance.now();
start = click ? click : now;
click = now;
}
var getStop = function() {
alert(performance.now()-start)
}
if (window.addEventListener) {
window.addEventListener('click', getStart , false);
} else {
window.attachEvent('onclick', function() {
return(getStart.call(window, window.event));
});
}
if (window.addEventListener) {
window.addEventListener('dblclick', getStop , false);
} else {
window.attachEvent('ondblclick', function() {
return(getStop.call(window, window.event));
});
}
Adding on to James Allardice's answer:
Depending on your implementation and where you are looking for double clicks you may want to also check the users mouse location (or I guess tap location). This is to avoid a double click firing when the user is clicking things on different parts of your page (again depends on your event listener implementation -- if it is just on one button for example this probably isn't an issue).
When a click event fires the event listener in my example below has two variables e.clientX and e.clientY. This will give you the location of the mouse. You might want to check to see if the user has moved their mouse significantly since the first click (adapt accordingly to your code).
document.addEventListener("click", function(e){ console.log("Mouse X: " + e.clientX + ": Mouse Y: " + e.clientY); });
You don't want to have it be too tight or else a user may never be able to fire a double click, and you don't want it to be too loose so that double clicks fire seemingly randomly for the user. Maybe start with a 25px or so box around the first click (again this depends on your application). This is something you can test and adjust based on your user interface.
I am assuming you don't have jQuery or aren't using it, because I believe jQuery might already do this calculation to fire dblclick
I wanted to find out the co-ordinates of the mouse click event on the page. Wrote a little piece of JS which works well on Chrome but not on Firefox. Seems the default global 'event' is not available in Firefox. Here is a smaller version of the code that worked on Chrome:
$("body").click(function() {
if (event == undefined) // for Chrome, 'event' is not undefined here
var event = window.event;
var xx;
var yy;
if (event) {
// Need this for Chrome (and IE)
xx = event.x;
yy = event.y;
} else {
// firefox
// WHAT SHOULD I DO HERE?
}
console.log('Click called on body.' + xx + ':' + yy);
}
What should I manage the Firefox case?
jQuery (which it looks like you are using) sorts out the event parameter versus global event property issue for you, so you don't need to worry about that. It also normalizes pageX and pageY properties.
$("body").click(function(evt) {
var xx = evt.pageX;
var yy = evt.pageY;
console.log('Click called on body.' + xx + ':' + yy);
});
JQuery passes the event as the first argument to your click handler.
You've forgotten to pass the event as a parameter. Use the below format, and do a console.log(e) to get all the data associated with it. But I'm not sure it has x and y coordinates, you might have to get the coordinates of the element it clicked.
$("body").click(function(e) {
}
EDIT: pageX and pageY seem to be provided, along with a bunch of others...
You need to pass the event variable in the click function call e.g.
.click(function(e){
console.log(e);
});
I'm getting a weird error where in Internet Explorer 7, when I call Math.round on a float it gives me an "Invalid Argument" error. Consider the following:
var elementLeft = parseInt(element.style.left); // Here we're actually getting NaN
function Foo(x) {
this.x = x;
this.apply = function(element) {
element.style.left = Math.round(this.x) + 'px';
};
}
Foo(elementLeft);
In this case x is a non-negative number and element is just a DOM element in my page (a div, in fact).
Any ideas?
EDIT: The variable passed in as the x parameter is actually initialized earlier as parseInt(element.style.left). It appears that the first time I try to read element.style.left, IE is actually giving back NaN. I have updated the code to reflect this. Anyone know any workarounds for this?
It appears that the first time I try to read element.style.left, IE is actually giving back NaN.
The first time you read element.style.left, is there actually any left style set on the element? Remember element.style only reflects style properties set in the inline style="..." attribute and not those applied by stylesheets.
If you haven't set an inline style, style.left will give you the undefined object, which does indeed parseInt to NaN.
Is IE defaulting x to a bad value?
Scroll down to Item 10 on this page:
Everything was working fine in
Firefox, Google Chrome etal. But I was
having problems with IE (of all
flavours). No selection tool would be
presented and a javascript warning was
produced which told me about an
'Invalid argument' being submitted to
the Math.round function.
The cause was that when you first
click on the image to start your
selection, the scaleX and scaleY
variables in the javascript on the
page result in a value of Infinity.
Firefox and every other browser seems
to silently step over this and carry
on processing as normal. IE of course
did not.
The solution was to add the following
line after the initial scaleX and
scaleY variables are calculated. This
appears to have solved the problem
fully. if(scaleX == Infinity || scaleY
== Infinity) return false; I hope this helps someone else and saves them the
hour of hunting it cost me ;o)
I don't think it's Math.round() that's giving you the error. It's probably the CSS subsystem. Try an alert() on the value that you're getting.
Some frameworks such as jQuery have facilities to read the calculated position of elements -- without requiring you to have explicitly set CSS position properties on them. Try reading the position of your element through jQuery. It might work.
For some reasons Javascript only works for the inline styling.
For example
<div style="left:500px;"></div>
if you wish to work on the position of an element, try setting the initial position in Java Script file, example:
function Xyz() {
var elem = document.getElementById('id');
elem.style.left = 500px;
numberLeft = 500;
//Now you can manipulate the position
var increment= 50;
var newLeft = numberLeft + increment;
elem.style.left = newLeft + 'px';
}
You get the idea. Put your logic in.