Today, I switch back to my comic book collection app written in Dart with Hipster MVC. Currently, I have a very simple fade-in animation that displays the create comic book form:
#library('Form view to add new comic book to my sweet collection.'); #import('dart:html'); #import('https://raw.github.com/eee-c/hipster-mvc/master/HipsterView.dart'); class AddComicForm extends HipsterView { // ... render() { el.style.opacity = '0'; el.innerHTML = template(); window.setTimeout(() { el.style.transition = '1s'; el.style.opacity = '1'; }, 1); } }There is nothing fancy there—the form element is simply placed in the normal document flow. The 1 millisecond timeout seems to be necessary to give Dart a chance to render the element with the form from the
template()
function. Without it, the transition is ignored.The first step for a modal dialog is the black, semi-opaque background that covers the rest of the document, ensuring that nothing else can be clicked. For that, I create a new
<div>
tag, position it absolutely, guess at the appropriate size, make the background color black with a slight opacity, and render it above the rest of the document. All of this can be done with the style
property on Element
: render() {
// Black background
Element bg = new Element.tag('div');
document.body.nodes.add(bg);
bg.style.position = 'absolute';
bg.style.top = '0px';
bg.style.left = '0px';
bg.style.width = "1000px";
bg.style.height = "1000px";
bg.style.backgroundColor = 'black';
bg.style.opacity = '0.8';
bg.style.zIndex = '1000';
// Display the dialog
// ...
}
The problem is the guess at the dimensions. Not surprisingly they only cover a portion of the document:I could make the dimensions larger, but that will only end up adding scrollbars when they are not warranted. This means that I have to calculate dimensions. Interestingly, Dart does this inside a future (to prevent blocking during a sometimes expensive calculation). So I move the background styling into the
rect
property's future so that I can use the document's width and height for the modal dialog's background: render() {
// Black background
Element bg = new Element.tag('div');
document.body.nodes.add(bg);
window.document.rect.then((document) {
bg.style.position = 'absolute';
bg.style.top = '0px';
bg.style.left = '0px';
bg.style.width = "${document.offset.width}px";
bg.style.height = "${document.client.height}px";
bg.style.backgroundColor = 'black';
bg.style.opacity = '0.8';
bg.style.zIndex = '1000';
// Display the dialog
// ...
});
}
With that, I am ready to place my dialog: render() {
// Black background
Element bg = new Element.tag('div');
document.body.nodes.add(bg);
window.document.rect.then((document) {
// Place the background above the document
// ...
// Place the modal dialog on top of the background
el.style.opacity = '0';
el.innerHTML = template();
el.style.position = 'absolute';
el.style.top = '0px';
el.style.left = '0px';
el.style.backgroundColor = 'white';
el.style.padding = '20px';
el.style.borderRadius = '10px';
el.style.transition = 'opacity 1s ease-in-out';
el.style.opacity = '1';
el.style.zIndex = '1001';
});
}
That works, but the dialog is somewhat poorly placed:To fix that, I need another
rect
future. This time, I grab the rect
for the form dialog element so that I can use that to calculate the distance from the left side of the page: render() {
// Black background
Element bg = new Element.tag('div');
document.body.nodes.add(bg);
window.document.rect.then((document) {
// Place the background above the document
// ...
// Place the modal dialog on top of the background
// ...
el.rect.then((dialog) {
el.style.top = '10px';
int offset_left = document.offset.width/2 - dialog.offset.width/2;
el.style.left = "${offset_left}px";
});
});
}
And that seems to do the trick:I am undecided on how much I like the
rect
property. It is a little awkward, but I do appreciate the performance consideration. As for the rest, this was pretty easy to build. Best of all, I can rely on Dart to generate compatible Javascript and not have to worry (much) about IE, Mozilla, and Safari. I do think that a separate class is needed to do a modal right. Right now, I have to manually remove both the background and dialog. Something for another day.Day #328
No comments:
Post a Comment