Repository: go-gitea/gitea
File: web_src/js/features/common-page.ts (TypeScript)

Code before:
}

export function initGlobalComponent() {
  fomanticQuery('.ui.menu.tabular:not(.custom) .item').tab();
  registerGlobalInitFunc('initAvatarUploader', initAvatarUploaderWithCropper);
  registerGlobalInitFunc('initSearchRepoBox', initCompSearchRepoBox);
}

// for performance considerations, it only uses performant syntax
function attachInputDirAuto(el: Partial<HTMLInputElement | HTMLTextAreaElement>) {
  if (el.type !== 'hidden' &&
    el.type !== 'checkbox' &&
    el.type !== 'radio' &&
    el.type !== 'range' &&
    el.type !== 'color') {
    el.dir = 'auto';
  }
}

function setSelectionEnd(el: HTMLInputElement | HTMLTextAreaElement) {
  el.setSelectionRange(el.value.length, el.value.length);
}

export function initGlobalInput() {
  registerGlobalSelectorFunc('input, textarea', attachInputDirAuto);
  registerGlobalSelectorFunc('[data-autofocus-end]', (el) => {
    if (!isElemVisible(el)) return;
    el.focus();
    if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
      setSelectionEnd(el);
    }
  });

  // when a show-panel button is clicked, focus the [data-autofocus-on-show-panel] element
  // inside the shown panel. This handler runs after initGlobalButtons has already made the panel visible.
  addDelegatedEventListener(document, 'click', '.show-panel', (el) => {
    const panelSel = el.getAttribute('data-panel');
    if (!panelSel) return;
    for (const panel of document.querySelectorAll<HTMLElement>(panelSel)) {
      if (!isElemVisible(panel)) continue;
      const focusEl = panel.querySelector<HTMLInputElement>('[data-autofocus-on-show-panel]');
      if (focusEl) {
        focusEl.focus();
        if (focusEl.hasAttribute('data-autofocus-end')) {
          setSelectionEnd(focusEl);
        }
      }
    }
  });
}


Review comment (performance):
I didn't use `registerGlobalSelectorFunc` because it is slower than `registerGlobalInitFunc`

Each `registerGlobalSelectorFunc` adds a new "query" call in the observer's loop.

And there are comments:

<img width="2182" height="368" alt="image" src="https://github.com/user-attachments/assets/e6f99868-12e9-4cc1-be10-d91fbc944c88" />


Code after:
}

export function initGlobalComponent() {
  fomanticQuery('.ui.menu.tabular:not(.custom) .item').tab();
  registerGlobalInitFunc('initAvatarUploader', initAvatarUploaderWithCropper);
  registerGlobalInitFunc('initSearchRepoBox', initCompSearchRepoBox);
}

// for performance considerations, it only uses performant syntax
function attachInputDirAuto(el: Partial<HTMLInputElement | HTMLTextAreaElement>) {
  if (el.type !== 'hidden' &&
    el.type !== 'checkbox' &&
    el.type !== 'radio' &&
    el.type !== 'range' &&
    el.type !== 'color') {
    el.dir = 'auto';
  }
}

function autoFocusEnd(el: HTMLInputElement | HTMLTextAreaElement) {
  el.focus();
  el.setSelectionRange(el.value.length, el.value.length);
}

export function applyAutoFocus(container: Element) {
  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/autofocus
  // "autofocus" behavior is defined by the standard: when a container (e.g.: dialog) becomes visible, focus the element with "autofocus" attribute
  // Fomantic UI already supports it for its modal dialog, we need to cover more cases (e.g.: ".show-panel" button)
  // Here is just a simple support, we don't expect more than one element that need "autofocus" appearing in the same container
  container.querySelector<HTMLElement>('[autofocus]')?.focus();
  // Also, apply our autoFocusEnd behavior
  // TODO: GLOBAL-INIT-MULTIPLE-FUNCTIONS: use "~=" operator in case we would extend the "data-global-init" to support more functions in the future.
  const el = container.querySelector<HTMLInputElement>('[data-global-init~="autoFocusEnd"]');
  if (el) autoFocusEnd(el);
}

export function initGlobalInput() {
  registerGlobalSelectorFunc('input, textarea', attachInputDirAuto);

  // autoFocusEnd is used for autofocus an input/textarea and move the cursor to the end of the text.
  // It is useful for "New Issue"/"New PR" pages when the title is pre-filled with prefix text (e.g.: from template or commit message)
  // The native "autofocus" isn't used because there is a delay between "focused (DOM rendering)" and "move cursor to end (our JS)", it causes flickers.
  registerGlobalInitFunc('autoFocusEnd', autoFocusEnd);
}

/**
 * Too many users set their ROOT_URL to wrong value, and it causes a lot of problems:
 *   * Cross-origin API request without correct cookie
 *   * Incorrect href in <a>
 *   * ...
 * So we check whether current URL starts with AppUrl(ROOT_URL).