MediaWiki:Gadget-watchlist.js: различия между версиями
Перейти к навигации
Перейти к поиску
Содержимое удалено Содержимое добавлено
уточнение настроек кук |
Используем контекст из аргумента хука "wikipage.content" для поиска списка изменений |
||
(не показано 40 промежуточных версий этого же участника) | |||
Строка 1: | Строка 1: | ||
(function () { |
|||
if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Watchlist' && mw.config.get( 'wgAction' ) === 'view' ) |
|||
mw.hook('wikipage.content').add(function () { |
|||
setTimeout(function () { // лечение для Firefox |
|||
var firstRun = true; |
|||
var whenPageLoaded = +(new Date()) - 20000 //add 20 sec just in case |
|||
if (mw.config.get('wgCanonicalSpecialPageName') === 'Watchlist') { |
|||
var mainTab, hideInterfaceCSS, rvOffCSS |
|||
// Polyfill |
|||
var sortingDone, allStarsOn, hoverOnTitlesDone |
|||
if (!String.prototype.includes) { |
|||
String.prototype.includes = function (search, start) { |
|||
'use strict'; |
|||
if (typeof start !== 'number') { |
|||
start = 0; |
|||
} |
|||
if (start + search.length > this.length) { |
|||
return false; |
|||
} else { |
|||
return this.indexOf(search, start) !== -1; |
|||
} |
|||
}; |
|||
} |
|||
var SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24; |
|||
var whenPageLoadedOrUpdated; |
|||
var hideInterfaceCSS, rvOffCSS; |
|||
var sortingDone, allStarsShown, hoverOnTitlesDone; |
|||
// ruwiki strings |
|||
var strings = { |
|||
watch: 'Следить', |
|||
unwatch: 'Не следить', |
|||
sortTip: 'Сортировать изменения по пространствам имён', |
|||
sortDone: 'Изменения уже отсортированы', |
|||
unwatchTip: 'Добавить/убрать звёздочки для вычёркивания страниц из списка наблюдения', |
|||
newOnly: 'Только новые', |
|||
newOnlyTip: 'Изменения с момента загрузки этой страницы', |
|||
watchlistTabNewOnlyTip: 'По клику откроются изменения с момента загрузки этой страницы', |
|||
all: 'Все', |
|||
allTip: 'Все изменения', |
|||
expandAll: 'Показать/спрятать все свёрнутые правки', |
|||
switchRevert: 'Спрятать/показать ссылки «откатить»', |
|||
fullPage: 'Спрятать/показать элементы интерфейса', |
|||
error: 'Ошибка', |
|||
unrecognizedReponse: 'ответ не распознан' |
|||
}; |
|||
mw.hook('wikipage.content').add(function ($content) { |
|||
function main() { |
|||
/* FUNCTIONS */ |
|||
function addLink(contents, tip, classes, href) { |
|||
return $('<a>') |
|||
.attr('href', href || 'javascript:') |
|||
.attr('title', tip) |
|||
.addClass(classes) |
|||
.append(contents) |
|||
.appendTo($linksIn); |
|||
} |
|||
function generateNewEntriesOnlyUrl() { |
|||
var uri = new mw.Uri(); |
|||
uri.query.from = whenPageLoadedOrUpdated; |
|||
delete uri.query.days; |
|||
return uri.toString(); |
|||
} |
|||
function generateAllEntriesUrl() { |
|||
var uri = new mw.Uri(); |
|||
delete uri.query.from; |
|||
return uri.toString(); |
|||
} |
|||
function newEntriesOnly(e) { |
|||
e.target.href = generateNewEntriesOnlyUrl(); |
|||
} |
|||
function allEntries(e) { |
|||
e.target.href = generateAllEntriesUrl(); |
|||
} |
|||
function showAllStars(e) { |
|||
if (e) { |
|||
e.preventDefault(); |
|||
} |
|||
// cookie set = stars are on |
|||
if (!allStarsShown) { |
|||
$changeslist.find('.mw-title') |
|||
.each(function (i, link) { |
|||
updateStar(getRow($(this))); |
|||
}); |
|||
if (e) { |
|||
var cookieDate = new Date($.now() + SECONDS_IN_A_DAY * 90).toGMTString(); |
|||
document.cookie = 'wlunw=1; expires=' + cookieDate + '; path=/'; |
|||
} |
|||
allStarsShown = true; |
|||
} else { // otherwise remove |
|||
$changeslist.find('.gadgetWatchlist-unwatchLink').remove(); |
|||
document.cookie = 'wlunw=0; expires=' + (new Date()).toGMTString() + '; path=/'; |
|||
if (!hoverOnTitlesDone) { |
|||
bindHoverOnTitles(); |
|||
} |
|||
allStarsShown = false; |
|||
} |
|||
} |
|||
function sortWatchlist(e) { |
|||
e.preventDefault(); |
|||
if (sortingDone) { |
|||
alert(strings.sortDone); |
|||
return; |
|||
} |
|||
$changeslist.find('h4').each(function () { // sort all days separately |
|||
var $container = $(this).next('div, ul'); |
|||
var $rows = $container.children('li, table'); |
|||
// create sorting keys |
|||
var key; |
|||
$rows.each(function (i) { |
|||
// use built-in class: either li.watchlist-5-<title> or |
|||
// table.mw-changeslist-ns100-<title> in enhanced recent changes |
|||
key = /(\d+)-(\S+)/.exec(this.className) || ['', 0, ' ']; // logs might not have this class |
|||
if (key[1] % 2) { |
|||
key[1]--; // sort talk page as if it was a base page |
|||
} |
|||
if (window.watchlistSortNamespaceOnly) { |
|||
key[2] = zzz(i); // keep timestamp order within each NS block |
|||
} |
|||
this.skey = zzz(key[1]) + ':' + key[2]; |
|||
}); |
|||
// sort array and then HTML |
|||
$rows.sort(function (a, b) { |
|||
return a.skey > b.skey ? 1 : (a.skey < b.skey ? -1 : 0); |
|||
}); |
|||
for (i = 0; i < $rows.length; i++) { |
|||
$container.append($rows.eq(i)); |
|||
} |
|||
}); |
|||
$('.mw-rcfilters-ui-changesListWrapperWidget-previousChangesIndicator').remove(); |
|||
sortingDone = true; |
|||
} |
|||
function expandMultipleEdits(e) { |
|||
e.preventDefault(); |
|||
var $collapsibles = $('.mw-changeslist .mw-collapsible:not(.mw-changeslist-legend)'); |
|||
// If at lease one branch is collapsed, we expand everything. |
|||
$collapsibles |
|||
[$collapsibles.hasClass('mw-collapsed') ? 'filter' : 'not']('.mw-collapsed') |
|||
.find('.mw-enhancedchanges-arrow') |
|||
.click(); |
|||
} |
|||
function switchRevert(e) { |
|||
if (e) { |
|||
e.preventDefault(); |
|||
} |
|||
if (!rvOffCSS) { |
|||
rvOffCSS = mw.util.addCSS('\ |
|||
.mw-rollback-link {\ |
|||
display: none;\ |
|||
}\ |
|||
'); |
|||
} else { |
|||
rvOffCSS.disabled = !rvOffCSS.disabled; |
|||
} |
|||
if (rvOffCSS.disabled) { |
|||
document.cookie = 'wlrvoff=0; expires=' + (new Date()).toGMTString() + '; path=/'; |
|||
} else if (e) { |
|||
var cookieDate = (new Date($.now() + SECONDS_IN_A_DAY * 90)).toGMTString(); |
|||
document.cookie = 'wlrvoff=1; expires=' + cookieDate + '; path=/'; |
|||
} |
|||
} |
|||
function bindHoverOnTitles() { // find all title links and assign hover event |
|||
if (hoverOnTitlesDone) return; |
|||
$changeslist.find('.mw-title') |
|||
.each(function () { |
|||
getRow($(this)) |
|||
.find('.mw-title') |
|||
.children('a') |
|||
.hover(hoverOnTitle); |
|||
}); |
|||
hoverOnTitlesDone = true; |
|||
} |
|||
function hoverOnTitle(e) { // on hover: add "unwatch" star after 1 second |
|||
var $link = $(this); |
|||
if (e.type === 'mouseenter') { |
|||
$link.data('unwatchTimeout', setTimeout(function () { |
|||
showStarOnHover($link); |
|||
}, 1000)); |
|||
} else { |
|||
clearTimeout($link.data('unwatchTimeout')); |
|||
} |
|||
} |
|||
function showStarOnHover($link) { |
|||
var $row = getRow($link); |
|||
updateStar($row); |
|||
// attach mouseleave to remove the star |
|||
if ($row.data('leaveAssigned')) return; |
|||
$row.data('leaveAssigned', true); |
|||
$row.mouseleave(function (e) { |
|||
var $unwatchLink = $(this).find('.gadgetWatchlist-unwatchLink'); |
|||
if ($unwatchLink.length && |
|||
!($unwatchLink.hasClass('gadgetWatchlist-failure') || |
|||
$unwatchLink.hasClass('gadgetWatchlist-waiting') |
|||
) && |
|||
!allStarsShown |
|||
) { |
|||
$unwatchLink.remove(); |
|||
} |
|||
}); |
|||
} |
|||
function updateStar($row) { |
|||
var action = $row.hasClass('gadgetWatchlist-unwatchedRow') ? 'watch' : 'unwatch'; |
|||
var $star = $row.find('.gadgetWatchlist-unwatchLink, .gadgetWatchlist-watchLink'); |
|||
if (!$star.length) { // create |
|||
var $link = $row.find('.mw-title').children('a'); |
|||
if (!$link.length) return; |
|||
$star = $('<a>') |
|||
.attr('href', $link.attr('href').replace(/\/wiki\//, '/ruwiki/w/index.php?title=') + '&action=' + |
|||
action) |
|||
.addClass('gadgetWatchlist-' + action + 'Link gadgetWatchlist-icon') |
|||
.click(changeWatchState) |
|||
.insertBefore($link); |
|||
} else { // update |
|||
$star |
|||
.attr('href', $star |
|||
.attr('href') |
|||
.replace(/&action=\w+/, '&action=' + action)) |
|||
.removeClass('gadgetWatchlist-' + (action === 'unwatch' ? 'watch' : 'unwatch') + 'Link') |
|||
.addClass('gadgetWatchlist-' + action + 'Link'); |
|||
} |
|||
$star.attr('title', mw.messages.get(action) || strings[action]); |
|||
} |
|||
function getRow($el) { |
|||
return $el.closest(isEnhanced ? 'tr' : 'li'); |
|||
} |
|||
function changeWatchState(e) { |
|||
var $star = $(this), errorMsg = ''; |
|||
var action; |
|||
var unwatch; |
|||
if ($star.attr('href').includes('&action=unwatch')) { |
|||
unwatch = ''; |
|||
action = 'unwatch'; |
|||
} else { |
|||
action = 'watch'; |
|||
} |
|||
var titles = getLinkTitle($star); |
|||
$star |
|||
.removeClass('gadgetWatchlist-failure') |
|||
.addClass('gadgetWatchlist-waiting'); |
|||
new mw.Api().postWithToken('watch', { |
|||
action: 'watch', |
|||
titles: titles, |
|||
unwatch: unwatch, |
|||
formatversion: 2, |
|||
}).then( |
|||
function (resp) { |
|||
if (!resp.watch || !resp.watch[0]) { |
|||
errorMsg = 'empty response'; |
|||
} else if (typeof resp.watch[0].unwatched === 'boolean') { |
|||
changeWatchStateSuccess(titles, true); |
|||
} else if (typeof resp.watch[0].watched === 'boolean') { |
|||
changeWatchStateSuccess(titles, false); |
|||
} else { |
|||
errorMsg = strings.unrecognizedReponse; |
|||
} |
|||
}, |
|||
function (code, data) { |
|||
var errorMsg = ( |
|||
// HTTP error |
|||
data.textStatus || |
|||
// API error |
|||
//ruwiki |
|||
(data.error && data.error.info) |
|||
var mm = { |
|||
); |
|||
sortTip: 'Сортировать страницы по пространствам', |
|||
if (errorMsg) { |
|||
sortDone: 'Изменения уже отсортированы', |
|||
errorMsg += ' (' + code + ')'; |
|||
unwatchTip: 'Добавить звёздочки для вычёркивания страниц из списка наблюдения', |
|||
} else { |
|||
onlynew: 'Только новые', |
|||
errorMsg = code; |
|||
onlynewTip: 'Изменения с момента загрузки этой страницы', |
|||
} |
|||
onlynewTipLowerCase: 'изменения с момента загрузки этой страницы', |
|||
} |
|||
expandAll: 'Показать/спрятать все свёрнутые правки', |
|||
).always(function () { // update unwatch link |
|||
switchRevert: 'Спрятать/показать ссылки «откатить»', |
|||
$star.removeClass('gadgetWatchlist-waiting'); |
|||
fullPage: 'Спрятать/показать элементы интерфейса' |
|||
if (errorMsg) { |
|||
}; |
|||
$star |
|||
.attr('title', strings.error + ': ' + errorMsg) |
|||
var isEnhanced = mw.util.$content.find('ul.special').length == 0 //RC type in preferences |
|||
.addClass('gadgetWatchlist-failure gadgetWatchlist-' + action + 'Link'); |
|||
} |
|||
}); |
|||
//find insertion points for links: after "days all" |
|||
e.preventDefault(); |
|||
var linksAt = $('#mw-watchlist-options').find('#days').next() |
|||
} |
|||
function changeWatchStateSuccess(name, isUnwatched) { |
|||
//UNWATCH links: |
|||
// find full name of associated talk page (or vice versa) |
|||
//on every line |
|||
var ns = getTitleNamespace(name); |
|||
if( document.cookie.indexOf('wlunw=1') != -1 ) $(showAllStars) |
|||
var name2 = name; |
|||
else $(bindHoverOnTitles) //mouseover on title |
|||
if (ns > 0) { |
|||
// switch for above, saved in a cookie |
|||
name2 = name2.replace(/^.+?:/, ''); // remove old prefix |
|||
addLnk('<img alt="x" style="width:1em;" src="/upwiki/wikipedia/commons/' |
|||
} |
|||
+ 'a/a4/Vector_skin_-_page_not_in_the_watchlist.png">', mm.unwatchTip).click(showAllStars) |
|||
ns = ns % 2 ? ns - 1 : ns + 1; // switch to associated namespace |
|||
//click on timestamp (enhanced RC) / empty space (non-enhanced) |
|||
if (ns > 0) { |
|||
name2 = mw.config.get('wgFormattedNamespaces')[ns] + ':' + name2; // add new prefix |
|||
if (document.cookie.indexOf('wlrvoff=1') != -1) switchRevert(); |
|||
} |
|||
// mark all rows that are either name or name2 |
|||
$changeslist.find('.mw-changeslist-title').each(function () { |
|||
// "sort" link |
|||
var title = getLinkTitle($(this)); |
|||
addLnk('↑↓', mm.sortTip).click(sortWatchlist); |
|||
if (title !== name && title !== name2) return; |
|||
var $row = getRow($(this)); |
|||
// "expand all" link |
|||
$row.toggleClass('gadgetWatchlist-unwatchedRow', isUnwatched); |
|||
if ($('.mw-enhancedchanges-arrow').length) { |
|||
if (!isUnwatched && !allStarsShown) { |
|||
addLnk('±', mm.expandAll).click(expandMultipleEdits); |
|||
$row.find('.gadgetWatchlist-watchLink').remove(); |
|||
} |
|||
} else { |
|||
updateStar($row); |
|||
if ($('.mw-rollback-link').length) { |
|||
} |
|||
// "switch revert" link |
|||
}); |
|||
addLnk('⎌', mm.switchRevert).click(switchRevert); |
|||
} |
} |
||
function hideInterface(e) { |
|||
// "only new" link |
|||
if (e) { |
|||
addLnk(mm.onlynew, mm.onlynewTip).mousedown(onlyNewEntries).attr('id', 'listSince'); |
|||
e.preventDefault(); |
|||
} |
|||
//TABS |
|||
var hideInterfaceCSSCode = '\ |
|||
if( window.wlNoTabs ) return |
|||
#firstHeading,\ |
|||
var mainTab = $('#ca-special, #ca-nstab-special').eq(0) //"Special" tab |
|||
div#siteNotice,\ |
|||
#contentSub,\ |
|||
//change main tab into "watchlist Δ" |
|||
.mw-wlheader-showupdated,\ |
|||
var wl = $.trim( $('h1#firstHeading').text() ) |
|||
fieldset#mw-watchlist-options,\ |
|||
mainTab.find('a') //replace "Special" tab text with "Watchlist" |
|||
div.mw-rc-label-legend,\ |
|||
.text(wl + ' △') //Δ is good but monobook makes is lowercase |
|||
#mw-fr-watchlist-pending-notice,\ |
|||
.attr('title', wl + ' — ' + mm.onlynewTipLowerCase) |
|||
.mw-indicators,\ |
|||
.on('mousedown keydown', onlyNewEntries) |
|||
.mw-rcfilters-ui-filterTagMultiselectWidget,\ |
|||
.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinksTable,\ |
|||
//add "hideInterface" tab |
|||
.mw-rcfilters-ui-watchlistTopSectionWidget-editWatchlistButton,\ |
|||
mainTab.clone(true).removeClass('selected') |
|||
.mw-rcfilters-ui-watchlistTopSectionWidget-separator {\ |
|||
.appendTo(mainTab.parent()) |
|||
display: none;\ |
|||
.click(hideInterface) |
|||
}\ |
|||
.attr('id','').attr('href','#') |
|||
\ |
|||
.find('a') |
|||
.client-js .mw-special-Watchlist .rcfilters-head.rcfilters-head {\ |
|||
.text('↸').attr('title', mm.fullPage).attr('accesskey','') |
|||
min-height: auto;\ |
|||
}\ |
|||
if( document.cookie.indexOf('wlmax=1') != -1 ) hideInterface() |
|||
'; |
|||
if (!hideInterfaceCSS) { |
|||
return |
|||
// If the new filters are on, wait until the interface is initialized. |
|||
if (!mw.user.options.get('wlenhancedfilters-disable')) { |
|||
hideInterfaceCSS = mw.util.addCSS(hideInterfaceCSSCode); |
|||
$('.mw-rcfilters-ui-markSeenButtonWidget') |
|||
.wrap('<div>') |
|||
.parent() |
|||
function addLnk(txt, tip){ |
|||
.addClass('mw-rcfilters-ui-markSeenButtonWidget-container') |
|||
linksAt.before(' ') |
|||
.appendTo('.mw-rcfilters-ui-watchlistTopSectionWidget-watchlistDetails'); |
|||
return $('<a href=# title="'+tip+'">'+txt+'</a>').insertBefore(linksAt) |
|||
} else { |
|||
} |
|||
hideInterfaceCSS = mw.util.addCSS(hideInterfaceCSSCode); |
|||
} |
|||
} else { |
|||
function onlyNewEntries(e) { |
|||
hideInterfaceCSS.disabled = !hideInterfaceCSS.disabled; |
|||
var url = window.location.href.split('#')[0] |
|||
if (!mw.user.options.get('wlenhancedfilters-disable')) { |
|||
var days = ( +(new Date()) - whenPageLoaded)/(1000 * 3600 * 24) |
|||
$('.mw-rcfilters-ui-markSeenButtonWidget-container') |
|||
if( days < 0 ) days = 0.01 //negative might happen when adjusting local time |
|||
.appendTo(hideInterfaceCSS.disabled ? |
|||
e.target.href = /[?&]days=/.test(url) |
|||
'.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinksTable .mw-rcfilters-ui-cell:first-child' : |
|||
? url.replace(/([?&]days=)[^&]*/, '$1'+days) |
|||
'.mw-rcfilters-ui-watchlistTopSectionWidget-watchlistDetails'); |
|||
: url + (url.indexOf('?') < 0 ? '?':'&') + 'days=' + days |
|||
} |
|||
return true |
|||
} |
|||
} |
|||
if (e) { |
|||
if (!hideInterfaceCSS.disabled) { |
|||
var cookieDate = new Date($.now() + SECONDS_IN_A_DAY * 90).toGMTString(); |
|||
function showAllStars(e){ |
|||
document.cookie = 'wlmax=1; expires=' + cookieDate + '; path=/'; |
|||
if( !allStarsOn ){ |
|||
} else { |
|||
mw.util.$content.find('a[href*="action=history"]') |
|||
document.cookie = 'wlmax=0; expires=' + (new Date()).toGMTString() + '; path=/'; |
|||
.each( function(i, lnk){ updateStar( getRow(this) ) } ) |
|||
} |
|||
document.cookie = 'wlunw=1; path=/' |
|||
} |
|||
allStarsOn = true |
|||
} |
|||
}else{ //otherwise remove |
|||
mw.util.$content.find('a.aj-unwatch').not('unwatched').remove() |
|||
function getTitleNamespace(title) { // returns namespace number |
|||
document.cookie = 'wlunw=0; expires=' + (new Date()).toGMTString() + '; path=/' |
|||
var prefix = /^(.+?):/.exec(title); |
|||
if( !hoverOnTitlesDone ) bindHoverOnTitles() |
|||
if (!prefix) { |
|||
allStarsOn = false |
|||
return 0; // no prefix means article |
|||
} |
|||
} |
|||
return false |
|||
return mw.config.get('wgNamespaceIds')[ prefix[1].toLowerCase().replace(/ /g, '_') ] || 0; |
|||
} |
|||
} |
|||
function sortWatchlist(e){ |
|||
function getLinkTitle($link) { // gets title for unwatch/watch links & common page links |
|||
e.preventDefault() |
|||
// Titles can be absent for .mw-changeslist-title elements because of Popups extension. |
|||
if( sortingDone ) return alert(mm.sortDone) |
|||
var title = $link.filter('.mw-changeslist-title').attr('title'); |
|||
mw.util.$content.find('h4').each(function(){ //sort all days separately |
|||
var container = $(this).next('div, ul') |
|||
if (!title) { |
|||
var rows = container.children('li, table') |
|||
title = mw.util.getParamValue('title', $link.attr('href')); |
|||
//create sorting keys |
|||
title = title && title.replace(/_/g, ' '); |
|||
var key |
|||
} |
|||
rows.each( function(i){ |
|||
//use built-in class: either li.watchlist-5-<title> or table.mw-changeslist-ns100-<title> in enhanced RC |
|||
if (!title) { |
|||
key = /(\d+)-(\S+)/.exec( this.className ) || ['', 0, ' '] //logs might not have this class |
|||
title = $link.filter('.mw-changeslist-title').text(); |
|||
if( key[1] % 2 ) key[1]-- //sort talk page as if it was a base page |
|||
} |
|||
if( window.watchlistSortNamespaceOnly ) key[2] = zzz(i) //keep timestamp order within each NS block |
|||
this.skey = zzz(key[1]) + ':' + key[2] |
|||
return title; |
|||
}) |
|||
} |
|||
//sort array and then HTML |
|||
rows.sort(function(a,b){ return a.skey > b.skey ? 1 : ( a.skey < b.skey ? -1 : 0 ) }) |
|||
function zzz(s) { // 5 -> 005 |
|||
for( i=0; i<rows.length; i++ ) container.append( rows.eq(i) ) |
|||
s = s.toString(); |
|||
}) |
|||
if (s.length === 1) { |
|||
sortingDone = true |
|||
return '00' + s; |
|||
} |
|||
} else if (s.length === 2) { |
|||
return '0' + s; |
|||
function expandMultipleEdits(e){ |
|||
} else { |
|||
e.preventDefault() |
|||
return s; |
|||
var i = 0, sp, state = $('.mw-changeslist .mw-collapsible')[0].style.display |
|||
} |
|||
while( sp=$('.mw-changeslist .mw-collapsible')[i++] ) |
|||
} |
|||
if( sp.style.display == state ) $(sp).find('.mw-enhancedchanges-arrow').click() |
|||
} |
|||
function zeroPad(n, p) { |
|||
return ('0000' + n).slice(-p); |
|||
function switchRevert(e) { |
|||
} |
|||
if (e) { |
|||
e.preventDefault(); |
|||
function generateTimestamp(date) { |
|||
} |
|||
return ( |
|||
if (!rvOffCSS) { |
|||
zeroPad(date.getUTCFullYear(), 4) + |
|||
rvOffCSS = mw.util.addCSS('.mw-rollback-link { display:none; }') |
|||
zeroPad(date.getUTCMonth() + 1, 2) + |
|||
document.cookie = 'wlrvoff=1; expires=' + (new Date($.now() + 1000 * 60 * 60 * 24 * 365)).toGMTString() + '; path=/'; |
|||
zeroPad(date.getUTCDate(), 2) + |
|||
} else { |
|||
zeroPad(date.getUTCHours(), 2) + |
|||
rvOffCSS.disabled = !rvOffCSS.disabled; |
|||
zeroPad(date.getUTCMinutes(), 2) + |
|||
document.cookie = 'wlrvoff=0; expires=' + (new Date()).toGMTString() + '; path=/'; |
|||
zeroPad(date.getUTCSeconds(), 2) |
|||
} |
|||
); |
|||
} |
|||
} |
|||
function bindHoverOnTitles(){ //find all "titles" links and assign hover event |
|||
/* MAIN BLOCK */ |
|||
if( hoverOnTitlesDone ) return |
|||
//$('#mw-content-text').find( isEnhanced ? 'table' : 'li') |
|||
// add 5–20 seconds just in case (for example, the scripting could take too much) |
|||
mw.util.$content.find('a[href*="action=history"]') |
|||
whenPageLoadedOrUpdated = generateTimestamp(new Date(new Date().getTime() - (firstRun ? 20000 : 5000))); |
|||
.each( function(){ |
|||
getRow(this).find('a[href^="/wiki/"]:first').hover( hoverOnTitle ) |
|||
sortingDone = false; |
|||
}) |
|||
allStarsShown = false; |
|||
hoverOnTitlesDone = true |
|||
hoverOnTitlesDone = false; |
|||
} |
|||
// UNWATCH LINKS |
|||
// on every line |
|||
function hoverOnTitle(e){ //on hover: add "unwatch" star after 1s |
|||
if (document.cookie.includes('wlunw=1')) { |
|||
var lnk = $(this) |
|||
showAllStars(); |
|||
if( e.type == 'mouseenter' ) |
|||
} else { |
|||
lnk.data( 'uwTimeout', setTimeout( function(){showStarOnHover(lnk)}, 1000 ) ) |
|||
bindHoverOnTitles(); // mouseover on title |
|||
else |
|||
} |
|||
clearTimeout( lnk.data( 'uwTimeout' ) ) |
|||
} |
|||
if (firstRun) { |
|||
if (document.cookie.includes('wlrvoff=1')) { |
|||
switchRevert(); |
|||
function showStarOnHover(lnk){ |
|||
} |
|||
var row = getRow(lnk) |
|||
updateStar(row) |
|||
// find insertion point for links |
|||
//attach mouseleave to remove the star |
|||
$linksIn = $('<div>') |
|||
if( row.attr('leaveAssigned') ) return |
|||
.addClass('mw-rcfilters-ui-cell gadgetWatchlist-linksContainer') |
|||
row.attr('leaveAssigned', true) |
|||
.insertBefore($( |
|||
row.mouseleave( function(e){ |
|||
!mw.user.options.get('wlenhancedfilters-disable') ? |
|||
var uw = $(this).find('.aj-unwatch') |
|||
'.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinks' : |
|||
if( uw.length |
|||
'.wlinfo' |
|||
&& /unwatch/.test( uw.attr('href') ) |
|||
)); |
|||
&& !/waiting|failure/.test( uw.attr('class') ) |
|||
&& !allStarsOn |
|||
// "show all stars" link |
|||
) |
|||
addLink('', strings.unwatchTip, 'gadgetWatchlist-icon gadgetWatchlist-icon-unwatched') |
|||
uw.remove() |
|||
.click(showAllStars); |
|||
}) |
|||
// FUNCTION LINKS |
|||
} |
|||
// "sort" link |
|||
addLink('↑↓', strings.sortTip).click(sortWatchlist); |
|||
// "expand all" link |
|||
// Auto-update could be used, so even if there is no $('.mw-enhancedchanges-arrow') elements, we keep |
|||
function updateStar(row){ |
|||
// the button. |
|||
var star = row.find('a.aj-unwatch') |
|||
if (isEnhanced) { |
|||
if( !star.length ){ //create |
|||
addLink('±', strings.expandAll).click(expandMultipleEdits); |
|||
star = $('<a class=aj-unwatch href="' |
|||
} |
|||
+ row.find('a[href*="action=history"]').attr('href').replace(/&curid=\d+/,'') |
|||
+ '">x</a>') |
|||
// "switch revert" link |
|||
.click(ajaxUnwatch) |
|||
if (mw.config.get('wgUserGroups').indexOf('rollbacker') !== -1 || |
|||
.insertBefore( row.find('a[href^="/wiki/"]:first') ) |
|||
mw.config.get('wgUserGroups').indexOf('sysop') !== -1 |
|||
.after(' ') |
|||
) { |
|||
} |
|||
addLink('⎌', strings.switchRevert).click(switchRevert); |
|||
//update |
|||
} |
|||
var isUnwatched = row.hasClass('unwatched') |
|||
var state = isUnwatched ? 'watch' : 'unwatch' |
|||
// "new only" link |
|||
star.attr( 'title', mw.msg(state) ) |
|||
addLink(strings.newOnly, strings.newOnlyTip, undefined, generateNewEntriesOnlyUrl()) |
|||
.attr( 'href', star.attr('href').replace(/&action=\w+/, '&action='+ state) ) |
|||
.mousedown(newEntriesOnly); |
|||
.html('<img alt=x style="width:0.6em" ' |
|||
+ 'src="/upwiki/wikipedia/commons/' |
|||
if (mw.util.getParamValue('from') !== null) { |
|||
+ ( isUnwatched |
|||
// "all" link |
|||
? 'a/a4/Vector_skin_-_page_not_in_the_watchlist.png' |
|||
addLink(strings.all, strings.allTip, undefined, generateAllEntriesUrl()).mousedown(allEntries); |
|||
: 'f/f2/Vector_skin_-_page_in_the_watchlist.png' |
|||
} |
|||
) |
|||
+ '" />') |
|||
// TABS |
|||
} |
|||
if (!window.wlNoTabs) { |
|||
var $mainTab = $('#ca-nstab-special').first(); // "Special" tab |
|||
function getRow(el){ |
|||
return $(el).closest(isEnhanced ? 'tr' : 'li') |
|||
// change main tab into "watchlist Δ" |
|||
} |
|||
var watchlistTitle = $.trim($('#firstHeading').text()); |
|||
$mainTab |
|||
.find('a') // replace "Special" with "Watchlist" as tab text |
|||
.text(watchlistTitle + ' △') // Δ is good but monobook makes is lowercase |
|||
.attr('title', strings.watchlistTabNewOnlyTip) |
|||
.attr('href', generateNewEntriesOnlyUrl()) |
|||
.on('mousedown keydown', newEntriesOnly); |
|||
// add "hideInterface" tab |
|||
$mainTab |
|||
.clone(true) |
|||
function ajaxUnwatch(e) { |
|||
.attr('id', '') |
|||
var xLnk = $(this), errMsg = '' |
|||
.attr('href', '') |
|||
var req = { token: mw.user.tokens.get('watchToken'), |
|||
.removeClass('selected') |
|||
title: getLinkTitle(xLnk) } |
|||
.click(hideInterface) |
|||
if( /&action=unwatch/.test(xLnk.attr('href')) ) req.unwatch = '' |
|||
.appendTo($mainTab.parent()) |
|||
xLnk.addClass('waiting') |
|||
.find('a') |
|||
$.ajax({ |
|||
.text('↸') |
|||
type:'POST', dataType: 'json', |
|||
.attr('title', strings.fullPage) |
|||
url: mw.util.wikiScript('api') + '?action=watch&format=json', |
|||
.attr('accesskey', ''); |
|||
data: req, |
|||
} |
|||
timeout: 5000, |
|||
success: function(resp){ |
|||
if( resp.error ) errMsg = resp.error.info |
|||
// OTHER TASKS |
|||
else if( !resp.watch ) errMsg = 'empty response' |
|||
if (document.cookie.includes('wlmax=1')) { |
|||
else if( typeof resp.watch.unwatched == 'string') unwatchSuccess( req.title, true ) |
|||
hideInterface(); |
|||
else if( typeof resp.watch.watched == 'string') unwatchSuccess( req.title, false ) |
|||
} |
|||
else errMsg = 'unrecognized response' |
|||
}, |
|||
mw.util.addCSS('\ |
|||
error: function(xhr, status, err) { |
|||
.mw-special-Watchlist .mw-changeslist .mw-rollback-link.mw-rollback-link {\ |
|||
errMsg = status + ':' + err |
|||
visibility: visible;\ |
|||
}, |
|||
}\ |
|||
complete: function(){ //update X link |
|||
'); |
|||
xLnk.removeClass('waiting') |
|||
if( errMsg ) xLnk.attr( 'title', 'API error: ' + errMsg ).addClass('failure') |
|||
firstRun = false; |
|||
else xLnk.removeClass('failure') |
|||
} |
|||
}) |
|||
return; |
|||
} |
} |
||
// Occurs in watchlist when mediawiki.rcfilters.filters.ui module for some reason fires |
|||
// wikipage.content for the second time with an element that is not in the DOM, |
|||
// fieldset#mw-watchlist-options (in mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelUpdate |
|||
function unwatchSuccess(name, isUnwatched) { |
|||
// function). |
|||
//find full name of associated talk page (or vice versa) |
|||
if (!$content.parent().length) return; |
|||
var ns = getTitleNamespace(name) |
|||
var name2 = name |
|||
var $changeslist = $content.find('.mw-changeslist'); |
|||
if( ns > 0 ) name2 = name2.replace(/^.+?:/,'') //remove old prefix |
|||
if( ns % 2 ) ns--; else ns++ //switch to "other" namespace |
|||
// Recent changes type in preferences. Don't confuse enhanced recent changes with enhanced filters. |
|||
if( ns > 0 ) name2 = mw.config.get( 'wgFormattedNamespaces' )[ns] + ':' + name2 //add new prefix |
|||
// mw.user.options.get('usenewrc') shouldn't be used here: RC mode could be set from URL. |
|||
//mark all rows that are either name or name2 |
|||
var isEnhanced = !$changeslist.find('ul.special').length; |
|||
mw.util.$content.find('a[href*="action=history"]').each(function(){ |
|||
var ttl = getLinkTitle(this) |
|||
if (mw.util.getParamValue('from') !== null) { |
|||
if( ttl != name && ttl != name2 ) return |
|||
$('#mw-watchlist-form input[name="from"]').remove(); |
|||
var row = getRow(this) |
|||
} |
|||
row.toggleClass('unwatched', isUnwatched || false) |
|||
updateStar(row) |
|||
if (!mw.user.options.get('wlenhancedfilters-disable')) { |
|||
if( !isUnwatched && !allStarsOn) row.find('a.aj-unwatch').remove() |
|||
mw.hook('structuredChangeFilters.ui.initialized').add(main); |
|||
}) |
|||
} else { |
|||
} |
|||
if (!navigator.userAgent.toLowerCase().includes('firefox')) { |
|||
main(); |
|||
} else { |
|||
// Cure for Firefox |
|||
setTimeout(main, 0); |
|||
} |
|||
} |
|||
}); |
|||
function hideInterface(e){ |
|||
if( e ) e.preventDefault() |
|||
if (!hideInterfaceCSS) hideInterfaceCSS = mw.util.addCSS('\ |
|||
h4 {font-size:90%}\ |
|||
#firstHeading,\ |
|||
div#siteNotice, #contentSub, fieldset#mw-watchlist-options,\ |
|||
div.mw-rc-label-legend, #mw-fr-watchlist-pending-notice {display:none}') |
|||
else hideInterfaceCSS.disabled = !hideInterfaceCSS.disabled |
|||
document.cookie = 'wlmax=' + (!hideInterfaceCSS.disabled ? '1; path=/' : '0; expires=' + (new Date()).toGMTString() + '; path=/') |
|||
} |
|||
function getTitleNamespace(title){ //returns namespace number |
|||
var prefix = /^(.+?):/.exec(title) |
|||
if( !prefix ) return 0 //no prefix means article |
|||
return mw.config.get( 'wgNamespaceIds' )[ prefix[1].toLowerCase().replace(/ /g,'_') ] || 0 |
|||
} |
|||
function getLinkTitle (lnk){ //gets 'title=' part from a link |
|||
return mw.util.getParamValue('title', $(lnk).attr('href')).replace(/_/g,' ') |
|||
//var ma = /(&|\?)title=([^&]+)/.exec( $(lnk).attr('href') ) |
|||
//if( ma ) return decodeURIComponent(ma[2]).replace(/_/g,' ') |
|||
//else return '' |
|||
} |
|||
function zzz(s){ // 5 -> 005 |
|||
s = s.toString() |
|||
if( s.length==1 ) return '00'+s |
|||
else if( s.length==2 ) return '0'+s |
|||
else return s |
|||
} |
} |
||
} |
})(); |
||
})//main |
Текущая версия от 04:06, 15 августа 2021
(function () {
var firstRun = true;
if (mw.config.get('wgCanonicalSpecialPageName') === 'Watchlist') {
// Polyfill
if (!String.prototype.includes) {
String.prototype.includes = function (search, start) {
'use strict';
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
var SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24;
var whenPageLoadedOrUpdated;
var hideInterfaceCSS, rvOffCSS;
var sortingDone, allStarsShown, hoverOnTitlesDone;
// ruwiki strings
var strings = {
watch: 'Следить',
unwatch: 'Не следить',
sortTip: 'Сортировать изменения по пространствам имён',
sortDone: 'Изменения уже отсортированы',
unwatchTip: 'Добавить/убрать звёздочки для вычёркивания страниц из списка наблюдения',
newOnly: 'Только новые',
newOnlyTip: 'Изменения с момента загрузки этой страницы',
watchlistTabNewOnlyTip: 'По клику откроются изменения с момента загрузки этой страницы',
all: 'Все',
allTip: 'Все изменения',
expandAll: 'Показать/спрятать все свёрнутые правки',
switchRevert: 'Спрятать/показать ссылки «откатить»',
fullPage: 'Спрятать/показать элементы интерфейса',
error: 'Ошибка',
unrecognizedReponse: 'ответ не распознан'
};
mw.hook('wikipage.content').add(function ($content) {
function main() {
/* FUNCTIONS */
function addLink(contents, tip, classes, href) {
return $('<a>')
.attr('href', href || 'javascript:')
.attr('title', tip)
.addClass(classes)
.append(contents)
.appendTo($linksIn);
}
function generateNewEntriesOnlyUrl() {
var uri = new mw.Uri();
uri.query.from = whenPageLoadedOrUpdated;
delete uri.query.days;
return uri.toString();
}
function generateAllEntriesUrl() {
var uri = new mw.Uri();
delete uri.query.from;
return uri.toString();
}
function newEntriesOnly(e) {
e.target.href = generateNewEntriesOnlyUrl();
}
function allEntries(e) {
e.target.href = generateAllEntriesUrl();
}
function showAllStars(e) {
if (e) {
e.preventDefault();
}
// cookie set = stars are on
if (!allStarsShown) {
$changeslist.find('.mw-title')
.each(function (i, link) {
updateStar(getRow($(this)));
});
if (e) {
var cookieDate = new Date($.now() + SECONDS_IN_A_DAY * 90).toGMTString();
document.cookie = 'wlunw=1; expires=' + cookieDate + '; path=/';
}
allStarsShown = true;
} else { // otherwise remove
$changeslist.find('.gadgetWatchlist-unwatchLink').remove();
document.cookie = 'wlunw=0; expires=' + (new Date()).toGMTString() + '; path=/';
if (!hoverOnTitlesDone) {
bindHoverOnTitles();
}
allStarsShown = false;
}
}
function sortWatchlist(e) {
e.preventDefault();
if (sortingDone) {
alert(strings.sortDone);
return;
}
$changeslist.find('h4').each(function () { // sort all days separately
var $container = $(this).next('div, ul');
var $rows = $container.children('li, table');
// create sorting keys
var key;
$rows.each(function (i) {
// use built-in class: either li.watchlist-5-<title> or
// table.mw-changeslist-ns100-<title> in enhanced recent changes
key = /(\d+)-(\S+)/.exec(this.className) || ['', 0, ' ']; // logs might not have this class
if (key[1] % 2) {
key[1]--; // sort talk page as if it was a base page
}
if (window.watchlistSortNamespaceOnly) {
key[2] = zzz(i); // keep timestamp order within each NS block
}
this.skey = zzz(key[1]) + ':' + key[2];
});
// sort array and then HTML
$rows.sort(function (a, b) {
return a.skey > b.skey ? 1 : (a.skey < b.skey ? -1 : 0);
});
for (i = 0; i < $rows.length; i++) {
$container.append($rows.eq(i));
}
});
$('.mw-rcfilters-ui-changesListWrapperWidget-previousChangesIndicator').remove();
sortingDone = true;
}
function expandMultipleEdits(e) {
e.preventDefault();
var $collapsibles = $('.mw-changeslist .mw-collapsible:not(.mw-changeslist-legend)');
// If at lease one branch is collapsed, we expand everything.
$collapsibles
[$collapsibles.hasClass('mw-collapsed') ? 'filter' : 'not']('.mw-collapsed')
.find('.mw-enhancedchanges-arrow')
.click();
}
function switchRevert(e) {
if (e) {
e.preventDefault();
}
if (!rvOffCSS) {
rvOffCSS = mw.util.addCSS('\
.mw-rollback-link {\
display: none;\
}\
');
} else {
rvOffCSS.disabled = !rvOffCSS.disabled;
}
if (rvOffCSS.disabled) {
document.cookie = 'wlrvoff=0; expires=' + (new Date()).toGMTString() + '; path=/';
} else if (e) {
var cookieDate = (new Date($.now() + SECONDS_IN_A_DAY * 90)).toGMTString();
document.cookie = 'wlrvoff=1; expires=' + cookieDate + '; path=/';
}
}
function bindHoverOnTitles() { // find all title links and assign hover event
if (hoverOnTitlesDone) return;
$changeslist.find('.mw-title')
.each(function () {
getRow($(this))
.find('.mw-title')
.children('a')
.hover(hoverOnTitle);
});
hoverOnTitlesDone = true;
}
function hoverOnTitle(e) { // on hover: add "unwatch" star after 1 second
var $link = $(this);
if (e.type === 'mouseenter') {
$link.data('unwatchTimeout', setTimeout(function () {
showStarOnHover($link);
}, 1000));
} else {
clearTimeout($link.data('unwatchTimeout'));
}
}
function showStarOnHover($link) {
var $row = getRow($link);
updateStar($row);
// attach mouseleave to remove the star
if ($row.data('leaveAssigned')) return;
$row.data('leaveAssigned', true);
$row.mouseleave(function (e) {
var $unwatchLink = $(this).find('.gadgetWatchlist-unwatchLink');
if ($unwatchLink.length &&
!($unwatchLink.hasClass('gadgetWatchlist-failure') ||
$unwatchLink.hasClass('gadgetWatchlist-waiting')
) &&
!allStarsShown
) {
$unwatchLink.remove();
}
});
}
function updateStar($row) {
var action = $row.hasClass('gadgetWatchlist-unwatchedRow') ? 'watch' : 'unwatch';
var $star = $row.find('.gadgetWatchlist-unwatchLink, .gadgetWatchlist-watchLink');
if (!$star.length) { // create
var $link = $row.find('.mw-title').children('a');
if (!$link.length) return;
$star = $('<a>')
.attr('href', $link.attr('href').replace(/\/wiki\//, '/ruwiki/w/index.php?title=') + '&action=' +
action)
.addClass('gadgetWatchlist-' + action + 'Link gadgetWatchlist-icon')
.click(changeWatchState)
.insertBefore($link);
} else { // update
$star
.attr('href', $star
.attr('href')
.replace(/&action=\w+/, '&action=' + action))
.removeClass('gadgetWatchlist-' + (action === 'unwatch' ? 'watch' : 'unwatch') + 'Link')
.addClass('gadgetWatchlist-' + action + 'Link');
}
$star.attr('title', mw.messages.get(action) || strings[action]);
}
function getRow($el) {
return $el.closest(isEnhanced ? 'tr' : 'li');
}
function changeWatchState(e) {
var $star = $(this), errorMsg = '';
var action;
var unwatch;
if ($star.attr('href').includes('&action=unwatch')) {
unwatch = '';
action = 'unwatch';
} else {
action = 'watch';
}
var titles = getLinkTitle($star);
$star
.removeClass('gadgetWatchlist-failure')
.addClass('gadgetWatchlist-waiting');
new mw.Api().postWithToken('watch', {
action: 'watch',
titles: titles,
unwatch: unwatch,
formatversion: 2,
}).then(
function (resp) {
if (!resp.watch || !resp.watch[0]) {
errorMsg = 'empty response';
} else if (typeof resp.watch[0].unwatched === 'boolean') {
changeWatchStateSuccess(titles, true);
} else if (typeof resp.watch[0].watched === 'boolean') {
changeWatchStateSuccess(titles, false);
} else {
errorMsg = strings.unrecognizedReponse;
}
},
function (code, data) {
var errorMsg = (
// HTTP error
data.textStatus ||
// API error
(data.error && data.error.info)
);
if (errorMsg) {
errorMsg += ' (' + code + ')';
} else {
errorMsg = code;
}
}
).always(function () { // update unwatch link
$star.removeClass('gadgetWatchlist-waiting');
if (errorMsg) {
$star
.attr('title', strings.error + ': ' + errorMsg)
.addClass('gadgetWatchlist-failure gadgetWatchlist-' + action + 'Link');
}
});
e.preventDefault();
}
function changeWatchStateSuccess(name, isUnwatched) {
// find full name of associated talk page (or vice versa)
var ns = getTitleNamespace(name);
var name2 = name;
if (ns > 0) {
name2 = name2.replace(/^.+?:/, ''); // remove old prefix
}
ns = ns % 2 ? ns - 1 : ns + 1; // switch to associated namespace
if (ns > 0) {
name2 = mw.config.get('wgFormattedNamespaces')[ns] + ':' + name2; // add new prefix
}
// mark all rows that are either name or name2
$changeslist.find('.mw-changeslist-title').each(function () {
var title = getLinkTitle($(this));
if (title !== name && title !== name2) return;
var $row = getRow($(this));
$row.toggleClass('gadgetWatchlist-unwatchedRow', isUnwatched);
if (!isUnwatched && !allStarsShown) {
$row.find('.gadgetWatchlist-watchLink').remove();
} else {
updateStar($row);
}
});
}
function hideInterface(e) {
if (e) {
e.preventDefault();
}
var hideInterfaceCSSCode = '\
#firstHeading,\
div#siteNotice,\
#contentSub,\
.mw-wlheader-showupdated,\
fieldset#mw-watchlist-options,\
div.mw-rc-label-legend,\
#mw-fr-watchlist-pending-notice,\
.mw-indicators,\
.mw-rcfilters-ui-filterTagMultiselectWidget,\
.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinksTable,\
.mw-rcfilters-ui-watchlistTopSectionWidget-editWatchlistButton,\
.mw-rcfilters-ui-watchlistTopSectionWidget-separator {\
display: none;\
}\
\
.client-js .mw-special-Watchlist .rcfilters-head.rcfilters-head {\
min-height: auto;\
}\
';
if (!hideInterfaceCSS) {
// If the new filters are on, wait until the interface is initialized.
if (!mw.user.options.get('wlenhancedfilters-disable')) {
hideInterfaceCSS = mw.util.addCSS(hideInterfaceCSSCode);
$('.mw-rcfilters-ui-markSeenButtonWidget')
.wrap('<div>')
.parent()
.addClass('mw-rcfilters-ui-markSeenButtonWidget-container')
.appendTo('.mw-rcfilters-ui-watchlistTopSectionWidget-watchlistDetails');
} else {
hideInterfaceCSS = mw.util.addCSS(hideInterfaceCSSCode);
}
} else {
hideInterfaceCSS.disabled = !hideInterfaceCSS.disabled;
if (!mw.user.options.get('wlenhancedfilters-disable')) {
$('.mw-rcfilters-ui-markSeenButtonWidget-container')
.appendTo(hideInterfaceCSS.disabled ?
'.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinksTable .mw-rcfilters-ui-cell:first-child' :
'.mw-rcfilters-ui-watchlistTopSectionWidget-watchlistDetails');
}
}
if (e) {
if (!hideInterfaceCSS.disabled) {
var cookieDate = new Date($.now() + SECONDS_IN_A_DAY * 90).toGMTString();
document.cookie = 'wlmax=1; expires=' + cookieDate + '; path=/';
} else {
document.cookie = 'wlmax=0; expires=' + (new Date()).toGMTString() + '; path=/';
}
}
}
function getTitleNamespace(title) { // returns namespace number
var prefix = /^(.+?):/.exec(title);
if (!prefix) {
return 0; // no prefix means article
}
return mw.config.get('wgNamespaceIds')[ prefix[1].toLowerCase().replace(/ /g, '_') ] || 0;
}
function getLinkTitle($link) { // gets title for unwatch/watch links & common page links
// Titles can be absent for .mw-changeslist-title elements because of Popups extension.
var title = $link.filter('.mw-changeslist-title').attr('title');
if (!title) {
title = mw.util.getParamValue('title', $link.attr('href'));
title = title && title.replace(/_/g, ' ');
}
if (!title) {
title = $link.filter('.mw-changeslist-title').text();
}
return title;
}
function zzz(s) { // 5 -> 005
s = s.toString();
if (s.length === 1) {
return '00' + s;
} else if (s.length === 2) {
return '0' + s;
} else {
return s;
}
}
function zeroPad(n, p) {
return ('0000' + n).slice(-p);
}
function generateTimestamp(date) {
return (
zeroPad(date.getUTCFullYear(), 4) +
zeroPad(date.getUTCMonth() + 1, 2) +
zeroPad(date.getUTCDate(), 2) +
zeroPad(date.getUTCHours(), 2) +
zeroPad(date.getUTCMinutes(), 2) +
zeroPad(date.getUTCSeconds(), 2)
);
}
/* MAIN BLOCK */
// add 5–20 seconds just in case (for example, the scripting could take too much)
whenPageLoadedOrUpdated = generateTimestamp(new Date(new Date().getTime() - (firstRun ? 20000 : 5000)));
sortingDone = false;
allStarsShown = false;
hoverOnTitlesDone = false;
// UNWATCH LINKS
// on every line
if (document.cookie.includes('wlunw=1')) {
showAllStars();
} else {
bindHoverOnTitles(); // mouseover on title
}
if (firstRun) {
if (document.cookie.includes('wlrvoff=1')) {
switchRevert();
}
// find insertion point for links
$linksIn = $('<div>')
.addClass('mw-rcfilters-ui-cell gadgetWatchlist-linksContainer')
.insertBefore($(
!mw.user.options.get('wlenhancedfilters-disable') ?
'.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinks' :
'.wlinfo'
));
// "show all stars" link
addLink('', strings.unwatchTip, 'gadgetWatchlist-icon gadgetWatchlist-icon-unwatched')
.click(showAllStars);
// FUNCTION LINKS
// "sort" link
addLink('↑↓', strings.sortTip).click(sortWatchlist);
// "expand all" link
// Auto-update could be used, so even if there is no $('.mw-enhancedchanges-arrow') elements, we keep
// the button.
if (isEnhanced) {
addLink('±', strings.expandAll).click(expandMultipleEdits);
}
// "switch revert" link
if (mw.config.get('wgUserGroups').indexOf('rollbacker') !== -1 ||
mw.config.get('wgUserGroups').indexOf('sysop') !== -1
) {
addLink('⎌', strings.switchRevert).click(switchRevert);
}
// "new only" link
addLink(strings.newOnly, strings.newOnlyTip, undefined, generateNewEntriesOnlyUrl())
.mousedown(newEntriesOnly);
if (mw.util.getParamValue('from') !== null) {
// "all" link
addLink(strings.all, strings.allTip, undefined, generateAllEntriesUrl()).mousedown(allEntries);
}
// TABS
if (!window.wlNoTabs) {
var $mainTab = $('#ca-nstab-special').first(); // "Special" tab
// change main tab into "watchlist Δ"
var watchlistTitle = $.trim($('#firstHeading').text());
$mainTab
.find('a') // replace "Special" with "Watchlist" as tab text
.text(watchlistTitle + ' △') // Δ is good but monobook makes is lowercase
.attr('title', strings.watchlistTabNewOnlyTip)
.attr('href', generateNewEntriesOnlyUrl())
.on('mousedown keydown', newEntriesOnly);
// add "hideInterface" tab
$mainTab
.clone(true)
.attr('id', '')
.attr('href', '')
.removeClass('selected')
.click(hideInterface)
.appendTo($mainTab.parent())
.find('a')
.text('↸')
.attr('title', strings.fullPage)
.attr('accesskey', '');
}
// OTHER TASKS
if (document.cookie.includes('wlmax=1')) {
hideInterface();
}
mw.util.addCSS('\
.mw-special-Watchlist .mw-changeslist .mw-rollback-link.mw-rollback-link {\
visibility: visible;\
}\
');
firstRun = false;
}
return;
}
// Occurs in watchlist when mediawiki.rcfilters.filters.ui module for some reason fires
// wikipage.content for the second time with an element that is not in the DOM,
// fieldset#mw-watchlist-options (in mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelUpdate
// function).
if (!$content.parent().length) return;
var $changeslist = $content.find('.mw-changeslist');
// Recent changes type in preferences. Don't confuse enhanced recent changes with enhanced filters.
// mw.user.options.get('usenewrc') shouldn't be used here: RC mode could be set from URL.
var isEnhanced = !$changeslist.find('ul.special').length;
if (mw.util.getParamValue('from') !== null) {
$('#mw-watchlist-form input[name="from"]').remove();
}
if (!mw.user.options.get('wlenhancedfilters-disable')) {
mw.hook('structuredChangeFilters.ui.initialized').add(main);
} else {
if (!navigator.userAgent.toLowerCase().includes('firefox')) {
main();
} else {
// Cure for Firefox
setTimeout(main, 0);
}
}
});
}
})();