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

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

novawiki
편집 요약 없음
편집 요약 없음
2번째 줄: 2번째 줄:


/**
/**
  * Autofocus search input on mobile
  * Aggressive autofocus for Citizen search
* Triggered when MobileFrontend search UI opens
  * - Remembers user intent even during page load
* Improves UX by immediately opening the virtual keyboard
  * - Focuses input the moment it becomes available & visible
*/
 
/**
* 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 TOGGLE_SELECTOR =
    '#citizen-search-details > summary.citizen-dropdown-summary';
   const INPUT_SELECTOR = '#searchInput';
   const INPUT_SELECTOR = '#searchInput';


   function focusInput() {
  let wantFocus = false;
  let observer = null;
  let retryTimer = null;
 
   function canFocus(input) {
    if (!input) return false;
    if (input.disabled) return false;
    const rect = input.getBoundingClientRect();
    return rect.width > 0 && rect.height > 0;
  }
 
  function tryFocus() {
    if (!wantFocus) return;
 
     const input = document.querySelector(INPUT_SELECTOR);
     const input = document.querySelector(INPUT_SELECTOR);
     if (!input) return false;
     if (!canFocus(input)) return;


    // If the toggle is still animating / collapsing, focus may fail.
    // preventScroll avoids weird jump on mobile.
     input.focus({ preventScroll: true });
     input.focus({ preventScroll: true });
    // Some iOS versions are picky; a click can help trigger the keyboard.
    // (Harmless elsewhere.)
     input.click();
     input.click();


     return document.activeElement === input;
     if (document.activeElement === input) {
      cleanup();
    }
   }
   }


   function focusSoon() {
   function cleanup() {
     // Try immediately first (best chance to count as user gesture)
     wantFocus = false;
     if (focusInput()) return;
     if (observer) observer.disconnect();
 
     observer = null;
     // Then wait 1-2 frames for Citizen to render/open the search card
     if (retryTimer) clearInterval(retryTimer);
     requestAnimationFrame(() => {
     retryTimer = null;
      if (focusInput()) return;
      requestAnimationFrame(() => focusInput());
     });
   }
   }


   // Use capturing so we still get it even if other handlers stop propagation.
   function startWatching() {
  document.addEventListener(
     // 1) DOM 변화 감시
     'touchend',
     if (!observer) {
     function (e) {
       observer = new MutationObserver(tryFocus);
       if (e.target.closest(TOGGLE_SELECTOR)) focusSoon();
      observer.observe(document.body, {
    },
        childList: true,
    true
        subtree: true,
  );
        attributes: true,
      });
    }


  // Fallback for devices/browsers that don't fire touchend as expected
    // 2) 혹시 Mutation이 안 잡히는 케이스 대비 폴링
  document.addEventListener(
     if (!retryTimer) {
     'click',
       retryTimer = setInterval(tryFocus, 50);
    function (e) {
     }
       if (e.target.closest(TOGGLE_SELECTOR)) focusSoon();
   }
     },
    true
   );
})();


/*general*/
  function onSearchIntent() {
 
     wantFocus = true;
(function () {
    tryFocus();      // 즉시 한 번
     function focusSearch() {
    startWatching(); // 안 되면 끝까지 쫓아감
        const input =
  }
            document.querySelector('.citizen-search__input') ||
            document.querySelector('#searchInput') ||
            document.querySelector('input[type="search"]');


        if (input) {
  // 🔑 진짜 중요한 부분: "유저 제스처"에서 intent만 기록
            input.focus({ preventScroll: true });
  ['touchstart', 'touchend', 'mousedown', 'click'].forEach((evt) => {
            input.click();
    document.addEventListener(
      evt,
      function (e) {
        if (e.target.closest(TOGGLE_SELECTOR)) {
          onSearchIntent();
         }
         }
    }
      },
 
      true
     // 검색 버튼/아이콘(스킨마다 다름)에서 이벤트로 잡기
     );
    document.addEventListener('click', function (e) {
  });
        // Citizen/모바일에서 검색 토글 버튼 후보들
        const isSearchButton =
            e.target.closest('.citizen-search__button, .mw-ui-icon-search, .search-toggle, a[title="Search"], button[title="Search"]');
 
        if (!isSearchButton) return;
 
        // 버튼 누른 "직후" 입력창이 생기므로 프레임 2번 정도만 양보
        requestAnimationFrame(() => requestAnimationFrame(focusSearch));
    }, true);
})();
})();

2026년 1월 17일 (토) 18:49 판

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

/**
 * Aggressive autofocus for Citizen search
 * - Remembers user intent even during page load
 * - Focuses input the moment it becomes available & visible
 */
(function () {
  const TOGGLE_SELECTOR =
    '#citizen-search-details > summary.citizen-dropdown-summary';
  const INPUT_SELECTOR = '#searchInput';

  let wantFocus = false;
  let observer = null;
  let retryTimer = null;

  function canFocus(input) {
    if (!input) return false;
    if (input.disabled) return false;
    const rect = input.getBoundingClientRect();
    return rect.width > 0 && rect.height > 0;
  }

  function tryFocus() {
    if (!wantFocus) return;

    const input = document.querySelector(INPUT_SELECTOR);
    if (!canFocus(input)) return;

    input.focus({ preventScroll: true });
    input.click();

    if (document.activeElement === input) {
      cleanup();
    }
  }

  function cleanup() {
    wantFocus = false;
    if (observer) observer.disconnect();
    observer = null;
    if (retryTimer) clearInterval(retryTimer);
    retryTimer = null;
  }

  function startWatching() {
    // 1) DOM 변화 감시
    if (!observer) {
      observer = new MutationObserver(tryFocus);
      observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: true,
      });
    }

    // 2) 혹시 Mutation이 안 잡히는 케이스 대비 폴링
    if (!retryTimer) {
      retryTimer = setInterval(tryFocus, 50);
    }
  }

  function onSearchIntent() {
    wantFocus = true;
    tryFocus();      // 즉시 한 번
    startWatching(); // 안 되면 끝까지 쫓아감
  }

  // 🔑 진짜 중요한 부분: "유저 제스처"에서 intent만 기록
  ['touchstart', 'touchend', 'mousedown', 'click'].forEach((evt) => {
    document.addEventListener(
      evt,
      function (e) {
        if (e.target.closest(TOGGLE_SELECTOR)) {
          onSearchIntent();
        }
      },
      true
    );
  });
})();