메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
만약 지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.

미디어위키:Common.js: 두 판 사이의 차이

novawiki
편집 요약 없음
편집 요약 없음
 
(같은 사용자의 중간 판 4개는 보이지 않습니다)
1번째 줄: 1번째 줄:
/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */
/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */


/**
/*Autofocus on when clicking search button*/
* Autofocus search input on mobile
* Triggered when MobileFrontend search UI opens
* Improves UX by immediately opening the virtual keyboard
*/
 
/**
* iOS-friendly autofocus for Citizen search
* - Bind focus to the actual user gesture on the search toggle (summary)
* - Use a couple rAFs to wait for the input to appear/expand
*/
(function () {
(function () {
   const TOGGLE_SELECTOR = '#citizen-search-details > summary.citizen-dropdown-summary';
   const DETAILS_ID = 'citizen-search-details';
   const INPUT_SELECTOR = '#searchInput';
  const TOGGLE_SEL = '#citizen-search-details > summary.citizen-dropdown-summary';
   const REAL_INPUT_ID = 'searchInput';


   function focusInput() {
   function ensureProxy() {
     const input = document.querySelector(INPUT_SELECTOR);
     let p = document.getElementById('mw-search-proxy');
     if (!input) return false;
     if (p) return p;


     // If the toggle is still animating / collapsing, focus may fail.
     p = document.createElement('input');
     // preventScroll avoids weird jump on mobile.
    p.id = 'mw-search-proxy';
     input.focus({ preventScroll: true });
    p.type = 'search';
     p.autocomplete = 'off';
     p.setAttribute('aria-hidden', 'true');


     // Some iOS versions are picky; a click can help trigger the keyboard.
     // "안 보이지만" 포커스는 가능한 상태로 (display:none / visibility:hidden 쓰면 포커스 자체가 막힘)
     // (Harmless elsewhere.)
    p.style.position = 'fixed';
     input.click();
    p.style.left = '-9999px';
    p.style.top = '0';
     p.style.width = '1px';
    p.style.height = '1px';
    p.style.opacity = '0';
     p.style.pointerEvents = 'none';


     return document.activeElement === input;
     document.documentElement.appendChild(p);
    return p;
   }
   }


   function focusSoon() {
   function focusRealSoon() {
     // Try immediately first (best chance to count as user gesture)
     const details = document.getElementById(DETAILS_ID);
     if (focusInput()) return;
    const real = document.getElementById(REAL_INPUT_ID);
     if (!details || !real) return;


     // Then wait 1-2 frames for Citizen to render/open the search card
     // 열기 보장
     requestAnimationFrame(() => {
     if (!details.open) details.open = true;
      if (focusInput()) return;
      requestAnimationFrame(() => focusInput());
    });
  }


  // Use capturing so we still get it even if other handlers stop propagation.
    // 레이아웃 한 번 강제 (iOS에 은근 도움 됨)
  document.addEventListener(
     void real.offsetHeight;
     'touchend',
    function (e) {
      if (e.target.closest(TOGGLE_SELECTOR)) focusSoon();
    },
    true
  );


  // Fallback for devices/browsers that don't fire touchend as expected
    // 키보드가 이미 떠있으면 real focus가 더 잘 붙는 편
  document.addEventListener(
    real.focus({ preventScroll: true });
     'click',
     real.click();
    function (e) {
   }
      if (e.target.closest(TOGGLE_SELECTOR)) focusSoon();
    },
    true
   );
})();


/*general*/
  function onToggleGesture(e) {
    const hit = e.target.closest(TOGGLE_SEL);
    if (!hit) return;


(function () {
    // 1) 유저 제스처 안에서 "input focus"를 먼저 한 번 만들어줌
     function focusSearch() {
     const proxy = ensureProxy();
        const input =
            document.querySelector('.citizen-search__input') ||
            document.querySelector('#searchInput') ||
            document.querySelector('input[type="search"]');


        if (input) {
    try {
            input.focus({ preventScroll: true });
      proxy.focus({ preventScroll: true });
            input.click();
      proxy.click();
        }
    } catch (_) {}
    }


     // 검색 버튼/아이콘(스킨마다 다름)에서 이벤트로 잡기
     // 2) 같은 제스처 안에서 real focus도 바로 시도
     document.addEventListener('click', function (e) {
     focusRealSoon();
        // Citizen/모바일에서 검색 토글 버튼 후보들
        const isSearchButton =
            e.target.closest('.citizen-search__button, .mw-ui-icon-search, .search-toggle, a[title="Search"], button[title="Search"]');


        if (!isSearchButton) return;
    // 3) 그래도 Citizen이 애니메이션/상태 적용을 늦게 하면 다음 프레임에 한 번 더
    requestAnimationFrame(() => {
      focusRealSoon();
      // proxy는 필요 없으니 정리
      try { proxy.blur(); } catch (_) {}
    });
  }


        // 버튼 누른 "직후" 입력창이 생기므로 프레임 2번 정도만 양보
  // iOS에서 제일 잘 먹는 건 touchstart
        requestAnimationFrame(() => requestAnimationFrame(focusSearch));
  document.addEventListener('touchstart', onToggleGesture, { capture: true, passive: true });
    }, true);
  document.addEventListener('click', onToggleGesture, true);
})();
})();

2026년 1월 17일 (토) 19:01 기준 최신판

/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */

/*Autofocus on when clicking search button*/
(function () {
  const DETAILS_ID = 'citizen-search-details';
  const TOGGLE_SEL = '#citizen-search-details > summary.citizen-dropdown-summary';
  const REAL_INPUT_ID = 'searchInput';

  function ensureProxy() {
    let p = document.getElementById('mw-search-proxy');
    if (p) return p;

    p = document.createElement('input');
    p.id = 'mw-search-proxy';
    p.type = 'search';
    p.autocomplete = 'off';
    p.setAttribute('aria-hidden', 'true');

    // "안 보이지만" 포커스는 가능한 상태로 (display:none / visibility:hidden 쓰면 포커스 자체가 막힘)
    p.style.position = 'fixed';
    p.style.left = '-9999px';
    p.style.top = '0';
    p.style.width = '1px';
    p.style.height = '1px';
    p.style.opacity = '0';
    p.style.pointerEvents = 'none';

    document.documentElement.appendChild(p);
    return p;
  }

  function focusRealSoon() {
    const details = document.getElementById(DETAILS_ID);
    const real = document.getElementById(REAL_INPUT_ID);
    if (!details || !real) return;

    // 열기 보장
    if (!details.open) details.open = true;

    // 레이아웃 한 번 강제 (iOS에 은근 도움 됨)
    void real.offsetHeight;

    // 키보드가 이미 떠있으면 real focus가 더 잘 붙는 편
    real.focus({ preventScroll: true });
    real.click();
  }

  function onToggleGesture(e) {
    const hit = e.target.closest(TOGGLE_SEL);
    if (!hit) return;

    // 1) 유저 제스처 안에서 "input focus"를 먼저 한 번 만들어줌
    const proxy = ensureProxy();

    try {
      proxy.focus({ preventScroll: true });
      proxy.click();
    } catch (_) {}

    // 2) 같은 제스처 안에서 real focus도 바로 시도
    focusRealSoon();

    // 3) 그래도 Citizen이 애니메이션/상태 적용을 늦게 하면 다음 프레임에 한 번 더
    requestAnimationFrame(() => {
      focusRealSoon();
      // proxy는 필요 없으니 정리
      try { proxy.blur(); } catch (_) {}
    });
  }

  // iOS에서 제일 잘 먹는 건 touchstart
  document.addEventListener('touchstart', onToggleGesture, { capture: true, passive: true });
  document.addEventListener('click', onToggleGesture, true);
})();