משתמש:קיפודנחש/88plus.js
הערה: לאחר הפרסום, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.
- פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload) או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
- גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
- אינטרנט אקספלורר / אדג': להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh) או ללחוץ על צירוף המקשים Ctrl-F5.
- אופרה: ללחוץ על Ctrl-F5.
mw.loader.using( ['mediawiki.api', 'mediawiki.util', 'mediawiki.user'] , function() {
const
storageTimestampKey = 'watchlistwatcher-newestseen',
storageSelectionKey = 'watchlistwatcher-userselection',
nbsp = ' ',
rlm = '‏';
var
api = new mw.Api(),
storage = window.localStorage,
items,
newest,
watchButton,
watchwButtonAnchor,
timer,
counts,
popup,
contentDiv,
selectedOptions = storage.getItem(storageSelectionKey),
titleCheckboxes,
selectAll,
refreshButton,
optionsLabels = {
watchlisthideanons: 'אנונימים',
watchlisthidebots: 'בוטים',
watchlisthideliu: 'רשומים', /* this strangely named option means "hide regitered users", IOW, show anons */
watchlisthideminor: 'משניות',
watchlisthidepatrolled: 'בדוקות',
watchlisthidecategorization: 'קטגוריות',
hidelog: 'פעולות יומן',
hideedit: 'עריכות',
},
lastOption = 'hideedit',
opts = {
/* watchlisthideown: we do not care about this one, since "unread" doesn't have own edits anyway */
watchlisthideanons: '!anon',
watchlisthidebots: '!bot',
watchlisthideliu: 'anon', /* this strangely named option means "hide regitered users", IOW, show anons */
watchlisthideminor: '!minor',
watchlisthidepatrolled: '!patrolled'
};
function titleLine(item) {
var titleLink = $('<a>').attr( { href: mw.util.getUrl(item.title), title: item.title }).text(item.title),
diffLink = $('<a>').attr( { href: mw.util.getUrl('special:diff/' + item.revid), title: 'הבדל' }) .text('הבדל'),
histLink = $('<a>').attr( { href: mw.util.getUrl(item.title, { action: 'history' }), title: 'היסטוריה' }).text('היסטוריה');
if (item.timestamp != item.notificationtimestamp) histLink = $('<strong>').append(histLink);
return $('<span>')
.append(titleLink)
.append(nbsp)
.append('(')
.append(diffLink)
.append('|')
.append(histLink)
.append(')');
}
function userLink(item) {
var user = item.user,
contribl = mw.util.getUrl('Special:Contributions/' + user),
pagel = mw.util.getUrl('User:' + user),
talkl = mw.util.getUrl('User talk:' + user),
pageLink = $('<a>', { href: pagel, title: user }).text(user),
contribLink = $('<a>', { href: contribl, title: 'תרומות' }).text('תרומות'),
talkLink = $('<a>', { href: talkl, title: 'שיחה' }).text('שיחה');
return $('<td>')
.css('max-width', '36em')
.append(pageLink)
.append(' (')
.append(talkLink)
.append('|')
.append(contribLink)
.append(')')
.append(nbsp)
.append($('<span>').html(rlm + (item.parsedcomment || '') + rlm))
;
}
function localize(date, short) {
var options = short
? { month: 'numeric', day: 'numeric', hour:'numeric', minute:'numeric' }
: { hour:'numeric', minute:'numeric', second: 'numeric', year: 'numeric', day: 'numeric', month: 'long' };
return date.toLocaleDateString('he', options);
}
function timeOrMany(item) {
var date = new Date(item.timestamp);
var timestamp = item.timestamp == item.notificationtimestamp
? localize(date) : 'מספר עריכות (' + localize(date, true) + ')';
return $('<td>').html(timestamp);
}
function makeCheckbox(item) {
var checkbox = new OO.ui.CheckboxInputWidget( { value: item.title } );
titleCheckboxes.push(checkbox);
return $('<td>').append(checkbox.$element);
}
function buildLine(item) {
var change = item.newlen - item.oldlen,
tooltip = change > 0
? 'נוספו ' + change
: 'הוסרו ' + (-change);
tooltip = 'בעריכה האחרונה ' + tooltip + ' בתים';
return $('<tr>')
.attr('title', tooltip)
.css( 'vertical-align', 'top' )
.append(makeCheckbox(item))
.append( timeOrMany(item) )
.append( titleLine(item) )
.append( userLink(item) ) ;
}
function buildContent() {
var div = $('<div>'),
already = false,
lastClicked = new Date(storage.getItem( storageTimestampKey ) || 0),
optionsDiv = $('<div>'),
table = $('<table>')
.css( { 'border-spacing': '1em 0' } );
selectAll = new OO.ui.CheckboxInputWidget( );
table.append(
$('<tr>')
.append($('<td>').append(selectAll.$element))
.append($('<td>').text('בחירת הכל'))
)
.append(counts ? $('<th>', { colspan: 3 }).text('חדשות') : '')
.append($('<tr>'))
.appendTo(div);
titleCheckboxes = [selectAll]; //reset every time
selectAll.on( 'change', function(selected) {
for (var i = 1; i < titleCheckboxes.length; i++) {
titleCheckboxes[i].setSelected(selected, true);
}
}) ;
if (! counts) return div.append($('<p>').css( { 'text-align': 'center', 'font-weight': 'bold' }).text('אין עריכות שטרם נצפו'));
storage.setItem( storageTimestampKey, new Date(items[0].timestamp ));
table;
for (var i in items) {
var item = items[i];
if (! already && new Date(item.timestamp) <= lastClicked) {
table.append($('<th>', { colspan: 3 }).text('קודמות'));
already = true;
}
table.append(buildLine(item));
}
return div;
}
function buildCheckboxWidget() {
var checkboxes = [];
function createChangeFunc(key) {
return function(value) {
selectedOptions[key] = value;
triggerRefresh();
};
}
for (var key in optionsLabels) {
checkboxes.push(
new OO.ui.FieldLayout(
new OO.ui.CheckboxInputWidget( {
value: key,
selected: selectedOptions[key]
} ).on( 'change', createChangeFunc(key) ),
{ label: optionsLabels[key], align: 'inline' }
)
);
}
var layout = new OO.ui.FieldLayout( new OO.ui.Widget( {
content: [
new OO.ui.HorizontalLayout( {
items: checkboxes
})
]
} ) );
return $('<div>')
.css( { 'margin-right': '1em' } )
.append($('<p>')
.css({ 'font-size': '150%', 'font-weight': 'bolder', margin: '1em' })
.text('הסתרת שינויים:')
)
.append(layout.$element);
}
function triggerRefresh() { setTimeout(showPopup, 0); }
function buttonsPanel() {
var
p = $('<p>');
refreshButton = new OO.ui.ButtonWidget( {
label: 'רענון'
})
.on( 'click', triggerRefresh );
refreshButton.$element.appendTo(p);
var markseenButton = new OO.ui.ButtonWidget( {
label: 'סימון הדפים המסומנים כאילו נצפו'
})
.on( 'click', markAsSeen ),
unwatchButton = new OO.ui.ButtonWidget( {
label: 'הסרת הדפים המסומנים מרשימת המעקב'
})
.on( 'click', unwatch );
return $('<p>')
.css({ 'text-align': 'center' })
.append(refreshButton.$element)
.append(markseenButton.$element)
.append(unwatchButton.$element);
}
function updateStorageAndRefresh() {
storage.setItem( storageTimestampKey, newest ); // remember the click: only items newer than latest click will trigger coloring the bubble.
triggerQuery( 0 ); // initiate click, so when it returns we can color the icon accordingly
}
function showPopup( e ) {
if (e) {
e.stopImmediatePropagation();
e.preventDefault();
}
storage.setItem( storageTimestampKey, newest ); // remember the click: only items newer than latest click will trigger coloring the bubble.
mw.loader.using( 'oojs-ui' ).done(function() {
queryAndUpdate().done(function() {
if (! popup) {
contentDiv = $('<div>')
.addClass('wlw-content');
popup = new OO.ui.PopupWidget( {
label: '',
head: true,
width: 1000,
autoClose: true,
$content: $('<div>')
.css( { overflow: 'auto' } )
.append(buttonsPanel())
.append(buildCheckboxWidget())
.append($('<p>'))
.append(contentDiv)
});
popup.$element
.appendTo(watchButton);
}
popup.setLabel( 'דפים ברשימת המעקב שטרם נצפו, מעודכן ל-' + localize( new Date() ) );
contentDiv
.empty()
.append(buildContent());
if ( e ) popup.toggle();
} ); // queryAndUpdate,done
} ); // using.done
}
function announce() {
const new_id = 'pt-notifications-watchlist';
if ( ! watchButton ) {
var url,
notif = $( '#pt-notifications-notice, #pt-notifications-alert' ).eq(-1);
if ( ! notif.length )
return;
watchButton = notif.clone()
.attr( { id: new_id } )
.insertAfter( notif );
watchwButtonAnchor = watchButton.find( 'a' )
.removeClass('oo-ui-icon-tray')
.click( showPopup )
.attr( { href: '', title: 'רשימת המעקב ' } );
}
var lastClicked = new Date(storage.getItem( storageTimestampKey ) || 0),
newChanges = newest > lastClicked;
if (refreshButton) {
refreshButton.setDisabled(! newChanges);
}
watchwButtonAnchor
.toggleClass( 'mw-echo-notifications-badge-unseen', newChanges )
.toggleClass( 'mw-echo-notifications-badge-all-read', counts === 0 )
.attr( { 'data-counter-text': counts || '', 'data-counter-num': counts } );
}
function calcParams() {
var
wlshow;
if (! selectedOptions || ! selectedOptions.hasOwnProperty(lastOption)) {
selectedOptions = {};
for (var key in optionsLabels) {
selectedOptions[key] = mw.user.options.get(key);
}
}
wlshow = Object.keys( opts )
.filter( function( opt) { return selectedOptions[opt]; } )
.map( function( k ) { return opts[k]; } )
.concat( 'unread' )
.join( '|' ),
wltype = ['new'];
if (! selectedOptions.watchlisthidecategorization) wltype.push('categorize');
if (! selectedOptions.hidelog) wltype.push('log');
if (! selectedOptions.hideedit) wltype.push('edit');
return {
list: 'watchlist',
wlprop: 'ids|user|title|timestamp|notificationtimestamp|parsedcomment|sizes',
wlshow: wlshow,
wltype: wltype.join('|'),
wllimit: window.script88limit || 50
};
}
function triggerQuery( timeout ) {
clearTimeout( timer );
if ( typeof(timeout) != 'number')
timeout = 1000;
timer = setTimeout( queryAndUpdate, timeout );
}
function markAsSeen() {
var titles = titleCheckboxes && titleCheckboxes
.filter(cb => cb.selected)
.map(cb => cb.value);
if (titles && titles.length) {
var promisses = titles.map(title => api.post( {
action: 'setnotificationtimestamp',
titles: title,
newerthanrevid: 0,
token: mw.user.tokens.get('csrfToken')
} ) );
Promise.all(promisses).then(function() {
setTimeout(triggerRefresh, 1500);
});
}
}
function unwatch() {
var titles = titleCheckboxes && titleCheckboxes
.filter(cb => cb.selected)
.map(cb => cb.value);
if (titles && titles.length) {
api.post( {
action: 'watch',
unwatch: true,
titles: titles.join("|"),
token: mw.user.tokens.get('watchToken')
} )
.done(triggerRefresh);
}
}
function queryAndUpdate() {
return api.get( calcParams() )
.done( function(data) {
counts = {};
if ( data && data.query && data.query.watchlist ) {
items = data.query.watchlist;
counts = items.length;
newest = counts ? new Date(items[0].timestamp) : null;
announce();
triggerQuery( 60000 );
}
} ); // promise?
} // queryandupdate
//load css page. would do it locally, but javascript does not support multiline strings, and putting all the CSS locally is just too much.
mw.loader.load( '//he.wikipedia.org/w/index.php?title=מדיה_ויקי:סקריפטים/88.css&action=raw&ctype=text/css', 'text/css' );
queryAndUpdate();
$('#mw-watchlist-resetbutton').submit( triggerQuery );
$( 'body ').on( 'script-88-refresh', triggerQuery );
mw.hook('wikipage.content').add( triggerQuery );
$('.oo-ui-buttonElement-button').click( triggerQuery );
$( 'body ').on( 'script-88-pretend-clicked', updateStorageAndRefresh );
} );