EventTarget.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. "use strict";
  2. const conversions = require("webidl-conversions");
  3. const utils = require("./utils.js");
  4. const EventListener = require("./EventListener.js");
  5. const AddEventListenerOptions = require("./AddEventListenerOptions.js");
  6. const EventListenerOptions = require("./EventListenerOptions.js");
  7. const Event = require("./Event.js");
  8. const implSymbol = utils.implSymbol;
  9. const ctorRegistrySymbol = utils.ctorRegistrySymbol;
  10. const interfaceName = "EventTarget";
  11. exports.is = value => {
  12. return utils.isObject(value) && Object.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
  13. };
  14. exports.isImpl = value => {
  15. return utils.isObject(value) && value instanceof Impl.implementation;
  16. };
  17. exports.convert = (globalObject, value, { context = "The provided value" } = {}) => {
  18. if (exports.is(value)) {
  19. return utils.implForWrapper(value);
  20. }
  21. throw new globalObject.TypeError(`${context} is not of type 'EventTarget'.`);
  22. };
  23. function makeWrapper(globalObject, newTarget) {
  24. let proto;
  25. if (newTarget !== undefined) {
  26. proto = newTarget.prototype;
  27. }
  28. if (!utils.isObject(proto)) {
  29. proto = globalObject[ctorRegistrySymbol]["EventTarget"].prototype;
  30. }
  31. return Object.create(proto);
  32. }
  33. exports.create = (globalObject, constructorArgs, privateData) => {
  34. const wrapper = makeWrapper(globalObject);
  35. return exports.setup(wrapper, globalObject, constructorArgs, privateData);
  36. };
  37. exports.createImpl = (globalObject, constructorArgs, privateData) => {
  38. const wrapper = exports.create(globalObject, constructorArgs, privateData);
  39. return utils.implForWrapper(wrapper);
  40. };
  41. exports._internalSetup = (wrapper, globalObject) => {};
  42. exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
  43. privateData.wrapper = wrapper;
  44. exports._internalSetup(wrapper, globalObject);
  45. Object.defineProperty(wrapper, implSymbol, {
  46. value: new Impl.implementation(globalObject, constructorArgs, privateData),
  47. configurable: true
  48. });
  49. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  50. if (Impl.init) {
  51. Impl.init(wrapper[implSymbol]);
  52. }
  53. return wrapper;
  54. };
  55. exports.new = (globalObject, newTarget) => {
  56. const wrapper = makeWrapper(globalObject, newTarget);
  57. exports._internalSetup(wrapper, globalObject);
  58. Object.defineProperty(wrapper, implSymbol, {
  59. value: Object.create(Impl.implementation.prototype),
  60. configurable: true
  61. });
  62. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  63. if (Impl.init) {
  64. Impl.init(wrapper[implSymbol]);
  65. }
  66. return wrapper[implSymbol];
  67. };
  68. const exposed = new Set(["Window", "Worker", "AudioWorklet"]);
  69. exports.install = (globalObject, globalNames) => {
  70. if (!globalNames.some(globalName => exposed.has(globalName))) {
  71. return;
  72. }
  73. const ctorRegistry = utils.initCtorRegistry(globalObject);
  74. class EventTarget {
  75. constructor() {
  76. return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
  77. }
  78. addEventListener(type, callback) {
  79. const esValue = this !== null && this !== undefined ? this : globalObject;
  80. if (!exports.is(esValue)) {
  81. throw new globalObject.TypeError(
  82. "'addEventListener' called on an object that is not a valid instance of EventTarget."
  83. );
  84. }
  85. if (arguments.length < 2) {
  86. throw new globalObject.TypeError(
  87. `Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only ${arguments.length} present.`
  88. );
  89. }
  90. const args = [];
  91. {
  92. let curArg = arguments[0];
  93. curArg = conversions["DOMString"](curArg, {
  94. context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 1",
  95. globals: globalObject
  96. });
  97. args.push(curArg);
  98. }
  99. {
  100. let curArg = arguments[1];
  101. if (curArg === null || curArg === undefined) {
  102. curArg = null;
  103. } else {
  104. curArg = EventListener.convert(globalObject, curArg, {
  105. context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 2"
  106. });
  107. }
  108. args.push(curArg);
  109. }
  110. {
  111. let curArg = arguments[2];
  112. if (curArg !== undefined) {
  113. if (curArg === null || curArg === undefined) {
  114. curArg = AddEventListenerOptions.convert(globalObject, curArg, {
  115. context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3"
  116. });
  117. } else if (utils.isObject(curArg)) {
  118. curArg = AddEventListenerOptions.convert(globalObject, curArg, {
  119. context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3" + " dictionary"
  120. });
  121. } else if (typeof curArg === "boolean") {
  122. curArg = conversions["boolean"](curArg, {
  123. context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3",
  124. globals: globalObject
  125. });
  126. } else {
  127. curArg = conversions["boolean"](curArg, {
  128. context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3",
  129. globals: globalObject
  130. });
  131. }
  132. }
  133. args.push(curArg);
  134. }
  135. return esValue[implSymbol].addEventListener(...args);
  136. }
  137. removeEventListener(type, callback) {
  138. const esValue = this !== null && this !== undefined ? this : globalObject;
  139. if (!exports.is(esValue)) {
  140. throw new globalObject.TypeError(
  141. "'removeEventListener' called on an object that is not a valid instance of EventTarget."
  142. );
  143. }
  144. if (arguments.length < 2) {
  145. throw new globalObject.TypeError(
  146. `Failed to execute 'removeEventListener' on 'EventTarget': 2 arguments required, but only ${arguments.length} present.`
  147. );
  148. }
  149. const args = [];
  150. {
  151. let curArg = arguments[0];
  152. curArg = conversions["DOMString"](curArg, {
  153. context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 1",
  154. globals: globalObject
  155. });
  156. args.push(curArg);
  157. }
  158. {
  159. let curArg = arguments[1];
  160. if (curArg === null || curArg === undefined) {
  161. curArg = null;
  162. } else {
  163. curArg = EventListener.convert(globalObject, curArg, {
  164. context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 2"
  165. });
  166. }
  167. args.push(curArg);
  168. }
  169. {
  170. let curArg = arguments[2];
  171. if (curArg !== undefined) {
  172. if (curArg === null || curArg === undefined) {
  173. curArg = EventListenerOptions.convert(globalObject, curArg, {
  174. context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3"
  175. });
  176. } else if (utils.isObject(curArg)) {
  177. curArg = EventListenerOptions.convert(globalObject, curArg, {
  178. context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3" + " dictionary"
  179. });
  180. } else if (typeof curArg === "boolean") {
  181. curArg = conversions["boolean"](curArg, {
  182. context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3",
  183. globals: globalObject
  184. });
  185. } else {
  186. curArg = conversions["boolean"](curArg, {
  187. context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3",
  188. globals: globalObject
  189. });
  190. }
  191. }
  192. args.push(curArg);
  193. }
  194. return esValue[implSymbol].removeEventListener(...args);
  195. }
  196. dispatchEvent(event) {
  197. const esValue = this !== null && this !== undefined ? this : globalObject;
  198. if (!exports.is(esValue)) {
  199. throw new globalObject.TypeError(
  200. "'dispatchEvent' called on an object that is not a valid instance of EventTarget."
  201. );
  202. }
  203. if (arguments.length < 1) {
  204. throw new globalObject.TypeError(
  205. `Failed to execute 'dispatchEvent' on 'EventTarget': 1 argument required, but only ${arguments.length} present.`
  206. );
  207. }
  208. const args = [];
  209. {
  210. let curArg = arguments[0];
  211. curArg = Event.convert(globalObject, curArg, {
  212. context: "Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1"
  213. });
  214. args.push(curArg);
  215. }
  216. return esValue[implSymbol].dispatchEvent(...args);
  217. }
  218. }
  219. Object.defineProperties(EventTarget.prototype, {
  220. addEventListener: { enumerable: true },
  221. removeEventListener: { enumerable: true },
  222. dispatchEvent: { enumerable: true },
  223. [Symbol.toStringTag]: { value: "EventTarget", configurable: true }
  224. });
  225. ctorRegistry[interfaceName] = EventTarget;
  226. Object.defineProperty(globalObject, interfaceName, {
  227. configurable: true,
  228. writable: true,
  229. value: EventTarget
  230. });
  231. };
  232. const Impl = require("../../jsdom/living/events/EventTarget-impl.js");