diff --git a/examples/fn/lib/component.dart b/examples/fn/lib/component.dart index 1503e6348cf5d16475da53b0949efccfb8117981..93900235baf743fac42d7e14a7a32dc388a11d52 100644 --- a/examples/fn/lib/component.dart +++ b/examples/fn/lib/component.dart @@ -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 diff --git a/examples/fn/lib/event.dart b/examples/fn/lib/event.dart new file mode 100644 index 0000000000000000000000000000000000000000..5b96d739d458207a586f7fe694d672e6d066c673 --- /dev/null +++ b/examples/fn/lib/event.dart @@ -0,0 +1,25 @@ +// 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 _handlers = new List(); + + void listen(String type, sky.EventListener listener) { + assert(listener != null); + _handlers.add(new EventHandler(type, listener)); + } + + void addAll(EventMap events) { + _handlers.addAll(events._handlers); + } +} diff --git a/examples/fn/lib/fn.dart b/examples/fn/lib/fn.dart index ab67c50bd603100390886d90813cdf4a45a07916..a1d6e2ba471eeba21a286b555a243969f0d76b81 100644 --- a/examples/fn/lib/fn.dart +++ b/examples/fn/lib/fn.dart @@ -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'; diff --git a/examples/fn/lib/node.dart b/examples/fn/lib/node.dart index 1339e204eacadb4b1d8cce2c1d42bbd7778e2616..54853b3e83278efc6a1a4aac8e60968ba2ce74e9 100644 --- a/examples/fn/lib/node.dart +++ b/examples/fn/lib/node.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 _children = null; String _className = ''; @@ -86,21 +77,7 @@ abstract class Element extends Node { List 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 newHandlers = events._handlers; + int newStartIndex = 0; + int newEndIndex = newHandlers.length; + + List 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 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 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 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]) { diff --git a/examples/fn/widgets/button.dart b/examples/fn/widgets/button.dart index ac7f62d62067af015d356c474139abe36d274e07..c7f53cac5baad6d88e0d631d57b205d8c2894fff 100644 --- a/examples/fn/widgets/button.dart +++ b/examples/fn/widgets/button.dart @@ -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] ); } diff --git a/examples/fn/widgets/buttonbase.dart b/examples/fn/widgets/buttonbase.dart index 461b44d49ab95c7c44e16de1e133f5df246ff16d..a69202280188acaf268d3e7b3b446d76bc401dbd 100644 --- a/examples/fn/widgets/buttonbase.dart +++ b/examples/fn/widgets/buttonbase.dart @@ -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(() { diff --git a/examples/fn/widgets/checkbox.dart b/examples/fn/widgets/checkbox.dart index 48026475601c654b6688a106f5395a4792627477..2825498d61a63aba9d47198e8d6f9483e3537446 100644 --- a/examples/fn/widgets/checkbox.dart +++ b/examples/fn/widgets/checkbox.dart @@ -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) { diff --git a/examples/fn/widgets/drawer.dart b/examples/fn/widgets/drawer.dart index 229022011e18d2b967dbd16601853739d51380b6..26edbb2f07d6b6ade11d5f86552f51ab5d3f07f2 100644 --- a/examples/fn/widgets/drawer.dart +++ b/examples/fn/widgets/drawer.dart @@ -127,24 +127,12 @@ class Drawer extends Component { bottom: 0;''' ); - Stream onPositionChanged; - sky.EventListener handleMaskFling; - sky.EventListener handleMaskTap; - sky.EventListener handlePointerCancel; - sky.EventListener handlePointerDown; - sky.EventListener handlePointerMove; - sky.EventListener handlePointerUp; + DrawerAnimation animation; List 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); + } } diff --git a/examples/fn/widgets/fixedheightscrollable.dart b/examples/fn/widgets/fixedheightscrollable.dart index ef343e26768f611990c85003263c59732bb5f6f6..3c134aa924d260aa2679e9cf0455938935845777 100644 --- a/examples/fn/widgets/fixedheightscrollable.dart +++ b/examples/fn/widgets/fixedheightscrollable.dart @@ -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() { diff --git a/examples/fn/widgets/icon.dart b/examples/fn/widgets/icon.dart index dded9217d4160f78b943e29ffb795b23947a5842..8f76d8f41044489d9e4d9bf11ffe74caec104939 100644 --- a/examples/fn/widgets/icon.dart +++ b/examples/fn/widgets/icon.dart @@ -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' diff --git a/examples/fn/widgets/material.dart b/examples/fn/widgets/material.dart index 0260705a0bdffc10b1b1642801a82ed784bfef18..2d38a511dc70db0d9d056f8c93bb6e9f34db5398 100644 --- a/examples/fn/widgets/material.dart +++ b/examples/fn/widgets/material.dart @@ -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(); diff --git a/examples/fn/widgets/menuitem.dart b/examples/fn/widgets/menuitem.dart index 22cd8f75aa060f396d5debd1fd602fa515958902..6a7407b1d5d7575d29b0aca1930fb6734cc1cc3b 100644 --- a/examples/fn/widgets/menuitem.dart +++ b/examples/fn/widgets/menuitem.dart @@ -33,18 +33,11 @@ class MenuItem extends ButtonBase { List 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( diff --git a/examples/fn/widgets/radio.dart b/examples/fn/widgets/radio.dart index fe907929e0b544d07c64029f2b9c3f4576e03f6b..c5c1b41f806e3c14ad76660099af10a97fccef81 100644 --- a/examples/fn/widgets/radio.dart +++ b/examples/fn/widgets/radio.dart @@ -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); } } diff --git a/examples/stocks-fn/stocksapp.dart b/examples/stocks-fn/stocksapp.dart index 501383c5de637f8851a0f2d942e12a644be4563f..562e615d1435503a8f72724a3ca9ee0295c4eb2b 100644 --- a/examples/stocks-fn/stocksapp.dart +++ b/examples/stocks-fn/stocksapp.dart @@ -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')]