<!--/**  parser.js  version: 1.0  written by: Samuel MainaCopyright: Copyright (c) 2004 by Knovel Corporation  Description: Preliminary validation for Knovel Search Queries.===============================================================================REGULAR EXPRESSIONS REFERENCE*/var foundError = false;          //Flag to keep track of whether an error has already occured.var errorMsg = "";               //Error message shown to user.var changeMessage = true;var response = "";//Error Messages.var ERROR0 = "Please enter one or more search terms."; // Changed by MN for KPP-1242 per email in KPP. 3/23/09var ERROR1 = "Missing an open parenthesis."; var ERROR2 = "Missing a close parenthesis."; var ERROR3 = "* Can only be used at the end of a word."; var ERROR6 = "Missing an opening/closing quotation mark."; var ERROR7 = "Quotation marks used incorrectly."; var ERROR8 = "Booleans cannot follow an open parenthesis." ; var ERROR9 = "Closing parenthesis cannot follow a boolean. "; var ERROR10 = "Cannot have empty parenthesis.";var ERROR11 = "Booleans used incorrectly.";var ERROR12 = "Single characters are ignored.";var ERROR13 = "Cannot start with a boolean.";var ERROR14 = "* Cannot be used inside quotations.";var ERROR15 = "Booleans are not allowed";var ERROR16 = "* Cannot be used with single characters";var ERROR17 = "Please Note:  Single characters return too many hits when searched in PDF and HTML text. However they can return valid hits from Knovel's custom-built index. Click \"OK\" to search the custom index only or \"Cancel\" to modify your search.";/**  Entry point. Called from JSP page when user submits form. (Basic Search)*/function validate(form, textBox){errorMsg = "";var strIn = "";var textField = textBox != undefined ? textBox : document.getElementById('topTextInput');  	var temp = textField.value;// Strip out all html tagstemp = temp.replace(/<.*?>/g, "");textField.value = temp;if(temp == ''){foundError = true;errorMsg = ERROR0;}else{   // Strip carriage returns  temp = temp.replace(/\n/g, "");  temp = temp.replace(/\r/g, "");  strIn = trimSpaces(temp.toLowerCase());  checkRemWords(strIn);  strIn = parensBalance(strIn);                //We first check the use of parenthesis. }// If an error was found, display it on the calling page.if(foundError){ showError('errorMsg1', errorMsg, 'subTabSearchHelpText');		foundError = false;textField.focus();changeMessage = true;return false;}// Basic searchif (textBox == undefined){  temp = removeSpacesBetweenHyphens(strIn);  temp = removeExtraBooleans(temp, strIn);      // temp = URLEncode(temp);  // form.SearchTermA1.value = temp;  document.getElementById('topTextInput').value = temp;}else{temp = removeSpacesBetweenHyphens(strIn);  	temp = removeExtraBooleans(temp, strIn);    // temp =  URLEncode(temp);textBox.value = temp;}return true;}/**  Entry point. Called from JSP page when user submits form. (Basic Search)*/function validateAdv(box, strIn, allowEmpty){errorMsg = "";if(strIn == '' && allowEmpty)    return true;else if(strIn == '' && !allowEmpty){errorMsg = ERROR0;foundError = true;return;}else{ 		  strIn = trimSpaces(strIn);  strIn = parensBalance(strIn);                //We first check the use of parenthesis.}if(!foundError) {if(strIn.match(/\s(and|not|or)(\s|$)/) != null){errorMsg = ERROR15;  foundError = true;}}// If an error was found, display it on the calling page.if (foundError){ var boxId = 'errorMsg' + box;		showError(boxId, errorMsg);	foundError = false;return false;}return true;}/**Function removes all unnecessary white space characters.e.g "hey there, (   (this    is just but    a  testing    String)     )  man" becomes"hey there, ((this is just but a testing String)) man"*/function trimSpaces(strIn){	  //check for double white spaces, white spaces leading and trailing parenthesis.strIn = strIn.replace(/\s+/g, " ");strIn = strIn.replace(/\s\)/g, ")");strIn = strIn.replace(/\(\s/g, "(");if(strIn.match(/^\s/) != null)  //If string starts with space, trim it.strIn = strIn.substring(1);if(strIn.match(/\s$/) != null)  //If string ends with space, trim it.strIn = strIn.substring(0, strIn.length-1);return strIn;}/**  Functions validates that the parenthesis are balanced.Basically counts the number of open and closed parenthesis and checks that they are equal.*/function parensBalance(strIn){//Check parenthesis balance. Need an even number to qualifyvar openParens = strIn.match(/\(/g) != null ? strIn.match(/\(/g).length : 0;var closedParens = strIn.match(/\)/g) != null ? strIn.match(/\)/g).length : 0;//If not balanced, check for parens within terms.//Condition here is that if parens appear within  terms, the word has to have an  asterisk.if(openParens != closedParens){openParens -= strIn.match(/\w\(\w*?\*/g) != null ? strIn.match(/\w\(\w*?\*/g).length : 0;    closedParens -= strIn.match(/\w\)\w*?\*/g) != null ? strIn.match(/\w\)\w*?\*/g).length : 0;}if(closedParens > openParens) //Extra close parenthesis. {errorMsg = ERROR1;foundError = true;return;}else if(openParens > closedParens){errorMsg = ERROR2;foundError = true;return;}//Check for this weird scenario. User enters nothing between parenthesis  if(strIn.match(/\(\)/) != null){errorMsg = ERROR10;foundError = true;return;}return checkAsterisk(strIn);}/**Function checks for the occurance of asterisk and verifies that it is properly used.Asterisk can only be used at the end of a word*/function checkAsterisk(strIn){if(strIn.indexOf("*") != -1)    // check if string has asterisk. If not return strIn.{//Check if String begin with '*'//Check if '*' appears between characters.//Check if '*' is infront of a termif(strIn.match(/^\*/) != null || strIn.match(/\S\*[^\s)"]/)  != null || strIn.match(/\s\(*?\*/)  != null){errorMsg = ERROR3;foundError = true;return;}}return checkQuotes(strIn);}/**  Function validates the use of quotations. Ensures that quotations are balanced and properly used.*/function checkQuotes(strIn){//check if string has quotesvar quotes = strIn.match(/"/g) != null ? strIn.match(/"/g).length : 0;//First check for balance;if(quotes%2 != 0){		  errorMsg = ERROR6;foundError = true;return;}//At this point we have determined that the Quotes are balanced. Now check for proper usage.if(strIn.match(/\"\s?\"/) != null) //check for quote followed by quote.{errorMsg = ERROR7;foundError = true;return;}  inQuotes = false;var parens = 0;for(i = 0; i < strIn.length; i++){var ch = strIn.charAt(i);if(ch == '*' && inQuotes)    // check if '*' appears within quotes.  {errorMsg = ERROR14;foundError = true;return;}if(ch == '"' && !inQuotes){inQuotes = true;continue;}else if(ch == '(' && inQuotes){parens++;continue;}else if(ch == ')' && inQuotes){parens--;continue;}if(ch == '"' && inQuotes)  {if(parens != 0){errorMsg = ERROR7;  foundError = true; return;}else inQuotes = false;}}strIn = checkSpaceBtwQuotes(strIn);return checkBooleans(strIn);}function checkSpaceBtwQuotes(strIn){var str = '';inQuotes = false;for(i = 0; i < strIn.length; i++){var ch = strIn.charAt(i);if(ch == '"' && !inQuotes)inQuotes = true;else if(ch == '"' && inQuotes)  {inQuotes = false;if(i+1 < strIn.length && strIn.charCodeAt(i+1) != 32){  str += ch + ' ';continue;}}str += ch;if(!inQuotes && i+1 < strIn.length && strIn.charAt(i) != 32 && strIn.charAt(i+1) == '"')str += ' ';}return str;}/** Function checks for proper use of booleans*/function checkBooleans(strIn){//Replace "and not" with "not"strIn = strIn.replace(/\band\snot\b/g, "not");//Check that the terms don't only have booleansvar temp = strIn;temp = temp.replace(/[^a-zA-Z0-9\s\*]/g, " ");temp =  trimSpaces(temp);var myList = temp.split(" ");var hasTerms = false;for(var i = 0; i < myList.length; i++){if(myList[i].length != 0 && myList[i] != "and" && myList[i] != "not" && myList[i] != "or"){  hasTerms = true;break;}}//Check that term does not start with a booleanif(myList[0] == "and" || myList[0] == "or" || myList[0] == "not")									{errorMsg = ERROR13;foundError = true;return;}if(!hasTerms)  {errorMsg = ERROR0;foundError = true;return;}//Check if boolean is preceeded by open parenthesis  if(strIn.match(/\s\((and|not|or)(\s|\))/) != null){errorMsg = ERROR8;foundError = true;}  //Check if boolean is followed by close parenthesis  if(strIn.match(/\s(and|not|or)\)/) != null){errorMsg = ERROR9;foundError = true;return;}return strIn;}/*  Replace space hyphen space with space eg 'antoine coefficients - vapor pressure' becomes 'antoine coefficients vapor pressure'  Trim spaces leading or trailing next to hyphensas per KWS-3016*/function removeSpacesBetweenHyphens(strIn){strIn = strIn.replace(/\s-\s/g, " ");strIn = strIn.replace(/-\s/g, "-");  strIn = strIn.replace(/\s-/g, "-");return strIn;}/**  Functions strips out consecutive booleans.  Strips out booleans if they are at the end of the query string.*/function removeExtraBooleans(strIn){//Remove extra booleansvar inBoolean = false;var temp2 = '';var theBoolean;myList = strIn.split(" ");for(var i = 0; i < myList.length; i++){if(myList[i].length != 0 && myList[i].toLowerCase() != "and" && myList[i].toLowerCase() != "not" && myList[i].toLowerCase() != "or")inBoolean = false;if(inBoolean){if(myList[i].toLowerCase() == "and" || myList[i].toLowerCase() == "or")  continue;if( myList[i].toLowerCase() == "not" && theBoolean != "and")  //If "not", check if previous was "and"  continue;}if(!inBoolean && (myList[i].toLowerCase() == "and" || myList[i].toLowerCase() == "not" || myList[i].toLowerCase() == "or")){inBoolean = true;theBoolean = myList[i].toLowerCase();  }temp2 += myList[i] + ' ';}//Check if string ends with a booleanvar temp = trimSpaces(temp2.toLowerCase());myList = temp.split(" ");var lastIndex = myList.length -1;if(myList[lastIndex] == 'not')  //If query ends with not, strip it out{temp2 = temp2.substring(0, temp2.length-4);if(myList[lastIndex-1] == 'and')  //If query ends with not, strip it out  temp2 = temp2.substring(0, temp2.length-4);}if(myList[lastIndex] == 'and')  //If query ends with and/not, strip them outtemp2 = temp2.substring(0, temp2.length-4);if(myList[lastIndex] == 'or' )  //If query ends with or, strip it outtemp2 = temp2.substring(0, temp2.length-3);return removeSpaceBetweenQoutes(trimSpaces(temp2));}function removeSpaceBetweenQoutes(strIn){//remove spaces between quotesvar inQuotes = false;var returnStr = "";for(i = 0; i < strIn.length; i++){var ch = strIn.charAt(i);if(!inQuotes && ch == '"')   {inQuotes = true;returnStr += ch;continue;}else if(inQuotes && ch == '"') inQuotes = false;		if((inQuotes && ch == ' ' && i+1 < strIn.length && strIn.charAt(i+1) == '"') || (inQuotes && ch == ' ' && i > 0 && strIn.charAt(i-1) == '"')) continue; returnStr += ch;}return returnStr;}/**  Resets basic search to default values*/function resetForm(hasDefaultSearchType){var object = document.MyForm;object.QueryBox.value = '';object.SecondSelect1.selectedIndex = 0;object.SubSubjectAreaID.selectedIndex =  0;object.SubjectAreaID[0].checked = !hasDefaultSearchType ? true : false;object.SubjectAreaID[1].checked = hasDefaultSearchType ? true : false;;}/** Functions switches the Basic Search (search in) drop-down values when within a book TOC or Advanced Search window.*/function changeOptions(){var object = document.MyForm;if(object.MyBookID != undefined && object.MyBookID.value == 0)  return true;if(object.MyBookID != undefined)  object.BookID.value = object.MyBookID.value;var object2 = object.SecondSelect1.options;//Determine how many radio buttons there are. For some Verticals, there are only 2, This Title only is the last option.var optionsCount = object.SubjectAreaID.length; 	if(object.SubjectAreaID[optionsCount-1].checked) //This title only{object2[1].text = 'Table of Contents';object2[1].value = '2';object2[2] = null;object2[3] = null;object2[4] = null;object2[2] = null;    object.SubSubjectAreaID.disabled = true;object.InBook.value = 'true';}else //Entire Vertical/My Subscription{object2[1].text = 'Author';object2[1].value = '4';var optionName = new Option('ISBN', '5', false, false);    object2[2] = optionName;optionName = new Option('Table of Contents', '2', false, false);    object2[3] = optionName;optionName = new Option('Title', '3', false, false);    object2[4] = optionName;object.SubSubjectAreaID.disabled = false;object.InBook.value = 'false';}return true;}/**  Function disables/enables Basic search Radio buttons when within a TOC.*/function checkSubjectAreaID(object, bookID){  if(object != undefined && object.SubjectAreaID != undefined && object.SubSubjectAreaID != undefined){if(bookID != 0)  {object.SubSubjectAreaID.selectedIndex = 0;object.SubSubjectAreaID.disabled = true;object.BookID.value = bookID; 	  }  else     {   object.SubjectAreaID[0].disabled = false;  object.SubjectAreaID[1].disabled = false;  }}}/**  Verifies that advanced search text boxes do not contain booleans*/function checkAdvancedSearchFields(){var object = document.MyForm;// First check that atleast one field is enteredvar searchTermA1 = object.SearchTermA1 != undefined ? trimSpaces(object.SearchTermA1.value.toLowerCase()) : '';var searchTermA2 = object.SearchTermA2 != undefined ? trimSpaces(object.SearchTermA2.value.toLowerCase()) : '';var searchTermB1 = object.SearchTermB1 != undefined ? trimSpaces(object.SearchTermB1.value.toLowerCase()) : '';var searchTermB2 = object.SearchTermB2 != undefined ? trimSpaces(object.SearchTermB2.value.toLowerCase()) : '';var searchTermC1 = object.SearchTermC1 != undefined ? trimSpaces(object.SearchTermC1.value.toLowerCase()) : '';var searchTermC2 = object.SearchTermC2 != undefined ? trimSpaces(object.SearchTermC2.value.toLowerCase()) : '';var operatorSelect1 = object.OperatorSelect1[object.OperatorSelect1.selectedIndex].value;var operatorSelect2 = object.OperatorSelect2[object.OperatorSelect2.selectedIndex].value;var operatorSelect3 = object.OperatorSelect3[object.OperatorSelect3.selectedIndex].value;// Check if user has populated at least one Search Term.if (operatorSelect1 != 1 && searchTermA1 == '' && operatorSelect2 != 1 && searchTermA2 == '' && operatorSelect3 != 1 && searchTermB1 == '' && searchTermB2 == '' && searchTermC1 == '' && searchTermC2 == ''){errorMsg = ERROR0;showError('errorMsg1', errorMsg);			object.SearchTermA1.focus();foundError = false;return false;}// If user has selected between option for operator (OperatorSelect 4), then ensure both Search Boxes are populatedif (operatorSelect1 == 4 && ((searchTermA1 == '' & searchTermA2 != '') || (searchTermA1 != '' & searchTermA2 == ''))){errorMsg = ERROR0;showError('errorMsg1', errorMsg);			if(searchTermA1 == '')object.SearchTermA1.focus();else object.SearchTermA2.focus();foundError = false;return false;}if (operatorSelect2 == 4 && ((searchTermB1 == '' & searchTermB2 != '') || (searchTermB1 != '' & searchTermB2 == ''))){errorMsg = ERROR0;showError('errorMsg2', errorMsg);			if(searchTermB1 == '')object.SearchTermB1.focus();else object.SearchTermB2.focus();foundError = false;return false;}if (operatorSelect3 == 4 && ((searchTermC1 == '' & searchTermC2 != '') || (searchTermC1 != '' & searchTermC2 == ''))){errorMsg = ERROR0;showError('errorMsg3', errorMsg);				if(searchTermC1 == '')object.SearchTermC1.focus();else object.SearchTermC2.focus();foundError = false;return false;}// SearchTermA1if (operatorSelect1 != 1){  if(!validateAdv(1, searchTermA1, true))   {  object.SearchTermA1.focus();foundError = false;  return false;  }}// SearchTermB1if (operatorSelect2 != 1){  if(!validateAdv(2, searchTermB1, true))   {  object.SearchTermB1.focus();foundError = false;  return false;  }}// SearchTermC1if (operatorSelect3 != 1){  if(!validateAdv(3, searchTermC1, true))   {  object.SearchTermC1.focus();foundError = false;  return false;  }}return true;}function URLEncode(strIn){// The Javascript escape and unescape functions do not correspond// with what browsers actually do...var SAFECHARS = "0123456789" +					// Numeric"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic"abcdefghijklmnopqrstuvwxyz" +"-_.!~*'()";					// RFC2396 Mark charactersvar HEX = "0123456789ABCDEF";var plaintext = strIn;var encoded = "";for (var i = 0; i < plaintext.length; i++ ) {var ch = plaintext.charAt(i);    if (ch == " ") {    encoded += "+";				// x-www-urlencoded, rather than %20} else if (SAFECHARS.indexOf(ch) != -1) {    encoded += ch;} else {    var charCode = ch.charCodeAt(0);if (charCode > 255) {   /* alert( "Unicode Character '"                         + ch                         + "' cannot be encoded using standard URL encoding.\n" +          "(URL encoding only supports 8-bit characters.)\n" +  "A space (+) will be substituted." );*/                                  //For us, no need for the messageencoded += "+";} else {encoded += "%";encoded += HEX.charAt((charCode >> 4) & 0xF);encoded += HEX.charAt(charCode & 0xF);}}} // forreturn encoded;}// display the error messagefunction showError(msgId, msg, idOff) {if (idOff) {document.getElementById(idOff).style.display = 'none';												}	document.getElementById(msgId).innerHTML = msg;document.getElementById(msgId).style.display = 'block';		}//check Rem wordsfunction checkRemWords(searchString){if(!(searchString.length == 0) && searchString.split(" ").length == 1 && stopWordsList.indexOf(searchString) != -1){foundError = true;errorMsg = "Your search contains a stop word, please try again.";}else if(!(searchString.length == 0)){var onlyFoundStopWords = false;var searchStringArray = searchString.split(" ");for(var i = 0; i < searchStringArray.length; i++){if(stopWordsList.indexOf(trimSpaces(searchStringArray[i])) != -1)onlyFoundStopWords = true;else {onlyFoundStopWords = false;break;}} if(onlyFoundStopWords){foundError = true;errorMsg = "Your search contains a stop word, please try again.";}	}}