User:Proteins/chemicalreactions.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//<pre>
// Analyze the chemical reactions on a page
//
// To use this script, add "importScript('User:Proteins/chemicalreactions.js');" to your monobook.js subpage 
// under your user page, as you can see at User:Proteins/monobook.js

var isotope_names = { 
"n" : "neutron", 
"H" : "hydrogen", 
"D" : "deuterium", 
"T" : "tritium", 
"He" : "helium", 
"Li" : "lithium", 
"Be" : "beryllium", 
"B" : "boron", 
"C" : "carbon",
"C13" : "carbon-13",  
"N" : "nitrogen", 
"N15" : "nitrogen-15", 
"O" : "oxygen", 
"F" : "fluorine", 
"Ne" : "neon"
};

var isotope_abbreviations = { 
"neutron" : "n", 
"hydrogen" : "H", 
"deuterium" : "D", 
"tritium" : "T", 
"helium" : "He", 
"lithium" : "Li", 
"beryllium" : "Be", 
"boron" : "B", 
"carbon" : "C",
"carbon-13" : "C13",  
"nitrogen" : "N", 
"nitrogen-15" : "N15", 
"oxygen" : "O", 
"fluorine" : "F", 
"neon" : "Ne"
};

var isotope_atomic_numbers = { 
"n" : "0", 
"H" : "1", 
"D" : "1", 
"T" : "1", 
"He" : "2", 
"Li" : "3", 
"Be" : "4", 
"B" : "5", 
"C" : "6",
"C13" : "6",  
"N" : "7", 
"N15" : "7", 
"O" : "8", 
"F" : "9", 
"Ne" : "10"
};

var isotope_weights = { 
"n" : "1.0", 
"H" : "1.0", 
"D" : "2.0", 
"T" : "3.0", 
"He" : "4.0", 
"Li" : "7.0", 
"Be" : "9.0", 
"B" : "11.0", 
"C" : "12.0",
"C13" : "13.0",  
"N" : "14.0", 
"N15" : "15.0", 
"O" : "16.0", 
"F" : "19.0", 
"Ne" : "20.0"
};

var isotope_indices = { 
"n" : "0", 
"H" : "1", 
"D" : "2", 
"T" : "3", 
"He" : "4", 
"Li" : "5", 
"Be" : "6", 
"B" : "7", 
"C" : "8",
"C13" : "9",  
"N" : "10", 
"N15" : "11", 
"O" : "12", 
"F" : "13", 
"Ne" : "14"
};

var isotope_abbreviation_array = [ 
"n", 
"H", "D", "T", "He", 
"Li", "Be", "B", "C", "C13",  "N", "N15", "O", "F", "Ne"
];

var atomic_element_abbreviation_array = [ 
"n", // 0 atomic number is also defined
"H", "He", 
"Li", "Be", "B", "C", "N", "O", "F", "Ne"
];

var isotope_name_array = [ 
"neutron", 
"hydrogen", 
"deuterium", 
"tritium", 
"helium", 
"lithium", 
"beryllium", 
"boron", 
"carbon",
"carbon-13",  
"nitrogen", 
"nitrogen-15", 
"oxygen", 
"fluorine", 
"neon"
];

//*******************
// The Main Function
//*******************

function analyzeChemicalReactions() {
	var alert_string = "";
	var error_string = "";
	var diagnostic_string = "";

	var products_string = "";
	var reactants_string = "";
	var products_Mw_string = "";
	var reactants_Mw_string = "";

	var body_content;

	var span_nodes;
	var temp_span_node;
	var num_span_nodes = 0;
	var span_node_index = 0;

	var temp_chemical_reaction;
	var chemical_reaction_name = ""; 
	var chemical_reaction_list = new Array();

	var num_reactions = 0;
	var reaction_index = 0;

	var reaction_symbol = "";
	var reaction_symbol_node;

	var reaction_products_node; 
	var reaction_reactants_node; 

	var num_product_molecules = 0;
	var num_reactant_molecules = 0;
	var num_product_molecule_types = 0;
	var num_reactant_molecule_types = 0;

	var child_nodes;
	var temp_child_node;
	var num_child_nodes = 0;
	var child_node_index = 0;

	var molecule_node; 
	var num_molecules = 0;
	var molecule_index = 0;

	var molecule_title = "";
	var num_molecule_types = 0;
	var molecule_type_index = 0;
	var molecule_type_name = "";

	var atom_node; 
	var num_atoms = 0;
	var atom_index = 0;

	var num_atom_types = 0;
	var atom_type_index = 0;

	var connecting_text = "";
	var prefactor_num_molecules = 1;

	var product_molecule_node;
	var product_molecule_node_list = new Array();
	var product_molecule_name_list = new Array();
	var product_molecule_count_list = new Array();

	var reactant_molecule_node;
	var reactant_molecule_node_list = new Array();
	var reactant_molecule_name_list = new Array();
	var reactant_molecule_count_list = new Array();

	var isotope_index = 0;
	var max_num_isotopes = 0;

	var isotope_name = "";
	var isotope_abbreviation = ""; 
	var atomic_number = 0;
	var molecular_weight = 0.0;
	var total_molecular_weight = 0.0;
	var sum_products_molecular_weights = 0.0;
	var sum_reactants_molecular_weights = 0.0;

	var subscript_node;
	var subscript_nodes;

	var reaction_is_balanced = true;
	var balanced_reaction_string = "";

	var product_num_atoms = new Array();
	var reactant_num_atoms = new Array();


// Initialize the reaction-balancing arrays

	max_num_isotopes = isotope_name_array.length;

	for (isotope_index=0; isotope_index<max_num_isotopes; isotope_index++) { 
		product_num_atoms[isotope_index] = 0;
		reactant_num_atoms[isotope_index] = 0;
	}


//****************************************
// Find the chemical reactions on the page
//****************************************

	num_chemical_reactions = 0;

// Get the bodyContent node
	body_content = document.getElementById('bodyContent');
	if (!body_content) { 
		error_string = "ERROR: There is no bodyContent node in this article.";
		window.alert(error_string);
		return;
	}

	span_nodes = body_content.getElementsByTagName("SPAN");
	if (!span_nodes) { 
		error_string = "ERROR: This page has no SPAN nodes.\n";
		window.alert(error_string);
		return; 
	}
	num_span_nodes = span_nodes.length;
	if (num_span_nodes < 1) { 
		error_string = "ERROR: This page has no SPAN nodes.\n";
		window.alert(error_string);
		return; 
	}

	for (span_node_index=0; span_node_index<num_span_nodes; span_node_index++) { 
		temp_span_node = span_nodes[span_node_index];
		if (!temp_span_node) { continue; }

		if (temp_span_node.className == "chemical-reaction") { 
			num_chemical_reactions++;
			chemical_reaction_list.push(temp_span_node);
		}
	} // closes loop over the SPAN nodes in the main article
	if (num_chemical_reactions < 1) { 
		error_string = "No chemical reactions were found on this page.";
		window.alert(error_string);
		return;
	} else if (num_chemical_reactions == 1) {
		alert_string = "This page has one chemical reaction.\n\n"; 
		window.alert(alert_string);
	} else {
		alert_string = "This page has " + num_chemical_reactions + " chemical reactions.\n\n"; 
		alert_string += "These will be analyzed in individual pop-up windows.\n"; 
		window.alert(alert_string);
	}


//*********************************************
// Loop over the chemical reactions on the page
//********************************************* 
	for (reaction_index=1; reaction_index<=num_chemical_reactions; reaction_index++) {
		alert_string = ""; // reset the alert string

		// Reset the reaction-balancing arrays
		for (isotope_index=0; isotope_index<max_num_isotopes; isotope_index++) { 
			product_num_atoms[isotope_index] = 0;
			reactant_num_atoms[isotope_index] = 0;
		}

		temp_chemical_reaction = chemical_reaction_list[reaction_index-1];
		if (!temp_chemical_reaction) { 
			error_string = "ERROR: Chemical reaction " + reaction_index + " is undefined.\n";
			window.alert(error_string);
			continue;
		}
		chemical_reaction_name = temp_chemical_reaction.title;
		if (!chemical_reaction_name) { 
			error_string = "ERROR: No name is defined for chemical reaction " + reaction_index + ".\n";
			window.alert(error_string);
			chemical_reaction_name = "UNNAMED REACTION";
		}
		alert_string += "Reaction " + reaction_index + " represents the " + chemical_reaction_name + "\n\n";
//		window.alert(alert_string);

		child_nodes = temp_chemical_reaction.childNodes;
		if (!child_nodes) { 
			error_string = "ERROR: Chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has no child nodes.\n";
			window.alert(error_string);
			continue;
		} 
		num_child_nodes = child_nodes.length;
		if (num_child_nodes<3) { 
			error_string = "ERROR: Chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has " + num_child_nodes + " child nodes, fewer than the minimum number 3.\n";
			window.alert(error_string);
			continue;
		} 

		reaction_symbol_node = null;
		reaction_products_node = null;
		reaction_reactants_node = null;
		for (child_node_index=0; child_node_index<num_child_nodes; child_node_index++) { 
			temp_child_node = child_nodes[child_node_index];
			if (!temp_child_node) { continue; } 
			if (temp_child_node.nodeType != 1) { continue; } 
			if (!temp_child_node.className) { continue; } 

			if (temp_child_node.className == "reaction-reactants") { 
				reaction_reactants_node = temp_child_node;
			}
			if (temp_child_node.className == "reaction-symbol") { 
				reaction_symbol_node = temp_child_node;
			}
			if (temp_child_node.className == "reaction-products") { 
				reaction_products_node = temp_child_node;
			}
		} // closes loop over the child nodes of the chemical reaction

		if (reaction_reactants_node == null) { 
			error_string = "ERROR: The reactants element of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") is missing.\n";
			window.alert(error_string);
			continue;
		}
		if (reaction_symbol_node == null) { 
			error_string = "ERROR: The symbol element of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") is missing.\n";
			window.alert(error_string);
			continue;
		}
		if (reaction_products_node == null) { 
			error_string = "ERROR: The products element of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") is missing.\n";
			window.alert(error_string);
			continue;
		}
//		alert_string += "Found the reaction reactants, symbol and products elements for chemical reaction " + reaction_index + " (" + chemical_reaction_name + ").\n";
//		window.alert(alert_string);


//**********************
// Analyze the reactants
//**********************
		child_nodes = reaction_reactants_node.childNodes;
		if (!child_nodes) { 
			error_string = "ERROR: The reactants node of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has no child nodes (molecules).\n";
			window.alert(error_string);
			continue;
		} 
		num_child_nodes = child_nodes.length;
		if (num_child_nodes<1) { 
			error_string = "ERROR: The reactants node of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has zero child nodes (molecules).\n";
			window.alert(error_string);
			continue;
		}

		num_reactant_molecules = 0;
		prefactor_num_molecules = 1;
		num_reactant_molecule_types = 0;
		for (child_node_index=0; child_node_index<num_child_nodes; child_node_index++) { 
			temp_child_node = child_nodes[child_node_index];
			if (!temp_child_node) { continue; } 
			if (temp_child_node.nodeType == 1) { // element node
				if (!temp_child_node.className) { continue; }
				
				if (temp_child_node.className == "molecule") {
					num_reactant_molecules += prefactor_num_molecules;
					reactant_molecule_count_list[num_reactant_molecule_types] = prefactor_num_molecules;
					reactant_molecule_node_list[num_reactant_molecule_types] = temp_child_node;
					molecule_type_name = temp_child_node.title;
					if (!molecule_type_name) { molecule_type_name = "unknown molecule"; }
					reactant_molecule_name_list[num_reactant_molecule_types] = molecule_type_name;
					prefactor_num_molecules = 1;
					num_reactant_molecule_types++;
				}
			} else if (temp_child_node.nodeType == 3) { // text node
				connecting_text = temp_child_node.data;
				connecting_text = connecting_text.replace(/[^0-9]/g, "");
				if (!connecting_text) { 
					prefactor_num_molecules = 1; 
				} else { 
					prefactor_num_molecules = connecting_text - 0; 
				}  
			}
		} // closes loop over the child nodes of the reaction_reactants_node

		sum_reactants_molecular_weights = 0.0;
		for (molecule_type_index=0; molecule_type_index<num_reactant_molecule_types; molecule_type_index++) {
			num_molecules = reactant_molecule_count_list[molecule_type_index]; 
			reactant_molecule_node = reactant_molecule_node_list[molecule_type_index];
			if (!reactant_molecule_node) { 
				error_string = "ERROR: Reactant molecule type " + molecule_type_index + " in chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") is undefined.\n";
				window.alert(error_string);
				continue;
			}
	
			span_nodes = reactant_molecule_node.getElementsByTagName("SPAN");
			if (!span_nodes) { 
				error_string = "ERROR: Reactant molecule type " + molecule_type_index + " in chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has no SPAN nodes (atoms).\n";
				window.alert(error_string);
				continue;
			} 
			num_span_nodes = span_nodes.length;
			if (num_span_nodes<1) { 
				error_string = "ERROR: Reactant molecule type " + molecule_type_index + " in chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has zero SPAN nodes (atoms).\n";
				window.alert(error_string);
				continue;
			}

			molecular_weight = 0.0;
			for (span_node_index=0; span_node_index<num_span_nodes; span_node_index++) { 
				temp_span_node = span_nodes[span_node_index];
				if (!temp_span_node) { continue; } 
				if (temp_span_node.className != "atom") { continue; } 

				isotope_name = temp_span_node.title;
				if (!isotope_name) { isotope_name = "hydrogen"; }
				isotope_abbreviation = isotope_abbreviations[isotope_name];
				atomic_number = isotope_atomic_numbers[isotope_abbreviation];
				isotope_index = isotope_indices[isotope_abbreviation] - 0;

				subscript_nodes = temp_span_node.getElementsByTagName("SUB");
				if (!subscript_nodes) { 
					num_atoms = 1;
				} else {
 					subscript_node = subscript_nodes[0];
					if (!subscript_node) { 
						num_atoms = 1;
					} else { 
						num_atoms = subscript_nodes[0].innerHTML;
					}
				}
				reactant_num_atoms[isotope_index] += num_molecules * num_atoms - 0;
				molecular_weight += num_atoms*isotope_weights[isotope_abbreviation] - 0;
				total_molecular_weight = num_molecules * molecular_weight;

			} // closes loop over child nodes (atoms) in molecule
			reactant_molecule_name_list[molecule_type_index] += " \t " + num_molecules + " x  Mw " + molecular_weight + " = " + total_molecular_weight + " Da";

			sum_reactants_molecular_weights += total_molecular_weight;

		} // closes loop over reactant molecule types 

		reactants_string = "The " + num_reactant_molecules + " reactant molecules are:\n";
		for (molecule_type_index=0; molecule_type_index<num_reactant_molecule_types; molecule_type_index++) { 
			num_molecules = reactant_molecule_count_list[molecule_type_index];
			if (num_molecules != 1) { 
				reactants_string += "\t " + num_molecules + " molecules of ";
			} else { 
				reactants_string += "\t 1 molecule of ";
			} 
			reactants_string += reactant_molecule_name_list[molecule_type_index] + "\n";
		}
		reactants_Mw_string = "Molecular weight of reactants = " + sum_reactants_molecular_weights + " Da\n";


//*********************
// Analyze the products
//*********************
		child_nodes = reaction_products_node.childNodes;
		if (!child_nodes) { 
			error_string = "ERROR: The products node of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has no child nodes (molecules).\n";
			window.alert(error_string);
			continue;
		} 
		num_child_nodes = child_nodes.length;
		if (num_child_nodes<1) { 
			error_string = "ERROR: The products node of chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has zero child nodes (molecules).\n";
			window.alert(error_string);
			continue;
		}
		num_product_molecules = 0;
		prefactor_num_molecules = 1;
		num_product_molecule_types = 0;
		for (child_node_index=0; child_node_index<num_child_nodes; child_node_index++) { 
			temp_child_node = child_nodes[child_node_index];
			if (!temp_child_node) { continue; } 
			if (temp_child_node.nodeType == 1) { // element node
				if (!temp_child_node.className) { continue; }
				
				if (temp_child_node.className == "molecule") {
					num_product_molecules += prefactor_num_molecules;
					product_molecule_count_list[num_product_molecule_types] = prefactor_num_molecules;
					product_molecule_node_list[num_product_molecule_types] = temp_child_node;
					molecule_type_name = temp_child_node.title;
					if (!molecule_type_name) { molecule_type_name = "unknown molecule"; }
					product_molecule_name_list[num_product_molecule_types] = molecule_type_name;
					prefactor_num_molecules = 1;
					num_product_molecule_types++;
				}
			} else if (temp_child_node.nodeType == 3) { // text node
				connecting_text = temp_child_node.data;
				connecting_text = connecting_text.replace(/[^0-9]/g, "");
				if (!connecting_text) { 
					prefactor_num_molecules = 1; 
				} else { 
					prefactor_num_molecules = connecting_text - 0; 
				}  
			}
		} // closes loop over the child nodes of the reaction_products_node

		sum_products_molecular_weights = 0.0;
		for (molecule_type_index=0; molecule_type_index<num_product_molecule_types; molecule_type_index++) {
			num_molecules = product_molecule_count_list[molecule_type_index];  
			product_molecule_node = product_molecule_node_list[molecule_type_index];
			if (!product_molecule_node) { 
				error_string = "ERROR: Product molecule type " + molecule_type_index + " in chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") is undefined.\n";
				window.alert(error_string);
				continue;
			}
	
			span_nodes = product_molecule_node.getElementsByTagName("SPAN");
			if (!span_nodes) { 
				error_string = "ERROR: Product molecule type " + molecule_type_index + " in chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has no SPAN nodes (atoms).\n";
				window.alert(error_string);
				continue;
			} 
			num_span_nodes = span_nodes.length;
			if (num_span_nodes<1) { 
				error_string = "ERROR: Product molecule type " + molecule_type_index + " in chemical reaction " + reaction_index + " (" + chemical_reaction_name + ") has zero SPAN nodes (atoms).\n";
				window.alert(error_string);
				continue;
			}

			molecular_weight = 0.0;
			for (span_node_index=0; span_node_index<num_span_nodes; span_node_index++) { 
				temp_span_node = span_nodes[span_node_index];
				if (!temp_span_node) { continue; } 
				if (temp_span_node.className != "atom") { continue; } 

				isotope_name = temp_span_node.title;
				if (!isotope_name) { isotope_name = "hydrogen"; }
				isotope_abbreviation = isotope_abbreviations[isotope_name];
				atomic_number = isotope_atomic_numbers[isotope_abbreviation];
				isotope_index = isotope_indices[isotope_abbreviation] - 0;

				subscript_nodes = temp_span_node.getElementsByTagName("SUB");
				if (!subscript_nodes) { 
					num_atoms = 1;
				} else {
 					subscript_node = subscript_nodes[0];
					if (!subscript_node) { 
						num_atoms = 1;
					} else { 
						num_atoms = subscript_nodes[0].innerHTML;
					}
				}
				product_num_atoms[isotope_index] += num_molecules * num_atoms - 0;
				molecular_weight += num_atoms*isotope_weights[isotope_abbreviation] - 0;
				total_molecular_weight = num_molecules * molecular_weight;

			} // closes loop over child nodes (atoms) in molecule
			product_molecule_name_list[molecule_type_index] += " \t " + num_molecules + " x  Mw " + molecular_weight + " = " + total_molecular_weight + " Da";

			sum_products_molecular_weights += total_molecular_weight;

		} // closes loop over product molecule types 

		products_string = "The " + num_product_molecules + " product molecules are:\n";
		for (molecule_type_index=0; molecule_type_index<num_product_molecule_types; molecule_type_index++) { 
			num_molecules = product_molecule_count_list[molecule_type_index];
			if (num_molecules != 1) { 
				products_string += "\t " + num_molecules + " molecules of ";
			} else { 
				products_string += "\t 1 molecule of ";
			} 
			products_string += product_molecule_name_list[molecule_type_index] + "\n";
		}
		products_Mw_string = "Molecular weight of products = " + sum_products_molecular_weights + " Da\n";


//****************************
// Analyze the reaction symbol
//****************************
		reaction_symbol = reaction_symbol_node.title;
		if (!reaction_symbol) { 
			error_string = "ERROR: The reaction symbol is undefined.\n";
			window.alert(error_string);
			continue;
		}
		switch (reaction_symbol) { 
			case "equilibrium":
				alert_string += "This reaction is an equilibrium between " + num_reactant_molecules + " reactant and " + num_product_molecules + " product molecules.\n\n";
				break;
			case "forward":
			case "forwards":
			case "forward_reaction":
				alert_string += "This is the forward reaction from " + num_reactant_molecules + " reactant molecules to " + num_product_molecules + " product molecules.\n\n";
				break;
			case "backward":
			case "backwards":
			case "back_reaction":
			case "backward_reaction":
				alert_string += "This is the backward reaction from " + num_product_molecules + " product molecules to " + num_reactant_molecules + " reactant molecules.\n\n";
				break;
			case "forward_equilibrium":
				alert_string += "This reaction is an equilibrium between " + num_reactant_molecules + " reactant and " + num_product_molecules + " product molecules that is strongly biased towards the products.\n\n";
				break;
			case "backward_equilibrium":
				alert_string += "This reaction is an equilibrium between " + num_reactant_molecules + " reactant and " + num_product_molecules + " product molecules that is strongly biased towards the reactants.\n\n";
				break;
			default: 
				error_string = "ERROR: The reaction symbol \"" + reaction_symbol + "\" is not recognized.\n";
				window.alert(error_string);
				continue;
		} // closes switch over the reaction_symbol


// ********************************
// Report analysis of this reaction
// ********************************
		alert_string += reactants_string + "\n";
		alert_string += products_string + "\n";

		if (sum_reactants_molecular_weights == sum_products_molecular_weights) { 
			alert_string += "Mass is conserved in the reaction\n";
		} else { 
			alert_string += "Mass is NOT conserved in the reaction\n";
		}
		alert_string += "\t" + reactants_Mw_string;
		alert_string += "\t" + products_Mw_string;
		alert_string += "\n";

		reaction_is_balanced = true;
		balanced_reaction_string = "";
		for (isotope_index=1; isotope_index<max_num_isotopes; isotope_index++) { 
			if (product_num_atoms[isotope_index] != reactant_num_atoms[isotope_index]) { 
				reaction_is_balanced = false;
				balanced_reaction_string += "\t Unbalanced " + isotope_name_array[isotope_index] + " atoms: Reactants " + reactant_num_atoms[isotope_index] + ", Products " + product_num_atoms[isotope_index] + "\n";
			} else if (reactant_num_atoms[isotope_index]>0){ 
				balanced_reaction_string += "\t Balanced " + isotope_name_array[isotope_index] + " atoms: Reactants " + reactant_num_atoms[isotope_index] + ", Products " + product_num_atoms[isotope_index] + "\n";
			}
		}
		if (reaction_is_balanced == true) { 
			alert_string += "Reaction is balanced in all atoms:\n";
			alert_string += balanced_reaction_string + "\n";
		} else { 
			alert_string += "Reaction is UNBALANCED as follows:\n";
			alert_string += balanced_reaction_string + "\n";
		}
		window.alert(alert_string);

	} // closes loop over the chemical reactions

} // closes function analyzeChemicalReactions()

addOnloadHook(function () {
mw.util.addPortletLink('p-navigation', 'javascript:analyzeChemicalReactions()', 'Chemical reactions', 'ca-reactions', 'Analyze the chemical reactions on a page', '!', '');
});

//</pre>