I am digging messing about with Polymer.dart and Shadow DOM. That's some good clean fun.
Without much difficulty, I have used Polymer to create an
<ice-code-editor>
tag that embeds nicely into a regular web page:It seems that it was easy, in part, because I cheated. The actual code editor is not part of the shadow DOM that contains the title of the element:
In some respects, this might qualify as no-harm, no-foul. After all, it works and no harm is being caused by the ICE Code Editor being part of the main DOM tree. On the other hand, encapsulating all of a Polymer element inside the shadow DOM can keep the contents secure. More relevant to this particular case, it will prevent conflicts between elements. ICE has been developed primarily for a one-instance-per-page use case. It might work with multiple instances, but why risk conflicts if I don't have to?
Anyhow, tonight, I am going to attempt to drive the editor into the shadow DOM using tests (that's a pretty cool sentence, eh?). After last night, I already have some tests that are probing the shadow DOM:
test("can set line number", (){
expect(
query('ice-code-editor').shadowRoot.query('h1').text,
contains('(42)')
);
});
Using that test as a basis, I can describe my expectations as: test("creates an editor and preview", (){
expect(
query('ice-code-editor').shadowRoot.query('.ice-code-editor-editor'),
isNotNull
);
expect(
query('ice-code-editor').shadowRoot.query('.ice-code-editor-preview'),
isNotNull
);
});
And, just like that, I have a failing test:PASS: [polymer] can embed code PASS: [polymer] can set line number FAIL: [polymer] creates an editor and preview Expected: not null Actual: <null>A quick look at my Polymer code shows where I need to address the situation:
@CustomTag('ice-code-editor') class IceCodeEditorElement extends PolymerElement with ObservableMixin { @published String src; @published int line_number; void created() { super.created(); var container = new DivElement(); host.append(container); var editor = new ICE.Editor(container); // Other setup... } }Instead of adding the container element to the document, I need only add it to the Polymer element's shadow root:
@CustomTag('ice-code-editor') class IceCodeEditorElement extends PolymerElement with ObservableMixin { @published String src; @published int line_number; void created() { super.created(); var container = new DivElement(); shadowRoot.append(container); var editor = new ICE.Editor(container); // Other setup... } }Easy peasy. Except, of course, it does not work at all.
It turns out that the JavaScript code editor (ACE code editor) that is being used via js-interop does a lot of mucking with the DOM. The real DOM. The DOM that needs to have access to
document
and various top-level methods.So I am pretty much out of luck in trying to add the editor to the shadow DOM. At least until the underlying JavaScript code supports the shadow DOM. That said, I am not at a complete dead end. Even though the editor part of ICE cannot be added to the shadow DOM, the preview layer can be:
test("creates a shadow preview", (){
expect(
query('ice-code-editor').shadowRoot.query('.ice-code-editor-preview'),
isNotNull
);
});
I make that test pass by adding a <div>
to the shadow DOM and then passing it to the ICE Editor
constructor:@CustomTag('ice-code-editor') class IceCodeEditorElement extends PolymerElement with ObservableMixin { // ... void created() { super.created(); var container = new DivElement(); host.append(container); var preview_el = new DivElement(); shadowRoot.append(preview_el); var editor = new ICE.Editor(container, preview_el: preview_el); // Other setup... } }Now that I think about it, it will not hurt to test that the editor is added to the main DOM tree as well:
test("creates an editor", (){
expect(
query('ice-code-editor').query('.ice-code-editor-editor'),
isNotNull
);
});
With that, I have four passing tests:PASS: [polymer] can embed code PASS: [polymer] can set line number PASS: [polymer] creates a shadow preview PASS: [polymer] creates an editor All 4 tests passed.Best of all, I drove new behavior—element encapsulation—with tests. At some point I will need to verify that multiple instances of
<ice-code-editor>
on the same page will not cause trouble, but I will leave that for another day. This first pass at TDDing Polymer.dart features seems a fine stopping point for tonight.Day #892
No comments:
Post a Comment