Problem with indexOf() and php variable

Hi,

I have downloaded a JavaScript from dhtmlgoodies.com wich makes a switch menu and highlights the active link.
The url from my dynamic menu sends two variables (i.e. domain.com/portfolio/brand.php?sid=7&cid=2) but the javascript only highlights the first menulink. Since they all use the same dynamic page (brand.php) I guess it’s because the js file only manages to get/pass the first variable?
At least it worked fine when I only passed one variable. The original script had indexOf(‘?’) and I changed it to ‘&’ - then it worked.
Is it possible to alter the indexOf() to get/pass more than one variable or is it somewhere else the script should be changed?
Appriciate any help. Thanks a lot.


	var activeMenuItem = new Array();
	
	function isUlInArray(inputObj,ulObj){
		while(inputObj && inputObj.id!='dhtmlgoodies_listMenu'){
			if(inputObj==ulObj)return true;
			inputObj = inputObj.parentNode;			
		}		
		return false;
	}
	
	function showHideSub(e,inputObj)
	{
		

		if(!inputObj)inputObj=this;
		var parentObj = inputObj.parentNode;
		var ul = parentObj.getElementsByTagName('UL')[0];
		if(activeMenuItem.length>0){
			for(var no=0;no<activeMenuItem.length;no++){
				if(!isUlInArray(ul,activeMenuItem[0]) && !isUlInArray(activeMenuItem[0],ul)){
					activeMenuItem[no].style.display='none';
					activeMenuItem.splice(no,1);
					no--;
				}
			}			
		}
		if(ul.offsetHeight == 0){
			ul.style.display='block';
			activeMenuItem.push(ul);
		}else{
			ul.style.display='none';
		}
	}
	
	function showHidePath(inputObj)
	{
		var startTag = inputObj;
		showHideSub(false,inputObj);
		inputObj = inputObj.parentNode;
		while(inputObj){			
			inputObj = inputObj.parentNode;
			if(inputObj.tagName=='LI')showHideSub(false,inputObj.getElementsByTagName('A')[0]);
			if(inputObj.id=='dhtmlgoodies_listMenu')inputObj=false;	
		}		
	}
	
	function initMenu()
	{
		var obj = document.getElementById('dhtmlgoodies_listMenu');
		var linkCounter=0;
		var aTags = obj.getElementsByTagName('A');
		var activeMenuItem = false;
		var activeMenuLink = false;
		var thisLocationArray = location.href.split(/\\//);
		var fileNameThis = thisLocationArray[thisLocationArray.length-1];
		if(fileNameThis.indexOf('&')>0)fileNameThis = fileNameThis.substr(0,fileNameThis.indexOf('&')); /* Changed the original '?' to '&' both places */
		if(fileNameThis.indexOf('#')>0)fileNameThis = fileNameThis.substr(0,fileNameThis.indexOf('#'));

		for(var no=0;no<aTags.length;no++){
			var parent = aTags[no].parentNode;
			var subs = parent.getElementsByTagName('UL');
			if(subs.length>0){
				aTags[no].onclick = showHideSub;	
				linkCounter++;
				aTags[no].id = 'aLink' + linkCounter;
			}	
			
			if(aTags[no].href.indexOf(fileNameThis)>=0 && aTags[no].href.charAt(aTags[no].href.length-1)!='#'){				
				if(aTags[no].parentNode.parentNode){								
					var parentObj = aTags[no].parentNode.parentNode.parentNode;
					var a = parentObj.getElementsByTagName('A')[0];
					if(a.id && !activeMenuLink){
						
						activeMenuLink = aTags[no];
						activeMenuItem = a.id;
					}
				}
			}		
		}		

		if(activeMenuLink){
			activeMenuLink.className='activeMenuLink';
		}
		if(activeMenuItem){
			if(document.getElementById(activeMenuItem))showHidePath(document.getElementById(activeMenuItem));	
		}
	}
	window.onload = initMenu;

You use a separate function that gets all the URL parameters.

function getUrlParam(name){
	var results = new RegExp('[\\\\?&]' + name + '=([^&#]*)').exec(window.location.href);
	if (!results) { return 0; }
	return results[1] || 0;
}

which you could simply call to get your “sid” and “cid” variables like so:

var sid = getUrlParam(sid);

Hi John,
Thanks for your reply. I’m not very experienced with js but I have put the function before the initMenu function, and called for the variable there.
Now all the client links are correct highlighted in the menu, but the menu collapses when I click on pagination links in the page. This adds two more variables to the url string (&page=2&ipp=1).
Is it possible to only call for two variables and stop. So that whatever comes after ?sid=x&cid=y will be overlooked?
Here is the script as it is now:


	var activeMenuItem = new Array();
	
	
	function isUlInArray(inputObj,ulObj){
		while(inputObj && inputObj.id!='dhtmlgoodies_listMenu'){
			if(inputObj==ulObj)return true;
			inputObj = inputObj.parentNode;			
		}		
		return false;
	}
	
	function showHideSub(e,inputObj)
	{
		

		if(!inputObj)inputObj=this;
		var parentObj = inputObj.parentNode;
		var ul = parentObj.getElementsByTagName('UL')[0];
		if(activeMenuItem.length>0){
			for(var no=0;no<activeMenuItem.length;no++){
				if(!isUlInArray(ul,activeMenuItem[0]) && !isUlInArray(activeMenuItem[0],ul)){
					activeMenuItem[no].style.display='none';
					activeMenuItem.splice(no,1);
					no--;
				}
			}			
		}
		if(ul.offsetHeight == 0){
			ul.style.display='block';
			activeMenuItem.push(ul);
		}else{
			ul.style.display='none';
		}
	}
	
	function showHidePath(inputObj)
	{
		var startTag = inputObj;
		showHideSub(false,inputObj);
		inputObj = inputObj.parentNode;
		while(inputObj){			
			inputObj = inputObj.parentNode;
			if(inputObj.tagName=='LI')showHideSub(false,inputObj.getElementsByTagName('A')[0]);
			if(inputObj.id=='dhtmlgoodies_listMenu')inputObj=false;	
		}		
	}
	
	function getUrlParam(name){
    var results = new RegExp('[\\\\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (!results) { return 0; }
    return results[1] || 0;
	}

	function initMenu()
	{
	var obj = document.getElementById('dhtmlgoodies_listMenu');
		var sid = getUrlParam(sid);
		var cid = getUrlParam(cid);
		var linkCounter=0;
		var aTags = obj.getElementsByTagName('A');
		var activeMenuItem = false;
		var activeMenuLink = false;
		var thisLocationArray = location.href.split(/\\//);
		var fileNameThis = thisLocationArray[thisLocationArray.length-1];
		if(fileNameThis.indexOf('sid' + 'cid')>0)fileNameThis = fileNameThis.substr(0,fileNameThis.indexOf('sid', 'cid'));
		if(fileNameThis.indexOf('#')>0)fileNameThis = fileNameThis.substr(0,fileNameThis.indexOf('#'));

		for(var no=0;no<aTags.length;no++){
			var parent = aTags[no].parentNode;
			var subs = parent.getElementsByTagName('UL');
			if(subs.length>0){
				aTags[no].onclick = showHideSub;	
				linkCounter++;
				aTags[no].id = 'aLink' + linkCounter;
			}	
			
			if(aTags[no].href.indexOf(fileNameThis)>=0 && aTags[no].href.charAt(aTags[no].href.length-1)!='#'){				
				if(aTags[no].parentNode.parentNode){								
					var parentObj = aTags[no].parentNode.parentNode.parentNode;
					var a = parentObj.getElementsByTagName('A')[0];
					if(a.id && !activeMenuLink){
						
						activeMenuLink = aTags[no];
						activeMenuItem = a.id;
					}
				}
			}		
		}		

		if(activeMenuLink){
			activeMenuLink.className='activeMenuLink';
		}
		if(activeMenuItem){
			if(document.getElementById(activeMenuItem))showHidePath(document.getElementById(activeMenuItem));	
		}
	}


	window.onload = initMenu;

I hope I’v placed the function right…
Thanks!

Do you perhaps have a test page up that I can take a look at - so I can get the whole picture, as it were.

This is the page as it is now:
http://100bang.no/portfolio/brand2.php?sid=7&cid=2

Thanks a lot!

Excellent, thanks for that. That helped a lot.

It took me a few minutes to track it down but I worked out that in your initMenu() function you were doing the following comparison:

if(aTags[no].href.indexOf(fileNameThis)>=0 && aTags[no].href.charAt(aTags[no].href.length-1)!=‘#’){

What happened here is, you are comparing the href of the link and the “fileNameThis” which is a string you constructed yourself based on the current location. What that means is that when you were doing that comparison it would look something like this:


OLD: http://localhost/tmp/menutester/brand2.php.htm?sid=7&cid=2 == brand2.php.htm?sid=7&cid=2&page=3&ipp=1 >>>>> -1
NEW: /tmp/menutester/brand2.php.htm?sid=7&cid=2 == /tmp/menutester/brand2.php.htm?sid=7&cid=2&page=3&ipp=1 >>>>> 0

(Output from doing a console.log() to Firebug after I copied 1 of your pages to my local test server)

As you can see, using the “href” of the link you are currently iterating over includes the entire location string (i.e. including the scheme, domain name, pathname and search parts of the URL)

The new comparison looks like this:

linkToExamine = aTags[no].pathname + aTags[no].search;
			
curUrl = window.location.pathname + window.location.search;
			
if(curUrl.indexOf(linkToExamine)>=0 && aTags[no].href.charAt(aTags[no].href.length-1)!='#'){

Now only the pathname and the search parts of the URL will be compared from both the current location and the current link you’re iterating over.

So your initMenu function now looks like this:


function initMenu() {
	var obj = document.getElementById('dhtmlgoodies_listMenu');
	var sid = getUrlParam(sid);
	var cid = getUrlParam(cid);
	var linkCounter=0;
	var aTags = obj.getElementsByTagName('A');
	var activeMenuItem = false;
	var activeMenuLink = false;
	var thisLocationArray = location.href.split(/\\//);
		
	var fileNameThis = thisLocationArray[thisLocationArray.length-1];
	if(fileNameThis.indexOf('sid' + 'cid')>0)fileNameThis = fileNameThis.substr(0,fileNameThis.indexOf('sid', 'cid'));
	if(fileNameThis.indexOf('#')>0)fileNameThis = fileNameThis.substr(0,fileNameThis.indexOf('#'));

	for(var no=0;no<aTags.length;no++){
		var parent = aTags[no].parentNode;
		var subs = parent.getElementsByTagName('UL');
		if(subs.length>0){
			aTags[no].onclick = showHideSub;	
			linkCounter++;
			aTags[no].id = 'aLink' + linkCounter;
		}	

		//Note the new comparison below here:
		linkToExamine = aTags[no].pathname + aTags[no].search;
		curUrl = window.location.pathname + window.location.search;
			
		if(curUrl.indexOf(linkToExamine)>=0 && aTags[no].href.charAt(aTags[no].href.length-1)!='#'){				
			if(aTags[no].parentNode.parentNode){								
				var parentObj = aTags[no].parentNode.parentNode.parentNode;
				var a = parentObj.getElementsByTagName('A')[0];
				if(a.id && !activeMenuLink){
					
					activeMenuLink = aTags[no];
					activeMenuItem = a.id;
				}
			}
		}		
	}		

	if(activeMenuLink){
		activeMenuLink.className='activeMenuLink';
	}
	if(activeMenuItem){
		if(document.getElementById(activeMenuItem))showHidePath(document.getElementById(activeMenuItem));	
	}
}

Nice, it works perfect :slight_smile:
Thank you very much for taking time to solve this for me!

I think I understand what you changed but there is no way I could fix this myself…

I have a question about this piece of code: ‘[\\?&]’ + name + ‘=([^&#]*)’ in the “function getUrlParam”. Does the caret and the asterisk mean that I can add more variables in the string without changes, or does it need to be repeated?
Thanks!

What that particular piece does is match the passed parameter out and returns the value.

The regex pattern ‘[\\?&]’ + name + ‘=([^&#]*)’
Could be read as:
Match a part starting with either a “?” or a “&” symbol, followed by the “name” (which is the name of the var passed to the function)
Then match the “=” and the rest of the string, unless you encounter “&” or “#”
When the regex is executed, the part in the parentheses will be returned as the 2nd part of the array (the first part is always the entire string).

See the MDC JS Regex reference for more info.

The way this works is that you can call getUrlParam(‘yourVarName’) as many times as you want, you won’t need to modify the function for it.

You could for example do this:

var page = getUrlParam('page');
var sid = getUrlParam('sid');
var cid = getUrlParam('cid');
var ipp = getUrlParam('ipp');

and it will work just fine :slight_smile:

Very nice!
Thanks a lot for your help:-)