OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 4 # BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 """This module provides functionality to generate dart:html event classes.""" | 6 """This module provides functionality to generate dart:html event classes.""" |
7 | 7 |
8 import logging | 8 import logging |
9 | 9 |
10 _logger = logging.getLogger('dartgenerator') | 10 _logger = logging.getLogger('dartgenerator') |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 'webkitSpeechChange': 'speechChange', | 175 'webkitSpeechChange': 'speechChange', |
176 'webkitsourceclose': 'sourceClose', | 176 'webkitsourceclose': 'sourceClose', |
177 'webkitsourceended': 'sourceEnded', | 177 'webkitsourceended': 'sourceEnded', |
178 'webkitsourceopen': 'sourceOpen', | 178 'webkitsourceopen': 'sourceOpen', |
179 'webkitTransitionEnd': 'transitionEnd', | 179 'webkitTransitionEnd': 'transitionEnd', |
180 'write': 'write', | 180 'write': 'write', |
181 'writeend': 'writeEnd', | 181 'writeend': 'writeEnd', |
182 'writestart': 'writeStart' | 182 'writestart': 'writeStart' |
183 } | 183 } |
184 | 184 |
| 185 _html_event_types = { |
| 186 '*.abort': ('abort', 'Event'), |
| 187 '*.beforecopy': ('beforeCopy', 'Event'), |
| 188 '*.beforecut': ('beforeCut', 'Event'), |
| 189 '*.beforepaste': ('beforePaste', 'Event'), |
| 190 '*.beforeunload': ('beforeUnload', 'Event'), |
| 191 '*.blur': ('blur', 'Event'), |
| 192 '*.canplay': ('canPlay', 'Event'), |
| 193 '*.canplaythrough': ('canPlayThrough', 'Event'), |
| 194 '*.change': ('change', 'Event'), |
| 195 '*.click': ('click', 'MouseEvent'), |
| 196 '*.contextmenu': ('contextMenu', 'MouseEvent'), |
| 197 '*.copy': ('copy', 'Event'), |
| 198 '*.cut': ('cut', 'Event'), |
| 199 '*.dblclick': ('doubleClick', 'Event'), |
| 200 '*.drag': ('drag', 'MouseEvent'), |
| 201 '*.dragend': ('dragEnd', 'MouseEvent'), |
| 202 '*.dragenter': ('dragEnter', 'MouseEvent'), |
| 203 '*.dragleave': ('dragLeave', 'MouseEvent'), |
| 204 '*.dragover': ('dragOver', 'MouseEvent'), |
| 205 '*.dragstart': ('dragStart', 'MouseEvent'), |
| 206 '*.drop': ('drop', 'MouseEvent'), |
| 207 '*.durationchange': ('durationChange', 'Event'), |
| 208 '*.emptied': ('emptied', 'Event'), |
| 209 '*.ended': ('ended', 'Event'), |
| 210 '*.error': ('error', 'Event'), |
| 211 '*.focus': ('focus', 'Event'), |
| 212 '*.hashchange': ('hashChange', 'HashChangeEvent'), |
| 213 '*.input': ('input', 'Event'), |
| 214 '*.invalid': ('invalid', 'Event'), |
| 215 '*.keydown': ('keyDown', 'KeyboardEvent'), |
| 216 '*.keypress': ('keyPress', 'KeyboardEvent'), |
| 217 '*.keyup': ('keyUp', 'KeyboardEvent'), |
| 218 '*.load': ('load', 'Event'), |
| 219 '*.loadeddata': ('loadedData', 'Event'), |
| 220 '*.loadedmetadata': ('loadedMetadata', 'Event'), |
| 221 '*.message': ('message', 'MessageEvent'), |
| 222 '*.mousedown': ('mouseDown', 'MouseEvent'), |
| 223 '*.mousemove': ('mouseMove', 'MouseEvent'), |
| 224 '*.mouseout': ('mouseOut', 'MouseEvent'), |
| 225 '*.mouseover': ('mouseOver', 'MouseEvent'), |
| 226 '*.mouseup': ('mouseUp', 'MouseEvent'), |
| 227 '*.mousewheel': ('mouseWheel', 'WheelEvent'), |
| 228 '*.offline': ('offline', 'Event'), |
| 229 '*.online': ('online', 'Event'), |
| 230 '*.paste': ('paste', 'Event'), |
| 231 '*.pause': ('pause', 'Event'), |
| 232 '*.play': ('play', 'Event'), |
| 233 '*.playing': ('playing', 'Event'), |
| 234 '*.popstate': ('popState', 'PopStateEvent'), |
| 235 '*.ratechange': ('rateChange', 'Event'), |
| 236 '*.reset': ('reset', 'Event'), |
| 237 '*.resize': ('resize', 'Event'), |
| 238 '*.scroll': ('scroll', 'Event'), |
| 239 '*.search': ('search', 'Event'), |
| 240 '*.seeked': ('seeked', 'Event'), |
| 241 '*.seeking': ('seeking', 'Event'), |
| 242 '*.select': ('select', 'Event'), |
| 243 '*.selectstart': ('selectStart', 'Event'), |
| 244 '*.stalled': ('stalled', 'Event'), |
| 245 '*.storage': ('storage', 'StorageEvent'), |
| 246 '*.submit': ('submit', 'Event'), |
| 247 '*.suspend': ('suspend', 'Event'), |
| 248 '*.timeupdate': ('timeUpdate', 'Event'), |
| 249 '*.touchcancel': ('touchCancel', 'TouchEvent'), |
| 250 '*.touchend': ('touchEnd', 'TouchEvent'), |
| 251 '*.touchenter': ('touchEnter', 'TouchEvent'), |
| 252 '*.touchleave': ('touchLeave', 'TouchEvent'), |
| 253 '*.touchmove': ('touchMove', 'TouchEvent'), |
| 254 '*.touchstart': ('touchStart', 'TouchEvent'), |
| 255 '*.unload': ('unload', 'Event'), |
| 256 '*.volumechange': ('volumeChange', 'Event'), |
| 257 '*.waiting': ('waiting', 'Event'), |
| 258 '*.webkitAnimationEnd': ('animationEnd', 'AnimationEvent'), |
| 259 '*.webkitAnimationIteration': ('animationIteration', 'AnimationEvent'), |
| 260 '*.webkitAnimationStart': ('animationStart', 'AnimationEvent'), |
| 261 '*.webkitTransitionEnd': ('transitionEnd', 'TransitionEvent'), |
| 262 '*.webkitfullscreenchange': ('fullscreenChange', 'Event'), |
| 263 '*.webkitfullscreenerror': ('fullscreenError', 'Event'), |
| 264 'AudioContext.complete': ('complete', 'Event'), |
| 265 'BatteryManager.chargingchange': ('chargingChange', 'Event'), |
| 266 'BatteryManager.chargingtimechange': ('chargingTimeChange', 'Event'), |
| 267 'BatteryManager.dischargingtimechange': ('dischargingTimeChange', 'Event'), |
| 268 'BatteryManager.levelchange': ('levelChange', 'Event'), |
| 269 'DOMApplicationCache.cached': ('cached', 'Event'), |
| 270 'DOMApplicationCache.checking': ('checking', 'Event'), |
| 271 'DOMApplicationCache.downloading': ('downloading', 'Event'), |
| 272 'DOMApplicationCache.noupdate': ('noUpdate', 'Event'), |
| 273 'DOMApplicationCache.obsolete': ('obsolete', 'Event'), |
| 274 'DOMApplicationCache.progress': ('progress', 'Event'), |
| 275 'DOMApplicationCache.updateready': ('updateReady', 'Event'), |
| 276 'Document.cuechange': ('cueChange', 'Event'), |
| 277 'Document.readystatechange': ('readyStateChange', 'Event'), |
| 278 'Document.selectionchange': ('selectionChange', 'Event'), |
| 279 'Document.webkitpointerlockchange': ('pointerLockChange', 'Event'), |
| 280 'Document.webkitpointerlockerror': ('pointerLockError', 'Event'), |
| 281 'Element.cuechange': ('cueChange', 'Event'), |
| 282 'EventSource.open': ('open', 'Event'), |
| 283 'FileReader.abort': ('abort', 'ProgressEvent'), |
| 284 'FileReader.load': ('load', 'ProgressEvent'), |
| 285 'FileReader.loadend': ('loadEnd', 'ProgressEvent'), |
| 286 'FileReader.loadstart': ('loadStart', 'ProgressEvent'), |
| 287 'FileReader.progress': ('progress', 'ProgressEvent'), |
| 288 'FileWriter.abort': ('abort', 'ProgressEvent'), |
| 289 'FileWriter.progress': ('progress', 'ProgressEvent'), |
| 290 'FileWriter.write': ('write', 'ProgressEvent'), |
| 291 'FileWriter.writeend': ('writeEnd', 'ProgressEvent'), |
| 292 'FileWriter.writestart': ('writeStart', 'ProgressEvent'), |
| 293 'HTMLBodyElement.storage': ('storage', 'StorageEvent'), |
| 294 'HTMLInputElement.webkitSpeechChange': ('speechChange', 'Event'), |
| 295 'HTMLMediaElement.loadstart': ('loadStart', 'Event'), |
| 296 'HTMLMediaElement.progress': ('progress', 'Event'), |
| 297 'HTMLMediaElement.show': ('show', 'Event'), |
| 298 'HTMLMediaElement.webkitkeyadded': ('keyAdded', 'MediaKeyEvent'), |
| 299 'HTMLMediaElement.webkitkeyerror': ('keyError', 'MediaKeyEvent'), |
| 300 'HTMLMediaElement.webkitkeymessage': ('keyMessage', 'MediaKeyEvent'), |
| 301 'HTMLMediaElement.webkitneedkey': ('needKey', 'MediaKeyEvent'), |
| 302 'IDBDatabase.versionchange': ('versionChange', 'UpgradeNeededEvent'), |
| 303 'IDBOpenDBRequest.blocked': ('blocked', 'Event'), |
| 304 'IDBOpenDBRequest.upgradeneeded': ('upgradeNeeded', 'VersionChangeEvent'), |
| 305 'IDBRequest.success': ('success', 'Event'), |
| 306 'IDBTransaction.complete': ('complete', 'Event'), |
| 307 'IDBVersionChangeRequest.blocked': ('blocked', 'Event'), |
| 308 'MediaController.play': ('play', 'Event'), |
| 309 'MediaStreamTrack.mute': ('mute', 'Event'), |
| 310 'MediaStreamTrack.unmute': ('unmute', 'Event'), |
| 311 'MediaStreamTrackList.addtrack': ('addTrack', 'MediaStreamTrackEvent'), |
| 312 'MediaStreamTrackList.removetrack': ('removeTrack', 'MediaStreamTrackEvent'), |
| 313 'Notification.click': ('click', 'Event'), |
| 314 'Notification.close': ('close', 'Event'), |
| 315 'Notification.display': ('display', 'Event'), |
| 316 'Notification.show': ('show', 'Event'), |
| 317 'RTCDataChannel.close': ('close', 'Event'), |
| 318 'RTCDataChannel.open': ('open', 'Event'), |
| 319 'RTCPeerConnection.addstream': ('addStream', 'MediaStreamEvent'), |
| 320 'RTCPeerConnection.connecting': ('connecting', 'MediaStreamEvent'), |
| 321 'RTCPeerConnection.datachannel': ('dataChannel', 'RtcDataChannelEvent'), |
| 322 'RTCPeerConnection.icecandidate': ('iceCandidate', 'RtcIceCandidateEvent'), |
| 323 'RTCPeerConnection.icechange': ('iceChange', 'Event'), |
| 324 'RTCPeerConnection.negotiationneeded': ('negotiationNeeded', 'Event'), |
| 325 'RTCPeerConnection.open': ('open', 'Event'), |
| 326 'RTCPeerConnection.removestream': ('removeStream', 'MediaStreamEvent'), |
| 327 'RTCPeerConnection.statechange': ('stateChange', 'Event'), |
| 328 'ScriptProcessorNode.audioprocess': ('audioProcess', 'AudioProcessingEvent'), |
| 329 'SharedWorkerContext.connect': ('connect', 'Event'), |
| 330 'SpeechRecognition.audioend': ('audioEnd', 'Event'), |
| 331 'SpeechRecognition.audiostart': ('audioStart', 'Event'), |
| 332 'SpeechRecognition.end': ('end', 'Event'), |
| 333 'SpeechRecognition.error': ('error', 'SpeechRecognitionError'), |
| 334 'SpeechRecognition.nomatch': ('noMatch', 'SpeechRecognitionEvent'), |
| 335 'SpeechRecognition.result': ('result', 'SpeechRecognitionEvent'), |
| 336 'SpeechRecognition.soundend': ('soundEnd', 'Event'), |
| 337 'SpeechRecognition.soundstart': ('soundStart', 'Event'), |
| 338 'SpeechRecognition.speechend': ('speechEnd', 'Event'), |
| 339 'SpeechRecognition.speechstart': ('speechStart', 'Event'), |
| 340 'SpeechRecognition.start': ('start', 'Event'), |
| 341 'TextTrack.cuechange': ('cueChange', 'Event'), |
| 342 'TextTrackCue.enter': ('enter', 'Event'), |
| 343 'TextTrackCue.exit': ('exit', 'Event'), |
| 344 'TextTrackList.addtrack': ('addTrack', 'TrackEvent'), |
| 345 'WebSocket.close': ('close', 'CloseEvent'), |
| 346 'WebSocket.open': ('open', 'Event'), # should be OpenEvent, but not exposed. |
| 347 'Window.DOMContentLoaded': ('contentLoaded', 'Event'), |
| 348 'Window.cuechange': ('cueChange', 'Event'), |
| 349 'Window.devicemotion': ('deviceMotion', 'DeviceMotionEvent'), |
| 350 'Window.deviceorientation': ('deviceOrientation', 'DeviceOrientationEvent'), |
| 351 'Window.loadstart': ('loadStart', 'Event'), |
| 352 'Window.pagehide': ('pageHide', 'Event'), |
| 353 'Window.pageshow': ('pageShow', 'Event'), |
| 354 'Window.progress': ('progress', 'Event'), |
| 355 'XMLHttpRequest.abort': ('abort', 'ProgressEvent'), |
| 356 'XMLHttpRequest.error': ('error', 'ProgressEvent'), |
| 357 'XMLHttpRequest.load': ('load', 'ProgressEvent'), |
| 358 'XMLHttpRequest.loadend': ('loadEnd', 'ProgressEvent'), |
| 359 'XMLHttpRequest.loadstart': ('loadStart', 'ProgressEvent'), |
| 360 'XMLHttpRequest.progress': ('progress', 'ProgressEvent'), |
| 361 'XMLHttpRequest.readystatechange': ('readyStateChange', 'ProgressEvent'), |
| 362 'XMLHttpRequestUpload.abort': ('abort', 'ProgressEvent'), |
| 363 'XMLHttpRequestUpload.error': ('error', 'ProgressEvent'), |
| 364 'XMLHttpRequestUpload.load': ('load', 'ProgressEvent'), |
| 365 'XMLHttpRequestUpload.loadend': ('loadEnd', 'ProgressEvent'), |
| 366 'XMLHttpRequestUpload.loadstart': ('loadStart', 'ProgressEvent'), |
| 367 'XMLHttpRequestUpload.progress': ('progress', 'ProgressEvent'), |
| 368 } |
| 369 |
185 # These classes require an explicit declaration for the "on" method even though | 370 # These classes require an explicit declaration for the "on" method even though |
186 # they don't declare any unique events, because the concrete class hierarchy | 371 # they don't declare any unique events, because the concrete class hierarchy |
187 # doesn't match the interface hierarchy. | 372 # doesn't match the interface hierarchy. |
188 _html_explicit_event_classes = set(['DocumentFragment']) | 373 _html_explicit_event_classes = set(['DocumentFragment']) |
189 | 374 |
190 class HtmlEventGenerator(object): | 375 class HtmlEventGenerator(object): |
191 | 376 |
192 def __init__(self, database, renamer, template_loader): | 377 def __init__(self, database, renamer, template_loader): |
193 self._event_classes = set() | 378 self._event_classes = set() |
194 self._database = database | 379 self._database = database |
195 self._renamer = renamer | 380 self._renamer = renamer |
196 self._template_loader = template_loader | 381 self._template_loader = template_loader |
197 | 382 |
| 383 def EmitStreamProviders(self, interface, html_interface_name, custom_events, |
| 384 members_emitter): |
| 385 events = self._GetEvents(interface, html_interface_name, custom_events) |
| 386 if not events: |
| 387 return |
| 388 |
| 389 for event_info in events: |
| 390 (dom_name, html_name, event_type) = event_info |
| 391 members_emitter.Emit( |
| 392 "\n" |
| 393 " static const EventStreamProvider<$TYPE> $(NAME)Event = " |
| 394 "const EventStreamProvider<$TYPE>('$DOM_NAME');\n", |
| 395 NAME=html_name, |
| 396 DOM_NAME=dom_name, |
| 397 TYPE=event_type) |
| 398 |
| 399 def EmitStreamGetters(self, interface, html_interface_name, custom_events, |
| 400 members_emitter): |
| 401 events = self._GetEvents(interface, html_interface_name, custom_events) |
| 402 if not events: |
| 403 return |
| 404 |
| 405 for event_info in events: |
| 406 (dom_name, html_name, event_type) = event_info |
| 407 getter_name = 'on%s%s' % (html_name[:1].upper(), html_name[1:]) |
| 408 |
| 409 members_emitter.Emit( |
| 410 "\n" |
| 411 " Stream<$TYPE> get $(NAME) => $PROVIDER.forTarget(this);\n", |
| 412 NAME=getter_name, |
| 413 PROVIDER=html_name + 'Event', |
| 414 TYPE=event_type) |
| 415 |
| 416 def _GetEvents(self, interface, html_interface_name, custom_events): |
| 417 events = set([attr for attr in interface.attributes |
| 418 if attr.type.id == 'EventListener']) |
| 419 if not events and interface.id not in _html_explicit_event_classes: |
| 420 return None |
| 421 |
| 422 dom_event_names = set() |
| 423 for event in events: |
| 424 dom_name = event.id[2:] |
| 425 dom_name = _on_attribute_to_event_name_mapping.get(dom_name, dom_name) |
| 426 dom_event_names.add(dom_name) |
| 427 if html_interface_name in _html_manual_events: |
| 428 dom_event_names.update(_html_manual_events[html_interface_name]) |
| 429 |
| 430 events = [] |
| 431 for dom_name in sorted(dom_event_names): |
| 432 event_info = self._FindEventInfo(html_interface_name, dom_name) |
| 433 if not event_info: |
| 434 continue |
| 435 |
| 436 (html_name, event_type) = event_info |
| 437 full_event_name = '%sEvents.%s' % (html_interface_name, html_name) |
| 438 if not full_event_name in custom_events: |
| 439 events.append((dom_name, html_name, event_type)) |
| 440 return events |
| 441 |
| 442 def _FindEventInfo(self, html_interface_name, dom_event_name): |
| 443 key = '%s.%s' % (html_interface_name, dom_event_name) |
| 444 if key in _html_event_types: |
| 445 return _html_event_types[key] |
| 446 key = '*.%s' % dom_event_name |
| 447 if key in _html_event_types: |
| 448 return _html_event_types[key] |
| 449 _logger.warn('Cannot resolve event type for %s.%s' % |
| 450 (html_interface_name, dom_event_name)) |
| 451 return None |
| 452 |
198 def ProcessInterface(self, interface, html_interface_name, custom_events, | 453 def ProcessInterface(self, interface, html_interface_name, custom_events, |
199 events_implementation_emitter): | 454 events_implementation_emitter): |
200 event_names = set([attr.id[2:] for attr in interface.attributes | 455 event_names = set([attr.id[2:] for attr in interface.attributes |
201 if attr.type.id == 'EventListener']) | 456 if attr.type.id == 'EventListener']) |
202 | 457 |
203 # Document and DocumentFragment actually derive from Element, so omit | 458 # Document and DocumentFragment actually derive from Element, so omit |
204 # any events which are duplicated with that. | 459 # any events which are duplicated with that. |
205 if interface.id == 'Document' or interface.id == 'DocumentFragment': | 460 if interface.id == 'Document' or interface.id == 'DocumentFragment': |
206 element_interface = self._database.GetInterface('Element') | 461 element_interface = self._database.GetInterface('Element') |
207 for attr in element_interface.attributes: | 462 for attr in element_interface.attributes: |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 parent_events_class_name = 'Events' | 522 parent_events_class_name = 'Events' |
268 interfaces_with_events = set() | 523 interfaces_with_events = set() |
269 for parent in self._database.Hierarchy(interface): | 524 for parent in self._database.Hierarchy(interface): |
270 if parent != interface and parent.id in self._event_classes: | 525 if parent != interface and parent.id in self._event_classes: |
271 parent_name = self._renamer.RenameInterface(parent) | 526 parent_name = self._renamer.RenameInterface(parent) |
272 parent_events_class_name = parent_name + 'Events' | 527 parent_events_class_name = parent_name + 'Events' |
273 interfaces_with_events.add(parent) | 528 interfaces_with_events.add(parent) |
274 if len(interfaces_with_events) > 1: | 529 if len(interfaces_with_events) > 1: |
275 raise Exception('Only one parent event class allowed ' + interface.id) | 530 raise Exception('Only one parent event class allowed ' + interface.id) |
276 return parent_events_class_name | 531 return parent_events_class_name |
OLD | NEW |