All files / core/src eventTarget.ts

54.16% Statements 26/48
55.55% Branches 10/18
36.36% Functions 4/11
52.17% Lines 24/46

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                428x 428x                                             12766x 4854x       12766x 432x     12334x                                                                                                                 11000x 4738x     6262x 6262x   6262x 20170x 5388x   5388x           82420x   61249x     21171x 21171x   21171x 496748x 496748x           21171x             428x      
/**
 * EventTarget - Provides the [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) interface
 */
class CornerstoneEventTarget implements EventTarget {
  private listeners;
  private debouncedListeners;
 
  constructor() {
    this.listeners = {};
    this.debouncedListeners = {};
  }
 
  public reset() {
    this.listeners = {};
    this.debouncedListeners = {};
  }
 
  public addEventListenerOnce(type, callback) {
    // Create a wrapper function to encapsulate the original callback
    const onceWrapper = (event) => {
      // Remove the listener after its first invocation
      this.removeEventListener(type, onceWrapper);
 
      // Call the original callback
      callback.call(this, event);
    };
 
    // Add the wrapper as the listener
    this.addEventListener(type, onceWrapper);
  }
 
  public addEventListener(type, callback) {
    if (!this.listeners[type]) {
      this.listeners[type] = [];
    }
 
    // prevent multiple callbacks from firing
    if (this.listeners[type].indexOf(callback) !== -1) {
      return;
    }
 
    this.listeners[type].push(callback);
  }
 
  /**
   * Adds a debounced event listener to the event target.
   *
   * @param type - The type of the event to listen for.
   * @param callback - The callback function to be executed when the event is triggered.
   * @param delay - The delay in milliseconds before the callback is invoked after the last event.
   */
  public addEventListenerDebounced(type, callback, delay) {
    // Ensure the dictionary for the type exists
    this.debouncedListeners[type] = this.debouncedListeners[type] || {};
    const debouncedCallbacks = this.debouncedListeners[type];
 
    // Check if there's already a debounced version of this callback registered
    if (!debouncedCallbacks[callback]) {
      const handle = (event) => {
        // Clear any existing timeout to reset the debounce timer
        if (debouncedCallbacks[callback]) {
          clearTimeout(debouncedCallbacks[callback].timeoutId);
        }
 
        // Set a new timeout
        debouncedCallbacks[callback].timeoutId = setTimeout(() => {
          callback.call(this, event);
        }, delay);
      };
 
      // Store the handle and initial timeoutId (null initially)
      debouncedCallbacks[callback] = {
        original: callback,
        handle,
        timeoutId: null,
      };
 
      // Register the debounced handler
      this.addEventListener(type, handle);
    }
  }
 
  /**
   * Removes a debounced event listener from the event target.
   *
   * @param type - The type of the event.
   * @param callback - The callback function to be removed.
   */
  public removeEventListenerDebounced(type, callback) {
    if (this.debouncedListeners[type]?.[callback]) {
      const debounced = this.debouncedListeners[type][callback];
      this.removeEventListener(type, debounced.handle);
      clearTimeout(debounced.timeoutId);
      delete this.debouncedListeners[type][callback];
    }
  }
 
  public removeEventListener(type, callback) {
    if (!this.listeners[type]) {
      return;
    }
 
    const stack = this.listeners[type];
    const stackLength = stack.length;
 
    for (let i = 0; i < stackLength; i++) {
      if (stack[i] === callback) {
        stack.splice(i, 1);
 
        return;
      }
    }
  }
 
  dispatchEvent(event) {
    if (!this.listeners[event.type]) {
      //console.warn(`Skipping dispatch since there are no listeners for ${event.type}`);
      return !event.defaultPrevented;
    }
 
    const stack = this.listeners[event.type].slice();
    const stackLength = stack.length;
 
    for (let i = 0; i < stackLength; i++) {
      try {
        stack[i].call(this, event);
      } catch (error) {
        console.error(`error in event listener of type:  ${event.type}`, error);
      }
    }
 
    return !event.defaultPrevented;
  }
}
 
/**
 * EventTarget - Provides the [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) interface
 */
const eventTarget = new CornerstoneEventTarget();
 
export default eventTarget;