MediaWiki:Compare.js
From Psalms: Layer by Layer
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
function fetchRenderedHTML(title, callback) { var url = mw.util.wikiScript() + '?title=' + encodeURIComponent(title) + '&action=render'; fetch(url) .then(function (response) { if (!response.ok) { throw new Error("Network response was not ok"); } return response.text(); }) .then(function (html) { console.log("Fetched HTML snippet:", html.slice(0, 500)); // limit log size var doc = document.implementation.createHTMLDocument("Comparison"); doc.body.innerHTML = html; callback(doc); }) .catch(function (err) { console.error("Error fetching page: " + title, err); document.getElementById("compare-output").textContent = "❌ Error fetching page: " + title + "\n" + err; }); } function runTableComparison() { var pageA = document.getElementById("input_1").value.trim(); var selectorA = document.getElementById("input_2").value.trim(); var pageB = document.getElementById("input_3").value.trim(); var selectorB = document.getElementById("input_4").value.trim(); var output = document.getElementById("compare-output"); output.innerHTML = "Running comparison…"; console.log("Page A:", pageA, "Selector A:", selectorA); console.log("Page B:", pageB, "Selector B:", selectorB); fetchRenderedHTML(pageA, function(domA) { var tableA = domA.querySelector(selectorA); if (!tableA) { output.innerHTML = "❌ Table A not found using selector: " + escapeHTML(selectorA); return; } fetchRenderedHTML(pageB, function(domB) { var tableB = domB.querySelector(selectorB); if (!tableB) { output.innerHTML = "❌ Table B not found using selector: " + escapeHTML(selectorB); return; } compareTables(tableA, tableB, output); }); }); } function fetchRenderedHTML(title, callback) { var apiUrl = mw.util.wikiScript("api"); var params = { action: "parse", page: title, format: "json", prop: "text" }; new mw.Api().get(params).done(function(data) { if (data && data.parse && data.parse.text) { var html = data.parse.text["*"]; var dom = document.createElement("div"); dom.innerHTML = html; callback(dom); } else { alert("Error fetching page: " + title); } }).fail(function(err) { alert("API error fetching: " + title); console.error(err); }); } function compareTables(tableA, tableB, output) { var rowsA = tableA.querySelectorAll("tr"); var rowsB = tableB.querySelectorAll("tr"); var maxRows = Math.max(rowsA.length, rowsB.length); var diffs = []; for (var i = 0; i < maxRows; i++) { var rowA = rowsA[i]; var rowB = rowsB[i]; if (!rowA || !rowB) { diffs.push("Row " + i + " missing in " + (!rowA ? "A" : "B")); continue; } var cellsA = rowA.querySelectorAll("td, th"); var cellsB = rowB.querySelectorAll("td, th"); var maxCells = Math.max(cellsA.length, cellsB.length); for (var j = 0; j < maxCells; j++) { var cellA = cellsA[j]; var cellB = cellsB[j]; if (!cellA || !cellB) { diffs.push("Row " + i + " Cell " + j + " missing in " + (!cellA ? "A" : "B")); continue; } var styleA = window.getComputedStyle(cellA); var styleB = window.getComputedStyle(cellB); ["backgroundColor", "color", "fontWeight", "textAlign"].forEach(function(prop) { if (styleA[prop] !== styleB[prop]) { var visualA = styleA[prop]; var visualB = styleB[prop]; if (prop === "backgroundColor" || prop === "color") { visualA += ' ' + createColorSwatch(styleA[prop]); visualB += ' ' + createColorSwatch(styleB[prop]); } diffs.push( "Row " + i + " Cell " + j + " style '" + prop + "' mismatch:<br>" + "<strong>Text A:</strong> " + escapeHTML(cellA.textContent.trim()) + "<br>" + "<strong>Style A:</strong> " + visualA + "<br>" + "<strong>Text B:</strong> " + escapeHTML(cellB.textContent.trim()) + "<br>" + "<strong>Style B:</strong> " + visualB ); } }); } } output.innerHTML = diffs.length ? "⚠️ Differences found:<br><br>" + diffs.join("<br><br>") : "✅ Tables match."; } function createColorSwatch(color) { return '<span style="display:inline-block;width:12px;height:12px;border:1px solid #ccc;margin-left:4px;vertical-align:middle;background:' + color + ';"></span>'; } function escapeHTML(str) { return str.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); }