├── CNAME ├── .gitignore ├── _config.yml ├── images ├── key.png ├── mouse.png ├── focus-blur.png └── _img-src.txt ├── download-test ├── auto-downloaded-image.png └── test.html ├── wheel-event-viewer.css ├── key-event-viewer.css ├── focus-event-viewer.css ├── wheel-event-viewer.html ├── README.md ├── mouse-event-viewer.html ├── index.css ├── key-event-viewer-ce.html ├── mouse-event-viewer-shadow.html ├── focus-event-viewer.html ├── key-event-viewer.html ├── mouse-event-viewer.css ├── shared.css ├── index.html ├── shared.js ├── mouse-event-viewer-core.js ├── window-size.html ├── mouse-event-viewer-shadow.js ├── output-table.js ├── wheel-event-viewer.js ├── options.js ├── focus-event-viewer.js ├── mouse-event-viewer-shared.js └── key-event-viewer.js /CNAME: -------------------------------------------------------------------------------- 1 | domeventviewer.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _ref/* 3 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate 2 | encoding: UTF-8 3 | -------------------------------------------------------------------------------- /images/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garykac/dom-event-viewer/HEAD/images/key.png -------------------------------------------------------------------------------- /images/mouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garykac/dom-event-viewer/HEAD/images/mouse.png -------------------------------------------------------------------------------- /images/focus-blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garykac/dom-event-viewer/HEAD/images/focus-blur.png -------------------------------------------------------------------------------- /download-test/auto-downloaded-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garykac/dom-event-viewer/HEAD/download-test/auto-downloaded-image.png -------------------------------------------------------------------------------- /wheel-event-viewer.css: -------------------------------------------------------------------------------- 1 | .hilite_target { 2 | background-color: #c0ffc0; 3 | padding: 0 10px; 4 | } 5 | 6 | #target { 7 | background-color: #c0ffc0; 8 | border: 1px solid black; 9 | margin: 10px 30px; 10 | padding: 20px; 11 | display: inline-block; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /images/_img-src.txt: -------------------------------------------------------------------------------- 1 | Mouse: 2 | https://www.pexels.com/photo/waiting-relax-lying-mouse-46966/ 3 | 4 | Key: 5 | https://www.pexels.com/photo/selective-photography-of-skeleton-key-hanging-217316/ 6 | 7 | Focus blur: 8 | https://pixabay.com/en/eyeglass-hand-bokeh-blur-building-2589290/ 9 | -------------------------------------------------------------------------------- /download-test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Auto-download image:

6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /key-event-viewer.css: -------------------------------------------------------------------------------- 1 | .keydown_row_hilight { 2 | background-color: #e0ffe0; 3 | } 4 | 5 | tr .keydown_row_hilight:hover { 6 | background-color: #e0e0e0; 7 | } 8 | 9 | .keydown_arrow:after { 10 | content: " ⬇"; 11 | } 12 | 13 | .keyup_arrow:after { 14 | content: " ⬆"; 15 | } 16 | 17 | .div_ce { 18 | border: 1px solid black; 19 | } 20 | -------------------------------------------------------------------------------- /focus-event-viewer.css: -------------------------------------------------------------------------------- 1 | .hilite_target_a { 2 | background-color: #c0ffc0; 3 | padding: 0 10px; 4 | } 5 | 6 | .hilite_target_b { 7 | background-color: #ffc0ff; 8 | padding: 0 10px; 9 | } 10 | 11 | .hilite_target_outer { 12 | background-color: #c0c0c0; 13 | padding: 0 10px; 14 | } 15 | 16 | .hilite_related_a { 17 | background-color: #e0ffe0; 18 | padding: 0 10px; 19 | } 20 | 21 | .hilite_related_b { 22 | background-color: #ffe0ff; 23 | padding: 0 10px; 24 | } 25 | 26 | .hilite_related_outer { 27 | background-color: #f0f0f0; 28 | padding: 0 10px; 29 | } 30 | 31 | .hilite_handler_a { 32 | background-color: #e0ffe0; 33 | padding: 0 10px; 34 | } 35 | 36 | .hilite_handler_b { 37 | background-color: #ffe0ff; 38 | padding: 0 10px; 39 | } 40 | 41 | .hilite_handler_outer { 42 | background-color: #f0f0f0; 43 | padding: 0 10px; 44 | } 45 | 46 | #outer { 47 | border: 1px solid black; 48 | background-color: #f0f0f0; 49 | padding: 10px 20px 5px 20px; 50 | } 51 | -------------------------------------------------------------------------------- /wheel-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Wheel Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | DOM Event Viewers 21 | 22 |

Wheel Event Viewer

23 | 24 |

UserAgent:

25 | 26 |
Scroll here
27 | 28 |

29 | 30 | Show Options 31 |

32 | 33 |
34 | 35 |
36 | 37 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dom event viewer 2 | 3 | A collection of tools for viewing and testing various DOM Events. 4 | 5 | To report a bug or a submit feature request for any of these tools, 6 | file an issue on Github. 7 | 8 | ### [Key Event Viewer](https://garykac.github.io/dom-event-viewer/key-event-viewer.html) 9 | 10 | View KeyboardEvents on a `` element: 11 | 12 | `keydown`, `keypress`, `keyup`, `textinput`, `beforeinput`, `input`, `compositionstart`, `compositionupdate`, `compositionend` 13 | 14 | #### [Key Event Viewer (for contenteditable)](https://garykac.github.io/dom-event-viewer/key-event-viewer-ce.html) 15 | 16 | Same as the standard Key Event Viewer except targetting a `
` element. 17 | 18 | ### [Mouse Event Viewer](https://garykac.github.io/dom-event-viewer/mouse-event-viewer.html) 19 | 20 | View MouseEvents on a set of overlapping `
`s: 21 | 22 | `mousedown`, `mouseenter`, `mouseleave`, `mousemove`, `mouseout`, `mouseover`, `mouseup` 23 | 24 | #### [Mouse Event Viewer (with shadow DOM)](https://garykac.github.io/dom-event-viewer/mouse-event-viewer-shadow.html) 25 | 26 | Same as the standard Mouse Event Viewer except with additional shadow DOM elements. 27 | 28 | ### [Focus Event Viewer](https://garykac.github.io/dom-event-viewer/focus-event-viewer.html) 29 | 30 | View FocusEvents between two edit fields: 31 | 32 | `blur`, `focus`, `focusin`, `focusout`, `DOMFocusIn`, `DOMFocusOut` 33 | -------------------------------------------------------------------------------- /mouse-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Mouse Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | DOM Event Viewers 22 | 23 |

Mouse Event Viewer

24 | 25 |

UserAgent:

26 | 27 |
A
B
C
28 | 29 |

30 | 31 | Show Options 32 |

33 | 34 |
35 | 36 |
37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-family: "Arial Black"; 3 | font-size: 24pt; 4 | text-align: center; 5 | } 6 | 7 | body { 8 | font-family: "Arial"; 9 | font-size: 10pt; 10 | margin: 40px auto; 11 | background-color: #ffffff; 12 | max-width: 800px; 13 | } 14 | 15 | img { 16 | padding: 0; 17 | margin: 0; 18 | display: block; 19 | vertical-align: top; 20 | } 21 | 22 | .container { 23 | display: flex; 24 | flex-direction: column; 25 | flex-wrap: nowrap; 26 | justify-content: flex-start; 27 | width: 100%; 28 | padding: 0; 29 | margin: 0; 30 | } 31 | 32 | .row { 33 | border: 1px solid black; 34 | border-collapse: collapse; 35 | display: flex; 36 | flex-direction: row; 37 | flex-wrap: nowrap; 38 | justify-content: flex-start; 39 | padding: 0; 40 | margin: 0; 41 | } 42 | 43 | .row:not(:first-child) { 44 | margin-top: -1px; 45 | } 46 | 47 | .sideimage { 48 | flex-basis: 100px; 49 | } 50 | 51 | .viewer-list { 52 | flex-basis: auto; 53 | } 54 | 55 | code { 56 | font-size: 10pt; 57 | font-style: bold; 58 | } 59 | 60 | .name { 61 | display: block; 62 | font-family: "Arial Black"; 63 | font-size: 16pt; 64 | font-style: bold; 65 | margin: 5px 10px; 66 | } 67 | 68 | .name a { 69 | text-decoration: none; 70 | } 71 | 72 | .name2 { 73 | display: block; 74 | font-family: "Arial Black"; 75 | font-size: 12pt; 76 | font-style: bold; 77 | margin: 5px 10px; 78 | } 79 | 80 | .name2 a { 81 | text-decoration: none; 82 | } 83 | 84 | .desc { 85 | display: block; 86 | margin: 5px 10px 8px 10px; 87 | } 88 | -------------------------------------------------------------------------------- /key-event-viewer-ce.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Keyboard Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | DOM Event Viewers 21 | 22 |

Keyboard Event Viewer for contenteditable

23 | 24 |

UserAgent:

25 | 26 |

div with contenteditable="true":

27 |
Initial text
28 | 29 |

30 | 31 | Show Options 32 |

33 | 34 |
35 | 36 | 37 |
38 | 39 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /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 | 19 | 20 | 21 | DOM Event Viewers 22 | 23 |

Mouse Event Viewer with shadow dom content

24 | 25 |

UserAgent:

26 | 27 |
A
B
C (host)
28 | 29 |

30 | 31 | Show Options 32 |

33 | 34 |
35 | 36 |
37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /focus-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Focus Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | DOM Event Viewers 21 | 22 |

Focus Event Viewer

23 | 24 |

UserAgent:

25 | 26 |
Outer 27 |

28 | A 29 | B 30 |

31 |
32 | 33 |

34 | 35 | Show Options 36 |

37 | 38 |
39 | 40 | 41 |
42 | 43 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /key-event-viewer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Keyboard Event Viewer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | DOM Event Viewers 21 | 22 |

Keyboard Event Viewer

23 | 24 |

UserAgent:

25 | 26 |

27 | input element with type="text": 28 |

29 |

30 | 31 | Show Options 32 | 33 | 34 |

35 | 36 |
37 | 38 | 39 |
40 | 41 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /mouse-event-viewer.css: -------------------------------------------------------------------------------- 1 | .hilite_div_a { 2 | background-color: #c0ffc0; 3 | padding: 0 10px; 4 | } 5 | 6 | .hilite_div_b { 7 | background-color: #ffc0ff; 8 | padding: 0 10px; 9 | } 10 | 11 | .hilite_div_c { 12 | background-color: #c0ffff; 13 | padding: 0 10px; 14 | } 15 | 16 | .hilite_div_d { 17 | background-color: #c0c0c0; 18 | padding: 0 10px; 19 | } 20 | 21 | .hilite_div_e { 22 | background-color: #808080; 23 | padding: 0 10px; 24 | } 25 | 26 | .hilite_related_a { 27 | background-color: #e0ffe0; 28 | padding: 0 10px; 29 | } 30 | 31 | .hilite_related_b { 32 | background-color: #ffe0ff; 33 | padding: 0 10px; 34 | } 35 | 36 | .hilite_related_c { 37 | background-color: #e0ffff; 38 | padding: 0 10px; 39 | } 40 | 41 | .hilite_related_d { 42 | background-color: #e0e0e0; 43 | padding: 0 10px; 44 | } 45 | 46 | .hilite_related_e { 47 | background-color: #a0a0a0; 48 | padding: 0 10px; 49 | } 50 | 51 | .hilite_handler_a { 52 | padding: 0 10px; 53 | } 54 | 55 | .hilite_handler_b { 56 | padding: 0 10px; 57 | } 58 | 59 | .hilite_handler_c { 60 | padding: 0 10px; 61 | } 62 | 63 | #div_a { 64 | background-color: #c0ffc0; 65 | border-left: 1px solid black; 66 | border-top: 1px solid black; 67 | border-bottom: 1px solid black; 68 | margin-left: 30px; 69 | padding: 10px 0 10px 10px; 70 | display: inline-block; 71 | } 72 | 73 | #div_b { 74 | background-color: #ffc0ff; 75 | border-left: 1px solid black; 76 | border-top: 1px solid black; 77 | border-bottom: 1px solid black; 78 | margin: 10px 0 10px 10px; 79 | padding: 10px 0 10px 10px; 80 | display: inline-block; 81 | } 82 | 83 | #div_c { 84 | background-color: #c0ffff; 85 | border-left: 1px solid black; 86 | border-top: 1px solid black; 87 | border-bottom: 1px solid black; 88 | margin: 10px 0 10px 10px; 89 | padding: 10px 0 10px 10px; 90 | display: inline-block; 91 | min-width: 200px; 92 | min-height: 30px; 93 | } 94 | -------------------------------------------------------------------------------- /shared.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-family: "Arial Black"; 3 | font-size: 20pt; 4 | } 5 | 6 | .subtitle { 7 | font-size: 12pt; 8 | font-style: italic; 9 | } 10 | 11 | body { 12 | font-family: "Arial"; 13 | font-size: 10pt; 14 | margin: 10px; 15 | padding: 0 20px; 16 | background-color: #ffffff; 17 | } 18 | 19 | .main_link { 20 | float: right; 21 | border: 1px solid black; 22 | border-radius: 4px; 23 | font-size: 9pt; 24 | padding: 2px 4px; 25 | text-decoration: none; 26 | background-color: #e0e0ff; 27 | } 28 | 29 | /* Options table */ 30 | 31 | #options { 32 | display: none; 33 | margin: 20px; 34 | } 35 | 36 | #optionstoggle { 37 | font-size: 10pt; 38 | } 39 | 40 | .opttable { 41 | border: 1px solid black; 42 | } 43 | 44 | .optcell { 45 | vertical-align: top; 46 | padding: 0 10px; 47 | } 48 | 49 | .opttitle { 50 | font-weight: bold; 51 | } 52 | 53 | input[type=checkbox]:disabled+label { 54 | color: #a0a0a0; 55 | } 56 | 57 | .showfieldoption { 58 | font-weight: normal; 59 | padding: 0 5px 0 5px; 60 | display: inline-block; 61 | min-width: 90px; 62 | text-align: center; 63 | } 64 | 65 | /* Event table */ 66 | 67 | .empty { 68 | background-color: #ffffff; 69 | } 70 | 71 | .subheader { 72 | font-size: 10pt; 73 | } 74 | 75 | .keycell { 76 | padding: 0 5px 0 5px; 77 | } 78 | 79 | .modOff { 80 | color: #ffd0d0; 81 | } 82 | 83 | .modOn { 84 | color: green; 85 | } 86 | 87 | .undef { 88 | color: #a0a0a0; 89 | } 90 | 91 | #output tr:hover, tr.highlight { 92 | background-color: #e0e0e0; 93 | } 94 | 95 | /* Common event highlighting */ 96 | .event_hilight { 97 | border: 1px solid #404040; 98 | border-radius: 4px; 99 | padding: 0 3px 0 3px; 100 | margin-left: 3px; 101 | } 102 | 103 | /* Fix for black background in Fullscreen (Chrome). */ 104 | 105 | html { 106 | background-color: #ffffff; 107 | } 108 | 109 | *:fullscreen, *:-webkit-full-screen, *:-moz-full-screen, *:-ms-fullscreen { 110 | background-color: rgba(255,255,255,0); 111 | width: 100%; 112 | height: 100%; 113 | } 114 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | DOM Event Viewing Tools 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

DOM Event Viewers

15 | 16 |
17 | 18 |
19 |
20 |
21 | Key Event Viewer 22 | View KeyboardEvents on a <input type="text"> element. 23 | keydown, keypress, keyup, textinput, beforeinput, input, compositionstart, compositionupdate, compositionend 24 | 25 | Key Event Viewer (for contenteditable) 26 | Same as the standard Key Event Viewer except targetting a <div contenteditable="true"> element. 27 |
28 |
29 | 30 |
31 |
32 |
33 | Mouse Event Viewer 34 | View MouseEvents on a set of overlapping <div>s. 35 | mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup 36 | 37 | Mouse Event Viewer (with shadow DOM) 38 | Same as the standard Mouse Event Viewer except with additional shadow DOM elements. 39 | 40 | Wheel Event Viewer 41 | View mouse scroll wheel events. 42 |
43 |
44 | 45 |
46 |
47 |
48 | Focus Event Viewer 49 | View FocusEvents between two <input> fields enclosed in a <div>. 50 | blur, focus, focusin, focusout, DOMFocusIn, DOMFocusOut 51 |
52 |
53 | 54 |
55 | 56 |

57 | To report a bug or a submit feature request for any of these tools, 58 | file an issue on Github. 59 |

60 | 61 |

62 | Interested in viewing dome vents? Try this search instead. 63 |

64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /shared.js: -------------------------------------------------------------------------------- 1 | // Shared helper 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | function clearChildren(e) { 5 | while (e.firstChild !== null) { 6 | e.removeChild(e.firstChild); 7 | } 8 | } 9 | 10 | function setText(e, text) { 11 | clearChildren(e); 12 | e.appendChild(document.createTextNode(text)); 13 | } 14 | 15 | function addEventListener(obj, etype, handler) { 16 | if (obj.addEventListener) { 17 | obj.addEventListener(etype, handler, false); 18 | } else if (obj.attachEvent) { 19 | obj.attachEvent("on" + etype, handler); 20 | } else { 21 | obj["on" + etype] = handler; 22 | } 23 | } 24 | 25 | function handleDefaultPropagation(etype, e) { 26 | var preventDefault = document.getElementById("pd_" + etype); 27 | if (preventDefault.checked && e.preventDefault) { 28 | e.preventDefault(); 29 | } 30 | var stopPropagation = document.getElementById("sp_" + etype); 31 | if (stopPropagation.checked && e.stopPropagation) { 32 | e.stopPropagation(); 33 | } 34 | // Always prevent default for Tab. 35 | if (e.keyCode == 9 || e.code == "Tab") { 36 | e.preventDefault(); 37 | } 38 | } 39 | 40 | function getModifierState(e) { 41 | Modifiers = [ 42 | "Alt", "AltGraph", "Control", "Shift", "Meta", 43 | // Locking keys 44 | "CapsLock", "NumLock", "ScrollLock", 45 | // Linux 46 | "Hyper", "Super", 47 | // Virtual keyboards 48 | "Symbol", "SymbolLock", 49 | // Not valid, but check anyway 50 | "Fn", "FnLock", 51 | ]; 52 | 53 | // Safari doesn't define getModifierState for mouse events. 54 | if (e.getModifierState === undefined) { 55 | return "Undefined"; 56 | } 57 | 58 | mods = undefined; 59 | for (var mod of Modifiers) { 60 | if (e.getModifierState(mod)) { 61 | if (!mods) { 62 | mods = mod; 63 | } else { 64 | mods += ", " + mod; 65 | } 66 | } 67 | } 68 | return mods; 69 | } 70 | 71 | function getEventPhase(e) { 72 | var p = e.eventPhase; 73 | var phase = '?'; 74 | if (p == 0) 75 | phase = 'None'; 76 | else if (p == 1) 77 | phase = 'Capturing'; 78 | else if (p == 2) 79 | phase = 'AtTarget'; 80 | else if (p == 3) 81 | phase = 'Bubbling'; 82 | return phase; 83 | } 84 | 85 | function calcString(data) { 86 | if (data === undefined) { 87 | return data; 88 | } 89 | return "'" + data + "'"; 90 | } 91 | 92 | function calcHilightString(eventType, data, addArrow) { 93 | if (data === undefined) { 94 | return null; 95 | } 96 | 97 | var keySpan = document.createElement("span"); 98 | var enableHilight = document.getElementById("hl_" + eventType); 99 | if (enableHilight && enableHilight.checked) { 100 | keySpan.classList.add("event_hilight"); 101 | keySpan.classList.add(eventType.toLowerCase() + "_hilight"); 102 | 103 | // Extra classes for keyboard event viewer. 104 | if (addArrow && (eventType == "keydown" || eventType == "keyup")) { 105 | keySpan.classList.add(eventType + "_arrow"); 106 | } 107 | } 108 | keySpan.textContent = data; 109 | return keySpan; 110 | } 111 | 112 | // CSS Stylesheet management 113 | 114 | function injectCustomCSS(event_info, table_info) { 115 | // Find style sheet to inject into. 116 | var sheet = undefined; 117 | for (var i = 0; i < document.styleSheets.length; i++) { 118 | if (document.styleSheets[i].title == "inject") { 119 | sheet = document.styleSheets[i]; 120 | } 121 | } 122 | 123 | if (sheet) { 124 | for (var event of event_info) { 125 | var ename = event[0]; 126 | var options = event[1][name]; 127 | var background = event[2]; 128 | if (background != "") { 129 | sheet.insertRule("." + ename.toLowerCase() + "_hilight { background: " + background + "; }", 0); 130 | } 131 | } 132 | 133 | for (var group of table_info) { 134 | var name = group[0]; 135 | var type = group[1]; 136 | var options = group[3]; 137 | if (options && options['header-background']) { 138 | var background = options['header-background']; 139 | var cssRule = "." + type + "_header { background-color: " + background + "; font-weight: bold; border: 1px solid black; }"; 140 | sheet.insertRule(cssRule, 0); 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /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 | ], { 11 | 'grouplabel': false, 12 | 'header-background': "#e0e0e0" 13 | }], 14 | 15 | // MouseEvent - Target 16 | ["Target", "target", [ 17 | ["A", "target", "text", {'style': 'hilite_div_a'}], 18 | ["B", "target", "text", {'style': 'hilite_div_b'}], 19 | ["C", "target", "text", {'style': 'hilite_div_c'}], 20 | ], { 21 | 'checked': true, 22 | 'header-background': "#ffffff" 23 | }], 24 | 25 | // MouseEvent - relatedTarget 26 | ["relatedTarget", "relatedTarget", [ 27 | ["rA", "relatedTarget", "text", {'style': 'hilite_related_a'}], 28 | ["rB", "relatedTarget", "text", {'style': 'hilite_related_b'}], 29 | ["rC", "relatedTarget", "text", {'style': 'hilite_related_c'}], 30 | ], { 31 | 'checked': false, 32 | 'header-background': "#ffffff" 33 | }], 34 | 35 | // MouseEvent - Handler 36 | ["Handler", "handler", [ 37 | ["hA", "handler", "text", {'style': 'hilite_handler_a'}], 38 | ["hB", "handler", "text", {'style': 'hilite_handler_b'}], 39 | ["hC", "handler", "text", {'style': 'hilite_handler_c'}], 40 | ], { 41 | 'checked': false, 42 | 'header-background': "#c0c0ff" 43 | }], 44 | 45 | // Event 46 | ["Event", "event", [ 47 | ["eventPhase", "event", "text"], 48 | ["bubbles", "event", "bool"], 49 | ["cancelable", "event", "bool"], 50 | ["defaultPrevented", "event", "bool"], 51 | ["composed", "event", "bool"], 52 | ["isTrusted", "event", "bool"], 53 | ["timeStamp", "event", "text"], 54 | ], { 55 | 'checked': false, 56 | 'header-background': "#a0ffff" 57 | }], 58 | 59 | // UIEvent 60 | ["UIEvent", "uievent", [ 61 | ["view", "uievent", "text"], 62 | ["detail", "uievent", "text"], 63 | ], { 64 | 'checked': false, 65 | 'header-background': "#ffffff" 66 | }], 67 | 68 | // MouseEvent - UI Events 69 | ["MouseEvent", "mouseevent", [ 70 | ["screenX", "mouseevent", "text"], 71 | ["screenY", "mouseevent", "text"], 72 | ["clientX", "mouseevent", "text"], 73 | ["clientY", "mouseevent", "text"], 74 | ], { 75 | 'checked': true, 76 | 'header-background': "#ffffc0" 77 | }], 78 | 79 | // PointerLock 80 | ["PointerLock", "plock", [ 81 | ["movementX", "plock", "text"], 82 | ["movementY", "plock", "text"], 83 | ], { 84 | 'checked': true, 85 | 'header-background': "#e0a0e0" 86 | }], 87 | 88 | // CSSOM 89 | ["CSSOM", "cssom", [ 90 | ["offsetX", "cssom", "text"], 91 | ["offsetY", "cssom", "text"], 92 | ["pageX", "cssom", "text"], 93 | ["pageY", "cssom", "text"], 94 | ["x", "cssom", "text"], 95 | ["y", "cssom", "text"], 96 | ], { 97 | 'checked': true, 98 | 'header-background': "#c0f0c0" 99 | }], 100 | 101 | // MouseEvent - UI Events 102 | ["Buttons", "buttons", [ 103 | ["button", "buttons", "text"], 104 | ["buttons", "buttons", "text"], 105 | ], { 106 | 'checked': true, 107 | 'header-background': "#e0e0e0" 108 | }], 109 | 110 | // KeyboardEvent - Modifiers 111 | ["Modifiers", "modifiers", [ 112 | ["getModifierState", "modifiers", "text"], 113 | ["shift", "modifiers", "bool"], 114 | ["ctrl", "modifiers", "bool"], 115 | ["alt", "modifiers", "bool"], 116 | ["meta", "modifiers", "bool"], 117 | ], { 118 | 'checked': true, 119 | 'header-background': "#ffc0c0" 120 | }], 121 | ]; 122 | 123 | function init() { 124 | init_shared(); 125 | 126 | var div_a = document.getElementById("div_a"); 127 | var div_b = document.getElementById("div_b"); 128 | var div_c = document.getElementById("div_c"); 129 | for (var div of [div_a, div_b, div_c]) { 130 | addEventListener(div, "mousedown", onMouseDown.bind(null, div)); 131 | addEventListener(div, "mouseenter", onMouseEnter.bind(null, div)); 132 | addEventListener(div, "mouseleave", onMouseLeave.bind(null, div)); 133 | addEventListener(div, "mousemove", onMouseMove.bind(null, div)); 134 | addEventListener(div, "mouseout", onMouseOut.bind(null, div)); 135 | addEventListener(div, "mouseover", onMouseOver.bind(null, div)); 136 | addEventListener(div, "mouseup", onMouseUp.bind(null, div)); 137 | addEventListener(div, "auxclick", onAuxClick.bind(null, div)); 138 | addEventListener(div, "click", onClick.bind(null, div)); 139 | addEventListener(div, "dblclick", onDblClick.bind(null, div)); 140 | addEventListener(div, "contextmenu", onContextMenu.bind(null, div)); 141 | } 142 | 143 | addEventListener(document.getElementById("body"), "keydown", onKeyDown); 144 | addEventListener(div_a, "contextmenu", onContextMenu); 145 | } 146 | -------------------------------------------------------------------------------- /window-size.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Window Size 6 | 7 | 8 | 9 | 60 | 61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |

Mouse click

74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | 87 | 88 | 89 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /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 | ], { 11 | 'grouplabel': false, 12 | 'header-background': "#e0e0e0" 13 | }], 14 | 15 | // MouseEvent - Target 16 | ["Target", "target", [ 17 | ["A", "target", "text", {'style': 'hilite_div_a'}], 18 | ["B", "target", "text", {'style': 'hilite_div_b'}], 19 | ["C", "target", "text", {'style': 'hilite_div_c'}], 20 | ["sD", "target", "text", {'style': 'hilite_div_d'}], 21 | ["sE", "target", "text", {'style': 'hilite_div_e'}], 22 | ], { 23 | 'checked': true, 24 | 'header-background': "#ffffff" 25 | }], 26 | 27 | // MouseEvent - relatedTarget 28 | ["relatedTarget", "relatedTarget", [ 29 | ["rA", "relatedTarget", "text", {'style': 'hilite_related_a'}], 30 | ["rB", "relatedTarget", "text", {'style': 'hilite_related_b'}], 31 | ["rC", "relatedTarget", "text", {'style': 'hilite_related_c'}], 32 | ["srD", "relatedTarget", "text", {'style': 'hilite_related_d'}], 33 | ["srE", "relatedTarget", "text", {'style': 'hilite_related_e'}], 34 | ], { 35 | 'checked': true, 36 | 'header-background': "#ffffff" 37 | }], 38 | 39 | // Event 40 | ["Event", "event", [ 41 | ["eventPhase", "event", "text"], 42 | ["bubbles", "event", "bool"], 43 | ["cancelable", "event", "bool"], 44 | ["defaultPrevented", "event", "bool"], 45 | ["composed", "event", "bool"], 46 | ["isTrusted", "event", "bool"], 47 | ["timeStamp", "event", "text"], 48 | ], { 49 | 'checked': false, 50 | 'header-background': "#a0ffff" 51 | }], 52 | 53 | // UIEvent 54 | ["UIEvent", "uievent", [ 55 | ["view", "uievent", "text"], 56 | ["detail", "uievent", "text"], 57 | ], { 58 | 'checked': false, 59 | 'header-background': "#e0e0e0" 60 | }], 61 | 62 | // MouseEvent - UI Events 63 | ["MouseEvent", "mouseevent", [ 64 | ["screenX", "mouseevent", "text"], 65 | ["screenY", "mouseevent", "text"], 66 | ["clientX", "mouseevent", "text"], 67 | ["clientY", "mouseevent", "text"], 68 | ], { 69 | 'checked': true, 70 | 'header-background': "#ffffc0" 71 | }], 72 | 73 | // PointerLock 74 | ["PointerLock", "plock", [ 75 | ["movementX", "plock", "text"], 76 | ["movementY", "plock", "text"], 77 | ], { 78 | 'checked': true, 79 | 'header-background': "#e0a0e0" 80 | }], 81 | 82 | // CSSOM 83 | ["CSSOM", "cssom", [ 84 | ["offsetX", "cssom", "text"], 85 | ["offsetY", "cssom", "text"], 86 | ["pageX", "cssom", "text"], 87 | ["pageY", "cssom", "text"], 88 | ["x", "cssom", "text"], 89 | ["y", "cssom", "text"], 90 | ], { 91 | 'checked': true, 92 | 'header-background': "#c0f0c0" 93 | }], 94 | 95 | // MouseEvent - UI Events 96 | ["Buttons", "buttons", [ 97 | ["button", "buttons", "text"], 98 | ["buttons", "buttons", "text"], 99 | ], { 100 | 'checked': true, 101 | 'header-background': "#e0e0e0" 102 | }], 103 | 104 | // KeyboardEvent - Modifiers 105 | ["Modifiers", "modifiers", [ 106 | ["getModifierState", "modifiers", "text"], 107 | ["shift", "modifiers", "bool"], 108 | ["ctrl", "modifiers", "bool"], 109 | ["alt", "modifiers", "bool"], 110 | ["meta", "modifiers", "bool"], 111 | ], { 112 | 'checked': true, 113 | 'header-background': "#ffc0c0" 114 | }], 115 | ]; 116 | 117 | function init() { 118 | init_shared(); 119 | 120 | var div_a = document.getElementById("div_a"); 121 | var div_b = document.getElementById("div_b"); 122 | var div_c = document.getElementById("div_c"); 123 | 124 | const shadow_root = div_c.attachShadow({ mode: 'open'}); 125 | shadow_root.innerHTML = 126 | '' + 138 | 'C (sHost)' + 139 | '
sD' + 140 | '
sE
' + 141 | '
'; 142 | var div_d = shadow_root.getElementById("div_d"); 143 | var div_e = shadow_root.getElementById("div_e"); 144 | 145 | for (var div of [div_a, div_b, div_c, div_d, div_e]) { 146 | addEventListener(div, "mousedown", onMouseDown.bind(null, div)); 147 | addEventListener(div, "mouseenter", onMouseEnter.bind(null, div)); 148 | addEventListener(div, "mouseleave", onMouseLeave.bind(null, div)); 149 | addEventListener(div, "mousemove", onMouseMove.bind(null, div)); 150 | addEventListener(div, "mouseout", onMouseOut.bind(null, div)); 151 | addEventListener(div, "mouseover", onMouseOver.bind(null, div)); 152 | addEventListener(div, "mouseup", onMouseUp.bind(null, div)); 153 | addEventListener(div, "auxclick", onAuxClick.bind(null, div)); 154 | addEventListener(div, "click", onClick.bind(null, div)); 155 | addEventListener(div, "dblclick", onDblClick.bind(null, div)); 156 | addEventListener(div, "contextmenu", onContextMenu.bind(null, div)); 157 | } 158 | 159 | addEventListener(document.getElementById("body"), "keydown", onKeyDown); 160 | addEventListener(div_a, "contextmenu", onContextMenu); 161 | } 162 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /wheel-event-viewer.js: -------------------------------------------------------------------------------- 1 | // Mouse event viewer - shared 2 | // Gary Kacmarcik - garykac@{gmail|google}.com 3 | 4 | var _wheel_event_info = [ 5 | ["mousedown", { 6 | 'preventDefault': {'checked': false}, 7 | 'stopPropagation': {}, 8 | 'ShowEvents': {}, 9 | 'Highlight': {'checked': false}, 10 | }, 11 | "#ccffcc"], 12 | ["mouseup", { 13 | 'preventDefault': {'checked': false}, 14 | 'stopPropagation': {}, 15 | 'ShowEvents': {}, 16 | 'Highlight': {'checked': false}, 17 | }, 18 | "#ffcccc"], 19 | ["wheel", { 20 | 'preventDefault': {'checked': true}, 21 | 'stopPropagation': {}, 22 | 'ShowEvents': {}, 23 | 'Highlight': {}, 24 | }, 25 | "#e0e0e0"], 26 | ]; 27 | 28 | var _wheel_table_info = [ 29 | // Unlabeled group 30 | ["", "etype", [ 31 | ["#", "etype", "text"], 32 | ["Event type", "etype", "html"], 33 | ], { 34 | 'grouplabel': false, 35 | 'header-background': "#e0e0e0" 36 | }], 37 | 38 | // Event 39 | ["Event", "event", [ 40 | ["eventPhase", "event", "text"], 41 | ["bubbles", "event", "bool"], 42 | ["cancelable", "event", "bool"], 43 | ["defaultPrevented", "event", "bool"], 44 | ["composed", "event", "bool"], 45 | ["isTrusted", "event", "bool"], 46 | ["timeStamp", "event", "text"], 47 | ], { 48 | 'checked': false, 49 | 'header-background': "#a0ffff" 50 | }], 51 | 52 | // UIEvent 53 | ["UIEvent", "uievent", [ 54 | ["view", "uievent", "text"], 55 | ["detail", "uievent", "text"], 56 | ], { 57 | 'checked': false, 58 | 'header-background': "#ffffff" 59 | }], 60 | 61 | // MouseEvent - UI Events 62 | ["MouseEvent", "mouseevent", [ 63 | ["screenX", "mouseevent", "text"], 64 | ["screenY", "mouseevent", "text"], 65 | ["clientX", "mouseevent", "text"], 66 | ["clientY", "mouseevent", "text"], 67 | ], { 68 | 'checked': true, 69 | 'header-background': "#ffffc0" 70 | }], 71 | 72 | // MouseEvent - UI Events 73 | ["Buttons", "buttons", [ 74 | ["button", "buttons", "text"], 75 | ["buttons", "buttons", "text"], 76 | ], { 77 | 'checked': true, 78 | 'header-background': "#e0e0e0" 79 | }], 80 | 81 | // WheelEvent - UI Events 82 | ["Wheel", "wheel", [ 83 | ["deltaX", "wheel", "text"], 84 | ["deltaY", "wheel", "text"], 85 | ["deltaZ", "wheel", "text"], 86 | ["deltaMode", "wheel", "text"], 87 | ], { 88 | 'checked': true, 89 | 'header-background': "#c0f0c0" 90 | }], 91 | ]; 92 | 93 | function setUserAgentText() { 94 | var userAgent = navigator.userAgent; 95 | uaDiv = document.getElementById("useragent"); 96 | setText(uaDiv, userAgent); 97 | } 98 | 99 | function resetTable() { 100 | clearTable(); 101 | initOutputTable(_wheel_table_info); 102 | } 103 | 104 | function init() { 105 | setUserAgentText(); 106 | var extra_options = [ 107 | ["text", "Note: Options apply to new events only."], 108 | ["text", "Press 'c' to Clear Table."], 109 | ]; 110 | createOptions(document.getElementById("options"), _wheel_event_info, _wheel_table_info, extra_options); 111 | injectCustomCSS(_wheel_event_info, _wheel_table_info); 112 | resetTable(); 113 | 114 | var target = document.getElementById("target"); 115 | addEventListener(target, "mousedown", onMouseDown); 116 | addEventListener(target, "mouseup", onMouseUp); 117 | addEventListener(target, "wheel", onWheel); 118 | 119 | addEventListener(document.getElementById("body"), "keydown", onKeyDown); 120 | addEventListener(target, "contextmenu", onContextMenu); 121 | } 122 | 123 | function onKeyDown(e) { 124 | if (e.code == "KeyC") { 125 | resetTable(); 126 | } 127 | } 128 | 129 | function onContextMenu(e) { 130 | e.preventDefault(); 131 | e.stopPropagation(); 132 | } 133 | 134 | function onMouseDown(e) { 135 | handleMouseEvent("mousedown", e); 136 | } 137 | 138 | function onMouseUp(e) { 139 | handleMouseEvent("mouseup", e); 140 | } 141 | 142 | function onWheel(e) { 143 | handleMouseEvent("wheel", e); 144 | } 145 | 146 | function handleMouseEvent(etype, e) { 147 | var show = document.getElementById("show_" + etype); 148 | if (show.checked) { 149 | addMouseEvent(etype, e); 150 | } 151 | handleDefaultPropagation(etype, e); 152 | } 153 | 154 | function addMouseEvent(etype, e) { 155 | if (!e) { 156 | e = window.event; 157 | } 158 | var target = e.target.id; 159 | var eventinfo = {}; 160 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 161 | 162 | eventinfo["eventPhase"] = getEventPhase(e); 163 | eventinfo["bubbles"] = e.bubbles; 164 | eventinfo["cancelable"] = e.cancelable; 165 | eventinfo["defaultPrevented"] = e.defaultPrevented; 166 | eventinfo["composed"] = e.composed; 167 | eventinfo["isTrusted"] = e.isTrusted; 168 | eventinfo["timeStamp"] = e.timeStamp; 169 | 170 | eventinfo["view"] = calcString(e.view !== null ? e.view.name : "null"); 171 | eventinfo["detail"] = e.detail; 172 | 173 | eventinfo["screenX"] = e.screenX; 174 | eventinfo["screenY"] = e.screenY; 175 | eventinfo["clientX"] = e.clientX; 176 | eventinfo["clientY"] = e.clientY; 177 | 178 | var button = "-"; 179 | if (etype == "mousedown" || etype == "mouseup") { 180 | button = e.button; 181 | } 182 | eventinfo["button"] = button; 183 | eventinfo["buttons"] = e.buttons; 184 | 185 | eventinfo["getModifierState"] = getModifierState(e); 186 | eventinfo["shift"] = e.shiftKey; 187 | eventinfo["ctrl"] = e.ctrlKey; 188 | eventinfo["alt"] = e.altKey; 189 | eventinfo["meta"] = e.metaKey; 190 | 191 | eventinfo["deltaX"] = e.deltaX; 192 | eventinfo["deltaY"] = e.deltaY; 193 | eventinfo["deltaZ"] = e.deltaZ; 194 | 195 | var deltaMode = "-"; 196 | if (etype == "wheel") { 197 | if (e.deltaMode == 0) 198 | deltaMode = "PIXEL"; 199 | else if (e.deltaMode == 1) 200 | deltaMode = "LINE"; 201 | else if (e.deltaMode == 2) 202 | deltaMode = "PAGE"; 203 | else 204 | deltaMode = "??? (" + e.deltaMode + ")"; 205 | } 206 | eventinfo["deltaMode"] = deltaMode; 207 | 208 | addEventToOutput(eventinfo); 209 | } 210 | -------------------------------------------------------------------------------- /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 | if (name == "Highlight" && (options.enabled == undefined || options.enabled)) { 29 | var classes = "event_hilight " + e.toLowerCase() + "_hilight"; 30 | if (options.class != undefined) 31 | classes += " " + options.class; 32 | options.class = classes; 33 | } 34 | options.onclick = 'onOptionClick(this)'; 35 | addOptionCheckbox(cell, prefix + e, e, options); 36 | } 37 | row.appendChild(cell); 38 | } 39 | 40 | cell = document.createElement('td'); 41 | cell.classList.add("optcell"); 42 | addOptionTitle(cell, "Show Fields"); 43 | for (var group of table_info) { 44 | var name = group[0]; 45 | var type = group[1]; 46 | var options = group[3]; 47 | options.enabled = true; 48 | options.class = type + "_header showfieldoption"; 49 | options.onclick = 'showFieldClick(this)'; 50 | if (name != "") { 51 | addOptionCheckbox(cell, "show_" + type, name, options); 52 | } 53 | } 54 | row.appendChild(cell); 55 | table.appendChild(row); 56 | 57 | if (extra != undefined && extra.length != 0) { 58 | var addTitle = true; 59 | for (var opt of extra) { 60 | row = document.createElement('tr'); 61 | cell = document.createElement('td'); 62 | cell.classList.add("optcell"); 63 | cell.setAttribute("colspan", "5"); 64 | 65 | if (addTitle) { 66 | addOptionTitle(cell, "General Options"); 67 | addTitle = false; 68 | } 69 | 70 | var type = opt[0]; 71 | if (type == "checkbox") { 72 | var name = opt[1]; 73 | var label = opt[2]; 74 | var options = opt[3]; 75 | if (options.onclick === undefined) { 76 | options.onclick = 'onOptionClick(this)'; 77 | } 78 | addOptionCheckbox(cell, name, label, options); 79 | } else if (type == "text") { 80 | var text = opt[1]; 81 | cell.appendChild(document.createTextNode(text)); 82 | } 83 | 84 | row.appendChild(cell); 85 | table.appendChild(row); 86 | } 87 | } 88 | 89 | options_div.appendChild(table); 90 | } 91 | 92 | function addOptionTitle(cell, title) { 93 | var span = document.createElement('span'); 94 | span.classList.add("opttitle"); 95 | span.textContent = title; 96 | cell.appendChild(span); 97 | cell.appendChild(document.createElement("br")); 98 | } 99 | 100 | function addOptionCheckbox(cell, id, text, options) { 101 | if (options.enabled === undefined) 102 | options.enabled = true; 103 | if (options.checked === undefined) 104 | options.checked = true; 105 | 106 | // Apply previously saved value (if any). 107 | var savedValue = window.localStorage.getItem(id); 108 | if (savedValue != null) { 109 | options.checked = (savedValue == "true"); 110 | } 111 | 112 | var input = document.createElement("input"); 113 | input.type = "checkbox"; 114 | input.id = id; 115 | input.checked = options.checked; 116 | input.disabled = !options.enabled; 117 | if (options.onclick != undefined && options.onclick != "") { 118 | input.setAttribute("onclick", options.onclick); 119 | } 120 | cell.appendChild(input); 121 | 122 | var label = document.createElement("label"); 123 | label.setAttribute("for", id); 124 | var span = document.createElement('span'); 125 | if (options.class !== undefined) { 126 | for (var c of options.class.split(' ')) { 127 | span.classList.add(c); 128 | } 129 | } 130 | span.appendChild(document.createTextNode(text)); 131 | label.appendChild(span); 132 | cell.appendChild(label); 133 | 134 | cell.appendChild(document.createElement("br")); 135 | } 136 | 137 | function addOptionText(cell, prefix, id, text) { 138 | var span1 = document.createElement('span'); 139 | span1.classList.add("opttext"); 140 | span1.appendChild(document.createTextNode(prefix)); 141 | 142 | var span2 = document.createElement('span'); 143 | span2.id = id; 144 | span2.textContent = 0; 145 | span1.appendChild(span2); 146 | span1.appendChild(document.createTextNode(text)); 147 | 148 | cell.appendChild(span1); 149 | cell.appendChild(document.createElement("br")); 150 | } 151 | 152 | function toggleOptions() { 153 | var link = document.getElementById("optionsToggle"); 154 | var options = document.getElementById("options"); 155 | clearChildren(link); 156 | if (options.style.display == "block") { 157 | options.style.display = "none"; 158 | link.appendChild(document.createTextNode("Show Options")); 159 | } 160 | else { 161 | options.style.display = "block"; 162 | link.appendChild(document.createTextNode("Hide Options")); 163 | } 164 | } 165 | 166 | function onOptionClick(cb) { 167 | window.localStorage.setItem(cb.id, cb.checked); 168 | } 169 | 170 | function showFieldClick(cb) { 171 | onOptionClick(cb); 172 | 173 | var celltype = cb.id.split('_')[1]; 174 | var show = cb.checked; 175 | 176 | var table = document.getElementById("output"); 177 | for (var ir = 0, row; row = table.rows[ir]; ir++) { 178 | for (var ic = 0, cell; cell = row.cells[ic]; ic++) { 179 | if (cell.classList.contains(celltype)) { 180 | if (show) { 181 | cell.style.display = ""; 182 | } else { 183 | cell.style.display = "none"; 184 | } 185 | } 186 | } 187 | } 188 | } 189 | 190 | -------------------------------------------------------------------------------- /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 | ], { 10 | 'grouplabel': false, 11 | 'header-background': "#e0e0e0" 12 | }], 13 | 14 | // Event - Target 15 | ["Target", "target", [ 16 | ["A", "target", "text", {'style': 'hilite_target_a'}], 17 | ["B", "target", "text", {'style': 'hilite_target_b'}], 18 | ["Outer", "target", "text", {'style': 'hilite_target_outer'}], 19 | ], { 20 | 'checked': true, 21 | 'header-background': "#ffffc0" 22 | }], 23 | 24 | // FocusEvent - relatedTarget 25 | ["relatedTarget", "focusevent", [ 26 | ["rA", "focusevent", "text", {'style': 'hilite_related_a'}], 27 | ["rB", "focusevent", "text", {'style': 'hilite_related_b'}], 28 | ["rOuter", "focusevent", "text", {'style': 'hilite_related_outer'}], 29 | ], { 30 | 'checked': true, 31 | 'header-background': "#c0ffff" 32 | }], 33 | 34 | // FocusEvent - Handler 35 | ["Handler", "handler", [ 36 | ["hA", "handler", "text", {'style': 'hilite_handler_a'}], 37 | ["hB", "handler", "text", {'style': 'hilite_handler_b'}], 38 | ["hOuter", "handler", "text", {'style': 'hilite_handler_outer'}], 39 | ], { 40 | 'checked': true, 41 | 'header-background': "#c0c0ff" 42 | }], 43 | ]; 44 | 45 | var _focus_event_info = [ 46 | ["blur", { 47 | 'preventDefault': {'checked': false}, 48 | 'stopPropagation': {'checked': false}, 49 | 'ShowEvents': {}, 50 | 'Highlight': {'checked': true}, 51 | }, 52 | "#ffa0a0"], 53 | ["focus", { 54 | 'preventDefault': {'checked': false}, 55 | 'stopPropagation': {'checked': false}, 56 | 'ShowEvents': {}, 57 | 'Highlight': {'checked': true}, 58 | }, 59 | "#a0ffa0"], 60 | ["focusin", { 61 | 'preventDefault': {'checked': false}, 62 | 'stopPropagation': {'checked': false}, 63 | 'ShowEvents': {}, 64 | 'Highlight': {'checked': false}, 65 | }, 66 | "#ccffcc"], 67 | ["focusout", { 68 | 'preventDefault': {'checked': false}, 69 | 'stopPropagation': {'checked': false}, 70 | 'ShowEvents': {}, 71 | 'Highlight': {'checked': false}, 72 | }, 73 | "#ffcccc"], 74 | ["DOMFocusIn", { 75 | 'preventDefault': {'checked': false}, 76 | 'stopPropagation': {'checked': false}, 77 | 'ShowEvents': {}, 78 | 'Highlight': {'checked': false}, 79 | }, 80 | "repeating-linear-gradient(-45deg, #cfc, #cfc 8px, #fff 8px, #fff 16px)"], 81 | ["DOMFocusOut", { 82 | 'preventDefault': {'checked': false}, 83 | 'stopPropagation': {'checked': false}, 84 | 'ShowEvents': {}, 85 | 'Highlight': {'checked': false}, 86 | }, 87 | "repeating-linear-gradient(-45deg, #fcc, #fcc 8px, #fff 8px, #fff 16px)"], 88 | ]; 89 | 90 | 91 | function setUserAgentText() { 92 | var userAgent = navigator.userAgent; 93 | uaDiv = document.getElementById("useragent"); 94 | setText(uaDiv, userAgent); 95 | } 96 | 97 | function resetTable(resetData=true) { 98 | // Reset focus first so the we clear out the events related to it. 99 | setInputFocus(resetData); 100 | 101 | clearTable(); 102 | initOutputTable(_focus_table_info); 103 | } 104 | 105 | function init() { 106 | setUserAgentText(); 107 | 108 | createOptions(document.getElementById("options"), _focus_event_info, _focus_table_info, []); 109 | injectCustomCSS(_focus_event_info, _focus_table_info); 110 | resetTable(false); 111 | 112 | var input_a = document.getElementById("input_a"); 113 | var input_b = document.getElementById("input_b"); 114 | var outer = document.getElementById("outer"); 115 | for (var div of [input_a, input_b, outer]) { 116 | addEventListener(div, "blur", onBlur.bind(null, div)); 117 | addEventListener(div, "focus", onFocus.bind(null, div)); 118 | addEventListener(div, "focusin", onFocusIn.bind(null, div)); 119 | addEventListener(div, "focusout", onFocusOut.bind(null, div)); 120 | addEventListener(div, "DOMFocusIn", onDomFocusIn.bind(null, div)); 121 | addEventListener(div, "DOMFocusOut", onDomFocusOut.bind(null, div)); 122 | } 123 | } 124 | 125 | // ===== 126 | // Focus events: blur, focusin, focusout 127 | // ===== 128 | 129 | function onBlur(handler, e) { 130 | handleFocusEvent("blur", handler, e); 131 | } 132 | 133 | function onFocus(handler, e) { 134 | handleFocusEvent("focus", handler, e); 135 | } 136 | 137 | function onFocusIn(handler, e) { 138 | handleFocusEvent("focusin", handler, e); 139 | } 140 | 141 | function onFocusOut(handler, e) { 142 | handleFocusEvent("focusout", handler, e); 143 | } 144 | 145 | function onDomFocusIn(handler, e) { 146 | handleFocusEvent("DOMFocusIn", handler, e); 147 | } 148 | 149 | function onDomFocusOut(handler, e) { 150 | handleFocusEvent("DOMFocusOut", handler, e); 151 | } 152 | 153 | function handleFocusEvent(etype, handler, e) { 154 | var show = document.getElementById("show_" + etype); 155 | if (show.checked) { 156 | addFocusEvent(etype, handler, e); 157 | } 158 | handleDefaultPropagation(etype, e); 159 | } 160 | 161 | function addFocusEvent(etype, handler, e) { 162 | if (!e) { 163 | e = window.event; 164 | } 165 | var target = e.target.id; 166 | var relatedTarget = e.relatedTarget ? e.relatedTarget.id : ""; 167 | var handler = handler.id; 168 | var eventinfo = {}; 169 | 170 | eventinfo["Event type"] = calcHilightString(etype, e.type); 171 | 172 | eventinfo["A"] = (target == "input_a" ? "A" : ""); 173 | eventinfo["B"] = (target == "input_b" ? "B" : ""); 174 | eventinfo["Outer"] = (target == "outer" ? "Outer" : ""); 175 | 176 | eventinfo["rA"] = (relatedTarget == "input_a" ? "A" : ""); 177 | eventinfo["rB"] = (relatedTarget == "input_b" ? "B" : ""); 178 | eventinfo["rOuter"] = (relatedTarget == "outer" ? "Outer" : ""); 179 | 180 | eventinfo["hA"] = (handler == "input_a" ? (handler == target ? "-" : "A") : ""); 181 | eventinfo["hB"] = (handler == "input_b" ? (handler == target ? "-" : "B") : ""); 182 | eventinfo["hOuter"] = (handler == "outer" ? (handler == target ? "-" : "Outer") : ""); 183 | 184 | addEventToOutput(eventinfo); 185 | } 186 | 187 | // ===== 188 | // Helper functions 189 | // ===== 190 | 191 | /* Set the focus to the input box. */ 192 | function setInputFocus(resetData) { 193 | var input = document.getElementById("input_a"); 194 | 195 | if (resetData) { 196 | input.value = ""; 197 | } 198 | 199 | // Set focus. 200 | input.focus(); 201 | } 202 | -------------------------------------------------------------------------------- /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': {}, 10 | }, 11 | "#e0e0e0"], 12 | ["mouseenter", { 13 | 'preventDefault': {'checked': false}, 14 | 'stopPropagation': {'enabled': false, 'checked': false}, 15 | 'ShowEvents': {}, 16 | 'Highlight': {}, 17 | }, 18 | "#ccffcc"], 19 | ["mouseleave", { 20 | 'preventDefault': {'checked': false}, 21 | 'stopPropagation': {'enabled': false, 'checked': false}, 22 | 'ShowEvents': {}, 23 | 'Highlight': {}, 24 | }, 25 | "#ffcccc"], 26 | ["mousemove", { 27 | 'preventDefault': {'checked': false}, 28 | 'stopPropagation': {}, 29 | 'ShowEvents': {}, 30 | 'Highlight': {'checked': false}, 31 | }, 32 | "#ffffff"], 33 | ["mouseout", { 34 | 'preventDefault': {'checked': false}, 35 | 'stopPropagation': {}, 36 | 'ShowEvents': {}, 37 | 'Highlight': {'checked': false}, 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}, 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': {}, 52 | }, 53 | "#e0e0e0"], 54 | ["auxclick", { 55 | 'preventDefault': {'checked': false}, 56 | 'stopPropagation': {}, 57 | 'ShowEvents': {}, 58 | 'Highlight': {}, 59 | }, 60 | "#ccccff"], 61 | ["click", { 62 | 'preventDefault': {'checked': false}, 63 | 'stopPropagation': {}, 64 | 'ShowEvents': {}, 65 | 'Highlight': {}, 66 | }, 67 | "#ccccff"], 68 | ["dblclick", { 69 | 'preventDefault': {'checked': false}, 70 | 'stopPropagation': {}, 71 | 'ShowEvents': {}, 72 | 'Highlight': {}, 73 | }, 74 | "#ccccff"], 75 | ["contextmenu", { 76 | 'preventDefault': {'checked': true}, 77 | 'stopPropagation': {}, 78 | 'ShowEvents': {}, 79 | 'Highlight': {}, 80 | }, 81 | "#ccffff"], 82 | ]; 83 | 84 | var _lastMouseMoveTarget = ""; 85 | var _mouseMoveCount = 0; 86 | 87 | function setUserAgentText() { 88 | var userAgent = navigator.userAgent; 89 | uaDiv = document.getElementById("useragent"); 90 | setText(uaDiv, userAgent); 91 | } 92 | 93 | function resetTable() { 94 | clearTable(); 95 | initOutputTable(_mouse_table_info); 96 | } 97 | 98 | function init_shared() { 99 | setUserAgentText(); 100 | var extra_options = [ 101 | ["checkbox", "combine_mousemove", "Combine mousemove events with same target", {}], 102 | ["text", "Note: Options apply to new events only."], 103 | ["text", "Press 'c' to Clear Table."], 104 | ]; 105 | createOptions(document.getElementById("options"), _mouse_event_info, _mouse_table_info, extra_options); 106 | injectCustomCSS(_mouse_event_info, _mouse_table_info); 107 | resetTable(); 108 | } 109 | 110 | function onKeyDown(e) { 111 | if (e.code == "KeyC") { 112 | resetTable(); 113 | _lastMouseMoveTarget = ""; 114 | } 115 | } 116 | 117 | function onContextMenu(handler, e) { 118 | handleMouseEvent("contextmenu", handler, e); 119 | } 120 | 121 | function onMouseDown(handler, e) { 122 | handleMouseEvent("mousedown", handler, e); 123 | } 124 | 125 | function onMouseEnter(handler, e) { 126 | handleMouseEvent("mouseenter", handler, e); 127 | } 128 | 129 | function onMouseLeave(handler, e) { 130 | handleMouseEvent("mouseleave", handler, e); 131 | } 132 | 133 | function onMouseMove(handler, e) { 134 | _mouseMoveCount++; 135 | var saveMouseMoveCount = _mouseMoveCount; 136 | 137 | // Combine duplicate move moves in the same target by removing last one. 138 | var combine = document.getElementById("combine_mousemove"); 139 | var show = document.getElementById("show_mousemove"); 140 | if (show.checked && combine.checked && _lastMouseMoveTarget == e.target.id) 141 | deleteLastOutputRow(); 142 | 143 | handleMouseEvent("mousemove", handler, e); 144 | 145 | _lastMouseMoveTarget = e.target.id; 146 | _mouseMoveCount = saveMouseMoveCount; 147 | } 148 | 149 | function onMouseOut(handler, e) { 150 | handleMouseEvent("mouseout", handler, e); 151 | } 152 | 153 | function onMouseOver(handler, e) { 154 | handleMouseEvent("mouseover", handler, e); 155 | } 156 | 157 | function onMouseUp(handler, e) { 158 | handleMouseEvent("mouseup", handler, e); 159 | } 160 | 161 | function onAuxClick(handler, e) { 162 | handleMouseEvent("auxclick", handler, e); 163 | } 164 | 165 | function onClick(handler, e) { 166 | handleMouseEvent("click", handler, e); 167 | } 168 | 169 | function onDblClick(handler, e) { 170 | handleMouseEvent("dblclick", handler, e); 171 | } 172 | 173 | function handleMouseEvent(etype, handler, e) { 174 | var show = document.getElementById("show_" + etype); 175 | if (show.checked) { 176 | addMouseEvent(etype, handler, e); 177 | } 178 | handleDefaultPropagation(etype, e); 179 | 180 | _lastMouseMoveTarget = ""; 181 | _mouseMoveCount = 0; 182 | } 183 | 184 | function addMouseEvent(etype, handler, e) { 185 | if (!e) { 186 | e = window.event; 187 | } 188 | var target = e.target.id; 189 | var relatedTarget = e.relatedTarget ? e.relatedTarget.id : ""; 190 | var handler = handler.id; 191 | var eventinfo = {}; 192 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 193 | eventinfo["Count"] = (etype == "mousemove" ? _mouseMoveCount : ""); 194 | 195 | eventinfo["A"] = (target == "div_a" ? "A" : ""); 196 | eventinfo["B"] = (target == "div_b" ? "B" : ""); 197 | eventinfo["C"] = (target == "div_c" ? "C" : ""); 198 | eventinfo["sD"] = (target == "div_d" ? "sD" : ""); 199 | eventinfo["sE"] = (target == "div_e" ? "sE" : ""); 200 | 201 | eventinfo["rA"] = (relatedTarget == "div_a" ? "A" : ""); 202 | eventinfo["rB"] = (relatedTarget == "div_b" ? "B" : ""); 203 | eventinfo["rC"] = (relatedTarget == "div_c" ? "C" : ""); 204 | eventinfo["srD"] = (relatedTarget == "div_d" ? "sD" : ""); 205 | eventinfo["srE"] = (relatedTarget == "div_e" ? "sE" : ""); 206 | 207 | eventinfo["hA"] = (handler == "div_a" ? (handler == target ? "-" : "A") : ""); 208 | eventinfo["hB"] = (handler == "div_b" ? (handler == target ? "-" : "B") : ""); 209 | eventinfo["hC"] = (handler == "div_c" ? (handler == target ? "-" : "C") : ""); 210 | 211 | eventinfo["eventPhase"] = getEventPhase(e); 212 | eventinfo["bubbles"] = e.bubbles; 213 | eventinfo["cancelable"] = e.cancelable; 214 | eventinfo["defaultPrevented"] = e.defaultPrevented; 215 | eventinfo["composed"] = e.composed; 216 | eventinfo["isTrusted"] = e.isTrusted; 217 | eventinfo["timeStamp"] = e.timeStamp; 218 | 219 | eventinfo["view"] = calcString(e.view !== null ? e.view.name : "null"); 220 | eventinfo["detail"] = e.detail; 221 | 222 | eventinfo["screenX"] = e.screenX; 223 | eventinfo["screenY"] = e.screenY; 224 | eventinfo["clientX"] = e.clientX; 225 | eventinfo["clientY"] = e.clientY; 226 | 227 | eventinfo["movementX"] = e.movementX; 228 | eventinfo["movementY"] = e.movementY; 229 | 230 | eventinfo["offsetX"] = e.offsetX; 231 | eventinfo["offsetY"] = e.offsetY; 232 | eventinfo["pageX"] = e.pageX; 233 | eventinfo["pageY"] = e.pageY; 234 | eventinfo["x"] = e.x; 235 | eventinfo["y"] = e.y; 236 | 237 | var button = "-"; 238 | if (etype == "mousedown" || etype == "mouseup") { 239 | button = e.button; 240 | } 241 | eventinfo["button"] = button; 242 | eventinfo["buttons"] = e.buttons; 243 | 244 | eventinfo["getModifierState"] = getModifierState(e); 245 | eventinfo["shift"] = e.shiftKey; 246 | eventinfo["ctrl"] = e.ctrlKey; 247 | eventinfo["alt"] = e.altKey; 248 | eventinfo["meta"] = e.metaKey; 249 | 250 | addEventToOutput(eventinfo); 251 | } 252 | -------------------------------------------------------------------------------- /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 | ], { 10 | 'grouplabel': false, 11 | 'header-background': "#e0e0e0" 12 | }], 13 | 14 | // KeyboardEvent - Legacy 15 | ["Legacy", "legacy", [ 16 | ["charCode", "legacy", "html"], 17 | ["keyCode", "legacy", "html"], 18 | ["which", "legacy", "text"], 19 | ], { 20 | 'checked': true, 21 | 'header-background': "#c0ffc0" 22 | }], 23 | 24 | // KeyboardEvent - Modifiers 25 | ["Modifiers", "modifiers", [ 26 | ["getModifierState", "modifiers", "text"], 27 | ["shift", "modifiers", "bool"], 28 | ["ctrl", "modifiers", "bool"], 29 | ["alt", "modifiers", "bool"], 30 | ["meta", "modifiers", "bool"], 31 | ], { 32 | 'checked': true, 33 | 'header-background': "#ffc0ff" 34 | }], 35 | 36 | // KeyboardEvent - Old DOM3 37 | ["Old DOM3", "olddom3", [ 38 | ["keyIdentifier", "olddom3", "text"], 39 | ["keyLocation", "olddom3", "text"], 40 | ["char", "olddom3", "text"], 41 | ], { 42 | 'checked': false, 43 | 'header-background': "#ffc0c0" 44 | }], 45 | 46 | // KeyboardEvent - UI Events 47 | ["UI Events", "uievents", [ 48 | ["key", "uievents", "html"], 49 | ["code", "uievents", "text"], 50 | ["location", "uievents", "text"], 51 | ["repeat", "uievents", "bool"], 52 | ["isComposing", "uievents", "bool"], 53 | ["inputType", "uievents", "text"], 54 | ["data", "uievents", "text"], 55 | ], { 56 | 'checked': true, 57 | 'header-background': "#c0ffff" 58 | }], 59 | 60 | // KeyboardEvent - Proposed 61 | ["Proposed", "proposed", [ 62 | ["locale", "proposed", "text"], 63 | ], { 64 | 'checked': false, 65 | 'header-background': "#ffffc0" 66 | }], 67 | 68 | // Input 69 | ["Input", "inputbox", [ 70 | ["Input field", "inputbox", "text", {'align': 'left'}], 71 | ], { 72 | 'checked': true, 73 | 'grouplabel': false, 74 | 'header-background': "#e0e0e0" 75 | }], 76 | ]; 77 | 78 | var _key_event_info = [ 79 | ["keydown", { 80 | 'preventDefault': {'checked': false}, 81 | 'stopPropagation': {}, 82 | 'ShowEvents': {}, 83 | 'Highlight': {'class': "keydown_arrow"}, 84 | }, 85 | "#c0ffc0"], 86 | ["keypress", { 87 | 'preventDefault': {'checked': false}, 88 | 'stopPropagation': {}, 89 | 'ShowEvents': {}, 90 | 'Highlight': {'checked': false}, 91 | }, 92 | "#c0c0ff"], 93 | ["keyup", { 94 | 'preventDefault': {'checked': false}, 95 | 'stopPropagation': {}, 96 | 'ShowEvents': {}, 97 | 'Highlight': {'class': "keyup_arrow"}, 98 | }, 99 | "#ffc0c0"], 100 | ["textinput", { 101 | 'preventDefault': {'checked': false}, 102 | 'stopPropagation': {'checked': false}, 103 | 'ShowEvents': {'checked': false}, 104 | 'Highlight': {'enabled': false, 'checked': false}, 105 | }, 106 | ""], 107 | ["beforeinput", { 108 | 'preventDefault': {'checked': false}, 109 | 'stopPropagation': {}, 110 | 'ShowEvents': {}, 111 | 'Highlight': {'enabled': false, 'checked': false}, 112 | }, 113 | "repeating-linear-gradient(-45deg, #fcc, #fcc 8px, #fff 8px, #fff 16px)"], 114 | ["input", { 115 | 'preventDefault': {'checked': false}, 116 | 'stopPropagation': {}, 117 | 'ShowEvents': {}, 118 | 'Highlight': {'enabled': false, 'checked': false}, 119 | }, 120 | "repeating-linear-gradient(-45deg, #cfc, #cfc 8px, #fff 8px, #fff 16px)"], 121 | ["compositionstart", { 122 | 'preventDefault': {'checked': false}, 123 | 'stopPropagation': {}, 124 | 'ShowEvents': {}, 125 | 'Highlight': {'enabled': false, 'checked': false}, 126 | }, 127 | "#e0e0e0"], 128 | ["compositionupdate", { 129 | 'preventDefault': {'checked': false}, 130 | 'stopPropagation': {}, 131 | 'ShowEvents': {}, 132 | 'Highlight': {'enabled': false, 'checked': false}, 133 | }, 134 | "#e0e0e0"], 135 | ["compositionend", { 136 | 'preventDefault': {'checked': false}, 137 | 'stopPropagation': {}, 138 | 'ShowEvents': {}, 139 | 'Highlight': {'enabled': false, 'checked': false}, 140 | }, 141 | "#e0e0e0"], 142 | ]; 143 | 144 | 145 | // True if the current row is a 'keydown' event. 146 | // This is used to set the background for the entire row when 'keydown' events are 147 | // highlighted. 148 | var _isKeydown = false; 149 | 150 | function setUserAgentText() { 151 | var userAgent = navigator.userAgent; 152 | uaDiv = document.getElementById("useragent"); 153 | setText(uaDiv, userAgent); 154 | } 155 | 156 | function resetTable(resetData=true) { 157 | clearTable(); 158 | initOutputTable(_key_table_info); 159 | 160 | setInputFocus(resetData); 161 | } 162 | 163 | var _inFullscreen = false; 164 | 165 | function toggleFullscreen() { 166 | var button = document.getElementById("toggleFullscreen"); 167 | if (_inFullscreen) { 168 | document.exitFullscreen(); 169 | _inFullscreen = false; 170 | button.value = "Enter Fullscreen" 171 | } else { 172 | document.body.requestFullscreen(); 173 | _inFullscreen = true; 174 | button.value = "Exit Fullscreen" 175 | } 176 | } 177 | 178 | var _isKeyboardLock = false; 179 | 180 | function toggleKeyboardLock() { 181 | var button = document.getElementById("toggleKeyboardLock"); 182 | if (_isKeyboardLock) { 183 | navigator.keyboard.unlock(); 184 | _isKeyboardLock = false; 185 | button.value = "Enable KeyboardLock" 186 | } else { 187 | navigator.keyboard.lock(); 188 | _isKeyboardLock = true; 189 | button.value = "Disable KeyboardLock" 190 | } 191 | } 192 | 193 | function init() { 194 | setUserAgentText(); 195 | var extra_options = [ 196 | ["checkbox", "readonlyToggle", "Read only <input>", { 197 | 'onclick': "updateReadonly()", 198 | 'checked': false, 199 | }], 200 | ["text", "Note: Options apply to new events only."], 201 | ]; 202 | 203 | var isContentEditable = false; 204 | var el = document.getElementById("input"); 205 | if (el.tagName == "DIV") { 206 | isContentEditable = true; 207 | } 208 | 209 | // Remove read-only option for contenteditable. 210 | if (isContentEditable) { 211 | extra_options.shift(); 212 | } 213 | 214 | createOptions(document.getElementById("options"), _key_event_info, _key_table_info, extra_options); 215 | injectCustomCSS(_key_event_info, _key_table_info); 216 | if (!isContentEditable) { 217 | updateReadonly(); 218 | } 219 | resetTable(false); 220 | 221 | var input = document.getElementById("input"); 222 | addEventListener(input, "keydown", onKeyDown); 223 | addEventListener(input, "keypress", onKeyPress); 224 | addEventListener(input, "keyup", onKeyUp); 225 | addEventListener(input, "textInput", onTextInput); 226 | addEventListener(input, "textinput", onTextInput); // For IE9 227 | addEventListener(input, "beforeinput", onBeforeInput); 228 | addEventListener(input, "input", onInput); 229 | addEventListener(input, "compositionstart", onCompositionStart); 230 | addEventListener(input, "compositionupdate", onCompositionUpdate); 231 | addEventListener(input, "compositionend", onCompositionEnd); 232 | } 233 | 234 | // ===== 235 | // Key events: keydown, keypress, keyup 236 | // ===== 237 | 238 | function onKeyDown(e) { 239 | _isKeydown = true; 240 | handleKeyEvent("keydown", e); 241 | _isKeydown = false; 242 | } 243 | 244 | function onKeyPress(e) { 245 | handleKeyEvent("keypress", e); 246 | } 247 | 248 | function onKeyUp(e) { 249 | handleKeyEvent("keyup", e); 250 | } 251 | 252 | function handleKeyEvent(etype, e) { 253 | var show = document.getElementById("show_" + etype); 254 | if (show.checked) { 255 | addKeyEvent(etype, e); 256 | } 257 | handleDefaultPropagation(etype, e); 258 | } 259 | 260 | function addKeyEvent(etype, e) { 261 | if (!e) { 262 | e = window.event; 263 | } 264 | var eventinfo = {}; 265 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 266 | eventinfo["charCode"] = calcRichKeyVal(etype, "charCode", e.charCode); 267 | eventinfo["keyCode"] = calcRichKeyVal(etype, "keyCode", e.keyCode); 268 | eventinfo["which"] = e.which; 269 | eventinfo["getModifierState"] = getModifierState(e); 270 | eventinfo["shift"] = e.shiftKey; 271 | eventinfo["ctrl"] = e.ctrlKey; 272 | eventinfo["alt"] = e.altKey; 273 | eventinfo["meta"] = e.metaKey; 274 | eventinfo["keyIdentifier"] = e.keyIdentifier; 275 | eventinfo["keyLocation"] = calcLocation(e.keyLocation); 276 | eventinfo["char"] = calcString(e.char); 277 | eventinfo["key"] = calcHilightString(etype, e.key, false); 278 | eventinfo["code"] = e.code; 279 | eventinfo["location"] = calcLocation(e.location); 280 | eventinfo["repeat"] = e.repeat; 281 | eventinfo["isComposing"] = e.isComposing; 282 | eventinfo["Input field"] = calcInput(); 283 | 284 | extra_class = undefined; 285 | if (_isKeydown && document.getElementById("hl_keydown").checked) { 286 | extra_class = "keydown_row_hilight"; 287 | } 288 | addEventToOutput(eventinfo, extra_class); 289 | } 290 | 291 | // ===== 292 | // Input events: textinput, beforeinput, input 293 | // ===== 294 | 295 | function onTextInput(e) { 296 | handleInputEvent("textinput", e); 297 | } 298 | 299 | function onBeforeInput(e) { 300 | handleInputEvent("beforeinput", e); 301 | } 302 | 303 | function onInput(e) { 304 | handleInputEvent("input", e); 305 | } 306 | 307 | function handleInputEvent(etype, e) { 308 | var show = document.getElementById("show_" + etype); 309 | if (show.checked) { 310 | addInputEvent(etype, e); 311 | } 312 | handleDefaultPropagation(etype, e); 313 | } 314 | 315 | function addInputEvent(etype, e) { 316 | if (!e) { 317 | e = window.event; 318 | } 319 | var eventinfo = {}; 320 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 321 | eventinfo["isComposing"] = e.isComposing; 322 | eventinfo["inputType"] = e.inputType; 323 | eventinfo["data"] = calcString(e.data); 324 | eventinfo["Input field"] = calcInput(); 325 | addEventToOutput(eventinfo); 326 | } 327 | 328 | // ===== 329 | // Composition events: compositionstart, compositionupdate, compositionend 330 | // ===== 331 | 332 | function onCompositionStart(e) { 333 | handleCompositionEvent("compositionstart", e); 334 | } 335 | 336 | function onCompositionUpdate(e) { 337 | handleCompositionEvent("compositionupdate", e); 338 | } 339 | 340 | function onCompositionEnd(e) { 341 | handleCompositionEvent("compositionend", e); 342 | } 343 | 344 | function handleCompositionEvent(etype, e) { 345 | var show = document.getElementById("show_"+etype); 346 | if (show.checked) { 347 | addCompositionEvent(etype, e); 348 | } 349 | handleDefaultPropagation(etype, e); 350 | } 351 | 352 | function addCompositionEvent(etype, e) { 353 | if (!e) { 354 | e = window.event; 355 | } 356 | var eventinfo = {}; 357 | eventinfo["Event type"] = calcHilightString(etype, e.type, true); 358 | eventinfo["isComposing"] = e.isComposing; 359 | eventinfo["data"] = calcString(e.data); 360 | eventinfo["Input field"] = calcInput(); 361 | addEventToOutput(eventinfo); 362 | } 363 | 364 | // ===== 365 | // Helper functions 366 | // ===== 367 | 368 | function calcInput() { 369 | var el = document.getElementById("input"); 370 | var value = ""; 371 | if (el.tagName == "DIV") { 372 | // <div contenteditable> 373 | value = el.innerText; 374 | } else { 375 | // <input> 376 | value = el.value; 377 | } 378 | return "'" + value + "'"; 379 | } 380 | 381 | /* Set the focus to the input box. */ 382 | function setInputFocus(resetData) { 383 | var input = document.getElementById("input"); 384 | 385 | if (resetData) { 386 | if (input.tagName == "DIV") { 387 | // <div contenteditable> 388 | clearChildren(input); 389 | } else { 390 | // <input> 391 | input.value = ""; 392 | } 393 | } 394 | 395 | // Set focus. 396 | if (input.tagName == "DIV") { 397 | // <div contenteditable> 398 | var sel = window.getSelection(); 399 | var range = document.createRange(); 400 | //range.setStart(input, 0); 401 | //range.setEnd(input, 0); 402 | range.selectNodeContents(input); 403 | sel.removeAllRanges(); 404 | sel.addRange(range); 405 | } else { 406 | // <input> 407 | input.focus(); 408 | } 409 | } 410 | 411 | function calcLocation(loc) { 412 | if (loc == 1) return "LEFT"; 413 | if (loc == 2) return "RIGHT"; 414 | if (loc == 3) return "NUMPAD"; 415 | return loc; 416 | } 417 | 418 | function calcRichKeyVal(eventType, attrName, key) { 419 | if (key === undefined) { 420 | return null; 421 | } 422 | 423 | var keyString = String.fromCharCode(key); 424 | if (attrName == "keyCode") { 425 | // Don't even try to decipher keyCode unless it's alphanum. 426 | if (key < 32 || key > 90) { 427 | keyString = ""; 428 | } 429 | // ...or a modifier. 430 | switch (key) { 431 | case 16: keyString = "Shift"; break; 432 | case 17: keyString = "Control"; break; 433 | case 18: keyString = "Alt"; break; 434 | case 91: 435 | case 93: 436 | case 224: 437 | keyString = "Meta"; 438 | break; 439 | } 440 | } 441 | 442 | if (keyString != "" 443 | && ((eventType == "keypress" && attrName == "charCode") 444 | || ((eventType == "keydown" || eventType == "keyup") && attrName == "keyCode") 445 | ) 446 | ) { 447 | var data = document.createElement("span"); 448 | data.appendChild(document.createTextNode(key)); 449 | var keySpan = document.createElement("span"); 450 | if (document.getElementById("hl_" + eventType).checked) { 451 | keySpan.classList.add("event_hilight"); 452 | keySpan.classList.add(eventType + "_hilight"); 453 | } else { 454 | keyString = " " + keyString; 455 | } 456 | keySpan.textContent = keyString; 457 | data.appendChild(keySpan); 458 | return data; 459 | } 460 | return document.createTextNode(key); 461 | } 462 | 463 | function updateReadonly() { 464 | var cbReadonly = document.getElementById("readonlyToggle"); 465 | var input = document.getElementById("input"); 466 | if (cbReadonly.checked) { 467 | input.setAttribute('readonly', true); 468 | } else { 469 | input.removeAttribute('readonly'); 470 | } 471 | onOptionClick(cbReadonly); 472 | setInputFocus(false); 473 | } 474 | --------------------------------------------------------------------------------