jsdom / jsdom

A JavaScript implementation of various web standards, for use with Node.js
MIT License
20.54k stars 1.7k forks source link

Add events to el.focus() and el.blur() #533

Closed tmpvar closed 8 years ago

tmpvar commented 11 years ago

Right now we are just changing the document.activeElement, but I believe we need to emit events as well.

Also, tests.

domenic commented 11 years ago

This could help with #525's :focus failure as well.

domenic commented 11 years ago

Actually as of HTML5 all elements have focus and blur methods:

http://dev.w3.org/html5/spec/single-page.html#focus-management

This is used in the newest Sizzle tests to focus a random div, interestingly.

tmpvar commented 11 years ago

O_o .. Ok, well I guess that just makes things easier lol

On Nov 22, 2012, at 12:50 PM, Domenic Denicola notifications@github.com wrote:

Actually as of HTML5 all elements have focus and blur methods:

http://dev.w3.org/html5/spec/single-page.html#focus-management

This is used in the newest Sizzle tests to focus a random div, interestingly.

— Reply to this email directly or view it on GitHub.

dperini commented 11 years ago

Not sure this is important here for JSDOM, nor I know how much could/should be implemented.

In browsers the Activation model takes place too (DOMActivate, DOMFocusIn, DOMFocusOut).

Consider that specs says this is important only if XFORMS or Aria support is required.

Also the above events seems now deprecated, for 2 of them there are replacements: focusin, focusout.

This is a reference for event synthesis in L3:

http://www.w3.org/TR/DOM-Level-3-Events/#click-synthesis

The order in which events happen is in § 5.2.2.1

dperini commented 11 years ago

The main concern that raised in me, after suggesting that patch, is if a transition through the "body" element is always required.

For example, if a text input is currently the activeElement having the keyboard focus and a click is performed on the next text input, the activeElement should transit directly to that target element instead of going through the "body" element (caused by the "blur" event).

This probably too complex for the objective but I wanted to share the doubts :)

ashmoran commented 11 years ago

I just ran into this. I'd managed to get a jquery.validate signup form fully tested with a manually-created JSDOM document, window etc, until I added validate-on-blur. It took me quite a while to figure out it's because these events aren't firing.

After digging around, it seems Zombie.js solves this problem by monkeypatching JSDOM: https://github.com/assaf/zombie/blob/master/src/zombie/dom_focus.coffee

Sadly there doesn't seem a way to re-use this without copypasting it into my project. (I'm extremely new to JavaScript/Node though, so maybe I've missed something.) Either way, it's a shame to have to use Zombie (or dismembered code thereof) for want of focus events in JSDOM.

Update: I decided to copypaste the Zombie monkeypatch and it works fine. Maybe it'd be possible to port this to JSDOM? I don't know if it's compliant with everything @dperini mentioned above though.

domenic commented 11 years ago

Wow, it looks like Zombie has a lot of patches. I wish they would contribute them back to jsdom.

nathansobo commented 10 years ago

Just adding a :+1: as another person who could use this functionality.

nathansobo commented 10 years ago

Here's an approach I took to trigger the basic events. Would this kind of approach be accepted as a patch? If so, where would the tests belong?

  activeElement = document.body
  Object.defineProperty document, 'activeElement',
    get: -> activeElement
    set: (newActiveElement) ->
      blurEvent = document.createEvent("HTMLEvents")
      blurEvent.initEvent("blur", false, false)
      focusEvent = document.createEvent("HTMLEvents")
      focusEvent.initEvent("focus", false, false)
      oldActiveElement = activeElement
      activeElement = newActiveElement
      oldActiveElement.dispatchEvent(blurEvent)
      newActiveElement.dispatchEvent(focusEvent)
domenic commented 10 years ago

No patches written in languages other than JavaScript will be accepted.

nathansobo commented 10 years ago

I mean the general approach, not the language.

btakita commented 10 years ago

@nathansobo Nice patch! I couldn't get event bubbling to work though, even when switching the bubbles flag on the initEvent calls.

btakita commented 10 years ago

Are there any attempts to get the Zombie patch into JSDOM?

btakita commented 10 years ago

I tried to integrate the zombie.js patch, but in some case, the focus and blur events were not getting triggered. The fix was to remove:

  HTML.HTMLElement.prototype.focus = function() {
  };
  HTML.HTMLElement.prototype.blur = function() {
  };

Unfortunately, I was not able to isolate the issue nor able to create a simple reproduction of this error...

nylen commented 8 years ago

It looks like this is still an issue. I have some code that needs to read document.activeElement in a blur event handler (since nobody told IE11 about relatedTarget). In order to test this code using jsdom, we have to use an extra step:

// 1. Reset document.activeElement (pick one, these are equivalent)
myElement.blur();
document.activeElement = document.body;

// 2. Send an event to call handlers
myElement.dispatchEvent( new Event( 'blur' ) );

Context: https://github.com/Automattic/wp-calypso/pull/2054