fb-brand-hook.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. (function () {
  2. var LOGO_URL = '/fb-logo.png?v=20260306w';
  3. var HOME_SEARCH_CACHE_KEY = 'fb.home.search.q';
  4. function setFavicons() {
  5. var rels = ['icon', 'shortcut icon', 'apple-touch-icon'];
  6. rels.forEach(function (rel) {
  7. var link = document.querySelector('link[rel="' + rel + '"]');
  8. if (!link) {
  9. link = document.createElement('link');
  10. link.setAttribute('rel', rel);
  11. document.head.appendChild(link);
  12. }
  13. link.setAttribute('href', LOGO_URL);
  14. link.setAttribute('type', 'image/png');
  15. });
  16. var msTile = document.querySelector('meta[name="msapplication-TileImage"]');
  17. if (msTile) msTile.setAttribute('content', LOGO_URL);
  18. }
  19. function ensureStaticStyles() {
  20. if (document.getElementById('fb-brand-style')) return;
  21. var style = document.createElement('style');
  22. style.id = 'fb-brand-style';
  23. style.textContent = [
  24. '.credits { display: none !important; }',
  25. '[class*="credits"] { display: none !important; }',
  26. '#fb-header-brand {',
  27. ' display: inline-flex;',
  28. ' align-items: center;',
  29. ' margin-right: 10px;',
  30. ' line-height: 1;',
  31. ' pointer-events: none;',
  32. ' user-select: none;',
  33. '}',
  34. '#fb-header-brand img { width: 26px; height: 26px; object-fit: contain; display:block; }',
  35. '#fb-top-corner-brand {',
  36. ' position: fixed;',
  37. ' top: 10px;',
  38. ' left: 12px;',
  39. ' z-index: 2147483000;',
  40. ' display: inline-flex;',
  41. ' align-items: center;',
  42. ' justify-content: center;',
  43. ' width: 40px;',
  44. ' height: 40px;',
  45. ' border-radius: 10px;',
  46. ' background: rgba(41,44,60,.75);',
  47. ' border: 1px solid rgba(198,208,245,.25);',
  48. ' backdrop-filter: blur(8px);',
  49. ' pointer-events: none;',
  50. ' user-select: none;',
  51. '}',
  52. '#fb-top-corner-brand img { width: 22px; height: 22px; object-fit: contain; display:block; }',
  53. 'body#login-page #fb-top-corner-brand, #login #fb-top-corner-brand { display: none !important; }',
  54. 'body#login-page #fb-header-brand, #login #fb-header-brand { display: none !important; }',
  55. '@media (max-width: 736px) { #fb-top-corner-brand { top: 8px; left: 8px; width: 34px; height: 34px; } }'
  56. ].join('\n');
  57. document.head.appendChild(style);
  58. }
  59. function tuneLoginBrand() {
  60. var login = document.getElementById('login');
  61. if (!login) return;
  62. var form = login.querySelector('form');
  63. if (!form) return;
  64. var imgs = form.querySelectorAll('img');
  65. if (imgs.length > 0) {
  66. imgs.forEach(function (img, idx) {
  67. if (idx === 0) {
  68. if (img.dataset.fbLogoReady !== '1') {
  69. img.src = LOGO_URL;
  70. img.srcset = '';
  71. img.style.width = '92px';
  72. img.style.height = '92px';
  73. img.style.objectFit = 'contain';
  74. img.style.display = 'block';
  75. img.style.margin = '0 auto 8px';
  76. img.dataset.fbLogoReady = '1';
  77. }
  78. } else {
  79. img.remove();
  80. }
  81. });
  82. }
  83. var title = form.querySelector('h1');
  84. if (title && title.textContent !== '繁星文档') {
  85. title.textContent = '繁星文档';
  86. title.style.marginTop = '6px';
  87. }
  88. }
  89. function suppressNativeHeaderBrand() {
  90. if (location.pathname.indexOf('/login') === 0 || document.getElementById('login')) return;
  91. var header = document.querySelector('header');
  92. if (!header) return;
  93. var walker = document.createTreeWalker(header, NodeFilter.SHOW_TEXT, null);
  94. var node;
  95. while ((node = walker.nextNode())) {
  96. var txt = (node.nodeValue || '').trim();
  97. if (txt === 'File Browser' || txt === '文件浏览器') {
  98. node.nodeValue = '';
  99. }
  100. }
  101. var nativeImgs = header.querySelectorAll('img:not(#fb-header-brand img)');
  102. nativeImgs.forEach(function (img) {
  103. if (img.closest && img.closest('#fb-header-brand')) return;
  104. img.style.display = 'none';
  105. });
  106. }
  107. function ensureHeaderBrand() {
  108. var onLogin = location.pathname.indexOf('/login') === 0 || !!document.getElementById('login');
  109. var old = document.getElementById('fb-header-brand');
  110. if (onLogin) {
  111. if (old) old.remove();
  112. return false;
  113. }
  114. var header = document.querySelector('header');
  115. if (!header) return false;
  116. var brand = old;
  117. if (!brand) {
  118. brand = document.createElement('div');
  119. brand.id = 'fb-header-brand';
  120. brand.setAttribute('aria-hidden', 'true');
  121. brand.innerHTML = '<img src="' + LOGO_URL + '" alt="logo" />';
  122. header.insertBefore(brand, header.firstChild);
  123. } else {
  124. var img = brand.querySelector('img');
  125. if (img) img.src = LOGO_URL;
  126. if (brand.parentElement !== header) {
  127. header.insertBefore(brand, header.firstChild);
  128. }
  129. }
  130. return true;
  131. }
  132. function ensureTopCornerFallback(useHeader) {
  133. var onLogin = location.pathname.indexOf('/login') === 0 || !!document.getElementById('login');
  134. var el = document.getElementById('fb-top-corner-brand');
  135. if (onLogin || useHeader) {
  136. if (el) el.remove();
  137. return;
  138. }
  139. if (!el) {
  140. el = document.createElement('div');
  141. el.id = 'fb-top-corner-brand';
  142. el.setAttribute('aria-hidden', 'true');
  143. el.innerHTML = '<img src="' + LOGO_URL + '" alt="logo" />';
  144. document.body.appendChild(el);
  145. } else {
  146. var img = el.querySelector('img');
  147. if (img) img.src = LOGO_URL;
  148. }
  149. }
  150. function renameSidebarRoot() {
  151. var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
  152. var node;
  153. while ((node = walker.nextNode())) {
  154. var txt = (node.nodeValue || '').trim();
  155. if (txt === '我的文件' || txt === 'My Files') {
  156. node.nodeValue = node.nodeValue.replace(txt, '繁星文档');
  157. }
  158. }
  159. }
  160. function removeLegacyInlineSearch() {
  161. var legacy = document.getElementById('fb-inline-search');
  162. if (legacy) legacy.remove();
  163. var legacyStyle = document.getElementById('fb-inline-search-style');
  164. if (legacyStyle) legacyStyle.remove();
  165. var search = document.getElementById('search');
  166. if (search && search.style && search.style.display === 'none') search.style.display = '';
  167. }
  168. function isSearchInput(el) {
  169. if (!el || el.tagName !== 'INPUT') return false;
  170. var t = (el.getAttribute('type') || '').toLowerCase();
  171. var p = (el.getAttribute('placeholder') || '').toLowerCase();
  172. if (t === 'search') return true;
  173. if (p.indexOf('search') >= 0 || p.indexOf('搜索') >= 0) return true;
  174. if ((el.className || '').toString().toLowerCase().indexOf('search') >= 0) return true;
  175. return false;
  176. }
  177. function readCachedHomeSearch() {
  178. try {
  179. return (sessionStorage.getItem(HOME_SEARCH_CACHE_KEY) || '').trim();
  180. } catch (e) {
  181. return '';
  182. }
  183. }
  184. function writeCachedHomeSearch(q) {
  185. try {
  186. sessionStorage.setItem(HOME_SEARCH_CACHE_KEY, (q || '').trim());
  187. } catch (e) {}
  188. }
  189. function goSearch(q) {
  190. if (location.pathname === '/search') return;
  191. var qs = (q || '').trim();
  192. if (!qs) qs = readCachedHomeSearch();
  193. location.assign('/search' + (qs ? ('?q=' + encodeURIComponent(qs)) : ''));
  194. }
  195. function installSearchRedirectGuards() {
  196. if (window.__fbSearchRedirectGuardInstalled) return;
  197. window.__fbSearchRedirectGuardInstalled = true;
  198. // Keep home search input value cached for /search fallback.
  199. document.addEventListener('input', function (e) {
  200. if (location.pathname.indexOf('/login') === 0) return;
  201. var homeInput = e.target && e.target.closest && e.target.closest('#search input, #search #input input');
  202. if (!homeInput) return;
  203. writeCachedHomeSearch(e.target.value || '');
  204. }, true);
  205. document.addEventListener('click', function (e) {
  206. if (location.pathname.indexOf('/login') === 0) return;
  207. var inSearch = e.target && e.target.closest && e.target.closest('#search');
  208. if (!inSearch) return;
  209. var onInput = e.target && e.target.closest && e.target.closest('#search input, #search #input input');
  210. if (onInput) return; // keep typing, no redirect on click.
  211. // Intercept magnifier / action click to prevent built-in index popup.
  212. var icon = e.target && e.target.closest && e.target.closest('.search-button,header .search-button,#search #input > i,#search .search-button,#search .action,#search [title*="search" i],#search [aria-label*="search" i],#search [title*="搜索" i],#search [aria-label*="搜索" i],#search i');
  213. if (!icon) return;
  214. e.preventDefault();
  215. e.stopPropagation();
  216. if (e.stopImmediatePropagation) e.stopImmediatePropagation();
  217. }, true);
  218. document.addEventListener('keydown', function (e) {
  219. if (location.pathname.indexOf('/login') === 0) return;
  220. if (location.pathname === '/search') return;
  221. var homeInput = e.target && e.target.closest && e.target.closest('#search input, #search #input input');
  222. if (!homeInput) return;
  223. if (e.key !== 'Enter') return;
  224. var q = (e.target.value || '').trim();
  225. writeCachedHomeSearch(q);
  226. e.preventDefault();
  227. e.stopPropagation();
  228. if (e.stopImmediatePropagation) e.stopImmediatePropagation();
  229. goSearch(q);
  230. }, true);
  231. }
  232. function apply() {
  233. setFavicons();
  234. ensureStaticStyles();
  235. tuneLoginBrand();
  236. suppressNativeHeaderBrand();
  237. var ok = ensureHeaderBrand();
  238. ensureTopCornerFallback(ok);
  239. renameSidebarRoot();
  240. removeLegacyInlineSearch();
  241. installSearchRedirectGuards();
  242. }
  243. var timer = null;
  244. var ob = new MutationObserver(function () {
  245. if (timer) clearTimeout(timer);
  246. timer = setTimeout(apply, 20);
  247. });
  248. ob.observe(document.documentElement, { childList: true, subtree: true });
  249. apply();
  250. if (window.requestAnimationFrame) requestAnimationFrame(apply);
  251. setTimeout(apply, 30);
  252. })();