PDA

View Full Version : persiststate is not compatible with nested menus



Triynko
07-29-2011, 06:40 PM
1) Script Title:
Bullet List Accordion Menu with nested levels
(ddaccordion.js)

2) Script URL (on DD):
http://www.dynamicdrive.com/dynamicindex17/ddaccordionmenu-bullet.htm

3) Describe problem:
The open/closed state is not retrieved properly for nested menus.

The working example is a bit contrived, and works only coincidentally because the nested menu happens to be the second item in the second top-level menu (i.e. the expanded index for both the top-level menu and submenu are both "1").

The state saving mechanism doesn't work with nested levels when the header names are ending sub-strings of one another (e.g. "expandable" and "subexpandable". If you were to use the given example menu and submenu header names, then if that sub-menu was the third item, instead of the second, you'd see that after clicking it and refreshing the page that the 3rd top-level menu would suddenly be open, instead of the 2nd one, in which the nested menu was clicked.

Can someone confirm that this is a problem?

Triynko
08-01-2011, 04:32 PM
I confirmed that this is a problem, I describe the exact nature and location of the bug, and I provide the fix.

The problem is that the "getCookie" method of the ddacordion.js script uses a regular expression to match the cookie name, which results in an array of matches, and it arbitrarily uses the first match. This is only a problem when you use menu/submenu names where one is an ending substring of the other, as in the example: "expandable" and "subexpandable". For example, names like "header" and "subheader" would be problematic, but "topheader" and "subheader" would be fine.


getCookie:function(Name){
var re=new RegExp(Name+"=[^;]+", "i") //construct RE to search for target name/value pair
if (document.cookie.match(re)) //if cookie found
return document.cookie.match(re)[0].split("=")[1] //return its value
return null
}

I found this bug by debugging the JavaScript with the Firebug addon, and adding breakpoints after the setCookie and getCookie calls to ensure cookies were being read/written correctly. I confirmed that despite the two cookies "subexpandable" and "expandable" being saved with separate and correct values, the getCookie method was always returning the same value for both. It was immediately obvious to me upon inspecting the getCookie method that the Regex used in combination with the zero index selector was the problem.

One solution is to add a word boundary anchor to the Regex, so that only the full cookie name is matched, rather than just the end of it. Or, you could simply choose sufficiently different header class names.

Just change the line in the getCookie method in the ddaccordion.js script that defines the regular expression so that it includes the word boundary anchor "\\b" (notice escaped backslash):

var re=new RegExp("\\b"+Name+"=[^;]+", "i")