Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
/*
task: replace lists with tables in watchlist/contribs and some other logs
tested in firefox only
*/
$(function (){
	function re_cat(arr){
		return new RegExp(arr.map(
			function(r){
				return r.source
			}
		).join(''));
	}

	function get_list_patterns(){
		const patterns = {
			'classes': {
				'plainlinks': {
					name: "abuselog",
					show_sections: false,
					re: re_cat([
						/^([0-9T:-]+):\s*/,                  // date
						/(<a .*?<\/a>)\s*/,                  // user
						/(<span .*?<\/span>) triggered /,    // user
						/(<a .*?<\/a>), /,                   // rule
						/performing the action "([^"]+)" /,  // action
						/on (<a .*?<\/a>)\.\s*/,             // page
						/Actions taken: ([^;]+);\s*/,        // action
						/Filter description: (.*)\s/,        // description
						/\((<a .*?<\/a>)\)\s*$/              // tools
					]),
					heading: ['date', 'user', 'user', 'rule', 'did', 'page', 'action', 'description', 'tools'],
					format: function(cells, last_row){
						cells[3] = cells[3].replace(/>talk</, '>t<').replace(/>block</, '>b<').replace(/>contribs</, '>c<').replace(/>\(\s*/, '>').replace(/>\s*\)\s*</, '><');
						cells[4] = cells[4].replace(/>filter /, '>');
						[2, 6, 8].forEach(i => {
							if(last_row[i] === cells[i]){
								cells[i] = '-"-'
							}else{
								last_row[i] = cells[i];
							}
						});
						cells[9] = cells[9].replace(/>details</, '>d<').replace(/>examine</, '>e<');
					}
				},

				'mw-contributions-list': {
					name: "contribs",
					show_sections: false,
					re: re_cat([
						/^(<span .*?<\/span>)\s*/,    // 1 vis
						/(<a .*?<\/a>)\s*/,           // 2 date
						/(<span .*?<\/span>)\s*<span class="mw-changeslist-separator"><\/span>\s*/, // 3 diff/hist
						/(<strong .*?<\/strong>|<span .*?<\/span>)\s*‎?\s*<span class="mw-changeslist-separator"><\/span>\s*/, // 4 bytes diff
						/(<abbr .*?<\/abbr>|)\s*/,    // 5 flags
						/(<a .*?<\/a>)\s*‎\s*/,       // 6 page title
						/(<span .*?<\/span>)/,        // 7 summary
						/(\s*<span class="mw-uctop">[^<]*<\/span>|)/, // 8 current or not
						/(\s*(?:<span class="mw-changeslist-links mw-pager-tools"><span>|)<span class="mw-rollback-link">.*?<\/span>|)/, // 9 rollback
						/(\s*<span class="mw-tag.*?<\/span>|)\s*$/ // 10 tags
					]),
					heading: ['vis', 'date', 'diff<br />hist&nbsp;', 'bytes', 'flag', 'page', 'summary', 'c', 'rb', 'tags'],
					format: function(cells, last_row){
						cells[1] = cells[1].replace(/>change visibility</, '>chg<');
						cells[3] = cells[3].replace(/>diff</, '>d<').replace(/>hist</, '>h<');
						cells[6] = cells[6].replace(/>Benutzer(?:in|):/, '>user:').replace(/>Benutzer(?:in|) Diskussion:/, '>user talk:').replace(/>Wikipedia:/, '>WP:');
						cells[8] = cells[8].replace(/>current/, '>c');
						cells[9] = cells[9].replace(/>rollback /, '>').replace(/ edits?</, '<').replace(/more than /, '&gt;');
						cells[10] = cells[10].replace(/<a [^>]+>Tags<\/a>\s*:\s/, '').replace(/Mobile web edit/, 'mob.').replace(/Mobile edit/, 'mob. web');
						cells[1] = cells[1].replace(/>\(\s*/, '>').replace(/>\s*\)\s*</, '><');
						const css_classes = ['.comment--without-parentheses', '.mw-changeslist-links', '.mw-diff-bytes', '.mw-uctop', '.mw-rollback-link', '.mw-tag-markers'];
						css_classes.forEach(c => {
							document.styleSheets[0].addRule(c + '::before','content: "";')
							document.styleSheets[0].addRule(c + '::after','content: "";')
						});
					}
				},

				'special': {
					name: "watchlist",
					show_sections: true,
					re: re_cat([
						/(<a .*?<\/a>|\bdiff\b).*?/,  // diff
						/(<a .*?<\/a>).*?/,           // hist
						/(<a .*?<\/a>).*?/,           // page
						/(<span class="mw-changeslist-date[^"]*">[0-9:]+<\/span>).*?/, // timestamp
						/(<strong .*?<\/strong>|<span dir="ltr" class="mw-plusminus-[a-z]+ mw-diff-bytes" .*?<\/span>).*?/, // bytes diff
						/(<a .*?<\/a>)\s*/,           // user
						/(<span class="mw-usertoollinks mw-changeslist-links">.*<\/span>)\s*/, // user tools
						/(‎\s*<span .*<\/span>|\Z)/   // summary, tags
					]),
					heading: ['diff', 'hist', 'page', 'time', 'bytes', 'user', 'u.&nbsp;links', 'summary', 'tags'],
					format: function(cells, last_row){
						cells[7] = cells[7].replace(/>talk</, '>t<').replace(/>contribs</, '>c<').replace(/>block</, '>b<');
						cells[8] = cells[8].replace(/^‎\s*/, '').replace(/<span class="mw-rollback-link">.*/, '');
						const tags = /(<span class="mw-tag-markers">.*)/.exec(cells[8]);
						if(tags){
							cells[9] = tags[1];
							cells[8] = cells[8].replace(/<span class="mw-tag-markers">.*/, '');
						}else{
							cells[9] = '';
						}
						cells[9] = cells[9].replace(/<a .*?>Tags?<\/a>:\s*/, '');
						const css_classes = ['.comment--without-parentheses', '.mw-changeslist-links', '.mw-diff-bytes', '.mw-uctop']; // '.mw-tag-markers'
						css_classes.forEach(c => {
							document.styleSheets[0].addRule(c + '::before','content: "";')
							document.styleSheets[0].addRule(c + '::after','content: "";')
						});
					}
				}

			},
			'ids': {
				'pagehistory': {
					name: "history",
					show_sections: false,
					re: new RegExp([
						/(<a .*?<\/a>|\b(?:cur|Aktuell)\b).*?/,                                      // 1 cur
						/(<a .*?<\/a>|\b(?:prev|Vorherige)\b).*?/,                                   //   prev
						/(<input .*?>).*?/,                                                          // 2 radio button from
						/(<input .*?>).*?/,                                                          //   radio button to
						/(<input .*?>.*?|)/,                                                         //   checkbox select
						/(<span class="[^"]+">\s*|)/,                                                //   date-container
						/(<a href="[^"]+" class="[^"]*mw-changeslist-date[^"]*"[^>]*>(?:[0-9T:-]+|[0-9][0-9A-Za-z: ,.-]+[0-9]{4})<\/a>|<span class="history-deleted[^>]*>(?:[0-9T:-]+|[0-9][0-9A-Za-z: ,.-]+[0-9]{4})<\/span>).*?/,  // 3 date
						/<span class="history-user">\s*(<a .*?<\/a>|<span [^>]+>\([^)]+\)<\/span>)\s*/, // 4 user
						/(<span class="mw-usertoollinks mw-changeslist-links">.*?<\/span>|)\s*<\/span>\s*‎\s*/, // 5 user tools
						/(<abbr [^>]*>m<\/abbr>|)\s*/,                                               // 6 minor change?
						/<span class="mw-changeslist-separator"><\/span>\s*/,
						/<span class="history-size mw-diff-bytes" data-mw-bytes="([0-9]+)">(?:[0-9.,]+\s+[bB]ytes?|empty|leer)<\/span>.*?/,      // 7 size
						/(<strong .*?<\/strong>|<span (?:dir="ltr" |)class="mw-plusminus-[a-z]+ mw-diff-bytes" .*?<\/span>).*?/,  // 8 diff size
						/(<span class="comment\b[^"]*">(?:.|\s)*?<\/span>)\s*/,                      // 9 comment
						/(<span class="mw-changeslist-links[^"]*">.*<\/span>|<span\b.*<\/span>|)$/,  // 10 edit tools, tags, checked revisions
					].map(function(r) {return r.source}).join('')),
					heading: ['cur/prev', 'sel', 'time', 'user', 'user tools', 'm', 'size', 'diff', 'comment', 'edit tools', 'tags', 'chk'],
					format: function(cells, last_row){
						cells[1] = '<nobr>' + cells[1] + '/' + cells[2] + '</nobr>';
						// re-activate "until" radio-buttons
						cells[4] = cells[4].replace(/ disabled=""/, '');
						cells[2] = '<nobr>' + cells[3] + cells[4] + cells[5] + '</nobr>';
						cells.splice(3, 3);
						if(cells[3].length > 0){
							cells[4] = cells[3] + cells[4] + "</span>";
						}
						cells.splice(3, 1);
						cells[5] = cells[5].replace(/>talk</, '>t<').replace(/>contribs</, '>c<').replace(/>block</, '>b<');
						cells[10] = cells[10].replace(/<span class="mw-rollback-link">.*?<\/span>/, '').replace(/>updated since your last visit</, '>updated<').replace(/>undo</, '>👎<').replace(/>thank</, '>👍<');
						const checked_rev = /(<span class="fr-[a-z-]+ plainlinks">.*)/.exec(cells[10]);
						if(checked_rev){
							cells[12] = checked_rev[1];
							cells[10] = cells[10].substr(0, cells[10].length - cells[12].length);
							cells[12] = cells[12].replace(/\[automatically checked\]/, 'auto').replace(/\[checked (by .*)\]/, '$1');
						}else{
							cells[12] = '';
						}
						const tags = /(<span class="mw-tag-markers">.*)/.exec(cells[10]);
						if(tags){
							cells[11] = tags[1];
							cells[10] = cells[10].substr(0, cells[10].length - cells[11].length);
						}else{
							cells[11] = '';
						}
						cells[11] = cells[11].replace(/<a .*?>Tags?<\/a>:\s*/, '').replace(/Mobile web edit/, 'mob.').replace(/Mobile edit/, 'mob. web');
						const css_classes = ['.comment--without-parentheses', '.mw-changeslist-links', '.mw-diff-bytes', '.mw-uctop', '.mw-tag-markers', '.mw-changeslist-links > span:not(:first-child)'];
						css_classes.forEach(c => {
							document.styleSheets[0].addRule(c + '::before','content: "";')
							document.styleSheets[0].addRule(c + '::after','content: "";')
						});
					}
				}

			}
		};
		return patterns;
	}

	function list_elem2row(elem, pattern, prev_row){
		let converted = false;
		let row = '';
		if(elem.tagName === 'LI'){
			const cells = pattern.re.exec(elem.innerHTML.replace(/\n/g, " "));
			let flaggedrevs_class = "";
			elem.classList.forEach(c => {
				if(c.startsWith("flaggedrevs")){
					flaggedrevs_class = c;
				}
			});
			if(flaggedrevs_class === '' && elem.children[0].className.startsWith("flaggedrevs")){
				flaggedrevs_class = elem.children[0].className;
			}
			row += "<tr" + (flaggedrevs_class == '' ? '': ' class="' + flaggedrevs_class + '"') + ">";
			if(cells){
				pattern.format(cells, prev_row);
				for(let i = 1; i < cells.length; ++i){
					row += "<td>" + cells[i] + "</td>";
				}
				converted = true;
			}else{
				row += '<td colspan="' + pattern.heading.length + '">' + elem.innerHTML + "</td>";
			}
			row += "</tr>";
		}
		return {row: row, converted: converted};
	}

	function list2table(list, pattern){
		if(list && list.children.length > 0){
			table = '<table class="wikitable"><tr>';
			pattern.heading.forEach(h => {
				table += "<th>" + h + "</th>";
			});
			let found_something = 0;
			table += "</tr>";
			const prev_row = Array(list.children.length);
			Array.from(list.children).forEach(elem => {
				const li_elems = (elem.tagName === 'UL' ? Array.from(elem.children) : [elem]) ;
				li_elems.forEach(li => {
					const row = list_elem2row(li, pattern, prev_row);
					if(row.converted){
						++found_something;
						table += row.row;
					}
				});
			});
			table += "</table>";
			if(found_something > 0){
				const mySpan = document.createElement("span");
				mySpan.innerHTML = table;
				list.parentNode.replaceChild(mySpan, list);
			}
		}
	}

	const patterns = get_list_patterns();
	const classes_of_lists = Object.keys(patterns.classes);
	classes_of_lists.forEach(class_name => {
		const lists = document.getElementsByClassName(class_name);
		if(lists && lists.length > 0){
			if(patterns.classes[class_name].show_sections){
				Array.from(lists).forEach(list => {
					list2table(list, patterns.classes[class_name]);
				});
			}else{
				list2table(lists.item(0).parentNode, patterns.classes[class_name]);
			}
		}
	});
	const ids_of_lists = Object.keys(patterns.ids);
	ids_of_lists.forEach(id => {
		const list = document.getElementById(id);
		if(list){
			list2table(list, patterns.ids[id]);
		}
	});
});