1
2
3
4
5
6
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
<!DOCTYPE html>
<title>MathMLElement GlobalEventHandlers</title>
<link rel="author" title="Brian Kardell" href="mailto:bkardell@igalia.com" />
<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
<link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-idl-attributes"/>
<link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-content-attributes"/>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/WebIDLParser.js"></script>
<script>
"use strict";
// The prefixed animation events are special; their event types are
// camel-case.
const prefixedAnimationAttributeToEventType = new Map([
["webkitanimationend", "webkitAnimationEnd"],
["webkitanimationiteration", "webkitAnimationIteration"],
["webkitanimationstart", "webkitAnimationStart"],
["webkittransitionend", "webkitTransitionEnd"],
]);
// basic pattern lifted from /html/webappapis/scripting/events/event-handler-all-global-events.html
promise_setup(async function() {
const res = await fetch("/interfaces/html.idl");
const htmlIDL = await res.text();
// Parsing the whole IDL file is slow, so use a small regexp to extract only
// the part that is relevant for this test.
const parsedHTMLIDL = WebIDL2.parse(htmlIDL.
match(/^interface mixin GlobalEventHandlers {[^{}]*};$/m)[0]);
const globalEventHandlers = parsedHTMLIDL.find(
idl => idl.name === "GlobalEventHandlers"
);
// onerror is too special
const names = globalEventHandlers.members
.map(member => member.name)
.filter(name => name !== "onerror");
for (const name of names) {
const withoutOn = name.substring(2);
promise_test(async () => {
const location = MathMLElement.prototype;
assert_true(
location.hasOwnProperty(name),
`${location.constructor.name} has an own property named "${name}"`
);
assert_false(
name in Element.prototype,
`Element.prototype must not contain a "${name}" property`
);
}, `${name}: must be on the appropriate locations for GlobalEventHandlers`);
promise_test(async () => {
const location = document.createElementNS(
"http://www.w3.org/1998/Math/MathML",
"math"
);
assert_equals(
location[name],
null,
`The default value of the property is null for a ${
location.constructor.name
} instance`
);
}, `${name}: the default value must be null`);
promise_test(async () => {
const div = document.createElement("div");
div.insertAdjacentHTML("beforeend", `<math ${name}="window.${name}Happened1 = true;"></math>`);
const compiledHandler = div.firstElementChild[name];
assert_equals(
typeof compiledHandler,
"function",
`The ${name} property must be a function`
);
compiledHandler();
assert_true(
window[`${name}Happened1`],
"Calling the handler must run the code"
);
}, `${name}: the content attribute must be compiled into a function as the corresponding property`);
promise_test(async () => {
const el = document.createElementNS(
"http://www.w3.org/1998/Math/MathML",
"math"
);
assert_equals(el[name], null, `The ${name} property must be null (no attribute)`);
el.setAttribute(name, `window.${name}Happened2 = true;`);
const compiledHandler = el[name];
assert_equals(
typeof compiledHandler,
"function",
`The ${name} property must be a function (set attribute)`
);
compiledHandler();
assert_true(
window[`${name}Happened2`],
"Calling the handler must run the code (set attribute)"
);
window[`${name}Happened2`] = false;
const clonedEl = el.cloneNode(true);
const clonedCompiledHandler = clonedEl[name];
assert_equals(
typeof clonedCompiledHandler,
"function",
`The ${name} property must be a function (clone node)`
);
clonedCompiledHandler();
assert_true(
window[`${name}Happened2`],
"Calling the handler must run the code (clone node)"
);
el.setAttribute(name, `window.${name}Happened3 = true;`);
const newCompiledHandler = el[name];
assert_equals(
typeof newCompiledHandler,
"function",
`The ${name} property must be a function (modify attribute)`
);
newCompiledHandler();
assert_true(
window[`${name}Happened3`],
"Calling the handler must run the code (modify attribute)"
);
el.removeAttribute(name);
assert_equals(el[name], null, `The ${name} property must be null (remove attribute)`);
}, `${name}: dynamic changes on the attribute`);
promise_test(async () => {
const element = document.createElementNS(
"http://www.w3.org/1998/Math/MathML",
"math"
);
let target = undefined;
element[name] = (e) => { target = e.currentTarget; }
let eventType = withoutOn;
if (prefixedAnimationAttributeToEventType.has(eventType)) {
eventType = prefixedAnimationAttributeToEventType.get(eventType);
}
element.dispatchEvent(new Event(eventType));
assert_equals(target, element, "The event must be fired at the <math> element");
}, `${name}: dispatching an Event at a <math> element must trigger element.${name}`);
}
});
</script>
|