User:SunAfterRain/js/Vector2022StickyHeaderAutoCopy.js
外观
< User:SunAfterRain | js
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/**
* vector-2022-sticky-header-auto-copy
* 將 vector-2022 中 #p-personal 的連結自動複製到 #p-personal-sticky-header
* 複製後的連結之 id 會是 `${origId}-sticky-header`
*
* 使用限制:
* 1. 若是 Linster 不是用 jQuery.on 附上去的則無法複製
* 可以用 `window.wgVector2022StickyHeaderAutoCopyUseNativeClickEvnet = true;` 讓點擊時直接調用 Element.click()
* 2. 後續加入的連結若不是 mw.util.addPortletLink 附上去的可能無法掃描到
* 可以用 `window.wgVector2022StickyHeaderAutoCopyUseMutationObserver = true;` 改用 MutationObserver,但瀏覽器負擔可能有點大
* 3. 不處理人為移除的連結
* 4. 已假定所有連結都有 id 且 id 都不會因為測試而重複,不會有與 css 選擇器不相容的 id,以及沒有人往 #p-personal-sticky-header
* 注入沒有注入 #p-personal 的連結,否則複製後的連結定位可能會失敗
*
* @author SunAfterRain
*/
// <nowiki>
$( () => {
if ( mw.config.get( 'skin' ) !== 'vector-2022' ) {
return;
}
const $personalTab = $( '#p-personal' );
const $personalStickyHeaderTab = $( '#p-personal-sticky-header' );
const stickHeaderIdSuffix = '-sticky-header';
// 以下被列出的 id 會被無視
const idBlackList = [
'pt-userpage',
'pt-sandbox',
'pt-preferences',
'pt-betafeatures',
'pt-watchlist',
'pt-mycontris',
'pt-mentordashboard',
'pt-logout',
'cx-language', // CX
'cx-imageGallery', // 上傳的檔案列表
'utcdate', // Gadget-UTCLiveClock / 已有適配
];
function findLinkToCopy() {
for ( const link of $personalTab.find( 'li' ).get() ) {
applyCopy( link );
}
}
function applyCopy( link ) {
const $link = $( link );
let id = $link.attr( 'id' ) || false;
if ( id ) {
if ( idBlackList.includes( id ) || !!$personalStickyHeaderTab.find( `#${ id }${ stickHeaderIdSuffix }` ).length ) {
return;
}
}
let $copyLink;
if ( window.wgVector2022StickyHeaderAutoCopyUseNativeClickEvnet ) {
const $a = $link.children( 'a' ).get();
$copyLink = $link.clone();
const $copyA = $copyLink.children( 'a' );
for ( const [ index, $self ] of $copyLink.children( 'a' ).get().entries() ) {
const $origAnchor = $a[ index ];
$( $self ).on( 'click', ( e ) => {
e.preventDefault();
$origAnchor.click();
} );
}
} else {
$copyLink = $link.clone( false, true );
}
if ( id ) {
$copyLink.attr( 'id', `${ id }${ stickHeaderIdSuffix }` );
}
const $next = $link.next();
let insertNextNode = false;
if ( $next.length && $next.attr( 'id' ) ) {
// 例如 Gadget-UTCLiveClock 在兩處用了一樣的 id
insertNextNode = $personalStickyHeaderTab.find( `#${ $next.attr( 'id' ) }, #${ $next.attr( 'id' ) }${ stickHeaderIdSuffix }` ).get( 0 );
}
if ( insertNextNode ) {
$copyLink.before( insertNextNode );
} else {
$personalStickyHeaderTab.append( $copyLink );
}
mw.hook( 'util.addPortletLink' ).fire( $copyLink.get( 0 ), {
id: id ? `${ id }${ stickHeaderIdSuffix }` : undefined,
isInsertByAutoCopyScript: true
} );
}
findLinkToCopy();
if ( window.wgVector2022StickyHeaderAutoCopyUseMutationObserver ) {
const personalTabList = $personalTab.find( 'ul' ).get( 0 );
const observer = new MutationObserver( ( mutations ) => {
for ( const mutation of mutations ) {
if (
mutation.target.tagName.toLowerCase() === 'li' &&
mutation.target.parentNode === personalTabList
) {
applyCopy( item );
}
}
} );
observer.observe( personalTabList, {
childList: true
} );
} else {
mw.hook( 'util.addPortletLink' ).add( ( item, { id } ) => {
if ( !$( item ).parents().get().includes( $personalTab.get( 0 ) ) ) {
return;
}
applyCopy( item );
} );
}
// 如果不在黑名單裡但自己有注入 #p-personal-sticky-header,把我們自己生成的刪掉
mw.hook( 'util.addPortletLink' ).add( ( item, { id, isInsertByAutoCopyScript } ) => {
if ( isInsertByAutoCopyScript || !$( item ).parents().get().includes( $personalStickyHeaderTab.get( 0 ) ) ) {
return;
}
$personalStickyHeaderTab.find( 'li' ).filter( ( _, e ) => ( $( e ).attr( 'id' ) === id || $e.attr( 'id' ) === `${ id }${ stickHeaderIdSuffix }` ) && e !== item ).remove();
} );
} );
// </nowiki>