@@ -310,6 +310,8 @@ var // currently active contextMenu trigger
310
310
layerClick : function ( e ) {
311
311
var $this = $ ( this ) ,
312
312
root = $this . data ( 'contextMenuRoot' ) ,
313
+ mouseup = false ,
314
+ button = e . button ,
313
315
x = e . pageX ,
314
316
y = e . pageY ,
315
317
target ,
@@ -319,59 +321,83 @@ var // currently active contextMenu trigger
319
321
e . preventDefault ( ) ;
320
322
e . stopImmediatePropagation ( ) ;
321
323
322
- if ( ( root . trigger == 'left' && e . button == 0 ) || ( root . trigger == 'right' && e . button == 2 ) ) {
323
- if ( document . elementFromPoint ) {
324
- root . $layer . hide ( ) ;
325
- target = document . elementFromPoint ( x , y ) ;
326
- root . $layer . show ( ) ;
324
+ // This hack looks about as ugly as it is
325
+ // Firefox 12 (at least) fires the contextmenu event directly "after" mousedown
326
+ // for some reason `root.$layer.hide(); document.elementFromPoint()` causes this
327
+ // contextmenu event to be triggered on the uncovered element instead of on the
328
+ // layer (where every other sane browser, including Firefox nightly at the time)
329
+ // triggers the event. This workaround might be obsolete by September 2012.
330
+ $this . on ( 'mouseup' , function ( ) {
331
+ mouseup = true ;
332
+ } ) ;
333
+ setTimeout ( function ( ) {
334
+ var $window , hideshow ;
335
+
336
+ // test if we need to reposition the menu
337
+ if ( ( root . trigger == 'left' && button == 0 ) || ( root . trigger == 'right' && button == 2 ) ) {
338
+ if ( document . elementFromPoint ) {
339
+ root . $layer . hide ( ) ;
340
+ target = document . elementFromPoint ( x , y ) ;
341
+ root . $layer . show ( ) ;
327
342
328
- selectors = [ ] ;
329
- for ( var s in namespaces ) {
330
- selectors . push ( s ) ;
331
- }
343
+ selectors = [ ] ;
344
+ for ( var s in namespaces ) {
345
+ selectors . push ( s ) ;
346
+ }
332
347
333
- target = $ ( target ) . closest ( selectors . join ( ', ' ) ) ;
348
+ target = $ ( target ) . closest ( selectors . join ( ', ' ) ) ;
334
349
335
- if ( target . length ) {
336
- if ( target . is ( root . $trigger [ 0 ] ) ) {
337
- root . position . call ( root . $trigger , root , x , y ) ;
338
- return ;
350
+ if ( target . length ) {
351
+ if ( target . is ( root . $trigger [ 0 ] ) ) {
352
+ root . position . call ( root . $trigger , root , x , y ) ;
353
+ return ;
354
+ }
339
355
}
340
- }
341
- } else {
342
- offset = root . $trigger . offset ( ) ;
343
-
344
- // while this looks kinda awful, it's the best way to avoid
345
- // unnecessarily calculating any positions
346
- offset . top += $ ( window ) . scrollTop ( ) ;
347
- if ( offset . top <= e . pageY ) {
348
- offset . left += $ ( window ) . scrollLeft ( ) ;
349
- if ( offset . left <= e . pageX ) {
350
- offset . bottom = offset . top + root . $trigger . outerHeight ( ) ;
351
- if ( offset . bottom >= e . pageY ) {
352
- offset . right = offset . left + root . $trigger . outerWidth ( ) ;
353
- if ( offset . right >= e . pageX ) {
354
- // reposition
355
- root . position . call ( root . $trigger , root , x , y ) ;
356
- return ;
356
+ } else {
357
+ offset = root . $trigger . offset ( ) ;
358
+ $window = $ ( window ) ;
359
+ // while this looks kinda awful, it's the best way to avoid
360
+ // unnecessarily calculating any positions
361
+ offset . top += $window . scrollTop ( ) ;
362
+ if ( offset . top <= e . pageY ) {
363
+ offset . left += $window . scrollLeft ( ) ;
364
+ if ( offset . left <= e . pageX ) {
365
+ offset . bottom = offset . top + root . $trigger . outerHeight ( ) ;
366
+ if ( offset . bottom >= e . pageY ) {
367
+ offset . right = offset . left + root . $trigger . outerWidth ( ) ;
368
+ if ( offset . right >= e . pageX ) {
369
+ // reposition
370
+ root . position . call ( root . $trigger , root , x , y ) ;
371
+ return ;
372
+ }
357
373
}
358
374
}
359
375
}
360
376
}
361
377
}
362
- }
378
+
379
+ hideshow = function ( e ) {
380
+ if ( e ) {
381
+ e . preventDefault ( ) ;
382
+ e . stopImmediatePropagation ( ) ;
383
+ }
384
+
385
+ root . $menu . trigger ( 'contextmenu:hide' ) ;
386
+ if ( target && target . length ) {
387
+ setTimeout ( function ( ) {
388
+ target . contextMenu ( { x : x , y : y } ) ;
389
+ } , 50 ) ;
390
+ }
391
+ } ;
363
392
364
- // remove only after mouseup has completed
365
- $this . on ( 'mouseup' , function ( e ) {
366
- e . preventDefault ( ) ;
367
- e . stopImmediatePropagation ( ) ;
368
- root . $menu . trigger ( 'contextmenu:hide' ) ;
369
- if ( target && target . length ) {
370
- setTimeout ( function ( ) {
371
- target . contextMenu ( { x : x , y : y } ) ;
372
- } , 50 ) ;
393
+ if ( mouseup ) {
394
+ // mouseup has already happened
395
+ hideshow ( ) ;
396
+ } else {
397
+ // remove only after mouseup has completed
398
+ $this . on ( 'mouseup' , hideshow ) ;
373
399
}
374
- } ) ;
400
+ } , 50 ) ;
375
401
} ,
376
402
// key handled :hover
377
403
keyStop : function ( e , opt ) {
0 commit comments