2 * JavaScript for Special:Watchlist
4 ( function ( mw
, $, OO
) {
6 var api
= new mw
.Api(), $progressBar
, $resetForm
= $( '#mw-watchlist-resetbutton' );
8 // If the user wants to reset their watchlist, use an API call to do so (no reload required)
9 // Adapted from a user script by User:NQ of English Wikipedia
10 // (User:NQ/WatchlistResetConfirm.js)
11 $resetForm
.submit( function ( event
) {
12 var $button
= $resetForm
.find( 'input[name=mw-watchlist-reset-submit]' );
14 event
.preventDefault();
16 // Disable reset button to prevent multiple concurrent requests
17 $button
.prop( 'disabled', true );
19 if ( !$progressBar
) {
20 $progressBar
= new OO
.ui
.ProgressBarWidget( { progress
: false } ).$element
;
22 position
: 'absolute', width
: '100%'
26 $resetForm
.append( $progressBar
);
28 // Use action=setnotificationtimestamp to mark all as visited,
29 // then set all watchlist lines accordingly
30 api
.postWithToken( 'csrf', {
31 formatversion
: 2, action
: 'setnotificationtimestamp', entirewatchlist
: true
32 } ).done( function () {
33 // Enable button again
34 $button
.prop( 'disabled', false );
35 // Hide the button because further clicks can not generate any visual changes
36 $button
.css( 'visibility', 'hidden' );
37 $progressBar
.detach();
38 $( '.mw-changeslist-line-watched' )
39 .removeClass( 'mw-changeslist-line-watched' )
40 .addClass( 'mw-changeslist-line-not-watched' );
41 } ).fail( function () {
42 // On error, fall back to server-side reset
43 // First remove this submit listener and then re-submit the form
44 $resetForm
.off( 'submit' ).submit();
48 // if the user wishes to reload the watchlist whenever a filter changes
49 if ( mw
.user
.options
.get( 'watchlistreloadautomatically' ) ) {
50 // add a listener on all form elements in the header form
51 $( '#mw-watchlist-form input, #mw-watchlist-form select' ).on( 'change', function () {
52 // submit the form when one of the input fields is modified
53 $( '#mw-watchlist-form' ).submit();
57 if ( mw
.user
.options
.get( 'watchlistunwatchlinks' ) ) {
58 // Watch/unwatch toggle link:
59 // If a page is on the watchlist, a '×' is shown which, when clicked, removes the page from the watchlist.
60 // After unwatching a page, the '×' becomes a '+', which if clicked re-watches the page.
61 // Unwatched page entries are struck through and have lowered opacity.
62 $( '.mw-unwatch-link, .mw-watch-link' ).click( function ( event
) {
63 var $unwatchLink
= $( this ), // EnhancedChangesList uses <table> for each row, while OldChangesList uses <li> for each row
64 $watchlistLine
= $unwatchLink
.closest( 'li, table' )
65 .find( '[data-target-page]' ),
66 pageTitle
= $watchlistLine
.data( 'targetPage' ),
67 isTalk
= mw
.Title
.newFromText( pageTitle
).getNamespaceId() % 2 === 1;
69 // Utility function for looping through each watchlist line that matches
70 // a certain page or its associated page (e.g. Talk)
71 function forEachMatchingTitle( title
, callback
) {
73 var titleObj
= mw
.Title
.newFromText( title
),
74 pageNamespaceId
= titleObj
.getNamespaceId(),
75 isTalk
= pageNamespaceId
% 2 === 1,
76 associatedTitle
= mw
.Title
.makeTitle( isTalk
? pageNamespaceId
- 1 : pageNamespaceId
+ 1,
77 titleObj
.getMainText() ).getPrefixedText();
78 $( '.mw-changeslist-line' ).each( function () {
79 var $this = $( this ), $row
, $unwatchLink
;
81 $this.find( '[data-target-page]' ).each( function () {
82 var $this = $( this ), rowTitle
= $this.data( 'targetPage' );
83 if ( rowTitle
=== title
|| rowTitle
=== associatedTitle
) {
85 // EnhancedChangesList groups log entries by performer rather than target page. Therefore...
86 // * If using OldChangesList, use the <li>
87 // * If using EnhancedChangesList and $this is part of a grouped log entry, use the <td> sub-entry
88 // * If using EnhancedChangesList and $this is not part of a grouped log entry, use the <table> grouped entry
91 'li, table.mw-collapsible.mw-changeslist-log td[data-target-page], table' );
92 $unwatchLink
= $row
.find( '.mw-unwatch-link, .mw-watch-link' );
94 callback( rowTitle
, $row
, $unwatchLink
);
100 // Depending on whether we are watching or unwatching, for each entry of the page (and its associated page i.e. Talk),
101 // change the text, tooltip, and non-JS href of the (un)watch button, and update the styling of the watchlist entry.
102 if ( $unwatchLink
.hasClass( 'mw-unwatch-link' ) ) {
103 api
.unwatch( pageTitle
)
105 forEachMatchingTitle( pageTitle
,
106 function ( rowPageTitle
, $row
, $rowUnwatchLink
) {
108 .text( mw
.msg( 'watchlist-unwatch-undo' ) )
109 .attr( 'title', mw
.msg( 'tooltip-ca-watch' ) )
111 mw
.util
.getUrl( rowPageTitle
, { action
: 'watch' } ) )
112 .removeClass( 'mw-unwatch-link loading' )
113 .addClass( 'mw-watch-link' );
115 '.mw-changeslist-line-inner, .mw-enhanced-rc-nested' )
116 .addBack( '.mw-enhanced-rc-nested' ) // For matching log sub-entry
117 .addClass( 'mw-changelist-line-inner-unwatched' );
121 mw
.message( isTalk
? 'removedwatchtext-talk' : 'removedwatchtext',
122 pageTitle
), { tag
: 'watch-self' } );
125 api
.watch( pageTitle
)
127 forEachMatchingTitle( pageTitle
,
128 function ( rowPageTitle
, $row
, $rowUnwatchLink
) {
130 .text( mw
.msg( 'watchlist-unwatch' ) )
131 .attr( 'title', mw
.msg( 'tooltip-ca-unwatch' ) )
133 mw
.util
.getUrl( rowPageTitle
, { action
: 'unwatch' } ) )
134 .removeClass( 'mw-watch-link loading' )
135 .addClass( 'mw-unwatch-link' );
136 $row
.find( '.mw-changelist-line-inner-unwatched' )
137 .addBack( '.mw-enhanced-rc-nested' )
138 .removeClass( 'mw-changelist-line-inner-unwatched' );
142 mw
.message( isTalk
? 'addedwatchtext-talk' : 'addedwatchtext',
143 pageTitle
), { tag
: 'watch-self' } );
147 event
.preventDefault();
148 event
.stopPropagation();
154 }( mediaWiki
, jQuery
, OO
)