How do I use document.activeElement with the ShadowDOM polyfill?

421 views
Skip to first unread message

Nik Graf

unread,
Jul 24, 2014, 11:20:31 AM7/24/14
to polym...@googlegroups.com
I would like to identify if my component is still the active element after a blur event.

Here example code & a use-case to provide more Context:

<polymer-element name="b-secret">
 
<template>
   
<div>Other things here</div>
   
<input id="password-field" type="password" value="{{value}}">
 
</template>
 
<script type="application/dart" src="secret.dart"></script>
</polymer-element>

A user clicks on a custom input element (b-secret). If you call document.activeElement you will get the custom element (b-secret) for Browsers supporting ShadowDOM. In Firefox (no ShadowDOM support) for example you will get the actual input element (#password-field) inside your component.

While I guess fixing document.activeElement is not really possible I would expected shadowRoot.querySelector('#password-field').hashCode to be the same as document.activeElement.hashCode.

I investigate a bit and recognized that the ShadowDOM shim creates a wrapper object for the queried input field when compiled to JavaScript. The wrapper object is aware of the field's hashCode I'm looking for, but I can't access it through Dart. See the annotated Screenshot: http://cl.ly/image/3F2b1l343O43

Justin Fagnani

unread,
Jul 24, 2014, 11:39:45 AM7/24/14
to Nik Graf, polymer-dev, w...@dartlang.org, John Messerly

+w...@dartlang.org, John

Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/polymer-dev/d7a1192a-4520-4b0d-869f-88c8f524e841%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

John Messerly

unread,
Jul 24, 2014, 3:13:26 PM7/24/14
to Justin Fagnani, Nik Graf, polymer-dev, w...@dartlang.org
Shadow DOM polyfill can't wrap accessors directly on document, so that's why `document.activeElement` doesn't work. Things like `document.head` have the same problem, see [1]. The usual answer is to introduce a querySelector or some other method call, which kicks in the polyfill. Or you can call: 

ShadowDOMPolyfill.wrap(document.activeElement)

Calling that method from Dart would involve JS interop. I'm not an expert there, but maybe something like: 

// might need a `new JsObject.fromBrowserObject()` around the method arg, not sure
context['ShadowDOMPolyfill'].callMethod('wrap', [document.activeElement]);



Rob Dodson

unread,
Jul 24, 2014, 3:36:44 PM7/24/14
to John Messerly, Justin Fagnani, Nik Graf, polymer-dev, w...@dartlang.org
I think on the PolymerJS side you don't need to include ShadowDOMPolyfill in the call. You should be able to just call wrap(document.activeElement)


Erik Arvidsson

unread,
Jul 24, 2014, 4:08:50 PM7/24/14
to Rob Dodson, John Messerly, Justin Fagnani, Nik Graf, polymer-dev, w...@dartlang.org
Rob is right. platform.js adds global wrap and unwrap functions that are noops if the browser supports native shadow dom.



For more options, visit https://groups.google.com/d/optout.



--
erik


Nik Graf

unread,
Jul 31, 2014, 6:42:06 AM7/31/14
to polym...@googlegroups.com, robd...@google.com, jmes...@google.com, justin...@google.com, n...@blossom.io, w...@dartlang.org
Works like a charm. Thanks for the help @ Justin, John, Rob & Erik - much appreciated.

This is the final version that worked for me (for the full example see the StackOverflow answer):

bool isActive() {
 
var passwordField = $['password-field'];
 
var activeElement = js.context.callMethod('wrap', [document.activeElement]);


 
// For Browsers with shadow DOM support the shadowRoot.host matches while
 
// for Browsers without shadow DOM support the password field match.
 
if (activeElement.hashCode != hashCode &&
      activeElement
.hashCode != passwordField.hashCode) {
   
return false;
 
} else {
   
return true;
 
}
}

Reply all
Reply to author
Forward
0 new messages