Benutzer:Lustiger seth/list2table.js
Erscheinungsbild
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
- Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
/*
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 ', '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 /, '>');
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. 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;
}
});
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]);
}
});
});