Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/python | |
| 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 3 # for details. All rights reserved. Use of this source code is governed by a | |
| 4 # BSD-style license that can be found in the LICENSE file. | |
| 5 | |
| 6 """This module provides functionality to generate dart:html event classes.""" | |
| 7 | |
| 8 # Events without onEventName attributes in the IDL we want to support. | |
| 9 # We can automatically extract most event event names by checking for | |
|
Anton Muhin
2012/10/01 14:38:38
nit: duplicate 'event event'
podivilov1
2012/10/02 12:09:15
Done.
| |
| 10 # onEventName methods in the IDL but some events aren't listed so we need | |
| 11 # to manually add them here so that they are easy for users to find. | |
| 12 _html_manual_events = { | |
| 13 'Element': ['touchleave', 'touchenter', 'webkitTransitionEnd'], | |
| 14 'Window': ['DOMContentLoaded'] | |
| 15 } | |
| 16 | |
| 17 # These event names must be camel case when attaching event listeners | |
| 18 # using addEventListener even though the onEventName properties in the DOM for | |
| 19 # them are not camel case. | |
| 20 _on_attribute_to_event_name_mapping = { | |
| 21 'webkitanimationend': 'webkitAnimationEnd', | |
| 22 'webkitanimationiteration': 'webkitAnimationIteration', | |
| 23 'webkitanimationstart': 'webkitAnimationStart', | |
| 24 'webkitspeechchange': 'webkitSpeechChange', | |
| 25 'webkittransitionend': 'webkitTransitionEnd', | |
| 26 } | |
| 27 | |
| 28 # Mapping from raw event names to the pretty camelCase event names exposed as | |
| 29 # properties in dart:html. If the DOM exposes a new event name, you will need | |
| 30 # to add the lower case to camel case conversion for that event name here. | |
| 31 _html_event_names = { | |
| 32 'DOMContentLoaded': 'contentLoaded', | |
| 33 'abort': 'abort', | |
| 34 'addstream': 'addStream', | |
| 35 'addtrack': 'addTrack', | |
| 36 'audioend': 'audioEnd', | |
| 37 'audioprocess': 'audioProcess', | |
| 38 'audiostart': 'audioStart', | |
| 39 'beforecopy': 'beforeCopy', | |
| 40 'beforecut': 'beforeCut', | |
| 41 'beforepaste': 'beforePaste', | |
| 42 'beforeunload': 'beforeUnload', | |
| 43 'blocked': 'blocked', | |
| 44 'blur': 'blur', | |
| 45 'cached': 'cached', | |
| 46 'canplay': 'canPlay', | |
| 47 'canplaythrough': 'canPlayThrough', | |
| 48 'change': 'change', | |
| 49 'chargingchange': 'chargingChange', | |
| 50 'chargingtimechange': 'chargingTimeChange', | |
| 51 'checking': 'checking', | |
| 52 'click': 'click', | |
| 53 'close': 'close', | |
| 54 'complete': 'complete', | |
| 55 'connect': 'connect', | |
| 56 'connecting': 'connecting', | |
| 57 'contextmenu': 'contextMenu', | |
| 58 'copy': 'copy', | |
| 59 'cuechange': 'cueChange', | |
| 60 'cut': 'cut', | |
| 61 'dblclick': 'doubleClick', | |
| 62 'devicemotion': 'deviceMotion', | |
| 63 'deviceorientation': 'deviceOrientation', | |
| 64 'dischargingtimechange': 'dischargingTimeChange', | |
| 65 'display': 'display', | |
| 66 'downloading': 'downloading', | |
| 67 'drag': 'drag', | |
| 68 'dragend': 'dragEnd', | |
| 69 'dragenter': 'dragEnter', | |
| 70 'dragleave': 'dragLeave', | |
| 71 'dragover': 'dragOver', | |
| 72 'dragstart': 'dragStart', | |
| 73 'drop': 'drop', | |
| 74 'durationchange': 'durationChange', | |
| 75 'emptied': 'emptied', | |
| 76 'end': 'end', | |
| 77 'ended': 'ended', | |
| 78 'enter': 'enter', | |
| 79 'error': 'error', | |
| 80 'exit': 'exit', | |
| 81 'focus': 'focus', | |
| 82 'hashchange': 'hashChange', | |
| 83 'icecandidate': 'iceCandidate', | |
| 84 'icechange': 'iceChange', | |
| 85 'input': 'input', | |
| 86 'invalid': 'invalid', | |
| 87 'keydown': 'keyDown', | |
| 88 'keypress': 'keyPress', | |
| 89 'keyup': 'keyUp', | |
| 90 'levelchange': 'levelChange', | |
| 91 'load': 'load', | |
| 92 'loadeddata': 'loadedData', | |
| 93 'loadedmetadata': 'loadedMetadata', | |
| 94 'loadend': 'loadEnd', | |
| 95 'loadstart': 'loadStart', | |
| 96 'message': 'message', | |
| 97 'mousedown': 'mouseDown', | |
| 98 'mousemove': 'mouseMove', | |
| 99 'mouseout': 'mouseOut', | |
| 100 'mouseover': 'mouseOver', | |
| 101 'mouseup': 'mouseUp', | |
| 102 'mousewheel': 'mouseWheel', | |
| 103 'mute': 'mute', | |
| 104 'negotiationneeded': 'negotiationNeeded', | |
| 105 'nomatch': 'noMatch', | |
| 106 'noupdate': 'noUpdate', | |
| 107 'obsolete': 'obsolete', | |
| 108 'offline': 'offline', | |
| 109 'online': 'online', | |
| 110 'open': 'open', | |
| 111 'pagehide': 'pageHide', | |
| 112 'pageshow': 'pageShow', | |
| 113 'paste': 'paste', | |
| 114 'pause': 'pause', | |
| 115 'play': 'play', | |
| 116 'playing': 'playing', | |
| 117 'popstate': 'popState', | |
| 118 'progress': 'progress', | |
| 119 'ratechange': 'rateChange', | |
| 120 'readystatechange': 'readyStateChange', | |
| 121 'removestream': 'removeStream', | |
| 122 'removetrack': 'removeTrack', | |
| 123 'reset': 'reset', | |
| 124 'resize': 'resize', | |
| 125 'result': 'result', | |
| 126 'resultdeleted': 'resultDeleted', | |
| 127 'scroll': 'scroll', | |
| 128 'search': 'search', | |
| 129 'seeked': 'seeked', | |
| 130 'seeking': 'seeking', | |
| 131 'select': 'select', | |
| 132 'selectionchange': 'selectionChange', | |
| 133 'selectstart': 'selectStart', | |
| 134 'show': 'show', | |
| 135 'soundend': 'soundEnd', | |
| 136 'soundstart': 'soundStart', | |
| 137 'speechend': 'speechEnd', | |
| 138 'speechstart': 'speechStart', | |
| 139 'stalled': 'stalled', | |
| 140 'start': 'start', | |
| 141 'statechange': 'stateChange', | |
| 142 'storage': 'storage', | |
| 143 'submit': 'submit', | |
| 144 'success': 'success', | |
| 145 'suspend': 'suspend', | |
| 146 'timeupdate': 'timeUpdate', | |
| 147 'touchcancel': 'touchCancel', | |
| 148 'touchend': 'touchEnd', | |
| 149 'touchenter': 'touchEnter', | |
| 150 'touchleave': 'touchLeave', | |
| 151 'touchmove': 'touchMove', | |
| 152 'touchstart': 'touchStart', | |
| 153 'unload': 'unload', | |
| 154 'upgradeneeded': 'upgradeNeeded', | |
| 155 'unmute': 'unmute', | |
| 156 'updateready': 'updateReady', | |
| 157 'versionchange': 'versionChange', | |
| 158 'volumechange': 'volumeChange', | |
| 159 'waiting': 'waiting', | |
| 160 'webkitAnimationEnd': 'animationEnd', | |
| 161 'webkitAnimationIteration': 'animationIteration', | |
| 162 'webkitAnimationStart': 'animationStart', | |
| 163 'webkitfullscreenchange': 'fullscreenChange', | |
| 164 'webkitfullscreenerror': 'fullscreenError', | |
| 165 'webkitkeyadded': 'keyAdded', | |
| 166 'webkitkeyerror': 'keyError', | |
| 167 'webkitkeymessage': 'keyMessage', | |
| 168 'webkitneedkey': 'needKey', | |
| 169 'webkitpointerlockchange': 'pointerLockChange', | |
| 170 'webkitpointerlockerror': 'pointerLockError', | |
| 171 'webkitSpeechChange': 'speechChange', | |
| 172 'webkitsourceclose': 'sourceClose', | |
| 173 'webkitsourceended': 'sourceEnded', | |
| 174 'webkitsourceopen': 'sourceOpen', | |
| 175 'webkitTransitionEnd': 'transitionEnd', | |
| 176 'write': 'write', | |
| 177 'writeend': 'writeEnd', | |
| 178 'writestart': 'writeStart' | |
| 179 } | |
| 180 | |
| 181 # These classes require an explicit declaration for the "on" method even though | |
| 182 # they don't declare any unique events, because the concrete class hierarchy | |
| 183 # doesn't match the interface hierarchy. | |
| 184 _html_explicit_event_classes = set(['DocumentFragment']) | |
| 185 | |
| 186 class HtmlEventGenerator(object): | |
| 187 | |
| 188 def __init__(self, database, template_loader): | |
| 189 self._event_classes = set() | |
| 190 self._database = database | |
| 191 self._template_loader = template_loader | |
| 192 | |
| 193 def ProcessInterface(self, interface, html_interface_name, custom_events, | |
| 194 events_interface_emitter, events_implementation_emitter): | |
| 195 events = set([attr for attr in interface.attributes | |
| 196 if attr.type.id == 'EventListener']) | |
| 197 if not events and interface.id not in _html_explicit_event_classes: | |
| 198 return None | |
| 199 | |
| 200 self._event_classes.add(interface.id) | |
| 201 events_interface = html_interface_name + 'Events' | |
| 202 parent_events_interface = self._GetParentEventsInterface(interface) | |
| 203 | |
| 204 if not events: | |
| 205 return parent_events_interface | |
| 206 | |
| 207 interface_events_members = events_interface_emitter.Emit( | |
| 208 '\nabstract class $INTERFACE implements $PARENT {\n$!MEMBERS}\n', | |
| 209 INTERFACE=events_interface, | |
| 210 PARENT=parent_events_interface) | |
| 211 | |
| 212 template_file = 'impl_%s.darttemplate' % events_interface | |
| 213 template = (self._template_loader.TryLoad(template_file) or | |
| 214 '\n' | |
| 215 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n' | |
| 216 ' $CLASSNAME(_ptr) : super(_ptr);\n' | |
| 217 '$!MEMBERS}\n') | |
| 218 | |
| 219 # TODO(jacobr): specify the type of _ptr as EventTarget | |
| 220 implementation_events_members = events_implementation_emitter.Emit( | |
| 221 template, | |
| 222 CLASSNAME='_%sImpl' % events_interface, | |
| 223 INTERFACE=events_interface, | |
| 224 SUPER='_%sImpl' % parent_events_interface) | |
| 225 | |
| 226 dom_event_names = set() | |
| 227 for event in events: | |
| 228 dom_name = event.id[2:] | |
| 229 dom_name = _on_attribute_to_event_name_mapping.get(dom_name, dom_name) | |
| 230 dom_event_names.add(dom_name) | |
| 231 if html_interface_name in _html_manual_events: | |
| 232 dom_event_names.update(_html_manual_events[html_interface_name]) | |
| 233 dom_event_names = sorted(dom_event_names, | |
| 234 key=lambda name: _html_event_names[name]) | |
| 235 for dom_name in dom_event_names: | |
| 236 if dom_name not in _html_event_names: | |
| 237 raise Exception('No known html even name for event: ' + dom_name) | |
| 238 html_name = _html_event_names[dom_name] | |
| 239 interface_events_members.Emit('\n EventListenerList get $NAME;\n', | |
| 240 NAME=html_name) | |
| 241 full_event_name = '%sEvents.%s' % (html_interface_name, html_name) | |
| 242 if not full_event_name in custom_events: | |
| 243 implementation_events_members.Emit( | |
| 244 "\n" | |
| 245 " EventListenerList get $NAME => this['$DOM_NAME'];\n", | |
| 246 NAME=html_name, | |
| 247 DOM_NAME=dom_name) | |
| 248 | |
| 249 return events_interface | |
| 250 | |
| 251 # TODO(jacobr): this isn't quite right.... | |
| 252 def _GetParentEventsInterface(self, interface): | |
| 253 # Ugly hack as we don't specify that Document and DocumentFragment inherit | |
| 254 # from Element in our IDL. | |
| 255 if interface.id == 'Document' or interface.id == 'DocumentFragment': | |
| 256 return 'ElementEvents' | |
| 257 | |
| 258 parent_events_interface = 'Events' | |
| 259 interfaces_with_events = set() | |
| 260 for parent in self._database.Hierarchy(interface): | |
| 261 if parent != interface and parent.id in self._event_classes: | |
| 262 parent_events_interface = parent.id + 'Events' | |
| 263 interfaces_with_events.add(parent) | |
| 264 if len(interfaces_with_events) > 1: | |
| 265 raise Exception('Only one parent event class allowed ' + interface.id) | |
| 266 return parent_events_interface | |
| OLD | NEW |