← Back to context

Comment by Sammi

18 hours ago

Very simple jquery implementation with all the easy apis:

  (function (global) {
    function $(selector, context = document) {
      let elements = [];

      if (typeof selector === "string") {
        elements = Array.from(context.querySelectorAll(selector));
      } else if (selector instanceof Element || selector === window || selector === document) {
        elements = [selector];
      } else if (selector instanceof NodeList || Array.isArray(selector)) {
        elements = Array.from(selector);
      } else if (typeof selector === "function") {
        // DOM ready
        if (document.readyState !== "loading") {
          selector();
        } else {
          document.addEventListener("DOMContentLoaded", selector);
        }
        return;
      }

      return new Dollar(elements);
    }

    class Dollar {
      constructor(elements) {
        this.elements = elements;
      }

      // Iterate
      each(callback) {
        this.elements.forEach((el, i) => callback.call(el, el, i));
        return this;
      }

      // Events
      on(event, handler, options) {
        return this.each(el => el.addEventListener(event, handler, options));
      }

      off(event, handler, options) {
        return this.each(el => el.removeEventListener(event, handler, options));
      }

      // Classes
      addClass(className) {
        return this.each(el => el.classList.add(...className.split(" ")));
      }

      removeClass(className) {
        return this.each(el => el.classList.remove(...className.split(" ")));
      }

      toggleClass(className) {
        return this.each(el => el.classList.toggle(className));
      }

      hasClass(className) {
        return this.elements[0]?.classList.contains(className) ?? false;
      }

      // Attributes
      attr(name, value) {
        if (value === undefined) {
          return this.elements[0]?.getAttribute(name);
        }
        return this.each(el => el.setAttribute(name, value));
      }

      removeAttr(name) {
        return this.each(el => el.removeAttribute(name));
      }

      // Content
      html(value) {
        if (value === undefined) {
          return this.elements[0]?.innerHTML;
        }
        return this.each(el => (el.innerHTML = value));
      }

      text(value) {
        if (value === undefined) {
          return this.elements[0]?.textContent;
        }
        return this.each(el => (el.textContent = value));
      }

      // DOM manipulation
      append(content) {
        return this.each(el => {
          if (content instanceof Element) {
            el.appendChild(content.cloneNode(true));
          } else {
            el.insertAdjacentHTML("beforeend", content);
          }
        });
      }

      remove() {
        return this.each(el => el.remove());
      }

      // Utilities
      get(index = 0) {
        return this.elements[index];
      }

      first() {
        return new Dollar(this.elements.slice(0, 1));
      }

      last() {
        return new Dollar(this.elements.slice(-1));
      }
    }

    global.$ = $;
  })(window);