├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── auto-publish.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── build.py ├── dom-architecture.bs ├── dom-architecture.html ├── event-algo.bs ├── event-algo.html ├── images ├── event-inheritance.svg ├── eventflow.svg └── stacked-event-mouse-dispatch.svg ├── index-snapshot.html ├── index.bs ├── proposals ├── d3e-keyflow.svg ├── dblclick.txt ├── keyflow-gecko.svg ├── mousewheel.txt └── trident-keyflow.svg ├── sections ├── acknowledgements.txt ├── conventions.txt ├── event-compositionevent.txt ├── event-focusevent.txt ├── event-inputevent.txt ├── event-interfaces.txt ├── event-keyboardevent.txt ├── event-mouseevent.txt ├── event-uievent.txt ├── event-wheelevent.txt ├── extending-events.txt ├── external-algorithms.txt ├── glossary.txt ├── introduction.txt ├── keyboard.txt ├── legacy-event-initializers.txt ├── legacy-event-types.txt ├── legacy-key-attributes.txt └── security.txt ├── stylesheet-extra.include ├── tests ├── key-mtest-101en-us.html ├── key-mtest-102fr-fr.html ├── key-mtest.css └── key-mtest.js ├── tools ├── focus-event-viewer.css ├── focus-event-viewer.html ├── focus-event-viewer.js ├── key-event-viewer-ce.html ├── key-event-viewer.css ├── key-event-viewer.html ├── key-event-viewer.js ├── main.css ├── main.html ├── mouse-event-viewer-core.js ├── mouse-event-viewer-shadow.html ├── mouse-event-viewer-shadow.js ├── mouse-event-viewer-shared.js ├── mouse-event-viewer.css ├── mouse-event-viewer.html ├── options.js └── output-table.js └── w3c.json /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Closes #?? 2 | 3 | The following tasks have been completed: 4 | 5 | * [ ] Confirmed there are no ReSpec/BikeShed errors or warnings. 6 | * [ ] Modified Web platform tests (link to pull request) 7 | 8 | Implementation commitment: 9 | 10 | * [ ] WebKit (https://bugs.webkit.org/show_bug.cgi?id=) 11 | * [ ] Chromium (https://bugs.chromium.org/p/chromium/issues/detail?id=) 12 | * [ ] Gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=) -------------------------------------------------------------------------------- /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | jobs: 7 | main: 8 | name: Build, Validate, Deploy 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - run: python build.py --includes-only 13 | - uses: w3c/spec-prod@v2 14 | with: 15 | GH_PAGES_BRANCH: gh-pages 16 | TOOLCHAIN: bikeshed 17 | BUILD_FAIL_ON: "link-error" 18 | W3C_NOTIFICATIONS_CC: ${{ secrets.CC }} 19 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN }} 20 | W3C_WG_DECISION_URL: https://lists.w3.org/Archives/Public/public-webapps/2014JulSep/0627.html 21 | W3C_BUILD_OVERRIDE: | 22 | status: WD 23 | shortname: uievents 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # These files are generated by the build.py script and should not 4 | # be checked in. 5 | sections/*.include 6 | index.html 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Web Platform Working Group 2 | 3 | Contributions to this repository are intended to become part of 4 | Recommendation-track documents governed by the 5 | [W3C Patent Policy](http://www.w3.org/Consortium/Patent-Policy-20040205/) 6 | and 7 | [Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). 8 | To make substantive contributions to specifications, you must either participate 9 | in the W3C 10 | [Web Platform Working Group](https://www.w3.org/WebPlatform/WG/) 11 | or make a 12 | [non-member patent licensing commitment](https://www.w3.org/2004/01/pp-impl/83482/nmlc). 13 | 14 | If you are not the sole contributor to a contribution (pull request), please 15 | identify all contributors in the pull request comment. 16 | 17 | To add a contributor (other than yourself, that's automatic), mark them one per 18 | line as follows: 19 | 20 | ``` 21 | +@github_username 22 | ``` 23 | 24 | If you added a contributor by mistake, you can remove them in a comment with: 25 | 26 | ``` 27 | -@github_username 28 | ``` 29 | 30 | If you are making a pull request on behalf of someone else but you had no part 31 | in designing the feature, you can remove yourself with the above syntax. 32 | 33 | # Tests 34 | 35 | For normative changes, a corresponding 36 | [web-platform-tests](https://github.com/web-platform-tests/wpt) PR is highly appreciated. Typically, 37 | both PRs will be merged at the same time. Note that a test change that contradicts the spec should 38 | not be merged before the corresponding spec change. If testing is not practical, please explain why 39 | and if appropriate [file an issue](https://github.com/web-platform-tests/wpt/issues/new) to follow 40 | up later. Add the `type:untestable` or `type:missing-coverage` label as appropriate. 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors 2 | under the 3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UI Events 2 | 3 | This repository is for the [UI Events specification](https://w3c.github.io/uievents/) (formerly known as DOM 3 Events). 4 | 5 | ## Goals 6 | 7 | The goal of the UI/DOM Events sub-group, part of the Web Applications Working Group, is to complete the 8 | UI Events specification according to market needs, to drive its adoption and implementation, to provide 9 | a comprehensive test suite (for implementability at least, and hopefully for interoperability, too), 10 | and to move it along the Recommendation Track to W3C Recommendation status. 11 | 12 | ## Communication 13 | 14 | For discussion of matters related to DOM Events, the group uses the www-dom@w3.org mailing list ([archive](http://lists.w3.org/Archives/Public/www-dom/)). 15 | 16 | ## Documents 17 | 18 | * Published Documents 19 | * [UI Events - Last Published WD](http://www.w3.org/TR/uievents/) 20 | * [DOM Level 3 KeyboardEvent key Values](http://www.w3.org/TR/DOM-Level-3-Events-key/) 21 | * [DOM Level 3 KeyboardEvent code Values](http://www.w3.org/TR/DOM-Level-3-Events-code/) 22 | * Editor's Drafts 23 | * [UI Events](https://w3c.github.io/uievents/) 24 | * [UI Events KeyboardEvent key Values](https://w3c.github.io/uievents-key/) 25 | * [UI Events KeyboardEvent code Values](https://w3c.github.io/uievents-code/) 26 | 27 | ## Open Issues 28 | 29 | * [UI Events Issues Database](https://github.com/w3c/uievents/issues) 30 | * Need for detailed review by implementors 31 | * Need for comprehensive test suite 32 | * [key Values Issues](https://github.com/w3c/uievents-key/issues) 33 | * [code Values Issues](https://github.com/w3c/uievents-code/issues) 34 | 35 | ## Building 36 | 37 | This spec was created using [bikeshed](https://github.com/tabatkins/bikeshed). 38 | If you would like to contribute edits, please make sure that your changes 39 | build correctly. 40 | 41 | To **build** this spec: 42 | 43 | 1. Clone this repo into a local directory. 44 | 1. Install [bikeshed](https://github.com/tabatkins/bikeshed) 45 | 1. Run `python build.py` in your local directory. 46 | 47 | To **make edits** to the spec: 48 | 49 | 1. Edit the `index.bs` file or any of the `sections\*.txt` files. 50 | 2. Build (as above). This will create a `sections\*.include` file for each 51 | `*.txt` file and then create the `index.html`. 52 | 53 | When submitting pull requests, make sure you don't include any of the 54 | `sections\*.include` files in your changelist — they've all been added to the 55 | `.gitignore` file so that you don't include them accidentally. All changes 56 | should be made in the `sections\*.txt` files and `index.bs`. 57 | 58 | ## Testing 59 | 60 | * [DomEventViewer](https://domeventviewer.com/) for testing UI Events 61 | * Web Platform Tests 62 | * [GitHub web-platform-tests/wpt uievents](https://github.com/web-platform-tests/wpt/tree/master/uievents) 63 | * Tests are mirrored on [wpt.live/uievents/](https://wpt.live/uievents/) 64 | 65 | ## Recommendations 66 | 67 | If you enjoyed this spec, you might be interested in these other specs from the same publisher: 68 | 69 | * UI Events KeyboardEvent code Values: [GitHub project](https://github.com/w3c/uievents-code/), [Link to spec](https://w3c.github.io/uievents-code/) 70 | * UI Events KeyboardEvent key Values: [GitHub project](https://github.com/w3c/uievents-key/), [Link to spec](https://w3c.github.io/uievents-key/) 71 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Script to build the Bikeshed (.bs) files for the UI Events spec.""" 4 | 5 | from __future__ import print_function 6 | 7 | import os.path 8 | import re 9 | import subprocess 10 | import sys 11 | 12 | DEBUG = False 13 | 14 | # This Parser processes the base *.txt files in the section/ directory to produce a set 15 | # of output *.bs files that can be used as input to Bikeshed to create the final .html 16 | # file. 17 | # This pre-processing marks up the Key and Code values (with appropriate links) and 18 | # generates HTML tables from the ASCII markup. 19 | class Parser(): 20 | """Pre-bikeshed parser for uievents spec.""" 21 | 22 | TABLE_TYPE_EVENT_SEQUENCE = 'event-sequence' 23 | TABLE_TYPE_EVENT_DEFINITION = 'event-definition' 24 | 25 | def __init__(self): 26 | self.curr_src = '' 27 | self.curr_dst = '' 28 | 29 | self.in_table = False 30 | self.table_type = '' 31 | self.table_header_data = [] 32 | self.table_column_format = [] 33 | self.table_row_data = [] 34 | self.is_header_row = False 35 | 36 | self.id = '0' 37 | self.event = 'evy' 38 | self.desc = 'desc' 39 | 40 | def error(self, msg): 41 | print(self.curr_src, self.line) 42 | print('Error: %s' % (msg)) 43 | sys.exit(1) 44 | 45 | def event_type(self, type): 46 | if type == '' or type == '...': 47 | return type 48 | return '' + type + '' 49 | 50 | def table_row(self): 51 | # Don't print header row for event-definition. 52 | if self.is_header_row and self.table_type == Parser.TABLE_TYPE_EVENT_DEFINITION: 53 | return '' 54 | 55 | if self.is_header_row: 56 | self.table_row_data = self.table_header_data 57 | 58 | if len(self.table_row_data) == 0: 59 | return '' 60 | if self.is_header_row: 61 | row = '' 62 | else: 63 | row = '' 64 | for i in range(0, len(self.table_row_data)): 65 | data = self.table_row_data[i] 66 | colname = self.table_header_data[i] 67 | align = self.table_column_format[i] 68 | style = '' 69 | if align == 'right': 70 | style = ' style="text-align:right"' 71 | elif align == 'center': 72 | style = ' style="text-align:center"' 73 | pre = '' % style 74 | post = '' 75 | if self.is_header_row or colname == '%': 76 | pre = '' % style 77 | post = '' 78 | if colname == '#': 79 | pre = '' % style 80 | if self.is_header_row: 81 | data = '' 82 | if not self.is_header_row and data != '': 83 | if colname == 'Event Type': 84 | data = self.event_type(data) 85 | if colname == 'DOM Interface': 86 | data = '{{' + data + '}}' 87 | row += pre + self.process_text(data) + post 88 | if self.is_header_row: 89 | row += '\n' 90 | else: 91 | row += '\n' 92 | return row 93 | 94 | def process_text(self, desc): 95 | m = re.match(r'^(.*)EVENT{(.+?)}(.*)$', desc) 96 | if m: 97 | pre = self.process_text(m.group(1)) 98 | name = m.group(2) 99 | post = self.process_text(m.group(3)) 100 | desc = pre + self.event_type(name) + post 101 | 102 | m = re.match(r'^(.*)CODE{(.*?)}(.*)$', desc) 103 | if m: 104 | pre = self.process_text(m.group(1)) 105 | name = m.group(2) 106 | post = self.process_text(m.group(3)) 107 | desc = '%s"%s"%s' % (pre, name, name, post) 108 | 109 | m = re.match(r'^(.*)KEY{(.+?)}(.*)$', desc) 110 | if m: 111 | pre = self.process_text(m.group(1)) 112 | name = m.group(2) 113 | post = self.process_text(m.group(3)) 114 | desc = '%s"%s"%s' % (pre, name, name, post) 115 | 116 | m = re.match(r'^(.*)KEY_NOLINK{(.+?)}(.*)$', desc) 117 | if m: 118 | pre = self.process_text(m.group(1)) 119 | name = m.group(2) 120 | post = self.process_text(m.group(3)) 121 | desc = '%s"%s"%s' % (pre, name, post) 122 | 123 | m = re.match(r'^(.*)KEYCAP{(.+?)}(.*)$', desc) 124 | if m: 125 | pre = self.process_text(m.group(1)) 126 | name = m.group(2) 127 | post = self.process_text(m.group(3)) 128 | desc = pre + '' + name + '' + post 129 | 130 | m = re.match(r'^(.*)GLYPH{(.*?)}(.*)$', desc) 131 | if m: 132 | pre = self.process_text(m.group(1)) 133 | name = m.group(2) 134 | post = self.process_text(m.group(3)) 135 | desc = pre + '"' + name + '"' + post 136 | 137 | m = re.match(r'^(.*)UNI{(.+?)}(.*)$', desc) 138 | if m: 139 | pre = self.process_text(m.group(1)) 140 | name = m.group(2) 141 | post = self.process_text(m.group(3)) 142 | if name[0:2] != 'U+': 143 | self.error('Invalid Unicode value (expected U+xxxx): %s\n' % name) 144 | desc = pre + '' + name + '' + post 145 | 146 | return desc 147 | 148 | def process_line(self, line): 149 | if self.in_table: 150 | # Header rows begin with '=|' 151 | m = re.match(r'^\s*\=\|(.*)\|$', line) 152 | if m: 153 | self.table_header_data = [x.strip() for x in m.group(1).split('|')] 154 | self.is_header_row = True 155 | return '' 156 | 157 | # New data rows begin with '+|' 158 | m = re.match(r'^\s*\+\|(.*)\|$', line) 159 | if m: 160 | result = self.table_row() 161 | self.table_row_data = [x.strip() for x in m.group(1).split('|')] 162 | self.is_header_row = False 163 | return result 164 | 165 | # Tables end with: '++--' 166 | m = re.match(r'^\s*\+\+--', line) 167 | if m: 168 | self.in_table = False 169 | return self.table_row() + '\n' 170 | 171 | # Separator lines begin with ' +' and end with '+' 172 | # They may only contain '-', '+' and 'o'. 173 | m = re.match(r'^\s* \+([\-\+o]+)\+', line) 174 | if m: 175 | # Separator lines may contain column formatting info. 176 | num_columns = len(self.table_header_data) 177 | format_data = [x.strip() for x in m.group(1).split('+')] 178 | if len(format_data) != num_columns: 179 | self.error('Unexpected number of columns (%d) in row (expected %d):\n%s' 180 | % (len(format_data), num_columns, line)) 181 | for i in range(0, len(self.table_header_data)): 182 | align = 'left' 183 | if len(format_data[i]) != 0: 184 | if format_data[i][0] == 'o': 185 | align = 'left' 186 | elif format_data[i][-1] == 'o': 187 | align = 'right' 188 | elif 'o' in format_data[i]: 189 | align = 'center' 190 | self.table_column_format.append(align) 191 | return '' 192 | 193 | # Row continued from previous line: ' |' 194 | m = re.match(r'^\s*\|(.*)\|', line) 195 | if m: 196 | num_columns = len(self.table_header_data) 197 | extra_data = [x.strip() for x in m.group(1).split('|')] 198 | if len(extra_data) != num_columns: 199 | self.error('Unexpected number of columns (%d) in row (expected %d):\n%s' 200 | % (len(extra_data), num_columns, line)) 201 | for i in range(0, len(self.table_header_data)): 202 | if len(extra_data[i]) != 0: 203 | if self.is_header_row: 204 | self.table_header_data[i] += ' ' + extra_data[i] 205 | else: 206 | self.table_row_data[i] += ' ' + extra_data[i] 207 | return '' 208 | 209 | self.error('Expected table line: ' + line) 210 | return('') 211 | 212 | # Tables begin with: ++---+----+-------+ 213 | m = re.match(r'^\s*\+\+--[\-\+]*\+(?P [\-a-z]+)?$', line) 214 | if m: 215 | table_class = m.group('class') 216 | if table_class == None: 217 | table_class = 'event-sequence-table' 218 | self.table_type = Parser.TABLE_TYPE_EVENT_SEQUENCE 219 | else: 220 | table_class = table_class[1:] 221 | self.table_type = Parser.TABLE_TYPE_EVENT_DEFINITION 222 | self.in_table = True 223 | #self.table_type = Parser.TABLE_TYPE_EVENT_SEQUENCE 224 | self.table_header_data = [] 225 | self.table_column_format = [] 226 | self.table_row_data = [] 227 | return '\n' % table_class 228 | 229 | return self.process_text(line.rstrip()) + '\n' 230 | 231 | def process(self, src, dst): 232 | print('Processing', src) 233 | self.curr_src = src 234 | self.curr_dst = dst 235 | 236 | if not os.path.isfile(src): 237 | self.error('File "%s" doesn\'t exist\n' % src) 238 | 239 | try: 240 | infile = open(src, 'r') 241 | except IOError as e: 242 | self.error('Unable to open "%s" for reading: %s\n' % (src, e)) 243 | 244 | try: 245 | outfile = open(dst, 'w') 246 | except IOError as e: 247 | self.error('Unable to open "%s" for writing: %s\n' % (dst, e)) 248 | 249 | self.line = 0 250 | for line in infile: 251 | self.line += 1 252 | new_line = self.process_line(line) 253 | outfile.write(new_line) 254 | 255 | outfile.close() 256 | infile.close() 257 | 258 | 259 | def process_main_spec(): 260 | sections = [ 261 | 'introduction', 262 | 'conventions', 263 | 'event-interfaces', 264 | 'event-uievent', 265 | 'event-focusevent', 266 | 'event-mouseevent', 267 | 'event-wheelevent', 268 | 'event-inputevent', 269 | 'event-keyboardevent', 270 | 'event-compositionevent', 271 | 'keyboard', 272 | 'external-algorithms', 273 | 'legacy-event-initializers', 274 | 'legacy-key-attributes', 275 | 'legacy-event-types', 276 | 'extending-events', 277 | 'security', 278 | 'acknowledgements', 279 | 'glossary', 280 | ] 281 | 282 | # Generate an .include file for each .txt file in the sections/ directory. 283 | # These .include files are referenced by the main index.bs file. 284 | for section in sections: 285 | infilename = 'sections/' + section + '.txt' 286 | outfilename = 'sections/' + section + '.include' 287 | 288 | # Generate the full include file for bikeshed. 289 | parser = Parser() 290 | parser.process(infilename, outfilename) 291 | 292 | if '--includes-only' in sys.argv: 293 | print('Skipped bikeshedding because of --includes-only.') 294 | else: 295 | print('Bikeshedding...') 296 | cmd = ["bikeshed", "spec"] 297 | if DEBUG: 298 | cmd.append('--line-numbers') 299 | subprocess.call(cmd) 300 | 301 | def main(): 302 | process_main_spec() 303 | 304 | if __name__ == '__main__': 305 | main() 306 | -------------------------------------------------------------------------------- /images/eventflow.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | DOM Level 3 Events: Event Flow 6 | Alternate description 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Window 41 | 42 | 43 | 44 | 45 | 46 | 47 | Document 48 | 49 | 50 | 51 | 52 | 53 | <html> 54 | 55 | 56 | 57 | 58 | <body> 59 | 60 | 61 | 62 | 63 | <table> 64 | 65 | 66 | 67 | 68 | <tbody> 69 | 70 | 71 | 72 | 73 | <tr> 74 | 75 | 76 | 77 | 78 | <tr> 79 | 80 | 81 | 82 | 83 | 84 | <td> 85 | 86 | 87 | 88 | 89 | Shady Grove 90 | 91 | 92 | 93 | 94 | 95 | <td> 96 | 97 | 98 | 99 | 100 | Aeolian 101 | 102 | 103 | 104 | 105 | 106 | <td> 107 | 108 | 109 | 110 | 111 | 112 | Over the River, Charlie 113 | 114 | 115 | 116 | 117 | 118 | 119 | <td> 120 | 121 | 122 | 123 | 124 | Dorian 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 136 | 138 | 140 | 142 | 144 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | Capture Phase (1) 155 | 156 | 158 | 159 | 160 | 161 | 162 | 164 | 166 | 167 | 168 | 169 | 170 | Target Phase (2) 171 | 172 | 174 | 175 | 176 | 177 | Bubbling Phase (3) 178 | 179 | 181 | 183 | 185 | 186 | 187 | 189 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /images/stacked-event-mouse-dispatch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 27 | 33 | 34 | 41 | 47 | 48 | 55 | 61 | 62 | 69 | 75 | 76 | 83 | 89 | 90 | 91 | 110 | 117 | 118 | 120 | 121 | 123 | image/svg+xml 124 | 126 | 127 | 128 | 129 | 130 | 135 | 138 | 146 | 154 | 162 | 169 | 178 | 187 | 191 | 195 | 196 | 200 | 204 | 205 | 209 | 213 | 214 | A 226 | B 238 | C 250 | 255 | 260 | 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /index.bs: -------------------------------------------------------------------------------- 1 |

UI Events

2 | 3 | 21 | 22 |
 23 | urlPrefix: https://www.w3.org/TR/WebIDL/#idl-; type: type;
 24 | 	text: long
 25 | urlPrefix: https://w3c.github.io/selection-api/#widl-Window-getSelection-Selection; type: dfn; for: Document
 26 | 	text: getSelection()
 27 | url: https://www.w3.org/TR/2004/REC-xml-20040204/#NT-S; type: dfn;
 28 | 	text: white space
 29 | url: https://www.w3.org/TR/uievents-key/#key-attribute-value; type: dfn; spec: uievents-key;
 30 | 	text: key attribute value
 31 | url: https://www.w3.org/TR/uievents-key/#keys-modifier; type: dfn; spec: uievents-key;
 32 | 	text: modifier keys table
 33 | url: https://html.spec.whatwg.org/multipage/forms.html#context-menus; type: dfn;
 34 | 	text: contextmenu
 35 | url: https://www.w3.org/TR/pointerevents3/#pointerevent-interface; type: interface; spec: pointerevents3
 36 | 	text: PointerEvent
 37 | url: https://dom.spec.whatwg.org/#concept-tree-ancestor; type: dfn;
 38 | 	text: ancestor
 39 | url: https://dom.spec.whatwg.org/#concept-event-initialize; type: dfn;
 40 | 	text: initialize an event
 41 | url: https://dom.spec.whatwg.org/#concept-event-create; type: dfn;
 42 | 	text: create a new event
 43 | 	text: creating a new event
 44 | urlPrefix: https://html.spec.whatwg.org/#; type: dfn; spec: html;
 45 | 	text: click focusable
 46 | 	text: focusable area
 47 | 
 48 | url: https://www.w3.org/TR/CSS21/visuren.html#x43; type: dfn;
 49 | 	text: stacking context
 50 | url: https://drafts.csswg.org/css-position-3/#positioned-box; type: dfn;
 51 | 	text: positioned
 52 | url: https://drafts.csswg.org/css-position-4/#paint-a-stacking-context; type: dfn;
 53 | 	text: painting a stacking context
 54 | url: https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint; type: dfn; spec: cssom-view
 55 | 	text: elementFromPoint
 56 | url: https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint; type: dfn; spec: cssom-view
 57 | 	text: elementsFromPoint
 58 | 
59 | 60 | 75 | 76 |
 77 | {
 78 | 	"DWW95": {
 79 | 		"title": "Developing International Software for Windows 95 and Windows NT: A Handbook for International Software Design",
 80 | 		"authors": [ "N. Kano" ],
 81 | 		"publisher": "Microsoft Press",
 82 | 		"date": "1995",
 83 | 		"isbn": "1-55615-840-8"
 84 | 	},
 85 | 	"US-ASCII": {
 86 | 		"title": "Coded Character Set - 7-Bit American Standard Code for Information Interchange",
 87 | 		"publisher": "Standard ANSI X3.4-1986",
 88 | 		"date": "1986"
 89 | 	},
 90 | 	"WIN1252": {
 91 | 		"title": "Windows 1252 a Coded Character Set - 8-Bit",
 92 | 		"href": "https://www.microsoft.com/globaldev/reference/sbcs/1252.htm",
 93 | 		"publisher": "Microsoft Corporation"
 94 | 	}
 95 | }
 96 | 
97 | 98 |
 99 | path: stylesheet-extra.include
100 | 
101 | 102 | 103 |
104 | path: sections/introduction.include
105 | 
106 | 107 | 108 |
109 | path: sections/conventions.include
110 | 
111 | 112 | 113 |
114 | path: sections/event-interfaces.include
115 | 
116 | 117 | 118 |
119 | path: sections/event-uievent.include
120 | 
121 |
122 | path: sections/event-focusevent.include
123 | 
124 |
125 | path: sections/event-mouseevent.include
126 | 
127 |
128 | path: sections/event-wheelevent.include
129 | 
130 |
131 | path: sections/event-inputevent.include
132 | 
133 |
134 | path: sections/event-keyboardevent.include
135 | 
136 |
137 | path: sections/event-compositionevent.include
138 | 
139 | 140 | 141 |
142 | path: sections/keyboard.include
143 | 
144 | 145 | 146 |
147 | path: sections/external-algorithms.include
148 | 
149 | 150 | 151 |
152 | path: sections/legacy-event-initializers.include
153 | 
154 | 155 | 156 |
157 | path: sections/legacy-key-attributes.include
158 | 
159 | 160 | 161 |
162 | path: sections/legacy-event-types.include
163 | 
164 | 165 | 166 |
167 | path: sections/extending-events.include
168 | 
169 | 170 | 171 |
172 | path: sections/security.include
173 | 
174 | 175 | 176 |
177 | path: sections/acknowledgements.include
178 | 
179 | 180 | 181 |
182 | path: sections/glossary.include
183 | 
184 | -------------------------------------------------------------------------------- /proposals/d3e-keyflow.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | DOM3 Events Key Event Flow Model 7 | schepers, 20-03-2008 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | No Key Events to Keydown 27 | 28 | 29 | Keydown to Keypress 30 | 31 | 32 | Keypress to Input Method Editor 33 | 34 | 35 | Input Method Editor to Combination of Keys 36 | 37 | 38 | Combination of Keys to Keyup 39 | 40 | 41 | Keyup to textInput 42 | 43 | 44 | Character Key to textInput 45 | 46 | 47 | Character Key to textInput 48 | 49 | 50 | 51 | Input Method Editor to Character Key 52 | 53 | 54 | 55 | Input Method Editor to Sustained 56 | 57 | 58 | 59 | Sustained to Delay 60 | 61 | 62 | 63 | Sustained to keyup 64 | 65 | 66 | 67 | Delay to keylongpress 68 | 69 | 70 | 71 | keylongpress to keypress 72 | 73 | 74 | 75 | keypress to Sustained 76 | 77 | 78 | 79 | keypress to Character Key 80 | 81 | 82 | 83 | 84 | Sustained to keypress 85 | 86 | 87 | 88 | 89 | 90 | Character Key to Modifier Key 91 | 92 | 93 | 94 | Modifier Key to Wait for Keys 95 | 96 | 97 | 98 | Wait for Keys to keydown 99 | 100 | 101 | 102 | 103 | Sustained to keyup 104 | 105 | 106 | 107 | 108 | No Key Events 109 | 110 | no key activity 111 | 112 | 113 | 114 | keydown Event 115 | 116 | keydown 117 | 118 | 119 | 120 | keypress Event 121 | 122 | keypress 123 | 124 | 125 | 126 | 127 | 128 | IME Operation Decision 129 | 130 | input message editor? 131 | 132 | 133 | 134 | Combination of Key Event 135 | 136 | 137 | combination of keys 138 | 139 | 140 | 141 | 142 | 143 | Sustained Keypress Decision 144 | 145 | Sustained? 146 | 147 | 148 | 149 | Character Key Decision 150 | 151 | character key? 152 | 153 | 154 | 155 | textInput 156 | 157 | textInput 158 | 159 | 160 | 161 | 162 | Modifier Key Decision 163 | 164 | modifier key? 165 | 166 | 167 | 168 | 169 | Wait for More Key-Events 170 | 171 | 172 | wait for more keys 173 | 174 | 175 | 176 | 177 | 178 | 179 | delay 180 | 181 | delay 182 | 183 | 184 | 185 | 186 | 187 | 188 | keylongpress Event 189 | 190 | keylongpress 191 | 192 | 193 | 194 | keypress Event 195 | 196 | keypress 197 | 198 | 199 | 200 | 201 | 202 | 203 | Sustained Keypress Decision 204 | 205 | Sustained? 206 | 207 | 208 | 209 | Character Key Decision 210 | 211 | character key? 212 | 213 | 214 | 215 | textInput 216 | 217 | textInput 218 | 219 | 220 | 221 | 222 | 223 | 224 | keyup Event 225 | 226 | keyup 227 | 228 | 229 | 230 | keyup Event 231 | 232 | keyup 233 | 234 | 235 | 236 | 237 | textInput 238 | 239 | textInput 240 | 241 | 242 | 243 | 250 | 251 | 252 | 253 | textInput without IME 254 | 255 | textInput without IME 256 | 257 | 258 | 259 | textInput repeat property 260 | 261 | repeat="true" 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /proposals/dblclick.txt: -------------------------------------------------------------------------------- 1 | Type dblclick 2 | Namespace None 3 | Interface MouseEvent 4 | Cancelable Yes 5 | Bubbles Yes 6 | Target Element 7 | 8 | Context Info is the same as for the click event the dblclick event is dispatched 9 | after, including UIEvent.detail taken in account platform conventions. 10 | 11 | dblclick is dispatched after the click event. It is not dispatched as default 12 | action of the click event though, cancelling the click event does not cancel the 13 | dblclick event. -------------------------------------------------------------------------------- /proposals/mousewheel.txt: -------------------------------------------------------------------------------- 1 | When "mouse wheeling" occurs, the implementation must dispatch a 2 | mouseomniwheel event implementing the following interface: 3 | 4 | interface MouseOmniWheelEvent : MouseEvent { 5 | readonly attribute long wheelDeltaX; 6 | readonly attribute long wheelDeltaY; 7 | readonly attribute long wheelDeltaZ; 8 | void initMouseOmniWheelEventNS(in DOMString namespaceURI, 9 | in DOMString typeArg, 10 | in boolean canBubbleArg, 11 | in boolean cancelableArg, 12 | in views::AbstractView viewArg, 13 | in long detailArg, 14 | in long screenXArg, 15 | in long screenYArg, 16 | in long clientXArg, 17 | in long clientYArg, 18 | in unsigned short buttonArg, 19 | in EventTarget relatedTargetArg, 20 | in DOMString modifiersList, 21 | in long wheelDeltaX, 22 | in long wheelDeltaY, 23 | in long wheelDeltaZ); 24 | }; 25 | 26 | wheelDeltaX is a number indicating the horizontal distance (positive means 27 | rotated to the right, negative means rotated to the left). 28 | 29 | wheelDeltaY is a number indicating the vertical distance (positive means rotated 30 | away from user or to the right, negative means rotated towards user or to the 31 | left). 32 | 33 | wheelDeltaZ, included for future extensibility, is a number indicating the 34 | distance along a third unspecified axis (positive means rotated away from the 35 | user, means rotated towards user). At the present time, implementors may use 36 | whatever modality is best suited to the task, such as the the use of the wheel 37 | in conjunction with a control key. 38 | 39 | The default value of wheelDeltaX, wheelDeltaY and wheelDeltaZ is 0. 40 | UIEvent.detail must always be 0. 41 | 42 | This event includes both scroll deltas. The default action of this event is to 43 | dispatch a mousewheel event if the y delta is non-zero. Besides 44 | that, its default action is to do whatever platform conventions suggest for the 45 | wheeling behavior. 46 | 47 | The mousewheel event implements the following interface: 48 | 49 | interface MouseWheelEvent : MouseEvent { 50 | readonly attribute long wheelDelta; 51 | void initMouseWheelEventNS(in DOMString namespaceURI, 52 | in DOMString typeArg, 53 | in boolean canBubbleArg, 54 | in boolean cancelableArg, 55 | in views::AbstractView viewArg, 56 | in long detailArg, 57 | in long screenXArg, 58 | in long screenYArg, 59 | in long clientXArg, 60 | in long clientYArg, 61 | in unsigned short buttonArg, 62 | in EventTarget relatedTargetArg, 63 | in DOMString modifiersList, 64 | in long wheelDelta); 65 | }; 66 | 67 | If the mousewheel event is cancelled, only the default action for 68 | vertical wheeling is cancelled. 69 | 70 | wheelDelta 71 | A number indicating the distance, measured as the number of "clicks" the wheel has been rotated. A positive value indicates that the wheel has been rotated away from the user (or in a right-hand manner on horizontally aligned devices) and a negative value indicates that the wheel has been rotated towards the user (or in a left-hand manner on horizontally aligned devices). The default value of the wheelDelta attribute is 0. 72 | 73 | A "click" is defined to be a unit of rotation. On some devices this is a finite physical step. On devices with smooth rotation, a "click" becomes the smallest reported amount of rotation. 74 | 75 | 76 | XXX: What about UIEvent.detail? 77 | 78 | For both mouseomniwheel and mousewheel, 79 | MouseEvent.relatedNode must indicate the element over which the 80 | pointer is located, or null if there is no such element (in the 81 | case where the device does not have a pointer, but does have a wheel). 82 | 83 | 84 | -------------------------------------------------------------------------------- /sections/acknowledgements.txt: -------------------------------------------------------------------------------- 1 |
2 |

Acknowledgements

3 | 4 | 5 | Many people contributed to the DOM specifications (Level 1, 2 or 3), 6 | including participants of the DOM Working Group, the DOM Interest Group, 7 | the WebAPI Working Group, and the WebApps Working Group. 8 | We especially thank the following: 9 | 10 | Andrew Watson (Object Management Group), 11 | Andy Heninger (IBM), 12 | Angel Diaz (IBM), 13 | Anne van Kesteren (Opera Software), 14 | Arnaud Le Hors (W3C and IBM), 15 | Arun Ranganathan (AOL), 16 | Ashok Malhotra (IBM and Microsoft), 17 | Ben Chang (Oracle), 18 | Bill Shea (Merrill Lynch), 19 | Bill Smith (Sun), 20 | Björn Höhrmann, 21 | Bob Sutor (IBM), 22 | Charles McCathie-Nevile (Opera Software, Co-Chair), 23 | Chris Lovett (Microsoft), 24 | Chris Wilson (Microsoft), 25 | Christophe Jolif (ILOG), 26 | David Brownell (Sun), 27 | David Ezell (Hewlett-Packard Company), 28 | David Singer (IBM), 29 | Dean Jackson (W3C, W3C Team Contact), 30 | Dimitris Dimitriadis (Improve AB and invited expert), 31 | Don Park (invited), 32 | Doug Schepers (Vectoreal), 33 | Elena Litani (IBM), 34 | Eric Vasilik (Microsoft), 35 | Gavin Nicol (INSO), 36 | Gorm Haug Eriksen (Opera Software), 37 | Ian Davis (Talis Information Limited), 38 | Ian Hickson (Google), 39 | Ian Jacobs (W3C), 40 | James Clark (invited), 41 | James Davidson (Sun), 42 | Jared Sorensen (Novell), 43 | Jeroen van Rotterdam (X-Hive Corporation), 44 | Joe Kesselman (IBM), 45 | Joe Lapp (webMethods), 46 | Joe Marini (Macromedia), 47 | John Robinson (AOL), 48 | Johnny Stenback (Netscape/AOL), 49 | Jon Ferraiolo (Adobe), 50 | Jonas Sicking (Mozilla Foundation), 51 | Jonathan Marsh (Microsoft), 52 | Jonathan Robie (Texcel Research and Software AG), 53 | Kim Adamson-Sharpe (SoftQuad Software Inc.), 54 | Lauren Wood (SoftQuad Software Inc., former Chair), 55 | Laurence Cable (Sun), 56 | Luca Mascaro (HTML Writers Guild), 57 | Maciej Stachowiak (Apple Computer), 58 | Marc Hadley (Sun Microsystems), 59 | Mark Davis (IBM), 60 | Mark Scardina (Oracle), 61 | Martin Dürst (W3C), 62 | Mary Brady (NIST), 63 | Michael Shenfield (Research In Motion), 64 | Mick Goulish (Software AG), 65 | Mike Champion (Arbortext and Software AG), 66 | Miles Sabin (Cromwell Media), 67 | Patti Lutsky (Arbortext), 68 | Paul Grosso (Arbortext), 69 | Peter Sharpe (SoftQuad Software Inc.), 70 | Phil Karlton (Netscape), 71 | Philippe Le Hégaret (W3C, W3C Team Contact and former Chair), 72 | Ramesh Lekshmynarayanan (Merrill Lynch), 73 | Ray Whitmer (iMall, Excite@Home, and Netscape/AOL, Chair), 74 | Rezaur Rahman (Intel), 75 | Rich Rollman (Microsoft), 76 | Rick Gessner (Netscape), 77 | Rick Jelliffe (invited), 78 | Rob Relyea (Microsoft), 79 | Robin Berjon (Expway, Co-Chair), 80 | Scott Hayman (Research In Motion), 81 | Scott Isaacs (Microsoft), 82 | Sharon Adler (INSO), 83 | Stéphane Sire (IntuiLab), 84 | Steve Byrne (JavaSoft), 85 | Tim Bray (invited), 86 | Tim Yu (Oracle), 87 | Tom Pixley (Netscape/AOL), 88 | T.V. Raman (Google). 89 | Vidur Apparao (Netscape) and 90 | Vinod Anupam (Lucent). 91 | 92 | Former editors: 93 | Tom Pixley (Netscape Communications Corporation) until July 2002; 94 | Philippe Le Hégaret (W3C) until November 2003; 95 | Björn Höhrmann (Invited Expert) until January 2008; 96 | and Jacob Rossi (Microsoft) from March 2011 to October 2011. 97 | 98 | Contributors: 99 | In the WebApps Working Group, the following people made substantial 100 | material contributions in the process of refining and revising this 101 | specification: 102 | Bob Lund (Cable Laboratories), 103 | Cameron McCormack (Invited Expert / Mozilla), 104 | Daniel Danilatos (Google), 105 | Gary Kacmarcik (Google), 106 | Glenn Adams (Samsung), 107 | Hallvord R. M. Steen (Opera), 108 | Hironori Bono (Google), 109 | Mark Vickers (Comcast), 110 | Masayuki Nakano (Mozilla), 111 | Olli Pettay (Mozilla), 112 | Takayoshi Kochi (Google) and 113 | Travis Leithead (Microsoft). 114 | 115 | Glossary contributors: 116 | Arnaud Le Hors (W3C) and 117 | Robert S. Sutor (IBM Research). 118 | 119 | Test suite contributors: 120 | Carmelo Montanez (NIST), 121 | Fred Drake, 122 | Mary Brady (NIST), 123 | Neil Delima (IBM), 124 | Rick Rivello (NIST), 125 | Robert Clary (Netscape), 126 | with a special mention to Curt Arnold. 127 | 128 | Thanks to all those who have helped to improve this specification by 129 | sending suggestions and corrections (please, keep bugging us with your 130 | issues!), or writing informative books or Web sites: 131 | Al Gilman, 132 | Alex Russell, 133 | Alexander J. Vincent, 134 | Alexey Proskuryakov, 135 | Arkadiusz Michalski, 136 | Brad Pettit, 137 | Cameron McCormack, 138 | Chris Rebert, 139 | Curt Arnold, 140 | David Flanagan, 141 | Dylan Schiemann, 142 | Erik Arvidsson, 143 | Garrett Smith, 144 | Giuseppe Pascale, 145 | James Su, 146 | Jan Goyvaerts (regular-expressions.info), 147 | Jorge Chamorro, 148 | Kazuyuki Ashimura, 149 | Ken Rehor, 150 | Magnus Kristiansen, 151 | Martijn Wargers, 152 | Martin Dürst, 153 | Michael B. Allen, 154 | Mike Taylor, 155 | Misha Wolf, 156 | Ojan Vafai, 157 | Oliver Hunt, 158 | Paul Irish, 159 | Peter-Paul Koch, 160 | Richard Ishida, 161 | Sean Hogan, 162 | Sergey Ilinsky, 163 | Sigurd Lerstad, 164 | Steven Pemberton, 165 | Tony Chang, 166 | William Edney and 167 | Øistein E. Andersen. 168 | 169 |
170 | -------------------------------------------------------------------------------- /sections/conventions.txt: -------------------------------------------------------------------------------- 1 |
2 |

Stylistic Conventions

3 | 4 | 5 | This specification follows the 6 | Proposed W3C Specification Conventions, 7 | with the following supplemental additions: 8 | 9 | * The key cap printed on a key is shown as 10 | KEYCAP{↓}, KEYCAP{=} or KEYCAP{Q}. This is used to refer to a 11 | key from the user's perspective without regard for the 12 | {{KeyboardEvent/key}} and {{KeyboardEvent/code}} values in the 13 | generated {{KeyboardEvent}}. 14 | 15 | * Glyphs representing character are shown as: GLYPH{𣧂}. 16 | 17 | * Unicode character encodings are shown as: UNI{U+003d}. 18 | 19 | * Names of key values generated by a key press (i.e., the value of 20 | {{KeyboardEvent}}.{{KeyboardEvent/key}}) are shown as: 21 | KEY{ArrowDown}, KEY_NOLINK{=}, KEY_NOLINK{q} or KEY_NOLINK{Q}. 22 | 23 | * Names of key codes associated with the physical keys (i.e., the 24 | value of {{KeyboardEvent}}.{{KeyboardEvent/code}}) are shown as: 25 | CODE{ArrowDown}, CODE{Equal} or CODE{KeyQ}. 26 | 27 | 28 | In addition, certain terms are used in this specification with particular 29 | meanings. The term implementation applies to a browser, content 30 | authoring tool, or other user agent that implements this specification, 31 | while a content author is a person who writes script or code that takes 32 | advantage of the interfaces, methods, attributes, events, and other features 33 | described in this specification in order to make Web applications, and a user is 34 | the person who uses those Web applications in an implementation. 35 | 36 | And finally: 37 | 38 |

This is a note.

39 | 40 | 41 | 42 |

This is an open issue.

43 | 44 |

This is a warning.

45 | 46 |
47 |   interface Example {
48 |       // This is an IDL definition.
49 |   };
50 | 
51 | 52 |
53 | -------------------------------------------------------------------------------- /sections/event-inputevent.txt: -------------------------------------------------------------------------------- 1 |
2 |

Input Events

3 | 4 | Input events are sent as notifications whenever the DOM is being updated (or about 5 | to be updated) as a direct result of a user action (e.g., keyboard input in an editable 6 | region, deleting or formatting text, ...). 7 | 8 |

Interface InputEvent

9 | 10 |
InputEvent
11 | 12 |

Introduced in DOM Level 3

13 | 14 |
 15 | 			[Exposed=Window]
 16 | 			interface InputEvent : UIEvent {
 17 | 				constructor(DOMString type, optional InputEventInit eventInitDict = {});
 18 | 				readonly attribute USVString? data;
 19 | 				readonly attribute boolean isComposing;
 20 | 				readonly attribute DOMString inputType;
 21 | 			};
 22 | 			
23 | 24 |
25 |
data
26 |
27 | data holds the value of the characters generated by 28 | an input method. This MAY be a single Unicode character or a 29 | non-empty sequence of Unicode characters [[Unicode]]. Characters 30 | SHOULD be normalized as defined by the Unicode normalization 31 | form NFC, defined in [[UAX15]]. 32 | This attribute MAY contain the empty string. 33 | 34 | The un-initialized value of this attribute MUST be 35 | null. 36 |
37 | 38 |
isComposing
39 |
40 | true if the input event occurs as part of a 41 | composition session, i.e., after a EVENT{compositionstart} event 42 | and before the corresponding EVENT{compositionend} event. 43 | 44 | The un-initialized value of this attribute MUST be 45 | false. 46 |
47 | 48 |
inputType
49 |
50 | inputType contains a string that identifies the type 51 | of input associated with the event. 52 | 53 | For a list of valid values for this attribute, refer to the 54 | [[Input-Events]] specification. 55 | 56 | The un-initialized value of this attribute MUST be 57 | the empty string "". 58 |
59 |
60 | 61 |
InputEventInit
62 | 63 |
 64 | 			dictionary InputEventInit : UIEventInit {
 65 | 				DOMString? data = null;
 66 | 				boolean isComposing = false;
 67 | 				DOMString inputType = "";
 68 | 			};
 69 | 			
70 | 71 |
72 |
data
73 |
74 | Initializes the data attribute of the InputEvent object. 75 |
76 | 77 |
isComposing
78 |
79 | Initializes the isComposing attribute of the InputEvent object. 80 |
81 | 82 |
inputType
83 |
84 | Initializes the inputType attribute of the InputEvent object. 85 |
86 |
87 | 88 |

Input Event Order

89 | 90 | The input events defined in this specification MUST occur in a set order 91 | relative to one another. 92 | 93 | ++---+-------------+---------------------------------------------------+ 94 | =| # | Event Type | Notes | 95 | +---+-------------+---------------------------------------------------+ 96 | +| 1 | beforeinput | | 97 | +| | | DOM element is updated | 98 | +| 2 | input | | 99 | ++---+-------------+---------------------------------------------------+ 100 | 101 |

Input Event Types

102 | 103 |
beforeinput
104 | 105 | ++------------------+--------------------------------------------------------------------------------------+ event-definition 106 | =| % | | 107 | +------------------+--------------------------------------------------------------------------------------+ 108 | +| Type | beforeinput | 109 | +| Interface | {{InputEvent}} | 110 | +| Sync / Async | Sync | 111 | +| Bubbles | Yes | 112 | +| Trusted Targets | Element (specifically: control types such as | 113 | | | HTMLInputElement, etc.) or any Element with | 114 | | | contenteditable attribute enabled | 115 | +| Cancelable | Yes | 116 | +| Composed | Yes | 117 | +| Default action | Update the DOM element | 118 | +| Context
|
    | 119 | | (trusted events) |
  • {{Event}}.{{Event/target}} : event target that is about to be updated
  • | 120 | | |
  • {{UIEvent}}.{{UIEvent/view}} : Window
  • | 121 | | |
  • {{UIEvent}}.{{UIEvent/detail}} : 0
  • | 122 | | |
  • {{InputEvent}}.{{InputEvent/data}} : the string containing the data that will | 123 | | | be added to the element, which MAY be null if the content will | 124 | | | be deleted
  • | 125 | | |
  • {{InputEvent}}.{{InputEvent/isComposing}} : true if this event is | 126 | | | dispatched during a dead key sequence or while an | 127 | | | input method editor is active (such that | 128 | | | composition events are being dispatched);| 129 | | | false otherwise.
  • | 130 | | |
| 131 | ++------------------+--------------------------------------------------------------------------------------+ 132 | 133 | A user agent MUST dispatch this event when the DOM is about 134 | to be updated. 135 | 136 |
input
137 | 138 | ++------------------+--------------------------------------------------------------------------------------+ event-definition 139 | =| % | | 140 | +------------------+--------------------------------------------------------------------------------------+ 141 | +| Type | input | 142 | +| Interface | {{InputEvent}} | 143 | +| Sync / Async | Sync | 144 | +| Bubbles | Yes | 145 | +| Trusted Targets | Element (specifically: control types such as | 146 | | | HTMLInputElement, etc.) or any Element with | 147 | | | contenteditable attribute enabled | 148 | +| Cancelable | No | 149 | +| Composed | Yes | 150 | +| Default action | None | 151 | +| Context
|
    | 152 | | (trusted events) |
  • {{Event}}.{{Event/target}} : event target that was just updated
  • | 153 | | |
  • {{UIEvent}}.{{UIEvent/view}} : Window
  • | 154 | | |
  • {{UIEvent}}.{{UIEvent/detail}} : 0
  • | 155 | | |
  • {{InputEvent}}.{{InputEvent/data}} : the string containing the data that has | 156 | | | been added to the element, which MAY be the empty string if the content | 157 | | | has been deleted
  • | 158 | | |
  • {{InputEvent}}.{{InputEvent/isComposing}} : true if this event is | 159 | | | dispatched during a dead key sequence or while an | 160 | | | input method editor is active (such that | 161 | | | composition events are being dispatched);| 162 | | | false otherwise.
  • | 163 | | |
| 164 | ++------------------+--------------------------------------------------------------------------------------+ 165 | 166 | A user agent MUST dispatch this event immediately after the 167 | DOM has been updated. 168 | 169 | 170 |
171 | -------------------------------------------------------------------------------- /sections/extending-events.txt: -------------------------------------------------------------------------------- 1 |
2 |

Extending Events

3 | 4 | 5 | This section is non-normative 6 | 7 |

Introduction

8 | 9 | This specification defines several interfaces and many events, however, this 10 | is not an exhaustive set of events for all purposes. To allow content 11 | authors and implementers to add desired functionality, this specification 12 | provides two mechanisms for extend this set of interfaces and events without 13 | creating conflicts: custom 14 | events and implementation-specific 16 | extensions. 17 | 18 |

Custom Events

19 | 20 | A script author MAY wish to define an application in terms of functional 21 | components, with event types that are meaningful to the application 22 | architecture. The content author can use the {{CustomEvent}} interface to 23 | create their own events appropriate to the level of abstraction they are 24 | using. 25 | 26 |
27 | A content author might have created an application which features a 28 | dynamically generated bar chart. This bar chart is meant to be updated every 29 | 5 minutes, or when a feed shows new information, or when the user refreshes 30 | it manually by clicking a button. There are several handlers that have to be 31 | called when the chart needs to be updated: the application has to fetch the 32 | most recent data, show an icon to the user that the event is being updated, 33 | and rebuild the chart. To manage this, the content author can choose to 34 | create a custom updateChart event, which is fired whenever one of the 35 | trigger conditions is met: 36 | 37 |

 38 | 		var chartData = ...;
 39 | 		var evt = document.createEvent("CustomEvent");
 40 | 		evt.initCustomEvent( "updateChart", true, false, { data: chartData });
 41 | 		document.documentElement.dispatchEvent(evt);
 42 | 		
43 |
44 | 45 |

Implementation-Specific Extensions

46 | 47 | While a new event is being designed and prototyped, or when an event is 48 | intended for implementation-specific functionality, it is desirable to 49 | distinguish it from standardized events. Implementors SHOULD prefix event 50 | types specific to their implementations with a short string to distinguish 51 | it from the same event in other implementations and from standardized 52 | events. This is similar to the 53 | vendor-specific keyword prefixes 54 | in CSS, though without the dashes ("-") used in CSS, since that 55 | can cause problems when used as an attribute name in Javascript. 56 | 57 |
58 | A particular browser vendor, FooCorp, might wish to introduce a 59 | new event, jump. This vendor implements 60 | fooJump in their browser, using their 61 | vendor-specific prefix: "foo". Early adopters start 62 | experimenting with the event, using 63 | someElement.addEventListener("fooJump", doJump, false ), 64 | and provide feedback to FooCorp, who change the behavior of fooJump accordingly. 66 | 67 | After some time, another vendor, BarOrg, decides they also want 68 | the functionality, but implement it slightly differently, so they use 69 | their own vendor-specific prefix, "bar" in their event type 70 | name: barJump. Content authors 71 | experimenting with this version of the jump event type register events with BarOrg's 73 | event type name. Content authors who wish to write code that accounts 74 | for both browsers can either register each event type separately with 75 | specific handlers, or use the same handler and switch on the name of the 76 | event type. Thus, early experiments in different codebases do not 77 | conflict, and the early adopter is able to write easily-maintained code 78 | for multiple implementations. 79 | 80 | Eventually, as the feature matures, the behavior of both browsers 81 | stabilizes and might converge due to content author and user feedback or 82 | through formal standardization. As this stabilization occurs, and risk 83 | of conflicts decrease, content authors can remove the forked code, and 84 | use the jump event type name (even before 85 | it is formally standardized) using the same event handler and the more 86 | generic registration method someElement.addEventListener( "jump", 87 | doJump, false). 88 |
89 | 90 |

Known Implementation-Specific Prefixes

91 | 92 | At the time of writing, the following event-type name prefixes are known to exist: 93 | 94 | ++---------------------+------------+-----------------------+ 95 | =| Prefix | Web Engine | Organization | 96 | +---------------------+------------+-----------------------+ 97 | +| moz, | Gecko | Mozilla | 98 | | Moz | | | 99 | +| ms, | Trident | Microsoft | 100 | | MS | | | 101 | +| o, | Presto | Opera Software | 102 | | O | | | 103 | +| webkit | WebKit | Apple, Google, others | 104 | ++---------------------+------------+-----------------------+ 105 | 106 |
107 | -------------------------------------------------------------------------------- /sections/external-algorithms.txt: -------------------------------------------------------------------------------- 1 |
2 |

External Algorithms

3 | 4 | This sections contains algorithms that are required by this specification, but are 5 | more properly hosted by other specifications. 6 | 7 | The intent is that this sections serve as a temporary home for these definitions, 8 | and they should eventually be moved into a more appropriate home so this entire 9 | section can be deleted. 10 | 11 |

Core DOM Algorithms

12 | 13 |

14 | The following algorithms should be moved... somewhere. 15 |

16 | 17 |
18 |

hit test

19 | 20 | : Input 21 | :: |pos|, the x,y coordinates relative to the viewport 22 | 23 | : Output 24 | :: The frontmost DOM element at |pos| 25 | 26 |

27 | To account for 28 | inert or 29 | disabled 30 | elements. this should call elementsFromPoint and reject 31 | invalid elements 32 |

33 | 34 | 1. Return [[CSSOM-View]]'s elementFromPoint with |pos| 35 | 36 |
37 | 38 |
39 |

calculate DOM path

40 | 41 | : Input 42 | :: |element|, the starting element 43 | 44 | : Output 45 | :: The list of ancestor elements for the given element 46 | 47 | 1. Let |path| = A list that contains |element| 48 | 49 |

50 | This needs a proper definition to add ancestors to |path|. 51 |

52 | 53 | 1. Return |path| 54 | 55 |
56 | 57 |

PointerLock Algorithms

58 | 59 |

60 | The following algorithm should be moved into the [[PointerLock]] spec. 61 |

62 | 63 |

Global State for PointerLock

64 | 65 |
Window-Level State
66 | 67 | The UA must maintain the following values that are shared for the Window. 68 | 69 | A last mouse move value (initially undefined) that records the position of the 70 | last mousemove event. 71 | 72 |
73 |

initialize PointerLock attributes for MouseEvent

74 | 75 | : Input 76 | :: |event|, a {{MouseEvent}} 77 | 78 | : Output 79 | :: None 80 | 81 | 1. Set |event|.{{MouseEvent/movementX}} = 0 82 | 1. Set |event|.{{MouseEvent/movementY}} = 0 83 | 84 |
85 | 86 |
87 |

set PointerLock attributes for mousemove

88 | 89 | : Input 90 | :: |event|, a {{MouseEvent}} 91 | 92 | : Output 93 | :: None 94 | 95 | 1. If |event|.{{Event/type}} is not "mousemove", then exit 96 | 97 | 1. If last mouse move is not defined, then 98 | 1. Set |event|.{{MouseEvent/movementX}} = 0 99 | 1. Set |event|.{{MouseEvent/movementY}} = 0 100 | 1. Otherwise, 101 | 1. Set |event|.{{MouseEvent/movementX}} = |event|.{{MouseEvent/screenX}} - last mouse move's x-coordinate 102 | 1. Set |event|.{{MouseEvent/movementY}} = |event|.{{MouseEvent/screenX}} - last mouse move's y-coordinate 103 | 104 | 1. Set last mouse move = ( |event|.{{MouseEvent/screenX}}, |event|.{{MouseEvent/screenY}} ) 105 | 106 |
107 | 108 |

PointerEvent Algorithms

109 | 110 |

111 | The following algorithms should be moved into the [[PointerEvents3]] spec. 112 |

113 | 114 |
115 |

initialize a PointerEvent

116 | 117 | : Input 118 | :: |event|, the {{PointerEvent}} to initialize 119 | :: |eventType|, a DOMString containing the event type 120 | :: |eventTarget|, the {{EventTarget}} of the event 121 | 122 | : Output 123 | :: None 124 | 125 | 1. Initialize a MouseEvent with |event|, |eventType| and |eventTarget| 126 | 127 |

128 | TODO - initialize the pointerevent attributes 129 |

130 | 131 |
132 | 133 |
134 |

create a PointerEvent

135 | 136 | : Input 137 | :: |eventType|, a DOMString containing the event type 138 | :: |eventTarget|, the {{EventTarget}} of the event 139 | 140 | : Output 141 | :: None 142 | 143 | 1. Let |event| = the result of 144 | creating a new event using {{PointerEvent}} 145 | 1. Initialize a PointerEvent with |event|, |eventType| and |eventTarget| 146 | 1. Return |event| 147 | 148 |
149 | 150 |
151 |

create PointerEvent from MouseEvent

152 | 153 | : Input 154 | :: |eventType|, a DOMString containing the event type 155 | :: |mouseevent|, the corresponding {{MouseEvent}} 156 | 157 | : Output 158 | :: None 159 | 160 | 1. Let |event| = the result of 161 | creating a new event using {{PointerEvent}} 162 | 163 | 1. Let |target| = |mouseevent|.{{target}} 164 | 165 | 1. Initialize a PointerEvent with |event|, |eventType| and |target| 166 | 167 | 1. Copy MouseEvent attributes from |mouseevent| into |event| 168 | 169 | 1. Return |event| 170 | 171 |
172 | 173 |
174 |

maybe send pointerout event

175 | 176 | : Input 177 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 178 | 179 | : Output 180 | :: None 181 | 182 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 183 | 184 | 1. Set pointerevent attributes 185 | 186 |

187 | TODO 188 |

189 | 190 | 1. Let |target| = |mouseout|.{{target}} 191 | 1. dispatch |pointerout| at |target| 192 | 193 |
194 | 195 |
196 |

maybe send pointerleave event

197 | 198 | : Input 199 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 200 | 201 | : Output 202 | :: None 203 | 204 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 205 | 206 | 1. Set pointerevent attributes 207 | 208 |

209 | TODO 210 |

211 | 212 | 1. Let |target| = |mouseout|.{{target}} 213 | 1. dispatch |pointerout| at |target| 214 | 215 |
216 | 217 |
218 |

maybe send pointerover event

219 | 220 | : Input 221 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 222 | 223 | : Output 224 | :: None 225 | 226 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 227 | 228 | 1. Set pointerevent attributes 229 | 230 |

231 | TODO 232 |

233 | 234 | 1. Let |target| = |mouseout|.{{target}} 235 | 1. dispatch |pointerout| at |target| 236 | 237 |
238 | 239 |
240 |

maybe send pointerenter event

241 | 242 | : Input 243 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 244 | 245 | : Output 246 | :: None 247 | 248 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 249 | 250 | 1. Set pointerevent attributes 251 | 252 |

253 | TODO 254 |

255 | 256 | 1. Let |target| = |mouseout|.{{target}} 257 | 1. dispatch |pointerout| at |target| 258 | 259 |
260 | 261 |
262 |

maybe send pointermove event

263 | 264 | : Input 265 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 266 | 267 | : Output 268 | :: None 269 | 270 |

271 | Can this send pointermove and pointerrawupdate? Or do we need 2 methods? 272 |

273 | 274 |

275 | What is needed to properly define how pointermove events are coalesced? 276 |

277 | 278 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 279 | 280 | 1. Set pointerevent attributes 281 | 282 |

283 | TODO 284 |

285 | 286 | 1. Let |target| = |mouseout|.{{target}} 287 | 1. dispatch |pointerout| at |target| 288 | 289 |
290 | 291 |
292 |

maybe send pointerdown event

293 | 294 | : Input 295 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 296 | 297 | : Output 298 | :: None 299 | 300 |

301 | Unlike mousedown events, 302 | pointerdown 303 | events are not nested when multiple buttons are pressed. 304 | The MouseEvent is passed so that the fields can be copied into the PointerEvent. 305 |

306 | 307 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 308 | 309 | 1. Set pointerevent attributes 310 | 311 |

312 | TODO 313 |

314 | 315 | 1. Let |target| = |mouseout|.{{target}} 316 | 1. dispatch |pointerout| at |target| 317 | 318 |
319 | 320 |
321 |

maybe send pointerup event

322 | 323 | : Input 324 | :: |mouseout|, the corresponding mouseout {{MouseEvent}} 325 | 326 | : Output 327 | :: None 328 | 329 |

330 | Unlike mouseup events, 331 | pointerup 332 | events are not nested when multiple buttons are pressed. 333 | The MouseEvent is passed so that the fields can be copied into the PointerEvent. 334 |

335 | 336 | 1. Let |pointerout| = create PointerEvent from MouseEvent with "pointerout" and |mouseout| 337 | 338 | 1. Set pointerevent attributes 339 | 340 |

341 | TODO 342 |

343 | 344 | 1. Let |target| = |mouseout|.{{target}} 345 | 1. dispatch |pointerout| at |target| 346 | 347 |
348 | 349 |
350 | -------------------------------------------------------------------------------- /sections/glossary.txt: -------------------------------------------------------------------------------- 1 |
2 |

Glossary

3 | 4 | Some of the following term definitions have been borrowed or modified from 5 | similar definitions in other W3C or standards documents. See the links within 6 | the definitions for more information. 7 | 8 | 9 | : activation trigger 10 | :: An event which is defined to initiate an activation behavior. 11 | 12 | : author 13 | :: In the context of this specification, an author, content 14 | author, or script author is a person who writes script or 15 | other executable content that uses the interfaces, events, and event flow 16 | defined in this specification. See [[#conf-authors]] conformance category 17 | for more details. 18 | 19 | : body element 20 | :: In HTML or XHTML documents, the body element represents the contents of the 21 | document. In a well-formed HTML document, the body element is a first 22 | descendant of the root element. 23 | 24 | : character value 25 | :: In the context of key values, a character value is a string representing one 26 | or more Unicode characters, such as a letter or symbol, or a set of letters, each 27 | belonging to the set of valid Unicode character categories. 28 | In this specification, character values are denoted as a unicode string 29 | (e.g., UNI{U+0020}) or a glyph representation of the same code point (e.g., 30 | GLYPH{ }), and are color coded to help distinguish these two representations. 31 | 32 |

33 | In source code, some key values, such as non-graphic characters, can be 34 | represented using the character escape syntax of the programming language in 35 | use. 36 |

37 | 38 | : dead key 39 | :: A dead key is a key or combination of keys which produces no character by 40 | itself, but which in combination or sequence with another key produces a 41 | modified character, such as a character with diacritical marks (e.g., 42 | GLYPH{ö}, GLYPH{é}, GLYPH{â}). 43 | 44 | : default action 45 | :: A default action is an OPTIONAL supplementary behavior that an 46 | implementation MUST perform in combination with the dispatch of the event 47 | object. Each event type definition, and each specification, defines the 48 | default action for that event type, if it has one. An instance of an 49 | event MAY have more than one default action under some circumstances, 50 | such as when associated with an activation trigger. A default 51 | action MAY be cancelled through the invocation of the 52 | {{Event/preventDefault()}} method. 53 | 54 | : delta 55 | :: The estimated scroll amount (in pixels, lines, or pages) that the user agent 56 | will scroll or zoom the page in response to the physical movement of an 57 | input device that supports the {{WheelEvent}} interface (such as a mouse 58 | wheel or touch pad). The value of a delta (e.g., the 59 | {{WheelEvent/deltaX}}, {{WheelEvent/deltaY}}, or {{WheelEvent/deltaZ}} 60 | attributes) is to be interpreted in the context of the current 61 | {{WheelEvent/deltaMode}} property. The relationship between the physical 62 | movement of a wheel (or other device) and whether the delta is 63 | positive or negative is environment and device dependent. However, if a user 64 | agent scrolls as the default action then the sign of the delta 65 | is given by a right-hand coordinate system where positive X,Y, and Z axes 66 | are directed towards the right-most edge, bottom-most edge, and farthest 67 | depth (away from the user) of the document, respectively. 68 | 69 | : deprecated 70 | :: Features marked as deprecated are included in the specification as reference 71 | to older implementations or specifications, but are OPTIONAL and 72 | discouraged. Only features which have existing or in-progress replacements 73 | MUST be deprecated in this specification. Implementations which do not 74 | already include support for the feature MAY implement deprecated features 75 | for reasons of backwards compatibility with existing content, but content 76 | authors creating content SHOULD NOT use deprecated features, unless there is 77 | no other way to solve a use case. Other specifications which reference this 78 | specification SHOULD NOT use deprecated features, but SHOULD point instead 79 | to the replacements of which the feature is deprecated in favor. Features 80 | marked as deprecated in this specification are expected to be dropped from 81 | future specifications. 82 | 83 | : empty string 84 | :: The empty string is a value of type DOMString of length 85 | 0, i.e., a string which contains no characters (neither 86 | printing nor control characters). 87 | 88 | : event focus 89 | :: Event focus is a special state of receptivity and concentration on a 90 | particular element or other event target within a document. Each 91 | element has different behavior when focused, depending on its functionality, 92 | such as priming the element for activation (as for a button or hyperlink) or 93 | toggling state (as for a checkbox), receiving text input (as for a text form 94 | field), or copying selected text. For more details, see 95 | [[#events-focusevent-doc-focus]]. 96 | 97 | : event focus ring 98 | :: An event focus ring is an ordered set of event focus targets within a 99 | document. A host language MAY define one or more ways to determine 100 | the order of targets, such as document order, a numerical index defined per 101 | focus target, explicit pointers between focus targets, or a hybrid of 102 | different models. Each document MAY contain multiple focus rings, or 103 | conditional focus rings. Typically, for document-order or indexed focus 104 | rings, focus wraps around from the last focus target to the 105 | first. 106 | 107 | : event target 108 | :: The object to which an event is targeted using the event flow. 109 | The event target is the value of the {{Event/target}} attribute. 110 | 111 | : event type 112 | :: An event type is an event object with a particular name and 113 | which defines particular trigger conditions, properties, and other 114 | characteristics which distinguish it from other event types. For example, 115 | the EVENT{click} event type has different characteristics than the 116 | EVENT{mouseover} or EVENT{load} event types. The event type is exposed as 117 | the {{Event/type}} attribute on the event object. 118 | Also loosely referred to as "event", such as the 119 | EVENT{click} event. 120 | 121 | : host language 122 | :: Any language which integrates the features of another language or API 123 | specification, while normatively referencing the origin specification rather 124 | than redefining those features, and extending those features only in ways 125 | defined by the origin specification. An origin specification typically is 126 | only intended to be implemented in the context of one or more host 127 | languages, not as a standalone language. For example, XHTML, HTML, and SVG 128 | are host languages for UI Events, and they integrate and extend the objects 129 | and models defined in this specification. 130 | 131 | : hysteresis 132 | :: A feature of human interface design to accept input values within a certain 133 | range of location or time, in order to improve the user experience. For 134 | example, allowing for small deviation in the time it takes for a user to 135 | double-click a mouse button is temporal hysteresis, and not immediately 136 | closing a nested menu if the user mouses out from the parent window when 137 | transitioning to the child menu is locative hysteresis. 138 | 139 | : IME 140 | : input method editor 141 | :: An input method editor (IME), also known as a front end 142 | processor, is an application that performs the conversion between 143 | keystrokes and ideographs or other characters, usually by user-guided 144 | dictionary lookup, often used in East Asian languages (e.g., Chinese, 145 | Japanese, Korean). An IME MAY also be used for dictionary-based word 146 | completion, such as on mobile devices. See [[#keys-IME]] for treatment of 147 | IMEs in this specification. See also text composition system. 148 | 149 | : key mapping 150 | :: Key mapping is the process of assigning a key value to a particular key, and 151 | is the result of a combination of several factors, including the operating 152 | system and the keyboard layout (e.g., QWERTY, Dvorak, Spanish, 153 | InScript, Chinese, etc.), and after taking into account all modifier 154 | key (KEYCAP{Shift}, KEYCAP{Alt}, et al.) and dead key states. 155 | 156 | : key value 157 | :: A key value is a character value or multi-character string (such as 158 | KEY{Enter}, KEY{Tab}, or KEY{MediaTrackNext}) associated with a key in a 159 | particular state. Every key has a key value, whether or not it has a 160 | character value. This includes control keys, function keys, 161 | modifier keys, dead keys, and any other key. The key value of 162 | any given key at any given time depends upon the key mapping. 163 | 164 | : modifier key 165 | :: A modifier key changes the normal behavior of a key, such as to produce a 166 | character of a different case (as with the KEYCAP{Shift} key), or to alter 167 | what functionality the key triggers (as with the KEYCAP{Fn} or KEYCAP{Alt} 168 | keys). See [[#keys-modifiers]] for more information about modifier keys and 169 | refer to the [=Modifier Keys table=] in [[UIEvents-Key]] for a list 170 | of valid modifier keys. 171 | 172 | : namespace URI 173 | :: A namespace URI is a URI that identifies an XML namespace. This is 174 | called the namespace name in [[XML-Names11]]. See also sections 1.3.2 175 | DOM URIs 176 | and 1.3.3 177 | XML Namespaces 178 | regarding URIs and namespace URIs handling and comparison in the DOM APIs. 179 | 180 | : QWERTY 181 | :: QWERTY (pronounced ˈkwɜrti) is a common keyboard layout, 182 | so named because the first five character keys on the top row of letter keys 183 | are Q, W, E, R, T, and Y. There are many other popular keyboard layouts 184 | (including the Dvorak and Colemak layouts), most designed for localization 185 | or ergonomics. 186 | 187 | : root element 188 | :: The first element node of a document, of which all other elements are 189 | children. The document element. 190 | 191 | : rotation 192 | :: An indication of incremental change on an input device using the 193 | {{WheelEvent}} interface. On some devices this MAY be a literal rotation of 194 | a wheel, while on others, it MAY be movement along a flat surface, or 195 | pressure on a particular button. 196 | 197 | : text composition system 198 | :: A software component that interprets some form of alternate input (such as a 199 | input method editor, a speech processor, or a handwriting recognition 200 | system) and converts it to text. 201 | 202 | : topmost event target 203 | :: The topmost event target MUST be the element highest in the rendering 204 | order which is capable of being an event target. In graphical user 205 | interfaces this is the element under the user's pointing device. A user 206 | interface's hit testing facility is used to determine the target. For 207 | specific details regarding hit testing and stacking order, refer to the 208 | host language. 209 | 210 | : Unicode character categories 211 | :: A subset of the General Category values that are defined for each Unicode 212 | code point. This subset contains all the 213 | Letter (Ll, 214 | Lm, 215 | Lo, 216 | Lt, 217 | Lu), 218 | Number (Nd, 219 | Nl, 220 | No), 221 | Punctuation (Pc, 222 | Pd, 223 | Pe, 224 | Pf, 225 | Pi, 226 | Po, 227 | Ps) 228 | and Symbol (Sc, 229 | Sk, 230 | Sm, 231 | So) 232 | category values. 233 | 234 | : un-initialized value 235 | :: The value of any event attribute (such as {{Event/bubbles}} or 236 | {{Event/currentTarget}}) before the event has been initialized with 237 | {{Event/initEvent()}}. The un-initialized values of an event apply 238 | immediately after a new event has been created using the method 239 | {{Document/createEvent()}}. 240 | 241 |
242 | -------------------------------------------------------------------------------- /sections/introduction.txt: -------------------------------------------------------------------------------- 1 |
2 |

Introduction

3 | 4 | 5 |

Overview

6 | 7 | UI Events is designed with two main goals. The first goal is the design of 8 | an event system which allows registration of [=event listeners=] and 9 | describes event flow through a tree structure. Additionally, the 10 | specification will provide standard modules of events for user interface 11 | control and document mutation notifications, including defined contextual 12 | information for each of these event modules. 13 | 14 | The second goal of UI Events is to provide a common subset of the current 15 | event systems used in existing browsers. This is intended to foster 16 | interoperability of existing scripts and content. It is not expected that 17 | this goal will be met with full backwards compatibility. However, the 18 | specification attempts to achieve this when possible. 19 | 20 | 21 |

Conformance

22 | 23 | This section is normative. 24 | 25 | Within this specification, the key words MUST, MUST NOT, 26 | REQUIRED, SHALL, SHALL NOT, SHOULD, 27 | SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL 28 | are to be interpreted as described in [[!RFC2119]]. 29 | 30 | This specification is to be understood in the context of the DOM Level 3 31 | Core specification [[!DOM-Level-3-Core]] and the general considerations for DOM 32 | implementations apply. For example, handling of namespace URIs is 33 | discussed in 34 | XML Namespaces. 35 | For additional information about 36 | conformance, 37 | please see the DOM Level 3 Core specification [[DOM-Level-3-Core]]. A user 38 | agent is not required to conform to the entirety of another 39 | specification in order to conform to this specification, but it MUST conform 40 | to the specific parts of any other specification which are called out in 41 | this specification (e.g., a conforming UI Events user agent MUST 42 | support the DOMString data type as defined in [[WebIDL]], but 43 | need not support every method or data type defined in [[WebIDL]] in order 44 | to conform to UI Events). 45 | 46 | This specification defines several classes of conformance for different 47 | user agents, specifications, and content authors: 48 | 49 | 50 |

Web browsers and other dynamic or interactive user agents

51 | 52 | A dynamic or interactive user agent, referred to here as a 53 | browser (be it a Web browser, AT (Accessibility Technology) 54 | application, or other similar program), conforms to UI Events if it 55 | supports: 56 | 57 | * the Core module defined in [[DOM-Level-3-Core]] 58 | 59 | * all the interfaces and events with their associated methods, 60 | attributes, and semantics defined in this specification with the 61 | exception of those marked as deprecated (a conforming user 62 | agent MAY implement the deprecated interfaces, events, or APIs for 63 | backwards compatibility, but is not required to do so in order to be 64 | conforming) 65 | 66 | * the complete set of key and code 67 | values defined in [[UIEvents-Key]] and [[UIEvents-Code]] (subject to 68 | platform availability), and 69 | 70 | * all other normative requirements defined in this specification. 71 | 72 | A conforming browser MUST dispatch events appropriate to the 73 | given {{EventTarget}} when the conditions defined for that event 74 | type have been met. 75 | 76 | A browser conforms specifically to UI Events if it implements the 77 | interfaces and related event types specified in this document. 78 | 79 | A conforming browser MUST support scripting, declarative interactivity, 80 | or some other means of detecting and dispatching events in the manner 81 | described by this specification, and MUST support the APIs specified for 82 | that event type. 83 | 84 | In addition to meeting all other conformance criteria, a conforming 85 | browser MAY implement features of this specification marked as 86 | deprecated, for backwards compatibility with existing content, 87 | but such implementation is discouraged. 88 | 89 | A conforming browser MAY also support features not found in this 90 | specification, but which use the interfaces, 91 | events, or other features defined in this specification, and MAY 92 | implement additional interfaces and event types appropriate to 93 | that implementation. Such features can be later standardized in future 94 | specifications. 95 | 96 | A browser which does not conform to all required portions of this 97 | specification MUST NOT claim conformance to UI Events. Such an 98 | implementation which does conform to portions of this specification MAY 99 | claim conformance to those specific portions. 100 | 101 | A conforming browser MUST also be a conforming implementation of 102 | the IDL fragments in this specification, as described in the Web IDL 103 | specification [[WebIDL]]. 104 | 105 |

Authoring tools

106 | 107 | A content authoring tool conforms to UI Events if it produces content 108 | which uses the event types, consistent 109 | in a manner as defined in this specification. 110 | 111 | A content authoring tool MUST NOT claim conformance to UI Events for 112 | content it produces which uses features of this specification marked as 113 | deprecated in this specification. 114 | 115 | A conforming content authoring tool SHOULD provide to the content author 116 | a means to use all event types and interfaces appropriate to all 117 | host languages in the content document being produced. 118 | 119 |

Content authors and content

120 | 121 | A content author creates conforming UI Events content if that 122 | content uses the event types 123 | consistent in a manner as defined in this specification. 124 | 125 | A content author SHOULD NOT use features of this specification 126 | marked as deprecated, but SHOULD rely instead upon 127 | replacement mechanisms defined in this specification and elsewhere. 128 | 129 | Conforming content MUST use the semantics of the interfaces and 130 | event types as described in this specification. 131 | 132 |

133 | Content authors are advised to follow best practices as described in 134 | accessibility and 135 | internationalization 136 | guideline specifications. 137 |

138 | 139 |

Specifications and host languages

140 | 141 | A specification or host language conforms to UI Events if it 142 | references and uses the event flow mechanism, interfaces, events, 143 | or other features defined in [[!DOM]], and does not extend 144 | these features in incompatible ways. 145 | 146 | A specification or host language conforms specifically to UI 147 | Events if it references and uses the interfaces and related event 148 | types specified in this document. A conforming specification MAY 149 | define additional interfaces and event types appropriate to that 150 | specification, or MAY extend the UI Events interfaces and event 151 | types in a manner that does not contradict or conflict with the 152 | definitions of those interfaces and event types in this 153 | specification. 154 | 155 | Specifications or host languages which reference UI Events SHOULD 156 | NOT use or recommend features of this specification marked as 157 | deprecated, but SHOULD use or recommend the indicated replacement 158 | for that the feature (if available). 159 | 160 |
161 | -------------------------------------------------------------------------------- /sections/legacy-event-initializers.txt: -------------------------------------------------------------------------------- 1 |
2 |

Legacy Event Initializers

3 | 4 | This section is normative. 5 | The following features are obsolete and should only be implemented by 6 | user agents that require compatibility with legacy software. 7 | 8 | Early versions of this specification included an initialization method on 9 | the interface (for example initMouseEvent) that required a long 10 | list of parameters that, in most cases, did not fully initialize all 11 | attributes of the event object. Because of this, event interfaces which were 12 | derived from the basic {{Event}} interface required that the initializer of 13 | each of the derived interfaces be called explicitly in order to 14 | fully initialize an event. 15 | 16 |
17 | Initializing all the attributes of a UIEvent requires calls to two 18 | initializer methods: initEvent and 19 | initUIEvent. 20 |
21 | 22 | Due in part to the length of time in the development of this standard, some 23 | implementations MAY have taken a dependency on these (now deprecated) 24 | initializer methods. For completeness, these legacy event initializers are 25 | described in this Appendix. 26 | 27 |

Legacy Event Initializer Interfaces

28 | 29 | This section is informative 30 | 31 | This section documents legacy initializer methods that were introduced 32 | in earlier versions of this specification. 33 | 34 |

Initializers for interface UIEvent

35 | 36 |
 37 | 		partial interface UIEvent {
 38 | 			// Deprecated in this specification
 39 | 			undefined initUIEvent(DOMString typeArg,
 40 | 				optional boolean bubblesArg = false,
 41 | 				optional boolean cancelableArg = false,
 42 | 				optional Window? viewArg = null,
 43 | 				optional long detailArg = 0);
 44 | 		};
 45 | 		
46 | 47 |
48 |
initUIEvent(typeArg)
49 |
50 | Initializes attributes of an {{UIEvent}} object. 51 | This method has the same behavior as {{Event/initEvent()}}. 52 | 53 |

54 | The initUIEvent method is deprecated, but 55 | supported for backwards-compatibility with widely-deployed 56 | implementations. 57 |

58 | 59 |
60 |
DOMString typeArg
61 |
62 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 63 |
64 | 65 |
boolean bubblesArg
66 |
67 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 68 |
69 | 70 |
boolean cancelableArg
71 |
72 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 73 |
74 | 75 |
Window? viewArg
76 |
77 | Specifies {{UIEvent/view}}. This value MAY be null. 78 |
79 | 80 |
long detailArg
81 |
82 | Specifies {{UIEvent/detail}}. 83 |
84 |
85 |
86 |
87 | 88 |

Initializers for interface MouseEvent

89 | 90 |
 91 | 		partial interface MouseEvent {
 92 | 			// Deprecated in this specification
 93 | 			undefined initMouseEvent(DOMString typeArg,
 94 | 				optional boolean bubblesArg = false,
 95 | 				optional boolean cancelableArg = false,
 96 | 				optional Window? viewArg = null,
 97 | 				optional long detailArg = 0,
 98 | 				optional long screenXArg = 0,
 99 | 				optional long screenYArg = 0,
100 | 				optional long clientXArg = 0,
101 | 				optional long clientYArg = 0,
102 | 				optional boolean ctrlKeyArg = false,
103 | 				optional boolean altKeyArg = false,
104 | 				optional boolean shiftKeyArg = false,
105 | 				optional boolean metaKeyArg = false,
106 | 				optional short buttonArg = 0,
107 | 				optional EventTarget? relatedTargetArg = null);
108 | 		};
109 | 		
110 | 111 |
112 |
initMouseEvent(typeArg)
113 |
114 | Initializes attributes of a {{MouseEvent}} object. This 115 | method has the same behavior as UIEvent.initUIEvent(). 116 | 117 |

118 | The initMouseEvent method is deprecated, but 119 | supported for backwards-compatibility with widely-deployed 120 | implementations. 121 |

122 | 123 |
124 |
DOMString typeArg
125 |
126 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 127 |
128 | 129 |
boolean bubblesArg
130 |
131 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 132 |
133 | 134 |
boolean cancelableArg
135 |
136 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 137 |
138 | 139 |
Window? viewArg
140 |
141 | Specifies {{UIEvent/view}}. This value MAY be null. 142 |
143 | 144 |
long detailArg
145 |
146 | Specifies {{UIEvent/detail}}. 147 |
148 | 149 |
long screenXArg
150 |
151 | Specifies {{MouseEvent/screenX}}. 152 |
153 | 154 |
long screenYArg
155 |
156 | Specifies {{MouseEvent/screenY}}. 157 |
158 | 159 |
long clientXArg
160 |
161 | Specifies {{MouseEvent/clientX}}. 162 |
163 | 164 |
long clientYArg
165 |
166 | Specifies {{MouseEvent/clientY}}. 167 |
168 | 169 |
boolean ctrlKeyArg
170 |
171 | Specifies {{MouseEvent/ctrlKey}}. 172 |
173 | 174 |
boolean altKeyArg
175 |
176 | Specifies {{MouseEvent/altKey}}. 177 |
178 | 179 |
boolean shiftKeyArg
180 |
181 | Specifies {{MouseEvent/shiftKey}}. 182 |
183 | 184 |
boolean metaKeyArg
185 |
186 | Specifies {{MouseEvent/metaKey}}. 187 |
188 | 189 |
short buttonArg
190 |
191 | Specifies {{MouseEvent/button}}. 192 |
193 | 194 |
EventTarget? relatedTargetArg
195 |
196 | Specifies {{MouseEvent/relatedTarget}}. This value MAY 197 | be null. 198 |
199 |
200 |
201 |
202 | 203 |

Initializers for interface KeyboardEvent

204 | 205 |

206 | The argument list to this legacy KeyboardEvent initializer does not 207 | include the detailArg (present in other initializers) and 208 | adds the locale argument; it is 209 | necessary to preserve this inconsistency for compatibility with existing 210 | implementations. 211 |

212 | 213 |
214 | 		partial interface KeyboardEvent {
215 | 			// Originally introduced (and deprecated) in this specification
216 | 			undefined initKeyboardEvent(DOMString typeArg,
217 | 				optional boolean bubblesArg = false,
218 | 				optional boolean cancelableArg = false,
219 | 				optional Window? viewArg = null,
220 | 				optional DOMString keyArg = "",
221 | 				optional unsigned long locationArg = 0,
222 | 				optional boolean ctrlKey = false,
223 | 				optional boolean altKey = false,
224 | 				optional boolean shiftKey = false,
225 | 				optional boolean metaKey = false);
226 | 		};
227 | 		
228 | 229 |
230 |
initKeyboardEvent(typeArg)
231 |
232 | Initializes attributes of a {{KeyboardEvent}} object. This 233 | method has the same behavior as UIEvent.initUIEvent(). 234 | The value of {{UIEvent/detail}} remains undefined. 235 | 236 |

237 | The initKeyboardEvent method is deprecated. 238 |

239 | 240 |
241 |
DOMString typeArg
242 |
243 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 244 |
245 | 246 |
boolean bubblesArg
247 |
248 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 249 |
250 | 251 |
boolean cancelableArg
252 |
253 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 254 |
255 | 256 |
Window? viewArg
257 |
258 | Specifies {{UIEvent/view}}. This value MAY be null. 259 |
260 | 261 |
DOMString keyArg
262 |
263 | Specifies {{KeyboardEvent/key}}. 264 |
265 | 266 |
unsigned long locationArg
267 |
268 | Specifies {{KeyboardEvent/location}}. 269 |
270 | 271 |
boolean ctrlKey
272 |
273 | Specifies whether the Control key modifier is active. 274 |
275 | 276 |
boolean altKey
277 |
278 | Specifies whether the Alt key modifier is active. 279 |
280 | 281 |
boolean shiftKey
282 |
283 | Specifies whether the Shift key modifier is active. 284 |
285 | 286 |
boolean metaKey
287 |
288 | Specifies whether the Meta key modifier is active. 289 |
290 |
291 |
292 |
293 | 294 |

Initializers for interface CompositionEvent

295 | 296 |

297 | The argument list to this legacy CompositionEvent initializer does not 298 | include the detailArg (present in other initializers) and 299 | adds the locale argument; it is 300 | necessary to preserve this inconsistency for compatibility with existing 301 | implementations. 302 |

303 | 304 |
305 | 		partial interface CompositionEvent {
306 | 			// Originally introduced (and deprecated) in this specification
307 | 			undefined initCompositionEvent(DOMString typeArg,
308 | 				optional boolean bubblesArg = false,
309 | 				optional boolean cancelableArg = false,
310 | 				optional WindowProxy? viewArg = null,
311 | 				optional DOMString dataArg = "");
312 | 		};
313 | 		
314 | 315 |
316 |
initCompositionEvent(typeArg)
317 |
318 | Initializes attributes of a CompositionEvent 319 | object. This method has the same behavior as 320 | UIEvent.initUIEvent(). The value of {{UIEvent/detail}} 321 | remains undefined. 322 | 323 |

324 | The initCompositionEvent method is deprecated. 325 |

326 | 327 |
328 |
DOMString typeArg
329 |
330 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 331 |
332 | 333 |
boolean bubblesArg
334 |
335 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 336 |
337 | 338 |
boolean cancelableArg
339 |
340 | Refer to the {{Event/initEvent()}} method for a description of this parameter. 341 |
342 | 343 |
Window? viewArg
344 |
345 | Specifies {{UIEvent/view}}. This value MAY be null. 346 |
347 | 348 |
DOMString dataArg
349 |
350 | Specifies {{CompositionEvent/data}}. 351 |
352 |
353 |
354 |
355 | 356 |
357 | -------------------------------------------------------------------------------- /sections/security.txt: -------------------------------------------------------------------------------- 1 |
2 |

Security Considerations

3 | 4 | 5 | This appendix discusses security considerations for UI Events implementations. 6 | The discussion is limited to security issues that arise directly from 7 | implementation of the event model, APIs and events defined in this 8 | specification. Implementations typically support other features like scripting 9 | languages, other APIs and additional events not defined in this document. These 10 | features constitute an unknown factor and are out of scope of this document. 11 | Implementers SHOULD consult the specifications of such features for their 12 | respective security considerations. 13 | 14 | Many of the event types defined in this specification are dispatched in response 15 | to user actions. This allows malicious [=event listeners=] to gain access to 16 | information users would typically consider confidential, e.g., typos they might 17 | have made when filling out a form, if they reconsider their answer to a multiple 18 | choice question shortly before submitting a form, their typing rate or primary 19 | input mechanism. In the worst case, malicious [=event listeners=] could capture all 20 | user interactions and submit them to a third party through means (not defined in 21 | this specification) that are generally available in DOM implementations, such as 22 | the XMLHttpRequest interface. 23 | 24 | In DOM implementations that support facilities to load external data, events 25 | like the EVENT{error} event can provide access to sensitive information about 26 | the environment of the computer system or network. An example would be a 27 | malicious HTML document that attempts to embed a resource on the local network 28 | or the localhost on different ports. An embedded DOM application could 29 | then listen for EVENT{error} and EVENT{load} events to determine which other 30 | computers in a network are accessible from the local system or which ports are 31 | open on the system to prepare further attacks. 32 | 33 | An implementation of UI Events alone is generally insufficient to perform 34 | attacks of this kind and the security considerations of the facilities that 35 | possibly support such attacks apply. For conformance with this specification, 36 | DOM implementations MAY take reasonable steps to ensure that DOM 37 | applications do not get access to confidential or sensitive information. For 38 | example, they might choose not to dispatch EVENT{load} events to nodes that 39 | attempt to embed resources on the local network. 40 | 41 |
42 | -------------------------------------------------------------------------------- /stylesheet-extra.include: -------------------------------------------------------------------------------- 1 | 242 | -------------------------------------------------------------------------------- /tests/key-mtest-101en-us.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Keyboard Layout Manual Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /tests/key-mtest-102fr-fr.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Keyboard Layout Manual Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /tests/key-mtest.css: -------------------------------------------------------------------------------- 1 | .keyboard { 2 | display: table; 3 | border-collapse: separate; 4 | border-spacing: 2px; 5 | width: 800px; 6 | border: 2px solid black; 7 | border-radius: 10px; 8 | padding: 5px; 9 | } 10 | 11 | .key-row { 12 | display: table; 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | .key { 18 | display: table-cell; 19 | border: 2px solid black; 20 | border-radius: 8px; 21 | width: 50px; 22 | height: 40px; 23 | vertical-align: middle; 24 | text-align: center; 25 | margin: 0; 26 | padding: 0; 27 | } 28 | 29 | .wide1 { 30 | width: 70px; 31 | } 32 | 33 | .wide2 { 34 | width: 90px; 35 | } 36 | 37 | .wide3 { 38 | width: 110px; 39 | } 40 | 41 | .wide4 { 42 | width: 130px; 43 | } 44 | 45 | .wide5 { 46 | width: 300px; 47 | } 48 | 49 | .nextKey { 50 | background-color: yellow; 51 | } 52 | 53 | .goodKey { 54 | background-color: #80ff08; 55 | } 56 | 57 | .badKey { 58 | background-color: #ff8080; 59 | } 60 | 61 | .activeModifierKey { 62 | background-color: #a0a0ff; 63 | } 64 | 65 | .skippedKey { 66 | background-color: #e0e0e0; 67 | } 68 | 69 | #options { 70 | display: none; 71 | margin: 20px; 72 | } 73 | 74 | #optionstoggle, #helptoggle { 75 | font-size: 10pt; 76 | } 77 | 78 | .opttable { 79 | border: 1px solid black; 80 | } 81 | 82 | .optcell { 83 | vertical-align: top; 84 | padding: 0 10px; 85 | } 86 | 87 | .opttitle { 88 | font-weight: bold; 89 | } 90 | 91 | .opttext { 92 | font-style: italic; 93 | } 94 | 95 | .disabledtext { 96 | color: #808080; 97 | } 98 | 99 | .error { 100 | border: 1px solid red; 101 | margin: 5px; 102 | padding: 5px; 103 | } 104 | 105 | .error1 { 106 | font-size: 12pt; 107 | margin: 0 0 0 10px; 108 | padding: 0; 109 | } 110 | 111 | .error2 { 112 | font-size: 10pt; 113 | margin: 0 0 0 20px; 114 | padding: 0; 115 | } 116 | 117 | .help { 118 | font-size: 11pt; 119 | margin: 0 0 5px 20px; 120 | padding: 0; 121 | } 122 | 123 | .main_link { 124 | float: right; 125 | border: 1px solid black; 126 | border-radius: 4px; 127 | font-size: 9pt; 128 | padding: 2px 4px; 129 | text-decoration: none; 130 | background-color: #e0e0ff; 131 | } 132 | 133 | body { 134 | margin: 10px; 135 | padding: 0 20px; 136 | } 137 | -------------------------------------------------------------------------------- /tools/focus-event-viewer.css: -------------------------------------------------------------------------------- 1 | .subtitle { 2 | font-size: 12pt; 3 | font-style: italic; 4 | } 5 | 6 | #options { 7 | display: none; 8 | margin: 20px; 9 | } 10 | 11 | #optionstoggle { 12 | font-size: 10pt; 13 | } 14 | 15 | .opttable { 16 | border: 1px solid black; 17 | } 18 | 19 | .optcell { 20 | vertical-align: top; 21 | padding: 0 10px; 22 | } 23 | 24 | .opttitle { 25 | font-weight: bold; 26 | } 27 | 28 | .empty { 29 | background-color: #ffffff; 30 | } 31 | 32 | .subheader { 33 | font-size: 10pt; 34 | } 35 | 36 | .etype_header { 37 | background-color: #e0e0e0; 38 | font-weight: bold; 39 | border: 1px solid black; 40 | } 41 | 42 | .target_header { 43 | background-color: #ffc0ff; 44 | font-weight: bold; 45 | border: 1px solid black; 46 | } 47 | 48 | .focusevent_header { 49 | background-color: #c0ffff; 50 | font-weight: bold; 51 | border: 1px solid black; 52 | } 53 | 54 | .undef { 55 | color: #a0a0a0; 56 | } 57 | 58 | input[type=checkbox]:disabled+label { 59 | color: #a0a0a0; 60 | } 61 | 62 | .focusevent_hilight { 63 | border: 1px solid #404040; 64 | border-radius: 4px; 65 | padding: 0 3px 0 3px; 66 | margin-left: 3px; 67 | } 68 | 69 | .blur_hilight { 70 | background: #e0e0e0; 71 | } 72 | 73 | .focusin_hilight { 74 | background: #ccffcc; 75 | } 76 | 77 | .focusout_hilight { 78 | background-color: #c0c0ff; 79 | } 80 | 81 | .domfocusin_hilight { 82 | background-color: #c0ffc0; 83 | } 84 | 85 | .domfocusout_hilight { 86 | background-color: #c0ffc0; 87 | } 88 | 89 | .showfieldoption { 90 | font-weight: normal; 91 | padding: 0 5px 0 5px; 92 | display: inline-block; 93 | min-width: 90px; 94 | text-align: center; 95 | } 96 | 97 | #output tr:hover, tr.highlight { 98 | background-color: #e0e0e0; 99 | } 100 | 101 | .div_ce { 102 | border: 1px solid black; 103 | } 104 | 105 | .main_link { 106 | float: right; 107 | border: 1px solid black; 108 | border-radius: 4px; 109 | font-size: 9pt; 110 | padding: 2px 4px; 111 | text-decoration: none; 112 | background-color: #e0e0ff; 113 | } 114 | 115 | body { 116 | margin: 10px; 117 | padding: 0 20px; 118 | background-color: #ffffff; 119 | } 120 | 121 | /* Fix for black background in Fullscreen (Chrome). */ 122 | html { 123 | background-color: #ffffff; 124 | } 125 | 126 | *:fullscreen, *:-webkit-full-screen, *:-moz-full-screen, *:-ms-fullscreen { 127 | background-color: rgba(255,255,255,0); 128 | width: 100%; 129 | height: 100%; 130 | } 131 | -------------------------------------------------------------------------------- /tools/focus-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Focus Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | UI Events Testing Tools 18 | 19 |

Focus Event Viewer

20 | 21 |

UserAgent:

22 | 23 |

24 | A: 25 | B: 26 |

27 |

28 | 29 | Show Options 30 |

31 | 32 |
33 | 34 |
35 |
36 | 37 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /tools/focus-event-viewer.js: -------------------------------------------------------------------------------- 1 | // Keyboard event viewer 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | var _focus_table_info = [ 5 | // Unlabeled group 6 | ["", "etype", [ 7 | ["#", "etype", "text"], 8 | ["Event type", "etype", "html"], 9 | ], {'grouplabel': false}], 10 | 11 | // MouseEvent - Target 12 | ["Target", "target", [ 13 | ["A", "target", "text", {'style': 'hilite_div_a'}], 14 | ["B", "target", "text", {'style': 'hilite_div_b'}], 15 | ], {'checked': true}], 16 | 17 | // FocusEvent - relatedTarget 18 | ["FocusEvent", "focusevent", [ 19 | ["rA", "focusevent", "text", {'style': 'hilite_div_a'}], 20 | ["rB", "focusevent", "text", {'style': 'hilite_div_b'}], 21 | ], {'checked': true}], 22 | 23 | ]; 24 | 25 | var _focus_event_info = [ 26 | ["blur", { 27 | 'preventDefault': {'checked': false}, 28 | 'stopPropagation': {}, 29 | 'ShowEvents': {}, 30 | 'Highlight': {'checked': false, 'class': "focusevent_hilight blur_hilight"}, 31 | }, 32 | "#ffcccc"], 33 | ["focusin", { 34 | 'preventDefault': {'checked': false}, 35 | 'stopPropagation': {}, 36 | 'ShowEvents': {}, 37 | 'Highlight': {'checked': true, 'class': "focusevent_hilight focusin_hilight"}, 38 | }, 39 | "#e0e0e0"], 40 | ["focusout", { 41 | 'preventDefault': {'checked': false}, 42 | 'stopPropagation': {}, 43 | 'ShowEvents': {}, 44 | 'Highlight': {'checked': true, 'class': "focusevent_hilight focusout_hilight"}, 45 | }, 46 | "#ccffcc"], 47 | ["DOMFocusIn", { 48 | 'preventDefault': {'checked': false}, 49 | 'stopPropagation': {}, 50 | 'ShowEvents': {}, 51 | 'Highlight': {'checked': false, 'class': "focusevent_hilight domfocusin_hilight"}, 52 | }, 53 | "#ffffff"], 54 | ["DOMFocusOut", { 55 | 'preventDefault': {'checked': false}, 56 | 'stopPropagation': {}, 57 | 'ShowEvents': {}, 58 | 'Highlight': {'checked': false, 'class': "focusevent_hilight domfocusout_hilight"}, 59 | }, 60 | "repeating-linear-gradient(-45deg, #fcc, #fcc 8px, #fff 8px, #fff 16px)"], 61 | ]; 62 | 63 | 64 | function setUserAgentText() { 65 | var userAgent = navigator.userAgent; 66 | uaDiv = document.getElementById("useragent"); 67 | setText(uaDiv, userAgent); 68 | } 69 | 70 | function resetTable(resetData=true) { 71 | clearTable(); 72 | initOutputTable(_focus_table_info); 73 | 74 | //setInputFocus(resetData); 75 | } 76 | 77 | function init() { 78 | setUserAgentText(); 79 | 80 | createOptions(document.getElementById("options"), _focus_event_info, _focus_table_info, []); 81 | resetTable(false); 82 | 83 | var input_a = document.getElementById("input_a"); 84 | var input_b = document.getElementById("input_b"); 85 | for (var div of [input_a, input_b]) { 86 | console.log("addign focus handlers"); 87 | addEventListener(div, "blur", onBlur); 88 | addEventListener(div, "focusin", onFocusIn); 89 | addEventListener(div, "focusout", onFocusOut); 90 | addEventListener(div, "DOMFocusIn", onDomFocusIn); 91 | addEventListener(div, "DOMFocusOut", onDomFocusOut); 92 | } 93 | } 94 | 95 | // ===== 96 | // Focus events: blur, focusin, focusout 97 | // ===== 98 | 99 | function onBlur(e) { 100 | handleFocusEvent("blur", e); 101 | } 102 | 103 | function onFocusIn(e) { 104 | handleFocusEvent("focusin", e); 105 | } 106 | 107 | function onFocusOut(e) { 108 | handleFocusEvent("focusout", e); 109 | } 110 | 111 | function onDomFocusIn(e) { 112 | handleFocusEvent("DomFocusIn", e); 113 | } 114 | 115 | function onDomFocusOut(e) { 116 | handleFocusEvent("DOMFocusOut", e); 117 | } 118 | 119 | function handleFocusEvent(etype, e) { 120 | console.log(etype); 121 | var show = document.getElementById("show_" + etype); 122 | if (show.checked) { 123 | addFocusEvent(etype, e); 124 | } 125 | handleDefaultPropagation(etype, e); 126 | } 127 | 128 | function addFocusEvent(etype, e) { 129 | if (!e) { 130 | e = window.event; 131 | } 132 | var target = e.target.id; 133 | var relatedTarget = e.relatedTarget.id; 134 | var eventinfo = {}; 135 | eventinfo["Event type"] = calcHilightString(etype, e.type); 136 | eventinfo["A"] = (target == "input_a" ? "A" : ""); 137 | eventinfo["B"] = (target == "input_b" ? "B" : ""); 138 | eventinfo["rA"] = (relatedTarget == "input_a" ? "A" : ""); 139 | eventinfo["rB"] = (relatedTarget == "input_b" ? "B" : ""); 140 | 141 | addEventToOutput(eventinfo); 142 | } 143 | 144 | // ===== 145 | // Helper functions 146 | // ===== 147 | 148 | /* Set the focus to the input box. */ 149 | function setInputFocus(resetData) { 150 | var input = document.getElementById("input_a"); 151 | 152 | if (resetData) { 153 | input.value = ""; 154 | } 155 | 156 | // Set focus. 157 | input.focus(); 158 | } 159 | 160 | function calcHilightString(eventType, data) { 161 | if (data === undefined) { 162 | return null; 163 | } 164 | 165 | var keySpan = document.createElement("span"); 166 | var enableHilight = document.getElementById("hl_" + eventType); 167 | if (enableHilight && enableHilight.checked) { 168 | keySpan.classList.add("focusevent_hilight"); 169 | keySpan.classList.add(eventType + "_hilight"); 170 | } 171 | keySpan.textContent = data; 172 | return keySpan; 173 | } 174 | 175 | -------------------------------------------------------------------------------- /tools/key-event-viewer-ce.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Keyboard Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | UI Events Testing Tools 18 | 19 |

Keyboard Event Viewer for contenteditable

20 | 21 |

UserAgent:

22 | 23 |

div with contenteditable="true":

24 |
Initial text
25 | 26 |

27 | 28 | Show Options 29 |

30 | 31 |
32 | 33 | 34 |
35 | 36 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tools/key-event-viewer.css: -------------------------------------------------------------------------------- 1 | .subtitle { 2 | font-size: 12pt; 3 | font-style: italic; 4 | } 5 | 6 | #options { 7 | display: none; 8 | margin: 20px; 9 | } 10 | 11 | #optionstoggle { 12 | font-size: 10pt; 13 | } 14 | 15 | .opttable { 16 | border: 1px solid black; 17 | } 18 | 19 | .optcell { 20 | vertical-align: top; 21 | padding: 0 10px; 22 | } 23 | 24 | .opttitle { 25 | font-weight: bold; 26 | } 27 | 28 | .empty { 29 | background-color: #ffffff; 30 | } 31 | 32 | .subheader { 33 | font-size: 10pt; 34 | } 35 | 36 | .etype_header { 37 | background-color: #e0e0e0; 38 | font-weight: bold; 39 | border: 1px solid black; 40 | } 41 | 42 | .legacy_header { 43 | background-color: #c0ffc0; 44 | font-weight: bold; 45 | border: 1px solid black; 46 | } 47 | 48 | .modifiers_header { 49 | background-color: #ffc0ff; 50 | font-weight: bold; 51 | border: 1px solid black; 52 | } 53 | 54 | .olddom3_header { 55 | background-color: #ffc0c0; 56 | font-weight: bold; 57 | border: 1px solid black; 58 | } 59 | 60 | .uievents_header { 61 | background-color: #c0ffff; 62 | font-weight: bold; 63 | border: 1px solid black; 64 | } 65 | 66 | .proposed_header { 67 | background-color: #ffffc0; 68 | font-weight: bold; 69 | border: 1px solid black; 70 | } 71 | 72 | .inputbox_header { 73 | background-color: #e0e0e0; 74 | font-weight: bold; 75 | border: 1px solid black; 76 | } 77 | 78 | .keycell { 79 | padding: 0 5px 0 5px; 80 | } 81 | 82 | .modOff { 83 | color: #ffd0d0; 84 | } 85 | 86 | .modOn { 87 | color: green; 88 | } 89 | 90 | .undef { 91 | color: #a0a0a0; 92 | } 93 | 94 | input[type=checkbox]:disabled+label { 95 | color: #a0a0a0; 96 | } 97 | 98 | .keyevent_hilight { 99 | border: 1px solid #404040; 100 | border-radius: 4px; 101 | padding: 0 3px 0 3px; 102 | margin-left: 3px; 103 | } 104 | 105 | .keypress_hilight { 106 | background-color: #c0c0ff; 107 | } 108 | 109 | .keydown_hilight { 110 | background-color: #c0ffc0; 111 | } 112 | 113 | .keydown_row_hilight { 114 | background-color: #e0ffe0; 115 | } 116 | 117 | tr .keydown_row_hilight:hover { 118 | background-color: #e0e0e0; 119 | } 120 | 121 | .keydown_arrow:after { 122 | content: " ⬇"; 123 | } 124 | 125 | .keyup_hilight { 126 | background-color: #ffc0c0; 127 | } 128 | 129 | .keyup_arrow:after { 130 | content: " ⬆"; 131 | } 132 | 133 | .showfieldoption { 134 | font-weight: normal; 135 | padding: 0 5px 0 5px; 136 | display: inline-block; 137 | min-width: 90px; 138 | text-align: center; 139 | } 140 | 141 | #output tr:hover, tr.highlight { 142 | background-color: #e0e0e0; 143 | } 144 | 145 | .div_ce { 146 | border: 1px solid black; 147 | } 148 | 149 | .main_link { 150 | float: right; 151 | border: 1px solid black; 152 | border-radius: 4px; 153 | font-size: 9pt; 154 | padding: 2px 4px; 155 | text-decoration: none; 156 | background-color: #e0e0ff; 157 | } 158 | 159 | body { 160 | margin: 10px; 161 | padding: 0 20px; 162 | background-color: #ffffff; 163 | } 164 | 165 | /* Fix for black background in Fullscreen (Chrome). */ 166 | html { 167 | background-color: #ffffff; 168 | } 169 | 170 | *:fullscreen, *:-webkit-full-screen, *:-moz-full-screen, *:-ms-fullscreen { 171 | background-color: rgba(255,255,255,0); 172 | width: 100%; 173 | height: 100%; 174 | } 175 | -------------------------------------------------------------------------------- /tools/key-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Keyboard Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | UI Events Testing Tools 18 | 19 |

Keyboard Event Viewer

20 | 21 |

UserAgent:

22 | 23 |

24 | input element with type="text": 25 |

26 |

27 | 28 | Show Options 29 |

30 | 31 |
32 | 33 | 34 |
35 | 36 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tools/key-event-viewer.js: -------------------------------------------------------------------------------- 1 | // Keyboard event viewer 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | var _key_table_info = [ 5 | // Unlabeled group 6 | ["", "etype", [ 7 | ["#", "etype", "text"], 8 | ["Event type", "etype", "html"], 9 | ], {'grouplabel': false}], 10 | 11 | // KeyboardEvent - Legacy 12 | ["Legacy", "legacy", [ 13 | ["charCode", "legacy", "html"], 14 | ["keyCode", "legacy", "html"], 15 | ["which", "legacy", "text"], 16 | ], {'checked': true}], 17 | 18 | // KeyboardEvent - Modifiers 19 | ["Modifiers", "modifiers", [ 20 | ["getModifierState", "modifiers", "text"], 21 | ["shift", "modifiers", "bool"], 22 | ["ctrl", "modifiers", "bool"], 23 | ["alt", "modifiers", "bool"], 24 | ["meta", "modifiers", "bool"], 25 | ], {'checked': true}], 26 | 27 | // KeyboardEvent - Old DOM3 28 | ["Old DOM3", "olddom3", [ 29 | ["keyIdentifier", "olddom3", "text"], 30 | ["keyLocation", "olddom3", "text"], 31 | ["char", "olddom3", "text"], 32 | ], {'checked': false}], 33 | 34 | // KeyboardEvent - UI Events 35 | ["UI Events", "uievents", [ 36 | ["key", "uievents", "html"], 37 | ["code", "uievents", "text"], 38 | ["location", "uievents", "text"], 39 | ["repeat", "uievents", "bool"], 40 | ["isComposing", "uievents", "bool"], 41 | ["inputType", "uievents", "text"], 42 | ["data", "uievents", "text"], 43 | ], {'checked': true}], 44 | 45 | // KeyboardEvent - Proposed 46 | ["Proposed", "proposed", [ 47 | ["locale", "proposed", "text"], 48 | ], {'checked': false}], 49 | 50 | // Input 51 | ["Input", "inputbox", [ 52 | ["Input field", "inputbox", "text", {'align': 'left'}], 53 | ], {'checked': true, 'grouplabel': false}], 54 | ]; 55 | 56 | var _key_event_info = [ 57 | ["keydown", { 58 | 'preventDefault': {'checked': false}, 59 | 'stopPropagation': {}, 60 | 'ShowEvents': {}, 61 | 'Highlight': {'class': "keyevent_hilight keydown_hilight keydown_arrow"}, 62 | }, 63 | "#e0e0e0"], 64 | ["keypress", { 65 | 'preventDefault': {'checked': false}, 66 | 'stopPropagation': {}, 67 | 'ShowEvents': {}, 68 | 'Highlight': {'checked': false, 'class': "keyevent_hilight keypress_hilight"}, 69 | }, 70 | "#ccffcc"], 71 | ["keyup", { 72 | 'preventDefault': {'checked': false}, 73 | 'stopPropagation': {}, 74 | 'ShowEvents': {}, 75 | 'Highlight': {'class': "keyevent_hilight keyup_hilight keyup_arrow"}, 76 | }, 77 | "#ffcccc"], 78 | ["textinput", { 79 | 'preventDefault': {'checked': false}, 80 | 'stopPropagation': {'checked': false}, 81 | 'ShowEvents': {'checked': false}, 82 | 'Highlight': {'enabled': false, 'checked': false}, 83 | }, 84 | "#ffffff"], 85 | ["beforeinput", { 86 | 'preventDefault': {'checked': false}, 87 | 'stopPropagation': {}, 88 | 'ShowEvents': {}, 89 | 'Highlight': {'enabled': false, 'checked': false}, 90 | }, 91 | "repeating-linear-gradient(-45deg, #fcc, #fcc 8px, #fff 8px, #fff 16px)"], 92 | ["input", { 93 | 'preventDefault': {'checked': false}, 94 | 'stopPropagation': {}, 95 | 'ShowEvents': {}, 96 | 'Highlight': {'enabled': false, 'checked': false}, 97 | }, 98 | "repeating-linear-gradient(-45deg, #cfc, #cfc 8px, #fff 8px, #fff 16px)"], 99 | ["compositionstart", { 100 | 'preventDefault': {'checked': false}, 101 | 'stopPropagation': {}, 102 | 'ShowEvents': {}, 103 | 'Highlight': {'enabled': false, 'checked': false}, 104 | }, 105 | "#e0e0e0"], 106 | ["compositionupdate", { 107 | 'preventDefault': {'checked': false}, 108 | 'stopPropagation': {}, 109 | 'ShowEvents': {}, 110 | 'Highlight': {'enabled': false, 'checked': false}, 111 | }, 112 | "#e0e0e0"], 113 | ["compositionend", { 114 | 'preventDefault': {'checked': false}, 115 | 'stopPropagation': {}, 116 | 'ShowEvents': {}, 117 | 'Highlight': {'enabled': false, 'checked': false}, 118 | }, 119 | "#e0e0e0"], 120 | ]; 121 | 122 | 123 | // True if the current row is a 'keydown' event. 124 | // This is used to set the background for the entire row when 'keydown' events are 125 | // highlighted. 126 | var _isKeydown = false; 127 | 128 | function setUserAgentText() { 129 | var userAgent = navigator.userAgent; 130 | uaDiv = document.getElementById("useragent"); 131 | setText(uaDiv, userAgent); 132 | } 133 | 134 | function resetTable(resetData=true) { 135 | clearTable(); 136 | initOutputTable(_key_table_info); 137 | 138 | setInputFocus(resetData); 139 | } 140 | 141 | function init() { 142 | setUserAgentText(); 143 | var extra_options = [ 144 | ["checkbox", "readonlyToggle", "Read only ", { 145 | 'onclick': "toggleReadonly()", 146 | 'checked': false, 147 | }], 148 | ["text", "Note: Options apply to new events only."], 149 | ]; 150 | 151 | // Remove read-only option for contenteditable. 152 | var el = document.getElementById("input"); 153 | if (el.tagName == "DIV") { 154 | extra_options.shift(); 155 | } 156 | 157 | createOptions(document.getElementById("options"), _key_event_info, _key_table_info, extra_options); 158 | resetTable(false); 159 | 160 | var input = document.getElementById("input"); 161 | addEventListener(input, "keydown", onKeyDown); 162 | addEventListener(input, "keypress", onKeyPress); 163 | addEventListener(input, "keyup", onKeyUp); 164 | addEventListener(input, "textInput", onTextInput); 165 | addEventListener(input, "textinput", onTextInput); // For IE9 166 | addEventListener(input, "beforeinput", onBeforeInput); 167 | addEventListener(input, "input", onInput); 168 | addEventListener(input, "compositionstart", onCompositionStart); 169 | addEventListener(input, "compositionupdate", onCompositionUpdate); 170 | addEventListener(input, "compositionend", onCompositionEnd); 171 | } 172 | 173 | // ===== 174 | // Key events: keydown, keypress, keyup 175 | // ===== 176 | 177 | function onKeyDown(e) { 178 | _isKeydown = true; 179 | handleKeyEvent("keydown", e); 180 | _isKeydown = false; 181 | } 182 | 183 | function onKeyPress(e) { 184 | handleKeyEvent("keypress", e); 185 | } 186 | 187 | function onKeyUp(e) { 188 | handleKeyEvent("keyup", e); 189 | } 190 | 191 | function handleKeyEvent(etype, e) { 192 | var show = document.getElementById("show_" + etype); 193 | if (show.checked) { 194 | addKeyEvent(etype, e); 195 | } 196 | handleDefaultPropagation(etype, e); 197 | } 198 | 199 | function addKeyEvent(etype, e) { 200 | if (!e) { 201 | e = window.event; 202 | } 203 | var eventinfo = {}; 204 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 205 | eventinfo["charCode"] = calcRichKeyVal(etype, "charCode", e.charCode); 206 | eventinfo["keyCode"] = calcRichKeyVal(etype, "keyCode", e.keyCode); 207 | eventinfo["which"] = e.which; 208 | eventinfo["getModifierState"] = getModifierState(e); 209 | eventinfo["shift"] = e.shiftKey; 210 | eventinfo["ctrl"] = e.ctrlKey; 211 | eventinfo["alt"] = e.altKey; 212 | eventinfo["meta"] = e.metaKey; 213 | eventinfo["keyIdentifier"] = e.keyIdentifier; 214 | eventinfo["keyLocation"] = calcLocation(e.keyLocation); 215 | eventinfo["char"] = calcString(e.char); 216 | eventinfo["key"] = calcHilightString(etype, e.key, false); 217 | eventinfo["code"] = e.code; 218 | eventinfo["location"] = calcLocation(e.location); 219 | eventinfo["repeat"] = e.repeat; 220 | eventinfo["isComposing"] = e.isComposing; 221 | eventinfo["Input field"] = calcInput(); 222 | 223 | extra_class = undefined; 224 | if (_isKeydown && document.getElementById("hl_keydown").checked) { 225 | extra_class = "keydown_row_hilight"; 226 | } 227 | addEventToOutput(eventinfo, extra_class); 228 | } 229 | 230 | // ===== 231 | // Input events: textinput, beforeinput, input 232 | // ===== 233 | 234 | function onTextInput(e) { 235 | handleInputEvent("textinput", e); 236 | } 237 | 238 | function onBeforeInput(e) { 239 | handleInputEvent("beforeinput", e); 240 | } 241 | 242 | function onInput(e) { 243 | handleInputEvent("input", e); 244 | } 245 | 246 | function handleInputEvent(etype, e) { 247 | var show = document.getElementById("show_" + etype); 248 | if (show.checked) { 249 | addInputEvent(etype, e); 250 | } 251 | handleDefaultPropagation(etype, e); 252 | } 253 | 254 | function addInputEvent(etype, e) { 255 | if (!e) { 256 | e = window.event; 257 | } 258 | var eventinfo = {}; 259 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 260 | eventinfo["isComposing"] = e.isComposing; 261 | eventinfo["inputType"] = e.inputType; 262 | eventinfo["data"] = calcString(e.data); 263 | eventinfo["Input field"] = calcInput(); 264 | addEventToOutput(eventinfo); 265 | } 266 | 267 | // ===== 268 | // Composition events: compositionstart, compositionupdate, compositionend 269 | // ===== 270 | 271 | function onCompositionStart(e) { 272 | handleCompositionEvent("compositionstart", e); 273 | } 274 | 275 | function onCompositionUpdate(e) { 276 | handleCompositionEvent("compositionupdate", e); 277 | } 278 | 279 | function onCompositionEnd(e) { 280 | handleCompositionEvent("compositionend", e); 281 | } 282 | 283 | function handleCompositionEvent(etype, e) { 284 | var show = document.getElementById("show_"+etype); 285 | if (show.checked) { 286 | addCompositionEvent(etype, e); 287 | } 288 | handleDefaultPropagation(etype, e); 289 | } 290 | 291 | function addCompositionEvent(etype, e) { 292 | if (!e) { 293 | e = window.event; 294 | } 295 | var eventinfo = {}; 296 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 297 | eventinfo["isComposing"] = e.isComposing; 298 | eventinfo["data"] = calcString(e.data); 299 | eventinfo["Input field"] = calcInput(); 300 | addEventToOutput(eventinfo); 301 | } 302 | 303 | // ===== 304 | // Helper functions 305 | // ===== 306 | 307 | function calcInput() { 308 | var el = document.getElementById("input"); 309 | var value = ""; 310 | if (el.tagName == "DIV") { 311 | //
312 | value = el.innerText; 313 | } else { 314 | // 315 | value = el.value; 316 | } 317 | return "'" + value + "'"; 318 | } 319 | 320 | /* Set the focus to the input box. */ 321 | function setInputFocus(resetData) { 322 | var input = document.getElementById("input"); 323 | 324 | if (resetData) { 325 | if (input.tagName == "DIV") { 326 | //
327 | clearChildren(input); 328 | } else { 329 | // 330 | input.value = ""; 331 | } 332 | } 333 | 334 | // Set focus. 335 | if (input.tagName == "DIV") { 336 | //
337 | var sel = window.getSelection(); 338 | var range = document.createRange(); 339 | //range.setStart(input, 0); 340 | //range.setEnd(input, 0); 341 | range.selectNodeContents(input); 342 | sel.removeAllRanges(); 343 | sel.addRange(range); 344 | } else { 345 | // 346 | input.focus(); 347 | } 348 | } 349 | 350 | function calcLocation(loc) { 351 | if (loc == 1) return "LEFT"; 352 | if (loc == 2) return "RIGHT"; 353 | if (loc == 3) return "NUMPAD"; 354 | return loc; 355 | } 356 | 357 | function calcRichKeyVal(eventType, attrName, key) { 358 | if (key === undefined) { 359 | return null; 360 | } 361 | 362 | var keyString = String.fromCharCode(key); 363 | if (attrName == "keyCode") { 364 | // Don't even try to decipher keyCode unless it's alphanum. 365 | if (key < 32 || key > 90) { 366 | keyString = ""; 367 | } 368 | // ...or a modifier. 369 | switch (key) { 370 | case 16: keyString = "Shift"; break; 371 | case 17: keyString = "Control"; break; 372 | case 18: keyString = "Alt"; break; 373 | case 91: 374 | case 93: 375 | case 224: 376 | keyString = "Meta"; 377 | break; 378 | } 379 | } 380 | 381 | if (keyString != "" 382 | && ((eventType == "keypress" && attrName == "charCode") 383 | || ((eventType == "keydown" || eventType == "keyup") && attrName == "keyCode") 384 | ) 385 | ) { 386 | var data = document.createElement("span"); 387 | data.appendChild(document.createTextNode(key)); 388 | var keySpan = document.createElement("span"); 389 | if (document.getElementById("hl_" + eventType).checked) { 390 | keySpan.classList.add("keyevent_hilight"); 391 | keySpan.classList.add(eventType + "_hilight"); 392 | } else { 393 | keyString = " " + keyString; 394 | } 395 | keySpan.textContent = keyString; 396 | data.appendChild(keySpan); 397 | return data; 398 | } 399 | return document.createTextNode(key); 400 | } 401 | 402 | function calcHilightString(eventType, data, addArrow) { 403 | if (data === undefined) { 404 | return null; 405 | } 406 | 407 | var keySpan = document.createElement("span"); 408 | var enableHilight = document.getElementById("hl_" + eventType); 409 | if (enableHilight && enableHilight.checked) { 410 | keySpan.classList.add("keyevent_hilight"); 411 | keySpan.classList.add(eventType + "_hilight"); 412 | if (addArrow && (eventType == "keydown" || eventType == "keyup")) { 413 | keySpan.classList.add(eventType + "_arrow"); 414 | } 415 | } 416 | keySpan.textContent = data; 417 | return keySpan; 418 | } 419 | 420 | function toggleReadonly() { 421 | var cbReadonly = document.getElementById("readonlyToggle"); 422 | var input = document.getElementById("input"); 423 | if (cbReadonly.checked) { 424 | input.setAttribute('readonly', true); 425 | } else { 426 | input.removeAttribute('readonly'); 427 | } 428 | setInputFocus(false); 429 | } 430 | -------------------------------------------------------------------------------- /tools/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 40px auto; 3 | background-color: #ffffff; 4 | max-width: 800px; 5 | } 6 | 7 | ul { 8 | padding: 0; 9 | margin: 0; 10 | list-style-type: none; 11 | } 12 | 13 | li { 14 | margin: 10px; 15 | padding: 10px; 16 | border: 1px solid black; 17 | border-radius: 10px; 18 | } 19 | 20 | code { 21 | font-size: 11pt; 22 | font-style: bold; 23 | } 24 | 25 | .name { 26 | display: block; 27 | font-size: 16pt; 28 | font-style: bold; 29 | } 30 | 31 | .desc { 32 | display: block; 33 | margin: 10px 0 0 0; 34 | } 35 | -------------------------------------------------------------------------------- /tools/main.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | UI Events Testing Tools 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

UI Events Testing Tools

18 | 19 |

20 | A collection of tools for viewing and testing various UI Events. 21 |

22 | 23 |

24 | To report a bug or a submit feature request for any of these tools, 25 | file an issue on Github. 26 |

27 | 28 |

Event Viewers

29 |
    30 |
  • 31 | Key Event Viewer 32 | View KeyboardEvents on a <input type="text"> element. 33 | Select which events and attributes to show and control event propagation. 34 | keydown, keypress, keyup, textinput, beforeinput, input, compositionstart, compositionupdate, compositionend 35 |
  • 36 |
  • 37 | Key Event Viewer (for contenteditable) 38 | Same as the standard Key Event Viewer except targetting a <div contenteditable="true"> element. 39 |
  • 40 |
  • 41 | Mouse Event Viewer 42 | View MouseEvents on a set of overlapping <div>s. 43 | mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup 44 |
  • 45 |
  • 46 | Mouse Event Viewer (with shadow DOM) 47 | Same as the standard Mouse Event Viewer except with additional shadow DOM elements. 48 |
  • 49 |
  • 50 | Focus Event Viewer 51 | View FocusEvents between two edit fields. 52 | blur, focusin, focusout, DOMFocusIn, DOMFocusOut 53 |
  • 54 |
55 | 56 |

Manual Keyboard Layout Tests

57 | 58 |

59 | These manual tests show a keyboard and require that you manually press the indicated 60 | keys. The key and code attributes of the KeyboardEvent will 61 | be checked against the known correct result for the layout. 62 |

63 | 64 |

65 | Note: Before running these tests, you must manually set your keyboard layout to match 66 | the layout being tested. 67 |

68 | 69 | 77 | 78 |

Other Event Testing Tools

79 | 80 |

81 | Additional tools for testing events. 82 |

83 | 84 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /tools/mouse-event-viewer-core.js: -------------------------------------------------------------------------------- 1 | // Mouse event viewer 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | var _mouse_table_info = [ 5 | // Unlabeled group 6 | ["", "etype", [ 7 | ["#", "etype", "text"], 8 | ["Event type", "etype", "html"], 9 | ["Count", "etype", "text"], 10 | ], {'grouplabel': false}], 11 | 12 | // MouseEvent - Target 13 | ["Target", "target", [ 14 | ["A", "target", "text", {'style': 'hilite_div_a'}], 15 | ["B", "target", "text", {'style': 'hilite_div_b'}], 16 | ["C", "target", "text", {'style': 'hilite_div_c'}], 17 | ], {'checked': true}], 18 | 19 | // MouseEvent - Handler 20 | ["Handler", "handler", [ 21 | ["hA", "handler", "text", {'style': 'hilite_handler_a'}], 22 | ["hB", "handler", "text", {'style': 'hilite_handler_b'}], 23 | ["hC", "handler", "text", {'style': 'hilite_handler_c'}], 24 | ], {'checked': false}], 25 | 26 | // Event 27 | ["Event", "event", [ 28 | ["eventPhase", "event", "text"], 29 | ["bubbles", "event", "bool"], 30 | ["cancelable", "event", "bool"], 31 | ["defaultPrevented", "event", "bool"], 32 | ["composed", "event", "bool"], 33 | ["isTrusted", "event", "bool"], 34 | ["timeStamp", "event", "text"], 35 | ], {'checked': false}], 36 | 37 | // UIEvent 38 | ["UIEvent", "uievent", [ 39 | ["view", "uievent", "text"], 40 | ["detail", "uievent", "text"], 41 | ], {'checked': false}], 42 | 43 | // MouseEvent - UI Events 44 | ["MouseEvent", "mouseevent", [ 45 | ["screenX", "mouseevent", "text"], 46 | ["screenY", "mouseevent", "text"], 47 | ["clientX", "mouseevent", "text"], 48 | ["clientY", "mouseevent", "text"], 49 | ], {'checked': true}], 50 | 51 | // PointerLock 52 | ["PointerLock", "plock", [ 53 | ["movementX", "plock", "text"], 54 | ["movementY", "plock", "text"], 55 | ], {'checked': true}], 56 | 57 | // CSSOM 58 | ["CSSOM", "cssom", [ 59 | ["offsetX", "cssom", "text"], 60 | ["offsetY", "cssom", "text"], 61 | ["pageX", "cssom", "text"], 62 | ["pageY", "cssom", "text"], 63 | ["x", "cssom", "text"], 64 | ["y", "cssom", "text"], 65 | ], {'checked': true}], 66 | 67 | // MouseEvent - UI Events 68 | ["Buttons", "buttons", [ 69 | ["button", "buttons", "text"], 70 | ["buttons", "buttons", "text"], 71 | ], {'checked': true}], 72 | 73 | // KeyboardEvent - Modifiers 74 | ["Modifiers", "modifiers", [ 75 | ["getModifierState", "modifiers", "text"], 76 | ["shift", "modifiers", "bool"], 77 | ["ctrl", "modifiers", "bool"], 78 | ["alt", "modifiers", "bool"], 79 | ["meta", "modifiers", "bool"], 80 | ], {'checked': true}], 81 | ]; 82 | 83 | function init() { 84 | init_shared(); 85 | 86 | var div_a = document.getElementById("div_a"); 87 | var div_b = document.getElementById("div_b"); 88 | var div_c = document.getElementById("div_c"); 89 | for (var div of [div_a, div_b, div_c]) { 90 | addEventListener(div, "mousedown", onMouseDown.bind(null, div)); 91 | addEventListener(div, "mouseenter", onMouseEnter.bind(null, div)); 92 | addEventListener(div, "mouseleave", onMouseLeave.bind(null, div)); 93 | addEventListener(div, "mousemove", onMouseMove.bind(null, div)); 94 | addEventListener(div, "mouseout", onMouseOut.bind(null, div)); 95 | addEventListener(div, "mouseover", onMouseOver.bind(null, div)); 96 | addEventListener(div, "mouseup", onMouseUp.bind(null, div)); 97 | } 98 | 99 | addEventListener(document.getElementById("body"), "keydown", onKeyDown); 100 | addEventListener(div_a, "contextmenu", onContextMenu); 101 | } 102 | -------------------------------------------------------------------------------- /tools/mouse-event-viewer-shadow.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Mouse Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | UI Events Testing Tools 19 | 20 |

Mouse Event Viewer with shadow dom content

21 | 22 |

UserAgent:

23 | 24 |
A
B
C (host)
25 | 26 |

27 | 28 | Show Options 29 |

30 | 31 |
32 | 33 |
34 | 35 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tools/mouse-event-viewer-shadow.js: -------------------------------------------------------------------------------- 1 | // Mouse event viewer 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | var _mouse_table_info = [ 5 | // Unlabeled group 6 | ["", "etype", [ 7 | ["#", "etype", "text"], 8 | ["Event type", "etype", "html"], 9 | ["Count", "etype", "text"], 10 | ], {'grouplabel': false}], 11 | 12 | // MouseEvent - Target 13 | ["Target", "target", [ 14 | ["A", "target", "text", {'style': 'hilite_div_a'}], 15 | ["B", "target", "text", {'style': 'hilite_div_b'}], 16 | ["C", "target", "text", {'style': 'hilite_div_c'}], 17 | ["sD", "target", "text", {'style': 'hilite_div_d'}], 18 | ["sE", "target", "text", {'style': 'hilite_div_e'}], 19 | ], {'checked': true}], 20 | 21 | // Event 22 | ["Event", "event", [ 23 | ["eventPhase", "event", "text"], 24 | ["bubbles", "event", "bool"], 25 | ["cancelable", "event", "bool"], 26 | ["defaultPrevented", "event", "bool"], 27 | ["composed", "event", "bool"], 28 | ["isTrusted", "event", "bool"], 29 | ["timeStamp", "event", "text"], 30 | ], {'checked': false}], 31 | 32 | // UIEvent 33 | ["UIEvent", "uievent", [ 34 | ["view", "uievent", "text"], 35 | ["detail", "uievent", "text"], 36 | ], {'checked': false}], 37 | 38 | // MouseEvent - UI Events 39 | ["MouseEvent", "mouseevent", [ 40 | ["screenX", "mouseevent", "text"], 41 | ["screenY", "mouseevent", "text"], 42 | ["clientX", "mouseevent", "text"], 43 | ["clientY", "mouseevent", "text"], 44 | ], {'checked': true}], 45 | 46 | // PointerLock 47 | ["PointerLock", "plock", [ 48 | ["movementX", "plock", "text"], 49 | ["movementY", "plock", "text"], 50 | ], {'checked': true}], 51 | 52 | // CSSOM 53 | ["CSSOM", "cssom", [ 54 | ["offsetX", "cssom", "text"], 55 | ["offsetY", "cssom", "text"], 56 | ["pageX", "cssom", "text"], 57 | ["pageY", "cssom", "text"], 58 | ["x", "cssom", "text"], 59 | ["y", "cssom", "text"], 60 | ], {'checked': true}], 61 | 62 | // MouseEvent - UI Events 63 | ["Buttons", "buttons", [ 64 | ["button", "buttons", "text"], 65 | ["buttons", "buttons", "text"], 66 | ], {'checked': true}], 67 | 68 | // KeyboardEvent - Modifiers 69 | ["Modifiers", "modifiers", [ 70 | ["getModifierState", "modifiers", "text"], 71 | ["shift", "modifiers", "bool"], 72 | ["ctrl", "modifiers", "bool"], 73 | ["alt", "modifiers", "bool"], 74 | ["meta", "modifiers", "bool"], 75 | ], {'checked': true}], 76 | ]; 77 | 78 | function init() { 79 | init_shared(); 80 | 81 | var div_a = document.getElementById("div_a"); 82 | var div_b = document.getElementById("div_b"); 83 | var div_c = document.getElementById("div_c"); 84 | 85 | const shadow_root = div_c.attachShadow({ mode: 'open'}); 86 | shadow_root.innerHTML = 87 | '' + 99 | 'C (sHost)' + 100 | '
sD' + 101 | '
sE
' + 102 | '
'; 103 | var div_d = shadow_root.getElementById("div_d"); 104 | var div_e = shadow_root.getElementById("div_e"); 105 | 106 | for (var div of [div_a, div_b, div_c, div_d, div_e]) { 107 | addEventListener(div, "mousedown", onMouseDown.bind(null, div)); 108 | addEventListener(div, "mouseenter", onMouseEnter.bind(null, div)); 109 | addEventListener(div, "mouseleave", onMouseLeave.bind(null, div)); 110 | addEventListener(div, "mousemove", onMouseMove.bind(null, div)); 111 | addEventListener(div, "mouseout", onMouseOut.bind(null, div)); 112 | addEventListener(div, "mouseover", onMouseOver.bind(null, div)); 113 | addEventListener(div, "mouseup", onMouseUp.bind(null, div)); 114 | } 115 | 116 | addEventListener(document.getElementById("body"), "keydown", onKeyDown); 117 | addEventListener(div_a, "contextmenu", onContextMenu); 118 | } 119 | -------------------------------------------------------------------------------- /tools/mouse-event-viewer-shared.js: -------------------------------------------------------------------------------- 1 | // Mouse event viewer - shared 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | var _mouse_event_info = [ 5 | ["mousedown", { 6 | 'preventDefault': {'checked': false}, 7 | 'stopPropagation': {}, 8 | 'ShowEvents': {}, 9 | 'Highlight': {'class': "mouseevent_hilight mousedown_hilight"}, 10 | }, 11 | "#e0e0e0"], 12 | ["mouseenter", { 13 | 'preventDefault': {'checked': false}, 14 | 'stopPropagation': {'enabled': false, 'checked': false}, 15 | 'ShowEvents': {}, 16 | 'Highlight': {'class': "mouseevent_hilight mouseenter_hilight"}, 17 | }, 18 | "#ccffcc"], 19 | ["mouseleave", { 20 | 'preventDefault': {'checked': false}, 21 | 'stopPropagation': {'enabled': false, 'checked': false}, 22 | 'ShowEvents': {}, 23 | 'Highlight': {'class': "mouseevent_hilight mouseleave_hilight"}, 24 | }, 25 | "#ffcccc"], 26 | ["mousemove", { 27 | 'preventDefault': {'checked': false}, 28 | 'stopPropagation': {}, 29 | 'ShowEvents': {}, 30 | 'Highlight': {'checked': false, 'class': "mouseevent_hilight mousemove_hilight"}, 31 | }, 32 | "#ffffff"], 33 | ["mouseout", { 34 | 'preventDefault': {'checked': false}, 35 | 'stopPropagation': {}, 36 | 'ShowEvents': {}, 37 | 'Highlight': {'checked': false, 'class': "mouseevent_hilight mouseout_hilight"}, 38 | }, 39 | "repeating-linear-gradient(-45deg, #fcc, #fcc 8px, #fff 8px, #fff 16px)"], 40 | ["mouseover", { 41 | 'preventDefault': {'checked': false}, 42 | 'stopPropagation': {}, 43 | 'ShowEvents': {}, 44 | 'Highlight': {'checked': false, 'class': "mouseevent_hilight mouseover_hilight"}, 45 | }, 46 | "repeating-linear-gradient(-45deg, #cfc, #cfc 8px, #fff 8px, #fff 16px)"], 47 | ["mouseup", { 48 | 'preventDefault': {'checked': false}, 49 | 'stopPropagation': {}, 50 | 'ShowEvents': {}, 51 | 'Highlight': {'class': "mouseevent_hilight mouseup_hilight"}, 52 | }, 53 | "#e0e0e0"], 54 | ]; 55 | 56 | var _lastMouseMoveTarget = ""; 57 | var _mouseMoveCount = 0; 58 | 59 | function setUserAgentText() { 60 | var userAgent = navigator.userAgent; 61 | uaDiv = document.getElementById("useragent"); 62 | setText(uaDiv, userAgent); 63 | } 64 | 65 | function resetTable() { 66 | clearTable(); 67 | initOutputTable(_mouse_table_info); 68 | } 69 | 70 | function init_shared() { 71 | setUserAgentText(); 72 | var extra_options = [ 73 | ["checkbox", "combine_mousemove", "Combine mousemove events with same target", {}], 74 | ["text", "Note: Options apply to new events only."], 75 | ["text", "Press 'c' to Clear Table."], 76 | ]; 77 | createOptions(document.getElementById("options"), _mouse_event_info, _mouse_table_info, extra_options); 78 | resetTable(); 79 | } 80 | 81 | function onKeyDown(e) { 82 | if (e.code == "KeyC") { 83 | resetTable(); 84 | _lastMouseMoveTarget = ""; 85 | } 86 | } 87 | 88 | function onContextMenu(e) { 89 | e.preventDefault(); 90 | e.stopPropagation(); 91 | } 92 | 93 | function onMouseDown(handler, e) { 94 | console.log(handler); 95 | handleMouseEvent("mousedown", handler, e); 96 | } 97 | 98 | function onMouseEnter(handler, e) { 99 | handleMouseEvent("mouseenter", handler, e); 100 | } 101 | 102 | function onMouseLeave(handler, e) { 103 | handleMouseEvent("mouseleave", handler, e); 104 | } 105 | 106 | function onMouseMove(handler, e) { 107 | _mouseMoveCount++; 108 | var saveMouseMoveCount = _mouseMoveCount; 109 | 110 | // Combine duplicate move moves in the same target by removing last one. 111 | var combine = document.getElementById("combine_mousemove"); 112 | var show = document.getElementById("show_mousemove"); 113 | if (show.checked && combine.checked && _lastMouseMoveTarget == e.target.id) 114 | deleteLastOutputRow(); 115 | 116 | handleMouseEvent("mousemove", handler, e); 117 | 118 | _lastMouseMoveTarget = e.target.id; 119 | _mouseMoveCount = saveMouseMoveCount; 120 | } 121 | 122 | function onMouseOut(handler, e) { 123 | handleMouseEvent("mouseout", handler, e); 124 | } 125 | 126 | function onMouseOver(handler, e) { 127 | handleMouseEvent("mouseover", handler, e); 128 | } 129 | 130 | function onMouseUp(handler, e) { 131 | handleMouseEvent("mouseup", handler, e); 132 | } 133 | 134 | function handleMouseEvent(etype, handler, e) { 135 | var show = document.getElementById("show_" + etype); 136 | if (show.checked) { 137 | addMouseEvent(etype, handler, e); 138 | } 139 | handleDefaultPropagation(etype, e); 140 | 141 | _lastMouseMoveTarget = ""; 142 | _mouseMoveCount = 0; 143 | } 144 | 145 | function addMouseEvent(etype, handler, e) { 146 | if (!e) { 147 | e = window.event; 148 | } 149 | var target = e.target.id; 150 | var handler = handler.id; 151 | var eventinfo = {}; 152 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 153 | eventinfo["Count"] = (etype == "mousemove" ? _mouseMoveCount : ""); 154 | 155 | eventinfo["A"] = (target == "div_a" ? "A" : ""); 156 | eventinfo["B"] = (target == "div_b" ? "B" : ""); 157 | eventinfo["C"] = (target == "div_c" ? "C" : ""); 158 | eventinfo["sD"] = (target == "div_d" ? "sD" : ""); 159 | eventinfo["sE"] = (target == "div_e" ? "sE" : ""); 160 | 161 | eventinfo["hA"] = (handler == "div_a" ? (handler == target ? "-" : "A") : ""); 162 | eventinfo["hB"] = (handler == "div_b" ? (handler == target ? "-" : "B") : ""); 163 | eventinfo["hC"] = (handler == "div_c" ? (handler == target ? "-" : "C") : ""); 164 | 165 | eventinfo["eventPhase"] = getEventPhase(e); 166 | eventinfo["bubbles"] = e.bubbles; 167 | eventinfo["cancelable"] = e.cancelable; 168 | eventinfo["defaultPrevented"] = e.defaultPrevented; 169 | eventinfo["composed"] = e.composed; 170 | eventinfo["isTrusted"] = e.isTrusted; 171 | eventinfo["timeStamp"] = e.timeStamp; 172 | 173 | eventinfo["view"] = calcString(e.view !== null ? e.view.name : "null"); 174 | eventinfo["detail"] = e.detail; 175 | 176 | eventinfo["screenX"] = e.screenX; 177 | eventinfo["screenY"] = e.screenY; 178 | eventinfo["clientX"] = e.clientX; 179 | eventinfo["clientY"] = e.clientY; 180 | 181 | eventinfo["movementX"] = e.movementX; 182 | eventinfo["movementY"] = e.movementY; 183 | 184 | eventinfo["offsetX"] = e.offsetX; 185 | eventinfo["offsetY"] = e.offsetY; 186 | eventinfo["pageX"] = e.pageX; 187 | eventinfo["pageY"] = e.pageY; 188 | eventinfo["x"] = e.x; 189 | eventinfo["y"] = e.y; 190 | 191 | var button = "-"; 192 | if (etype == "mousedown" || etype == "mouseup") { 193 | button = e.button; 194 | } 195 | eventinfo["button"] = button; 196 | eventinfo["buttons"] = e.buttons; 197 | 198 | eventinfo["getModifierState"] = getModifierState(e); 199 | eventinfo["shift"] = e.shiftKey; 200 | eventinfo["ctrl"] = e.ctrlKey; 201 | eventinfo["alt"] = e.altKey; 202 | eventinfo["meta"] = e.metaKey; 203 | 204 | addEventToOutput(eventinfo); 205 | } 206 | 207 | // ===== 208 | // Helper functions 209 | // ===== 210 | 211 | function calcHilightString(eventType, data) { 212 | if (data === undefined) { 213 | return null; 214 | } 215 | 216 | var keySpan = document.createElement("span"); 217 | var enableHilight = document.getElementById("hl_" + eventType); 218 | if (enableHilight && enableHilight.checked) { 219 | keySpan.classList.add("mouseevent_hilight"); 220 | keySpan.classList.add(eventType + "_hilight"); 221 | } 222 | keySpan.textContent = data; 223 | return keySpan; 224 | } 225 | 226 | -------------------------------------------------------------------------------- /tools/mouse-event-viewer.css: -------------------------------------------------------------------------------- 1 | .subtitle { 2 | font-size: 12pt; 3 | font-style: italic; 4 | } 5 | 6 | #options { 7 | display: none; 8 | margin: 20px; 9 | } 10 | 11 | #optionstoggle { 12 | font-size: 10pt; 13 | } 14 | 15 | .opttable { 16 | border: 1px solid black; 17 | } 18 | 19 | .optcell { 20 | vertical-align: top; 21 | padding: 0 10px; 22 | } 23 | 24 | .opttitle { 25 | font-weight: bold; 26 | } 27 | 28 | .empty { 29 | background-color: #ffffff; 30 | } 31 | 32 | .subheader { 33 | font-size: 10pt; 34 | } 35 | 36 | .etype_header { 37 | background-color: #e0e0e0; 38 | font-weight: bold; 39 | border: 1px solid black; 40 | } 41 | 42 | .target_header { 43 | background-color: #ffffff; 44 | font-weight: bold; 45 | border: 1px solid black; 46 | } 47 | 48 | .handler_header { 49 | background-color: #c0c0ff; 50 | font-weight: bold; 51 | border: 1px solid black; 52 | } 53 | 54 | .event_header { 55 | background-color: #a0ffff; 56 | font-weight: bold; 57 | border: 1px solid black; 58 | } 59 | 60 | .uievent_header { 61 | background-color: #ffffff; 62 | font-weight: bold; 63 | border: 1px solid black; 64 | } 65 | 66 | .mouseevent_header { 67 | background-color: #ffffc0; 68 | font-weight: bold; 69 | border: 1px solid black; 70 | } 71 | 72 | .plock_header { 73 | background-color: #e0a0e0; 74 | font-weight: bold; 75 | border: 1px solid black; 76 | } 77 | 78 | .cssom_header { 79 | background-color: #c0f0c0; 80 | font-weight: bold; 81 | border: 1px solid black; 82 | } 83 | 84 | .modifiers_header { 85 | background-color: #ffc0c0; 86 | font-weight: bold; 87 | border: 1px solid black; 88 | } 89 | 90 | .buttons_header { 91 | background-color: #e0e0e0; 92 | font-weight: bold; 93 | border: 1px solid black; 94 | } 95 | 96 | .keycell { 97 | padding: 0 5px 0 5px; 98 | } 99 | 100 | .modOff { 101 | color: #ffd0d0; 102 | } 103 | 104 | .modOn { 105 | color: green; 106 | } 107 | 108 | .undef { 109 | color: #a0a0a0; 110 | } 111 | 112 | input[type=checkbox]:disabled+label { 113 | color: #a0a0a0; 114 | } 115 | 116 | .mouseevent_hilight { 117 | border: 1px solid #404040; 118 | border-radius: 4px; 119 | padding: 0 3px 0 3px; 120 | margin-left: 3px; 121 | } 122 | 123 | .mousedown_hilight { 124 | background: #e0e0e0; 125 | } 126 | 127 | .mouseenter_hilight { 128 | background: #ccffcc; 129 | } 130 | 131 | .mouseleave_hilight { 132 | background: #ffcccc; 133 | } 134 | 135 | .mousemove_hilight { 136 | background: #ffffff; 137 | } 138 | 139 | .mouseout_hilight { 140 | background: repeating-linear-gradient(-45deg, #fcc, #fcc 8px, #fff 8px, #fff 16px); 141 | } 142 | 143 | .mouseover_hilight { 144 | background: repeating-linear-gradient(-45deg, #cfc, #cfc 8px, #fff 8px, #fff 16px); 145 | } 146 | 147 | .mouseup_hilight { 148 | background: #e0e0e0; 149 | } 150 | 151 | .showfieldoption { 152 | font-weight: normal; 153 | padding: 0 5px 0 5px; 154 | display: inline-block; 155 | min-width: 90px; 156 | text-align: center; 157 | } 158 | 159 | .hilite_div_a { 160 | background-color: #c0ffc0; 161 | padding: 0 10px; 162 | } 163 | 164 | .hilite_div_b { 165 | background-color: #ffc0ff; 166 | padding: 0 10px; 167 | } 168 | 169 | .hilite_div_c { 170 | background-color: #c0ffff; 171 | padding: 0 10px; 172 | } 173 | 174 | .hilite_div_d { 175 | background-color: #c0c0c0; 176 | padding: 0 10px; 177 | } 178 | 179 | .hilite_div_e { 180 | background-color: #808080; 181 | padding: 0 10px; 182 | } 183 | 184 | .hilite_handler_a { 185 | padding: 0 10px; 186 | } 187 | 188 | .hilite_handler_b { 189 | padding: 0 10px; 190 | } 191 | 192 | .hilite_handler_c { 193 | padding: 0 10px; 194 | } 195 | 196 | #div_a { 197 | background-color: #c0ffc0; 198 | border-left: 1px solid black; 199 | border-top: 1px solid black; 200 | border-bottom: 1px solid black; 201 | margin-left: 30px; 202 | padding: 10px 0 10px 10px; 203 | display: inline-block; 204 | } 205 | 206 | #div_b { 207 | background-color: #ffc0ff; 208 | border-left: 1px solid black; 209 | border-top: 1px solid black; 210 | border-bottom: 1px solid black; 211 | margin: 10px 0 10px 10px; 212 | padding: 10px 0 10px 10px; 213 | display: inline-block; 214 | } 215 | 216 | #div_c { 217 | background-color: #c0ffff; 218 | border-left: 1px solid black; 219 | border-top: 1px solid black; 220 | border-bottom: 1px solid black; 221 | margin: 10px 0 10px 10px; 222 | padding: 10px 0 10px 10px; 223 | display: inline-block; 224 | min-width: 200px; 225 | min-height: 30px; 226 | } 227 | 228 | #output tr:hover, tr.highlight { 229 | background-color: #e0e0e0; 230 | } 231 | 232 | .main_link { 233 | float: right; 234 | border: 1px solid black; 235 | border-radius: 4px; 236 | font-size: 9pt; 237 | padding: 2px 4px; 238 | text-decoration: none; 239 | background-color: #e0e0ff; 240 | } 241 | 242 | body { 243 | margin: 10px; 244 | padding: 0 20px; 245 | background-color: #ffffff; 246 | } 247 | 248 | /* Fix for black background in Fullscreen (Chrome). */ 249 | html { 250 | background-color: #ffffff; 251 | } 252 | 253 | *:fullscreen, *:-webkit-full-screen, *:-moz-full-screen, *:-ms-fullscreen { 254 | background-color: rgba(255,255,255,0); 255 | width: 100%; 256 | height: 100%; 257 | } 258 | -------------------------------------------------------------------------------- /tools/mouse-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Mouse Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | UI Events Testing Tools 19 | 20 |

Mouse Event Viewer

21 | 22 |

UserAgent:

23 | 24 |
A
B
C
25 | 26 |

27 | 28 | Show Options 29 |

30 | 31 |
32 | 33 |
34 | 35 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tools/options.js: -------------------------------------------------------------------------------- 1 | // Event test options block 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | _column_info = [ 5 | ["preventDefault", "pd_"], 6 | ["stopPropagation", "sp_"], 7 | ["ShowEvents", "show_"], 8 | ["Highlight", "hl_"], 9 | ]; 10 | 11 | function createOptions(options_div, event_info, table_info, extra) { 12 | var table = document.createElement('table'); 13 | var row, cell; 14 | 15 | table.classList.add("opttable"); 16 | row = document.createElement('tr'); 17 | 18 | for (var col of _column_info) { 19 | var name = col[0]; 20 | var prefix = col[1]; 21 | 22 | cell = document.createElement('td'); 23 | cell.classList.add("optcell"); 24 | addOptionTitle(cell, name); 25 | for (var event of event_info) { 26 | var e = event[0]; 27 | var options = event[1][name]; 28 | addOptionCheckbox(cell, prefix + e, e, options); 29 | } 30 | row.appendChild(cell); 31 | } 32 | 33 | cell = document.createElement('td'); 34 | cell.classList.add("optcell"); 35 | addOptionTitle(cell, "Show Fields"); 36 | for (var group of table_info) { 37 | var name = group[0]; 38 | var type = group[1]; 39 | var options = group[3]; 40 | options.enabled = true; 41 | options.class = type + "_header showfieldoption"; 42 | options.onclick = 'showFieldClick(this)'; 43 | if (name != "") { 44 | addOptionCheckbox(cell, "show_" + type, name, options); 45 | } 46 | } 47 | row.appendChild(cell); 48 | table.appendChild(row); 49 | 50 | if (extra != undefined && extra.length != 0) { 51 | var addTitle = true; 52 | for (var opt of extra) { 53 | row = document.createElement('tr'); 54 | cell = document.createElement('td'); 55 | cell.classList.add("optcell"); 56 | cell.setAttribute("colspan", "5"); 57 | 58 | if (addTitle) { 59 | addOptionTitle(cell, "General Options"); 60 | addTitle = false; 61 | } 62 | 63 | var type = opt[0]; 64 | if (type == "checkbox") { 65 | var name = opt[1]; 66 | var label = opt[2]; 67 | var options = opt[3]; 68 | addOptionCheckbox(cell, name, label, options); 69 | } else if (type == "text") { 70 | var text = opt[1]; 71 | cell.appendChild(document.createTextNode(text)); 72 | } 73 | 74 | row.appendChild(cell); 75 | table.appendChild(row); 76 | } 77 | } 78 | 79 | options_div.appendChild(table); 80 | } 81 | 82 | function addOptionTitle(cell, title) { 83 | var span = document.createElement('span'); 84 | span.classList.add("opttitle"); 85 | span.textContent = title; 86 | cell.appendChild(span); 87 | cell.appendChild(document.createElement("br")); 88 | } 89 | 90 | function addOptionCheckbox(cell, id, text, options) { 91 | if (options.enabled === undefined) 92 | options.enabled = true; 93 | if (options.checked === undefined) 94 | options.checked = true; 95 | 96 | var input = document.createElement("input"); 97 | input.type = "checkbox"; 98 | input.id = id; 99 | input.checked = options.checked; 100 | input.disabled = !options.enabled; 101 | if (options.onclick != undefined && options.onclick != "") { 102 | input.setAttribute("onclick", options.onclick); 103 | } 104 | cell.appendChild(input); 105 | 106 | var label = document.createElement("label"); 107 | label.setAttribute("for", id); 108 | var span = document.createElement('span'); 109 | if (options.class !== undefined) { 110 | for (var c of options.class.split(' ')) { 111 | span.classList.add(c); 112 | } 113 | } 114 | span.appendChild(document.createTextNode(text)); 115 | label.appendChild(span); 116 | cell.appendChild(label); 117 | 118 | cell.appendChild(document.createElement("br")); 119 | } 120 | 121 | function addOptionText(cell, prefix, id, text) { 122 | var span1 = document.createElement('span'); 123 | span1.classList.add("opttext"); 124 | span1.appendChild(document.createTextNode(prefix)); 125 | 126 | var span2 = document.createElement('span'); 127 | span2.id = id; 128 | span2.textContent = 0; 129 | span1.appendChild(span2); 130 | span1.appendChild(document.createTextNode(text)); 131 | 132 | cell.appendChild(span1); 133 | cell.appendChild(document.createElement("br")); 134 | } 135 | 136 | function toggleOptions() { 137 | var link = document.getElementById("optionsToggle"); 138 | var options = document.getElementById("options"); 139 | clearChildren(link); 140 | if (options.style.display == "block") { 141 | options.style.display = "none"; 142 | link.appendChild(document.createTextNode("Show Options")); 143 | } 144 | else { 145 | options.style.display = "block"; 146 | link.appendChild(document.createTextNode("Hide Options")); 147 | } 148 | } 149 | 150 | function showFieldClick(cb) { 151 | var celltype = cb.id.split('_')[1]; 152 | var show = cb.checked; 153 | 154 | var table = document.getElementById("output"); 155 | for (var ir = 0, row; row = table.rows[ir]; ir++) { 156 | for (var ic = 0, cell; cell = row.cells[ic]; ic++) { 157 | if (cell.classList.contains(celltype)) { 158 | if (show) { 159 | cell.style.display = ""; 160 | } else { 161 | cell.style.display = "none"; 162 | } 163 | } 164 | } 165 | } 166 | } 167 | 168 | -------------------------------------------------------------------------------- /tools/output-table.js: -------------------------------------------------------------------------------- 1 | // Event test output table 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | // Output table 5 | // Assumes: 6 | // * The html contains and empty with id="output". 7 | //
8 | // * First column of table is '#' and will contain an auto-generated sequence id. 9 | // * For each group-type, there is a CSS class with that name and one for the header 10 | // with a '_header' suffix. 11 | // * There is a 'subheader' CSS class for the 2nd header row. 12 | 13 | var NUM_HEADER_ROWS = 2; 14 | var MAX_OUTPUT_ROWS = 100 + NUM_HEADER_ROWS; 15 | 16 | // Sequence ID for numbering events. 17 | var _seqId = 1; 18 | 19 | 20 | // Output table info 21 | // Format: 22 | // array of 23 | // : [ , , , , ] 24 | // : 25 | // : cell type for style 26 | // : an array of 27 | // : [ , <cell-type>, <options> ] 28 | // <options> : dict of options: 29 | // 'align': left 30 | var _table_info; 31 | 32 | function initOutputTable(table_info) { 33 | _table_info = table_info; 34 | createTableHeader(); 35 | _seqId = 1; 36 | } 37 | 38 | function createTableHeader(table_info) { 39 | var table = document.getElementById("output"); 40 | var head = table.createTHead(); 41 | var row1 = head.insertRow(-1); // For column group names 42 | var row2 = head.insertRow(-1); // For column names 43 | 44 | for (var group of _table_info) { 45 | var group_title = group[0]; 46 | var group_type = group[1]; 47 | var group_style = group_type + '_header'; 48 | var columns = group[2]; 49 | var options = group[3]; 50 | if (options.grouplabel != undefined && !options.grouplabel) { 51 | group_title = ""; 52 | group_style = ""; 53 | } 54 | addTableCellText(row1, group_title, group_type, group_style, columns.length); 55 | 56 | for (var col of columns) { 57 | var title = col[0]; 58 | var type = col[1]; 59 | var format = col[2]; 60 | var options = col[3]; 61 | 62 | var style = [type + '_header', 'subheader']; 63 | if (options && options['style']) { 64 | style.push(options['style']); 65 | } 66 | 67 | addTableCellText(row2, title, type, style); 68 | } 69 | } 70 | } 71 | 72 | function clearTable() { 73 | clearChildren(document.getElementById("output")); 74 | } 75 | 76 | /* Create the event table row from the event info */ 77 | function addEventToOutput(eventinfo, extra_class) { 78 | var row = addOutputRow(extra_class); 79 | 80 | for (var group of _table_info) { 81 | var columns = group[2]; 82 | for (var col of columns) { 83 | var title = col[0]; 84 | var type = col[1]; 85 | var format = col[2]; 86 | var options = col[3]; 87 | 88 | var val = eventinfo[title]; 89 | if (title == '#') { 90 | val = _seqId; 91 | } 92 | 93 | var style = undefined; 94 | var align = undefined; 95 | if (options && val != "") { 96 | style = options['style']; 97 | align = options['align']; 98 | } 99 | 100 | if (format == 'text') 101 | addTableCellText(row, val, type, style, undefined, align); 102 | else if (format == 'bool') 103 | addTableCellBoolean(row, val, type, style, undefined, align); 104 | else 105 | addTableCell(row, val, type, style, undefined, align); 106 | } 107 | } 108 | 109 | _seqId++; 110 | } 111 | 112 | // Delete the most recent output row. 113 | function deleteLastOutputRow() { 114 | var table = document.getElementById("output"); 115 | table.deleteRow(NUM_HEADER_ROWS); 116 | } 117 | 118 | // extra_class: Additional CSS class to add to this row. 119 | function addOutputRow(extra_class) { 120 | var table = document.getElementById("output"); 121 | 122 | while (table.rows.length >= MAX_OUTPUT_ROWS) { 123 | table.deleteRow(-1); 124 | } 125 | // Insert after the header rows. 126 | var row = table.insertRow(NUM_HEADER_ROWS); 127 | if (extra_class) { 128 | row.classList.add(extra_class); 129 | } 130 | return row; 131 | } 132 | 133 | function addTableCellBoolean(row, key, celltype) { 134 | var modstyle = key ? "modOn" : "modOff"; 135 | addTableCellText(row, calcBoolean(key), celltype, modstyle); 136 | } 137 | 138 | function calcBoolean(key) { 139 | return key ? "✓" : "✗"; 140 | } 141 | 142 | function addTableCellText(row, textdata, celltype, style, span, align) { 143 | var data = null; 144 | if (textdata !== undefined) { 145 | data = document.createTextNode(textdata); 146 | } 147 | addTableCell(row, data, celltype, style, span, align); 148 | } 149 | 150 | function addTableCell(row, data, celltype, style, span, align) { 151 | var cell = row.insertCell(-1); 152 | if (data === undefined || data == null) { 153 | data = document.createTextNode("-"); 154 | style = "undef"; 155 | } 156 | cell.appendChild(data); 157 | if (align === undefined) { 158 | align = "center"; 159 | } 160 | cell.setAttribute("align", align); 161 | if (span !== undefined) { 162 | cell.setAttribute("colspan", span); 163 | } 164 | cell.classList.add("keycell"); 165 | cell.classList.add(celltype); 166 | if (style !== undefined && style != "") { 167 | if (style instanceof Array) { 168 | for (var i = 0; i < style.length; i++) { 169 | cell.classList.add(style[i]); 170 | } 171 | } else { 172 | cell.classList.add(style); 173 | } 174 | } 175 | if (celltype == "etype") { 176 | return; 177 | } 178 | // Hide this cell if it belongs to a hidden celltype. 179 | var show = document.getElementById("show_" + celltype).checked; 180 | if (!show) { 181 | cell.style.display = "none"; 182 | } 183 | } 184 | 185 | // ===== 186 | // Helper functions 187 | // ===== 188 | 189 | function clearChildren(e) { 190 | while (e.firstChild !== null) { 191 | e.removeChild(e.firstChild); 192 | } 193 | } 194 | 195 | function setText(e, text) { 196 | clearChildren(e); 197 | e.appendChild(document.createTextNode(text)); 198 | } 199 | 200 | function addEventListener(obj, etype, handler) { 201 | if (obj.addEventListener) { 202 | obj.addEventListener(etype, handler, false); 203 | } else if (obj.attachEvent) { 204 | obj.attachEvent("on" + etype, handler); 205 | } else { 206 | obj["on" + etype] = handler; 207 | } 208 | } 209 | 210 | function handleDefaultPropagation(etype, e) { 211 | var preventDefault = document.getElementById("pd_" + etype); 212 | if (preventDefault.checked && e.preventDefault) { 213 | e.preventDefault(); 214 | } 215 | var stopPropagation = document.getElementById("sp_" + etype); 216 | if (stopPropagation.checked && e.stopPropagation) { 217 | e.stopPropagation(); 218 | } 219 | // Always prevent default for Tab. 220 | if (e.keyCode == 9 || e.code == "Tab") { 221 | e.preventDefault(); 222 | } 223 | } 224 | 225 | function getModifierState(e) { 226 | Modifiers = [ 227 | "Alt", "AltGraph", "Control", "Shift", "Meta", 228 | // Locking keys 229 | "CapsLock", "NumLock", "ScrollLock", 230 | // Linux 231 | "Hyper", "Super", 232 | // Virtual keyboards 233 | "Symbol", "SymbolLock", 234 | // Not valid, but check anyway 235 | "Fn", "FnLock", 236 | ]; 237 | 238 | // Safari doesn't define getModifierState for mouse events. 239 | if (e.getModifierState === undefined) { 240 | return "Undefined"; 241 | } 242 | 243 | mods = undefined; 244 | for (var mod of Modifiers) { 245 | if (e.getModifierState(mod)) { 246 | if (!mods) { 247 | mods = mod; 248 | } else { 249 | mods += ", " + mod; 250 | } 251 | } 252 | } 253 | return mods; 254 | } 255 | 256 | function getEventPhase(e) { 257 | var p = e.eventPhase; 258 | var phase = '?'; 259 | if (p == 0) 260 | phase = 'None'; 261 | else if (p == 1) 262 | phase = 'Capturing'; 263 | else if (p == 2) 264 | phase = 'AtTarget'; 265 | else if (p == 3) 266 | phase = 'Bubbling'; 267 | return phase; 268 | } 269 | 270 | function calcString(data) { 271 | if (data === undefined) { 272 | return data; 273 | } 274 | return "'" + data + "'"; 275 | } 276 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [ 3 | "114929" 4 | ], 5 | "contacts": [ 6 | "siusin" 7 | ], 8 | "shortName": "uievents", 9 | "repo-type": "rec-track" 10 | } 11 | --------------------------------------------------------------------------------