| 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 from generator import GetAnnotationsAndComments, FormatAnnotationsAndComments | 9 from generator import GetAnnotationsAndComments, FormatAnnotationsAndComments |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 # using addEventListener even though the onEventName properties in the DOM for | 23 # using addEventListener even though the onEventName properties in the DOM for |
| 24 # them are not camel case. | 24 # them are not camel case. |
| 25 _on_attribute_to_event_name_mapping = { | 25 _on_attribute_to_event_name_mapping = { |
| 26 'webkitanimationend': 'webkitAnimationEnd', | 26 'webkitanimationend': 'webkitAnimationEnd', |
| 27 'webkitanimationiteration': 'webkitAnimationIteration', | 27 'webkitanimationiteration': 'webkitAnimationIteration', |
| 28 'webkitanimationstart': 'webkitAnimationStart', | 28 'webkitanimationstart': 'webkitAnimationStart', |
| 29 'webkitspeechchange': 'webkitSpeechChange', | 29 'webkitspeechchange': 'webkitSpeechChange', |
| 30 'webkittransitionend': 'webkitTransitionEnd', | 30 'webkittransitionend': 'webkitTransitionEnd', |
| 31 } | 31 } |
| 32 | 32 |
| 33 # Mapping from raw event names to the pretty camelCase event names exposed as | |
| 34 # properties in dart:html. If the DOM exposes a new event name, you will need | |
| 35 # to add the lower case to camel case conversion for that event name here. | |
| 36 _html_event_names = { | |
| 37 'DOMContentLoaded': 'contentLoaded', | |
| 38 'abort': 'abort', | |
| 39 'addstream': 'addStream', | |
| 40 'addtrack': 'addTrack', | |
| 41 'audioend': 'audioEnd', | |
| 42 'audioprocess': 'audioProcess', | |
| 43 'audiostart': 'audioStart', | |
| 44 'beforecopy': 'beforeCopy', | |
| 45 'beforecut': 'beforeCut', | |
| 46 'beforepaste': 'beforePaste', | |
| 47 'beforeunload': 'beforeUnload', | |
| 48 'blocked': 'blocked', | |
| 49 'blur': 'blur', | |
| 50 'cached': 'cached', | |
| 51 'canplay': 'canPlay', | |
| 52 'canplaythrough': 'canPlayThrough', | |
| 53 'change': 'change', | |
| 54 'chargingchange': 'chargingChange', | |
| 55 'chargingtimechange': 'chargingTimeChange', | |
| 56 'checking': 'checking', | |
| 57 'click': 'click', | |
| 58 'close': 'close', | |
| 59 'complete': 'complete', | |
| 60 'connect': 'connect', | |
| 61 'connecting': 'connecting', | |
| 62 'contextmenu': 'contextMenu', | |
| 63 'copy': 'copy', | |
| 64 'cuechange': 'cueChange', | |
| 65 'cut': 'cut', | |
| 66 'dblclick': 'doubleClick', | |
| 67 'devicemotion': 'deviceMotion', | |
| 68 'deviceorientation': 'deviceOrientation', | |
| 69 'dischargingtimechange': 'dischargingTimeChange', | |
| 70 'display': 'display', | |
| 71 'downloading': 'downloading', | |
| 72 'drag': 'drag', | |
| 73 'dragend': 'dragEnd', | |
| 74 'dragenter': 'dragEnter', | |
| 75 'dragleave': 'dragLeave', | |
| 76 'dragover': 'dragOver', | |
| 77 'dragstart': 'dragStart', | |
| 78 'drop': 'drop', | |
| 79 'durationchange': 'durationChange', | |
| 80 'emptied': 'emptied', | |
| 81 'end': 'end', | |
| 82 'ended': 'ended', | |
| 83 'enter': 'enter', | |
| 84 'error': 'error', | |
| 85 'exit': 'exit', | |
| 86 'focus': 'focus', | |
| 87 'hashchange': 'hashChange', | |
| 88 'icecandidate': 'iceCandidate', | |
| 89 'icechange': 'iceChange', | |
| 90 'input': 'input', | |
| 91 'invalid': 'invalid', | |
| 92 'keydown': 'keyDown', | |
| 93 'keypress': 'keyPress', | |
| 94 'keyup': 'keyUp', | |
| 95 'levelchange': 'levelChange', | |
| 96 'load': 'load', | |
| 97 'loadeddata': 'loadedData', | |
| 98 'loadedmetadata': 'loadedMetadata', | |
| 99 'loadend': 'loadEnd', | |
| 100 'loadstart': 'loadStart', | |
| 101 'message': 'message', | |
| 102 'mousedown': 'mouseDown', | |
| 103 'mousemove': 'mouseMove', | |
| 104 'mouseout': 'mouseOut', | |
| 105 'mouseover': 'mouseOver', | |
| 106 'mouseup': 'mouseUp', | |
| 107 'mousewheel': 'mouseWheel', | |
| 108 'mute': 'mute', | |
| 109 'negotiationneeded': 'negotiationNeeded', | |
| 110 'nomatch': 'noMatch', | |
| 111 'noupdate': 'noUpdate', | |
| 112 'obsolete': 'obsolete', | |
| 113 'offline': 'offline', | |
| 114 'online': 'online', | |
| 115 'open': 'open', | |
| 116 'pagehide': 'pageHide', | |
| 117 'pageshow': 'pageShow', | |
| 118 'paste': 'paste', | |
| 119 'pause': 'pause', | |
| 120 'play': 'play', | |
| 121 'playing': 'playing', | |
| 122 'popstate': 'popState', | |
| 123 'progress': 'progress', | |
| 124 'ratechange': 'rateChange', | |
| 125 'readystatechange': 'readyStateChange', | |
| 126 'removestream': 'removeStream', | |
| 127 'removetrack': 'removeTrack', | |
| 128 'reset': 'reset', | |
| 129 'resize': 'resize', | |
| 130 'result': 'result', | |
| 131 'resultdeleted': 'resultDeleted', | |
| 132 'scroll': 'scroll', | |
| 133 'search': 'search', | |
| 134 'seeked': 'seeked', | |
| 135 'seeking': 'seeking', | |
| 136 'select': 'select', | |
| 137 'selectionchange': 'selectionChange', | |
| 138 'selectstart': 'selectStart', | |
| 139 'show': 'show', | |
| 140 'soundend': 'soundEnd', | |
| 141 'soundstart': 'soundStart', | |
| 142 'speechend': 'speechEnd', | |
| 143 'speechstart': 'speechStart', | |
| 144 'stalled': 'stalled', | |
| 145 'start': 'start', | |
| 146 'statechange': 'stateChange', | |
| 147 'storage': 'storage', | |
| 148 'submit': 'submit', | |
| 149 'success': 'success', | |
| 150 'suspend': 'suspend', | |
| 151 'timeupdate': 'timeUpdate', | |
| 152 'touchcancel': 'touchCancel', | |
| 153 'touchend': 'touchEnd', | |
| 154 'touchenter': 'touchEnter', | |
| 155 'touchleave': 'touchLeave', | |
| 156 'touchmove': 'touchMove', | |
| 157 'touchstart': 'touchStart', | |
| 158 'unload': 'unload', | |
| 159 'upgradeneeded': 'upgradeNeeded', | |
| 160 'unmute': 'unmute', | |
| 161 'updateready': 'updateReady', | |
| 162 'versionchange': 'versionChange', | |
| 163 'volumechange': 'volumeChange', | |
| 164 'waiting': 'waiting', | |
| 165 'webkitAnimationEnd': 'animationEnd', | |
| 166 'webkitAnimationIteration': 'animationIteration', | |
| 167 'webkitAnimationStart': 'animationStart', | |
| 168 'webkitfullscreenchange': 'fullscreenChange', | |
| 169 'webkitfullscreenerror': 'fullscreenError', | |
| 170 'webkitkeyadded': 'keyAdded', | |
| 171 'webkitkeyerror': 'keyError', | |
| 172 'webkitkeymessage': 'keyMessage', | |
| 173 'webkitneedkey': 'needKey', | |
| 174 'webkitpointerlockchange': 'pointerLockChange', | |
| 175 'webkitpointerlockerror': 'pointerLockError', | |
| 176 'webkitSpeechChange': 'speechChange', | |
| 177 'webkitsourceclose': 'sourceClose', | |
| 178 'webkitsourceended': 'sourceEnded', | |
| 179 'webkitsourceopen': 'sourceOpen', | |
| 180 'webkitTransitionEnd': 'transitionEnd', | |
| 181 'write': 'write', | |
| 182 'writeend': 'writeEnd', | |
| 183 'writestart': 'writeStart' | |
| 184 } | |
| 185 | |
| 186 _html_event_types = { | 33 _html_event_types = { |
| 187 '*.abort': ('abort', 'Event'), | 34 '*.abort': ('abort', 'Event'), |
| 188 '*.beforecopy': ('beforeCopy', 'Event'), | 35 '*.beforecopy': ('beforeCopy', 'Event'), |
| 189 '*.beforecut': ('beforeCut', 'Event'), | 36 '*.beforecut': ('beforeCut', 'Event'), |
| 190 '*.beforepaste': ('beforePaste', 'Event'), | 37 '*.beforepaste': ('beforePaste', 'Event'), |
| 191 '*.beforeunload': ('beforeUnload', 'Event'), | 38 '*.beforeunload': ('beforeUnload', 'Event'), |
| 192 '*.blur': ('blur', 'Event'), | 39 '*.blur': ('blur', 'Event'), |
| 193 '*.canplay': ('canPlay', 'Event'), | 40 '*.canplay': ('canPlay', 'Event'), |
| 194 '*.canplaythrough': ('canPlayThrough', 'Event'), | 41 '*.canplaythrough': ('canPlayThrough', 'Event'), |
| 195 '*.change': ('change', 'Event'), | 42 '*.change': ('change', 'Event'), |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 """ | 357 """ |
| 511 key = '%s.%s' % (html_interface_name, dom_event_name) | 358 key = '%s.%s' % (html_interface_name, dom_event_name) |
| 512 if key in _html_event_types: | 359 if key in _html_event_types: |
| 513 return _html_event_types[key] | 360 return _html_event_types[key] |
| 514 key = '*.%s' % dom_event_name | 361 key = '*.%s' % dom_event_name |
| 515 if key in _html_event_types: | 362 if key in _html_event_types: |
| 516 return _html_event_types[key] | 363 return _html_event_types[key] |
| 517 _logger.warn('Cannot resolve event type for %s.%s' % | 364 _logger.warn('Cannot resolve event type for %s.%s' % |
| 518 (html_interface_name, dom_event_name)) | 365 (html_interface_name, dom_event_name)) |
| 519 return None | 366 return None |
| 520 | |
| 521 def ProcessInterface(self, interface, html_interface_name, custom_events, | |
| 522 events_implementation_emitter): | |
| 523 event_names = set([attr.id[2:] for attr in interface.attributes | |
| 524 if attr.type.id == 'EventListener']) | |
| 525 | |
| 526 # Document and DocumentFragment actually derive from Element, so omit | |
| 527 # any events which are duplicated with that. | |
| 528 if interface.id == 'Document' or interface.id == 'DocumentFragment': | |
| 529 element_interface = self._database.GetInterface('Element') | |
| 530 for attr in element_interface.attributes: | |
| 531 if attr.type.id == 'EventListener' and attr.id[2:] in event_names: | |
| 532 event_names.remove(attr.id[2:]) | |
| 533 | |
| 534 if not event_names and interface.id not in _html_explicit_event_classes: | |
| 535 return None | |
| 536 | |
| 537 self._event_classes.add(interface.id) | |
| 538 events_class_name = html_interface_name + 'Events' | |
| 539 parent_events_class_name = self._GetParentEventsClassName(interface) | |
| 540 | |
| 541 if not event_names: | |
| 542 return parent_events_class_name | |
| 543 | |
| 544 template_file = 'impl_%s.darttemplate' % events_class_name | |
| 545 template = (self._template_loader.TryLoad(template_file) or | |
| 546 '\n' | |
| 547 '@DocsEditable\n' | |
| 548 '@deprecated\n' | |
| 549 'class $CLASSNAME extends $SUPER {\n' | |
| 550 ' @DocsEditable\n' | |
| 551 ' $CLASSNAME(EventTarget _ptr) : super(_ptr);\n' | |
| 552 '$!MEMBERS}\n') | |
| 553 | |
| 554 # TODO(jacobr): specify the type of _ptr as EventTarget | |
| 555 implementation_events_members = events_implementation_emitter.Emit( | |
| 556 template, | |
| 557 CLASSNAME=events_class_name, | |
| 558 SUPER='%s' % parent_events_class_name) | |
| 559 | |
| 560 dom_event_names = set() | |
| 561 for event in event_names: | |
| 562 dom_name = event | |
| 563 dom_name = _on_attribute_to_event_name_mapping.get(dom_name, dom_name) | |
| 564 dom_event_names.add(dom_name) | |
| 565 if html_interface_name in _html_manual_events: | |
| 566 dom_event_names.update(_html_manual_events[html_interface_name]) | |
| 567 for dom_name in sorted(dom_event_names): | |
| 568 if dom_name not in _html_event_names: | |
| 569 _logger.warn('omitting %s event as there is no HTML name for it' % dom_n
ame) | |
| 570 continue | |
| 571 | |
| 572 html_name = _html_event_names[dom_name] | |
| 573 full_event_name = '%sEvents.%s' % (html_interface_name, html_name) | |
| 574 if not full_event_name in custom_events: | |
| 575 implementation_events_members.Emit( | |
| 576 "\n" | |
| 577 " @DocsEditable\n" | |
| 578 " EventListenerList get $NAME => this['$DOM_NAME'];\n", | |
| 579 NAME=html_name, | |
| 580 DOM_NAME=dom_name) | |
| 581 | |
| 582 return events_class_name | |
| 583 | |
| 584 # TODO(jacobr): this isn't quite right.... | |
| 585 def _GetParentEventsClassName(self, interface): | |
| 586 # Ugly hack as we don't specify that Document and DocumentFragment inherit | |
| 587 # from Element in our IDL. | |
| 588 if interface.id == 'Document' or interface.id == 'DocumentFragment': | |
| 589 return 'ElementEvents' | |
| 590 | |
| 591 parent_events_class_name = 'Events' | |
| 592 interfaces_with_events = set() | |
| 593 for parent in self._database.Hierarchy(interface): | |
| 594 if parent != interface and parent.id in self._event_classes: | |
| 595 parent_name = self._renamer.RenameInterface(parent) | |
| 596 parent_events_class_name = parent_name + 'Events' | |
| 597 interfaces_with_events.add(parent) | |
| 598 if len(interfaces_with_events) > 1: | |
| 599 raise Exception('Only one parent event class allowed ' + interface.id) | |
| 600 return parent_events_class_name | |
| OLD | NEW |