events.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import window from "../global/window";
  2. import data from "./data";
  3. import extend from "./extend";
  4. import DependencyLib from "./inputmask.dependencyLib";
  5. export { on, off, trigger, Evnt as Event };
  6. const document = window.document;
  7. function isValidElement(elem) {
  8. return elem instanceof Element && data(elem, "events");
  9. }
  10. let Evnt;
  11. if (typeof window.CustomEvent === "function") {
  12. Evnt = window.CustomEvent;
  13. } else if (window.Event && document && document.createEvent) {
  14. Evnt = function (event, params) {
  15. params = params || {
  16. bubbles: false,
  17. cancelable: false,
  18. composed: true,
  19. detail: undefined
  20. };
  21. const evt = document.createEvent("CustomEvent");
  22. evt.initCustomEvent(
  23. event,
  24. params.bubbles,
  25. params.cancelable,
  26. params.detail
  27. );
  28. return evt;
  29. };
  30. Evnt.prototype = window.Event.prototype;
  31. } else if (typeof Event !== "undefined") {
  32. // nodejs
  33. Evnt = Event;
  34. }
  35. function on(events, handler) {
  36. if (!this[0] || !isValidElement(this[0])) {
  37. return this; // Early return if no valid element
  38. }
  39. const elem = this[0],
  40. eventRegistry = data(elem, "events"),
  41. addEvent = (ev, namespace) => {
  42. // register domevent
  43. if (elem.addEventListener) {
  44. // all browsers except IE before version 9
  45. elem.addEventListener(ev, handler, false);
  46. } else if (elem.attachEvent) {
  47. // IE before version 9
  48. elem.attachEvent(`on${ev}`, handler);
  49. }
  50. eventRegistry[ev] = eventRegistry[ev] || {};
  51. eventRegistry[ev][namespace] = eventRegistry[ev][namespace] || [];
  52. eventRegistry[ev][namespace].push(handler);
  53. };
  54. events.split(" ").forEach((event) => {
  55. const [ev, namespace = "global"] = event.split(".");
  56. addEvent(ev, namespace);
  57. });
  58. return this;
  59. }
  60. function off(events, handler) {
  61. let eventRegistry, elem;
  62. function removeEvent(ev, namespace, handler) {
  63. if (ev in eventRegistry === true) {
  64. // unbind to dom events
  65. if (elem.removeEventListener) {
  66. // all browsers except IE before version 9
  67. elem.removeEventListener(ev, handler, false);
  68. } else if (elem.detachEvent) {
  69. // IE before version 9
  70. elem.detachEvent(`on${ev}`, handler);
  71. }
  72. // when the namespace is not defined (global namespace), we need to clean up all events in all namespaces
  73. if (namespace === "global") {
  74. for (const nmsp in eventRegistry[ev]) {
  75. eventRegistry[ev][nmsp].splice(
  76. eventRegistry[ev][nmsp].indexOf(handler),
  77. 1
  78. );
  79. }
  80. } else {
  81. eventRegistry[ev][namespace].splice(
  82. eventRegistry[ev][namespace].indexOf(handler),
  83. 1
  84. );
  85. }
  86. }
  87. }
  88. function resolveNamespace(ev, namespace) {
  89. const evts = [];
  90. let hndx, hndL;
  91. if (ev.length > 0) {
  92. const namespaces = namespace
  93. ? [namespace]
  94. : Object.keys(eventRegistry[ev]);
  95. for (let nsi = 0; nsi < namespaces.length; nsi++) {
  96. namespace = namespaces[nsi];
  97. if (handler === undefined) {
  98. for (
  99. hndx = 0, hndL = eventRegistry[ev][namespace]?.length || 0;
  100. hndx < hndL;
  101. hndx++
  102. ) {
  103. evts.push({
  104. ev,
  105. namespace,
  106. handler: eventRegistry[ev][namespace][hndx]
  107. });
  108. }
  109. } else {
  110. evts.push({
  111. ev,
  112. namespace,
  113. handler
  114. });
  115. }
  116. }
  117. } else if (namespace.length > 0) {
  118. for (const evNdx in eventRegistry) {
  119. if (eventRegistry[evNdx][namespace]) {
  120. if (handler === undefined) {
  121. for (
  122. hndx = 0, hndL = eventRegistry[evNdx][namespace].length;
  123. hndx < hndL;
  124. hndx++
  125. ) {
  126. evts.push({
  127. ev: evNdx,
  128. namespace,
  129. handler: eventRegistry[evNdx][namespace][hndx]
  130. });
  131. }
  132. } else {
  133. evts.push({
  134. ev: evNdx,
  135. namespace,
  136. handler
  137. });
  138. }
  139. }
  140. }
  141. }
  142. return evts;
  143. }
  144. if (isValidElement(this[0])) {
  145. eventRegistry = data(this[0], "events");
  146. elem = this[0];
  147. // if no events defined, remove all events
  148. events = events || Object.keys(eventRegistry).join(" ");
  149. if (events !== "") {
  150. events.split(" ").forEach((event) => {
  151. const [ev, namespace] = event.split(".");
  152. resolveNamespace(ev, namespace).forEach(
  153. ({ ev: ev1, handler: handler1, namespace: namespace1 }) => {
  154. removeEvent(ev1, namespace1, handler1);
  155. }
  156. );
  157. });
  158. }
  159. }
  160. return this;
  161. }
  162. function trigger(events /* , args... */) {
  163. if (isValidElement(this[0])) {
  164. const eventRegistry = data(this[0], "events"),
  165. elem = this[0],
  166. _events = typeof events === "string" ? events.split(" ") : [events.type];
  167. for (let endx = 0; endx < _events.length; endx++) {
  168. const nsEvent = _events[endx].split("."),
  169. ev = nsEvent[0],
  170. namespace = nsEvent[1] || "global";
  171. if (document !== undefined) {
  172. // trigger domevent
  173. let evnt;
  174. const params = {
  175. bubbles: true,
  176. cancelable: true,
  177. composed: true,
  178. detail: arguments[1]
  179. };
  180. // The custom event that will be created
  181. if (document.createEvent) {
  182. try {
  183. switch (ev) {
  184. case "input":
  185. params.inputType = "insertText";
  186. evnt = new InputEvent(ev, params);
  187. break;
  188. default:
  189. evnt = new CustomEvent(ev, params);
  190. }
  191. } catch (e) {
  192. evnt = document.createEvent("CustomEvent");
  193. evnt.initCustomEvent(
  194. ev,
  195. params.bubbles,
  196. params.cancelable,
  197. params.detail
  198. );
  199. }
  200. if (events.type) extend(evnt, events);
  201. elem.dispatchEvent(evnt);
  202. } else {
  203. evnt = document.createEventObject();
  204. evnt.eventType = ev;
  205. evnt.detail = arguments[1];
  206. if (events.type) extend(evnt, events);
  207. elem.fireEvent("on" + evnt.eventType, evnt);
  208. }
  209. } else if (eventRegistry[ev] !== undefined) {
  210. arguments[0] = arguments[0].type
  211. ? arguments[0]
  212. : DependencyLib.Event(arguments[0]);
  213. arguments[0].detail = arguments.slice(1);
  214. const registry = eventRegistry[ev],
  215. handlers =
  216. namespace === "global"
  217. ? Object.values(registry).flat()
  218. : registry[namespace];
  219. handlers.forEach((handler) => handler.apply(elem, arguments));
  220. }
  221. }
  222. }
  223. return this;
  224. }