After loading your script, I made some adjustments, added timing lines, and conducted some testing. The results showed that the time elapsed from completing the AJAX call until the table was fixed and fully functional ranged from 400 to 500 milliseconds. This speed should be sufficient for most users and scenarios.
However, if there are instances where every millisecond counts, you have the option to switch to using MutationObservers. While they are faster, they are also more delicate, less universal across browsers, and can be tricky to work with. In this particular scenario, implementing MutationObservers reduced the time from AJAX completion to the fixed table to a range of 20 to 40 milliseconds.
I would recommend utilizing a library like Mutation Summary to simplify the process and minimize any potential difficulties.
To transition from a basic waitForKeyElements() setup to Mutation Summary, follow these steps:
Include
@require https://raw.githubusercontent.com/rafaelw/mutation-summary/master/src/mutation-summary.js
in your metadata block.
Integrate your waitForKeyElements callback and simple selector into the following structure:
var muteObserver = new MutationSummary ( {
callback: handleDiscographyChanges,
rootNode: $( {ANY-JQUERY-SELECTOR} )[0],
queries: [ {element: {A-SIMPLE-SELECTOR}} ]
} );
function handleDiscographyChanges (muteSummaries) {
var mSummary = muteSummaries[0];
if (mSummary.added.length) {
{YOUR-CALLBACK} ( $(mSummary.added[0]) );
}
}
For example, in this case, you would change:
waitForKeyElements (".display.discog", appendColumn);
To:
var muteObserver = new MutationSummary ( {
callback: handleDiscographyChanges,
rootNode: $("#band_disco")[0],
queries: [ {element: ".discog"} ]
} );
function handleDiscographyChanges (muteSummaries) {
var mSummary = muteSummaries[0];
if (mSummary.added.length) {
appendColumn ( $(mSummary.added[0]) );
}
}
Make sure to determine the rootNode
by analyzing the structure of the page.
Below is a full script featuring 3 optional methods and timing logs. This script was tested on Firefox only, but it should be compatible with Tampermonkey as well.
Review the //OPTION n
lines preceding each section to comment out specific parts if needed.
// ==UserScript==
// @name Metal Archives (discography pages) - Reviews column split and sortable tables
// @include http://www.metal-archives.com/bands/*
// @include http://www.metal-archives.com/band/*
// @grant none
// @require http://code.jquery.com/ui/1.9.1/jquery-ui.min.js
// @require https://greasyfork.org/scripts/2199-waitforkeyelements/code/waitForKeyElements.js?version=6349
// @require https://greasyfork.org/scripts/5844-tablesorter/code/TableSorter.js?version=21758
// @require https://raw.githubusercontent.com/rafaelw/mutation-summary/master/src/mutation-summary.js
// ==/UserScript==
function appendColumn(jNode) {
logTime ("Table fixed");
// STEP 1+2: SPLIT THE 'REVIEWS' COLUMN INTO A 'REVIEWS' COLUMN AND A 'RATINGS' COLUMN
var tbl = jNode[0]; // reference to the table
// To avoid further execution, stop if the current sub-table is empty
if (tbl.rows[1].cells[0].innerHTML == '<em>Nothing entered yet. Please add the releases, if applicable. </em>') {
return;
}
var newCell, newText;
const cols = tbl.rows[0].cells.length - 1;
var tr = tbl.tHead.children[0],
th = document.createElement('th');
th.innerHTML = "Ratings";
th.className = "ratingsCol";
tr.appendChild(th);
for (i = 1; i < tbl.rows.length; i++) {
k = tbl.rows[i].cells[cols].innerHTML; // Get the content of the current cell in the Review column and store it in 'k'
re1 = /<a [^>]*>[^(]*[(]([^)]+)/ ; // RegEx to match the 'Ratings' percentage (including the % symbol)
l = re1.exec(k); // Execute the RegEx and store it in 'l'
newCell = tbl.rows[i].insertCell(-1); // Add a new cell for the 'Ratings' column in each row
if (re1.test(k) != 0){ // Create new cells only if there are matches in the RegEx
re0 = /(<a [^>]*>)[0-9]*[^(]/ ; // RegEx to match the reviews URL
url = re0.exec(k); // Execute the RegEx and store it in 'url'
newCell.innerHTML = url[1] + l[1] + '</url>'; // Add the Ratings percentage as a link to Reviews
re2 = /<a [^>]*>([0-9]*)[^(]/ ; // RegEx to match the 'Reviews' number
m = re2.exec(k); // Execute the RegEx and store it in 'm'
newCell = tbl.rows[i].cells[cols];
newCell.innerHTML = url[1] + m[1] + '</url>'; // Add the Reviews number as a link to Reviews
}
}
// STEP 3: MAKE THE DISCOGRAPHY TABLE SORTABLE (using the jQuery plugin "tablesorter")
$(tbl).tablesorter ( {
cssAsc: 'up',
cssDesc: 'down',
headers: {
0: {sorter: false}
}
} );
}
//OPTION 1
//waitForKeyElements (".display.discog", appendColumn);
$(document).ajaxComplete (function (e, xhr, config){
logTime ("Ajax complete");
//OPTION 2
return; //-- For compare test
if (config.url.indexOf ('/tab/') != -1){
$(".display.discog").each ( function () {
appendColumn ( $(this) );
} );
}
} );
$("#band_disco > ul > li").on ("click", "a.ui-tabs-anchor", function (zEvent) {
logTime (zEvent.target.textContent + " tab was clicked.");
} );
function logTime (lableTxt) {
var tNow = new Date ();
console.log (tNow.toLocaleFormat ('%H:%M:%S') + "." + tNow.getMilliseconds (), " <== " + lableTxt);
}
//OPTION 3
//*--- Remove leading slash, from this line, to comment out block, below.
var muteObserver = new MutationSummary ( {
callback: handleDiscographyChanges,
rootNode: $("#band_disco")[0],
queries: [ {element: ".discog"} ]
} );
//*/ -- Tail end of optional comment block
function handleDiscographyChanges (muteSummaries) {
var mSummary = muteSummaries[0];
if (mSummary.added.length) {
appendColumn ( $(mSummary.added[0]) );
}
}
Note that certain styling code and original comments have been excluded from this demonstration.