FBTitle Fix

Replaces generic Facebook tab title with the actual page or group name

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         FBTitle Fix
// @namespace    https://github.com/2u841r/FBTitle-Fix
// @version      1.0.1
// @description  Replaces generic Facebook tab title with the actual page or group name
// @author       Zubair Ibn Zamir
// @license      MIT
// @match        *://*.facebook.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  function getPageName() {
    // Primary: h1 button div (old page/group name header)
    const h1btn = document.querySelector('h1 div[role="button"]');
    if (h1btn) {
      const text = h1btn.childNodes[0]?.textContent?.trim();
      if (text) return text;
    }

    // Fallback: h1 text (groups: h1 > span). Skip hidden/junk h1s like the
    // visually-hidden "Facebook" logo heading.
    for (const h1 of document.querySelectorAll('h1')) {
      const text = h1.textContent?.trim();
      if (!text || text === 'Facebook') continue;
      if (h1.getBoundingClientRect().width === 0) continue;
      return text;
    }

    // Fallback: 2026-07 layout, page header has no h1 anymore.
    // Tail of the header container path; atomic class hashes may break on FB redesigns.
    const span = document.querySelector('div.x1cy8zhl.x1614ocl > div > div > span > div');
    if (span) {
      const text = span.textContent?.trim();
      if (text) return text;
    }

    // Last resort: structural walk, no classes. First short standalone text
    // block inside main content, above the fold (header area).
    const main = document.querySelector('div[role="main"]');
    if (main) {
      const candidates = main.querySelectorAll('span > div');
      for (const el of candidates) {
        if (el.children.length > 0) continue;
        if (el.getBoundingClientRect().top > 600) break;
        const text = el.textContent?.trim();
        if (text && text.length >= 2 && text.length <= 100) return text;
      }
    }

    return null;
  }

  function updateTitle() {
    const name = getPageName();
    if (name && !document.title.startsWith(name)) {
      document.title = name + ' | Facebook';
    }
  }

  const observer = new MutationObserver(() => updateTitle());
  observer.observe(document.body, { childList: true, subtree: true });

  const _pushState = history.pushState.bind(history);
  history.pushState = function (...args) {
    _pushState(...args);
    setTimeout(updateTitle, 500);
  };

  window.addEventListener('popstate', () => setTimeout(updateTitle, 500));

  updateTitle();
})();