-
Notifications
You must be signed in to change notification settings - Fork 1
/
Links.js
154 lines (133 loc) · 5.54 KB
/
Links.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// <nowiki>
/*
This script adds a left menu below the toolbox called "More tools", and includes some links:
- userspace only
- common.js
- global.js
- vector.js
- common.css
- global.css
- central auth (good for seeing what global permissions people have)
- rename log
- global lock log
- Twinkle CSD log
- Twinkle PROD log
- Twinkle XfD log
- Draftify log
- Page curation log
- all namespaces
- subpages
This script also adds "Pending changes" to the left main menu.
Skin support
- left menu
- vector
- modern
- monobook
- timeless
- right menu (tools menu)
- vector-2022
- not displayed at all
- minerva
*/
class Links {
constructor( mw ) {
this.mw = mw;
}
async execute() {
this.mw.util.addPortletLink( 'p-navigation', this.mw.util.getUrl( 'Special:PendingChanges' ), 'Pending changes' );
this.pageName = this.mw.config.get( 'wgPageName' );
this.createBottomLeftMenuContainer();
this.username = this.getFirstMatch( this.pageName, /(?:User:|User_talk:)([^/]+).*/ );
if ( this.username ) {
await this.generateUserspaceLinks();
}
await this.generateSubpageLink();
}
createBottomLeftMenuContainer() {
// Works as expected in vector, modern, monobook, timeless. Is in right menu instead of left menu in vector-2022. Doesn't show up at all in minerva.
// Could fix in those skins by adding it before an existing nearby portlet, then using the p.parentNode.appendChild( p ); trick.
this.mw.util.addPortlet( 'p-links', 'More tools', '#p-coll-print_export' );
}
async generateUserspaceLinks() {
this.username = 'User:' + this.username;
this.usernameURI = encodeURIComponent( this.username.replace( /_/g, ' ' ).replace( /^User:/, '' ) );
this.mw.util.addPortletLink( 'p-links', `/wiki/${ this.username }/common.js`, 'common.js' );
this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/${ this.username }/global.js`, 'global.js' );
this.mw.util.addPortletLink( 'p-links', `/wiki/${ this.username }/vector.js`, 'vector.js' );
this.mw.util.addPortletLink( 'p-links', `/wiki/${ this.username }/common.css`, 'common.css' );
this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/${ this.username }/global.css`, 'global.css' );
this.mw.util.addPortletLink( 'p-links', `/wiki/Special:CentralAuth?target=${ this.usernameURI }`, 'Central auth' );
this.mw.util.addPortletLink( 'p-links', `/wiki/Special:Log?type=rights&user=&page=${ this.usernameURI }`, 'User rights log' );
this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:Log?type=rights&user=&page=${ this.usernameURI }@enwiki`, 'User rights log (meta)' );
this.generateRenameLogLinks();
this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:Log?page=User%3A${ this.usernameURI }%40global`, 'Global lock log' );
await this.generateTwinkleLogLinks();
this.mw.util.addPortletLink( 'p-links', `/wiki/Special:Log?type=pagetriage-curation&subtype=review&user=User%3A${ this.usernameURI }`, 'Page curation log' );
}
generateSubpageLink() {
let parentName = this.pageName + '/';
if ( this.pageName.includes( '/' ) ) {
parentName = this.getFirstMatch( this.pageName, /^([^/]+\/)/ );
}
this.mw.util.addPortletLink( 'p-links', `/wiki/Special:PrefixIndex/${ parentName }`, 'Subpages' );
}
async generateTwinkleLogLinks() {
// twinkle logs (csd, prod, xfd) and draftify log
// check if they exist with an API query before adding links
const logPages = await this.pagesExist( [
`${ this.username }/CSD log`,
`${ this.username }/PROD log`,
`${ this.username }/XfD log`,
`${ this.username }/Draftify log`
] );
for ( const title of logPages ) {
const shortTitle = title.replace( /^.*\//, '' );
this.mw.util.addPortletLink( 'p-links', `/wiki/${ title }`, shortTitle );
}
}
generateRenameLogLinks() {
// All modern renames seem to be put into both en:Special:Log->User rename log AND meta:Special:Log->User rename log.
// One older rename was put only into meta:Special:Log->User rename log.
// Another older rename was put only into en:Special:Log->User rename log, and was complicated by the fact that ~enwiki had been added to the end of it.
// Spaces vs underscores don't seem to matter. User: or no User: doesn't seem to matter.
this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:GlobalRenameProgress?username=${ this.usernameURI }`, 'Rename log 1' );
this.mw.util.addPortletLink( 'p-links', `https://meta.wikimedia.org/wiki/Special:Log?type=renameuser&user=&page=${ this.usernameURI }`, 'Rename log 2' );
this.mw.util.addPortletLink( 'p-links', `/wiki/Special:Log?type=renameuser&user=&page=${ this.usernameURI }%7Eenwiki`, 'Rename log 3' );
}
getFirstMatch( string, regex ) {
const matches = string.match( regex );
if ( matches && matches[ 1 ] ) {
return matches[ 1 ];
}
return '';
}
/**
* @param {Array} titles
*/
async pagesExist( titles ) {
const api = new this.mw.Api();
let response = await api.get( {
action: 'query',
format: 'json',
prop: 'revisions',
titles: titles.join( '|' )
} );
response = response.query.pages;
const pages = [];
for ( const key in response ) {
// the Number class will convert any non-numbers to 0
// the API will return -1 for non-existent pages
// the API will return the page ID for existing pages
if ( Number( key ) > 0 ) {
pages.push( response[ key ].title );
}
}
return pages;
}
}
$( async () => {
await mw.loader.using( [ 'mediawiki.api' ], async () => {
await ( new Links( mw ) ).execute();
} );
} );
// </nowiki>