Commit 50c2f883 authored by Adam Barth's avatar Adam Barth

Don't hardcode the list of events types in fn

This CL changes how events work in fn. Previously, event listeners were passed
in as constructor arguments. Now Nodes hold an |events| object, which contains
all the event registrations. When a Component renders, all its |events| are
copied onto the Node it produces. When an Element syncs, it walks its |events|
and adds them as event listeners on the underlying sky.Element.

The net result of this change is increased flexibility in how events are
registered. Now components don't need to enumerate all the possible events that
they support. Instead, the parent component can listen for whatever events it
likes.

Also, I've cleaned up the association between DrawerAnimation and Drawer. Now
the constructor for Drawer accepts an |animation| object and wires up its
internal event handlers itself instead of requiring the constructor to do all
the wiring.

R=rafaelw@chromium.org

Review URL: https://codereview.chromium.org/975863003
parent 3f347184
......@@ -103,6 +103,8 @@ abstract class Component extends Node {
_currentlyRendering = null;
_currentOrder = lastOrder;
_rendered.events.addAll(events);
_dirty = false;
// TODO(rafaelw): This prevents components from returning different node
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of fn;
class EventHandler {
final String type;
final sky.EventListener listener;
EventHandler(this.type, this.listener);
}
class EventMap {
final List<EventHandler> _handlers = new List<EventHandler>();
void listen(String type, sky.EventListener listener) {
assert(listener != null);
_handlers.add(new EventHandler(type, listener));
}
void addAll(EventMap events) {
_handlers.addAll(events._handlers);
}
}
......@@ -10,6 +10,7 @@ import 'dart:sky' as sky;
import 'reflect.dart' as reflect;
part 'component.dart';
part 'event.dart';
part 'node.dart';
part 'style.dart';
......
......@@ -18,6 +18,10 @@ abstract class Node {
String _key = null;
sky.Node _root = null;
// TODO(abarth): Both Elements and Components have |events| but |Text|
// doesn't. Should we add a common base class to contain |events|?
final EventMap events = new EventMap();
Node({ Object key }) {
_key = key == null ? "$runtimeType" : "$runtimeType-$key";
}
......@@ -65,19 +69,6 @@ abstract class Element extends Node {
String inlineStyle;
sky.EventListener onClick;
sky.EventListener onFlingCancel;
sky.EventListener onFlingStart;
sky.EventListener onGestureTap;
sky.EventListener onPointerCancel;
sky.EventListener onPointerDown;
sky.EventListener onPointerMove;
sky.EventListener onPointerUp;
sky.EventListener onScrollEnd;
sky.EventListener onScrollStart;
sky.EventListener onScrollUpdate;
sky.EventListener onWheel;
List<Node> _children = null;
String _className = '';
......@@ -86,21 +77,7 @@ abstract class Element extends Node {
List<Node> children,
Style style,
this.inlineStyle,
// Events
this.onClick,
this.onFlingCancel,
this.onFlingStart,
this.onGestureTap,
this.onPointerCancel,
this.onPointerDown,
this.onPointerMove,
this.onPointerUp,
this.onScrollEnd,
this.onScrollStart,
this.onScrollUpdate,
this.onWheel
this.inlineStyle
}) : super(key:key) {
_className = style == null ? '': style._className;
......@@ -135,34 +112,48 @@ abstract class Element extends Node {
}
}
void _syncEvent(String eventName, sky.EventListener listener,
sky.EventListener oldListener) {
sky.Element root = _root as sky.Element;
if (listener == oldListener)
return;
void _syncEvents([Element old]) {
List<EventHandler> newHandlers = events._handlers;
int newStartIndex = 0;
int newEndIndex = newHandlers.length;
List<EventHandler> oldHandlers = old.events._handlers;
int oldStartIndex = 0;
int oldEndIndex = oldHandlers.length;
// Skip over leading handlers that match.
while (newStartIndex < newEndIndex && oldStartIndex < oldEndIndex) {
EventHandler newHander = newHandlers[newStartIndex];
EventHandler oldHandler = oldHandlers[oldStartIndex];
if (newHander.type != oldHandler.type
|| newHander.listener != oldHandler.listener)
break;
++newStartIndex;
++oldStartIndex;
}
if (oldListener != null) {
root.removeEventListener(eventName, oldListener);
// Skip over trailing handlers that match.
while (newStartIndex < newEndIndex && oldStartIndex < oldEndIndex) {
EventHandler newHander = newHandlers[newEndIndex - 1];
EventHandler oldHandler = oldHandlers[oldEndIndex - 1];
if (newHander.type != oldHandler.type
|| newHander.listener != oldHandler.listener)
break;
--newEndIndex;
--oldEndIndex;
}
if (listener != null) {
root.addEventListener(eventName, listener);
sky.Element root = _root as sky.Element;
for (int i = oldStartIndex; i < oldEndIndex; ++i) {
EventHandler oldHandler = oldHandlers[i];
root.removeEventListener(oldHandler.type, oldHandler.listener);
}
}
void _syncEvents([Element old]) {
_syncEvent('click', onClick, old.onClick);
_syncEvent('gestureflingcancel', onFlingCancel, old.onFlingCancel);
_syncEvent('gestureflingstart', onFlingStart, old.onFlingStart);
_syncEvent('gesturescrollend', onScrollEnd, old.onScrollEnd);
_syncEvent('gesturescrollstart', onScrollStart, old.onScrollStart);
_syncEvent('gesturescrollupdate', onScrollUpdate, old.onScrollUpdate);
_syncEvent('gesturetap', onGestureTap, old.onGestureTap);
_syncEvent('pointercancel', onPointerCancel, old.onPointerCancel);
_syncEvent('pointerdown', onPointerDown, old.onPointerDown);
_syncEvent('pointermove', onPointerMove, old.onPointerMove);
_syncEvent('pointerup', onPointerUp, old.onPointerUp);
_syncEvent('wheel', onWheel, old.onWheel);
for (int i = newStartIndex; i < newEndIndex; ++i) {
EventHandler newHander = newHandlers[i];
root.addEventListener(newHander.type, newHander.listener);
}
}
void _syncNode([Element old]) {
......@@ -356,36 +347,12 @@ class Container extends Element {
Object key,
List<Node> children,
Style style,
String inlineStyle,
sky.EventListener onClick,
sky.EventListener onFlingCancel,
sky.EventListener onFlingStart,
sky.EventListener onGestureTap,
sky.EventListener onPointerCancel,
sky.EventListener onPointerDown,
sky.EventListener onPointerMove,
sky.EventListener onPointerUp,
sky.EventListener onScrollEnd,
sky.EventListener onScrollStart,
sky.EventListener onScrollUpdate,
sky.EventListener onWheel
String inlineStyle
}) : super(
key: key,
children: children,
style: style,
inlineStyle: inlineStyle,
onClick: onClick,
onFlingCancel: onFlingCancel,
onFlingStart: onFlingStart,
onGestureTap: onGestureTap,
onPointerCancel: onPointerCancel,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onScrollEnd: onScrollEnd,
onScrollStart: onScrollStart,
onScrollUpdate: onScrollUpdate,
onWheel: onWheel
inlineStyle: inlineStyle
);
}
......@@ -405,18 +372,6 @@ class Image extends Element {
List<Node> children,
Style style,
String inlineStyle,
sky.EventListener onClick,
sky.EventListener onFlingCancel,
sky.EventListener onFlingStart,
sky.EventListener onGestureTap,
sky.EventListener onPointerCancel,
sky.EventListener onPointerDown,
sky.EventListener onPointerMove,
sky.EventListener onPointerUp,
sky.EventListener onScrollEnd,
sky.EventListener onScrollStart,
sky.EventListener onScrollUpdate,
sky.EventListener onWheel,
this.width,
this.height,
this.src
......@@ -424,19 +379,7 @@ class Image extends Element {
key: key,
children: children,
style: style,
inlineStyle: inlineStyle,
onClick: onClick,
onFlingCancel: onFlingCancel,
onFlingStart: onFlingStart,
onGestureTap: onGestureTap,
onPointerCancel: onPointerCancel,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onScrollEnd: onScrollEnd,
onScrollStart: onScrollStart,
onScrollUpdate: onScrollUpdate,
onWheel: onWheel
inlineStyle: inlineStyle
);
void _syncNode([Element old]) {
......@@ -470,18 +413,6 @@ class Anchor extends Element {
List<Node> children,
Style style,
String inlineStyle,
sky.EventListener onClick,
sky.EventListener onFlingCancel,
sky.EventListener onFlingStart,
sky.EventListener onGestureTap,
sky.EventListener onPointerCancel,
sky.EventListener onPointerDown,
sky.EventListener onPointerMove,
sky.EventListener onPointerUp,
sky.EventListener onScrollEnd,
sky.EventListener onScrollStart,
sky.EventListener onScrollUpdate,
sky.EventListener onWheel,
this.width,
this.height,
this.href
......@@ -489,19 +420,7 @@ class Anchor extends Element {
key: key,
children: children,
style: style,
inlineStyle: inlineStyle,
onClick: onClick,
onFlingCancel: onFlingCancel,
onFlingStart: onFlingStart,
onGestureTap: onGestureTap,
onPointerCancel: onPointerCancel,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onScrollEnd: onScrollEnd,
onScrollStart: onScrollStart,
onScrollUpdate: onScrollUpdate,
onWheel: onWheel
inlineStyle: inlineStyle
);
void _syncNode([Element old]) {
......
......@@ -26,18 +26,13 @@ class Button extends ButtonBase {
);
Node content;
sky.EventListener onClick;
Button({ Object key, this.content, this.onClick }) : super(key: key);
Button({ Object key, this.content }) : super(key: key);
Node render() {
return new Container(
key: 'Button',
style: _highlight ? _highlightStyle : _style,
onClick: onClick,
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp,
onPointerCancel: _handlePointerCancel,
children: [super.render(), content]
);
}
......
......@@ -4,7 +4,11 @@ abstract class ButtonBase extends MaterialComponent {
bool _highlight = false;
ButtonBase({ Object key }) : super(key: key);
ButtonBase({ Object key }) : super(key: key) {
events.listen('pointerdown', _handlePointerDown);
events.listen('pointerup', _handlePointerUp);
events.listen('pointercancel', _handlePointerCancel);
}
void _handlePointerDown(_) {
setState(() {
......
......@@ -57,10 +57,6 @@ class Checkbox extends ButtonBase {
Node render() {
return new Container(
style: _style,
onClick: _handleClick,
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp,
onPointerCancel: _handlePointerCancel,
children: [
super.render(),
new Container(
......@@ -72,7 +68,7 @@ class Checkbox extends ButtonBase {
]
)
]
);
)..events.listen('click', _handleClick);
}
void _handleClick(sky.Event e) {
......
......@@ -127,24 +127,12 @@ class Drawer extends Component {
bottom: 0;'''
);
Stream<double> onPositionChanged;
sky.EventListener handleMaskFling;
sky.EventListener handleMaskTap;
sky.EventListener handlePointerCancel;
sky.EventListener handlePointerDown;
sky.EventListener handlePointerMove;
sky.EventListener handlePointerUp;
DrawerAnimation animation;
List<Node> children;
Drawer({
Object key,
this.onPositionChanged,
this.handleMaskFling,
this.handleMaskTap,
this.handlePointerCancel,
this.handlePointerDown,
this.handlePointerMove,
this.handlePointerUp,
this.animation,
this.children
}) : super(key: key);
......@@ -157,7 +145,7 @@ class Drawer extends Component {
return;
_listening = true;
onPositionChanged.listen((position) {
animation.onPositionChanged.listen((position) {
setState(() {
_position = position;
});
......@@ -172,29 +160,28 @@ class Drawer extends Component {
String maskInlineStyle = 'opacity: ${(_position / _kWidth + 1) * 0.25}';
String contentInlineStyle = 'transform: translateX(${_position}px)';
Container mask = new Container(
key: 'Mask',
style: _maskStyle,
inlineStyle: maskInlineStyle
)..events.listen('gesturetap', animation.handleMaskTap)
..events.listen('gestureflingstart', animation.handleFlingStart);
Container content = new Container(
key: 'Content',
style: _contentStyle,
inlineStyle: contentInlineStyle,
children: children
);
return new Container(
style: _style,
inlineStyle: inlineStyle,
onPointerDown: handlePointerDown,
onPointerMove: handlePointerMove,
onPointerUp: handlePointerUp,
onPointerCancel: handlePointerCancel,
children: [
new Container(
key: 'Mask',
style: _maskStyle,
inlineStyle: maskInlineStyle,
onGestureTap: handleMaskTap,
onFlingStart: handleMaskFling
),
new Container(
key: 'Content',
style: _contentStyle,
inlineStyle: contentInlineStyle,
children: children
)
]
);
children: [ mask, content ]
)..events.listen('pointerdown', animation.handlePointerDown)
..events.listen('pointermove', animation.handlePointerMove)
..events.listen('pointerup', animation.handlePointerUp)
..events.listen('pointercancel', animation.handlePointerCancel);
}
}
......@@ -50,10 +50,6 @@ abstract class FixedHeightScrollable extends Component {
return new Container(
style: _style,
onFlingStart: _handleFlingStart,
onFlingCancel: _handleFlingCancel,
onScrollUpdate: _handleScrollUpdate,
onWheel: _handleWheel,
children: [
new Container(
style: _scrollAreaStyle,
......@@ -61,7 +57,11 @@ abstract class FixedHeightScrollable extends Component {
children: items
)
]
);
)
..events.listen('gestureflingstart', _handleFlingStart)
..events.listen('gestureflingcancel', _handleFlingCancel)
..events.listen('gesturescrollupdate', _handleScrollUpdate)
..events.listen('wheel', _handleWheel);
}
void willUnmount() {
......
......@@ -7,14 +7,12 @@ class Icon extends Component {
Style style;
int size;
String type;
sky.EventListener onClick;
Icon({
String key,
this.style,
this.size,
this.type: '',
this.onClick
this.type: ''
}) : super(key: key);
Node render() {
......@@ -28,7 +26,6 @@ class Icon extends Component {
return new Image(
style: style,
onClick: onClick,
width: size,
height: size,
src: '${kAssetBase}/${category}/2x_web/ic_${subtype}_${size}dp.png'
......
......@@ -26,12 +26,11 @@ abstract class MaterialComponent extends Component {
return new Container(
style: _style,
onScrollStart: _cancelSplashes,
onWheel: _cancelSplashes,
onPointerDown: _startSplash,
children: children,
key: _splashesKey
);
)..events.listen('gesturescrollstart', _cancelSplashes)
..events.listen('wheel', _cancelSplashes)
..events.listen('pointerdown', _startSplash);
}
sky.ClientRect _getBoundingRect() => getRoot().getBoundingClientRect();
......
......@@ -33,18 +33,11 @@ class MenuItem extends ButtonBase {
List<Node> children;
String icon;
sky.EventListener onClick;
MenuItem({ Object key, this.icon, this.children, this.onClick }) : super(key: key) {
}
MenuItem({ Object key, this.icon, this.children }) : super(key: key);
Node render() {
return new Container(
style: _highlight ? _highlightStyle : _style,
onClick: onClick,
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp,
onPointerCancel: _handlePointerCancel,
children: [
super.render(),
new Icon(
......
......@@ -48,16 +48,12 @@ class Radio extends ButtonBase {
Node render() {
return new Container(
style: _highlight ? _highlightStyle : _style,
onClick: _handleClick,
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp,
onPointerCancel: _handlePointerCancel,
children: value == groupValue ?
[super.render(), new Container( style : _dotStyle )] : [super.render()]
);
)..events.listen('click', _handleClick);
}
void _handleClick(sky.Event e) {
void _handleClick(_) {
onChanged(value);
}
}
......@@ -37,13 +37,7 @@ class StocksApp extends App {
Node render() {
var drawer = new Drawer(
onPositionChanged: _drawerAnimation.onPositionChanged,
handleMaskFling: _drawerAnimation.handleFlingStart,
handleMaskTap: _drawerAnimation.handleMaskTap,
handlePointerCancel: _drawerAnimation.handlePointerCancel,
handlePointerDown: _drawerAnimation.handlePointerDown,
handlePointerMove: _drawerAnimation.handlePointerMove,
handlePointerUp: _drawerAnimation.handlePointerUp,
animation: _drawerAnimation,
children: [
new DrawerHeader(
children: [new Text('Stocks')]
......@@ -76,9 +70,9 @@ class StocksApp extends App {
var toolbar = new Toolbar(
children: [
new Icon(key: 'menu', style: _iconStyle,
onClick: _drawerAnimation.toggle,
size: 24,
type: 'navigation/menu_white'),
type: 'navigation/menu_white')
..events.listen('click', _drawerAnimation.toggle),
new Container(
style: _titleStyle,
children: [new Text('I am a stocks app')]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment