User:Proteins/quickdiffs.js

// // Summarizes the differences between two page versions in pop-up windows // Perhaps calculate fractional change in document? // // To use this script, add "importScript('User:Proteins/quickdiffs.js');" to your monobook.js subpage // under your user page, as you can see at User:Proteins/monobook.js

function quickDiffs { var alert_string = ""; var num_alert_strings = 0; var alert_string_index = 0; var alert_string_list = new Array;

var body_content;

var article_tables; var temp_article_table; var num_article_tables = 0; var article_table_index = 0;

var diff_table; var num_diff_tables = 0;

var diff_table_body; var diff_table_bodies; var num_diff_table_bodies = 0;

var temp_table_row; var diff_table_rows; var table_row_index= 0; var num_diff_table_rows = 0;

var table_row_data; var temp_table_datum; var table_datum_index = 0; var num_table_row_data = 0; var temp_table_datum_text = ""; var temp_table_datum_text_node;

var diff_old_version_info; //className = "diff-otitle" var diff_new_version_info; //className = "diff-ntitle"

var mw_diff_otitle1; var mw_diff_otitle1_child; var mw_diff_otitle1_grandchild; var mw_diff_otitle1_text = "";

var mw_diff_otitle2; var mw_diff_otitle2_child; var mw_diff_otitle2_grandchild; var mw_diff_otitle2_text = "";

var mw_diff_otitle3; var mw_diff_otitle3_child; var mw_diff_otitle3_grandchild; var mw_diff_otitle3_text = "";

var mw_diff_otitle4; var mw_diff_otitle4_child; var mw_diff_otitle4_grandchild; var mw_diff_otitle4_text = "";

var mw_diff_ntitle1; var mw_diff_ntitle1_child; var mw_diff_ntitle1_grandchild; var mw_diff_ntitle1_text = "";

var mw_diff_ntitle2; var mw_diff_ntitle2_child; var mw_diff_ntitle2_grandchild; var mw_diff_ntitle2_text = "";

var mw_diff_ntitle3; var mw_diff_ntitle3_child; var mw_diff_ntitle3_grandchild; var mw_diff_ntitle3_text = "";

var mw_diff_ntitle4; var mw_diff_ntitle4_child; var mw_diff_ntitle4_grandchild; var mw_diff_ntitle4_text = "";

var revisions = ""; var num_revisions = 0;

var num_line_numbers = 0; var current_old_line_number = 0; var current_new_line_number = 0; var old_line_numbers = new Array; var new_line_numbers = new Array;

var line_number_flag = 0; var num_diff_addedlines = 0; var num_diff_deletedlines = 0; var num_diff_context_lines = 0; var num_diff_undefined_lines = 0;

var num_changes = 0; var num_additions = 0; var num_deletions = 0; var num_replacements = 0;

var span_index = 0; var num_potential_spans = 0;

var temp_added_span; var added_span_nodes; var num_added_spans = 0; var added_span_text = ""; var temp_added_line = ""; var prev_added_line = ""; var temp_added_span_text = "";

var temp_deleted_span; var deleted_span_nodes; var num_deleted_spans = 0; var deleted_span_text = ""; var temp_deleted_line = ""; var prev_deleted_line = ""; var temp_deleted_span_text = "";

var num_changed_lines = 0; var diff_added_lines = new Array; var diff_deleted_lines = new Array; var num_changes_in_line = new Array;

var diff_changes = new Array; var diff_change_line_numbers = new Array;

// Check that there is exactly one table on this page with the className "diff" body_content = document.getElementById('bodyContent'); if (!body_content) { alert_string = "ERROR: This article has no bodyContent element."; window.alert(alert_string); return; }

article_tables = body_content.getElementsByTagName("TABLE"); if (!article_tables) { alert_string = "ERROR: This article has no TABLE elements."; window.alert(alert_string); return; }	num_article_tables = article_tables.length; if (!num_article_tables) { alert_string = "ERROR: This article has no TABLE elements."; window.alert(alert_string); return; }

num_diff_tables = 0; for (article_table_index=0; article_table_index<num_article_tables; article_table_index++) { temp_article_table = article_tables[article_table_index]; if (!temp_article_table) { continue; }

if (temp_article_table.className == "diff") { num_diff_tables++; diff_table = temp_article_table; }	} // closes loop searching for the diff table if (num_diff_tables == 0) { alert_string = "ERROR: This article has no TABLE elements belonging to the \"diff\" class."; window.alert(alert_string); return; } else if (num_diff_tables != 1) { alert_string = "ERROR: This article has " + num_diff_tables + " TABLE elements belonging to the \"diff\" class."; alert_string += "An article should have at most one \"diff\" table.\n"; window.alert(alert_string); return; }

// Check that there is exactly one table body diff_table_bodies = diff_table.getElementsByTagName("TBODY"); if (!diff_table_bodies) { alert_string = "ERROR: This article has no TBODY element within its \"diff\" table."; window.alert(alert_string); return; }	num_diff_table_bodies = diff_table_bodies.length; if (!num_diff_table_bodies) { alert_string = "ERROR: This article has no TBODY element within its \"diff\" table."; window.alert(alert_string); return; } else if (num_diff_table_bodies != 1) { alert_string = "ERROR: This article has " + num_diff_table_bodies + " TBODY elements within its \"diff\" table."; alert_string += "A \"diff\" table should have at most one TBODY element.\n"; window.alert(alert_string); return; }	diff_table_body = diff_table_bodies[0]; if (!diff_table_body) { alert_string = "ERROR: This article has a null TBODY element within its \"diff\" table."; window.alert(alert_string); return; }

// Loop over the table rows in the table body diff_table_rows = diff_table_body.getElementsByTagName("TR"); if (!diff_table_rows) { alert_string = "ERROR: This article has no TR elements within its \"diff\" table body."; window.alert(alert_string); return; }	num_diff_table_rows = diff_table_rows.length; if (!num_diff_table_rows) { alert_string = "ERROR: This article has no TR elements within its \"diff\" table body."; window.alert(alert_string); return; } else if (num_diff_table_rows == 1) { alert_string = "This article has only one row (TR element) within its \"diff\" table body."; alert_string += "This shouldn't happen under ordinary circumstances; however, it suggests that the two versions are identical\n"; window.alert(alert_string); return; }

// Get header texts for older version mw_diff_otitle1_text = ""; mw_diff_otitle1 = document.getElementById('mw-diff-otitle1'); if (!mw_diff_otitle1) { window.alert("ERROR: This article has no element with id \"mw-diff-otitle1\".\n\n"); } else { mw_diff_otitle1_child = mw_diff_otitle1.firstChild; if (!mw_diff_otitle1_child) { window.alert("ERROR: The \"mw-diff-otitle1\" element has no child node.\n\n"); } else { mw_diff_otitle1_grandchild = mw_diff_otitle1_child.firstChild; if (!mw_diff_otitle1_grandchild) { window.alert("ERROR: The \"mw-diff-otitle1\" element has no grandchild node.\n\n"); } else { mw_diff_otitle1_text = mw_diff_otitle1_grandchild.innerHTML; } // closes check for grandchild node } // closes check for child node } // closes check for mw_diff_otitle1 node //	window.alert("The mw_diff_otitle1_text is " + mw_diff_otitle1_text + "\n");

mw_diff_otitle2_text = ""; mw_diff_otitle2 = document.getElementById('mw-diff-otitle2'); if (!mw_diff_otitle2) { window.alert("ERROR: This article has no element with id \"mw-diff-otitle2\".\n\n"); } else { mw_diff_otitle2_child = mw_diff_otitle2.firstChild; if (!mw_diff_otitle2_child) { window.alert("ERROR: The \"mw-diff-otitle2\" element has no child node.\n\n"); } else { mw_diff_otitle2_text = mw_diff_otitle2_child.innerHTML; } // closes check for child node } // closes check for mw_diff_otitle2 node //	window.alert("The mw_diff_otitle2_text is " + mw_diff_otitle2_text + "\n");

mw_diff_otitle3_text = ""; mw_diff_otitle3 = document.getElementById('mw-diff-otitle3'); if (!mw_diff_otitle3) { window.alert("ERROR: This article has no element with id \"mw-diff-otitle3\".\n\n"); } else { mw_diff_otitle3_text = mw_diff_otitle3.innerHTML; mw_diff_otitle3_text = mw_diff_otitle3_text.replace(/&gt;/ig, ">"); mw_diff_otitle3_text = mw_diff_otitle3_text.replace(/&lt;/ig, "<"); mw_diff_otitle3_text = mw_diff_otitle3_text.replace(/(<([^>]+)>)/ig,""); } // closes check for mw_diff_otitle3 node //	window.alert("The mw_diff_otitle3_text is " + mw_diff_otitle3_text + "\n");

// Possibly add code for mw_diff_otitle4 here, but seems unneeded

// Get header texts for newer version mw_diff_ntitle1_text = ""; mw_diff_ntitle1 = document.getElementById('mw-diff-ntitle1'); if (!mw_diff_ntitle1) { window.alert("ERROR: This article has no element with id \"mw-diff-ntitle1\".\n\n"); } else { mw_diff_ntitle1_child = mw_diff_ntitle1.firstChild; if (!mw_diff_ntitle1_child) { window.alert("ERROR: The \"mw-diff-ntitle1\" element has no child node.\n\n"); } else { mw_diff_ntitle1_grandchild = mw_diff_ntitle1_child.firstChild; if (!mw_diff_ntitle1_grandchild) { window.alert("ERROR: The \"mw-diff-ntitle1\" element has no grandchild node.\n\n"); } else { mw_diff_ntitle1_text = mw_diff_ntitle1_grandchild.innerHTML; } // closes check for grandchild node } // closes check for child node } // closes check for mw_diff_ntitle1 node //	window.alert("The mw_diff_ntitle1_text is " + mw_diff_ntitle1_text + "\n");

mw_diff_ntitle2_text = ""; mw_diff_ntitle2 = document.getElementById('mw-diff-ntitle2'); if (!mw_diff_ntitle2) { window.alert("ERROR: This article has no element with id \"mw-diff-ntitle2\".\n\n"); } else { mw_diff_ntitle2_child = mw_diff_ntitle2.firstChild; if (!mw_diff_ntitle2_child) { window.alert("ERROR: The \"mw-diff-ntitle2\" element has no child node.\n\n"); } else { mw_diff_ntitle2_text = mw_diff_ntitle2_child.innerHTML; } // closes check for child node } // closes check for mw_diff_ntitle2 node //	window.alert("The mw_diff_ntitle2_text is " + mw_diff_ntitle2_text + "\n");

mw_diff_ntitle3_text = ""; mw_diff_ntitle3 = document.getElementById('mw-diff-ntitle3'); if (!mw_diff_ntitle3) { window.alert("ERROR: This article has no element with id \"mw-diff-ntitle3\".\n\n"); } else { mw_diff_ntitle3_text = mw_diff_ntitle3.innerHTML; mw_diff_ntitle3_text = mw_diff_ntitle3_text.replace(/&gt;/ig, ">"); mw_diff_ntitle3_text = mw_diff_ntitle3_text.replace(/&lt;/ig, "<"); mw_diff_ntitle3_text = mw_diff_ntitle3_text.replace(/(<([^>]+)>)/ig,""); } // closes check for mw_diff_ntitle3 node //	window.alert("The mw_diff_ntitle3_text is " + mw_diff_ntitle3_text + "\n");

// Possibly add code for mw_diff_ntitle4 here, but seems unneeded

// Loop over the rows in the difference table num_alert_strings = 0; alert_string_list[0] = "NONE";

num_revisions = 1; revisions = "The newer version is separated from the older version by one revision.";

for (table_row_index=0; table_row_index<num_diff_table_rows; table_row_index++) { temp_table_row = diff_table_rows[table_row_index]; if (!temp_table_row) { continue; }

table_row_data = temp_table_row.getElementsByTagName("TD"); if (!table_row_data) { continue; } num_table_row_data = table_row_data.length; if (!num_table_row_data) { continue; }

temp_added_line = ""; temp_deleted_line = "";

line_number_flag = 0; num_diff_addlines = 0; num_diff_deletedlines = 0; num_diff_context_lines = 0; num_diff_undefined_lines = 0;

for (table_datum_index=0; table_datum_index<num_table_row_data; table_datum_index++) { temp_table_datum = table_row_data[table_datum_index]; if (!temp_table_datum) { continue; }

if (temp_table_datum.className == "diff-lineno") { temp_table_datum_text_node = temp_table_datum.firstChild; if (!temp_table_datum_text_node) { continue; } if (temp_table_datum_text_node.nodeType != 3) { continue; } temp_table_datum_text = temp_table_datum_text_node.data; temp_table_datum_text = temp_table_datum_text.replace(/[^0-9]*/ig, ""); if (line_number_flag == 0) { current_old_line_number = temp_table_datum_text - 2; line_number_flag = 1; } else if (line_number_flag == 1) { current_new_line_number = temp_table_datum_text - 2; line_number_flag = 2; } else if (line_number_flag == 2) { // ignore this table_datum as anomalous // there should be only two line numbers in any table row } else { alert_string = "ERROR: Line_number_flag = " + line_number_flag + " in datum " + table_datum_index + " of diff table row " + table_row_index + ".\n"; window.alert(alert_string); return; }			} else if (temp_table_datum.className == "diff-multi") { temp_table_datum_text_node = temp_table_datum.firstChild; if (!temp_table_datum_text_node) { continue; } if (temp_table_datum_text_node.nodeType == 3) { num_revisions = 0; // to flag for errors temp_table_datum_text = temp_table_datum_text_node.data; if (temp_table_datum_text.match(/^\(One/)) { 						num_revisions = 2;					} else {						temp_table_datum_text = temp_table_datum_text.replace(/[^0-9]*/ig, "");						if (temp_table_datum_text) {							num_revisions = temp_table_datum_text;							num_revisions++;						}					}					if (num_revisions == 1) { // should never happen, but...						revisions = "The newer version is separated from the older version by one revision.";					} else {						revisions = "The newer version is separated from the older version by " + num_revisions + " revisions.";					}				} // closes check that the first child node is a text node			} else if (temp_table_datum.className == "diff-context") { 				num_diff_context_lines++;

} else if (temp_table_datum.className == "diff-addedline") { num_diff_addedlines = 1; num_added_spans = 0; added_span_text = ""; temp_added_line = temp_table_datum.innerHTML; if (temp_added_line) { // replace HTML tags temp_added_line = temp_added_line.replace(/&gt;/ig, ">"); temp_added_line = temp_added_line.replace(/&lt;/ig, "<"); temp_added_line = temp_added_line.replace(/(<([^>]+)>)/ig,"");

// replace renamed wiki links temp_added_line = temp_added_line.replace(/\[\[([^\|\]]+?)\|([^\|]+?)\]\]/ig,"$2"); // replace renamed HTTP links, such as external links and diffs temp_added_line = temp_added_line.replace(/\[http:([^\s]+)\s(.*?)\]/, "$2");

temp_added_line = temp_added_line.replace(/&amp;/ig, "&"); temp_added_line = temp_added_line.replace(/ /ig, " "); temp_added_line = temp_added_line.replace(/&#160;/ig, " ");

temp_added_line = temp_added_line.replace(/\'\'\'/ig, ""); temp_added_line = temp_added_line.replace(/\'\'/ig, ""); temp_added_line = temp_added_line.replace(/\s+/ig, " "); } else { temp_added_line = ""; } if (temp_added_line.replace(/\s/ig, "").length < 1) { num_diff_addedlines = 0; continue; }

added_span_nodes = temp_table_datum.getElementsByTagName("SPAN"); if (!added_span_nodes) { num_added_spans = 0; continue; } num_potential_spans = added_span_nodes.length; for (span_index=0; span_index]+)>)/ig,""); if (!temp_added_span_text) { continue; }

num_added_spans++; added_span_text += "\t Addition " + num_added_spans + ": " + temp_added_span_text + "\n"; } // closes loop over the added spans added_span_text = "The " + num_added_spans + " additions were:\n" + added_span_text; } else if (temp_table_datum.className == "diff-deletedline") { num_diff_deletedlines = 1; num_deleted_spans = 0; deleted_span_text = ""; temp_deleted_line = temp_table_datum.innerHTML; if (temp_deleted_line) { // replace HTML tags temp_deleted_line = temp_deleted_line.replace(/&gt;/ig, ">"); temp_deleted_line = temp_deleted_line.replace(/&lt;/ig, "<"); temp_deleted_line = temp_deleted_line.replace(/(<([^>]+)>)/ig,"");

// replace renamed wiki links temp_deleted_line = temp_deleted_line.replace(/\[\[([^\|\]]+?)\|([^\|]+?)\]\]/ig,"$2"); // replace renamed HTTP links, such as external links and diffs temp_deleted_line = temp_deleted_line.replace(/\[http:([^\s]+)\s(.*?)\]/, "$2");

temp_deleted_line = temp_deleted_line.replace(/&amp;/ig, "&"); temp_deleted_line = temp_deleted_line.replace(/ /ig, " "); temp_deleted_line = temp_deleted_line.replace(/&#160;/ig, " ");

temp_deleted_line = temp_deleted_line.replace(/\'\'\'/ig, ""); temp_deleted_line = temp_deleted_line.replace(/\'\'/ig, ""); temp_deleted_line = temp_deleted_line.replace(/\s+/ig, " "); } else { temp_deleted_line = ""; } if (temp_deleted_line.replace(/\s/ig, "").length < 1) { num_diff_deletedlines = 0; continue; }

deleted_span_nodes = temp_table_datum.getElementsByTagName("SPAN"); if (!deleted_span_nodes) { num_deleted_spans = 0; continue; } num_potential_spans = deleted_span_nodes.length; for (span_index=0; span_index]+)>)/ig,""); if (!temp_deleted_span_text) { continue; }

num_deleted_spans++; deleted_span_text += "\t Deletion " + num_deleted_spans + ": " + temp_deleted_span_text + "\n"; } // closes loop over the deleted spans deleted_span_text = "The " + num_deleted_spans + " deletions were:\n" + deleted_span_text; } else if (temp_table_datum.className == "diff-marker") { // do nothing } else { num_diff_undefined_lines++; } // closes classification of the table datum } // closes loop over the data within a table row

if ((num_diff_addedlines > 0) && (temp_added_line) && (num_diff_deletedlines > 0) && (temp_deleted_line)) { current_new_line_number++; current_old_line_number++; num_replacements++; alert_string = "Text replacement " + num_replacements + " in line number " + current_new_line_number + " of the newer version (line number " + current_old_line_number + " of the older version)\n\n"; alert_string += "There were " + num_added_spans + " additions and " + num_deleted_spans + " deletions to arrive at the current version of this line:\n\n"; alert_string += temp_added_line + "\n\n";

if ((num_added_spans>15) && (alert_string)) { num_alert_strings++; alert_string_list[num_alert_strings-1] = alert_string; //				window.alert(alert_string); alert_string = ""; }			if (num_added_spans>0) { alert_string += added_span_text; }			if ((num_deleted_spans>15) && (alert_string)) { num_alert_strings++; alert_string_list[num_alert_strings-1] = alert_string; //				window.alert(alert_string); alert_string = ""; }			if (num_deleted_spans>0) { alert_string += deleted_span_text; }			if (alert_string) { num_alert_strings++; alert_string_list[num_alert_strings-1] = alert_string; //				window.alert(alert_string); }		} else if ((num_diff_addedlines > 0) && (temp_added_line)) { num_additions++; current_new_line_number++; alert_string = "Text addition " + num_additions + " in line number " + current_new_line_number + " of the newer version (line number " + current_old_line_number + " of the older version)\n\n"; alert_string += "The following line was added to the article:\n\n"; alert_string += temp_added_line; num_alert_strings++; alert_string_list[num_alert_strings-1] = alert_string; //			window.alert(alert_string); } else if ((num_diff_deletedlines > 0) && (temp_deleted_line)) { num_deletions++; current_old_line_number++; alert_string = "Text deletion " + num_deletions + " in line number " + current_new_line_number + " of the newer version (line number " + current_old_line_number + " of the older version)\n\n"; alert_string += "The following line was deleted from the article:\n\n"; alert_string += temp_deleted_line; num_alert_strings++; alert_string_list[num_alert_strings-1] = alert_string; //			window.alert(alert_string); } else if (num_diff_context_lines == 2) { current_new_line_number++; current_old_line_number++; } // closes classification change as addition, deletion or replacement } // closes loop over the table rows

// Report the results alert_string = ""; if (revisions) { alert_string += revisions + "\n\n"; }	num_changes = num_additions + num_deletions + num_replacements; if (num_changes == 0) { alert_string += "The two versions are identical."; window.alert(alert_string); } else { alert_string += "The newer version differs by ";

if (num_additions == 1) { alert_string += "one addition"; } else if (num_additions > 1) { alert_string += num_additions + " additions"; }		if (num_additions>0) { if (num_additions == num_changes) { alert_string += ".\n\n"; } else if ((num_deletions == 0) || (num_replacements == 0)) { alert_string += " and "; } else { alert_string += ", "; }		}		if (num_deletions == 1) { alert_string += "one deletion"; } else if (num_deletions > 1) { alert_string += num_deletions + " deletions"; }		if (num_deletions>0) { if (num_replacements > 0) { alert_string += " and "; } else { alert_string += ".\n\n"; }		}		if (num_replacements == 1) { alert_string += "one replacement.\n\n"; } else if (num_replacements > 1) { alert_string += num_replacements + " replacements.\n\n"; }

if (num_alert_strings == 1) { alert_string += "These changes will be described on the following alert window.\n"; } else if (num_alert_strings > 1) { alert_string += "These changes will be described on the following " + num_alert_strings + " alert windows.\n"; }

window.alert(alert_string); for (alert_string_index=0; alert_string_index<num_alert_strings; alert_string_index++) { alert_string = alert_string_list[alert_string_index]; window.alert(alert_string); }	} // closes check for zero changes } // closes function quickDiffs addOnloadHook(function { mw.util.addPortletLink('p-cactions', 'javascript:quickDiffs', 'qd', 'ca-quickdiff', 'Summarizes the differences between two page versions', 'b', ''); }); //