interpreter.js 23 KB

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