interpreter.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. class ListenerMap {
  2. constructor(root) {
  3. // bubbling events can listen at the root element
  4. this.global = {};
  5. // non bubbling events listen at the element the listener was created at
  6. this.local = {};
  7. this.root = root;
  8. }
  9. create(event_name, element, handler, bubbles) {
  10. if (bubbles) {
  11. if (this.global[event_name] === undefined) {
  12. this.global[event_name] = {};
  13. this.global[event_name].active = 1;
  14. this.global[event_name].callback = handler;
  15. this.root.addEventListener(event_name, handler);
  16. } else {
  17. this.global[event_name].active++;
  18. }
  19. }
  20. else {
  21. const id = element.getAttribute("data-dioxus-id");
  22. if (!this.local[id]) {
  23. this.local[id] = {};
  24. }
  25. this.local[id][event_name] = handler;
  26. element.addEventListener(event_name, handler);
  27. }
  28. }
  29. remove(element, event_name, bubbles) {
  30. if (bubbles) {
  31. this.global[event_name].active--;
  32. if (this.global[event_name].active === 0) {
  33. this.root.removeEventListener(event_name, this.global[event_name].callback);
  34. delete this.global[event_name];
  35. }
  36. }
  37. else {
  38. const id = element.getAttribute("data-dioxus-id");
  39. delete this.local[id][event_name];
  40. if (this.local[id].length === 0) {
  41. delete this.local[id];
  42. }
  43. element.removeEventListener(event_name, handler);
  44. }
  45. }
  46. removeAllNonBubbling(element) {
  47. const id = element.getAttribute("data-dioxus-id");
  48. delete this.local[id];
  49. }
  50. }
  51. class Interpreter {
  52. constructor(root) {
  53. this.root = root;
  54. this.listeners = new ListenerMap(root);
  55. this.nodes = [root];
  56. this.stack = [root];
  57. this.handlers = {};
  58. this.templates = {};
  59. this.lastNodeWasText = false;
  60. }
  61. top() {
  62. return this.stack[this.stack.length - 1];
  63. }
  64. pop() {
  65. return this.stack.pop();
  66. }
  67. MountToRoot() {
  68. this.AppendChildren(this.stack.length - 1);
  69. }
  70. SetNode(id, node) {
  71. this.nodes[id] = node;
  72. }
  73. PushRoot(root) {
  74. const node = this.nodes[root];
  75. this.stack.push(node);
  76. }
  77. PopRoot() {
  78. this.stack.pop();
  79. }
  80. AppendChildren(many) {
  81. // let root = this.nodes[id];
  82. let root = this.stack[this.stack.length - 1 - many];
  83. let to_add = this.stack.splice(this.stack.length - many);
  84. for (let i = 0; i < many; i++) {
  85. root.appendChild(to_add[i]);
  86. }
  87. }
  88. ReplaceWith(root_id, m) {
  89. let root = this.nodes[root_id];
  90. let els = this.stack.splice(this.stack.length - m);
  91. if (is_element_node(root.nodeType)) {
  92. this.listeners.removeAllNonBubbling(root);
  93. }
  94. root.replaceWith(...els);
  95. }
  96. InsertAfter(root, n) {
  97. let old = this.nodes[root];
  98. let new_nodes = this.stack.splice(this.stack.length - n);
  99. old.after(...new_nodes);
  100. }
  101. InsertBefore(root, n) {
  102. let old = this.nodes[root];
  103. let new_nodes = this.stack.splice(this.stack.length - n);
  104. old.before(...new_nodes);
  105. }
  106. Remove(root) {
  107. let node = this.nodes[root];
  108. if (node !== undefined) {
  109. if (is_element_node(node)) {
  110. this.listeners.removeAllNonBubbling(node);
  111. }
  112. node.remove();
  113. }
  114. }
  115. CreateRawText(text) {
  116. this.stack.push(document.createTextNode(text));
  117. }
  118. CreateTextNode(text, root) {
  119. const node = document.createTextNode(text);
  120. this.nodes[root] = node;
  121. this.stack.push(node);
  122. }
  123. CreatePlaceholder(root) {
  124. let el = document.createElement("pre");
  125. el.hidden = true;
  126. this.stack.push(el);
  127. this.nodes[root] = el;
  128. }
  129. NewEventListener(event_name, root, bubbles, handler) {
  130. const element = this.nodes[root];
  131. element.setAttribute("data-dioxus-id", `${root}`);
  132. this.listeners.create(event_name, element, handler, bubbles);
  133. }
  134. RemoveEventListener(root, event_name, bubbles) {
  135. const element = this.nodes[root];
  136. element.removeAttribute(`data-dioxus-id`);
  137. this.listeners.remove(element, event_name, bubbles);
  138. }
  139. SetText(root, text) {
  140. this.nodes[root].textContent = text;
  141. }
  142. SetAttribute(id, field, value, ns) {
  143. const node = this.nodes[id];
  144. this.SetAttributeInner(node, field, value, ns);
  145. }
  146. SetAttributeInner(node, field, value, ns) {
  147. const name = field;
  148. if (ns === "style") {
  149. // ????? why do we need to do this
  150. if (node.style === undefined) {
  151. node.style = {};
  152. }
  153. node.style[name] = value;
  154. } else if (ns != null && ns != undefined) {
  155. node.setAttributeNS(ns, name, value);
  156. } else {
  157. switch (name) {
  158. case "value":
  159. if (value !== node.value) {
  160. node.value = value;
  161. }
  162. break;
  163. case "checked":
  164. node.checked = value === "true";
  165. break;
  166. case "selected":
  167. node.selected = value === "true";
  168. break;
  169. case "dangerous_inner_html":
  170. node.innerHTML = value;
  171. break;
  172. default:
  173. // https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
  174. if (value === "false" && bool_attrs.hasOwnProperty(name)) {
  175. node.removeAttribute(name);
  176. } else {
  177. node.setAttribute(name, value);
  178. }
  179. }
  180. }
  181. }
  182. RemoveAttribute(root, field, ns) {
  183. const name = field;
  184. const node = this.nodes[root];
  185. if (ns == "style") {
  186. node.style.removeProperty(name);
  187. } else if (ns !== null || ns !== undefined) {
  188. node.removeAttributeNS(ns, name);
  189. } else if (name === "value") {
  190. node.value = "";
  191. } else if (name === "checked") {
  192. node.checked = false;
  193. } else if (name === "selected") {
  194. node.selected = false;
  195. } else if (name === "dangerous_inner_html") {
  196. node.innerHTML = "";
  197. } else {
  198. node.removeAttribute(name);
  199. }
  200. }
  201. handleEdits(edits) {
  202. for (let template of edits.templates) {
  203. this.SaveTemplate(template);
  204. }
  205. for (let edit of edits.edits) {
  206. this.handleEdit(edit);
  207. }
  208. }
  209. SaveTemplate(template) {
  210. let roots = [];
  211. for (let root of template.roots) {
  212. roots.push(this.MakeTemplateNode(root));
  213. }
  214. this.templates[template.name] = roots;
  215. }
  216. MakeTemplateNode(node) {
  217. console.log("making template node", node);
  218. switch (node.type) {
  219. case "Text":
  220. return document.createTextNode(node.text);
  221. case "Dynamic":
  222. let dyn = document.createElement("pre");
  223. dyn.hidden = true;
  224. return dyn;
  225. case "DynamicText":
  226. return document.createTextNode("placeholder");
  227. case "Element":
  228. let el;
  229. if (node.namespace != null) {
  230. el = document.createElementNS(node.namespace, node.tag);
  231. } else {
  232. el = document.createElement(node.tag);
  233. }
  234. for (let attr of node.attrs) {
  235. if (attr.type == "Static") {
  236. this.SetAttributeInner(el, attr.name, attr.value, attr.namespace);
  237. }
  238. }
  239. for (let child of node.children) {
  240. el.appendChild(this.MakeTemplateNode(child));
  241. }
  242. return el;
  243. }
  244. }
  245. AssignId(path, id) {
  246. this.nodes[id] = this.LoadChild(path);
  247. }
  248. LoadChild(path) {
  249. // iterate through each number and get that child
  250. let node = this.stack[this.stack.length - 1];
  251. for (let i = 0; i < path.length; i++) {
  252. node = node.childNodes[path[i]];
  253. }
  254. return node;
  255. }
  256. HydrateText(path, value, id) {
  257. let node = this.LoadChild(path);
  258. if (node.nodeType == Node.TEXT_NODE) {
  259. node.textContent = value;
  260. } else {
  261. // replace with a textnode
  262. let text = document.createTextNode(value);
  263. node.replaceWith(text);
  264. node = text;
  265. }
  266. this.nodes[id] = node;
  267. }
  268. ReplacePlaceholder(path, m) {
  269. let els = this.stack.splice(this.stack.length - m);
  270. let node = this.LoadChild(path);
  271. node.replaceWith(...els);
  272. }
  273. LoadTemplate(name, index, id) {
  274. let node = this.templates[name][index].cloneNode(true);
  275. this.nodes[id] = node;
  276. this.stack.push(node);
  277. }
  278. handleEdit(edit) {
  279. switch (edit.type) {
  280. case "AppendChildren":
  281. this.AppendChildren(edit.m);
  282. break;
  283. case "AssignId":
  284. this.AssignId(edit.path, edit.id);
  285. break;
  286. case "CreatePlaceholder":
  287. this.CreatePlaceholder(edit.id);
  288. break;
  289. case "CreateTextNode":
  290. this.CreateTextNode(edit.value);
  291. break;
  292. case "HydrateText":
  293. this.HydrateText(edit.path, edit.value, edit.id);
  294. break;
  295. case "LoadTemplate":
  296. this.LoadTemplate(edit.name, edit.index, edit.id);
  297. break;
  298. case "PushRoot":
  299. this.PushRoot(edit.id);
  300. break;
  301. case "ReplaceWith":
  302. this.ReplaceWith(edit.id, edit.m);
  303. break;
  304. case "ReplacePlaceholder":
  305. this.ReplacePlaceholder(edit.path, edit.m);
  306. break;
  307. case "InsertAfter":
  308. this.InsertAfter(edit.id, edit.m);
  309. break;
  310. case "InsertBefore":
  311. this.InsertBefore(edit.id, edit.m);
  312. break;
  313. case "Remove":
  314. this.Remove(edit.id);
  315. break;
  316. case "SetText":
  317. this.SetText(edit.id, edit.value);
  318. break;
  319. case "SetAttribute":
  320. this.SetAttribute(edit.id, edit.name, edit.value, edit.ns);
  321. break;
  322. case "SetBoolAttribute":
  323. this.SetAttribute(edit.id, edit.name, edit.value, edit.ns);
  324. break;
  325. case "RemoveAttribute":
  326. this.RemoveAttribute(edit.id, edit.name, edit.ns);
  327. break;
  328. case "RemoveEventListener":
  329. this.RemoveEventListener(edit.id, edit.name);
  330. break;
  331. case "NewEventListener":
  332. let bubbles = event_bubbles(edit.name);
  333. // this handler is only provided on desktop implementations since this
  334. // method is not used by the web implementation
  335. let handler = (event) => {
  336. let target = event.target;
  337. if (target != null) {
  338. let realId = target.getAttribute(`data-dioxus-id`);
  339. let shouldPreventDefault = target.getAttribute(
  340. `dioxus-prevent-default`
  341. );
  342. if (event.type === "click") {
  343. // todo call prevent default if it's the right type of event
  344. if (shouldPreventDefault !== `onclick`) {
  345. if (target.tagName === "A") {
  346. event.preventDefault();
  347. const href = target.getAttribute("href");
  348. if (href !== "" && href !== null && href !== undefined) {
  349. window.ipc.postMessage(
  350. serializeIpcMessage("browser_open", { href })
  351. );
  352. }
  353. }
  354. }
  355. // also prevent buttons from submitting
  356. if (target.tagName === "BUTTON" && event.type == "submit") {
  357. event.preventDefault();
  358. }
  359. }
  360. // walk the tree to find the real element
  361. while (realId == null) {
  362. // we've reached the root we don't want to send an event
  363. if (target.parentElement === null) {
  364. return;
  365. }
  366. target = target.parentElement;
  367. realId = target.getAttribute(`data-dioxus-id`);
  368. }
  369. shouldPreventDefault = target.getAttribute(
  370. `dioxus-prevent-default`
  371. );
  372. let contents = serialize_event(event);
  373. if (shouldPreventDefault === `on${event.type}`) {
  374. event.preventDefault();
  375. }
  376. if (event.type === "submit") {
  377. event.preventDefault();
  378. }
  379. if (
  380. target.tagName === "FORM" &&
  381. (event.type === "submit" || event.type === "input")
  382. ) {
  383. for (let x = 0; x < target.elements.length; x++) {
  384. let element = target.elements[x];
  385. let name = element.getAttribute("name");
  386. if (name != null) {
  387. if (element.getAttribute("type") === "checkbox") {
  388. // @ts-ignore
  389. contents.values[name] = element.checked ? "true" : "false";
  390. } else if (element.getAttribute("type") === "radio") {
  391. if (element.checked) {
  392. contents.values[name] = element.value;
  393. }
  394. } else {
  395. // @ts-ignore
  396. contents.values[name] =
  397. element.value ?? element.textContent;
  398. }
  399. }
  400. }
  401. }
  402. if (realId === null) {
  403. return;
  404. }
  405. window.ipc.postMessage(
  406. serializeIpcMessage("user_event", {
  407. name: edit.name,
  408. element: parseInt(realId),
  409. data: contents,
  410. bubbles,
  411. })
  412. );
  413. }
  414. };
  415. this.NewEventListener(edit.name, edit.id, bubbles, handler);
  416. break;
  417. }
  418. }
  419. }
  420. function serialize_event(event) {
  421. switch (event.type) {
  422. case "copy":
  423. case "cut":
  424. case "past": {
  425. return {};
  426. }
  427. case "compositionend":
  428. case "compositionstart":
  429. case "compositionupdate": {
  430. let { data } = event;
  431. return {
  432. data,
  433. };
  434. }
  435. case "keydown":
  436. case "keypress":
  437. case "keyup": {
  438. let {
  439. charCode,
  440. key,
  441. altKey,
  442. ctrlKey,
  443. metaKey,
  444. keyCode,
  445. shiftKey,
  446. location,
  447. repeat,
  448. which,
  449. code,
  450. } = event;
  451. return {
  452. char_code: charCode,
  453. key: key,
  454. alt_key: altKey,
  455. ctrl_key: ctrlKey,
  456. meta_key: metaKey,
  457. key_code: keyCode,
  458. shift_key: shiftKey,
  459. location: location,
  460. repeat: repeat,
  461. which: which,
  462. code,
  463. };
  464. }
  465. case "focus":
  466. case "blur": {
  467. return {};
  468. }
  469. case "change": {
  470. let target = event.target;
  471. let value;
  472. if (target.type === "checkbox" || target.type === "radio") {
  473. value = target.checked ? "true" : "false";
  474. } else {
  475. value = target.value ?? target.textContent;
  476. }
  477. return {
  478. value: value,
  479. values: {},
  480. };
  481. }
  482. case "input":
  483. case "invalid":
  484. case "reset":
  485. case "submit": {
  486. let target = event.target;
  487. let value = target.value ?? target.textContent;
  488. if (target.type === "checkbox") {
  489. value = target.checked ? "true" : "false";
  490. }
  491. return {
  492. value: value,
  493. values: {},
  494. };
  495. }
  496. case "click":
  497. case "contextmenu":
  498. case "doubleclick":
  499. case "dblclick":
  500. case "drag":
  501. case "dragend":
  502. case "dragenter":
  503. case "dragexit":
  504. case "dragleave":
  505. case "dragover":
  506. case "dragstart":
  507. case "drop":
  508. case "mousedown":
  509. case "mouseenter":
  510. case "mouseleave":
  511. case "mousemove":
  512. case "mouseout":
  513. case "mouseover":
  514. case "mouseup": {
  515. const {
  516. altKey,
  517. button,
  518. buttons,
  519. clientX,
  520. clientY,
  521. ctrlKey,
  522. metaKey,
  523. offsetX,
  524. offsetY,
  525. pageX,
  526. pageY,
  527. screenX,
  528. screenY,
  529. shiftKey,
  530. } = event;
  531. return {
  532. alt_key: altKey,
  533. button: button,
  534. buttons: buttons,
  535. client_x: clientX,
  536. client_y: clientY,
  537. ctrl_key: ctrlKey,
  538. meta_key: metaKey,
  539. offset_x: offsetX,
  540. offset_y: offsetY,
  541. page_x: pageX,
  542. page_y: pageY,
  543. screen_x: screenX,
  544. screen_y: screenY,
  545. shift_key: shiftKey,
  546. };
  547. }
  548. case "pointerdown":
  549. case "pointermove":
  550. case "pointerup":
  551. case "pointercancel":
  552. case "gotpointercapture":
  553. case "lostpointercapture":
  554. case "pointerenter":
  555. case "pointerleave":
  556. case "pointerover":
  557. case "pointerout": {
  558. const {
  559. altKey,
  560. button,
  561. buttons,
  562. clientX,
  563. clientY,
  564. ctrlKey,
  565. metaKey,
  566. pageX,
  567. pageY,
  568. screenX,
  569. screenY,
  570. shiftKey,
  571. pointerId,
  572. width,
  573. height,
  574. pressure,
  575. tangentialPressure,
  576. tiltX,
  577. tiltY,
  578. twist,
  579. pointerType,
  580. isPrimary,
  581. } = event;
  582. return {
  583. alt_key: altKey,
  584. button: button,
  585. buttons: buttons,
  586. client_x: clientX,
  587. client_y: clientY,
  588. ctrl_key: ctrlKey,
  589. meta_key: metaKey,
  590. page_x: pageX,
  591. page_y: pageY,
  592. screen_x: screenX,
  593. screen_y: screenY,
  594. shift_key: shiftKey,
  595. pointer_id: pointerId,
  596. width: width,
  597. height: height,
  598. pressure: pressure,
  599. tangential_pressure: tangentialPressure,
  600. tilt_x: tiltX,
  601. tilt_y: tiltY,
  602. twist: twist,
  603. pointer_type: pointerType,
  604. is_primary: isPrimary,
  605. };
  606. }
  607. case "select": {
  608. return {};
  609. }
  610. case "touchcancel":
  611. case "touchend":
  612. case "touchmove":
  613. case "touchstart": {
  614. const { altKey, ctrlKey, metaKey, shiftKey } = event;
  615. return {
  616. // changed_touches: event.changedTouches,
  617. // target_touches: event.targetTouches,
  618. // touches: event.touches,
  619. alt_key: altKey,
  620. ctrl_key: ctrlKey,
  621. meta_key: metaKey,
  622. shift_key: shiftKey,
  623. };
  624. }
  625. case "scroll": {
  626. return {};
  627. }
  628. case "wheel": {
  629. const { deltaX, deltaY, deltaZ, deltaMode } = event;
  630. return {
  631. delta_x: deltaX,
  632. delta_y: deltaY,
  633. delta_z: deltaZ,
  634. delta_mode: deltaMode,
  635. };
  636. }
  637. case "animationstart":
  638. case "animationend":
  639. case "animationiteration": {
  640. const { animationName, elapsedTime, pseudoElement } = event;
  641. return {
  642. animation_name: animationName,
  643. elapsed_time: elapsedTime,
  644. pseudo_element: pseudoElement,
  645. };
  646. }
  647. case "transitionend": {
  648. const { propertyName, elapsedTime, pseudoElement } = event;
  649. return {
  650. property_name: propertyName,
  651. elapsed_time: elapsedTime,
  652. pseudo_element: pseudoElement,
  653. };
  654. }
  655. case "abort":
  656. case "canplay":
  657. case "canplaythrough":
  658. case "durationchange":
  659. case "emptied":
  660. case "encrypted":
  661. case "ended":
  662. case "error":
  663. case "loadeddata":
  664. case "loadedmetadata":
  665. case "loadstart":
  666. case "pause":
  667. case "play":
  668. case "playing":
  669. case "progress":
  670. case "ratechange":
  671. case "seeked":
  672. case "seeking":
  673. case "stalled":
  674. case "suspend":
  675. case "timeupdate":
  676. case "volumechange":
  677. case "waiting": {
  678. return {};
  679. }
  680. case "toggle": {
  681. return {};
  682. }
  683. default: {
  684. return {};
  685. }
  686. }
  687. }
  688. function serializeIpcMessage(method, params = {}) {
  689. return JSON.stringify({ method, params });
  690. }
  691. const bool_attrs = {
  692. allowfullscreen: true,
  693. allowpaymentrequest: true,
  694. async: true,
  695. autofocus: true,
  696. autoplay: true,
  697. checked: true,
  698. controls: true,
  699. default: true,
  700. defer: true,
  701. disabled: true,
  702. formnovalidate: true,
  703. hidden: true,
  704. ismap: true,
  705. itemscope: true,
  706. loop: true,
  707. multiple: true,
  708. muted: true,
  709. nomodule: true,
  710. novalidate: true,
  711. open: true,
  712. playsinline: true,
  713. readonly: true,
  714. required: true,
  715. reversed: true,
  716. selected: true,
  717. truespeed: true,
  718. };
  719. function is_element_node(node) {
  720. return node.nodeType == 1;
  721. }
  722. function event_bubbles(event) {
  723. switch (event) {
  724. case "copy":
  725. return true;
  726. case "cut":
  727. return true;
  728. case "paste":
  729. return true;
  730. case "compositionend":
  731. return true;
  732. case "compositionstart":
  733. return true;
  734. case "compositionupdate":
  735. return true;
  736. case "keydown":
  737. return true;
  738. case "keypress":
  739. return true;
  740. case "keyup":
  741. return true;
  742. case "focus":
  743. return false;
  744. case "focusout":
  745. return true;
  746. case "focusin":
  747. return true;
  748. case "blur":
  749. return false;
  750. case "change":
  751. return true;
  752. case "input":
  753. return true;
  754. case "invalid":
  755. return true;
  756. case "reset":
  757. return true;
  758. case "submit":
  759. return true;
  760. case "click":
  761. return true;
  762. case "contextmenu":
  763. return true;
  764. case "doubleclick":
  765. return true;
  766. case "dblclick":
  767. return true;
  768. case "drag":
  769. return true;
  770. case "dragend":
  771. return true;
  772. case "dragenter":
  773. return false;
  774. case "dragexit":
  775. return false;
  776. case "dragleave":
  777. return true;
  778. case "dragover":
  779. return true;
  780. case "dragstart":
  781. return true;
  782. case "drop":
  783. return true;
  784. case "mousedown":
  785. return true;
  786. case "mouseenter":
  787. return false;
  788. case "mouseleave":
  789. return false;
  790. case "mousemove":
  791. return true;
  792. case "mouseout":
  793. return true;
  794. case "scroll":
  795. return false;
  796. case "mouseover":
  797. return true;
  798. case "mouseup":
  799. return true;
  800. case "pointerdown":
  801. return true;
  802. case "pointermove":
  803. return true;
  804. case "pointerup":
  805. return true;
  806. case "pointercancel":
  807. return true;
  808. case "gotpointercapture":
  809. return true;
  810. case "lostpointercapture":
  811. return true;
  812. case "pointerenter":
  813. return false;
  814. case "pointerleave":
  815. return false;
  816. case "pointerover":
  817. return true;
  818. case "pointerout":
  819. return true;
  820. case "select":
  821. return true;
  822. case "touchcancel":
  823. return true;
  824. case "touchend":
  825. return true;
  826. case "touchmove":
  827. return true;
  828. case "touchstart":
  829. return true;
  830. case "wheel":
  831. return true;
  832. case "abort":
  833. return false;
  834. case "canplay":
  835. return false;
  836. case "canplaythrough":
  837. return false;
  838. case "durationchange":
  839. return false;
  840. case "emptied":
  841. return false;
  842. case "encrypted":
  843. return true;
  844. case "ended":
  845. return false;
  846. case "error":
  847. return false;
  848. case "loadeddata":
  849. return false;
  850. case "loadedmetadata":
  851. return false;
  852. case "loadstart":
  853. return false;
  854. case "pause":
  855. return false;
  856. case "play":
  857. return false;
  858. case "playing":
  859. return false;
  860. case "progress":
  861. return false;
  862. case "ratechange":
  863. return false;
  864. case "seeked":
  865. return false;
  866. case "seeking":
  867. return false;
  868. case "stalled":
  869. return false;
  870. case "suspend":
  871. return false;
  872. case "timeupdate":
  873. return false;
  874. case "volumechange":
  875. return false;
  876. case "waiting":
  877. return false;
  878. case "animationstart":
  879. return true;
  880. case "animationend":
  881. return true;
  882. case "animationiteration":
  883. return true;
  884. case "transitionend":
  885. return true;
  886. case "toggle":
  887. return true;
  888. }
  889. return true;
  890. }